也談PE重定位表

最近研究脫殼,遇到了dll,因此不可避免的須要修復重定位表。之前研究過也脫過很多殼,但都是exe歷來沒有手工修太重定位表,因而搜索之,恩有這麼一篇:《PE重定位表學習手記》,有剛巧手上有看雪段鋼等編著的《加密與解密》,一併閱讀。html

《PE重定位表學習手記》中說到:算法

每一個塊的首部是以下定義:
typedef struct _IMAGE_BASE_RELOCATION {
DWORD VirtualAddress;
DWORD SizeOfBlock;
} IMAGE_BASE_RELOCATION;windows

……服務器

這個可由每一個塊結構中的Size來肯定。Size的值是以DWORD表示的當前整個塊的大小,先減去IMAGE_BASE_RELOCATION的大小, 由於重定位數據是16位WORD的,再除以2,就獲得個重定位數據的個數。由Size能夠直接到達下一個重定位塊,如圖所 示:0x5E850000+0x000000EC=0x5E8500EC即爲第二個重定位塊的地址,直至某個塊首結構的VirtualAddress爲 0,代表重定位表結束。數據結構

……ide

do
{//處理一個接一個的重定位塊,最後一個重定位塊以RAV=0結束
函數

……學習

}while (pRelocBlock->VirtualAddress);加密

《加密與解密》中說到:3d

若是還有更多段,將重複上面數據結構,直到VirtualAddress爲NULL,表示結束。如圖13.48所示是重定位表結構的一個示意圖。

OK,照此,就是說若是咱們本身手工建立編輯了重定位表,那麼須要填充8個字節的0(也就是空的IMAGE_BASE_RELOCATION)做爲重定位表的結束標記。而且pe文件頭目錄表中的重定位表尺寸也修改成整個重定位表數據的大小(固然包括這8個空字節)。

運行……嚯,0xC0000005……(若是8個空字節後剛好還有雜亂的隨機數據,你還會看到各類有意思的Win32 ErrorCode)。

爲啥呢?是修改的時候手抖了嗎?眼花?神經衰弱?非也,是這些文章錯了!咱們先來看看微軟官方權威的《Microsoft PE and COFF Specification

如下文字來自Microsoft PE and COFF Specification(Updated: September 21, 2010 File name: pecoff_v8.docx)
5.6 The .reloc Section (Image Only)

The base relocation table contains entries for all base relocations in the image. The Base Relocation Table field in the optional header data directories gives the number of bytes in the base relocation table. For more information, see section 3.4.3, 「Optional Header Data Directories (Image Only).」 The base relocation table is divided into blocks. Each block represents the base relocations for a 4K page. Each block must start on a 32-bit boundary.

能夠看到,微軟的文檔中並無說重定位表須要padding zero來做爲end標誌。

下面咱們看看到底windows中是怎麼處理這個重定位表的,下面是反彙編windows xp sp2的 ntdll.dll,實際的LoadLibraryA/W最後會調用到  LdrLoadDll(x, x, x, x)

而後沿下列調用鏈(用IDA和微軟的符號服務器便可方便的分析):

LdrLoadDll(x, x, x, x)->LdrpLoadDll(x,x,x,x,x,x)-> LdrpMapDll(x,x,x,x,x,x)->LdrRelocateImage(x, x, x, x, x)->LdrRelocateImageWithBias(x,x,x,x,x,x,x)

LdrRelocateImageWithBias就是實際執行重定位算法的函數,咱們來看看這個函數是怎麼作的:

image

首先RtlImageDirectoryEntryToData從目錄表中獲取重定位表的偏移和尺寸(TotalCountBytes)

而後指針移動到重定位表開始,而後循環開始每一項IMAGE_BASE_RELOCATION調用一次LdrProcessRelocationBlockLongLong,LdrProcessRelocationBlockLongLong返回值是下一項的指針,除非訪問到了無效內存,不然這個指針咱們能夠認爲永遠是有效的,7C93D8A7這裏的跳轉不會執行到。TotalCountBytes爲零的時候,說明重定位表處理完成,成功返回。

LdrProcessRelocationBlockLongLong是一個很是單純的函數,裏面徹底根據讀取到的數據來對PE進行重定位,也就是說,它永遠認爲輸入數據是正確的!沒有任何錯誤處理!

好了,如今咱們回到一開始的問題:windows遇到了重定位表的最後一項,咱們手工寫的8個零,因而LdrProcessRelocationBlockLongLong一絲不苟的開始在VirtualAddress = 0的地方,開始處理(SizeOfBlock-8)/2項,別忘了SizeOfBlock=0,(SizeOfBlock-8)/2是什麼請讀者本身算吧……

總結:重定位表實際有多少項就是多少項!

相關文章
相關標籤/搜索