PE格式第九講,資源表解析
一丶熟悉Windows管理文件的方法
首先,為什么標題是這個,主要是為了下邊講解資源方便,因為資源結構體很亂.如果直接拿出來講解,那么就會很暈.
1.windows管理文件方法
樹形結構
可以看出結構
根目錄
子目錄
文件.xxx
子目錄
子目錄 (子目錄里面還可以有文件夾).....
那么我們的資源也是這樣存儲的.
二丶資源結構體解析
首先,資源結構體分為很多個,但是有用的就3個.一般也分為三個
IMAGE_RESOURCE_DIRECTORY 根目錄(資源目錄頭)
IMAGE_RESOURCE_DIRECTORY_ENTRY 子目錄(資源目錄項)其中根目錄下可以有很多子目錄(也就是說根目錄下會有子目錄的)
IMAGE_RESOURCE_DATA_ENTRY 文件(資源數據)
結構體解析:
1.資源目錄頭(也可以看做管理文件的根目錄)
typedef struct _IMAGE_RESOURCE_DIRECTORY { DWORD Characteristics; 資源屬性 DWORD TimeDateStamp; 時間戳 WORD MajorVersion; 資源大版本號 WORD MinorVersion; 資源小版本號 WORD NumberOfNamedEntries; 按照名稱命名的數量 WORD NumberOfIdEntries; 按照ID命名的數量 // IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; } IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;
首先我們看到資源目錄頭的結構體了,這里大家要知道,有用的就最后兩個成員,還有一段注釋.
1.按照名稱命名的數量
意思就是我們的資源是字符串命名加載的有多少個
2.按照ID命名的數量
意思就是我們的資源如果按照ID有多少個.
一般都是用ID的.
最后兩個字段主要是資源的標識,是以ID的有多少個,以字符串標識的有多少個.
2.資源目錄項(子目錄)
typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { union { struct { DWORD NameOffset:31; 位段: 低31位飄逝偏移 定義了目錄項的名稱或者ID DWORD NameIsString:1; 位段: 高位, 如果這位為1,則表示31位的偏移指向的是一個Unicode字符串的指針偏移 }; 這里列出結構體,自己去看,IMAGE_RESOURCE_DIR_STRING_U 里面是字符串長度還有字符串,不是\0結尾 DWORD Name; WORD Id; }; union { DWORD OffsetToData; 偏移RVA因為是聯合體,所以有不同的解釋 struct { DWORD OffsetToDirectory:31; 看高位,如果高位是1,那么RVA偏移指向的是新的(根目錄) DWORD DataIsDirectory:1; }; }; } IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;
前邊我們說了
根目錄(資源目錄頭)下面存放的是這個結構體,這個結構體是一個聯合體,所以會有不同的解釋
1.首先,聯合體是8個字節大小.
2.其中第一個DWORD大小,看高位,如果高位是1,那么低31位是指向新的目錄項名稱的結構體IMAGE_RESOURCE_DIR_STRING_U
3.如果高位為0,則是ID號,這個ID號說的是 資源ID類型,比如3類型指的就是ICON
具體,可以隨便寫個RT_XXX開頭的宏去查看.
這里我寫下,跟一下看看.
4.第二個DWORD量,也是RVA偏移,如果高位為1,那么代表它還是一個目錄,也就是指向了一個新的根目錄了,這是個不斷遞歸的過程.
如果不是,則指向文件偏移結構體了.
文件偏移結構體:(應該是資源數據結構體)
typedef struct _IMAGE_RESOURCE_DATA_ENTRY { DWORD OffsetToData; 資源數據的偏移RVA DWORD Size; 大小 DWORD CodePage; 代碼頁緩沖(CMD設置窗口的時候就是這個,沒用) DWORD Reserved; 保留 } IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;
這個就很簡單了,直接前邊4個字節指向就是ICON資源的位置.
三丶實戰演練,定位ICON資源.
看了上面結構體,可能會暈,因為聯合體很多,不同的方式有不同的解釋方法,那么一步一步的跟隨
1.首先通過數據目錄定位資源根目錄(也就是根目錄,占16個字節,第一個結構體)
由此得出 RVA = 1B000
然后查看屬於哪個節
由此得出,節的虛擬地址也是從1b000開始的,那么直接看文件偏移即可.
因為此時FA = RVA了,為了方便,一次截圖就指明了,在文件的7800h位置
然后我們定位到7800h的位置
2.找到位置,查看結構體
找到位置后,我們對比結構體成員,看看是什么一次,因為這個是資源根目錄,所以查看資源根目錄結構體
typedef struct _IMAGE_RESOURCE_DIRECTORY { DWORD Characteristics; DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; WORD NumberOfNamedEntries; WORD NumberOfIdEntries; // IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; } IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;
我們發現,意思就是按照ID分類的資源有多少個,我們得出是7個,字符串標識的資源有0個,所以不用看了.
3.定位資源目錄項(子目錄)
我們知道,資源根目錄下面是子目錄,現在有7個按照ID分類的資源,那么就有7個資源目錄項(子目錄)
我們看下結構體.
typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { union { struct { DWORD NameOffset:31; DWORD NameIsString:1; }; DWORD Name; WORD Id; }; union { DWORD OffsetToData; struct { DWORD OffsetToDirectory:31; DWORD DataIsDirectory:1; }; }; } IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;
首先,我們不要被這個結構體弄暈.我們首先要知道結構體的大小
結構體是2個union(聯合體,共用體),而里面的最大類型是DWORD,所以這個結構體大小是8個字節.
那么我們就知道了,在資源根目錄下有7各這樣的數組大小,也就是 7 * 8 = 56字節,整個數組占56個字節
那么我們看下
第二個紅色箭頭沒有弄完,截圖就完了,不好意思,第二個箭頭的意思就是,整個56個字節,是資源目錄項,其中黃色區域,屬於第一個資源目錄項
那么根據上面的結構體,我們先看黃色區域的第一的4個字節,看看高位是否是1
這里有兩種解釋方式
1.如果高位為1,那么表示一個字符串,那么低31位指向了一個字符串結構體
2.如果高位為0,那么表示是一個雙字節的ID (資源類型)
現在得出 00000003 很顯然,高位為0,那么表示一個資源類型,而資源類型上面看過了,3表示是一個ICON
那么在看黃色區域的第二的4個字節
1.高位為1,那么低31位表示指向了一個新的"根目錄" (結構體大小還是16個字節,還是最后4個字節有用,也就是上面第一個結構體)
2.如果高位為0,那么低31位表示指向了一個資源數據結構體(可以表示為文件)
現在得出, 80000048 很顯然高位為1,因為高1位是個8,那么低31位則表示指向一個新的"根目錄"
得出RVA偏移得48
那么根據剛才的FA = RVA FA = 7800 那么現在新的目錄的FA = 7800 + 48 = 7848
那么在7848h表示新的根目錄,跟過去看下.
4.定位新的根目錄
可以看出,有是4個新的數據目錄項,那么我們接着看下4個數組是什么.
我們還是繼續,看資源類型為3的,通過上圖,我們得出,資源數據類型為三的(ICON)的高4個字節的高1位還是8
也就會80000140,那么意思就是又指向了一個新的"根目錄"
5.繼續尋找新的根目錄
上圖得出 偏移是140 FA = 7800 + 140 = 7940
那么文件位置7940是新的根目錄,接着數16個字節.
我們看到7940位置是一個新的根目錄,那么我們看出,它按照ID分類,就一項了,那么下面8個字節就是數據目錄項了.(子目錄)
那么我們由此得出,它的高位不是1,
現在的 00000238 高位不是1了,那么根據 "子目錄"結構體的定義,高位不是1那么這個RVA偏移則是指向了一個文件結構體的偏移
我們繼續計算FA ,一致FA = 7800 ,得出的RVA = 238 則FA = 7800+238 = 7A38h
6.定位資源數據(文件)
那么我們定義為7A38的位置,看下資源數據結構是什么樣子
為了防止大家結構體忘記,重新拷貝到這里觀看.
typedef struct _IMAGE_RESOURCE_DATA_ENTRY { DWORD OffsetToData; DWORD Size; DWORD CodePage; DWORD Reserved; } IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;
就第一個個成員有用,4個字節,表示ICON的RVA偏移.
那么定位到7A38
得出第一個成員的RVA偏移是 0001c018
RVA = 1C018
按照FA = RVA ,的知剛才的RVA = 1B000
求FA = ?
FA = 1C018 - 1B000 + 7800 = 8818
那么文件偏移8818的位置,則是ICON的數據了.
我們看下.
可以看出,很像圖標資源了,那么此時,我們去看下我們的圖標二進制,是不是這個.
對比文件
我們可以看出,位置確實是這個地方了.那么此時就已經成功的找到了ICON類型的資源了