frida / frida-gum

Cross-platform instrumentation and introspection library written in C
https://frida.re
Other
733 stars 242 forks source link

Under certain cases, `_gum_interceptor_backend_create_trampoline` does not relocate instructions properly on aarch64 for the `on_invoke_trampoline` #759

Closed mineo333 closed 9 months ago

mineo333 commented 9 months ago

I'm doing some stuff with gum_interceptor_replace on LibAFL, and under certain cases it does not seem to relocate certain branches properly.

Right now, my platform is darwin (MacOS) and I'm trying to replace _platform_memcmp. The unmodified implementation looks as follows in lldb:

subs   x2, x2, #0x10
b.lo   #0x2c
nop
nop
...

When the code eventually calls the original implementation of _platform_memcmp, it, as intended, jumps to the ctx->on_invoke_trampoline as seen here. However, the on_invoke_trampoline looks as follows in lldb:

subs   x2, x2, #0x10
b.lo   #0x2c
nop    
nop    
ldr    x16, #0x8
br     x16
.long  0x8dfbc2c0                
udf    #0x1

As can be seen, the first 4 instructions are there followed by the br to the original implementation. This is as intended as seen in here. But, the b.lo cuts the block short and branches to zeroed memory resulting in the program crashing.

From what I understand, the current implementation of the trampoline builder doesn't support this kind of rewriting with branches in the first ~4 instructions because if there's no eoi it seems to dump the instructions verbatim as seen here.

Based on the current implementation of gum_arm64_relocator_read_one, it seems that this will occur for any block with an direct branch in the first 4 instructions.

The best solution here seems to be writing support for relocating these kinds of situations. I'm unsure if that is the best course of action here however.

mineo333 commented 9 months ago

This seems to be a problem associated with libafl and/or frida-rust. https://github.com/frida/frida-rust/issues/81 may still be a problem.

More specifically, the capstone IDs do not match for the correct instructions. For example, for a cbz, capstone may return a different insn->id than the id that frida receives. This behavior seems to be exclusive to the rust.