關於 linux 中 elf 檔案格式可參考詳細文件《elf_format》,本文僅記錄筆者理解got/plt的過程。
got(global offset table):全域性偏移表用於記錄在 elf 檔案中所用到的共享庫中符號的絕對位址。在程式剛開始執行時,got 表項是空的,當符號第一次被呼叫時會動態解析符號的絕對位址然後轉去執行,並將被解析符號的絕對位址記錄在 got 中,第二次呼叫同一符號時,由於 got 中已經記錄了其絕對位址,直接轉去執行即可(不用重新解析)。
plt(procedure linkage table):過程鏈結表的作用是將位置無關的符號轉移到絕對位址。當乙個外部符號被呼叫時,plt 去引用 got 中的其符號對應的絕對位址,然後轉入並執行。
got 位於.got.plt
section 中,而 plt 位於.plt
section中。下面給出一示例程式:
#include #include int main(int argc, char* ar**)編譯該程式:printf("you input: ");
printf(ar**[1]);
printf("down\n");
return 0;
}
gcc -o format format.c
然後我們通過readelf
命令來檢視format
程式的 sectioin 資訊,並檢查 got:
從上圖可看到,該 elf 檔案共包含29個 section,有關 got 的重定向:
.rel.dyn
記錄了載入時需要重定位的變數,.rel.plt
記錄的是需要重定位的函式。
接下來,我們使用gdb
來對程式進行除錯,觀察程式在呼叫printf()
函式時,got 的變化情況。
因為程式邏輯需要輸入引數,設定好引數後,在主函式處下斷點,然後執行,單步除錯來到printf()
函式呼叫的地方:
這裡可以看到在0x080484ab
處指令為:
call 0x8048330
然後檢視一下0x8048330
處的**:
可以看到流程會跳轉到ds[0x804a00c]
處,而0x804a00c
是printf()
重定位偏移(檢視上面 got 資訊圖),接著看一下後面的流程都做了什麼:
根據上面的流程分析,進行單步除錯,當動態解析(_dl_runtime_resolve)完成後,流程會直接跳轉到printf()
函式主體:
上面我們說過,當第一次呼叫符號時會動態解析其絕對位址並寫到 got 中,下次呼叫的時候就不用再次解析了,我們來看看這個時候原先0x804a00c
處的指向情況:
其所指向的位址正好為第一次解析後得到的printf()
函式的入口位址。
程式中,printf()
函式的呼叫過程可以總結為:
總結來說就是,got 儲存了程式中所要呼叫的函式的位址,執行一開時其表項為空,會在執行時實時的更新表項。乙個符號呼叫在第一次時會解析出絕對位址更新到 got 中,第二次呼叫時就直接找到 got 表項所儲存的函式位址直接呼叫了。
(清楚上述動態解析的過程,有助於理解got覆寫利用)
通過GDB除錯理解指標
源 include intmain 編譯上面的 之後進行除錯。在初始化之前,a pon ppon的值各為 可以使用info locals命令進行檢視區域性變數 0x0執行結束退出main之前,a pon ppon的值各為 a 0xapon 0x7ffeefbff94c ppon 0x7ffeefbf...
gdb 除錯 vs除錯
一 先要生成二進位制檔案 g g 1.cpp o 1.out g引數不要省,不然 gdb l 引數用不了 二 引數 設定斷點 設定 函式斷點break func 在某行設定斷點break 7 檢視斷點資訊 info break 刪除斷點 d 刪除所有斷點 d 3 刪除第三個 執行 r 下一步 n 逐...
GDB除錯命令以及GDB除錯段錯誤
一 gdb的除錯命令。c語言是 cc g tst.c o tst c 是g g o 生成的檔案 file.cpp c 除錯程式命令 gdb file 啟動,羅列 行數ist 1,break 行數 info break,run r 除錯執行,step s 單步除錯,檢視變數 print p 變數名,檢...