範例檔案
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
得到在二進位檔案的位置。