I am learning more about shellcode and making syscalls in arm64 on iOS devices. The device I am testing on is iPhone 6S.
I got the list of syscalls from this link (https://github.com/radare/radare2/blob/master/libr/include/sflib/darwin-arm-64/ios-syscalls.txt).
I learnt that x8 is used for putting the syscall number for arm64 from here (http://arm.ninja/2016/03/07/decoding-syscalls-in-arm64/).
I figured the various registers used to pass in parameters for arm64 should be the same as arm so I referred to this link (https://w3challs.com/syscalls/?arch=arm_strong), taken from https://azeria-labs.com/writing-arm-shellcode/.
I wrote inline assembly in Xcode and here are some snippets
//exit syscall
__asm__ volatile("mov x8, #1");
__asm__ volatile("mov x0, #0");
__asm__ volatile("svc 0x80");
However, the application does not terminate when I stepped over these codes.
char write_buffer[]="console_text";
int write_buffer_size = sizeof(write_buffer);
__asm__ volatile("mov x8,#4;" //arm64 uses x8 for syscall number
"mov x0,#1;" //1 for stdout file descriptor
"mov x1,%0;" //the buffer to display
"mov x2,%1;" //buffer size
"svc 0x80;"
:
:"r"(write_buffer),"r"(write_buffer_size)
:"x0","x1","x2","x8"
);
If this syscall works, it should print out some text in Xcode's console output screen. However, nothing gets printed.
There are many online articles for ARM assembly, some use svc 0x80
and some use svc 0
etc and so there can be a few variations. I tried various methods but I could not get the two code snippets to work.
Can someone provide some guidance?
EDIT:
This is what Xcode shows in its Assembly view when I wrote a C function syscall int return_value=syscall(1,0);
mov x1, sp
mov x30, #0
str x30, [x1]
orr w8, wzr, #0x1
stur x0, [x29, #-32] ; 8-byte Folded Spill
mov x0, x8
bl _syscall
I am not sure why this code was emitted.
The registers used for syscalls are arbitrary, and the resources you've picked are certainly wrong for XNU.
As far as I'm aware, the XNU syscall ABI for arm64 is private and subject to change without notice so there's no published standard that it follows, but you can see how it works by looking at the XNU source (view it online or download a tarball), specifically the handle_svc
function.
I'm not gonna go into detail on where exactly you find which bits, but the end result is:
svc
is ignored, but the standard library uses svc 0x80
(see here and here).x16
holds the syscall numberx0
through x8
hold up to 9 arguments*x0
and x1
hold up to 2 return values (e.g. in the case of fork
)x0
holds the error code* This is used only in the case of an indirect syscall (x16 = 0
) with 8 arguments.
* Comments in the XNU source also mention x9
, but it seems the engineer who wrote that should brush up on off-by-one errors.
And then it comes to the actual syscall numbers available:
bsd/kern/syscalls.master
in the XNU source tree. Those take syscall numbers from 0
up to about 540
in the latest iOS 13 beta.osfmk/kern/syscall_sw.c
in the XNU source tree. Those syscalls are invoked with negative numbers between -10
and -100
(e.g. -28
would be task_self_trap
).mach_absolute_time
and mach_continuous_time
can be invoked with syscall numbers -3
and -4
respectively.platform_syscall
with the syscall number 0x80000000
.