My approach works on arm-linux.
1. Attach to the target process with ptrace() system call.
2. Create a break point in the target process like a debugger.
3. When the break point is hit, copy some bootstrap code (more on bootstrap
code below) on the stack of the target process. The stack of the target
process can be found by parsing /proc/<pid>/maps, the corresponding line
entry ends with "[stack]"
4. Replace the break point with a "bx ip" instruction (similar to "jmp" in
x86), modify the value of register "ip", then resume the target process.
The target process will execute the injected bootstrap code.
About the bootstrap code:
a). The first instruction of the bootstrap code is a break point. When this
break point is hit, do the following:
* Clear the break point created in step 2.
* Replace the break point created in step a) with a "nop" instruction.
* Replace the first instruction of the injected function with any illegal
instruction, I picked "0xdead" for THUMB code, "0xdeaddead" for ARM code.
* Resume the target process
b) The bootstrap code just register a signal handler for SIGILL with
sigaction() system call. The third argument of the signal handler is a
pointer to a "struct ucontext_t" structure (This structure isn't defined in
android NDK, but can simply copy one from a gnu cross toolchain). In side
the signal handler we can do anything we like.
c) Modify the "pc" register of the "ucontext_t" register and return from
the signal handler, the target process will jump to the corresponding
address.
d) After the jump in step c), first restore the registers (the values of
the registers are saved in the "ucontext_t" structure), then execute the
first instruction of the injected function if the instruction is position
independent, otherwise interpret it (I haven't implemented this part yet,
better to do the interpretation before returning from the signal handler).
e) execute the rest of the injected function or return to its caller.
BTW, according to C standard the behavior of returning from a SIGILL
handler is undefined, but on arm-linux it just works.
Thanks
-Yao
- Show quoted text -
reply
| permalink