ARM64 Assembly (AArch64)
ARM64 is the instruction set architecture (ISA) of all Apple Silicon chips (A-series, M-series). All code running on iPhone is ARM64 machine code.
Why You Need To Learn This
- Kernel exploits require reading disassembly to find gadgets and understand control flow
- PAC bypasses require understanding PAC instructions (PACIA, AUTIA, β¦)
- ROP/JOP chains are built from assembly gadgets
- The debugger (lldb) displays assembly, not C
Key Knowledge
1. Registers
| Register | Purpose |
|---|---|
X0 - X7 |
Function arguments & return values (X0 = arg1 & return) |
X8 |
Indirect result location (struct return) |
X9 - X15 |
Temporary registers (caller-saved) |
X16 (IP0) |
Intra-procedure scratch, also used for PLT/stub calls |
X17 (IP1) |
Intra-procedure scratch |
X18 |
Platform register (reserved on Apple platforms) |
X19 - X28 |
Callee-saved registers |
X29 (FP) |
Frame pointer |
X30 (LR) |
Link register (return address) |
SP |
Stack pointer (must always be 16-byte aligned) |
PC |
Program counter (cannot be accessed directly like on ARM32) |
NZCV |
Condition flags: Negative, Zero, Carry, oVerflow |
Special registers for iOS exploitation:
W0 - W28: 32-bit view of X0-X28 (lower 32 bits)TPIDR_EL1: Thread-local storage pointer for kernelTTBR0_EL1/TTBR1_EL1: Translation Table Base Registers (page table pointers)VBAR_EL1: Vector Base Address Register (exception handlers)SCTLR_EL1: System Control Register
2. Instructions Commonly Encountered in Exploit Analysis
Data Movement:
MOV X0, X1 ; X0 = X1
MOV X0, #0x1234 ; X0 = immediate value
MOVK X0, #0xABCD, LSL #16 ; Move with keep (set bits 16-31)
LDR X0, [X1] ; X0 = *(uint64_t*)X1
LDR X0, [X1, #0x10] ; X0 = *(uint64_t*)(X1 + 0x10)
LDP X0, X1, [SP] ; Load pair from stack
STR X0, [X1] ; *(uint64_t*)X1 = X0
STP X29, X30, [SP, #-0x10]! ; Push FP and LR to stack (pre-index)
Arithmetic & Logic:
ADD X0, X1, X2 ; X0 = X1 + X2
SUB X0, X1, #0x10 ; X0 = X1 - 0x10
AND X0, X1, #0xFF ; X0 = X1 & 0xFF (masking)
ORR X0, X1, X2 ; X0 = X1 | X2
EOR X0, X1, X2 ; X0 = X1 ^ X2 (XOR)
LSL X0, X1, #4 ; X0 = X1 << 4
LSR X0, X1, #4 ; X0 = X1 >> 4 (logical shift)
Branching:
B label ; Unconditional branch
BL function ; Branch with link (function call, LR = return addr)
BR X16 ; Branch to register (indirect jump)
BLR X8 ; Branch with link to register (indirect call)
RET ; Return (branch to LR/X30)
CBZ X0, label ; Branch if X0 == 0
CBNZ X0, label ; Branch if X0 != 0
B.EQ label ; Branch if equal (Z flag set)
B.NE label ; Branch if not equal
B.GT / B.LT / B.GE / B.LE ; Signed comparisons
B.HI / B.LO / B.HS / B.LS ; Unsigned comparisons
Compare:
CMP X0, X1 ; Set flags based on X0 - X1
CMN X0, X1 ; Set flags based on X0 + X1
TST X0, #0x1 ; Set flags based on X0 & 0x1
System:
SVC #0x80 ; Supervisor call (syscall on iOS/macOS)
MRS X0, CurrentEL ; Read system register
MSR TTBR0_EL1, X0 ; Write system register
ISB ; Instruction Synchronization Barrier
DSB SY ; Data Synchronization Barrier
TLBI ; TLB Invalidate
3. PAC Instructions (A12+)
PACIA X0, X1 ; Sign X0 with key A, context X1
PACIB X0, X1 ; Sign X0 with key B, context X1
PACIZA X0 ; Sign X0 with key A, zero context
AUTIA X0, X1 ; Authenticate X0 with key A, context X1
AUTIB X0, X1 ; Authenticate X0 with key B, context X1
XPACI X0 ; Strip PAC bits from X0 (no auth check)
BRAA X0, X1 ; Authenticate & branch (key A)
BLRAA X0, X1 ; Authenticate & branch with link (key A)
RETAB ; Authenticate LR with key B & return
Significance for exploitation:
PACIA/PACIBadd a cryptographic signature to a pointerAUTIA/AUTIBverify the signature β if invalid, the pointer is corrupted, causing a crashXPACIstrips PAC bits without verification β useful when you need the raw address- Signing gadgets use
PACIAon controlled input to forge valid PAC values
4. Calling Convention (AAPCS64 β Apple variant)
Caller:
1. Place arguments in X0-X7 (integer) or D0-D7 (float)
2. Arguments beyond 8 are pushed onto the stack
3. BL function_name (LR = return address)
Callee (function prologue):
STP X29, X30, [SP, #-frame_size]! ; Save FP and LR
MOV X29, SP ; Set up frame pointer
... function body ...
Callee (function epilogue):
LDP X29, X30, [SP], #frame_size ; Restore FP and LR
RET ; Return to caller
Apple-specific:
- X18 reserved (platform register β do not touch)
- Stack must be 16-byte aligned at all times when calling a function
- Red zone: 128 bytes below SP can be used without adjusting SP (leaf functions)
5. Memory Model
Address space on ARM64 iOS:
0x0000000000000000 β
β Userspace (TTBR0_EL1)
0x0000007FFFFFFFFF β (~512GB, in practice iOS limits to 0x8000000000 = 32GB)
0xFFFF000000000000 β
β Kernel space (TTBR1_EL1)
0xFFFFFFFFFFFFFFFF β
Exception Levels:
EL0 β Userspace (apps, daemons)
EL1 β Kernel (XNU)
EL2 β Hypervisor (SPTM on iOS 17+; unused prior to that)
EL3 β Secure Monitor (iBoot, Secure Enclave communication)
Learning Resources
Beginner
- Azeria Labs β ARM Assembly Basics (ARM32 but concepts are similar)
- ARM Developer β Learn the Architecture: AArch64
- ARM Architecture Reference Manual (ARMv8-A) β the definitive reference, very thick but comprehensive
Intermediate
- Read disassembly output from IDA/Ghidra for real iOS binaries
- Write inline assembly in C and compile for arm64
- Debug iOS apps with lldb, read register state
Advanced
- Analyze kernel cache disassembly
- Find PAC signing/auth gadgets in system frameworks
- Understand the exception vector table (VBAR_EL1) and how the kernel handles traps
Practice Exercises
- Write βHello Worldβ in ARM64 assembly for macOS (if you have an Apple Silicon Mac)
- Disassemble a simple iOS binary with IDA/Ghidra, trace execution flow by hand
- Identify calling convention in decompiled code: find arguments, return values, stack frame
- Find gadgets in a Mach-O binary: sequences ending with RET, BLR, or BR
- Read PAC instructions in kernelcache disassembly and understand what they protect