PE文件格式詳解(八)


0x00 前言

  前面了解了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)。

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

0x03 實例講解資源的結構

工具:hexworkshoplordPE,目標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。  

如下圖就是資源:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM