August 2, 2010

ptrace / SIGTRAP / int3 的關聯

最近的時間大部分投入於某個產品的研發,自然得考慮到一些議題,其中包含了 anti-hacking,順便就複習 ptrace 一類的操作,本文可視為 [以 ptrace 系統呼叫來追蹤/修改行程] 的補充,以實驗方式,觀察這些底層機制。

在 UNIX 的世界裡,作業系統提供 ptrace 系統呼叫,允許我們優雅地進行「攔截」或「追蹤」其他行程的動作,這也是 gdb 與 strace 一類系統工具背後的原理,比方說 Evan Teran 就依據如此的機制,撰寫一個 [Qt4/ptrace-based Binary Debugger]。無論是如何操作,大抵依循以下三個步驟:
  • 調用 ptrace 系統呼叫
  • 判斷 SIGTRAP 是否為監看的程式 (如 GDB) 所攔截
  • 透過硬體平台的指令,去觸發 breakpoint / SIGTRAP,進而執行特定的追蹤動作。以 x86 為例,就是 "int3" 指令
在 GNU/Linux + IA32 環境下,筆者撰寫一個小程式,試圖觸發 breakpoint,來觀察在 gdb 底下與否,有什麼變化: [hello-int3.c]
#include <stdio.h>
int main()
{
	puts("Hello");
	__asm__ __volatile__("int3");
	puts("World");
	return 0;
}
試著編譯並執行:
$ gcc -o hello-int3{,.c} -g && ./hello-int3
Hello
Trace/breakpoint trap (core dumped)
顯然,在 x86 上,這個 "int3" 的組合語言指令,觸發了 breakpoint / SIGTRAP,依據 Linux Process 預設的 signal handler,就是終止程式的執行。那麼,在 gdb 下呢?繼續作實驗:
$ gdb ./hello-int3
GNU gdb (GDB) 7.1-ubuntu
...
(gdb) r
Starting program: /home/jserv/tmp/hello-int3 
Hello

Program received signal SIGTRAP, Trace/breakpoint trap.
main () at hello-int3.c:6
6		puts("World");
(gdb) 
看來 gdb 註冊了 SIGTRAP handler,才會得知 hello-int3 執行的 Process 具體的資訊, 並依據 DWARF,查詢到停留在 C 程式的第六行 (尚未執行)。Francis Bacon 說過,最好的證明,就是練習,對資訊科技更是如此,根據稍早的觀察,我們可推論出,若要讓 Linux Process 免於被 gdb 所「騷擾」(anti-hacking 的基礎),必須在程式內適時註冊 SIGTRAP handler。筆者準備以下的驗證程式碼: [dbg-int3.c]
#include <stdio.h> 
#include <signal.h>

static volatile sig_atomic_t being_debugged = 1;
static void int3_handler(int signo) { being_debugged = 0; }

int main()
{
        signal(SIGTRAP, int3_handler);
        __asm__ __volatile__("int3");
        if (being_debugged) {
		puts("No, I don't want to serve you.");
                while (1) {
			/* endless loop */ ;
		}
        }
        puts("Yes, real routines go here.");
        return 0;
}
試著編譯並執行:
$ gcc -o dbg-int3{,.c} -g && ./dbg-int3
Yes, real routines go here.
這是平常的執行結果,因為先註冊專屬的 SIGTRAP handler,當執行 "int3" 指令,自然會去觸發,設定「此時不被 debugger 追蹤」的狀態。那在 gdb 底下執行呢?比較看看:
$ gdb ./dbg-int3 
GNU gdb (GDB) 7.1-ubuntu
...
(gdb) r
Starting program: /home/jserv/tmp/dbg-int3 

Program received signal SIGTRAP, Trace/breakpoint trap.
0x08048421 in main ()
(gdb) 
GDB 告訴我們 SIGTRAP 被觸發了,這時候我們就要思考,到底 SIGTRAP handler 是不是被 GDB 給「攔截」或「改寫」過,繼續看下去:
(gdb) c
Continuing.
No, I don't want to serve you.
顯示 "No, I don't want to serve you." 一段文字後,就陷入無窮迴圈,可反推,GDB 的確會對 attached process 作 SIGTRAP handler 的攔截處理,而我們的程式則反將一軍,非暴力不合作。

另外,若不想使用 SIGTRAP handler 的機制,可直接用 ptrace 系統呼叫來檢查,改寫上述程式碼如下: [ptraceme.c]
編譯並直接在 gdb 裡面執行:
$ gcc -o ptraceme{,.c} -g && gdb ptraceme
GNU gdb (GDB) 7.1-ubuntu
...
(gdb) r
Starting program: /home/jserv/tmp/ptraceme 
No, I don't want to serve you.
同樣達成目的。需要留意的是,有一些特別的 Linux 系統,如 Google Chrome OS,也是透過上述這些常見的 anti-hacking 技倆,實現作業系統層級的 sandbox 機制。
由 jserv 發表於 August 2, 2010 2:30 AM
迴響
發表迴響









記住我的資訊?