ptrace可以在用戶端攔截或修改系統的syscall 使parent可以監視和控制clild的reg和img實現斷點與追蹤 在X86的系統要進行syscall是先把register的值設好,然後呼叫int80 而ptrace會再syscall之前先看process是否處於被追蹤(traced)的狀態 如果是的話,就把控制權給"追蹤的process",因此此時可以進行觀察修改reg或設斷點 GDB背後的原理其實就是靠ptrace
舉例:parent先fork出一個child並且監視他的行為 1. Child先允許別人可以追蹤他(PTRACE_TRACEME) if(child == 0){ptrace(PTRACE_TRACEME, 0, NULL, NULL); syscall...} 2. Parent等待kernel呼叫,取得child reg的值(PTRACE_PEEKUSER) wait(NULL); eax = ptrace (PTRACE_PEEKUSER, child, 4 * ORIG_EAX, NULL); ptrace(PTRACE_CONT, child, NULL, NULL);
anti-debug code
#include <stdio.h> #include <sys/ptrace.h> int main() { if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) { printf("DEBUGGING...\n"); return 1; } printf("Hello\n"); return 0; }
因為已經被gdb traced了,所以在呼叫ptrace就會failed,
藉此來達成anti-debug的功能。
繞過方法1: LDPROLAD ptrace.c int ptrace(int i, int j, int k, int l) { printf(" PTRACE CALLED!\n"); } $ gcc -shared ptrace.c -o ptrace.so (gdb) set environment LD_PRELOAD ./ptrace.so
繞過方法2: Binary Patch objdump -D a.out | less /main 804843c: e8 0f ff ff ff call 8048350 8048441: 85 c0 test %eax,%eax 8048443: 79 13 jns 8048458 test Usage: TEST dest,src Modifies flags: CF(carry) OF(overflow) PF SF(negative or sign) ZF(zero) Performs a logical AND of the two operands updating the flags register "without saving the result". test %eax,%eax (if eax < 0, set SF to 1 ) 79 Jump if not sign (jns) positive 78 Jump if sign (js) negative vim a.out :%! xxd /79 change 79 to 78 :%! xxd -r ZZ 如此一來gdb和真實的環境就相反了 比較正確的改法是 jmp (without any condition) http://ref.x86asm.net/coder32.html#xEB vim a.out :%! xxd /79 change 79 to eb :%! xxd -r ZZ 804843c: e8 0f ff ff ff call 8048350 8048441: 85 c0 test %eax,%eax 8048443: eb 13 jmp 8048458
補充
strace: trace syscall and signal
ltrace: a lib call tracer
背後其實都是透過ptrace來實現的
Advertisements