Windows 將程序的各種界面定義為資源,包括加速鍵(Accelerator)、位圖(Bitmap)、光標(Cursor)、對話框(Dialog Box)、圖標(Icon)、菜單(Menu)、串表(String Table)、工具欄(Toolbar)和版本信息(Version Information)等。
資源有很多種類型,每種類型的資源中可能存在多個資源項,這些資源項用不同的ID 或者名稱來區分。但是要將這么多種類型的不同ID 的資源有序地組織起來是一件非常痛苦的事情,因此,我們采取類似於磁盤目錄結構的方式保存。
PE 文件中的資源是按照 資源類型 -> 資源ID -> 資源代碼頁 的3層樹型目錄結構來組織資源的,通過層層索引才能夠進入相應的子目錄找到正確的資源。
資源目錄結構:
數 據目錄表中的 IMAGE_DIRECTORY_ENTRY_RESOURCE 條目(第三項)包含資源的 RVA 和大小。資源目錄結構中的每一個節點都是由 IMAGE_RESOURCE_DIRECTORY 結構和緊跟其后的數個IMAGE_RESOURCE_DIRECTORY_ENTRY 結構組成的。
我們再來看這張圖:
IMAGE_RESOURCE_DIRECTORY STRUCT 【資源表位於數據目錄表的第三項,共動態分配字節,其中結構體中的成員指出的RVA偏移量都是對於此結構體的地址作為基地址】 { +00 h DWORD Characteristics ; 理論上為資源的屬性,不過事實上總是0 +04 h DWORD TimeDateStamp ; 資源的產生時刻 +08 h WORD MajorVersion ; 理論上為資源的版本,不過事實上總是0 +0A h WORD MinorVersion +0C h WORD NumberOfNamedEntries ; 以名稱(字符串)命名的入口數量 +0E h WORD NumberOfIdEntries ; 以ID(整型數字)命名的入口數量 };IMAGE_RESOURCE_DIRECTORY ENDS
后面緊接着一個結構體,個數由上個結構指出:
IMAGE_RESOURCE_DIRECTORY_ENTRY STRUCT { +10 h DWORD Name ; 目錄項的名稱字符串指針或ID,高位為1時指向子結構體一 +14 h DWORD OffsetToData ; 目錄項指針,高位為1時指向子結構體二 };IMAGE_RESOURCE_DIRECTORY_ENTRY ENDS
Name 字段完全是個百變精靈,改字段定義的是目錄項的名稱或ID。
當結構用於第一層目錄時,定義的是資源類型;
當結構定義於第二層目錄時,定義的是資源的名稱;
當結構用於第三層目錄時,定義的是代碼頁編號。
注意:
當最高位為 0 的時候,表示字段的值作為 ID 使用;
而最高位為 1 的時候,字段的低位作為指針使用(資源名稱字符串是使用 UNICODE編碼),但是這個指針不是直接指向字符串,而是指向一個IMAGE_RESOURCE_DIR_STRING_U 結構的。
子結構體一:
IMAGE_RESOURCE_DIR_STRING_U STRUCT { +00 h DWORD Length ; 字符串的長度 +04 h DWORD NameString ; UNICODE字符串,由於字符串是不定長的。由Length 制定長度 };IMAGE_RESOURCE_DIR_STRING_U ENDS
OffsetOfData 字段是一個指針,
當最高位為 1 時,低位數據指向下一層目錄塊的其實地址;
當最高位為 0 時,指針指向 IMAGE_RESOURCE_DATA_ENTRY 結構。
注意:將 Name 和 OffsetToData 用做指針時需要注意,該指針是從資源區塊開始的地方算起的偏移量(即根目錄的起始位置的偏移量),不是我們習慣的 RVA 哦。
最后,在上圖中我們看到,在第一層的時候,IMAGE_RESOURCE_DIRECTORY_ENTRY 的Name 字段作為資源類型使用。
具體類型匹配見下表:
經 過三層 IAMGE_RESOURCE_DIRECTORY_ENTRY (一般是3層,偶爾少一些。第一層資源類型,第二層資源名,第三層是資源的 Language),第三層目錄結構中的 OffsetOfData 指向 IMAGE_RESOURCE_DATA_ENTRY 結構。該結構描述了資源數據的位置和大小,定義如下:
子結構體二:
IMAGE_RESOURCE_DATA_ENTRY STRUCT { +00 h DWORD OffsetToData ; 資源數據的RVA +04 h DWORD Size ; 資源數據的長度 +08 h DWORD CodePage ; 代碼頁, 一般為0 +0C h DWORD Reserved ; 保留字段 };IMAGE_RESOURCE_DATA_ENTRY ENDS
此處的 IMAGE_RESOURCE_DATA_ENTRY 結構就是真正的資源數據了。結構中的OffsetOfData 指向資源數據的指針,其為 RVA 值