iOS ARM64 Syscalls - PullRequest
       61

iOS ARM64 Syscalls

0 голосов
/ 11 июля 2019

Я узнаю больше о шеллкоде и создании системных вызовов в arm64 на устройствах iOS. Устройство, на котором я тестирую это iPhone 6S.

Я получил список системных вызовов по этой ссылке (https://github.com/radare/radare2/blob/master/libr/include/sflib/darwin-arm-64/ios-syscalls.txt).

Я узнал, что x8 используется для ввода номера системного вызова для arm64 отсюда (http://arm.ninja/2016/03/07/decoding-syscalls-in-arm64/).

Я полагал, что различные регистры, используемые для передачи параметров для arm64, должны совпадать с arm, поэтому я сослался на эту ссылку (https://w3challs.com/syscalls/?arch=arm_strong), взято с https://azeria -labs.com / writing-arm -shellcode / .

Я написал встроенную сборку в XCode, и вот некоторые фрагменты

//exit syscall
__asm__ volatile("mov x8, #1");
__asm__ volatile("mov x0, #0");
__asm__ volatile("svc 0x80");

Однако приложение не завершает работу, когда я перешагнул через эти коды.

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"
                 );

Если этот системный вызов работает, он должен распечатать некоторый текст на экране вывода консоли Xcode. Однако ничего не печатается.

Есть много онлайн-статей по сборке ARM, некоторые используют svc 0x80, некоторые используют svc 0 и т. Д., Поэтому может быть несколько вариантов. Я пробовал разные методы, но не смог заставить работать два фрагмента кода.

Может ли кто-нибудь дать какое-нибудь руководство?

EDIT: Это то, что Xcode показывает в своем представлении Assembly, когда я написал syscall функции C 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

Я не уверен, почему этот код был выпущен.

Ответы [ 2 ]

2 голосов
/ 18 июля 2019

Это должно помочь вам. Как упомянул @Siguza, вы должны использовать x16, а не x8 для номера системного вызова.

#import <sys/syscall.h>
char testStringGlobal[] = "helloWorld from global variable\n";
int main(int argc, char * argv[]) {
    char testStringOnStack[] = "helloWorld from stack variable\n";
#if TARGET_CPU_ARM64

    //VARIANT 1 suggested by @PeterCordes
    //an an input it's a file descriptor set to STD_OUT 1 so the syscall write output appears in Xcode debug output
    //as an output this will be used for returning syscall return value;
    register long x0 asm("x0") = 1;
    //as an input string to write
    //as an output this will be used for returning syscall return value higher half (in this particular case 0)
    register char *x1 asm("x1") = testStringOnStack;
    //string length
    register long x2 asm("x2") = strlen(testStringOnStack);
    //syscall write is 4
    register long x16 asm("x16") = SYS_write; //syscall write definition - see my footnote below

    //full variant using stack local variables for register x0,x1,x2,x16 input
    //syscall result collected in x0 & x1 using "semi" intrinsic assembler
    asm volatile(//all args prepared, make the syscall
                 "svc #0x80"
                 :"=r"(x0),"=r"(x1) //mark x0 & x1 as syscall outputs
                 :"r"(x0), "r"(x1), "r"(x2), "r"(x16): //mark the inputs
                 //inform the compiler we read the memory
                 "memory",
                 //inform the compiler we clobber carry flag (during the syscall itself)
                 "cc");

    //VARIANT 2
    //syscall write for globals variable using "semi" intrinsic assembler
    //args hardcoded
    //output of syscall is ignored
    asm volatile(//prepare x1 with the help of x8 register
                 "mov x1, %0 \t\n"
                 //set file descriptor to STD_OUT 1 so it appears in Xcode debug output
                 "mov x0, #1 \t\n"
                 //hardcoded length
                 "mov x2, #32 \t\n"
                 //syscall write is 4
                 "mov x16, #0x4 \t\n"
                 //all args prepared, make the syscall
                 "svc #0x80"
                 ::"r"(testStringGlobal):
                 //clobbered registers list
                 "x1","x0","x2","x16",
                 //inform the compiler we read the memory
                 "memory",
                 //inform the compiler we clobber carry flag (during the syscall itself)
                 "cc");

    //VARIANT 3 - only applicable to global variables using "page" address
    //which is  PC-relative addressing to load addresses at a fixed offset from the current location (PIC code).
    //syscall write for global variable using "semi" intrinsic assembler
    asm volatile(//set x1 on proper PAGE
                 "adrp x1,_testStringGlobal@PAGE \t\n" //notice the underscore preceding variable name by convention
                 //add the offset of the testStringGlobal variable
                 "add x1,x1,_testStringGlobal@PAGEOFF \t\n"
                 //set file descriptor to STD_OUT 1 so it appears in Xcode debug output
                 "mov x0, #1 \t\n"
                 //hardcoded length
                 "mov x2, #32 \t\n"
                 //syscall write is 4
                 "mov x16, #0x4 \t\n"
                 //all args prepared, make the syscall
                 "svc #0x80"
                 :::
                 //clobbered registers list
                 "x1","x0","x2","x16",
                 //inform the compiler we read the memory
                 "memory",
                 //inform the compiler we clobber carry flag (during the syscall itself)
                 "cc");
#endif
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

EDIT

К отличному комментарию @PeterCordes, да, есть заголовок определения чисел системного вызова <sys/syscall.h>, который я включил в приведенный выше фрагмент ^ в Варианте 1. Но важно упомянуть, что он определен Apple следующим образом:

#ifdef __APPLE_API_PRIVATE
#define SYS_syscall        0
#define SYS_exit           1
#define SYS_fork           2
#define SYS_read           3
#define SYS_write          4

Я еще не слышал о случае отказа AppStore для приложения iOS из-за использования системного вызова напрямую через svc 0x80, тем не менее, это определенно не публичный API.

Что касается предложенного "=@ccc" @PeterCordes, то есть флага переноса (устанавливаемого syscall при ошибке) в качестве выходного ограничения, которое не поддерживается в последней бета / LLVM XCode11 8.0.0 даже для x86 и определенно не для ARM.

2 голосов
/ 11 июля 2019

Регистры, используемые для системных вызовов, абсолютно произвольны, и выбранные вами ресурсы, безусловно, не подходят для XNU.

Насколько мне известно, системный вызов XNU ABI для arm64 является полностью закрытым и может быть изменен без уведомления, поэтому нет опубликованного стандарта, которому он следует, но вы можете разобрать, как он работает, получив копию XNU source (как tarballs или , просматривающий его онлайн , если вы предпочитаете), grep для функции handle_svc и просто следование коду.
Я не буду вдаваться в подробности о том, где именно вы найдете какие биты, но конечный результат:

  • Незамедлительно переданный svc игнорируется, но стандартная библиотека использует svc 0x80.
  • x16 содержит номер системного вызова
  • x0 до x8 содержат до 9 аргументов *
  • В стеке нет аргументов
  • x0 и x1 содержат до 2 возвращаемых значений (например, в случае fork)
  • Бит переноса используется для сообщения об ошибке, в этом случае x0 содержит код ошибки

* Используется только в случае косвенного системного вызова (x16 = 0) с 8 аргументами.
* Комментарии в источнике XNU также упоминают x9, но, кажется, инженер, который написал это, должен устранить отдельные ошибки.

А затем речь идет о реальных доступных номерах системных вызовов:

  • Каноническим источником для системных вызовов UNIX является файл bsd/kern/syscalls.master в дереве исходных текстов XNU. В последней бета-версии iOS 13 они принимают номера системных вызовов от 0 до 540.
  • Каноническим источником "системных вызовов" Маха является файл osfmk/kern/syscall_sw.c в дереве исходных текстов XNU. Эти системные вызовы вызываются с отрицательными числами от -10 до -100 (например, -28 будет task_self_trap).
  • Не связанные с последней точкой, два системных вызова mach_absolute_time и mach_continuous_time могут быть вызваны с номерами системных вызовов -3 и -4 соответственно.
  • Несколько операций низкого уровня доступны через platform_syscall с номером системного вызова 0x80000000.
...