Gallopsled / pwntools

CTF framework and exploit development library
http://pwntools.com
Other
11.92k stars 1.69k forks source link

Idea: Search for Assembly Code Addresses #1350

Open phi1010 opened 4 years ago

phi1010 commented 4 years ago

Hello,

I'd like pwntools to generate ROP-code for aarch64. Since in my binaries, there are nearly no usable gadets, it'd like to jump to the middle of some functions. Since their location can change with updated binaries, I'd like to find these code locations automatically.

This partially already works, e.g. I can find a rop gadget manually rotating and popping some registers:

In [19]: list(elf.search(asm("mov x0, x19; ldp x19, x20, [sp, #0x10]; ldp x29, x30, [sp], #0x20; ret")))
Out[19]: [36100]

Now, I'd like to find the location of some assembly code calling a specific function:

In [20]: list(elf.search(asm("mov x1, x0; mov x0, x19; ldr x19, [sp, #16]; ldp x29, x30, [sp], #32; b utee_log")))
[ERROR] Shellcode contains relocations:

I know the actual base address where the elf will be loaded, but to my understanding, this probably is irrelevant -- apart from asm() not knowing the necessary symbols.

I suppose, when searching this for this code, the library would need to recompile the assembly for every position it shall be located in, resulting in different relative jump offsets to the specified jump target, then comparing it to the code actually there; which seems a bit inefficient.

Disassembling first and then comparing probably is as difficult, since simple text comparison might fail at equivalent code with different text representations (e.g. Compare and Branch if Equal vs. Compare and Branch if Zero).

The most universal and still efficient way for different platforms probably would be to assemble the code replacing the symbol which some placeholder, disassemble it again -- causing the representation to become somewhat normalized -- and then do a text comparison, stripping the addresses from the disassembly. Maybe someone has a better idea for this?

phi1010 commented 4 years ago

As clarification: rop.find_gadget does not help here, which might be caused by aarch64/ARM64 only sometimes popping return addresses from the stack, or since the code I'm searching for is not actually a traditional gadget.

In [42]: rop.find_gadget("")
Out[42]: Gadget(0x24, ['ret'], [], 0x8)

In [44]: rop.find_gadget("mov x0, x19")

In [45]: rop.gadgets
Out[45]:
{36: Gadget(0x24, ['ret'], [], 0x8),
 6900: Gadget(0x1af4, ['ret', 'ret'], [], 0x10)}