August 30, 2011

避開 PTRACE_TRACME 反追蹤技巧

在前文 [ptrace / SIGTRAP / int3 的關聯] 提到藉由檢查 ptrace(PTRACE_TRACEME, ...) 的技巧,確認該 process 是否被 GDB 所追蹤,而做出必要的回應。不過,這不表示就沒轍,事實上,還是能透過 gdb 來追蹤。

先來看看之前的範例程式碼:
嘗試編譯並使用 gdb:
$ gcc -o ptraceme{,.c} && gdb ptraceme
GNU gdb (Ubuntu/Linaro 7.3-0ubuntu2) 7.3-2011.08
...
(gdb) r
Starting program: /tmp/ptraceme 
No, I don't want to serve you.
由於執行到無窮迴圈,我們只好按下 Ctrl-C 結束:
^C
Program received signal SIGINT, Interrupt.
0x08048451 in main ()
讓我們來觀察反組譯的程式碼:(筆者的環境是 x86 32-bit)
   0x0804843c <+40>:	call   0x8048350 <ptrace@plt>
   0x08048441 <+45>:	test   %eax,%eax
   0x08048443 <+47>:	jns    0x8048453 <main+63>
   0x08048445 <+49>:	movl   $0x8048540,(%esp)
   0x0804844c <+56>:	call   0x8048320 <puts@plt>
=> 0x08048451 <+61>:	jmp    0x8048451 <main+61>
顯然 "jmp 0x8048451" 就是目前的無窮迴圈,但我們往上可見 call ptrace 這個調用 ptrace 系統呼叫的動作,接下來一行就是關鍵:
   0x0804843c <+40>: call   0x8048350 <ptrace@plt>
   0x08048441 <+45>: test   %eax,%eax
使用 test 指令來查對 ptrace() 系統呼叫的傳回值 (置於 %eax 暫存器),那也意味著,如果我們能在此設定中斷點,並且強制更改 %eax 內含值,就可跳過此反追蹤技巧。咱們來試試看:
(gdb) b *0x08048441
Breakpoint 1 at 0x8048441
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /tmp/ptraceme 

Breakpoint 1, 0x08048441 in main ()
如我們預期,停在 test 指令那邊,這時設定 %eax 暫存器並繼續執行:
(gdb) set $eax=0
(gdb) c
Continuing.
Yes, real routines go here
[Inferior 1 (process 13899) exited normally]
終於見到 "Yes, real routines go here" 字樣,而且該 process 也正常執行完畢。我們可編撰以下的 GDB script,來自動化上述操作,原理就是檢查 ptrace 系統呼叫的參數與修改回傳值。建立檔案 "gdb-ptrace" 如下:
set $ptrace_bpnum = 0

define ptrace-hook
    catch syscall ptrace
    commands
        if ($ebx == 0)
	    set $eax = 0
            continue
        end
    end
    set $ptrace_bpnum = $bpnum
end

define ptrace-unhook
    if ($ptrace_bpnum != 0)
        delete $ptrace_bpnum
        set $ptrace_bpnum = 0
    end
end
我們定義兩個自訂指令: ptrace-hook 與 ptrace-unhook,前者的技巧在於 "catch syscall ptrace",這時要求 GDB 檢查參數。離開 GDB 後,載入該 GDB script 並重新執行 ptraceme 執行檔:
$ gdb -x gdb-ptrace ptraceme
GNU gdb (Ubuntu/Linaro 7.3-0ubuntu2) 7.3-2011.08
...
鍵入自訂指令並執行:
(gdb) ptrace-hook 
Catchpoint 1 (syscall 'ptrace' [26])
(gdb) r
Starting program: /tmp/ptraceme 

Catchpoint 1 (call to syscall 'ptrace'), 0x001110c2 in ?? ()
   from /lib/ld-linux.so.2

Catchpoint 1 (returned from syscall 'ptrace'), 0x001110c2 in ?? ()
   from /lib/ld-linux.so.2
Yes, real routines go here
[Inferior 1 (process 13973) exited normally]
由上可見,Catchpoint 1 就是 syscall 'ptrace',我們順利的攔截並改變程式執行流程。
由 jserv 發表於 August 30, 2011 11:25 PM
迴響
發表迴響









記住我的資訊?