範例檔案
https://github.com/Dinlon5566/IT_Reverse_Engineering/tree/main/Dx13
當加載 EXE 程式的時候,檔案會被加載到 Optional_Header 的 Image Base 所指定的位置上 ( 他通常是第一個加載到記憶體上的程序,不必考慮重定位的問題 ),不過要是有幾個要加載的 DLL 想加載到位置 800000h 上的話就會發生衝突。

這時候,PE loader 會把那些嘗試加載同樣位置的檔案分配到另外一個地方,就不會導致衝突。

雖然 something.dll 中的有些取用位置是與 Image Base 相對的,但還是有些位置是寫死在編碼上,要是直接存取預設的位置必然會導致存取錯誤,這時候就需要使用重定位表了。
這個重定位作業會將被偏移過的檔案中,寫死的位置記錄下來並把重定位的位置也一併記起來。然後計算正確的位置,步驟如下 :
DLL 的 IMAGE_BASE 的值 ( VA → RVA)RVA + 重定位後基址 ( RVA → VA )至於重定位表可以保存程式在重定位後的基址,它的位置資訊會保存在
IMAGE_NT_HEADERS->OptionalHeader.DataDirectory[5] 中

可以看到圖片中有重定位表的 RVA 位置 與 重定位表的大小,不過還是看一下 DataDirectory 的資料結構。

哇嗚 ! 好簡單!
透過上面指引的位置到了 00005000 看看

詳細看看這個表格的單位結構映照到上圖 ( from winnt.h )。

VirtualAddress - 00005000 : 重定位區塊的 RVA 位置
SizeOfBlock - 00005004 : 重定位區塊的大小
而之後的值 ( 00005008~ ) 是以注釋的型態存在的,大小為 WORD ,該值為硬編碼中的類型與位置偏移。
來試著分析上圖的前幾行。


( 5000 RVA → 2200 RAW )
首先,可以看到這個區塊的基準位置是 00001000,區塊的大小是 00000134。
下一行的 3003 中,0002209 **前 4 bit **的 3 代表 類型 “IMAGE_REL_BASED_HIGHLOW"


? https://learn.microsoft.com/zh-tw/windows/win32/debug/pe-format
使用手冊上有列舉全部的基底重新配置類型表,有興趣可以來看,這邊只類舉先關類型
而其餘 12 bit 的 003 代表偏移量,所以代表 1000+003 的位置就有一個硬編碼,用 PE-BEAR 看一下 :
1003 : 00 31 40 00 → 0x402100 指向儲存字串的位置
1008 : 20 21 40 00 → 0x402120 也是儲存字串的位置

順帶一提 : 根據位置減去 ImageBase 加上 Option_Header 中 sizeOfHeaders 定義的大小,得到 1003 - 1000 + 400 = 403 得到在二進位檔案的位置。