Topper Harley
Topper Harley

Reputation: 425

ARM64 assembly - execve arguments on stack

I am new to Aarch64 assembly (but I know some basics of x86 assembly). I am trying to write something like a "shellcode" on Android OS.

This shellcode is injected into another function. It is supposed to create a file /data/local/tmp/AAABBBCCC using execve and /system/bin/sh -c. I don't have to care about null bytes in my case.

Prior to execve call I make a syscall open_at (with O_CREAT and O_EXCL) and create another file in /data/local/tmp/ (I load the address of the filename using 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"

I know that for x86 you need to get the address of the first string using a trick with CALL instruction in order to make the argument array on the stack, because if you use labels like I did here, the addresses of the labels are contained within the instruction opcodes and after the injection they're not valid. But this should be a different case, right? The instruction ADR should be pc-relative and in its opcode I don't see any addresses, just relative distances.

When I inject the code to the funtion, the call to open_at always succeeds and the file is created. However the file that should be created by execve is never created.

What is the right way to make the argument array on the stack for execve on Aarch64? The stack must be 16-aligned, so I tried to always push two arguments at a time (using STP), but that did not work either.

The code for injecting is made using aarch64-linux-android toolchain like this:

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

Thank you for your answers!

Upvotes: 2

Views: 1344

Answers (1)

Topper Harley
Topper Harley

Reputation: 425

After a few minutes after I posted this question I realized where the mistake was.

The correct way to create the array of arguments on the stack is using the STP instruction. It stores two registers at a time (I was using it wrong before -- I provided the registers in a wrong order). It should be done like this:

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

adr     x1, arg1
adr     x2, arg0
stp     x2, x1, [sp, #-16]!

Upvotes: 2

Related Questions