PE文件格式1.9版_第1頁
PE文件格式1.9版_第2頁
PE文件格式1.9版_第3頁
PE文件格式1.9版_第4頁
PE文件格式1.9版_第5頁
已閱讀5頁,還剩41頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、PE文件格式1.9版原著:Bernd. Luevelsmeyer                              注意:本譯文的所有大小標(biāo)題序號都是譯者添加,以方便大家閱讀。圓圈內(nèi)的數(shù)字是注釋的編號,其中注釋譯自微軟的PECOFF規(guī)范,其它譯自網(wǎng)絡(luò)。-譯者一、前言(Preface

2、)-PE(“portable executable”,可移植的可執(zhí)行文件)文件格式,是微軟WindwosNT,Windows95和Win32子集中的可執(zhí)行的二進(jìn)制文件的格式;在WindowsNT中,驅(qū)動程序也是這種格式。它還能被應(yīng)用于各種目標(biāo)文件和庫文件中。這種文件格式是由微軟設(shè)計的,并于1993年被TIS(tool interface standard,工具接口標(biāo)準(zhǔn))委員會(由Microsoft,Intel,Borland,Watcom,IBM,等等組成)所批準(zhǔn),它明顯的基于COFF文件格式的許多知識。COFF(“common object 

3、file fromat”,通用目標(biāo)文件格式)是應(yīng)用于好幾種UNIX系統(tǒng)和VMS系統(tǒng)中的目標(biāo)文件和可執(zhí)行文件的格式。Win32 SDK中包含一個名叫<winnt.h>的頭文件,其中含有很多用于PE格式的#define和typedef定義。我將逐步地提到其中的很多結(jié)構(gòu)成員名字和#define定義。你也可能發(fā)現(xiàn)DLL文件“imagehelp.dll”很有用途,它是WindowNT的一部分,但其書面文件卻很缺乏。它的一些功用在“Developer Network”(開發(fā)者網(wǎng)絡(luò))中有所描述。二、總覽(General Layout)-在一個PE文件的開始

4、處,我們會看到一個MS-DOS可執(zhí)行體(英語叫“stub”,意為“根,存根”);它使任何PE文件都是一個有效的MS-DOS可執(zhí)行文件。在DOS-根之后是一個32位的簽名以及魔數(shù)0x00004550 (IMAGE_NT_SIGNATURE)(意為“NT簽名”,也就是PE簽名;十六進(jìn)制數(shù)45和50分別代表ASCII碼字母E和P-譯者注)。之后是文件頭(按COFF格式),用來說明該二進(jìn)制文件將運行在何種機器之上、分幾個區(qū)段、鏈接的時間、是可執(zhí)行文件還是DLL、等等。(本文中可執(zhí)行文件和DLL文件的區(qū)別在于:DLL文件不能被啟動,但能被別的二進(jìn)制文件使用,而一個二進(jìn)制文件則不能鏈接到另一個可

5、執(zhí)行文件。)那些之后,是可選頭(盡管它一直都存在,卻仍被稱作“可選”-因為COFF文件格式僅為庫文件使用一個“可選頭”,卻不為目標(biāo)文件使用一個“可選頭”,這就是為什么它被稱為“可選”的原因)。它會告訴我們該二進(jìn)制文件怎樣被載入的更多信息:開始的地址呀、保留的堆棧數(shù)呀、數(shù)據(jù)段的大小呀、等等??蛇x頭的一個有趣的部分是尾部的“數(shù)據(jù)目錄”數(shù)組;這些目錄包含許多指向各“節(jié)”數(shù)據(jù)的指針。例如:如果一個二進(jìn)制文件擁有一個輸出目錄,那么你就會在數(shù)組成員“IMAGE_DIRECTORY_ENTRY_EXPORT”(輸出目錄項)中找到一個指向那個目錄的指針,而該指針指向文件中的某節(jié)。跟在各種頭后面我們就發(fā)現(xiàn)各個“

6、節(jié)”了,它們都由“節(jié)頭”引導(dǎo)。本質(zhì)上講,各節(jié)中的內(nèi)容才是你執(zhí)行一個程序真正需要的東西,所有頭和目錄這些東西只是為了幫助你找到它們。每節(jié)都含有和對齊、包含什么樣的數(shù)據(jù)(如“已初始化數(shù)據(jù)”等等)、是否能共享等有關(guān)的一些標(biāo)記,還有就是數(shù)據(jù)本身。大多數(shù)(并非所有)節(jié)都含有一個或多個可通過可選頭的“數(shù)據(jù)目錄”數(shù)組中的項來參見的目錄,如輸出函數(shù)目錄和基址重定位目錄等。無目錄形式的內(nèi)容有:例如“可執(zhí)行代碼”或“已初始化數(shù)據(jù)”等。    +-+    | DOS-stub    &

7、#160;     |    -DOS-頭    +-+    | file-header       |    -文件頭    +-+    | optional header  

8、0;|    -可選頭    |- - - - - - - - - -|    |                   |    | data

9、0;directories  |    -數(shù)據(jù)目錄    |                   |    +-+    |         

10、;          |    | section headers   |     -節(jié)頭    |                  &#

11、160;|    +-+    |                   |    | section 1         |    

12、0;-節(jié)1    |                   |    +-+    |                 &

13、#160; |    | section 2         |     -節(jié)2    |                   |  

14、60; +-+    |                   |    | .               |    |

15、                   |    +-+    |                   |   

16、 | section n         |     -節(jié)n    |                   |    +-+三、DOS-根和簽名(DOS-stu

17、b and Signature)-DOS-根的概念很早從16位windows的可執(zhí)行文件(當(dāng)時是“NE”格式)時就廣為人知了。根原來是用于OS/2系統(tǒng)的可執(zhí)行文件的,也用于自解壓檔案文件和其它的應(yīng)用程序。對于PE文件來說,它是一個總是由大約100個字節(jié)所組成的和MS-DOS 2.0兼容的可執(zhí)行體,用來輸出象“this program needs windows NT”之類的錯誤信息。你可以通過確認(rèn)DOS-頭部分是否為一個IMAGE_DOS_HEADER(DOS頭)結(jié)構(gòu)來認(rèn)出DOS-根,它的前兩個字節(jié)必須為連續(xù)的兩個字母“MZ

18、”(有一個#define IMAGE_DOS_SIGNATURE的定義是針對這個WORD單元的)。你可以通過跟在后面的簽名來將一個PE二進(jìn)制文件和其它含有根的二進(jìn)制文件區(qū)分開來,跟在后面的簽名可由頭成員'e_lfanew'(它是從字節(jié)偏移地址60處開始的,有32字節(jié)長)所設(shè)定的偏移地址找到。對于OS/2系統(tǒng)和Windows系統(tǒng)的二進(jìn)制文件來說,簽名是一個16位的word單元;對于PE文件來說,它是一個按照8位字節(jié)邊界對齊的32位的longword單元,并且IMAGE_NT_SIGNATURE(NT簽名)的值已由#defined定義為0x00004550(即字母“PE/

19、0/0”-譯者)。四、文件頭(File Header)-要到達(dá)IMAGE_FILE_HEADER(文件頭)結(jié)構(gòu),請先確認(rèn)DOS-頭“MZ”(起始的2個字節(jié)),然后找出DOS-根的頭部的成員“e_lfanew”,并從文件開始處跳過那么多的字節(jié)。在核實你在那里找到的簽名后,IMAGE_FILE_HEADER(文件頭)結(jié)構(gòu)的文件頭就緊跟其后開始了,下面我們將從頭至尾的介紹其成員。1)第一個成員是“Machine(機器)”,一個16位的值,用來指出該二進(jìn)制文件預(yù)定運行于什么樣的系統(tǒng)。已知的合法的值有:     IMAGE_FILE_MACHI

20、NE_I386 (0x14c)            Intel 80386 處理器或更高     0x014d            Intel 80386 處理器或更高     0x014e &#

21、160;          Intel 80386 處理器或更高     0x0160                       R3000 (MIPS)處理器,大尾  

22、;   IMAGE_FILE_MACHINE_R3000 (0x162)             R3000 (MIPS)處理器,小尾     IMAGE_FILE_MACHINE_R4000 (0x166)            

23、0;R4000 (MIPS)處理器,小尾     IMAGE_FILE_MACHINE_R10000 (0x168)             R10000 (MIPS)處理器,小尾     IMAGE_FILE_MACHINE_ALPHA (0x184)      &#

24、160;      DEC Alpha AXP處理器     IMAGE_FILE_MACHINE_POWERPC (0x1F0)             IBM Power PC,小尾2)然后是“NumberOfSections(節(jié)數(shù))”成員,16位的值。它是緊跟在頭后面的節(jié)的數(shù)目。我們以后將討論節(jié)的問題。

25、3)下一個成員是時間戳“TimeDateStamp”(32位),用來給出文件建立的時間。即使它的“官方”版本號沒有改變,你也可通過這個值來區(qū)分同一個文件的不同版本。(除了同一個文件的不同版本之間必須唯一,時間戳的格式?jīng)]有明文規(guī)定,但似乎是按照UTC?時間“從1970年1月1日00:00:00算起的秒數(shù)值”-也就是大多數(shù)C語言編譯器給time_t標(biāo)志使用的格式。)這個時間戳是用來綁定各個輸入目錄的,我們稍后再討論它。警告:有一些鏈接器往往將時間戳設(shè)為荒唐的值,而不是如前所述的time_t格式的鏈接時間。4-5)成員“PointerToSymbolTable(符號表指針)”和成員“NumberOf

26、Symbols(符號數(shù))”(都是32位)都用于調(diào)試信息的。我不知道該怎樣去解讀它,并且我發(fā)現(xiàn)該指針的值總為0。6)成員“SizeOfOptionalHeader(可選頭大?。保?6位)只是“IMAGE_OPTIONAL_HEADER(可選頭)”項的大小,你能用它去驗證PE文件結(jié)構(gòu)的正確性。7)成員“Characteristics(特性)”是一個16位的,由許多標(biāo)志位形成的集合組成,但大多數(shù)標(biāo)志位只對目標(biāo)文件和庫文件有效。具體如下:    位0 IMAGE_FILE_RELOCS_STRIPPED(重定位被剝離文件) 表示如果文件中沒

27、有重定位信息,該位置1,這就表明各節(jié)的重定位信息都在它們各自的節(jié)中;可執(zhí)行文件不使用該位,它們的重定位信息放在下面將要描述的“base relocation”(基址重定位)目錄中。    位1 IMAGE_FILE_EXECUTABLE_IMAGE(可執(zhí)行映象文件) 表示如果文件是一個可執(zhí)行文件,也即不是目標(biāo)文件或者庫文件時,置1。如果鏈接器嘗試創(chuàng)建一個可執(zhí)行文件,卻因為一些原因失敗了,并保存映像以便下次例如增量鏈接時使用,此時此標(biāo)志位也可能置1。    位2 IMAGE_F

28、ILE_LINE_NUMS_STRIPPED(行數(shù)被剝離文件) 表示如果行數(shù)信息被剝除,此位置1;此位也不用于可執(zhí)行文件。    位3 IMAGE_FILE_LOCAL_SYMS_STRIPPED(本地符號被剝離文件) 表示如果文件中沒有關(guān)于本地符號的信息時,此位置1(此位也不用于可執(zhí)行文件)。    位4 IMAGE_FILE_AGGRESIVE_WS_TRIM(強行工作集修剪文件) 表示如果操作系統(tǒng)被假定為:通過將正在運行的進(jìn)程(它所使用的內(nèi)存數(shù)量)強行的頁清除

29、來修剪它的工作集時,此位置1。如果一進(jìn)程是大部分時間處于等待,且一天中僅被喚醒一次的演示性的應(yīng)用程序之類時,此位也應(yīng)該被置1。        位7 IMAGE_FILE_BYTES_REVERSED_LO(低字節(jié)變換文件)和 位15IMAGE_FILE_BYTES_REVERSED_HI(高字節(jié)變換文件) 表示如果一文件的字節(jié)序不是機器所預(yù)期的形式,因此它在讀入前必須調(diào)換字節(jié)時,此位置1。這樣做對可執(zhí)行文件是不可靠的(操作系統(tǒng)期望可執(zhí)行文件都已經(jīng)被正確地按字節(jié)排整齊了)。 &

30、#160;  位8 IMAGE_FILE_32BIT_MACHINE(32位機器文件) 表示如果使用的機器被期望為32位的機器時,此位置1?,F(xiàn)在的應(yīng)用程序總將此位置1;NT5系統(tǒng)可能工作不同。    位9 IMAGE_FILE_DEBUG_STRIPPED(調(diào)試信息被剝離文件) 表示如果文件中沒有調(diào)試信息,此位置1。此位可執(zhí)行文件不用。按照其它信息(6)(這里指的是參考書目中的第6種-譯者注),此位被稱作“恒定”,并且當(dāng)一個映象文件只有在被裝入優(yōu)先的裝入地址才能運行(亦即:此文件不可重定位)時,

31、此位置1。       位10 IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP(移動介質(zhì)文件從交換文件運行) 表示如果一個應(yīng)用程序不可以從可移動的介質(zhì),如軟盤或CD-ROM上運行時,此位置1。在這種情況下,建議操作系統(tǒng)將文件復(fù)制到交換文件并從那里執(zhí)行。    位11 IMAGE_FILE_NET_RUN_FROM_SWAP(網(wǎng)絡(luò)文件從交換文件運行) 表示如果一個應(yīng)用程序不可以從網(wǎng)絡(luò)上運行時,此位置1。在這種情況下,建議操作系

32、統(tǒng)將文件復(fù)制到交換文件并從那里執(zhí)行。    位12 IMAGE_FILE_SYSTEM(系統(tǒng)文件) 表示如果文件是一個象驅(qū)動程序那樣的系統(tǒng)文件,此位置1。此位可執(zhí)行文件不用;我所見過的所有NT系統(tǒng)的驅(qū)動程序也不用。    位13 IMAGE_FILE_DLL(DLL文件) 表示如果文件是一個DLL文件時,此位置1。    位14 IMAGE_FILE_UP_SYSTEM_ONLY(僅但處理器系統(tǒng)的文件) 表示如果文件

33、不設(shè)計運行在多處理器系統(tǒng)上(也就是說,因為此文件嚴(yán)格地依賴單一處理器的一些方式工作,所以它會發(fā)生沖突)時,此位置1。五、相對虛擬地址(Relative Virtual Addresses)-PE格式大量地使用所謂的RVA(相對虛擬地址)。一個RVA,亦即一個“Relative Virtual Addresses(相對虛擬地址)”,是在你不知道基地址時,被用來描述一個內(nèi)存地址的。它是需要加上基地址才能獲得線性地址的數(shù)值。基地址就是PE映象文件被裝入內(nèi)存的地址,并且可能會隨著一次又一次的調(diào)用而變化。例如:假若一個可執(zhí)行文件被裝入的地址是0x400000,并且

34、從RVA 0x1560處開始執(zhí)行,那么有效的執(zhí)行開始處將位于0x401560地址處。假若它被裝入的地址為0x100000,那么執(zhí)行開始處就位于0x101560地址處。因為PE-文件中的各部分(各節(jié))不需要像已載入的映象文件那樣對齊,事情變得復(fù)雜起來。例如,文件中的各節(jié)常按照512(十六進(jìn)制的0x200-譯者注)字節(jié)邊界對齊,而已載入的映象文件則可能按照4096(十六進(jìn)制的0x1000-譯者注)字節(jié)邊界對齊。參見下面的“SectionAlignment(節(jié)對齊)”和“FileAlignment(文件對齊)”。因此,為了在PE文件中找到一個特定RVA地址的信息,你得按照文件已被載入時的那

35、樣來計算偏移量,但要按照文件的偏移量來跳過。試舉一例,假若你已知道執(zhí)行開始處位于RVA 0x1560地址處,并且想從那里開始的代碼處反匯編。為了從文件中找到這個地址,你得先查明在RAM(內(nèi)存)中各節(jié)是按照4096字節(jié)對齊的,并且“.code”節(jié)是從RVA 0x1000地址處開始,有16384字節(jié)長;然后你才知道RVA 0x1560地址位于此節(jié)的偏移量0x560處。你還要查明在文件中那節(jié)是按512字節(jié)邊界對齊,且“.code”節(jié)在文件中從偏移量0x800處開始,然后你就知道在文件中代碼的執(zhí)行開始處就在0x800+0x560=0xd60字節(jié)處。然后你反匯編它并發(fā)現(xiàn)訪問

36、一個變量的線性地址位于0x1051d0處。二進(jìn)制文件的線性地址在裝入時將被重定位,并常被假定使用的是優(yōu)先載入地址。因為你已查明優(yōu)先載入地址為0x100000,因此我們可開始處理RVA 0x51d0了。因數(shù)據(jù)節(jié)開始于RVA 0x5000處,且有2048字節(jié)長,所以它處于數(shù)據(jù)節(jié)中。又因數(shù)據(jù)節(jié)在文件中開始于偏移量0x4800處,所以該變量就可以在文件中的0x4800+0x51d0-0x5000=0x49d0處找到。六、可選頭(Optional Header)-緊跟在文件頭后面的就是IMAGE_OPTIONAL_HEADER(盡管它名叫“可選頭”,它卻一直都在那里)。它包

37、含有怎樣去準(zhǔn)確處理PE文件的信息。我們也將從頭至尾的介紹其成員。1)第一個16位的word單元叫“Magic(魔數(shù))”,就我目前所觀察過的PE文件而言,它的值總是0x010b。2-3)下面2個字節(jié)是創(chuàng)建此文件的鏈接器的版本(MajorLinkerVersion,“鏈接器主版本號”和MinorLinkerVersion,“鏈接器小版本號”)。這兩個值又是不可靠的,并不能總是正確地反映鏈接器的版本號。(有好幾個鏈接器根本就不設(shè)置這個值。)況且,你可想象一下,你連使用的是“什么”鏈接器都不知道,知道它的版本號又有什么作用呢?4-6)下面3個longword(每個32位)分別用來設(shè)定可執(zhí)行代碼的大?。?/p>

38、“SizeOfCode”)、已初始化數(shù)據(jù)的大小(“SizeOfInitializedData”,所謂的“數(shù)據(jù)段”)、以及未初始化數(shù)據(jù)的大?。ā癝izeOfUninitializedData”,所謂的“bss?段”)。這些值也是不可靠的(例如:數(shù)據(jù)段實際上可能會被編譯器或者鏈接器分成好幾段),并且你可以通過查看可選頭后面的各個“節(jié)”來獲得更準(zhǔn)確的大小。7)下一個32位值是RVA。這個RVA是代碼入口點的偏移量(AddressOfEntryPoint,“入口點地址”)。執(zhí)行將從這里開始,它可以是:例如DLL文件的LibMain()的地址,或者一個程序的開始代碼(這里相應(yīng)的叫main())的地址,或

39、者驅(qū)動程序的DriverEntry()的地址。如果你敢于“手工”裝載映象文件,那么在你完成所有的修正和重定位后,你可以從這個地址開始執(zhí)行你的進(jìn)程。8-9)下兩個32位值分別是可執(zhí)行代碼的偏移值(BaseOfCode,“代碼基址”)和已初始化數(shù)據(jù)的偏移值(BaseOfData,“數(shù)據(jù)基址”),兩個都是RVA,并且兩個對我們來說都沒有多少意義,因為你可以通過查看可選頭后面的各個“節(jié)”來獲得更可靠的信息。未初始化的數(shù)據(jù)沒有偏移量,正因為它沒有初始化,所以在映象文件中提供這些數(shù)據(jù)是沒有用處的。10)下一項是個32位值,提供整個二進(jìn)制文件包括所有頭的優(yōu)先(線性)載入地址(ImageBase,“映象文件基

40、址”)。這是一個文件已被鏈接器重定位后的地址(總是64 KB的倍數(shù))。如果二進(jìn)制文件事實上能被載入這個地址,那么加載器就不用再重定位文件了,也就節(jié)省了一些載入時間。優(yōu)先載入地址在另一個映象文件已被先載入那個地址(“地址沖突”,在當(dāng)你載入好幾個全部按照鏈接器的缺省值重定位的DLL文件時經(jīng)常發(fā)生)時,或者該內(nèi)存已被用于其它目的(堆棧、malloc()、未初始化數(shù)據(jù)、或不管是什么)時,就不能用了。在這些情況下,映象文件必須被載人其它的地址,并且需要重定位(參見下面的“重定位目錄”)。如果是一個DLL文件,這么做還會產(chǎn)生其它問題,因為此時的“綁定輸入”已不再有效,所以使用DLL的二進(jìn)制文件必

41、須被修正-參見下面的“輸入目錄”一節(jié)。11-12)下兩個32位值分別是RAM中的“SectionAlignment”(當(dāng)映象文件已被載入后,意為“節(jié)對齊”)和文件中的“FileAlignment”(文件對齊),它們都是PE文件的各節(jié)的對齊值。這兩個值通常都是32,或者是:FileAlignment為512,SectionAlignment為4096。節(jié)會在以后討論。13-14)下2個16位word單元都是預(yù)期的操作系統(tǒng)版本信息(MajorOperatingSystemVersion,“操作系統(tǒng)主版本號”)和(MinorOperatingSystemVersion,“操作系統(tǒng)小版本號”)它們都使

42、用微軟自己書面確定的名字。這個版本信息應(yīng)該為操作系統(tǒng)的版本號(如NT 或 Win95),而不是子系統(tǒng)的版本信息(如Win32)。版本信息常常被不提供或者錯誤提供。很明顯的,加載器并不使用它們。15-16)下2個16位word單元都是本二進(jìn)制文件的版本信息('MajorImageVersion'“映象文件主版本號”和'MinorImageVersion'“映象文件小版本號”)。很多鏈接器不正確地設(shè)定這個信息,許多程序員也懶得提供這些,因此即便存在這樣的信息,你最好也不要信賴它。17-18)下2個16位word單元都是預(yù)期的子系統(tǒng)版本信息(

43、9;MajorSubsystemVersion'“子系統(tǒng)主版本號”和'MinorSubsystemVersion'“子系統(tǒng)小版本號”)。此信息應(yīng)該為Win32或POSIX的版本信息,因為很明顯的,16位程序或OS/2程序都不是PE格式的。子系統(tǒng)版本應(yīng)該被正確的提供,因為它“會”被檢驗和使用:如果一個應(yīng)用程序是一個Win32-GUI應(yīng)用程序并運行于NT4系統(tǒng)之上,而且子系統(tǒng)版本“不是”4.0的話,那么對話框就不會是以3D形式顯示,并且一些其它的特征也只會按“老式”的方式工作,因為此應(yīng)用程序預(yù)期是在NT 3.51系統(tǒng)上運行的,而NT 3.51系統(tǒng)上只有程

44、序管理器而沒有瀏覽器、等等,于是NT 4.0系統(tǒng)就盡可能地仿照那個系統(tǒng)的行為來運行程序。19)然后,我們便碰到32位的“Win32VersionValue”(Win32版本值)。我不清楚它有什么作用。在我所觀察過的PE文件中,它全部都為0。20)下一個是32位值,給出映象文件將要使用的內(nèi)存數(shù)量,單位為字節(jié)(SizeOfImage,“映象文件大小”)。如果是按照“SectionAlignment”對齊的,它就是所有頭和節(jié)的長度的總和。它提示加載器,為了載入映象文件需要多少頁。21)下一個是32位值,給出所有頭的總長度,包括數(shù)據(jù)目錄和節(jié)頭(SizeOfHeaders,“頭的大小”)。同時

45、,它也是從文件的開頭到第一節(jié)的原始數(shù)據(jù)的偏移量。22)然后,我們發(fā)現(xiàn)一個32位的校驗和(“CheckSum”)。這個校驗和,對于當(dāng)前的NT版本,只在映象文件是NT驅(qū)動程序時才校驗(如果校驗和不正確,驅(qū)動就將裝載失敗)。對于其他的二進(jìn)制文件形式,校驗和不需提供并且可能為0。計算校驗和的算法是微軟的私產(chǎn),他們不會告訴你的。但是,Win32 SDK的好幾個工具都會計算和/或補正一個有效的校驗和,而且imagehelp.dll中的CheckSumMappedFile()函數(shù)也會做同樣的工作。使用校驗和的目的是為了防止載入無論如何都會沖突的、已損壞的二進(jìn)制文件-況且一個沖突的驅(qū)動程序會導(dǎo)致一個

46、BSOD?錯誤,因此最好根本就不載入這樣的壞文件。23)然后,就到了一個16位的word單元“Subsystem”(子系統(tǒng)),用來說明映象文件應(yīng)運行于什么樣的NT子系統(tǒng)之上:        IMAGE_SUBSYSTEM_NATIVE (1)             二進(jìn)制文件不需要子系統(tǒng)。用于驅(qū)動程序。      &

47、#160;         IMAGE_SUBSYSTEM_WINDOWS_GUI (2)             映象文件是一個Win32二進(jìn)制圖象文件。(它還是能用AllocConsole()打開一個控制臺界面,但在開始時卻不能自動地打開。)          &#

48、160;          IMAGE_SUBSYSTEM_WINDOWS_CUI (3)             二進(jìn)制文件是一個Win32控制臺界面二進(jìn)制文件。(它將在開始時按照缺省值打開一個控制臺,或者繼承其父程序的控制臺。)        IMAGE_SUBSYSTEM_

49、OS2_CUI (5)              二進(jìn)制文件是一個OS/2控制臺界面二進(jìn)制文件。(OS/2控制臺界面二進(jìn)制文件是OS/2格式,因此此值在PE文件中很少使用。)        IMAGE_SUBSYSTEM_POSIX_CUI (7)         &#

50、160;    二進(jìn)制文件使用POSIX?控制臺子系統(tǒng)。Windows 95的二進(jìn)制文件總是使用Win32子系統(tǒng),因此它的二進(jìn)制文件的合法值只有2和3;我不知道windows 95的“原”二進(jìn)制文件是否可能(會有其它值-譯者添加,僅供參考)。24)下一個是16位的值,指明,如果是DLL文件,何時調(diào)用DLL文件的入口點(DllCharacteristics,“DLL特性”)。此值似乎不用;很明顯地,DLL文件總是被通報所有的情況。         

51、如果位0被置1,DLL文件被通知進(jìn)程附加(亦即DLL載入)。         如果位1被置1,DLL文件被通知線程附加(亦即線程終止)。         如果位2被置1,DLL文件被通知線程附加(亦即線程創(chuàng)建)。         如果位3被置1,DLL文件被通知進(jìn)程附加(亦即DLL卸載)。25-28)下4個32位值分別是:保留棧

52、的大?。⊿izeOfStackReserve)、初始時指定棧大?。⊿izeOfStackCommit)、保留堆的大?。⊿izeOfHeapReserve)和指定堆大?。⊿izeOfHeapCommit)?!氨A舻摹睌?shù)量是保留給特定目的的地址空間(不是真正的RAM);在程序開始時,“指定的”數(shù)量是指在RAM中實際分配的大小。如果需要的話,“指定的”值也是指定的堆或棧用來增加的數(shù)量。(有資料說,不管“SizeOfStackCommit”的值是多少,棧都是按頁增加的。我沒有驗證過。)因此,舉例來說,如一個程序的保留堆有1 MB,指定堆為64 KB,那么啟動時堆的大小為64

53、0;KB,并且保證可以擴大到1 MB。堆將按64 KB一塊來增加?!岸选痹诒疚闹惺侵钢饕ㄈ笔。┒?。如果它愿意的話,一個進(jìn)程可創(chuàng)建很多堆。棧是指第一個線程的棧(啟動main()的那個)。進(jìn)程可以創(chuàng)建很多線程,每個線程都有自己的棧。DLL文件沒有自己的堆或棧,所以它們的映象文件忽略這些值。我不知道驅(qū)動程序是否有它們自己的堆或棧,但我認(rèn)為它們沒有。29)堆和棧的這些描述之后,我們就發(fā)現(xiàn)一個32位的“LoaderFlags(加載器標(biāo)志)”,我沒有找到它的任何有用的描述。我只發(fā)現(xiàn)一篇時新的關(guān)于設(shè)置此標(biāo)志位的短文,說設(shè)置此標(biāo)志位會在映象文件載入后自動地調(diào)用一個斷點或者調(diào)試器;可似乎不

54、正確。30)接著我們會發(fā)現(xiàn)32位的“NumberOfRvaAndSizes(Rva數(shù)和大?。保蔷o隨其后的目錄的有效項的數(shù)目。我已發(fā)現(xiàn)此值不可靠;你也許希望用常量IMAGE_NUMBEROF_DIRECTORY_ENTRIES(映象文件目錄項數(shù)目)來代替它,或者用它們中的較小者。NumberOfRvaAndSizes之后是一個IMAGE_NUMBEROF_DIRECTORY_ENTRIES (16)(映象文件目錄項數(shù)目)個IMAGE_DATA_DIRECTORY(映象文件數(shù)據(jù)目錄)數(shù)組。這些目錄中的每一個目錄都描述了一個特定的、位于目錄項后面的某一節(jié)中的信息的位置(32位的RVA

55、,叫“VirtualAddress(虛擬地址)”)和大?。ㄒ彩?2位,叫“Size(大?。保?。例如,安全目錄能在索引4中給定的RVA處發(fā)現(xiàn)并具有索引4中給定的大小。稍后我將討論我知道其結(jié)構(gòu)的目錄。已定義的目錄及索引有:    IMAGE_DIRECTORY_ENTRY_EXPORT (0)        輸出符號目錄;大多用于DLL文件。        后面介紹。  

56、;      IMAGE_DIRECTORY_ENTRY_IMPORT (1)        輸入符號目錄;參見后面。        IMAGE_DIRECTORY_ENTRY_RESOURCE (2)        資源目錄。后面介紹。   

57、60;    IMAGE_DIRECTORY_ENTRY_EXCEPTION (3)        異常目錄 - 結(jié)構(gòu)和用途不詳。        IMAGE_DIRECTORY_ENTRY_SECURITY (4)        安全目錄 - 結(jié)構(gòu)和用途不詳。

58、        IMAGE_DIRECTORY_ENTRY_BASERELOC (5)        基址重定位表 - 參見后面。        IMAGE_DIRECTORY_ENTRY_DEBUG (6)        調(diào)試目錄

59、0;- 內(nèi)容編譯器相關(guān)。此外, 許多編譯器將編譯信息填入代碼節(jié),并不為此創(chuàng)建一個單獨的節(jié)。        IMAGE_DIRECTORY_ENTRY_COPYRIGHT (7)        描述字符串 - 一些隨意的版權(quán)信息之類。        IMAGE_DIRECTORY_ENTRY_GLOBALPTR

60、 (8)        機器值 (MIPS GP) - 結(jié)構(gòu)和用途不詳。        IMAGE_DIRECTORY_ENTRY_TLS (9)        線程級局部存儲目錄 - 結(jié)構(gòu)不詳;包含聲明為“_declspec(thread)”的變量, 也就是每線程的全

61、局變量。        IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG (10)        載入配置目錄 - 結(jié)構(gòu)和用途不詳。        IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (11)      &#

62、160; 綁定輸入目錄 - 參見輸入目錄的描述。        IMAGE_DIRECTORY_ENTRY_IAT (12)        輸入地址表 - 參見輸入目錄的描述。試舉一例,如果我們在索引7中發(fā)現(xiàn)2個longword:0x12000 和 33,并且載入地址為0x10000,那么我們就知道版權(quán)信息數(shù)據(jù)位于地址0x10000+0x12000(在哪個節(jié)

63、都有可能)處,并且版權(quán)信息有33字節(jié)長。如果二進(jìn)制文件中沒有使用特殊類型的目錄,Size(大小)和VirtualAddress(虛擬地址)的值就都為0。七、節(jié)目錄(Section directories)-節(jié)由兩個主要部分組成:首先,是一個節(jié)描述(IMAGE_SECTION_HEADER意為“節(jié)頭”類型的),然后是原始的節(jié)數(shù)據(jù)。因此,我們會在數(shù)據(jù)目錄后發(fā)現(xiàn)一“NumberOfSections”個節(jié)頭組成的數(shù)組,它們按照各節(jié)的RVA排序。節(jié)頭包括:1)一個IMAGE_SIZEOF_SHORT_NAME (8)(意為“短名的大小”)個字節(jié)的數(shù)組,形成節(jié)的名稱(ASCII形式)。

64、如果所有的8位都被用光,該字符串就沒有0結(jié)束符!典型的名稱象“.data”或“.text”或“.bss”形式。開頭的“.”不是必須的,名稱也可能為“CODE”或“IAT”或類似的形式。請注意:并不是所有的名稱都和節(jié)中的內(nèi)容相關(guān)。一個名叫“.code”的節(jié)可能包含也可能不包含可執(zhí)行代碼;它還可能只包含輸入地址表;它也可能包含代碼“和”地址表“和”未初始化數(shù)據(jù)。要找到節(jié)中的信息,你必須通過可選頭的數(shù)據(jù)目錄來查詢它。既不要過分相信它的名稱,也不要以為節(jié)的原始數(shù)據(jù)會從節(jié)的開頭就開始。2)IMAGE_SECTION_HEADER(“節(jié)頭”)的下一個成員是一個32位的、“PhysicalAddress(物

65、理地址)”和“VirtualSize(虛擬大?。苯M成的共用體。在目標(biāo)文件中,它是內(nèi)容重定位到的地址;在可執(zhí)行文件中,它是內(nèi)容的大小。事實上,此域似乎沒被使用;因為有的鏈接器輸入大小,有的鏈接器輸入地址,我還發(fā)現(xiàn)有一個鏈接器輸入0,而所有的可執(zhí)行文件都運行如風(fēng)。3)下一個成員是“VirtualAddress(虛擬地址)”,是一個32位的值,用來保存載入RAM(內(nèi)存)后,節(jié)中數(shù)據(jù)的RVA。4)然后,我們到了32位的“SizeOfRawData”(意味“原始數(shù)據(jù)大小”),它表示節(jié)中數(shù)據(jù)被大約到下一個“FileAlignment”的整數(shù)倍時節(jié)的大小。5)下一個是“PointerToRawData”(

66、意味“原始數(shù)據(jù)指針”,32位),它特別有用,因為它是從文件的開頭到節(jié)中數(shù)據(jù)的偏移量。如果它為0,那么節(jié)的數(shù)據(jù)就不包含在文件中,并且要在載入時才定。6-9)然后,我們得到“PointerToRelocations”(意味“重定位指針”,32位)和“PointerToLinenumbers”(意味“行數(shù)指針”,也是32位),以及“NumberOfRelocations”(意味“重定位數(shù)”,16位)和“NumberOfLinenumbers”(意味“行數(shù)數(shù)”,也是16位)。所以這些都是只用于目標(biāo)文件的信息??蓤?zhí)行文件擁有一個特殊的基址重定位目錄,并且行數(shù)信息(如果真的存在的話)通常包含在有一個特殊目

67、的的調(diào)試段中或者別的什么地方。10)節(jié)頭的最后一個成員是32位的“Characteristics”(意味“特性”),它是一串描述節(jié)的內(nèi)存如何被處理的標(biāo)志:    如果位5 IMAGE_SCN_CNT_CODE(含有代碼的節(jié))被置1,表示節(jié)中包含可執(zhí)行代碼。        如果位6 IMAGE_SCN_CNT_INITIALIZED_DATA(含有初始化數(shù)據(jù)的節(jié))被置1,表示節(jié)中包含執(zhí)行開始前即取得已定義值的數(shù)據(jù)。換言之:文件中節(jié)的數(shù)據(jù)就是有意義的。

68、0;       如果位7 IMAGE_SCN_CNT_UNINITIALIZED_DATA(含有未初始化數(shù)據(jù)的節(jié))被置1, 表示節(jié)中包含未初始化數(shù)據(jù),并需于執(zhí)行開始前被初始化為全0。這通常是BSS節(jié)。    如果位9 IMAGE_SCN_LNK_INFO(鏈接器信息節(jié))被置1, 表示節(jié)中不包含映象數(shù)據(jù),只有一些注釋、描述或者其他的文檔。這些信息是目標(biāo)文件的一部分,并有可能是提供給鏈接器的信息,比如需要哪些庫文件。  

69、0; 如果位11 IMAGE_SCN_LNK_REMOVE(鏈接可刪除節(jié))被置1,表示數(shù)據(jù)是目標(biāo)文件的、被預(yù)定于可執(zhí)行文件被鏈接后丟棄掉的節(jié)的一部分。常和位9連用。    如果位12 IMAGE_SCN_LNK_COMDAT(鏈接通用塊節(jié))被置1, 表示節(jié)中包含“common block data”(通用塊數(shù)據(jù)),也即某種形式的打包函數(shù)。    如果位15 IMAGE_SCN_MEM_FARDATA(內(nèi)存遠(yuǎn)程數(shù)據(jù)節(jié))被置1,表示我們擁有遠(yuǎn)程數(shù)據(jù)-

70、意味著什么。此位的含義不明。    如果位17 IMAGE_SCN_MEM_PURGEABLE(內(nèi)存可清除節(jié))被置1, 表示節(jié)中的數(shù)據(jù)可清除-但我認(rèn)為它和“可丟棄”不是一回事,可丟棄擁有自己的標(biāo)志位,參見后面。同樣,它也明顯的不是用來指示16位信息的,因為它也有一個IMAGE_SCN_MEM_16BIT定義。此位的含義不明。    如果位18 IMAGE_SCN_MEM_LOCKED(內(nèi)存被鎖節(jié))被置1, 表示節(jié)不應(yīng)該被從內(nèi)存中移除?抑或表明沒有重定位信息?此位的含義不明。&

71、#160;   如果位19 IMAGE_SCN_MEM_PRELOAD(內(nèi)存預(yù)載入節(jié))被置1,表示節(jié)在執(zhí)行開始前應(yīng)該被頁載入?此位的含義不明。    位20至23 指定我沒有找到信息的對齊。諸如#defines IMAGE_SCN_ALIGN_16BYTES之類。我曾經(jīng)見過的唯一值為0,是16位的缺省對齊。 我懷疑它們是庫之類文件的目標(biāo)對齊。    如果位24 IMAGE_SCN_LNK_NRELOC_OVFL(鏈接擴展重定位節(jié))被置1

72、,表示節(jié)中包含一些我不知道的擴展重定位。    如果位25 IMAGE_SCN_MEM_DISCARDABLE(內(nèi)存可丟棄節(jié))被置1,表示節(jié)中的數(shù)據(jù)在進(jìn)程啟動后就不需要了。它是,舉例來說,含有重定位信息的情況。我曾經(jīng)見過它也用于只執(zhí)行一次的驅(qū)動和服務(wù)程序的啟動例程,還用于輸入目錄。    如果位26 IMAGE_SCN_MEM_NOT_CACHED(內(nèi)存不緩存節(jié))被置1,表示節(jié)中的數(shù)據(jù)不應(yīng)該被緩存。不要問我為什么不。這是不是意味著關(guān)掉2級緩存?    如果

73、位27 IMAGE_SCN_MEM_NOT_PAGED(內(nèi)存不可頁換出節(jié))被置1,表示節(jié)中的數(shù)據(jù)不應(yīng)該頁換出。它對驅(qū)動程序有意義。    如果位28 IMAGE_SCN_MEM_SHARED(內(nèi)存共享節(jié))被置1,表示節(jié)中的數(shù)據(jù)在映象文件的所有正在運行的實例中共享。如果它是,例如DLL文件的未初始化數(shù)據(jù),那么DLL的所有正在運行的實例程序在任何時候都將擁有相同的變量內(nèi)容。注意:只有第一個實例的節(jié)被初始化。含有代碼的節(jié)總是被共享寫時拷貝(copy-on-write)(亦即:如果重定位必不可少,那么共享就不工作)。(譯注:“寫時拷貝”的譯法

74、也許根本就是錯誤的,但我一時找不到更準(zhǔn)確的翻譯,也不清楚其具體含義,只能以此充數(shù)了。希望知情著指點。)    如果位29 IMAGE_SCN_MEM_EXECUTE(內(nèi)存可執(zhí)行節(jié))被置1,表示進(jìn)程對節(jié)的內(nèi)存有“執(zhí)行”的存取權(quán)限。        如果位30 IMAGE_SCN_MEM_READ(內(nèi)存可讀節(jié))被置1,表示進(jìn)程對節(jié)的內(nèi)存有“讀”的存取權(quán)限。        如果位31&

75、#160;IMAGE_SCN_MEM_WRITE(內(nèi)存可寫節(jié))被置1,表示進(jìn)程對節(jié)的內(nèi)存有“寫”的存取權(quán)限。在節(jié)頭之后,我們就會發(fā)現(xiàn)節(jié)本身。在文件中,它們按照“FileAlignment”(文件對齊)的字節(jié)數(shù)對齊(也就是說,在可選頭之后和每個節(jié)的數(shù)據(jù)之后將要填充一些字節(jié))并按照它們的RVA排序。在載入后(內(nèi)存中),  它們按照“SectionAlignment”(節(jié)對齊)的字節(jié)數(shù)對齊。試舉一例,如果可選頭在文件的偏移量981處結(jié)束,“FileAlignment”(文件對齊)的值為512,那么第一個節(jié)將于1024字節(jié)處開始。注意:你可通過“PointerToRawData”(

76、原始數(shù)據(jù)指針)或者“VirtualAddress”(虛擬地址)的值來找到各節(jié),因此實際上根本沒必要在對齊上小題大做。試畫映象文件的全圖如下:    +-+    |     DOS-根        |    +-+    |      文件頭

77、60;      |    +-+    |      可選頭       |    |- - - - - - - - - -|    |  

78、;                 |-+    |     數(shù)據(jù)目錄      |                |&

79、#160;   |                   |                |    |   (指向節(jié)中  

80、0;    |-+  |    |     目錄的RVA)    |             |  |    |         

81、          |-+   |  |    |                   |         | 

82、0; |  |    +-+         |   |  |    |                   |-+   |

83、60;  |  |    |       節(jié)頭        |     |   |   |  |    |     (指向節(jié)  

84、     |-+  |   |   |  |    |     邊界的RVA)    |  |  |   |   |  |    +-+<-+ 

85、 |   |   |  |    |                   |     | <-+   |  |    |      節(jié)數(shù)據(jù) 1     |     |       |  |    | &

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論