文章總列表

強力Debug技巧: 攔截function & Backtrace (2)

第一招是攔截任意 standard C library 的 function
在下面的範例裡, 攔截的對象是 atoi()

首先主程式長這個樣子...

Main program (hello.c)

 #include <stdio.h>
int main()
{
printf("I love debug >_<\n");
printf("atoi(100) = %d\n", atoi("100"));
return 0;
}

用 gcc 編譯這個程式並且執行, 結果大概長這樣子:

 gcc hello.c -o hello

./hello
I love debug >_<
atoi(100) = 100

----


所謂的攔截atoi(), 就是寫了另一個atoi(), 名字和 standard C library 的一樣.
讓程式在執行時, 呼叫到自己寫的atoi(), 而不是library提供的.

這個偽atoi()的程式碼如下:

Wrapper function (atoi_wrapper.c)

 #define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>

// ATOI-wrapper
int atoi(const char *nptr)
{
int ret;

// Get pointer of REAL-atoi by shared library
int (*real_atoi)(const char *nptr) =
dlsym(RTLD_NEXT, “atoi”);

// Before REAL-atoi, do some hacking
printf(“[ATOI] before REAL atoi()\n”);

// Call REAL-atoi
ret = (*real_atoi)(nptr);

// After REAL-atoi, do some hacking...
printf(“[ATOI] after REAL atoi()\n”);
ret = ret + 100;

return ret;
}

這個偽atoi()是一個wrapper, 呼叫的時候, 會先加點料, 然後才呼叫真的atoi().
我在這個偽 atoi() 裡印了一些東西, 順便把輸出的結果竄改 (+100)
如果動得起來, 表示我們能攔截任意函數, 並且在呼叫前, 以及呼叫後動手腳.

編譯的手段是建立一個 shared library:

 gcc -fPIC -rdynamic -c atoi_wrapper.c
gcc -shared -o libatoiwrap.so atoi_wrapper.o -ldl

順利的話, 上面兩步做完, 目錄裡會多出一個 libatoiwrap.so


----


接下來, 讓 hello 執行時, 呼叫的 atoi() 被 libatoiwrap.so 的 atoi() 攔截

先看一下正常的執行結果:

 ./hello

I love debug >_<
atoi(100) = 100

如果動點手腳, 攔截 atoi() , 用 libatoiwrap.so 裡的取代 :

 LD_LIBRARY_PATH=. LD_PRELOAD=libatoiwrap.so ./hello

I love debug >_<
[ATOI] before REAL atoi()
[ATOI] after REAL atoi()
atoi(100) = 200

----


在上面的範例裡, atoi()的結果被竄改, 我們可以用這招來追蹤程式.
他做的事, 其實是改變 shared library 載入的程序, 看的更仔細的話
還可以順便認識 shared library 運作的機制.

特別推薦這篇由 SETIATHOME 團隊發表的文章:
Intercepting Arbitrary Functions on Windows, UNIX, and
Macintosh OS X Platforms
http://lattice.umiacs.umd.edu/files/functions_tr.pdf

這篇文章的範例都是從這裡出來的

留言

這個網誌中的熱門文章

STM32 UART + DMA,使用HAL實作TX/RX,以及不定長度接收

幼犬書桌椅選擇心得 升降桌 兒童桌椅

CANON G3000 廢墨瓶改裝