25. PE结构-PE详解之资源
資源結構
資源是PE 文件中非常重要的部分,幾乎所有的PE 文件中都包含著資源,與導入表和導出表相比,資源的組織方式要復雜很多,其實我們只要看下圖就知道俺所言不虛。
分3級:1 資源類型 ,2 資源ID, 3 資源代碼頁, 4 最后指向資源
我們知道我們的資源有很多種類型,每種類型的資源中可能存在多個資源項,這些資源項用不同的ID 或者名稱來區分。但是要將這么多種類型的不同ID 的資源有序地組織起來是一件非常痛苦的事情,因此,我們采取類似于磁盤目錄結構的方式保存。
從圖中我們可以看到,PE 文件中的資源是按照 資源類型 -> 資源ID -> 資源代碼頁 的3層樹型目錄結構來組織資源的,通過層層索引才能夠進入相應的子目錄找到正確的資源。
資源目錄結構
數據目錄表中的 IMAGE_DIRECTORY_ENTRY_RESOURCE 條目(第三項)包含資源的 RVA 和大小。資源目錄結構中的每一個節點都是由 IMAGE_RESOURCE_DIRECTORY(深灰色) 結構和緊跟其后的數個IMAGE_RESOURCE_DIRECTORY_ENTRY 結構組成的(淺灰色)。(是不是有點像我們之前提到的文件目錄?文件夾每個都長得一樣,一個嵌套另一個,這樣子可以實現將非常復雜的數據細化切分,小澤瑪利亞、蒼井空、吉澤明步、松島楓……)
我們再來看這張圖:
認識了這層關系后,我們來看下?IMAGE_RESOURCE_DIRECTORY 這個結構,該結構長度為 16 字節,共有 6 個字段,定義如下:
IMAGE_RESOURCE_DIRECTORY STRUCT
? ? Characteristics??????? DWORD????? ??? ;理論上為資源的屬性,不過事實上總是0
? ? TimeDateStamp????? DWORD????? ??? ;資源的產生時刻
? ? MajorVersion????????? WORD????? ? ??? ;理論上為資源的版本,不過事實上總是0
? ? MinorVersion????????? WORD???? ?? ?
? ? NumberOfNamedEntries? WORD???? ??? ;以名稱(字符串)命名的入口數量
? ? NumberOfIdEntries???????? WORD???? ??? ;以ID(整型數字)命名的入口數量
IMAGE_RESOURCE_DIRECTORY ENDS
其實在這里邊我們唯一要注意的就是 NameberOfNamedEntries 和 NumberOfIdEntries,它們說明了本目錄中目錄項的數量。兩者加起來就是本目錄中的目錄項總和。也就是后邊跟著的
IMAGE_RESOURCE_DIRECTORY_ENTRY 數目。
資源目錄入口的結構(IMAGE_RESOURCE_DIRECTORY_ENTRY)
IMAGE_RESOURCE_DIRECTORY_ENTRY 緊跟在資源目錄結構后,此結構長度為 8 個字節,包含 2 個字段。該結構定義如下:
IMAGE_RESOURCE_DIRECTORY_ENTRY STRUCT
? ? Name????????????????? DWORD??? ??? ;目錄項的名稱字符串指針或ID
? ? OffsetToData??????? DWORD??? ??? ;目錄項指針
IMAGE_RESOURCE_DIRECTORY_ENTRY ENDS
Name 字段完全是個百變精靈,改字段定義的是目錄項的名稱或ID。當結構用于第一層目錄時,定義的是資源類型;當結構定義于第二層目錄時,定義的是資源的名稱;當結構用于第三層目錄時,定義的是代碼頁編號。
注意:當最高位為 0? 的時候,表示字段的值作為 ID 使用;而最高位為 1 的時候,字段的低位作為指針使用(資源名稱字符串是使用 UNICODE編碼),但是這個指針不是直接指向字符串哦,而是指向一個 IMAGE_RESOURCE_DIR_STRING_U 結構的。
該結構定義如下:
IMAGE_RESOURCE_DIR_STRING_U STRUCT
? ? Length???????????? DWORD?????? ??? ; 字符串的長度
? ? NameString????? DWORD?????? ??? ; 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
? ? ?OffsetToData ??? DWORD ??? ???? ; 資源數據的RVA
? ? ?Size ??? ??? ???????? DWORD ??? ???? ; 資源數據的長度
? ? ?CodePage ??? ???? DWORD ??? ???? ; 代碼頁, 一般為0
? ? ?Reserved ??? ????? DWORD ??? ? ?? ; 保留字段
MAGE_RESOURCE_DATA_ENTRY ENDS
此處的?IMAGE_RESOURCE_DATA_ENTRY 結構就是真正的資源數據了。結構中的OffsetOfData 指向資源數據的指針,其為 RVA 值。
總結
以上是生活随笔為你收集整理的25. PE结构-PE详解之资源的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Qt:Windows编程—Qt实现本地服
- 下一篇: Shell脚本编程:使用shell打印九