Pwn學習隨筆( 四 )

其中除第一個表項以外,plt 表的第一條都是跳轉到對應的 got 表項,而 got 表項的內容我們可以通過 gdb 來看一下 , 如果函數還沒有執行的時候,這里的地址是對應 plt 表項的下一條命令,即 push 0x0(作為參數傳入-- 相應函數在 rel.plt 中的偏移)
在想要調用的函數沒有被調用過 , 想要調用他的時候,是按照這個過程來調用的
xxx@plt -> xxx@got -> xxx@plt -> 公共@plt -> _dl_runtime_resolve(通過這個函數找到運行時函數的地址)
到這里我們還需要知道

  1. _dl_runtime_resolve 是怎么知道要查找 printf 函數的
  2. _dl_runtime_resolve 找到 printf 函數地址之后,它怎么知道回填到哪個 GOT 表項
第一個問題 , 在 xxx@plt 中,我們在 jmp 之前 push 了一個參數,每個 xxx@plt 的 push 的操作數都不一樣 , 那個參數就相當于函數的 id,告訴了 _dl_runtime_resolve 要去找哪一個函數的地址
第二個問題,看 .rel.plt 的位置就對應著 xxx@plt 里 jmp 的地址 , 該位置就是偏移量,使用readelf -r plt讀取elf文件中重定位節信息
Pwn學習隨筆

文章插圖
在 i386 架構下,除了每個函數占用一個 GOT 表項外,GOT 表項還保留了3個公共表項,也即 got 的前3項,分別保存:
  • got [0]: 本 ELF 動態段 (.dynamic 段)的裝載地址
  • got [1]:本 ELF 的 link_map 數據結構描述符地址,包含了進行符號解析需要的當前 ELF 對象的信息 。每個 link_map 都是一條雙向鏈表的一個節點 , 而這個鏈表保存了所有加載的 ELF 對象的信息 。
  • got [2]:指向動態裝載器中 _dl_runtime_resolve 函數的指針 。
動態鏈接器在加載完 ELF 之后,都會將這3地址寫到 GOT 表的前3項
Pwn學習隨筆

文章插圖

Pwn學習隨筆

文章插圖
通過編寫如下所示的代碼來幫助理解pltgot這兩個表
// gcc -m32 -no-pie -g -o plt plt.c#include <stdio.h>#include <stdlib.h>int main(int argc, char **argv){puts("hello,world");exit(0);}使用objdump -h plt , 查看該文件編譯后的所有節的信息
plt:file format elf32-i386Sections:Idx NameSizeVMALMAFile offAlgn 10 .rel.plt000000180804832c0804832c0000032c2**2CONTENTS, ALLOC, LOAD, READONLY, DATA 12 .plt000000400804903008049030000010302**4CONTENTS, ALLOC, LOAD, READONLY, CODE 13 .plt.sec000000300804907008049070000010702**4CONTENTS, ALLOC, LOAD, READONLY, CODE 22 .got000000040804bffc0804bffc00002ffc2**2CONTENTS, ALLOC, LOAD, DATA 23 .got.plt000000180804c0000804c000000030002**2CONTENTS, ALLOC, LOAD, DATA然后打開gdb進行分析,可以看到調用函數puts的地址為0x80491de,在該地址處下一個斷點
Pwn學習隨筆

文章插圖
然后使用si進入puts函數內部
Pwn學習隨筆

文章插圖
可以看到在 puts@plt 中第一條指令是跳轉,0x804c00c其實就是[_GLOBAL_OFFSET_TABLE_ + 12],這個地址剛好位于.got.plt表中,也就是說 , puts@plt 的第一步是去 .got.plt 找地址
23 .got.plt000000180804c0000804c000000030002**2CONTENTS, ALLOC, LOAD, DATA
Pwn學習隨筆

文章插圖
這時候我們如果再按一次si,可以看到會直接執行到下面的那一行的指令,原因就是:我們之前沒有調用過 puts@plt 函數,.got.plt 里面存儲的puts的地址就是下一條指令的地址而非真正的地址 , 所以按照之前說的 , 現在要觸發鏈接器找到 puts 函數的地址了
下面的[_GLOBAL_OFFSET_TABLE_ + 4] 處的指令,這個地址0x804c004也是位于.got.plt節中的,查看該地址存儲的內容
Pwn學習隨筆

文章插圖
其中0xf7ffd990指向ld.so的數據段,0xf7fe7b10指向可執行區域 , 簡而言之,觸發了鏈接器/加載器,在加載器處理之前,查看之前的.got.plt節中的地址0x804c00c所存儲的值為

推薦閱讀