一種調試 glibc 函數的好方法是用您自己的版本覆蓋所關注的函數。在沒有 root 許可權和不必重新編譯 libc 源代碼的情況下就可以完成這個任務。想象一下編寫您自己的 open() 版本該有多激動啊! 如果您沒有應用程序的源代碼並且由於 C 的 GNU 庫(glibc)函數正將某些錯誤信息返回給該應用程序而使它失敗,那麼您該怎麼辦?因為 glibc 是開放源碼,所以您當然可以獲得其源代碼、對它進行更改、重新構建和安裝。然而,這不適合那些膽怯的人,因為雖然 API 有很好的文檔說明,但 GNU C 庫的內部組織卻沒有。查找正確的函數原型只是眾多挑戰中的第一個。它還是一個很大的包,所以第一次編譯時,它將花一些時間(glibc 2.2.2 有 8552 個文件和 1775440 行代碼,包括注釋)。
更好的方法 比重新構建 glibc 更好的方法是選擇性地覆蓋一個函數。許多現代的 Unix 都支持預裝入用戶定義庫這一概念。這些庫可以是完整的替代(即,glibc 的專用版本)也可以是子集 — 甚至是一個函數。首先,通過設置 LD_LIBRARY_PATH 來包含庫的專用版本,您可以使用 glibc 的專用版本。可通過使用 LD_PRELOAD 環境值來使用您編寫的庫例程的子集。LD_LIBRARY_PATH 和 LD_PRELOAD 都是由動態 ELF 鏈接器/裝入器控制的。它使用第一個匹配來滿足任何符號名。通過預裝入您自己的庫或函數版本,您“短路”了正常路徑,這樣就允許您覆蓋它。 這裡是一個示例 makefile,它覆蓋 glibc 函數 setresgid(): 覆蓋 setresgid() 的 Makefile # # Makefile # all: libs setresgid-tester # # Make a shared Library # libs: libfuncs.c gcc -shared -Wl,-soname,libfuncs.so.1 -o libfuncs.so.1.0 libfuncs.c ln -s libfuncs.so.1.0 libfuncs.so.1 ln -s libfuncs.so.1 libfuncs.so # # Here is a program that calls setresgid() for testing # setresgid-tester: setresgid-tester.c gcc -o setresgid-tester setresgid-tester.c 文件 libfuncs.c 包含我的 setresgid() 專用版本。實現它以支持與原始 setresgid() 相同的參數數目時要小心,並在其它方面完成與原始 setresgid() 相同的操作,盡管我的版本欺騙該應用程序並始終返回 0。 關注的第二個文件是 setresgid-tester.c。它通過調用 setresgid() 試驗新函數。 這是動態庫的源代碼: 替換庫 /* Put all the functions you want to override here */ #include #include #include int errno; int setresgid(rgid, egid, sgid) gid_t rgid,egid,sgid; { errno=1; printf("It me the shim, Hi there!\n"); return(0); } 您還需要一個簡單方法來測試您的 setresgid() 專用版本。可以使用 strace 或 ltrace 來監視進程運行。這是普通測試示例的源代碼:
普通測試示例 /* setresgid() system/library call tester */ #include #include main(){ setresgid(0,0,0); } 現在,編譯該庫,設置 LD_PRELOAD shell 變量,然後運行測試應用程序。您可能還需要設置 LD_LIBRARY_PATH。
運行測試應用程序 eXPort LD_PRELOAD=libfuncs.so export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./setresgid-tester It's me the shim, Hi there! 還可以通過使用 ldd 列出動態鏈接庫來確認是否正在使用專用庫:
確認專用庫的使用 [jay@prion ld_preload]$ ldd setresgid-tester libfuncs.so => libfuncs.so (0x40018000) libc.so.6 => /lib/libc.so.6 (0x40022000) /lib/ld-Linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
結束語 編寫 GNU C 庫函數的專用版本是調試系統問題或進行快速修正的好方法。使用 LD_PRELOAD shell 變量,可以選擇性地用您自己的專用版本來覆蓋系統 C 庫函數。這種技術可用於 Linux 和 Solaris 環境。