認識PE中的IMPort表

 有很多介紹PE文件的文章,但是我打算寫一篇關於輸入表的文章,因爲它對於破解很有用。 
    我想解釋它的最好的方法是舉一個例子,你可以跟着我逐步深入,一步一步的思考,最後你將完全明白,我選擇了一個我剛下載下來的小程序,它是用TASM編譯的,有一個比較小的輸入表,所以我想它應該是個不錯的範例。 
    好了,讓我們開始吧。首先我們得找到輸入表,它的地址放在PE文件頭偏移80處,所以我們用16進制編輯器打開我們的EXE文件,我們先得找到PE文件頭的起始點,這很簡單,因爲它總是以PE,0,0開始,我們可以在偏移100處找到它。在一般的WIN32程序中文件頭偏移被放在文件0X3C處,在那我們通常可看到00 01 00 00,由於數據存儲時是低位在前,高位在後的,所以翻轉過來實際就是00000100,就象前面我們說的。接下來我們就可以在PE文件中找到我們的輸入表,100+80=180在偏移180處我們看到0030 0000,翻轉一下,它其實應該是00003000,這說明輸入表在內存3000處,我們必須把它轉換成文件偏移。 
    一般來說,輸入表總是在某個段的起始處,我們可以用PE編輯器來查看虛擬偏移,尋找3000並由此發現原始偏移。很簡單的。打開我們看到: 
-CODE  00001000 00001000 00000200 00000600 
-DATA  00001000 00002000 00000200 00000800 
.idata 00001000 00003000 00000200 00000A00 
.reloc 00001000 00004000 00000200 00000C00 
    找一下,我們就發現.idata段的虛擬偏移是3000,原始偏移是A00,3000-A00=2600,我們要記住2600,以便以後轉換其它的偏移。如果你沒找到輸入表的虛擬偏移,那麼就找一下最接近的段。 
    來到偏移A00處,我們就看到被稱爲IMAGE_IMPORT_DESCRIPTORs(IID)的東東,它用5個字段表示每一個被調用DLL的信息,最後以Null結束。 
************************************************************************** 
(IID) IMAGE_IMPORT_DESCRIPTOR的結構包含如下5個字段: 
OriginalFirstThunk, TimeDateStamp, ForwarderChain, Name, FirstThunk 

OriginalFirstThunk 
該字段是指向一32位以00結束的RVA偏移地址串,此地址串中每個地址描述一個輸入函數,它在輸入表中的順序是不變的。 

TimeDateStamp 
一個32位的時間標誌,有特殊的用處。 

ForwarderChain 
輸入函數列表的32位索引。 

Name 
DLL文件名(一個以00結束的ASCII字符串)的32位RVA地址。 

FirstThunk 
該字段是指向一32位以00結束的RVA偏移地址串,此地址串中每個地址描述一個輸入函數,它在輸入表中的順序是可變的。 
************************************************************************** 

好了,你有沒有理解?讓我們看看我們有多少IID,它們從偏移A00處開始 
3C30 0000 / 0000 0000 / 0000 0000 / 8C30 0000 / 6430 0000 
{OrignalFirstThunk} {TimeDateStamp} {ForwardChain} {Name} {First Thunk} 
5C30 0000 / 0000 0000 / 0000 0000 / 9930 0000 / 8430 0000 
{OrignalFirstThunk} {TimeDateStamp} {ForwardChain} {Name} {First Thunk} 
0000 0000 / 0000 0000 / 0000 0000 / 0000 0000 / 0000 0000 

    每三分之一是個分界,我們知道每個IID包含了一個DLL的調用信息,現在我們有2個IID,所以我們估計這個程序調用了2個DLL。甚至我可以打賭,你能推測出我們將能找到什麼。
    每個IID的第四個字段表示的是名字,通過它我們可以知道被調用的函數名。第一個IID的名字字段是8C30 0000,翻轉過來也就是地址0000308C,將它減去2600可以得到原始偏移,308C-2600=A8C,來到文件偏移A8C處,我們看到了什麼?啊哈!原來調用的是KERNEL32.dll。 
    好了,接下來我們就要去找出KERNEL32.dll中被調用的函數。回到第一個IID。 
    FirstThunk字段包含了被調用的函數名的標誌,OriginalFirstThunk僅僅是FirstThunk的備份,甚至有的程序根本沒有,所以我們通常看FirstThunk,它在程序運行時被初始化。
    KERNEL32.dll的FirstThunk字段值是6430 0000,翻轉過來也就是地址00003064,減去2600得A64,在偏移A64處就是我們的IMAGE_THUNK_DATA,它存儲的是一串地址,以一串00結束。如下:    
A430 0000/B230 0000/C030 0000/CE30 0000/DE30 0000/EA30 0000/F630 0000/0000 0000 
    通常在一個完整的程序裏都將有這些。我們現在有了7個函數調用,讓我們來看其中的兩個: 
DE30 0000翻轉後是30DE,減去2600後等於ADE,看在偏移ADE處的字符串是ReadFile, 
EA30 0000翻轉後是30EA,減去2600後等於AEA,看在偏移AEA處的字符串是WriteFile, 
    你可能注意到了,在函數名前還有2個這字節的00,它是被作爲一個提示。 
    很簡單吧,你可以自己來試一下。回到A00,看第二個DLL的調用 
5C30 0000 / 0000 0000 / 0000 0000 / 9930 0000 / 8430 0000 
{OrignalFirstThunk} {TimeDateStamp} {ForwardChain} {Name} {First Thunk} 
    先找它的DLL文件名。9930翻轉爲3099-2600 =A99,在偏移A99處找到USER32.dll。再看FirstThunk字段值:8430翻轉爲3084-2600=A84,偏移A84處保存的地址爲08310000,翻轉後3108-2600=B08,偏移B08處字符串爲MessageBoxA。明白了吧,接下來你就可以把這些用在你自己的EXE文件上了。 
    摘要: 
    在PE文件頭+80偏移處存放着輸入表的地址,輸入表包含了DLL被調用的每個函數的函數名和FirstThunk,通常還有Forward Chain和TimeStamp。 
    當運行程序時系統調用GetProcAddress,將函數名作爲參數,換取真正的函數入口地址,並在內存中寫入輸入表。當你對一個程序脫殼時你可能注意到你有了一個已經初始化的FirstThunk。例如,在我的WIN98上,函數GetProcAddress的入口地址是AE6DF7BF,在98上,所有的KERNEL32.dll函數調用地址看上去地址都象:xxxxF7BF,如果你在輸入表中看到這些,你可以利用orignal thunk重建它,或者重建這個PE程序。 
    好了,我已經告訴你它們是如何工作的,我不是專家,如果你發現什麼錯誤,請告訴我。
發佈了5 篇原創文章 · 獲贊 5 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章