• <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
            技術(shù)文摘
            posts - 137,  comments - 268,  trackbacks - 0
            程序所用到的各種資源,比如 bmp,cursor,menu,對(duì)話框等都存在PE文件中。
                我們將詳細(xì)介紹關(guān)于資源的各種結(jié)構(gòu),通過一個(gè)例子來說明資源及其相關(guān)結(jié)構(gòu)是怎么放在PE文件中的。以及如何在遍歷PE文件中的所有資源。我們只最終找到這些資源在文件中的位置和長度。而不具體分析某種資源的格式,比如有個(gè)BMP的資源,我們不分析BMP格式。

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

                資源都放在PE文件的某個(gè)節(jié)中,該節(jié)的節(jié)表項(xiàng)中的PointerToRawData,就是資源節(jié)在文件中的位置。

            1.1 得到PE Header在文件中的位置。
                通過DOS Header結(jié)構(gòu)的成員e_lfanew,可以確定PE Header的在文件中的位置。

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

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

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

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

            二 PE文件中的資源。

                我們已經(jīng)得到了資源節(jié)在文件中的位置。
            資源節(jié)最開始是一個(gè)IMAGE_RESOURCE_DIRECTORY結(jié)構(gòu)。
            在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;
            這個(gè)結(jié)構(gòu)長度為16字節(jié),共有6個(gè)字段。
            各字段含義如下:
            Characteristics: Resource flags,保留用于以后使用,目前都為0。
            TimeDateStamp:資源編譯器產(chǎn)生資源的時(shí)間。
            MajorVersion:
            MinorVersion:
            NumberOfNamedEntries:用字符串來標(biāo)示IMAGE_RESOURCE_DIRECTORY_ENTRY項(xiàng)的,緊跟著本結(jié)構(gòu)的IMAGE_RESOURCE_DIRECTORY_ENTRY數(shù)組的成員個(gè)數(shù)。
            Number of ID Entries:用整形數(shù)字來表示IMAGE_RESOURCE_DIRECTORY_ENTRY項(xiàng)的,緊跟著本結(jié)構(gòu)的IMAGE_RESOURCE_DIRECTORY_ENTRY數(shù)組的成員個(gè)數(shù)。

                IMAGE_RESOURCE_DIRECTORY后面一定會(huì)緊跟著一個(gè)IMAGE_RESOURCE_DIRECTORY_ENTRY數(shù)組。
            IMAGE_RESOURCE_DIRECTORY_ENTRY結(jié)構(gòu)定義如下。

            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;
            這個(gè)結(jié)構(gòu)長度為8個(gè)字節(jié)。共有兩個(gè)字段,每個(gè)字段4個(gè)字節(jié)。
            根據(jù)不同情況,這兩個(gè)字段的含義不一樣。這個(gè)結(jié)構(gòu)的定義如果看不懂的話,后面的例子一看就會(huì)明白了。
            第一個(gè)字段,當(dāng)?shù)谝粋€(gè)字段的最高位是1的時(shí)候,表示,這個(gè)DWORD的剩下31位表明一個(gè)相對(duì)于資源開始位置的偏移,這個(gè)偏移的內(nèi)容是一個(gè)IMAGE_RESOURCE_DIR_STRING,用里面的字符串來標(biāo)明這個(gè)IMAGE_RESOURCE_DIRECTORY_ENTRY。當(dāng)?shù)谝粋€(gè)字段的最高位是0的時(shí)候,表示,這個(gè)DWORD的低WORD中的值作為id標(biāo)明這個(gè)IMAGE_RESOURCE_DIRECTORY_ENTRY。
            第二個(gè)字段,當(dāng)?shù)诙€(gè)字段的最高位是1的時(shí)候,表示,還有下一層的結(jié)構(gòu)。這個(gè)DWORD的剩下31位表明一個(gè)相對(duì)于資源開始位置的偏移,這個(gè)偏移的內(nèi)容會(huì)是一個(gè)下一層的IMAGE_RESOURCE_DIRECTORY結(jié)構(gòu),這個(gè)請(qǐng)看后面的例子中的說明。
            當(dāng)?shù)诙€(gè)字段的最高位是0的時(shí)候,表示,已經(jīng)沒有下一層的結(jié)構(gòu)了。這個(gè)DWORD的剩下31位表明一個(gè)相對(duì)于資源開始位置的偏移,這個(gè)偏移的內(nèi)容會(huì)是一個(gè)IMAGE_RESOURCE_DATA_ENTRY結(jié)構(gòu),IMAGE_RESOURCE_DATA_ENTRY結(jié)構(gòu)會(huì)說明資源的位置。

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

                經(jīng)過3層IMAGE_RESOURCE_DIRECTORY_ENTRY(一般是3層,也有可能更少些。第一層資源類型bmp,menu等等,第二層資源名,第三層是資源的Language。)最終會(huì)找到一個(gè)IMAGE_RESOURCE_DATA_ENTRY結(jié)構(gòu),這個(gè)結(jié)構(gòu)中存有相應(yīng)(某資源類型,某資源名,某資源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;
            這個(gè)結(jié)構(gòu)長16個(gè)字節(jié),有4個(gè)字段。
            OffsetToData:這是一個(gè)內(nèi)存中的RVA,要轉(zhuǎn)化成文件中的位置,需要用這個(gè)值減去資源節(jié)的開始RVA,
            資源節(jié)的開始RVA可以由Optional Header中的DataDirectory數(shù)組中的第三項(xiàng)中的VirtualAddress的值得到。
            或者節(jié)表中,資源節(jié)那項(xiàng)中的VirtualAddress的值得到。相減之后,就可以得到相對(duì)于資源節(jié)開始的偏移。
            再加上資源節(jié)在文件中的開始位置,節(jié)表中資源節(jié)那項(xiàng)中的PointerToRawData的值,就是資源在文件中的位置。

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

            上面是資源各種結(jié)構(gòu)的說明,知道這些結(jié)構(gòu)還遠(yuǎn)遠(yuǎn)不夠,下面我們通過一個(gè)例子來看如何通過這些結(jié)構(gòu)找到資源。

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

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

             

            圖4.1

            圖中長的長方形表示一個(gè)IMAGE_RESOURCE_DIRECTORY結(jié)構(gòu),長16個(gè)字節(jié),簡稱directory。
            圖中短的長方形表示一個(gè)IMAGE_RESOURCE_DIRECTORY_ENTRY結(jié)構(gòu),長8個(gè)字節(jié),簡稱directory_entry。
            圖中圓圈表示一個(gè)IMAGE_RESOURCE_DATA_ENTRY結(jié)構(gòu),長16個(gè)字節(jié),簡稱data_entry。

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

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

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

            我們?yōu)榱丝雌饋砬宄恳恍惺且粋€(gè)結(jié)構(gòu),并且每個(gè)結(jié)構(gòu)的不同成員用 / 分開,例如,
            一個(gè)directory結(jié)構(gòu) 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 04 00  
            可以看到結(jié)構(gòu)成員,Characteristics為0,TimeDateStamp為0,MajorVersion為4,(如果你不明白為什么是0004而不是0400的話,請(qǐng)看 《JIURL PE 格式學(xué)習(xí)總結(jié)(一)》中關(guān)于 big-endian和little-endian的介紹),MinorVersion為0,NumberOfNamedEntries為0,NumberOfIdEntries為4。

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

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

            下面就是telnet.exe中的內(nèi)容,可以用16進(jìn)制編輯器打開附帶的telnet.exe對(duì)照著看。

            00013600h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 04 00 
            (directory結(jié)構(gòu),16字節(jié)長。圖4.1中11中的directory。0個(gè)NamedEntries,4個(gè)IdEntries。)
            00013610h: 03 00 00 00 / 30 00 00 80
            (directory_entry結(jié)構(gòu),8字節(jié)長。圖4.1中11中的directory_entry數(shù)組第一個(gè)元素。第一個(gè)字段高位為0,說明第一個(gè)字段表示id,由于是第一層,所以類型id為3。第二個(gè)字段高位為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結(jié)構(gòu),16字節(jié)長。圖4.1中23。1個(gè)NamedEntries,0個(gè)IdEntries。)
            000136b0h: D0 03 00 80 / 10 02 00 80
            (directory結(jié)構(gòu)中已經(jīng)表明這是一個(gè)NamedEntries,第一個(gè)字段中的高位為1,說明第一個(gè)字段中的值為一個(gè)指向IMAGE_RESOURCE_DIR_STRING結(jié)構(gòu)的偏移,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結(jié)構(gòu),8字節(jié)長。第一個(gè)字段高位為0,說明第一個(gè)字段表示id,由于是第三層,所以Language id為409h。第二個(gè)字段高位為0,說明已經(jīng)是葉子了,第二字段中的低31位為到一個(gè)data_entry結(jié)構(gòu)的偏移,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結(jié)構(gòu),16字節(jié)長,存有一個(gè)資源的RVA和大小。資源節(jié)開始處的RVA為32000。先算出該資源相對(duì)于資源開始處的偏移323E0-32000=3E0h。再用偏移加上資源節(jié)開始處的文件偏移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結(jié)構(gòu),長度可變。第一個(gè)字段2個(gè)字節(jié)長,值為6。表明其后的Unicode字符串長度為6。第二字段是一個(gè)Unicode字符串,不包括最后的結(jié)束符,長度為6,內(nèi)容是"TELNET\0")
            000139e0h: 28 00 00 00 20 00 00 00 40 00 00 00 01 00 01 00
            000139f0h: ...

            需要補(bǔ)充說明的是,每個(gè)directory后面緊跟的是directory_entry數(shù)組,directory_entry數(shù)組的每個(gè)元素,有兩個(gè)字段,每個(gè)字段的高位用來判斷該字段代表的含義。尤其是第二字段 OffsetToData ,如果高位為1表明還有下一層,指向另一個(gè)directory。如果高位為0,表明指向一個(gè)data_entry。directory_entry第一個(gè)字段通常都是作為id,里面低WORD中的值,用來標(biāo)示這個(gè)directory_entry,很少的情況下,第一字段保存一個(gè)到unicode字符串的偏移(本例中000136a0h),用字符串來標(biāo)示這個(gè)directory_entry。如果一個(gè)directory后兩個(gè)字段都不為0的話,即后面緊跟的directory_entry數(shù)組既有NamedEntries,又有IDEntries,那么directory_entry數(shù)組首先是NamedEntries之后緊跟著IDEntries。一般情況下都是一般來說都是有三層,第一層中的directory_entry數(shù)組的每個(gè)元素的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層。

            我們?cè)賮砜磶讉€(gè)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,所以該資源結(jié)束處的位置在文件中的 13C40 h處。而一下個(gè)data_entry (00013850h處)中,資源在文件中的位置為 13C40h (32640-32000+13600) 長度為 2E8h。我們可以看到兩個(gè)資源是首尾相接的,就是說一個(gè)資源和另一個(gè)資源是緊挨在一起的,中間沒有空隙,其他的資源用相同的方法計(jì)算,也可以得到同樣的結(jié)論。

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

            三 遍歷PE文件中的資源

                遍歷那個(gè)樹型結(jié)構(gòu),找到每個(gè)資源的方法之一是,

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

               處理葉子的函數(shù),用來處理data_entry結(jié)構(gòu),負(fù)責(zé)根據(jù)data_entry結(jié)構(gòu)找到真正的資源。比如叫DumpResourceEntry(),它的參數(shù)中的一個(gè)是一個(gè)data_entry的地址。然后跟據(jù)data_entry中的值作處理。

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

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

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

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

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

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

            常用鏈接

            留言簿(17)

            隨筆分類(138)

            隨筆檔案(137)

            網(wǎng)絡(luò)開發(fā)

            最新隨筆

            搜索

            •  

            積分與排名

            • 積分 - 500432
            • 排名 - 37

            最新隨筆

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            91精品国产综合久久婷婷| 青青草原综合久久| 久久免费99精品国产自在现线 | 欧美牲交A欧牲交aⅴ久久| 天天久久狠狠色综合| 久久中文精品无码中文字幕| 狠狠综合久久综合88亚洲| 精品多毛少妇人妻AV免费久久| 久久久国产打桩机| 精品一久久香蕉国产线看播放| 色婷婷狠狠久久综合五月| 久久精品国产精品亜洲毛片 | 国产午夜福利精品久久| 久久久精品2019免费观看| 久久精品国产男包| 国产99久久久久久免费看| 99久久夜色精品国产网站| 国产精品免费久久久久影院| 久久久久AV综合网成人| 超级碰碰碰碰97久久久久| 热久久国产欧美一区二区精品| 精品久久久久香蕉网| 97久久精品无码一区二区天美| 最新久久免费视频| 中文字幕精品久久久久人妻| 久久99精品久久久久久hb无码| 人妻少妇精品久久| 日本久久中文字幕| 久久AⅤ人妻少妇嫩草影院| 久久久久久毛片免费播放| 日韩久久久久久中文人妻| 久久久久久精品久久久久| 香蕉久久久久久狠狠色| 久久婷婷午色综合夜啪| 天堂无码久久综合东京热| 久久久久噜噜噜亚洲熟女综合| 国产午夜电影久久| 免费精品久久久久久中文字幕| 久久久久久久亚洲精品| 午夜福利91久久福利| 区久久AAA片69亚洲|