1. 程式人生 > 其它 >PE檔案詳解八

PE檔案詳解八

前面瞭解了PE檔案的輸入和輸出,今天來看看另一個重要的結構——資源。資源結構是很典型的樹形結構,層層查詢,最終找到資源位置。

0x01 資源結構介紹

Windows程式的各種介面成為資源,包括加速鍵,點陣圖,游標,對話方塊,圖示,選單,串標,工具欄,版本資訊等等,在所有的PE檔案中資源結構是最為複雜的。下圖為資源的樹形結構圖:

   通常來講,資源的目錄為三層結構。最上面的為根目錄,它儲存了資源的型別同時儲存指向下一級的指標,二級目錄包含資源id(至於啥事資源ID後面會講到)和指向第三級的指標,三級目錄儲存資原始碼和指向真正資源的指標。這裡最要理解的是這三級目錄用的都是同一結構。這個結構包含兩個子結構——資源目錄結構(IMAGE_RESOURCE_DIRECTORY)和資源目錄入口地址結構(IMAGE_RESOURCE_DIRECTOTY_RNTRY)。理解了這兩個結構各自的作用就能明白整個資源結構。下面分別從這兩個結構講起。

0x02 資源目錄結構(IMAGE_RESOURCE_DIRECTORY)

資源目錄結構是由資料目錄表的第三個子項(Resource Table)所指向的(想想資料目標表有多重要把,基本上後面所講都要從它開始)。該結構包含16個位元組,共6個欄位,下面的該結構的定義:

// 【資源表位於資料目錄表的第三項,共動態分配位元組, 其中結構體中的成員指出的RVA偏移量都是對於此結構體的地址作為基地址】

typedef struct _IMAGE_RESOURCE_DIRECTORY

{

DWORD Characteristics; //理論上為資源的屬性,不過事實上總是0

DWORD TimeDateStamp; //資源的產生時刻

WORD MajorVersion; //理論上為資源的版本,不過事實上總是0

WORD MinorVersion

WORD NumberOfNamedEntries;      //以名稱(字串)命名的入口數量

WORD NumberOfIdEntries; //以ID(整型數字)命名的入口數量

} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;

這六個欄位真正有用的是最後兩個欄位:

WORD NumberOfNamedEntries:標明入口數量,所謂入口數量,資源目錄入口地址結構(IMAGE_RESOURCE_DIRECTOTY_RNTRY)結構的數量,這個結構都是緊緊跟著資源目錄結構(IMAGE_RESOURCE_DIRECTORY),不過它標記數量的方式是用字串。

WORD NumberOfIdEntries:這個欄位本質上和前一個欄位一模一樣,不過它是用id來標明數量。注意:最後統計資源入口地址結構數量的時候是這兩個的相加的和。

0x03 資源目錄入口地址結構(IMAGE_RESOURCE_DIRECTORY_ENTRY)

 資源目錄入口地址結構雖然很簡單,但是卻非常重要。它不僅包含了指向下一級目錄的地址,好包含了指向真正資源的資料入口地址。

typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY

{

DWORD  Name;        //目錄項的名稱字串指標或者ID

DWORD  OffsetToData;    //資源資料偏移地址或者子目錄偏移地址

}_IMAGE_RESOURCE_DIRECTORY_ENTRY, *P_IMAGE_RESOURCE_DIRECTORY_ENTRY;

這兩個欄位都是極為重要的,下面將詳細講解這兩個欄位的含義:

Name:大小為雙字,該欄位定義了目錄項的名稱或者ID。當用於第一級目錄時,它表示的是資源的型別,用於第二級目錄時表示資源的名稱,用於第三級目錄時,用於表示資源的內碼表號編號。當最高位是0的時候,表示欄位的值作為ID來使用(前面說了該欄位可以表示資源的型別,資源的型別就是用ID來區分的,不同資源型別ID不一樣)。當最高位是1時,地位欄位表示一個指標,這個指標就是指向了資源的名稱的UNICODE編碼(前面也講到該欄位可以表示目錄的名稱)。下表統計了系統已經定義的資源型別。表一

型別ID值

資源型別

型別ID值

資源型別

01h

游標(Cursor)

08h

字型(Font)

02h

點陣圖(Bitmap)

09h

加速鍵(Accelerator)

03h

圖示(Icon)

0ah

未格式資源(Unformatted)

04h

選單(Menu)

Obh

訊息表(MessageTable)

05h

對話方塊(Dialog)

0ch

游標組(Group Cursor)

06h

字串(Stiring)

0eh

圖示組(Group Icon)

07h

字型目錄(Font Directory)

10h

版本資訊(Version Information)

 

OffsetToData:雙字結構,是一個指標。當最高為為1時,低位指向的是下一級目錄的起始地址,當最高為是0時,指向的是真正的資料資源的目錄入口結構(IMAGE_RESOURCR_DIRCTORY_DATA)。

重要說明:當欄位Name和Offset作為指標時,該指標是從資源區塊開始的地方算起的偏移量,不是RVA,即根目錄的起始位置偏移量(就是從第一級資源目錄結構(IMAGE_RESOURCE_DIRECTORY)的起始地址算起)

0x03 例項講解資源的結構

工具:hexworkshop,lordPE,目標PE檔案:pediy.exe。

下面我將一級級逐級追擊資源:

1)根目錄

首先找到資料目錄表的第三項,它指向了第一級目錄即根目錄地址。它在PE檔案頭偏移88h處。地址為:0ch+88h=148h。直接跳轉至148h處,如下圖:

標明RVA=4000h,這裡本來如果要跳轉至根目錄是要進行地址轉化,但是這裡是特殊情況,由於這個PE檔案磁碟分頁和記憶體分頁的值相等,故RVA=Offset,緣由可看下圖:

 我們現在直接跳轉至4000h處,該處即為根目錄起始地址,如下圖:

 現在我們按照順序以西讀出這個第一個結構IMAGE_RESOURCE_DIRECTORY的六個欄位的值。記在下表中:表二

 

Charateristics

TimeStamp

MajorVersion

MinnorVersion

NumberOfEntris

NumberOfIdEntries

 

0000 0000

0000 0000

0000

0000

0000

0003

 

由最後兩個欄位可知緊隨IMAGE_RESOURCE_DIRECTORY的共有三個IMAGE_RESOURCE_DIRECTORY_ENTRY結構,如下圖:

 依次將資料讀出登記在下表:表三

 

第一個Dir_entry結構

第二個Dir_entry結構

第三個Dir_entry結構

偏移地址

4010h

4018h

4020h

欄位Name

0000 0003h

0000 0004h

0000 000Eh

欄位OffsetToData

8000 0028h

8000 0040h

8000 0058h

 由於有三個下級目錄,我們就以第二個IMAGE_RESOURCE_DIRECTORY_ENTRY結構來分析下一級資源結構。

2)二級目錄

  根目錄的IMAGE_RESOURCE_DIRECTORY_ENTRY結構的欄位Name=0000 0004h,最高為0,所以它表示資源型別,低位值為0004h,這個資源的ID號,查詢表一可得這是個選單(Mune資源)。再來看欄位OffsetToData=8000 0040h,明顯最高為是1,所以這個指標指向的是下一級資源目錄。其低31位值是40h,這個就是下級目錄距離根目錄的偏移地址,地址為:

4000h+40h=4040h。我們跳往地址4040h處,得到下圖:

 依次讀出IMAGE_RESOURCE_DIRECTORY結構的六個欄位統計在下表:

 

Charateristics

TimeStamp

MajorVersion

MinnorVersion

NumberOfEntris

NumberOfIdEntries

0000 0000

0000 0000

0000

0000

0000

0000 0001

 

根據最後一個欄位可知,緊跟這結構IMAGE_RESOURCE_DIRECTORY的結構IMAGE_RESOURCE_DIRECTORY_ENTRY只有一個,如下圖:

 我們依次讀出兩個欄位的值:Name=8000 00E8h OffsetToData=8000 0088h。由於欄位Name的最高位是1,所以低位欄位表示指向結構IMAGE_RESOURCE_DATA_STRING_U結構,這個結構儲存了資源名的unicod值,我們跳往40E8h處,如下圖:

 由上圖可知資源名是PEDIY。第二個欄位OffsetToData的最高位是1,低位表示指向下級目錄的地址,我們跳往4088h。

3)第三級目錄

跳轉至地址4088h,我們來到了第三級目錄,如下圖:

 依次讀出六個欄位統計在下表:

Charateristics

TimeStamp

MajorVersion

MinnorVersion

NumberOfEntris

NumberOfIdEntries

0000 0000

0000 0000

0000 0000

0000 0000

0000 0000

0000 0001

根據最後一個欄位可知緊隨結構IMAGE_RESOURCE_DIRECTORY只有一個IMAGE_RESOURCE_DIRECTORY_ENTRY結構,如下圖:

 欄位Name=0000 0409h,欄位OffsetToData=0000 00C8h。在第三級目錄中Name欄位表示內碼表編號,這裡是409表示英語,OffsetToData最高位是0,低31位作為指標指向資源資料入口結構(IMAGE_RESOURCE_DATA_ENTRY)。該結構的定義如下:

IMAGE_RESOURCE_DATA_ENTRY STRUCT

   {

OffsetToData  DWORD //資源資料的RVA

Size         DWORD//資源資料的長度

CodePage    DWORD//內碼表,一般為0

Reserved     DWORD//保留欄位

};IMAGE_RESOURCE_DATA_ENTRY ENDS

我們直接跳轉至40c8h處,如下圖:

 

逐個讀出各個欄位的值統計在下表中:

OffsetToData

Size

CodePage

Reserved

0000 4400

0000 005a

0000 0000

0000 0000

至此,我們總算找到了資源的真正地址即在欄位OffsetToData=4400h,大小為欄位Size=5ah。  

如下圖就是資源: