• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            aurain
            技術文摘
            posts - 137,  comments - 268,  trackbacks - 0
            程序所用到的各種資源,比如 bmp,cursor,menu,對話框等都存在PE文件中。
                我們將詳細介紹關于資源的各種結構,通過一個例子來說明資源及其相關結構是怎么放在PE文件中的。以及如何在遍歷PE文件中的所有資源。我們只最終找到這些資源在文件中的位置和長度。而不具體分析某種資源的格式,比如有個BMP的資源,我們不分析BMP格式。

            一 找到資源在文件中位置。

                資源都放在PE文件的某個節中,該節的節表項中的PointerToRawData,就是資源節在文件中的位置。

            1.1 得到PE Header在文件中的位置。
                通過DOS Header結構的成員e_lfanew,可以確定PE Header的在文件中的位置。

            1.2 得到文件中節的數目。
                確定PE Header的在文件中的位置之后,就可以確定PE Header中的成員FileHeader和成員OptionalHeader在文件中的位置。根據 FileHeader 中的 成員NumberOfSections 的值,就可以確定文件中節的數目,也就是節表數組中元素的個數。

            1.3 得到節表在文件中的位置。
                PE Header在文件中的位置加上PE Header結構的大小就可以得到節表在文件中的開始位置。PE Header結構的大小可以由Signature的大小加上FileHeader的大小再加上FileHeader中的SizeOfOptionalHeade來確定。其實到目前為止SizeOfOptionalHeade也就是結構Optional Header的大小也是固定的,所以整個PE Header結構的大小也是固定。不過為了安全起見,還是用Signature的大小加上FileHeader的大小再加上FileHeader中的SizeOfOptionalHeade來確定比較保險。

            1.4 得到資源節在文件中的位置。
                第1.2步中我們確定了文件中節的數目,第1.3步中我們確定了節表在文件中的位置。
                現在有兩種方法來確定資源在文件中的位置。
                第一種方法,根據節的數目,遍歷節表數組。也就是從0到(節表數-1)的每一個節表項。
            比較每一個節表項的Name字段,看是否等于".rsrc"。如果等于。就找到了資源節的節表項。
            這個節表項中的 PointerToRawData 中的值,就是資源節在文件中的位置。
                第二種方法,取得PE Header中的Optional Header中的DataDirectory數組中的第三項,
            也就是資源項。DataDirectory[]數組的每項都是IMAGE_DATA_DIRECTORY結構,該結構定義如下。
            typedef struct _IMAGE_DATA_DIRECTORY {
            DWORD VirtualAddress;
            DWORD Size;
            } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
            取得DataDirectory數組中的第三項中的成員VirtualAddress的值。這個值就是在內存中資源節的RVA。
            然后根據節的數目,遍歷節表數組。也就是從0到(節表數-1)的每一個節表項。
            每個節在內存中的RVA的范圍是從該節表項的成員VirtualAddress字段的值開始(包括這個值),
            到VirtualAddress+Misc.VirtualSize的值結束(不包括這個值)。
            我們遍歷整個節表,看我們取得的資源節的RVA,在哪個節表項的RVA范圍之內。
            如果在范圍之內,就找到了資源節的節表項。
            這個節表項中的 PointerToRawData 中的值,就是資源節在文件中的位置。
            如果這個PE文件沒有資源的話,DataDirectory數組中的第三項內容為0。

            這樣我們就得到了資源在文件中開始的位置。

            二 PE文件中的資源。

                我們已經得到了資源節在文件中的位置。
            資源節最開始是一個IMAGE_RESOURCE_DIRECTORY結構。
            在WINNT.H中定義如下。

            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;
            這個結構長度為16字節,共有6個字段。
            各字段含義如下:
            Characteristics: Resource flags,保留用于以后使用,目前都為0。
            TimeDateStamp:資源編譯器產生資源的時間。
            MajorVersion:
            MinorVersion:
            NumberOfNamedEntries:用字符串來標示IMAGE_RESOURCE_DIRECTORY_ENTRY項的,緊跟著本結構的IMAGE_RESOURCE_DIRECTORY_ENTRY數組的成員個數。
            Number of ID Entries:用整形數字來表示IMAGE_RESOURCE_DIRECTORY_ENTRY項的,緊跟著本結構的IMAGE_RESOURCE_DIRECTORY_ENTRY數組的成員個數。

                IMAGE_RESOURCE_DIRECTORY后面一定會緊跟著一個IMAGE_RESOURCE_DIRECTORY_ENTRY數組。
            IMAGE_RESOURCE_DIRECTORY_ENTRY結構定義如下。

            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;
            這個結構長度為8個字節。共有兩個字段,每個字段4個字節。
            根據不同情況,這兩個字段的含義不一樣。這個結構的定義如果看不懂的話,后面的例子一看就會明白了。
            第一個字段,當第一個字段的最高位是1的時候,表示,這個DWORD的剩下31位表明一個相對于資源開始位置的偏移,這個偏移的內容是一個IMAGE_RESOURCE_DIR_STRING,用里面的字符串來標明這個IMAGE_RESOURCE_DIRECTORY_ENTRY。當第一個字段的最高位是0的時候,表示,這個DWORD的低WORD中的值作為id標明這個IMAGE_RESOURCE_DIRECTORY_ENTRY。
            第二個字段,當第二個字段的最高位是1的時候,表示,還有下一層的結構。這個DWORD的剩下31位表明一個相對于資源開始位置的偏移,這個偏移的內容會是一個下一層的IMAGE_RESOURCE_DIRECTORY結構,這個請看后面的例子中的說明。
            當第二個字段的最高位是0的時候,表示,已經沒有下一層的結構了。這個DWORD的剩下31位表明一個相對于資源開始位置的偏移,這個偏移的內容會是一個IMAGE_RESOURCE_DATA_ENTRY結構,IMAGE_RESOURCE_DATA_ENTRY結構會說明資源的位置。

                標示一個IMAGE_RESOURCE_DIRECTORY_ENTRY一般都是使用id,就是一個整數。
            但是也有少數的使用IMAGE_RESOURCE_DIR_STRING來標示一個IMAGE_RESOURCE_DIRECTORY_ENTRY。
            IMAGE_RESOURCE_DIRECTORY_ENTRY結構定義如下。
            typedef struct _IMAGE_RESOURCE_DIR_STRING_U {
            WORD Length;
            WCHAR NameString[ 1 ];
            } IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U;
            這個結構中將有一個Unicode的字符串,是字對齊的。所有這些用來標識的IMAGE_RESOURCE_DIR_STRING都放在一起,這個結構的長度是可變的,由第一個字段Length指明后面的Unicode字符串的長度。

                經過3層IMAGE_RESOURCE_DIRECTORY_ENTRY(一般是3層,也有可能更少些。第一層資源類型bmp,menu等等,第二層資源名,第三層是資源的Language。)最終會找到一個IMAGE_RESOURCE_DATA_ENTRY結構,這個結構中存有相應(某資源類型,某資源名,某資源Language)資源的位置和大小,就真正找到資源了。IMAGE_RESOURCE_DATA_ENTRY定義如下。
            typedef struct _IMAGE_RESOURCE_DATA_ENTRY {
            DWORD OffsetToData;
            DWORD Size;
            DWORD CodePage;
            DWORD Reserved;
            } IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;
            這個結構長16個字節,有4個字段。
            OffsetToData:這是一個內存中的RVA,要轉化成文件中的位置,需要用這個值減去資源節的開始RVA,
            資源節的開始RVA可以由Optional Header中的DataDirectory數組中的第三項中的VirtualAddress的值得到。
            或者節表中,資源節那項中的VirtualAddress的值得到。相減之后,就可以得到相對于資源節開始的偏移。
            再加上資源節在文件中的開始位置,節表中資源節那項中的PointerToRawData的值,就是資源在文件中的位置。

            Size:資源的大小,以字節為單位。
            CodePage:一般來說是Unicode code page。
            Reserved:保留,值為0。

            上面是資源各種結構的說明,知道這些結構還遠遠不夠,下面我們通過一個例子來看如何通過這些結構找到資源。

            我們的例子是Win2k中的可執行文件telnet.exe。為了防止大家版本不同,本文附帶了這個PE文件。

            PE文件的資源的各種結構放在一個樹型結構中,這個結構一般有3層,如圖4.1,就是telnet.exe中的情況。

             

            圖4.1

            圖中長的長方形表示一個IMAGE_RESOURCE_DIRECTORY結構,長16個字節,簡稱directory。
            圖中短的長方形表示一個IMAGE_RESOURCE_DIRECTORY_ENTRY結構,長8個字節,簡稱directory_entry。
            圖中圓圈表示一個IMAGE_RESOURCE_DATA_ENTRY結構,長16個字節,簡稱data_entry。

            為了以后的敘述方便還給樹的每一個節點起了名字,第一層的叫11,第二層的叫21,22,23,24,第三層的叫31,32,33,34,35,36,37,38,39,310,311,312。

            在資源節開始處,是一個directory結構,這個結構中指明了緊跟在它后面的一個directory_entry結構數組中的元素的個數。這個directory結構之后,緊跟著的就是那個directory_entry結構數組。他們一起組成了11。就如圖4.1中所示。其他的每個節點,21,22..31,32..312,都是這樣,每個 directory結構后面緊跟directory_entry 結構數組。11中的directory_entry結構數組中的每一個元素,都存有到下一層某個節點的偏移。也就是通過directory_entry結構數組的每個元素可以找到21,22,23,24。其他的節點中情況也是一樣。圖中看不到的一點是,所有的節點之間都是緊緊的挨在一起存放的,11之后緊跟著的是21,21之后緊跟著的是22,22之后緊跟著的是23。依此類推。directory_entry結構數組中的每一個元素除了有到下一層某節點的偏移,(是下一層的節點,還是已經到了最終的data_entry,后面詳細敘述)還有一個Name或者Id字段(是Name還是Id后面詳細敘述),根據不同的層,代表的含義也不一樣。第一層的每個directory_entry的這個值,代表類型。比如11的第一個directory_entry的Id值為3,3代表icon,從這個directory_entry往下的都是都是圖標了(關于不同類型值的定義,后面詳細敘述)。第二層每個directory_entry的這個值代表Name,第三層代表Language。11,21,31的左邊那個data_entry,的三個值分別為3,1,409(都是16進制),就是說是一個圖標類型,Name為1h,Language為409h的資源。

            下面我們來通過telnet.exe中資源節的具體內容來看,用開始講到的尋找資源節在文件中位置的方法,我們找到了資源節在文件中的位置為00013600h。

            我們為了看起來清楚,每一行是一個結構,并且每個結構的不同成員用 / 分開,例如,
            一個directory結構 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 04 00  
            可以看到結構成員,Characteristics為0,TimeDateStamp為0,MajorVersion為4,(如果你不明白為什么是0004而不是0400的話,請看 《JIURL PE 格式學習總結(一)》中關于 big-endian和little-endian的介紹),MinorVersion為0,NumberOfNamedEntries為0,NumberOfIdEntries為4。

            一個directory_entry結構 03 00 00 00 / 30 00 00 80 
            可以看到結構成員,第一個字段的第一個字節00h的二進制為00000000,最高位為0,所以低兩個字節中的值為Id,Id為3。第二個字段的第一個字節80h(如果你不明白為什么第一個字節是80h而不是30h的話,請看 《JIURL PE 格式學習總結(一)》中關于 big-endian和little-endian的介紹)的二進制為10000000,最高位為1 所以說明還有下一層,還沒有到葉子,所以第二字段代表到下一層某個節點的偏移 OffsetToData 值為30。

            一個data_entry結構 E0 23 03 00 / 30 01 00 00 / E4 04 00 00 / 00 00 00 00 
            可以看到結構成員,OffsetToData為323E0h(這是一個內存中的RVA,要轉化成文件中的位置,需要用這個值減去資源節的開始RVA,資源節的開始RVA可以由Optional Header中的DataDirectory數組中的第三項中的VirtualAddress的值得到。或者節表中,資源節那項中的VirtualAddress的值得到。相減之后,就可以得到相對于資源節開始的偏移。再加上資源節在文件中的開始位置,節表中資源節那項中的PointerToRawData的值,就是資源在文件中的位置。),Size為130h,CodePage為4E4h,Reserved為0。

            下面就是telnet.exe中的內容,可以用16進制編輯器打開附帶的telnet.exe對照著看。

            00013600h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 04 00 
            (directory結構,16字節長。圖4.1中11中的directory。0個NamedEntries,4個IdEntries。)
            00013610h: 03 00 00 00 / 30 00 00 80
            (directory_entry結構,8字節長。圖4.1中11中的directory_entry數組第一個元素。第一個字段高位為0,說明第一個字段表示id,由于是第一層,所以類型id為3。第二個字段高位為1,說明還有下一層,第二字段中的低31位為到圖4.1中21的偏移,30+00013600h=00013630h。)
            00013618h: 06 00 00 00 / 50 00 00 80
            00013620h: 0E 00 00 00 / A0 00 00 80
            00013628h: 10 00 00 00 / B8 00 00 80
            00013630h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 (directory21)
            00013640h: 01 00 00 00 / D0 00 00 80 (d0+00013600h=000136d0h。)
            00013648h: 02 00 00 00 / F0 00 00 80
            00013650h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 08 00  (directory22)
            00013660h: 08 00 00 00 / 10 01 00 80
            00013668h: 09 00 00 00 / 30 01 00 80
            00013670h: 0C 00 00 00 / 50 01 00 80
            00013678h: 0D 00 00 00 / 70 01 00 80
            00013680h: 10 00 00 00 / 90 01 00 80
            00013688h: 11 00 00 00 / B0 01 00 80
            00013690h: 12 00 00 00 / D0 01 00 80
            00013698h: 39 00 00 00 / F0 01 00 80
            000136a0h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 01 00 / 00 00 
            (directory結構,16字節長。圖4.1中23。1個NamedEntries,0個IdEntries。)
            000136b0h: D0 03 00 80 / 10 02 00 80
            (directory結構中已經表明這是一個NamedEntries,第一個字段中的高位為1,說明第一個字段中的值為一個指向IMAGE_RESOURCE_DIR_STRING結構的偏移,3D0+00013600h=000139D0h。)
            000136b8h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 01 00 (directory24)
            000136c8h: 01 00 00 00 / 30 02 00 80
            000136d0h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 (directory31)
            000136e0h: 09 04 00 00 / 50 02 00 00 
            (directory_entry結構,8字節長。第一個字段高位為0,說明第一個字段表示id,由于是第三層,所以Language id為409h。第二個字段高位為0,說明已經是葉子了,第二字段中的低31位為到一個data_entry結構的偏移,250+00013600h=00013850h。)
            000136e8h: 04 08 00 00 / 60 02 00 00
            000136f0h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 (directory32)
            00013700h: 09 04 00 00 / 70 02 00 00
            00013708h: 04 08 00 00 / 80 02 00 00
            00013710h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 (directory33)
            00013720h: 09 04 00 00 / 90 02 00 00
            00013728h: 04 08 00 00 / A0 02 00 00
            00013730h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 (directory34)
            00013740h: 09 04 00 00 / B0 02 00 00
            00013748h: 04 08 00 00 / C0 02 00 00
            00013750h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 (directory35)
            00013760h: 09 04 00 00 / D0 02 00 00
            00013768h: 04 08 00 00 / E0 02 00 00
            00013770h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 (directory36)
            00013780h: 09 04 00 00 / F0 02 00 00
            00013788h: 04 08 00 00 / 00 03 00 00
            00013790h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 (directory37)
            000137a0h: 09 04 00 00 / 10 03 00 00
            000137a8h: 04 08 00 00 / 20 03 00 00
            000137b0h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 (directory38)
            000137c0h: 09 04 00 00 / 30 03 00 00
            000137c8h: 04 08 00 00 / 40 03 00 00
            000137d0h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 (directory39)
            000137e0h: 09 04 00 00 / 50 03 00 00
            000137e8h: 04 08 00 00 / 60 03 00 00
            000137f0h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 (directory310)
            00013800h: 09 04 00 00 / 70 03 00 00
            00013808h: 04 08 00 00 / 80 03 00 00
            00013810h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 (directory311)
            00013820h: 09 04 00 00 / 90 03 00 00
            00013828h: 04 08 00 00 / A0 03 00 00
            00013830h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 (directory312)
            00013840h: 09 04 00 00 / B0 03 00 00
            00013848h: 04 08 00 00 / C0 03 00 00
            00013850h: E0 23 03 00 / 30 01 00 00 / E4 04 00 00 / 00 00 00 00
            (data_entry結構,16字節長,存有一個資源的RVA和大小。資源節開始處的RVA為32000。先算出該資源相對于資源開始處的偏移323E0-32000=3E0h。再用偏移加上資源節開始處的文件偏移13600得到該資源在文件中的位置,3E0+13600=139E0h。)

            00013850h: 10 25 03 00 / 30 01 00 00 / E4 04 00 00 / 00 00 00 00
            00013850h: 40 26 03 00 / E8 02 00 00 / E4 04 00 00 / 00 00 00 00
            00013860h: 28 29 03 00 / E8 02 00 00 / E4 04 00 00 / 00 00 00 00
            00013870h: 10 2C 03 00 / 70 00 00 00 / E4 04 00 00 / 00 00 00 00
            00013880h: 80 2C 03 00 / 70 00 00 00 / E4 04 00 00 / 00 00 00 00
            00013890h: F0 2C 03 00 / 56 03 00 00 / E4 04 00 00 / 00 00 00 00
            000138a0h: 48 30 03 00 / C0 01 00 00 / E4 04 00 00 / 00 00 00 00
            000138b0h: F0 2C 03 00 / 56 03 00 00 / E4 04 00 00 / 00 00 00 00
            000138c0h: 48 30 03 00 / C0 01 00 00 / E4 04 00 00 / 00 00 00 00
            000138d0h: 08 32 03 00 / A8 01 00 00 / E4 04 00 00 / 00 00 00 00
            000138e0h: B0 33 03 00 / F4 00 00 00 / E4 04 00 00 / 00 00 00 00
            000138f0h: A4 34 03 00 / B6 00 00 00 / E4 04 00 00 / 00 00 00 00
            00013900h: 5C 35 03 00 / 94 00 00 00 / E4 04 00 00 / 00 00 00 00
            00013910h: F0 35 03 00 / 40 04 00 00 / E4 04 00 00 / 00 00 00 00
            00013920h: 30 3A 03 00 / DC 02 00 00 / E4 04 00 00 / 00 00 00 00
            00013930h: 0C 3D 03 00 / 32 02 00 00 / E4 04 00 00 / 00 00 00 00
            00013940h: 40 3F 03 00 / 90 01 00 00 / E4 04 00 00 / 00 00 00 00
            00013950h: D0 40 03 00 / FC 04 00 00 / E4 04 00 00 / 00 00 00 00
            00013960h: CC 45 03 00 / C0 03 00 00 / E4 04 00 00 / 00 00 00 00
            00013970h: 8C 49 03 00 / B6 00 00 00 / E4 04 00 00 / 00 00 00 00
            00013980h: 44 4A 03 00 / 84 00 00 00 / E4 04 00 00 / 00 00 00 00
            00013990h: C8 4A 03 00 / 22 00 00 00 / E4 04 00 00 / 00 00 00 00
            000139a0h: EC 4A 03 00 / 22 00 00 00 / E4 04 00 00 / 00 00 00 00
            000139b0h: 10 4B 03 00 / 60 03 00 00 / E4 04 00 00 / 00 00 00 00
            000139c0h: 70 4E 03 00 / 60 03 00 00 / E4 04 00 00 / 00 00 00 00
            000139d0h: 06 00 / 54 00 45 00 4C 00 4E 00 45 00 54 00 00 00
            (IMAGE_RESOURCE_DIR_STRING結構,長度可變。第一個字段2個字節長,值為6。表明其后的Unicode字符串長度為6。第二字段是一個Unicode字符串,不包括最后的結束符,長度為6,內容是"TELNET\0")
            000139e0h: 28 00 00 00 20 00 00 00 40 00 00 00 01 00 01 00
            000139f0h: ...

            需要補充說明的是,每個directory后面緊跟的是directory_entry數組,directory_entry數組的每個元素,有兩個字段,每個字段的高位用來判斷該字段代表的含義。尤其是第二字段 OffsetToData ,如果高位為1表明還有下一層,指向另一個directory。如果高位為0,表明指向一個data_entry。directory_entry第一個字段通常都是作為id,里面低WORD中的值,用來標示這個directory_entry,很少的情況下,第一字段保存一個到unicode字符串的偏移(本例中000136a0h),用字符串來標示這個directory_entry。如果一個directory后兩個字段都不為0的話,即后面緊跟的directory_entry數組既有NamedEntries,又有IDEntries,那么directory_entry數組首先是NamedEntries之后緊跟著IDEntries。一般情況下都是一般來說都是有三層,第一層中的directory_entry數組的每個元素的id,代表不同的類型,不同類型的值在 WINGDI.H 中定義如下
            #define RT_CURSOR MAKEINTRESOURCE(1)
            #define RT_BITMAP MAKEINTRESOURCE(2)
            #define RT_ICON MAKEINTRESOURCE(3)
            #define RT_MENU MAKEINTRESOURCE(4)
            #define RT_DIALOG MAKEINTRESOURCE(5)
            #define RT_STRING MAKEINTRESOURCE(6)
            #define RT_FONTDIR MAKEINTRESOURCE(7)
            #define RT_FONT MAKEINTRESOURCE(8)
            #define RT_ACCELERATOR MAKEINTRESOURCE(9)
            #define RT_RCDATA MAKEINTRESOURCE(10)
            #define RT_MESSAGETABLE MAKEINTRESOURCE(11)

            #define DIFFERENCE 11
            #define RT_GROUP_CURSOR MAKEINTRESOURCE((DWORD)RT_CURSOR + DIFFERENCE)
            #define RT_GROUP_ICON MAKEINTRESOURCE((DWORD)RT_ICON + DIFFERENCE)
            #define RT_VERSION MAKEINTRESOURCE(16)
            #define RT_DLGINCLUDE MAKEINTRESOURCE(17)
            #if(WINVER >= 0x0400)
            #define RT_PLUGPLAY MAKEINTRESOURCE(19)
            #define RT_VXD MAKEINTRESOURCE(20)
            #define RT_ANICURSOR MAKEINTRESOURCE(21)
            #define RT_ANIICON MAKEINTRESOURCE(22)
            #endif /* WINVER >= 0x0400 */
            #define RT_HTML MAKEINTRESOURCE(23)
            也有可能有不到三層的情況,比如只有類型和Name兩層,沒有Language層。

            我們再來看幾個data_entry
            00013850h: 10 25 03 00 / 30 01 00 00 / E4 04 00 00 / 00 00 00 00
            00013850h: 40 26 03 00 / E8 02 00 00 / E4 04 00 00 / 00 00 00 00
            00013860h: 28 29 03 00 / E8 02 00 00 / E4 04 00 00 / 00 00 00 00
            可以算出 00013850h 處的 data_entry 中,資源的文件位置為 13B10h(32510-32000+13600) 長度為 130h,所以該資源結束處的位置在文件中的 13C40 h處。而一下個data_entry (00013850h處)中,資源在文件中的位置為 13C40h (32640-32000+13600) 長度為 2E8h。我們可以看到兩個資源是首尾相接的,就是說一個資源和另一個資源是緊挨在一起的,中間沒有空隙,其他的資源用相同的方法計算,也可以得到同樣的結論。

            總結,找到資源節開始的位置,首先是一個directory,后面緊跟著directory_entry數組,數組的每個元素代表的資源類型不同,通過每個元素,我們可以找到第二層另一個directory,后面緊跟著directory_entry數組。這一層的數組的每個元素代表的資源Name不同。然后我們可以找到第三層的每個directory,后面緊跟著directory_entry數組。這一層的數組的每個元素代表的資源Language不同。然后通過每個directory_entry我們可以找到每個data_entry。通過每個data_entry,我們就可以找到每個真正的資源。
            本部分內容較為復雜,需要多閱讀幾遍。

            三 遍歷PE文件中的資源

                遍歷那個樹型結構,找到每個資源的方法之一是,

                一個函數,用來處理directory和它后面緊跟著的directory_entry數組。比如叫  DumpResourceDirectory(),它的參數中的一個是一個directory的地址,函數根據這個地址,得到一個directory結構,從中得到directory_entry數組元素的個數。然后for循環遍歷每個元素,對于每個元素做判斷看是否已經到了葉子,也就是directory_entry的第二個字段的高位是否為0,是1表示沒有到葉子,遞歸調用本函數,不過傳入的參數,是根據這個directory_entry中保存的另一個directory的地址。是0表示已經到了葉子,調用另一個處理葉子的函數,傳入相關地址。

               處理葉子的函數,用來處理data_entry結構,負責根據data_entry結構找到真正的資源。比如叫DumpResourceEntry(),它的參數中的一個是一個data_entry的地址。然后跟據data_entry中的值作處理。

               這樣,通過遞歸和判斷,就能遍歷PE文件中所有的資源。

               用這種方法遍歷圖4.1中的樹,順序會是11,21,31,32,22,33,34,35,36,37,38,39,310,23,311,24,312。

                這種遍歷方法的源程序,可以參考 PEDUMP - Matt Pietrek 1995 。《Windows95系統程式設計大奧秘》附書源碼中有。

            posted on 2009-06-29 14:07 閱讀(1427) 評論(2)  編輯 收藏 引用 所屬分類: Windows開發

            FeedBack:
            # re: JIURL PE 格式學習總結(四)-- PE文件中的資源
            2009-07-22 10:37 | daisy
            up...  回復  更多評論
              
            # re: JIURL PE 格式學習總結(四)-- PE文件中的資源
            2010-12-21 12:43 | 路過
            很詳細,相對于資源開始位置的偏移 這個我沒留意弄了好一會1  回復  更多評論
              

            <2008年2月>
            272829303112
            3456789
            10111213141516
            17181920212223
            2425262728291
            2345678

            常用鏈接

            留言簿(17)

            隨筆分類(138)

            隨筆檔案(137)

            網絡開發

            最新隨筆

            搜索

            •  

            積分與排名

            • 積分 - 499069
            • 排名 - 36

            最新隨筆

            最新評論

            閱讀排行榜

            評論排行榜

            久久久噜噜噜久久| 久久91精品国产91| 秋霞久久国产精品电影院| 精品久久人妻av中文字幕| 国产欧美一区二区久久| 国产精品热久久无码av| 久久国产欧美日韩精品| 国产三级久久久精品麻豆三级| 狠狠色丁香婷婷综合久久来来去 | 久久久久人妻一区二区三区 | 久久久WWW免费人成精品| 亚洲一区精品伊人久久伊人| 久久精品国产亚洲av麻豆色欲| 久久精品亚洲乱码伦伦中文| 久久久av波多野一区二区| 青青青青久久精品国产h久久精品五福影院1421 | 一级做a爰片久久毛片看看| 久久99精品国产麻豆| 久久伊人五月丁香狠狠色| 久久91精品国产91久久户| 久久人人爽人人人人爽AV| 狠狠人妻久久久久久综合| 99久久免费国产精精品| 亚洲天堂久久久| 欧美一级久久久久久久大片| 国产精品久久久久乳精品爆 | 亚洲AV日韩精品久久久久| 欧美久久一区二区三区| 国产免费久久精品丫丫| 久久91精品国产91久久户| 国产精品一久久香蕉国产线看 | 久久久久久久精品妇女99| 日日狠狠久久偷偷色综合0| 久久国产成人午夜aⅴ影院| 伊人热人久久中文字幕| 精品一区二区久久久久久久网站| 久久久久亚洲AV片无码下载蜜桃| 无码专区久久综合久中文字幕| 综合久久国产九一剧情麻豆| 无码人妻久久一区二区三区免费丨| 狠狠色狠狠色综合久久|