Сборка ARM64 - аргументы execve в стеке

Я новичок в сборке Aarch64 (но знаю некоторые основы сборки x86). Я пытаюсь написать что-то вроде «шеллкода» на ОС Android.

Этот шеллкод внедряется в другую функцию. Предполагается создать файл /data/local/tmp/AAABBBCCC, используя execve и /system/bin/sh -c. В моем случае мне не нужно заботиться о нулевых байтах.

Перед вызовом execve я делаю системный вызов open_atO_CREAT и O_EXCL) и создаю другой файл в /data/local/tmp/ (я загружаю адрес имени файла, используя adr x1, path).

...

call to open_at

... 

// push terminating 0
mov     x1, 0
str     x1, [sp, #-16]!
// push arg2
adr     x1, arg2
str     x1, [sp, #-16]!
// push arg1
adr     x1, arg1
str     x1, [sp, #-16]!
// push arg0
adr     x1, arg0
str     x1, [sp, #-16]!
// call execve
adr     x0, command
ldr     x1, [sp]
mov     x2, 0
mov     x8, SYS_EXECVE
svc     0

...
.balign 4
command:
    .string "/system/bin/sh"
arg0:
    .string "/system/bin/sh"
arg1:
    .string "-c"
arg2:
    .string "/system/bin/touch /data/local/tmp/AAABBCCC"

Я знаю, что для x86 вам нужно получить адрес первой строки, используя трюк с инструкцией CALL, чтобы сделать массив аргументов в стеке, потому что, если вы используете метки, как я сделал здесь, адреса меток содержатся внутри коды операций инструкции и после инъекции они недействительны. Но это должен быть другой случай, верно? Инструкция ADR должна быть относительно ПК, и в ее опкоде я не вижу никаких адресов, только относительные расстояния.

Когда я ввожу код в функцию, вызов open_at всегда завершается успешно, и файл создается. Однако файл, который должен быть создан execve, никогда не создается.

Как правильно сделать массив аргументов в стеке для execve на Aarch64? Стек должен быть выровнен по 16, поэтому я пытался всегда помещать два аргумента за раз (используя STP), но это тоже не сработало.

Код для инъекций делается с помощью aarch64-linux-android тулчейна вот так:

as -o code.o code.asm
objcopy -O binary code.bin code.o
xxd -i code.bin

Спасибо за ваши ответы!


person Topper Harley    schedule 09.04.2018    source источник
comment
Пробовали ли вы использовать strace, чтобы понять, какие системные вызовы выполняет ваш код?   -  person fuz    schedule 09.04.2018


Ответы (1)


Через несколько минут после того, как я разместил этот вопрос, я понял, где была ошибка.

Правильный способ создания массива аргументов в стеке — использование инструкции STP. Он хранит два регистра одновременно (раньше я использовал его неправильно — я предоставил регистры в неправильном порядке). Это должно быть сделано следующим образом:

mov     x1, 0
adr     x2, arg2
stp     x2, x1, [sp, #-16]!

adr     x1, arg1
adr     x2, arg0
stp     x2, x1, [sp, #-16]!
person Topper Harley    schedule 09.04.2018
comment
Или вы могли бы использовать [sp, #-8]! для передачи одного значения за раз вместо сохранения 8 байтов и уменьшения SP на 16. Но да, stp явно лучше, потому что он быстрый и экономит все инструкции. - person Peter Cordes; 10.04.2018
comment
Действительно? Если вы посмотрите на этот веб-сайт, первый код под заголовком Проблема, начинающийся с Broken AArch64 implementation of ..., говорит, что это не сработает... - person Topper Harley; 11.04.2018
comment
Ах, спасибо, я не очень хорошо знаю AArch64; спасибо за ссылку. Я не знал, что выравнивание стека по 16 байт требуется всегда и обеспечивается аппаратно! (Очевидно, что его можно отключить с помощью привилегированного кода: community.arm.com/processors/b/blog/posts/) Это интересная функция; Интересно, почему именно они сделали это вместо того, чтобы оставить на усмотрение соглашений о требованиях/гарантиях выравнивания стека, как на x86 и других ISA. - person Peter Cordes; 11.04.2018