西西軟件園多重安全檢測(cè)下載網(wǎng)站、值得信賴的軟件下載站!
軟件
軟件
文章
搜索

首頁(yè)編程開(kāi)發(fā)其它知識(shí) → windows pe 詳細(xì)介紹

windows pe 詳細(xì)介紹

相關(guān)軟件相關(guān)文章發(fā)表評(píng)論 來(lái)源:本站原創(chuàng)時(shí)間:2010/3/26 13:32:19字體大。A-A+

作者:不詳點(diǎn)擊:357次評(píng)論:6次標(biāo)簽: pe

金山打字通20152.1.0.34 官方最新版
  • 類型:教育學(xué)習(xí)大。26.6M語(yǔ)言:中文 評(píng)分:7.8
  • 標(biāo)簽:
立即下載

pe文件結(jié)構(gòu)圖PE文件被稱為可移植的執(zhí)行體是Portable Execute的全稱,常見(jiàn)的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微軟Windows操作系統(tǒng)上的程序文件(可能是間接被執(zhí)行,如DLL)
  一個(gè)操作系統(tǒng)的可執(zhí)行文件格式在很多方面是這個(gè)系統(tǒng)的一面鏡子。雖然學(xué)習(xí)一個(gè)可執(zhí)行文件格式通常不是一個(gè)程序員的首要任務(wù),但是你可以從這其中學(xué)到大量的知識(shí)。在這篇文章中,我會(huì)給出 MicroSoft 的所有基于 win32系統(tǒng)(如winnt,win9x)的可移植可執(zhí)行(PE)文件格式的詳細(xì)介紹。在可預(yù)知的未來(lái),包括 Windows2000 , PE 文件格式在 MicroSoft 的操作系統(tǒng)中扮演一個(gè)重要的角色。如果你在使用 Win32 或 Winnt ,那么你已經(jīng)在使用 PE 文件了。甚至你只是在 Windows3.1 下使用 Visual C++ 編程,你使用的仍然是 PE 文件(Visual C++ 的 32 位 MS-DOS 擴(kuò)展組件用這個(gè)格式)。簡(jiǎn)而言之,PE 格式已經(jīng)普遍應(yīng)用,并且在不短的將來(lái)仍是不可避免的,F(xiàn)在是時(shí)候找出這種新的可執(zhí)行文件格式為操作系統(tǒng)帶來(lái)的東西了。
  我最后不會(huì)讓你盯住無(wú)窮無(wú)盡的十六進(jìn)制Dump,也不會(huì)詳細(xì)討論頁(yè)面的每一個(gè)單獨(dú)的位的重要性。代替的,我會(huì)向你介紹包含在 PE 文件中的概念,并且將他們和你每天都遇到的東西聯(lián)系起來(lái)。比如,線程局部變量的概念,如下所述:
  declspec(thread) int i;
  我快要發(fā)瘋了,直到我發(fā)現(xiàn)它在可執(zhí)行文件中實(shí)現(xiàn)起來(lái)是如此的簡(jiǎn)單并且優(yōu)雅。既然你們中的許多人都有使用 16 Windows 的背景,我將把 Win32 PE 文件的構(gòu)造追溯到和它等價(jià)的16 位 NE 文件。
  除了一個(gè)不同的可執(zhí)行文件格式, MicroSoft 還引入了一個(gè)用它的編譯器和匯編器生成的新的目標(biāo)模塊格式。這個(gè)新的 OBJ 文件格式有許多和PE 文件共同的東東。我做了許多無(wú)用功去查找這個(gè)新的 OBJ 文件格式的文檔。所以我以自己的理解對(duì)它進(jìn)行解析,并且,在這里,除了 PE 文件,我會(huì)描述它的一部分。
  大家都知道,Windows NT 繼承了 VAX? VMS? 和 UNIX? 的傳統(tǒng)。許多 Windows NT 的創(chuàng)始人在進(jìn)入微軟前都在這些平臺(tái)上進(jìn)行設(shè)計(jì)和編碼。當(dāng)他們開(kāi)始設(shè)計(jì) Windows NT 時(shí),很自然的,為了最小化項(xiàng)目啟動(dòng)時(shí)間,他們會(huì)使用以前寫(xiě)好的并且已經(jīng)測(cè)試過(guò)的工具。用這些工具生成的并且工作的可執(zhí)行和 OBJ 文件格式叫做 COFF (Common Object File Format 的首字母縮寫(xiě))。COFF 的相對(duì)年齡可以用八進(jìn)制的域來(lái)指定。COFF 本身是一個(gè)好的起點(diǎn),但是需要擴(kuò)展到一個(gè)現(xiàn)代操作系統(tǒng)如 Windows 95 和 Windows NT 的需要。這個(gè)更新的結(jié)果就是(PE格式)可移植可執(zhí)行文件格式。它被稱為"可移植的"是因?yàn)樵谒衅脚_(tái)(如x86,Alpha,MIPS等等)上實(shí)現(xiàn)的WindowsNT 都使用相同的可執(zhí)行文件格式。當(dāng)然了,也有許多不同的東西如二進(jìn)制代碼的CPU指令。重要的是操作系統(tǒng)的裝入器和程序設(shè)計(jì)工具不需要為任何一種CPU完全重寫(xiě)就能達(dá)到目的。
  MicroSoft 拋棄現(xiàn)存的32位工具和可執(zhí)行文件格式的事實(shí)證實(shí)了他們想讓 WindowsNT 升級(jí)并且運(yùn)行的更快的決心。為16位Windows編寫(xiě)的虛擬設(shè)備驅(qū)動(dòng)程序用一種不同的32位文件布局--LE 文件格式--WindowsNT出現(xiàn)很早以前就存在了。比這更重要的是對(duì) OBJ 文件的替換!在 WindowsNT 的 C 編譯器以前,所有的微軟編譯器都用 Intel 的 OMF ( Object Module Format ) 規(guī)范。就像前面提到的,MicroSoft 的 Win32 編譯器生成 COFF 格式的 OBJ 文件。一些微軟的競(jìng)爭(zhēng)者,如 Borland 和 Symentec ,選擇放棄了 COFF 格式并堅(jiān)持 Intel 的 OMF 文件格式。這樣的結(jié)果是制作 OBJ 和 LIB 的公司為了使用多個(gè)不同的編譯器,不得不為每個(gè)不同的編譯器分發(fā)這些庫(kù)的不同版本(如果他們不這么做)。
  PE 文件格式在 winnt.h 頭文件中文檔化了(用最不精確的語(yǔ)言)!大約在 winnt.h 的中間部分標(biāo)題為"Image Format"的一個(gè)快。在把 MS-DOS 的 MZ 文件頭和 NE 文件頭移入新的PE文件頭之前,這個(gè)塊就開(kāi)始于一個(gè)小欄。WINNT.H提供PE文件用到的生鮮數(shù)據(jù)結(jié)構(gòu)的定義,但只有很少有助于理解這些數(shù)據(jù)結(jié)構(gòu)和標(biāo)志變量的注釋。不管誰(shuí)為PE文件格式寫(xiě)出這樣的頭文件都肯定是一個(gè)信徒無(wú)疑(突然持續(xù)地冒出Michael J. O'Leary的名字來(lái))。描述名字,連同深嵌的結(jié)構(gòu)體和宏。當(dāng)你配套winnt.h進(jìn)行編碼時(shí),類似下面這樣的表達(dá)式并不鮮見(jiàn):
  pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]
  .VirtualAddress;
  為了有助于邏輯的理解這些winnt.h中的信息,閱讀可移植可執(zhí)行和公共對(duì)象文件格式的規(guī)格說(shuō)明,這些在MSDN既看光盤(pán)中是可用的,一直包括到2001年8月。
  現(xiàn)在讓我們轉(zhuǎn)換到COFF格式的OBJ文件的主體上來(lái),WINNT.H包括COFF OBJ和LIB的結(jié)構(gòu)化定義和類型定義。不幸的是,我還沒(méi)有找到上面提到的可執(zhí)行文件格式的類似文檔。既然PE文件和COFF OBJ文件是如此的相似,我決定是時(shí)間把這些文件帶到重點(diǎn)上來(lái),并且把它們也文檔化。僅僅讀過(guò)了關(guān)于PE文件的組成,你自己也想Dump一些PE文件來(lái)看這些概念。如果你用微軟基于32位WINDOWS的開(kāi)發(fā)工具,DUMPBIN 程序可以將PE文件和COFF OBJ/LIB文件轉(zhuǎn)化為可讀的形式。在所有的PEDump器中,DUMPBIN是最容易理解的。它恰好有一些很好的選項(xiàng)來(lái)反匯編它正解析的文件的代碼塊,Borland用戶可以使用tdump來(lái)瀏覽PE文件,但tdump不能解析 COFF OBJ/LIB 文件。這不是一個(gè)重要的東西因?yàn)锽orland的編譯器首先就不生成 COFF 格式的OBJ文件。
  我寫(xiě)了一個(gè)PE和COFF OBJ 文件的Dump程序--PEDUMP,我想提供一些比DUMPBIN更加可理解的輸出。雖然它沒(méi)有反匯編器以及和LIB庫(kù)文件一起工作,它在其他方面和DUMPBIN是一樣的,并且加入了一些新的特性來(lái)使它值得被認(rèn)同。它的源代碼在任何一個(gè)MSJ電子公報(bào)版上都可以找到,所有我不打算在這里把他全部列出。作為代替,我展示一些從PEDUMP得到的示例輸出來(lái)闡明我為它們描述的概念。
  譯注:--說(shuō)實(shí)話,我從這這份代碼中幾乎唯一學(xué)到的東西就是"如何處理命令行",其它的都沒(méi)學(xué)到。
  表 1 PEDUMP.C
  file://--------------------/
  // PROGRAM: PEDUMP
  // FILE: PEDUMP.C
  // AUTHOR: Matt Pietrek - 1993
  file://--------------------/
  #include <windows.h>
  #include <stdio.h>
  #include "objdump.h"
  #include "exedump.h"
  #include "extrnvar.h"
  // Global variables set here, and used in EXEDUMP.C and OBJDUMP.C
  BOOL fShowRelocations = FALSE;
  BOOL fShowRawSectionData = FALSE;
  BOOL fShowSymbolTable = FALSE;
  BOOL fShowLineNumbers = FALSE;
  char HelpText[] =
  "PEDUMP - Win32/COFF .EXE/.OBJ file dumper - 1993 Matt Pietrek\n\n"
  "Syntax: PEDUMP [switches] filename\n\n"
  " /A include everything in dump\n"
  " /H include hex dump of sections\n"
  " /L include line number information\n"
  " /R show base relocations\n"
  " /S show symbol table\n";
  // Open up a file, memory map it, and call the appropriate dumping routine
  void DumpFile(LPSTR filename)
  HANDLE hFile;
  HANDLE hFileMapping;
  LPVOID lpFileBase;
  PIMAGE_DOS_HEADER dosHeader;
  hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  if ( hFile = = INVALID_HANDLE_VALUE )
  { printf("Couldn't open file with CreateFile()\n");
  return; }
  hFileMapping = CreateFileMapping(hFile, NULL,
  PAGE_READONLY, 0, 0, NULL);
  if ( hFileMapping = = 0 )
  {
  CloseHandle(hFile);
  printf("Couldn't open file mapping with CreateFileMapping()\n");
  return;
  lpFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
  if ( lpFileBase = = 0 )
  CloseHandle(hFileMapping);
  CloseHandle(hFile);
  printf("Couldn't map view of file with MapViewOfFile()\n");
  return;
  printf("Dump of file %s\n\n", filename);
  dosHeader = (PIMAGE_DOS_HEADER)lpFileBase;
  if ( dosHeader->e_magic = = IMAGE_DOS_SIGNATURE )
  { DumpExeFile( dosHeader ); }
  else if ( (dosHeader->e_magic = = 0x014C) // Does it look like a i386
  && (dosHeader->e_sp = = 0) ) // COFF OBJ file???
  // The two tests above aren't what they look like. They're
  // really checking for IMAGE_FILE_HEADER.Machine = = i386 (0x14C)
  // and IMAGE_FILE_HEADER.SizeOfOptionalHeader = = 0;
  DumpObjFile( (PIMAGE_FILE_HEADER)lpFileBase );
  else
  printf("unrecognized file format\n");
  UnmapViewOfFile(lpFileBase);
  CloseHandle(hFileMapping);
  CloseHandle(hFile);
  // process all the command line arguments and return a pointer to
  // the filename argument.
  PSTR ProcessCommandLine(int argc, char *argv[])
  int i;
  for ( i=1; i < argc; i++ )
  strupr(argv);
  // Is it a switch character?
  if ( (argv[0] = = '-') || (argv[0] = = '/') )
  if ( argv[1] = = 'A' )
  { fShowRelocations = TRUE;
  fShowRawSectionData = TRUE;
  fShowSymbolTable = TRUE;
  fShowLineNumbers = TRUE; }
  else if ( argv[1] = = 'H' )
  fShowRawSectionData = TRUE;
  else if ( argv[1] = = 'L' )
  fShowLineNumbers = TRUE;
  else if ( argv[1] = = 'R' )
  fShowRelocations = TRUE;
  else if ( argv[1] = = 'S' )
  fShowSymbolTable = TRUE;
  else // Not a switch character. Must be the filename
  { return argv; }
  int main(int argc, char *argv[])
  PSTR filename;
  if ( argc = = 1 )
  { printf( HelpText );
  return 1; }
  filename = ProcessCommandLine(argc, argv);
  if ( filename )
  DumpFile( filename );
  return 0;
  }
  1 WIN32 與 PE 基本概念
  讓我們復(fù)習(xí)一下幾個(gè)透過(guò)PE文件的設(shè)計(jì)了解到的基本概念。我用術(shù)語(yǔ)"MODULE"來(lái)表示一個(gè)可執(zhí)行文件或一個(gè)DLL載入內(nèi)存的代碼(CODE)、數(shù)據(jù)(DATA)、資源(RESOURCES),除了代碼和數(shù)據(jù)是你的程序直接使用的,一個(gè)模塊還可以由WINDOWS用來(lái)確定數(shù)據(jù)和代碼載入的位置的支撐數(shù)據(jù)結(jié)構(gòu)組成。在16位WINDOWS中,這些支撐數(shù)據(jù)結(jié)構(gòu)在模塊數(shù)據(jù)庫(kù)(用一個(gè)HMODULE來(lái)指示的段)中。在WIN32里面,這些數(shù)據(jù)結(jié)構(gòu)在PE文件頭中,這些我將會(huì)簡(jiǎn)要地解釋一下。
  PE文件略圖
  關(guān)于PE文件最重要的是,磁盤(pán)上的可執(zhí)行文件和它被WINDOWS調(diào)入內(nèi)存之后是非常相像的。WINDOWS載入器不必為從磁盤(pán)上載入一個(gè)文件而辛辛苦苦創(chuàng)建一個(gè)進(jìn)程。載入器使用內(nèi)存映射文件機(jī)制來(lái)把文件中相似的塊映射到虛擬空間中。用一個(gè)構(gòu)造式的分析模型,一個(gè)PE文件類似一個(gè)預(yù)制的屋子。它本質(zhì)上開(kāi)始于這樣一個(gè)空間,這個(gè)空間后面有幾個(gè)把它連到其余空間的機(jī)件(就是說(shuō),把它聯(lián)系到它的DLL上,等等)。這對(duì)PE格式的DLL是一樣容易應(yīng)用的。一旦這個(gè)模塊被載入,Windows 就可以有效的把它和其它內(nèi)存映射文件同等對(duì)待。
  和16位Windows不同的是。16位NE文件的載入器讀取文件的一部分并且創(chuàng)建完全不同的數(shù)據(jù)結(jié)構(gòu)在內(nèi)存中表示模塊。當(dāng)數(shù)據(jù)段或者代碼段需要載入時(shí),載入器必須從全局堆中新申請(qǐng)一個(gè)段,從可執(zhí)行文件中找出生鮮數(shù)據(jù),轉(zhuǎn)到這個(gè)位置,讀入這些生鮮數(shù)據(jù),并且要進(jìn)行適當(dāng)?shù)男拚3硕,每個(gè)16位模塊都有責(zé)任記住當(dāng)前它使用的所有段選擇器,而不管這個(gè)段是否被丟棄了,如此等等。
  對(duì)Win32來(lái)講,模塊所使用的所有代碼,數(shù)據(jù),資源,導(dǎo)入表,和其它需要的模塊數(shù)據(jù)結(jié)構(gòu)都在一個(gè)連續(xù)的內(nèi)存塊中。在這種形勢(shì)下,你只需要知道載入器把可執(zhí)行文件映射到了什么地方。通過(guò)作為映像的一部分的指針,你可以很容易的找到這個(gè)模塊所有不同的塊。
  另一個(gè)你需要知道的概念是相對(duì)虛擬地址(RVA)。PE文件中的許多域都用術(shù)語(yǔ)RVA來(lái)指定。一個(gè)RVA只是一些項(xiàng)目相對(duì)于文件映射到內(nèi)存的偏移。比如說(shuō),載入器把一個(gè)文件映射到虛擬地址0x10000開(kāi)始的內(nèi)存塊。如果一個(gè)映像中的實(shí)際的表的首址是0x10464,那么它的RVA就是0x464。
  (虛擬地址 0x10464)-(基地址 0x10000)=RVA 0x00464
  為了把一個(gè)RVA轉(zhuǎn)化成一個(gè)有用的指針,只需要把RVA值加到模塊的基地址上即可;刂肥莾(nèi)存映射EXE和DLL文件的首址,在Win32中這是一個(gè)很重要的概念。為了方便起見(jiàn),WindowsNT 和 Windows9x用模塊的基地址作為這個(gè)模塊的實(shí)例句柄(HINSTANCE)。在Win32中,把模塊的基地址叫做HINSTANCE可能導(dǎo)致混淆,因?yàn)樾g(shù)語(yǔ)"實(shí)例句柄"來(lái)自16位Windows。一個(gè)程序在16位Windows中的每個(gè)拷貝得到它自己分開(kāi)的數(shù)據(jù)段(和一個(gè)聯(lián)系起來(lái)的全局句柄)來(lái)把它和這個(gè)程序其它的拷貝分別開(kāi)來(lái),就形成了術(shù)語(yǔ)"實(shí)例句柄"。在Win32中,每個(gè)程序不必和其它程序區(qū)別開(kāi)來(lái),因?yàn)樗麄儾还蚕硐嗤牡刂房臻g。術(shù)語(yǔ)INSTANCE仍然保持16位windows和32位Windows之間的連續(xù)性。在Win32中重要的是你可以對(duì)任何DLL調(diào)用GetModuleHandle()得到一個(gè)指針去訪問(wèn)它的組件(譯注)。
  譯注:如果 dllname 為 NULL,則得到執(zhí)行體自己的模塊句柄。這是非常有用的,如通常編譯器產(chǎn)生的啟動(dòng)代碼將取得這個(gè)句柄并將它作為一個(gè)參數(shù)hInstance傳給WinMain !
  你最終需要理解的PE文件的概念是"塊(Section)"。PE文件中的一個(gè)塊和NE文件中的一個(gè)段或者資源等價(jià)。塊可以包含代碼或者數(shù)據(jù)。和段不同的是,塊是內(nèi)存中連續(xù)的空間,而沒(méi)有尺寸限制。當(dāng)你的連接器和庫(kù)為你建立,并且包含對(duì)操作系統(tǒng)非常重要的信息的其它的數(shù)據(jù)塊時(shí),這些塊包含你的程序直接聲明和使用的代碼或數(shù)據(jù)。在一些PE格式的描述中,塊也叫做對(duì)象。術(shù)語(yǔ)對(duì)象有如此多的涵義,以至于只能把代碼和數(shù)據(jù)叫做"塊"。
  2 PE首部
  和其它可執(zhí)行文件格式一樣,PE文件在眾所周知的地方有一些定義文件其余部分面貌的域。首部就包含這樣象代碼和數(shù)據(jù)的位置和尺寸的地方,操作系統(tǒng)要對(duì)它進(jìn)行干預(yù),比如初始堆棧大小,和其它重要的塊的信息,我將要簡(jiǎn)短的介紹一下。和微軟其它可執(zhí)行格式相比,主要的首部不是在文件的最開(kāi)始。典型的PE文件最開(kāi)始的數(shù)百個(gè)字節(jié)被DOS殘留部分占用。這個(gè)殘留部分是一個(gè)可以打印如"這個(gè)程序不能在DOS下運(yùn)行!"這類信息的小程序。所以,你在一個(gè)不支持Win32的系統(tǒng)中運(yùn)行這個(gè)程序,便可以得到這類錯(cuò)誤信息。當(dāng)載入器把一個(gè)Win32程序映射到內(nèi)存,這個(gè)映射文件的第一個(gè)字節(jié)對(duì)應(yīng)于DOS殘留部分的第一個(gè)字節(jié)。那是無(wú)疑的。和你啟動(dòng)的任一個(gè)基于Win32 的程序一起,都有一個(gè)基于DOS的程序連帶被載入。
  和微軟的其它可執(zhí)行格式一樣,你可以通過(guò)查找它的起始偏移來(lái)得到真實(shí)首部,這個(gè)偏移放在DOS殘留首部中。WINNT.H頭文件包含了DOS殘留程序的數(shù)據(jù)結(jié)構(gòu)定義,使得很容易找到PE首部的起始位置。e_lfanew 域是PE真實(shí)首部的偏移。為了得到PE首部在內(nèi)存中的指針,只需要把這個(gè)值加到映像的基址上即可。
  file://忽/略類型轉(zhuǎn)化和指針轉(zhuǎn)化 ...
  pNTHeader = dosHeader + dosHeader->e_lfanew;
  一旦你有了PE主首部的指針,游戲就可以開(kāi)始了!PE主首部是一個(gè)IMAGE_NT_HEADERS的結(jié)構(gòu),在WINNT.H中定義。這個(gè)結(jié)構(gòu)由一個(gè)雙字(DWORD)和兩個(gè)子結(jié)構(gòu)組成,布局如下:
  DWORD Signature;
  IMAGE_FILE_HEADER FileHeader;
  IMAGE_OPTIONAL_HEADER OptionalHeader;
  標(biāo)志域用ASCII表示就是"PE"。如果在DOS首部中用了e_lfanew域,你得到一個(gè)NE標(biāo)志而不是PE,那么這是16位NE文件。同樣的,在標(biāo)志域中的LE表示這是一個(gè)Windows3.x 的虛擬設(shè)備驅(qū)動(dòng)程序(VxD)。LX表示這個(gè)文件是OS/2 2.0文件。
  PE DWORD標(biāo)志后的是結(jié)構(gòu) IMAGE_FILE_HEADER 。這個(gè)域只包含這個(gè)文件最基本的信息。這個(gè)結(jié)構(gòu)表現(xiàn)為并未從它的原始COFF實(shí)現(xiàn)更改過(guò)。除了是PE首部的一部分,它還表現(xiàn)在微軟Win32編譯器生成的COFF OBJ 文件的最開(kāi)始部分。IMAGE_FILE_HEADER的這個(gè)域顯示在下面:
  表2 IMAGE_FILE_HEADER Fields
  WORD Machine
  表示CPU的類型,下面定義了一些CPU的ID
  0x14d Intel i860
  0x14c Intel I386 (same ID used for 486 and 586)
  0x162 MIPS R3000
  0x166 MIPS R4000
  0x183 DEC Alpha AXP
  WORD NumberOfSections
  這個(gè)文件中的塊數(shù)目。
  DWORD TimeDateStamp
  連接器產(chǎn)生這個(gè)文件的日期(對(duì)OBJ文件是編譯器),這個(gè)域保存的數(shù)是從1969年12月下午4:00開(kāi)始到現(xiàn)在經(jīng)過(guò)的秒數(shù)。
  DWORD PointerToSymbolTable
  COFF符號(hào)表的文件偏移量。這個(gè)域只用于有COFF調(diào)試信息的OBJ文件和PE文件,PE文件支持多種調(diào)試信息格式,所以調(diào)試器應(yīng)該指向數(shù)據(jù)目錄的IMAGE_DIRECTORY_ENTRY_DEBUG條目。
  DWORD NumberOfSymbols
  COFF符號(hào)表的符號(hào)數(shù)目。見(jiàn)上面。
  WORD SizeOfOptionalHeader
  這個(gè)結(jié)構(gòu)后面的可選首部的尺寸。在OBJ文件中,這個(gè)域是0。在可執(zhí)行文件中,這是跟在這個(gè)結(jié)構(gòu)后的IMAGE_OPTIONAL_HEADER結(jié)構(gòu)的尺寸。
  WORD Characteristics
  關(guān)于這個(gè)文件信息的標(biāo)志。一些重要的域如下:
  0x0001 這個(gè)文件中沒(méi)有重定位信息
  0x0002 可執(zhí)行文件映像(不是OBJ或LIB文件)
  0x2000 文件是動(dòng)態(tài)連接庫(kù),而非程序
  其它域定義在WINNT.H中。
  PE首部的第三個(gè)組成部分是一個(gè)IMAGE_OPTIONAL_HEADER型的結(jié)構(gòu)。對(duì)PE文件,這一部分當(dāng)然不是"可選的"。COFF格式允許單獨(dú)實(shí)現(xiàn)來(lái)定義一個(gè)超出標(biāo)準(zhǔn)IMAGE_FILE_HEADER附加信息的結(jié)構(gòu)。IMAGE_OPTIONAL_HEADER里面的域是PE的實(shí)現(xiàn)者感到超出IMAGE_FILE_HEADER基本信息以外非常關(guān)鍵的信息。
  并非 IMAGE_OPTIONAL_HEADER 的所有域都是重要的(見(jiàn)圖4)。比較重要,需要知道的是ImageBase 和 SubSystem 域。你可以忽略其它域的描述。
  表3 IMAGE_FILE_HEADER 的域:
  WORD Magic
  表現(xiàn)為一些類別的標(biāo)志字,通常是0X010B 。
  BYTE MajorLinkerVersion
  BYTE MinorLinkerVersion
  生成這個(gè)文件的連接器的版本。這個(gè)數(shù)字以十進(jìn)制顯示比用十六進(jìn)制好。一個(gè)典型的連接器版本是2.23。
  DWORD SizeOfCode
  所有代碼塊的進(jìn)位尺寸。通常大多數(shù)文件只有一個(gè)代碼塊,所以這個(gè)域和 .TEXT 塊匹配。
  DWORD SizeOfInitializedData
  已初始化的數(shù)據(jù)組成的塊的大。ú话ùa段)。然而,和它在文件中的表現(xiàn)形式并不一致。
  DWORD SizeOfUninitializedData
  載入器在虛擬內(nèi)存中申請(qǐng)空間,但在磁盤(pán)上的文件中并不占用空間的塊的尺寸。這些塊在程序啟動(dòng)時(shí)不需要指定初值,因此術(shù)語(yǔ)名就是"未初始化的數(shù)據(jù)"。未初始化的數(shù)據(jù)通常在一個(gè)名叫 .bss 的塊中。
  DWORD AddressOfEntryPoint
  載入器開(kāi)始執(zhí)行這個(gè)程序的地址,即這個(gè)PE文件的入口地址。這是一個(gè)RVA,通常在 .text 塊中。
  DWORD BaseOfCode
  代碼塊起始地址的RVA 。在內(nèi)存中,代碼塊通常在PE首部之后,數(shù)據(jù)塊之前。在微軟的連接器產(chǎn)生的EXE文件中,這個(gè)值通常是0x1000 。Borland 的連接器 TLINK32 也一樣,把映像第一個(gè)代碼塊的RVA和映像基址相加,填入這個(gè)域。
  譯注:這個(gè)域好像一直沒(méi)有什么用
  DWORD BaseOfData
  數(shù)據(jù)塊起始地址的RVA 。在內(nèi)存中,數(shù)據(jù)塊經(jīng)常在最后,在PE首部和代碼塊之后。
  譯注:這個(gè)域好像也一直沒(méi)有什么用
  DWORD ImageBase
  連接器創(chuàng)建一個(gè)可執(zhí)行文件時(shí),它假定這個(gè)文件被映射到內(nèi)存中的一個(gè)指定的地方,這個(gè)地址就存在這個(gè)域中,假定一個(gè)載入地址可以使連接器優(yōu)化以便節(jié)省空間。如果載入器真的把這個(gè)文件映射到了這個(gè)地方,在運(yùn)行之前代碼不需要任何改變。在為WindowsNT 創(chuàng)建的可執(zhí)行文件中,默認(rèn)的ImageBase 是0x10000。對(duì)DLL,默認(rèn)是0x40000。在Window95中,地址0x10000不能用來(lái)載入32位EXE文件,因?yàn)檫@個(gè)區(qū)域在一個(gè)被所有進(jìn)程共享的線性地址空間中。因此,微軟把Win32可執(zhí)行文件的默認(rèn)基址改為0x40000,假定基址為0x10000 的老程序坐在Windows95 中需要更長(zhǎng)的載入時(shí)間,這是因?yàn)檩d入器需要重定位基址。
  譯注:這個(gè)域即"Prefered Load Address",如果沒(méi)有什么意外,這就是該P(yáng)E文件載入內(nèi)存后的地址。
  DWORD SectionAlignment
  映射到內(nèi)存中時(shí),每個(gè)塊都必須保證開(kāi)始于這個(gè)值的整數(shù)倍。為了分頁(yè)的目的,默認(rèn)的SectionAlignment 是 0x1000。
  DWORD FileAlignment
  在PE文件中,組成每個(gè)塊的生鮮數(shù)據(jù)必須保證開(kāi)始于這個(gè)值的整數(shù)倍。默認(rèn)值是0x200 字節(jié),也許是為了保證塊都開(kāi)始于一個(gè)磁盤(pán)扇區(qū)(一個(gè)扇區(qū)通常是 512 字節(jié))。這個(gè)域和NE文件中的段/資源對(duì)齊(segment/resource alignment)尺寸是等價(jià)的。和NE文件不同的是,PE文件通常沒(méi)有數(shù)百個(gè)的塊,所以,為了對(duì)齊而浪費(fèi)的通?臻g很少。
  WORD MajorOperatingSystemVersion
  WORD MinorOperatingSystemVersion
  這個(gè)程序運(yùn)行需要的操作系統(tǒng)的最小版本號(hào)。這個(gè)域有點(diǎn)含糊,因?yàn)镾ubsystem 域(后面將會(huì)說(shuō)到)可以提供類似的功能。這個(gè)域在到目前為止的Win32中默認(rèn)是1.0。
  WORD MajorImageVersion
  WORD MinorImageVersion
  一個(gè)可由用戶定義的域。這允許你有不同的EXE和DLL版本。你可以通過(guò)鏈接器的 /version 選項(xiàng)設(shè)置這個(gè)域的值。例如:"link /version:2.0 myobj.obj"。
  WORD MajorSubsystemVersion
  WORD MinorSubsystemVersion
  這個(gè)程序運(yùn)行需要的最小子系統(tǒng)版本號(hào)。這個(gè)域的一個(gè)典型值是3.10 (表示W(wǎng)indowsNT 3.1)。
  DWORD Reserved1
  通常是 0 。
  DWORD SizeOfImage
  載入器必須關(guān)心的這個(gè)映像所有部分的大小總和。是從映像的開(kāi)始到最后一個(gè)塊結(jié)尾這段區(qū)域的大小。最后一個(gè)塊結(jié)尾按SectionAlignment進(jìn)位。
  譯注:這個(gè)很重要,可以大,但不可以!
  DWORD SizeOfHeaders
  PE首部和塊表的大小。塊的實(shí)際數(shù)據(jù)緊跟在所有首部組件之后。
  DWORD CheckSum
  這個(gè)文件的CRC校驗(yàn)和。在微軟可執(zhí)行格式中,這個(gè)域被忽略并且置為0 。這個(gè)規(guī)則的一個(gè)例外情況是信任服務(wù),這類EXE文件必須有一個(gè)合法的校驗(yàn)和。
  WORD Subsystem
  可執(zhí)行文件的用戶界面使用的子系統(tǒng)類型。WINNT.H 定義了下面這些值:
  NATIVE 1 不需要子系統(tǒng)(比如設(shè)備驅(qū)動(dòng))
  WINDOWS_GUI 2 在Windows圖形用戶界面子系統(tǒng)下運(yùn)行
  WINDOWS_CUI 3 在Windows字符子系統(tǒng)下運(yùn)行(控制臺(tái)程序)
  OS2_CUI 5 在OS/2字符子系統(tǒng)下運(yùn)行(僅對(duì)OS/2 1.x)
  POSIX_CUI 7 在 Posix 字符子系統(tǒng)下運(yùn)行
  WORD DllCharacteristics
  指定在何種環(huán)境下一個(gè)DLL的初始化函數(shù)(比如DllMain)將被調(diào)用的標(biāo)志變量。這個(gè)值經(jīng)常被置為0 。但是操作系統(tǒng)在下面四種情況下仍然調(diào)用DLL的初始化函數(shù)。
  下面的值定義為:
  1 DLL第一次載入到進(jìn)程中的地址空間中時(shí)調(diào)用
  2 一個(gè)線程結(jié)束時(shí)調(diào)用
  4 一個(gè)線程開(kāi)始時(shí)調(diào)用
  8 退出DLL時(shí)調(diào)用
  DWORD SizeOfStackReserve
  為初始線程保留的虛擬內(nèi)存總數(shù)。然而并不是所有這些內(nèi)存都被提交(見(jiàn)下一個(gè)域)。這個(gè)域的默認(rèn)值是0x100000(1Mbytes)。如果你在CreateThread 中把堆棧尺寸指定為 0 ,結(jié)果將是用這個(gè)相同的值(0x10000)。
  DWORD SizeOfStackCommit
  開(kāi)始提交的初始線程堆?倲(shù)。對(duì)微軟的連接器,這個(gè)域默認(rèn)是0x1000字節(jié)(一頁(yè)),TLINK32 是兩頁(yè)。
  DWORD SizeOfHeapReserve
  為初始進(jìn)程的堆保留的虛擬內(nèi)存總數(shù)。這個(gè)堆的句柄可以用GetPocessHeap 得到。并不是所有這些內(nèi)存都被提交(見(jiàn)下一個(gè)域)。
  DWORD SizeOfHeapCommit
  開(kāi)始為進(jìn)程堆提交的內(nèi)存總數(shù)。默認(rèn)是一頁(yè)。
  PE文件格式
  1.PE文件的含義
  PE文件的意思是Portable Executable(可移植,可執(zhí)行),它是win32可執(zhí)行文件的標(biāo)準(zhǔn)格式.它的一些特性繼承unix的COFF文件格式,同時(shí)保留了與舊版MS-DOS和WINDOWS的兼容.其可移植可執(zhí)行意味著是跨win32平臺(tái)的.
  2.PE文件的層次結(jié)構(gòu)
  PE文件最前面緊隨DOS MZ文件頭的是一個(gè)DOS可執(zhí)行文件(Stub).這使得PE文件成為一個(gè)合法的MS-DOS可執(zhí)行文件.DOS MZ文件頭后面是一個(gè)32位的PE文件標(biāo)志0x50450000(IMAGE_NT_SIGNATURE),即PE00.接下來(lái)的是PE的映像文件頭,包含的信息有該程序的運(yùn)行平臺(tái),有多少個(gè)節(jié),文件鏈接的時(shí)間,文件的命名格式.后面還緊跟一個(gè)可選映像頭,包含PE文件的邏輯分布信息,程序加載信息,開(kāi)始地址,保留的堆棧數(shù)量,數(shù)據(jù)段大小等.可選頭還有一個(gè)重要的域,稱為:數(shù)據(jù)目錄表"的數(shù)組,表的每一項(xiàng)都是指向某一節(jié)的指針.可選映像頭后面緊跟的是節(jié)表和節(jié).節(jié)通過(guò)節(jié)表來(lái)實(shí)現(xiàn)索引.實(shí)際上,節(jié)的內(nèi)容才是真正執(zhí)行的數(shù)據(jù)和程序.每一個(gè)節(jié)都有相關(guān)的標(biāo)志.每一個(gè)節(jié)會(huì)被一個(gè)或多個(gè)目錄表指向,目錄表可通過(guò)可選頭的"數(shù)據(jù)目錄表"的入口找到.就像輸出函數(shù)表或基址重定位表.也存在沒(méi)有目錄表指向的節(jié).
  3.PE文件層次解釋
  A.DOS STUB和DOS頭
  DOS插樁程序在大多數(shù)情況下由匯編器/編譯器自動(dòng)產(chǎn)生.通常它調(diào)用INT 21H服務(wù)9來(lái)顯示上述字符串.可以通過(guò)IMAGE_DOS_HEADER結(jié)構(gòu)來(lái)識(shí)別一個(gè)合法的DOS頭.這個(gè)結(jié)構(gòu)的頭兩個(gè)字節(jié)肯定是"MZ".可通過(guò)該結(jié)構(gòu)的e_lfanew成員來(lái)找到PE文件的開(kāi)始標(biāo)志.MS-DOS頭部占據(jù)了PE文件的頭64個(gè)字節(jié).在微軟的WINNT.H中可以找到其內(nèi)容結(jié)構(gòu)的描述.
  B.PE文件頭
  在DOS STUB后是PE文件頭(PE header).PE文件頭是PE相關(guān)結(jié)構(gòu)IMGAE_NT_HEADERS的簡(jiǎn)稱,即NT映像頭,存放PE整個(gè)文件信息發(fā)布的重要字段,包含了PE裝載器用到的重要域.執(zhí)行體在操作系統(tǒng)中執(zhí)行時(shí),PE裝載器將從DOS MZ頭中找到PE頭文件的起始偏移量e_lfanew,從而跳過(guò)DOS STUB直接定位真正的PE文件.它由3部分組成:
  (1)PE文件標(biāo)志(4H字節(jié))
  PE文件標(biāo)志0x50450000即PE00,標(biāo)志著NT映像頭的開(kāi)始,也是PE文件中與windows有關(guān)內(nèi)容的開(kāi)始.
  (2)映像文件(14H字節(jié))
  是NT映像文件的主要部分,包含PE文件的基本信息
  (3)可選映像頭
  包含PE文件的邏輯分布信息.
  C.節(jié)表
  節(jié)表其實(shí)是緊跟NT映像文件的一個(gè)結(jié)構(gòu)數(shù)組.其成員數(shù)目由映像文件頭結(jié)構(gòu)NumberOFSectios域的值來(lái)決定.
  D.節(jié)
  PE文件的真正內(nèi)容劃分為塊,稱之為節(jié).節(jié)的劃分基于各組數(shù)據(jù)的共同屬性.惟有節(jié)的屬性設(shè)置決定了節(jié)的特性和功能.典型的windows NT應(yīng)用程序可以具有9個(gè)節(jié):.texr,.bss.rdata,.data,.rsrc,edata,idata,pdata,.debug
  判斷一個(gè)文件是否為PE文件
  function TForm1.is_PE(FileName: string): boolean;
  var //檢測(cè)指定文件是否有效PE文件
  PEDosHead: TImageDosHeader;
  PENTHead: TImageNtHeaders;
  m_file: integer;
  begin
  Result := False;
  m_file := FileOpen(filename, fmOpenRead or fmShareDenyNone); //只讀和其它任意
  if m_File > 0 then
  try
  FileSeek(m_file, 0, soFromBeginning); //將指針挪至文件頭
  FileRead(m_file, PEDosHead, SizeOf(PEDosHead)); //讀PEDosHead結(jié)構(gòu)
  FileSeek(m_file, PEDosHead._lfanew, soFromBeginning); //將指針挪至_lfanew
  FileRead(m_file, PENTHead, SizeOf(PENTHead)); //讀PENTHead結(jié)構(gòu)
  finally
  FileClose(m_file);
  end;
  if (PENTHead.Signature = IMAGE_NT_SIGNATURE) then //檢驗(yàn)文件頭部第一個(gè)字的值是否等于 IMAGE_DOS_SIGNATURE
  Result := True;
  end;
  pe文件結(jié)構(gòu)圖

    識(shí)字軟件
    (17)識(shí)字軟件
    現(xiàn)在的父母可能不像以前那樣會(huì)拿著書(shū)本教小孩子識(shí)字,因?yàn)楝F(xiàn)在的科技十分發(fā)達(dá),年輕的父母可以借助軟件來(lái)幫助幼兒識(shí)字,可以節(jié)約一些書(shū)本費(fèi)用哦,今天給大家推薦的是幼兒識(shí)字軟件,幼兒識(shí)字軟件哪個(gè)好挑一款好的早期教育啟蒙軟件是非常重要的,一般的幼兒識(shí)字軟件都有兒歌欣賞成語(yǔ)故事還有兒歌等,可以提高寶寶的學(xué)習(xí)興趣,所以幼兒識(shí)字軟件必不可少哦...更多>>
    • 悟空識(shí)字2.0.4.10 官方免費(fèi)版

      05-05 / 1M

      推薦理由:悟空識(shí)字是一款專門(mén)為3-8歲學(xué)齡前及一年級(jí)兒童開(kāi)發(fā)的識(shí)字軟件。整套軟件包括1200個(gè)最常用漢字、1200個(gè)句子和
    • 熊貓識(shí)字V3.3.130 官方版

      02-22 / 772KB

      推薦理由: 本識(shí)字軟件是一款專門(mén)為三至八歲小朋友早期閱讀和上小學(xué)準(zhǔn)備的兒童識(shí)字軟件,90%以上的家長(zhǎng)認(rèn)為,學(xué)好
    • 熊貓識(shí)字樂(lè)園v3.0.505官方版

      06-11 / 74.5M

      推薦理由:本軟件是一款專門(mén)為2-8歲學(xué)齡前兒童開(kāi)發(fā)的專業(yè)早教產(chǎn)品。熊貓樂(lè)園包括熊貓識(shí)字、熊貓啟蒙(看圖識(shí)物)、親子
    • 幼兒識(shí)字母發(fā)聲工具v1.0 綠色免費(fèi)版

      03-26 / 4.8M

      推薦理由:26個(gè)字母的發(fā)聲,還有字母歌哦,是培育寶寶的好工具 特點(diǎn):讀音清楚,口音圓潤(rùn)
    • 哆哆識(shí)字3.5.0 安卓版

      11-02 / 42.9M

      推薦理由:現(xiàn)代家庭培養(yǎng)孩子的教育成本逐漸加大,書(shū)籍圖書(shū),培訓(xùn)班,安排的滿滿當(dāng)當(dāng),花費(fèi)大卻難見(jiàn)成效。解決早教問(wèn)題
    • 酷娃識(shí)字V1.1.6 官方安裝版

      08-22 / 2.0M

      推薦理由: 酷娃識(shí)字是一款交互式智能識(shí)字軟件。是北京普濟(jì)達(dá)公司結(jié)合國(guó)際先進(jìn)技術(shù)及多年的幼教識(shí)字的實(shí)踐經(jīng)驗(yàn),
    公式編輯器
    (10)公式編輯器
    隨著互聯(lián)網(wǎng)的迅速發(fā)展,通過(guò)網(wǎng)絡(luò)獲取發(fā)布和共享信息資源已成為人們工作學(xué)習(xí)研究和交流的基本手段。數(shù)學(xué)是科學(xué)技術(shù)的基本語(yǔ)言,因而對(duì)于教育和科研領(lǐng)域來(lái)說(shuō),解決基于網(wǎng)頁(yè)的數(shù)學(xué)公式編輯問(wèn)題顯得更為迫切。公式編輯器作為解決手段之一是目前很多人選擇的方法,我們常見(jiàn)的就是一款強(qiáng)大的數(shù)學(xué)公式編輯器?梢詫⒕庉嫼玫墓奖4娉啥喾N圖片格式或透明圖片格式,可以很方便的添加或移除符號(hào)表達(dá)式等模板只需要簡(jiǎn)單地用鼠標(biāo)拖進(jìn)拖出即可...更多>>
    練習(xí)打字
    (13)練習(xí)打字
    很多網(wǎng)民初練打字時(shí)中會(huì)感覺(jué)很困難,時(shí)常就是盯著鍵盤(pán)一個(gè)個(gè)的按鍵的敲出來(lái),這樣的打字方法會(huì)很沒(méi)效率,而且也難以提升打字速度。要想學(xué)會(huì)打字,先打?qū)W會(huì)如何操作鍵盤(pán),并且要經(jīng)過(guò)不斷使用鍵盤(pán)進(jìn)行打字練習(xí)才能達(dá)到得心應(yīng)手的程度。為了讓眾多初學(xué)打字的網(wǎng)民能更快的學(xué)會(huì)快速打字,很多練習(xí)打字的軟件就應(yīng)運(yùn)而生了,這類軟件主要就是教大家如何正確的練習(xí)打字的方法來(lái)達(dá)到最有效率的打字練習(xí)。這里給大家推薦一些比較好用的練習(xí)打...更多>>
    打字練習(xí)
    (10)打字練習(xí)
    西西軟件園提供最新最全的學(xué)拼音打字軟件下載,指法練習(xí),打字速度測(cè)試,獨(dú)特的任務(wù)關(guān)卡模式,助零基礎(chǔ)用戶輕松成為打字高手,循序漸進(jìn)突破盲打障礙,短時(shí)間運(yùn)指如飛,完全擺脫枯燥學(xué)習(xí)。可以給出任意漢字的拼音,即使是多音字,也可以根據(jù)上下文給出正確的拼音。而且把拼音再變成和鍵盤(pán)對(duì)應(yīng)的大寫(xiě)英文字母,小孩子可以輕松的用拼音輸入法打出這些字。...更多>>
    金山打字通2015
    (15)金山打字通2015
    金山打字通新版上線,為各位用戶提供最新的打字游戲及課程,金山打字通全新上線,你還不趕緊體驗(yàn)金山打字通新版特色獨(dú)特的關(guān)卡模式有效避免用戶因急于求成而產(chǎn)生挫敗感失去打字學(xué)習(xí)興趣提供各類輸入法練習(xí)提供英文打字拼音打字五筆打字三種主流輸入法針對(duì)性學(xué)習(xí)從易到難循序漸進(jìn)從知識(shí)講解到實(shí)踐練習(xí),從字母或字根到詞組和文章練習(xí)速度測(cè)試打字高手隨時(shí)檢查打字練習(xí)成果,還可與打字高手一決高下可自定義課程自由選擇練習(xí)課程,并...更多>>
    • 2345王牌輸入法V4.3.4970 官方版

      10-21 / 32.9M

      推薦理由:2345王牌輸入法是2345公司推出的一款PC端中文輸入軟件。輸入法專注于輸入本質(zhì),倡導(dǎo)純凈輸入,無(wú)廣告,無(wú)彈
    • 金山打字通20152.1.0.34 官方最新版

      12-12 / 26.6M

      推薦理由:作為一款目前使用人數(shù)最多,功能最為強(qiáng)大的打字軟件,金山打字通2014版重裝亮相再次成就經(jīng)典。這款專為上網(wǎng)
    • 金山打字通20172.2.0.51 官方安裝版

      01-20 / 31.0M

      推薦理由:金山打字通2013支持五筆打字,拼音打字,中文打字,指法練習(xí),打字速度測(cè)試,獨(dú)特的任務(wù)關(guān)卡模式,助零基礎(chǔ)
    • 金山畫(huà)王2006特別版

      05-15 / 188.0M

      推薦理由:這個(gè)比較經(jīng)典的軟件了,40多種仿真畫(huà)筆、特效工具,可隨心創(chuàng)作、任意揮灑!镓S富畫(huà)筆提供鉛筆、噴筆、水彩
    • 金山打字通2006簡(jiǎn)體中文正式完整安

      05-15 / 100M

      推薦理由:金山打字主要由英文打字、拼音打字、五筆打字、打字游戲等六部分組成。所有練習(xí)用詞匯和文章都分專業(yè)和通用
    • 金山打字通2013SP3 綠色去廣告版

      01-25 / 14.7M

      推薦理由:金山打字是金山公司推出的系列教育軟件。主要由金山打字通和金山打字游戲兩部分構(gòu)成是一款功能齊全、數(shù)據(jù)豐

    相關(guān)評(píng)論

    閱讀本文后您有什么感想? 已有人給出評(píng)價(jià)!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過(guò)難過(guò)
    • 5 囧
    • 3 圍觀圍觀
    • 2 無(wú)聊無(wú)聊

    熱門(mén)評(píng)論

    最新評(píng)論

    發(fā)表評(píng)論 查看所有評(píng)論(6)

    昵稱:
    表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
    字?jǐn)?shù): 0/500 (您的評(píng)論需要經(jīng)過(guò)審核才能顯示)