PE文件結(jié)構(gòu)詳解_第1頁
PE文件結(jié)構(gòu)詳解_第2頁
PE文件結(jié)構(gòu)詳解_第3頁
PE文件結(jié)構(gòu)詳解_第4頁
PE文件結(jié)構(gòu)詳解_第5頁
已閱讀5頁,還剩13頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

PE文件結(jié)構(gòu)詳解1摘要WindowsNT3.1引入了一種名為PE文件格式的新可執(zhí)行文件格式。PE文件格式的規(guī)范包含在了MSDN的CD中(SpecsandStrategy,Specifications,WindowsNTFileFormatSpecifications),但是它非常之晦澀。然而這一的文檔并未提供足夠的信息,所以開發(fā)者們無法很好地弄懂PE格式。本文旨在解決這一問題,它會對整個的PE文件格式作一個十分徹底的解釋,另外,本文中還帶有對所有必需結(jié)構(gòu)的描述以及示范如何使用這些信息的源碼示例。為了獲得PE文件中所包含的重要信息,我編寫了一個名為PEFILE.DLL的動態(tài)鏈接庫,本文中所有出現(xiàn)的源碼示例亦均摘自于此。這個DLL和它的源代碼都作為PEFile示例程序的一部分包含在了CD中(譯注:示例程序請在MSDN中尋找,本站恕不提供),你可以在你自己的應(yīng)用程序中使用這個DLL;同樣,你亦可以依你所愿地使用并構(gòu)建它的源碼。在本文末尾,你會找到PEFILE.DLL的函數(shù)導(dǎo)出列表和一個如何使用它們的說明。我覺得你會發(fā)現(xiàn)這些函數(shù)會讓你從容應(yīng)付PE文件格式的。2介紹Windows操作系統(tǒng)家族最近增加的WindowsNT為開發(fā)環(huán)境和應(yīng)用程序本身帶來了很大的改變,這之中一個最為重大的當(dāng)屬PE文件格式了。新的PE文件格式主要來自于UNIX操作系統(tǒng)所通用的COFF規(guī)范,同時為了保證與舊版本MS-DOS及Windows操作系統(tǒng)的兼容,PE文件格式也保留了MS-DOS中那熟悉的MZ頭部。在本文之中,PE文件格式是以自頂而下的順序解釋的。在你從頭開始研究文件內(nèi)容的過程之中,本文會詳細討論PE文件的每一個組成部分。很多解決PE文件格式的工作和直接觀看數(shù)據(jù)有關(guān)。例如,要弄懂導(dǎo)入地址名稱表是如何構(gòu)成的,我就得同時查看.idata段頭部、導(dǎo)入映像數(shù)據(jù)目錄、可選頭部以及當(dāng)前的.idata段實體,而EXEVIEW.EXE就是查看這些信息的最佳示例。在針對PE文件的有關(guān)編程中,你可能用到以下一些數(shù)據(jù)結(jié)構(gòu):IMAGE_DOS_HEADERIMAGE_IMPORT_DESCRIPTORIMAGE_NT_HEADERS IMAGE_SECTION_HEADERIMAGE_OPTIONAL_HEADERIMAGE_DATA_DIRECTORYIMAGE_FILE_HEADER3PE文件結(jié)構(gòu)圖RVA記錄在可選頭部中(3)RVA記錄在可選頭部中(3)IMAGE_NT_HEADERS(1)(2)(4)IMAGE_SECTION_HEADERlfnew-DOS頭部長度IMAGE_DOS_HEADERDWORDSignature;IMAGE_FILE_HEADERIMAGE_OPTIONAL_HEADER長度:dosHeader->elfnewdosHeader長度圖1PE文件結(jié)構(gòu)從MS-DOS文件頭結(jié)構(gòu)開始,我將按照PE文件格式各成分的出現(xiàn)順序依次對其進行討論,并且討論的大部分是以示例代碼為基礎(chǔ)來示范如何獲得文件的信息的。3.1MS-DOS頭部/實模式頭部PE文件格式的第一個組成部分是MS-DOS頭部。在PE文件格式中,它并非一個新概念,因為它與MS-DOS2.0以來就已有的MS-DOS頭部是完全一樣的。保留這個相同結(jié)構(gòu)的最主要原因是,當(dāng)你嘗試在Windows3.1以下或MS-DOS2.0以上的系統(tǒng)下裝載一個文件的時候,操作系統(tǒng)能夠讀取這個文件并明白它是和當(dāng)前系統(tǒng)不相兼容的。換句話說,當(dāng)你在MS-DOS6.0下運行一個WindowsNT可執(zhí)行文件時,你會得到這樣一條消息:“ThisprogramcannotberuninDOSmode.”如果MS-DOS頭部不是作為PE文件格式的第一部分的話,操作系統(tǒng)裝載文件的時候就會失敗,并提供一些完全沒用的信息,例如:“Thenamespecifiedisnotrecognizedasaninternalorexternalcommand,operableprogramorbatchfile.”MS-DOS頭部占據(jù)了PE文件的頭64個字節(jié),描述它內(nèi)容的結(jié)構(gòu),即圖1中的(1)部分的定義如下:typedefstruct_IMAGE_DOS_HEADER{//DOS的.EXE頭部USHORTe_magic;//魔術(shù)數(shù)字USHORTe_cblp;//文件最后頁的字節(jié)數(shù)USHORTe_cp;//文件頁數(shù)USHORTe_crlc;//重定義元素個數(shù)USHORTe_cparhdr;//頭部尺寸,以段落為單位USHORTe_minalloc;//所需的最小附加段USHORTe_maxalloc;//所需的最大附加段USHORTe_ss;//初始的SS值(相對偏移量)USHORTe_sp;//初始的SP值USHORTe_csum;//校驗和USHORTe_ip;//初始的IP值USHORTe_cs;//初始的CS值(相對偏移量)USHORTe_lfarlc;//重分配表文件地址USHORTe_ovno;//覆蓋號USHORTe_res[4];//保留字USHORTe_oemid;//OEM標(biāo)識符(相對e_oeminfo)USHORTe_oeminfo;//OEM信息USHORTe_res2[10];//保留字LONGe_lfanew;//新exe頭部的文件地址}IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER;第一個域e_magic,被稱為魔術(shù)數(shù)字,它被用于表示一個MS-DOS兼容的文件類型。所有MS-DOS兼容的可執(zhí)行文件都將這個值設(shè)為0x5A4D,表示ASCII字符MZ。MS-DOS頭部之所以有的時候被稱為MZ頭部,就是這個緣故。還有許多其它的域?qū)τ贛S-DOS操作系統(tǒng)來說都有用,但是對于WindowsNT來說,這個結(jié)構(gòu)中只有一個有用的域——最后一個域e_lfnew,一個4字節(jié)的文件偏移量,PE文件頭部就是由它定位的。且MS_DOS頭部(dos_head)的地址即為文件映像后的基地址,對于WindowsNT的PE文件來說,PE文件頭部是緊跟在MS-DOS頭部和實模式程序殘余之后的。.操作打開文件:hFile=CreateFile(lpFileName,…);MS-DOS頭部地址:dos_head=(IMAGE_DOS_HEADER*)basepointer;打印MS-DOS頭部信息:3.2實模式殘余程序?qū)嵞J綒堄喑绦蚴且粋€在裝載時能夠被MS-DOS運行的實際程序。對于一個MS-DOS的可執(zhí)行映像文件,應(yīng)用程序就是從這里執(zhí)行的。對于Windows、OS/2、WindowsNT這些操作系統(tǒng)來說,MS-DOS殘余程序就代替了主程序的位置被放在這里。這種殘余程序通常什么也不做,而只是輸出一行文本,例如:“ThisprogramrequiresMicrosoftWindowsv3.1orgreater.”當(dāng)然,用戶可以在此放入任何的殘余程序,這就意味著你可能經(jīng)??吹较襁@樣的東西:“Youcan''trunaWindowsNTapplicationonOS/2,it''ssimplynotpossible.”當(dāng)為Windows3.1構(gòu)建一個應(yīng)用程序的時候,鏈接器將向你的可執(zhí)行文件中鏈接一個名為WINSTUB.EXE的默認殘余程序。你可以用一個基于MS-DOS的有效程序取代WINSTUB,并且用STUB模塊定義語句指示鏈接器,這樣就能夠取代鏈接器的默認行為。為WindowsNT開發(fā)的應(yīng)用程序可以通過使用-STUB:鏈接器選項來實現(xiàn)。不同的文件,其大小不一樣,即圖1中(2)部分的大小由MS-DOS頭的域e_lfnew來確定。3.3PE文件頭部與標(biāo)志PE文件頭部的地址(peheader)是由MS-DOS頭部的e_lfanew域定位的,這個域只是給出了文件的偏移量,所以要確定PE頭部的實際內(nèi)存映射地址,就需要添加文件的內(nèi)存映射基地址。Peheader=dos_head+dos_head->e_lfanew。PE文件頭部的定義,即圖1中(3)部分的定義如下:TheIMAGE_NT_HEADERSstructurerepresentsthePEheaderformat.typedefstruct_IMAGE_NT_HEADERS{

DWORDSignature;

IMAGE_FILE_HEADERFileHeader;

IMAGE_OPTIONAL_HEADEROptionalHeader;}IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS;其中,文件頭FileHeader的結(jié)構(gòu)體定義如下:TheIMAGE_FILE_HEADERstructurerepresentstheCOFFheaderformat.typedefstruct_IMAGE_FILE_HEADER{

WORDMachine;

WORDNumberOfSections;

DWORDTimeDateStamp;

DWORDPointerToSymbolTable;

DWORDNumberOfSymbols;

WORDSizeOfOptionalHeader;

WORDCharacteristics;}IMAGE_FILE_HEADER,*PIMAGE_FILE_HEADER;這個文件頭結(jié)構(gòu)中一個有用的入口是NumberOfSections域,它表示如果你要方便地提取文件信息的話,就需要了解多少個段,更明確一點來說,有多少個段頭部和多少個段實體。每一個段頭部和段實體都在文件中連續(xù)地排列著,所以要決定段頭部和段實體在哪里結(jié)束的話,段的數(shù)目是必需的。以下的語句從PE文件頭中提取了段的數(shù)目:numberofsection=peHeader->FileHeader.NumberOfSections; 3.4PE可選頭部PE可執(zhí)行文件中接下來的224個字節(jié)組成了PE可選頭部。雖然它的名字是“可選頭部”,但是請確信:這個頭部并非“可選”,而是“必需”的。可選頭部的偏移量即為:offset=dos_head->e_lfanew+SIZE_OF_NT_SIGNATURE(即:4)+sizeof(IMAGE_FILE_HEADER)??蛇x頭部包含了很多關(guān)于可執(zhí)行映像的重要信息,例如初始的堆棧大小、程序入口點的位置、首選基地址、操作系統(tǒng)版本、段對齊的信息等等。IMAGE_OPTIONAL_HEADER結(jié)構(gòu)如下:TheIMAGE_OPTIONAL_HEADERstructurerepresentstheoptionalheaderformat.typedefstruct_IMAGE_OPTIONAL_HEADER{

WORDMagic;

BYTEMajorLinkerVersion;

BYTEMinorLinkerVersion;

DWORDSizeOfCode;//Sizeofthecodesection,inbytes,orthesumofallsuchsections//iftherearemultiplecodesections.DWORDSizeOfInitializedData;//Sizeoftheinitializeddatasection,inbytes,or//thesumofallsuchsectionsiftherearemultipleinitializeddatasections.DWORDSizeOfUninitializedData;//Sizeoftheuninitializeddatasection,inbytes,orthesumofallsuchsectionsiftherearemultipleuninitializeddatasections.DWORDAddressOfEntryPoint;//Pointertotheentrypointfunction,relativetothe//imagebaseaddress.TheentrypointfunctionisoptionalforDLLs.Whennoentry//pointispresent,thismemberiszero.DWORDBaseOfCode;//Pointertothebeginningofthecodesection,relativetothe//imagebase.DWORDBaseOfData;//Pointertothebeginningofthedatasection,relativetothe//imagebase.DWORDImageBase;//Preferredaddressofthefirstbyteoftheimagewhenitisloaded//inmemory.Thisvalueisamultipleof64Kbytes.ThedefaultvalueforDLLsis//0x10000000.Thedefaultvalueforapplicationsis0x00400000.DWORDSectionAlignment;//Alignmentofsectionsloadedinmemory,inbytes.Thisvalue//mustbegreaterthanorequaltotheFileAlignmentmember.Thedefaultvalueisthe//pagesizeforthesystem.DWORDFileAlignment;

WORDMajorOperatingSystemVersion;

WORDMinorOperatingSystemVersion;

WORDMajorImageVersion;

WORDMinorImageVersion;

WORDMajorSubsystemVersion;

WORDMinorSubsystemVersion;

DWORDWin32VersionValue;

DWORDSizeOfImage;//Sizeoftheimage,inbytes,includingallheaders.Mustbea//multipleofSectionAlignment.DWORDSizeOfHeaders;//CombinedsizeoftheMS-DOSstub,thePEheader,andthesection//headers,roundedtoamultipleofthevaluespecifiedintheFileAlignmentmember.DWORDCheckSum;

WORDSubsystem;

WORDDllCharacteristics;

DWORDSizeOfStackReserve;

DWORDSizeOfStackCommit;

DWORDSizeOfHeapReserve;

DWORDSizeOfHeapCommit;

DWORDLoaderFlags;

DWORDNumberOfRvaAndSizes;

IMAGE_DATA_DIRECTORYDataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];}IMAGE_OPTIONAL_HEADER,*PIMAGE_OPTIONAL_HEADER;其中NumberOfRvaAndSizes這個域標(biāo)識了接下來的DataDirectory數(shù)組。請注意它被用來標(biāo)識這個數(shù)組,而不是數(shù)組中的各個入口數(shù)字,這一點非常重要。DataDirectory。數(shù)據(jù)目錄表示文件中其它可執(zhí)行信息重要組成部分的位置。它事實上就是一個IMAGE_DATA_DIRECTORY結(jié)構(gòu)的數(shù)組,位于可選頭部結(jié)構(gòu)的末尾。TheIMAGE_DATA_DIRECTORYstructurerepresentsthedatadirectory.typedefstruct_IMAGE_DATA_DIRECTORY{

DWORDVirtualAddress;

DWORDSize;}IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;當(dāng)前的PE文件格式定義了16種可能的數(shù)據(jù)目錄,這之中的11種現(xiàn)在在使用中。數(shù)據(jù)目錄的各個元素依次如下所示:Thefollowingisalistofthedatadirectories:Offset都是用于庫函數(shù)的引入Description都是用于庫函數(shù)的引入96Exporttableaddressandsize104Importtableaddressandsize//輸入表(引入表)112Resourcetableaddressandsize120Exceptiontableaddressandsize128Certificatetableaddressandsize136Baserelocationtableaddressandsize//重定位信息144Debugginginformationstartingaddressandsize152Architecture-specificdataaddressandsize160Globalpointerregisterrelativevirtualaddress168Threadlocalstorage(TLS)tableaddressandsize176Loadconfigurationtableaddressandsize184Boundimporttableaddressandsize//綁定輸入表(引入表)192Importaddresstableaddressandsize200Delayimportdescriptoraddressandsize208Reserved由上表可知,有如下定義#defineIMAGE_NUMBEROF_DIRECTORY_ENTRIES16。4PE文件節(jié)表(段頭部)PE文件規(guī)范由目前為止定義的那些頭部以及一個名為“段”的一般對象組成。段包含了文件的內(nèi)容,包括代碼、數(shù)據(jù)、資源以及其它可執(zhí)行信息,每個段都有一個頭部和一個實體(原始數(shù)據(jù))。我將在下面描述段頭部的有關(guān)信息,但是段實體則缺少一個嚴格的文件結(jié)構(gòu)。因此,它們幾乎可以被鏈接器按任何的方法組織,只要它的頭部填充了足夠能夠解釋數(shù)據(jù)的信息。段頭部定義如下:TheIMAGE_SECTION_HEADERstructurerepresentstheimagesectionheaderformat.typedefstruct_IMAGE_SECTION_HEADER{

BYTEName[IMAGE_SIZEOF_SHORT_NAME];

union{

DWORDPhysicalAddress;//Fileaddress.DWORDVirtualSize;//Totalsizeofthesectionwhenloadedintomemory,inbytes.//ifthisvalueisgreaterthantheSizeOfRawDatamember,thesectionisfilledwith//zeroes.}Misc;

DWORDVirtualAddress;//Addressofthefirstbyteofthesectionwhenloadedintomemory,//relativetotheimagebase.DWORDSizeOfRawData;//Sizeoftheinitializeddataondisk,inbytes.Thisvalue//mustbeamultipleoftheFileAlignmentmemberoftheIMAGE_OPTIONAL_HEADERstructure.//IfthisvalueislessthantheVirtualSizemember,theremainderofthesectionis//filledwithzeroes.Ifthesectioncontainsonlyuninitializeddata,thememberis//zero.DWORDPointerToRawData;//FilepointertothefirstpagewithintheCOFFfile.Thisvaluemust//beamultipleoftheFileAlignmentmemberoftheIMAGE_OPTIONAL_HEADERstructure.If//asectioncontainsonlyuninitializeddata,thismemberiszero.//本節(jié)在文件中的偏移量DWORDPointerToRelocations;//Filepointertothebeginningoftherelocationentries//forthesection.Iftherearenorelocations,thisvalueiszero.DWORDPointerToLinenumbers;//Filepointertothebeginningoftheline-number//entriesforthesection.IftherearenoCOFFlinenumbers,thisvalueiszero.WORDNumberOfRelocations;//Numberofrelocationentriesforthesection.Thisvalue//iszeroforexecutableimages.WORDNumberOfLinenumbers;//Numberofline-numberentriesforthesection.DWORDCharacteristics;}IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER;段頭部信息在文件中的位置已在圖1的(4)部分模擬出,要得到所有段頭部的總大小:SecAllSize=numberofsection*sizeof(IMAGE_SECTION_HEADER);由于PE文件標(biāo)志占4個字節(jié),通常有這樣的宏定義:#defineSIZE_OF_NT_SIGNATURE4,即可按如下方法得到:則第一個段頭部的偏移量可按如下方法得到:SecOffset=dos_head->e_lfanew+SIZE_OF_NT_SIGNATURE+sizeof(IMAGE_FILE_HEADER)+peHeader->FileHeader.SizeOfOptionalHeader;PE的所有段頭部是線性排列,且各段頭部大小相同,所以可將指向第一個段的指針向前移動sizeof(IMAGE_SECTION_HEADER)多個單元,以指向下一個段頭部。*(section_header+1)與section_header[1]指向同一個單元。5PE文件的輸入表輸入表的結(jié)構(gòu):輸入表是以一個IMAGE_IMPORT_DESCRIPTOR(IID)數(shù)組開始,一個程序要調(diào)用幾個dll就會有幾個IID項,即每個IID對應(yīng)于一個dll。IID結(jié)構(gòu):typedefstruct_IMAGE_IMPORT_DESCRIPTOR{Union{DWORDCharacteristics;//00hDWORDOriginalFirstThunk;//注釋1};DWORDTimeDateStamp;//04h時間標(biāo)志,可以忽略;DWORDForwarderChain;//08h正向鏈接索引,一般為0,當(dāng)程序引用一個dll//中的api,而這個api又引用其它dll中的api時用DWORDName;//0ChDLL名字的指針,以00結(jié)尾的ASCII字符的RVA地址;DWORDFirstThunk;//10h注釋2}IMAGE_IMPORT_DESCRIPTOR;由該結(jié)構(gòu)體可知,每一個描述輸入表信息的數(shù)據(jù)結(jié)構(gòu)在內(nèi)存中占20個字節(jié)。注釋1:該值為一個IMAGE_THUNK_DATA數(shù)組的RVA,其中的每個指針都指向IMAGE_IMPORT_BY_NAME結(jié)構(gòu)。(IMAGE_THUNK_DATA包含了一個指向IMAGE_IMPORT_BY_NAME結(jié)構(gòu)的指針,而非該結(jié)構(gòu)本身,即:有幾個IMAGE_IMPORT_BY_NAME結(jié)構(gòu),收集這些結(jié)構(gòu)的RVA(即:IMAGE_THUNK_DATA)組成一個數(shù)組,以0結(jié)尾,然后將數(shù)組的RVA(指針)放入OriginalFirst-Thunk)。IMAGE_THUNK_DATA的結(jié)構(gòu):typedefstruct_IMAGE_THUNK_DATA{Union{PBYTEForwarderString;//當(dāng)該結(jié)構(gòu)雙字最高位為1時,表示函數(shù)以序號方式輸//入,此時雙字低位為函數(shù)序號PDWORDFunction;//當(dāng)最高位為0時,表示函數(shù)以字符串類型的函數(shù)名方式輸//入,此時整個雙字的值是DWORDOrdinal;//一個RVA,指向一個MAGE_IMPORT_BY_NAME結(jié)構(gòu)//(如下定義)PIMAGE_IMPORT_BY_NAMEAddressOfData;}u1;}IMAGE_THUNK_DATA,*PIMAGE_THUNK_DATA;該結(jié)構(gòu)只占4個字節(jié),在文件中準(zhǔn)確定位到該塊數(shù)據(jù)時,只需要讀取4個字節(jié)。從而就可判斷所讀取的數(shù)據(jù)的最高為是為0還是為1,進而確定函數(shù)輸入方式。注意該值也是一個相對虛擬地址RVA,指示了IMAGE_IMPORT_BY_NAME結(jié)構(gòu)的數(shù)據(jù)地址。IMAGE_IMPORT_BY_NAME結(jié)構(gòu):typedefstruct_IMAGE_IMPORT_BY_NAME{WORDHint;//指示本函數(shù)在所駐留dll中的輸出表中的序號(不是必須的)BYTEName[1];//含有輸入函數(shù)的函數(shù)名,一個ASCII碼字符串,以NULL結(jié)尾}IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME;在應(yīng)用過程中,通常將IMAGE_IMPORT_BY_NAME自定義為如下的數(shù)據(jù)類型:typedefstruct_IMAGE_IMPORT_BY_NAME1{WORDHint;//指示本函數(shù)在所駐留dll中的輸出表中的序號(不是必須的)BYTEName[256];//含有輸入函數(shù)的函數(shù)名,一個ASCII碼字符串,以NULL結(jié)尾}IMAGE_IMPORT_BY_NAME1,*PIMAGE_IMPORT_BY_NAME1;注釋2:FirstThunk也是一個指向IMAGE_THUNK_DATA數(shù)組的RVA地址,如果不是一個指針,則就是該功能在DLL中的序號;注釋3:OriginalFirstThunk與FirstThunk在本質(zhì)上一致,不同在于:在pe文件被pe裝載器裝入之前,兩者一樣,指向同一個數(shù)組。當(dāng)pe文件被裝載器裝入之后,OriginalFirstThunk還指向原來的數(shù)組(INT輸入名字表:ImportNameTable),而FirstThunk則用調(diào)用的輸入函數(shù)在內(nèi)存的虛擬地址來代替表中的內(nèi)容,即指向的是一張指向輸入函數(shù)地址的表,稱為:IAT(輸入地址表:ImportAddressTable)。 綜上所述,可知輸入表有如下的文件存儲模式:5PE文件的輸出表輸出表的結(jié)構(gòu)定義:typedefstruct_IMAGE_EXPORT_DIRECTORY{DWORDCharacteristics;DWORDTimeDateStamp;WORDMajorVersion;WORDMinorVersion;DWORDName;DWORDBase;DWORDNumberOfFunctions;DWORDNumberOfNames;DWORDAddressOfFunctions;//RVAfrombaseofimageDWORDAddressOfNames;//RVAfrombaseofimageDWORDAddressOfNameOrdinals;//RVAfrombaseofimage}IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY;輸出表一般存在與dll文件中,很少出現(xiàn)在exe文件中(也有)。主要為可執(zhí)行文件修正其IAT提供信息和依據(jù);輸出表的位置在:pe頭的可選映像頭中的數(shù)據(jù)目錄表的第1個字段中,OffSet=PEHeader->OptionalHeader.DataDirectory[0].VirtualAddress處,這是一個相對虛擬地址。要定位到文件的真實物理地址,或者定位到文件映射后在內(nèi)存中的地址,只需要將OffSet轉(zhuǎn)化為真實物理地址的偏移地址,即:RVA-->RAW,若是后者,加上文件映射后的基址就可以準(zhǔn)確定位到相應(yīng)的內(nèi)存單元,以操作IED結(jié)構(gòu)數(shù)據(jù)。準(zhǔn)確定位后,只要讀取sizeof(IMAGE_EXPORT_DIRECTORY)字節(jié)的數(shù)據(jù),即可獲取輸出表的描述信息。說明:pBuffer為文件映射后的基址。輸出表指向一個IMAGE_EXPORT_DIRECTORY(IED),其結(jié)構(gòu)定義如下:typedefstructIMAGE_EXPORT_DIRECTORY{ULONGCharateristics;未使用,總為0ULONGTimeDateStamp;文件生成時間USHORTMajorVersion;主版本號,一般為0USHORTMinorVersion;次版本號,一般為0ULONGName;模塊中的真實名稱ULONGBase;基數(shù),加上序數(shù)就是函數(shù)地址數(shù)組的索引值//通常為1ULONGNumberOfFunctions;AddressOfFunction序列中的元素個數(shù)ULONGNumberOfNames;AddressOfNames序列中的元素個數(shù)PULONG*AddressOfFunctions;指向函數(shù)地址數(shù)組PULONG*AddressOfNames;函數(shù)名字的指針地址PUSHORT*AddressOfNameOndinals;指向輸出序號數(shù)組}IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY說明:01、NumberOfFunctions和NumberOfNames一般相等;

02、NumberOfNames此值一般表示以名稱輸出的函數(shù)個數(shù),通常與輸出函數(shù)總數(shù)相等。若為0,表示模塊僅僅通過序號引出。

通過上面的定義,輸出表在文件中有如下的存儲結(jié)構(gòu):注意:01.以上描述的地址均是RVA 02.第i個函數(shù)名稱與第i個輸出序號對應(yīng),但與第i個函數(shù)地址不對應(yīng)。他們之間存在如下的關(guān)系:第i個函數(shù)名稱對應(yīng)的地址=(RVA1—>RAW)+第i個輸出序號。6PE文件的重定位表為方便理解,作如下定義:PIMAGE_DOS_HEADERpDosHeader;//指向DOS頭部PIMAGE_NT_HEADERSpNTHeader;//指向NT頭部 PDWORDRelocTableRVA;//指向重定位表的相對虛擬地址的指針PIMAGE_BASE_RELOCATIONpReloc;//指向重定位表的真實地址首先,先判斷重定位表是否存在:RelocTableRVA=&(pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress),判斷RelocTableRVA是否為0即可。若不為0,則重定位表存在。重定位表的數(shù)據(jù)組織方式是由許多重定位塊串接而成。每個塊是必須以4字節(jié)對齊,用0填補空缺。重定位塊的結(jié)構(gòu)如下:typedefstruct_IMAGE_BASE_RELOCATION{DWORDVirtualAddress;DWORDSizeOfBlock;//WORDTypeOffset[1];}IMAGE_BASE_RELOCATION;(1)VirtualAddress:這組重定位數(shù)據(jù)的RVA地址。(2)SizeOfBlack:四個字節(jié),當(dāng)前重定位結(jié)構(gòu)的大小。(3)TypeOffset:是一個數(shù)組。數(shù)組每項大小是兩個字節(jié),其中高4位是重定位的類型,低12位是重定位地址,它與VirtualAddress相加就是PE映像需要修改的地址數(shù)據(jù)的指針。 每個重定位塊的每2個字節(jié)的低12位表示一個重定位數(shù)據(jù)的RVA,該RVA加上VirtualAddress就是該重定位數(shù)據(jù)的真實偏移地址RAW,RAW加上基地址就得到重定位數(shù)據(jù)的真實物理地址。把該地址中的數(shù)據(jù)(需要修正的數(shù)據(jù))減去IMAGE_OPTINAL_HEADER中的ImageBase,再加上當(dāng)前加載的實際基址就可以了。6PE文件的資源段通常情況,資源節(jié)的名稱一般都為:.rsrc。目前我們只考慮這種情況。Section的結(jié)構(gòu)說明如下:typedefstruct_IMAGE_SECTION_HEADER{ BYTEName[IMAGE_SIZEOF_SHORT_NAME]; Union{ DWORDPhysicalAddress; DWORDVirtualSize; }Misc; DWORDVirtualAddress; DWORDSizeOfRawData; DWORDPointerToRawData; DWORDPointerToRelocations; DWORDPointerToLinenumbers; WORDNumberOfRelocations; WORDNumberOfLinenumbers; DWORDCharacteristics;}IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER;獲取資源節(jié)表的首地址:IMAGE_DOS_HEADER*dosHeadA=(IMAGE_DOS_HEADER*)pFileSource;//DOS頭IMAGE_NT_HEADERS*ntHeadA=(IMAGE_NT_HEADERS*)(pFileSource+dosHeadA->e_lfanew);//NT頭IMAGE_SECTION_HEADER*secHeadA=(IMAGE_SECTION_HEADER*)((char*)ntHeadA+sizeof(IMAGE_NT_HEADERS));//第一個節(jié)的首地址//循環(huán)找出.rsrc節(jié)for(inti=0;i<ntHeadA->FileHeader.NumberOfSections;i++,secHeadA++){if(strcmp((char*)secHeadA->Name,".rsrc")==0){//找到.rsrc節(jié) ……break;}}下面是幾個需要用到的結(jié)構(gòu)與相關(guān)的解釋:typedefstruct_IMAGE_RESOURCE_DIRECTORY{//資源樹結(jié)構(gòu) DWORDCharacteristics;//標(biāo)識此資源的類型 DWORDTimeDateStamp; WORDMajorVersion; WORDMinorVersion; WORDNumberOfNamedEntries; WORDNumberOfIdEntries;//此結(jié)構(gòu)下還包含有的資源結(jié)構(gòu)樹,即:還有幾個子樹。//IMAGE_RESOURCE_DIRECTORY_ENTRYDirectoryEntries[];//請注意這里,下面還會講到。}IMAGE_RESOURCE_DIRECTORY,*PIMAGE_RESOURCE_DIRECTORY;根據(jù)節(jié)表,我們就可以找到資源的入口地址。IMAGE_RESOURCE_DIRECTORY*dirResourceA=(IMAGE_RESOURCE_DIRECTORY*)((char*)pFileSource+secHeadA->PointerToRawData);//得到資源入口地址此結(jié)構(gòu)的其他解釋請見VC的頭文件winnt.h.整個資源的結(jié)構(gòu)就好像一棵樹型,不同資源如:menu,icon,dialog,cursor等。都如同每根樹枝,樹枝的Characteristics會標(biāo)識不同的資源類型,而每根樹枝又會有子樹枝。這樣一直循環(huán),直到IMAGE_RESOURCE_DIRECTORY的NumberOfIdEntries為0時才結(jié)束。通常情況,子樹都分為三層。每一個子樹的類型由IMAGE_RESOURCE_DIRECTORY中的Characteristics來標(biāo)識。如:當(dāng)?shù)谝粚拥腃haracteristics==3時,則說明此結(jié)構(gòu)為ICON資源。Characteristics類型定義如下(可在winuser.h中找到):/**PredefinedResourceTypes*/#defineRT_CURSORMAKEINTRESOURCE(1)#defineRT_BITMAPMAKEINTRESOURCE(2)#defineRT_ICONMAKEINTRESOURCE(3)#defineRT_MENUMAKEINTRESOURCE(4)#defineRT_DIALOGMAKEINTRESOURCE(5)#defineRT_STRINGMAKEINTRESOURCE(6)#defineRT_FONTDIRMAKEINTRESOURCE(7)#defineRT_FONTMAKEINTRESOURCE(8)#defineRT_ACCELERATORMAKEINTRESOURCE(9)#defineRT_RCDATAMAKEINTRESOURCE(10)#defineRT_MESSAGETABLEMAKEINTRESOURCE(11)要得到每個子資源的入口地址。這里要用到的一個結(jié)構(gòu)是:typedefstruct_IMAGE_RESOURCE_DIRECTORY_ENTRY{ Union { struct { DWORDNameOffset:31; DWORDNameIsString:1; }; DWORDName; WORDId; }; Union { DWORDOffsetToData;//指向資源的入口址 struct { DWORDOffsetToDirectory:31; DWORDDataIsDirectory:1;//指向下一級目錄的相對地址 }; };}IMAGE_RESOURCE_DIRECTORY_ENTRY,*PIMAGE_RESOURCE_DIRECTORY_ENTRY;上面對IMAGE_RESOURCE_DIRECTORY_ENTRY的解釋也已經(jīng)是非常清楚了。結(jié)構(gòu)中有兩個成員:OffsetToData,DataIsDirectroy,當(dāng)DataIsDirectroy大于0時,則說明此結(jié)構(gòu)還有下一級目錄,否則,OffsetToData肯定不為0。那OffsetToData的值就是我們所得到的資源入口的RVA了。那么,IMAGE_RESOURCE_DIRECTORY_ENTRY結(jié)構(gòu)應(yīng)該怎么得到呢?讓我們再看一下,IMAGE_RESOURCE_DIRECTORY的結(jié)構(gòu)說明吧。typedefstruct_IMAGE_RESOURCE_DIRECTORY{//資源樹結(jié)構(gòu) DWORDCharacteristics;//標(biāo)識此資源的類型 DWORDTimeDateStamp; WORDMajorVersion; WORDMinorVersion; WORDNumberOfNamedEntries; WORDNumberOfIdEntries;// //IMAGE_RESOURCE_DIRECTORY_ENTRYDirectoryEntries[];緊跟在后 //面的就是MAGE_RESOURCE_DIRECTORY_ENTRY結(jié)構(gòu)數(shù)組, //DirectoryEntries數(shù)組的個數(shù)實際上也就是NumberOfIdEntries.你也可以 //理解為IMAGE_RESOURCE_DIRECTORY_ENTRY //DirectoryEntries[NumberOfIdEntri

溫馨提示

  • 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論