pe文件的简介

发布网友 发布时间:2022-04-22 05:43

我来回答

1个回答

热心网友 时间:2022-05-13 02:04

一个操作系统的可执行文件格式在很多方面是这个系统的一面镜子。虽然学习一个可执行文件格式通常不是一个程序员的首要任务,但是你可以从这其中学到大量的知识。在这篇文章中,我会给出 Microsoft 的所有基于win32系统(如winnt,win9x)的可移植可执行(PE)文件格式的详细介绍。在可预知的未来,包括Windows2000, PE文件格式在 MicroSoft 的操作系统中扮演一个重要的角色。如果你在使用 Win32 或 Winnt ,那么你已经在使用 PE 文件了。甚至你只是在 Windows3.1 下使用 Visual C++编程,你使用的仍然是 PE 文件(Visual C++ 的 32 位MS-DOS扩展组件用这个格式)。简而言之,PE 格式已经普遍应用,并且在不短的将来仍是不可避免的。现在是时候找出这种新的可执行文件格式为操作系统带来的东西了。 我最后不会让你盯住无穷无尽的十六进制Dump,也不会详细讨论页面的每一个单独的位的重要性。代替的,我会向你介绍包含在 PE 文件中的概念,并且将他们和你每天都遇到的东西联系起来。比如,线程局部变量的概念,如下所述:
declspec(thread) int i;
我快要发疯了,直到我发现它在可执行文件中实现起来是如此的简单并且优雅。既然你们中的许多人都有使用 16 Windows 的背景,我将把 Win32 PE 文件的构造追溯到和它等价的16 位 NE 文件。
除了一个不同的可执行文件格式, MicroSoft 还引入了一个用它的编译器和汇编器生成的新的目标模块格式。这个新的 OBJ 文件格式有许多和PE 文件共同的东东。我做了许多无用功去查找这个新的OBJ 文件格式的文档。所以我以自己的理解对它进行解析,并且,在这里,除了 PE 文件,我会描述它的一部分。 大家都知道,Windows NT继承了 VAX? VMS? 和 UNIX? 的传统。许多 Windows NT 的创始人在进入微软前都在这些平台上进行设计和编码。当他们开始设计 Windows NT 时,很自然的,为了最小化项目启动时间,他们会使用以前写好的并且已经测试过的工具。用这些工具生成的并且工作的可执行和 OBJ 文件格式叫做 COFF (Common Object File Format 的首字母缩写)。COFF 的相对年龄可以用八进制的域来指定。COFF 本身是一个好的起点,但是需要扩展到一个现代操作系统如 Windows 95 和 Windows NT 的需要。这个更新的结果就是(PE格式)可移植可执行文件格式。它被称为可移植的是因为在所有平台(如x86,Alpha,MIPS等等)上实现的WindowsNT 都使用相同的可执行文件格式。当然了,也有许多不同的东西如二进制代码的CPU指令。重要的是操作系统的装入器和程序设计工具不需要为任何一种CPU完全重写就能达到目的。
MicroSoft 抛弃现存的32位工具和可执行文件格式的事实证实了他们想让 WindowsNT 升级并且运行的更快的决心。为16位Windows编写的虚拟设备驱动程序用一种不同的32位文件布局--LE文件格式--WindowsNT出现很早以前就存在了。比这更重要的是对 OBJ 文件的替换!在 WindowsNT 的 C编译器以前,所有的微软编译器都用 Intel 的 OMF ( Object Mole Format ) 规范。就像前面提到的,MicroSoft 的 Win32编译器生成 COFF 格式的 OBJ 文件。一些微软的竞争者,如 Borland 和 Symentec ,选择放弃了 COFF 格式并坚持 Intel 的 OMF文件格式。这样的结果是制作 OBJ 和 LIB 的公司为了使用多个不同的编译器,不得不为每个不同的编译器分发这些库的不同版本(如果他们不这么做)。
PE 文件格式在 winnt.h 头文件中文档化了(用最不精确的语言)!大约在 winnt.h 的中间部分标题为Image Format的一个块。在把 MS-DOS 的 MZ文件头和 NE 文件头移入新的PE文件头之前,这个块就开始于一个小栏。WINNT.H提供PE文件用到的生鲜数据结构的定义,但只有很少有助于理解这些数据结构和标志变量的注释。不管谁为PE文件格式写出这样的头文件都肯定是一个信徒无疑(突然持续地冒出Michael J. O'Leary的名字来)。描述名字,连同深嵌的结构体和宏。当你配套winnt.h进行编码时,类似下面这样的表达式并不鲜见:
pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]
.VirtualAddress;
为了有助于逻辑的理解这些winnt.h中的信息,阅读可移植可执行和公共对象文件格式的规格说明,这些在MSDN既看光盘中是可用的,一直包括到2001年8月。
现在让我们转换到COFF格式的OBJ文件的主体上来,WINNT.H包括COFF OBJ和LIB的结构化定义和类型定义。不幸的是,我还没有找到上面提到的可执行文件格式的类似文档。既然PE文件和COFF OBJ文件是如此的相似,我决定是时间把这些文件带到重点上来,并且把它们也文档化。仅仅读过了关于PE文件的组成,你自己也想Dump一些PE文件来看这些概念。如果你用微软基于32位WINDOWS的开发工具,DUMPBIN 程序可以将PE文件和COFF OBJ/LIB文件转化为可读的形式。在所有的PEDump器中,DUMPBIN是最容易理解的。它恰好有一些很好的选项来反汇编它正解析的文件的代码块,Borland用户可以使用tmp来浏览PE文件,但tmp不能解析 COFF OBJ/LIB 文件。这不是一个重要的东西因为Borland的编译器首先就不生成 COFF 格式的OBJ文件。
我写了一个PE和COFF OBJ 文件的Dump程序--PEDUMP,我想提供一些比DUMPBIN更加可理解的输出。虽然它没有反汇编器以及和LIB库文件一起工作,它在其他方面和DUMPBIN是一样的,并且加入了一些新的特性来使它值得被认同。它的源代码在任何一个MSJ电子公报版上都可以找到,所有我不打算在这里把他全部列出。作为代替,我展示一些从PEDUMP得到的示例输出来阐明我为它们描述的概念。
译注:--说实话,我从这这份代码中几乎唯一学到的东西就是如何处理命令行,其它的都没学到。 表 1 PEDUMP.C
file://--------------------/ // PROGRAM: PEDUMP// FILE: PEDUMP.C// AUTHOR: Matt Pietrek - 1993file://--------------------/#include <windows.h>#include <stdio.h>#include objmp.h#include exemp.h#include extrnvar.h// Global variables set here, and used in EXEDUMP.C and OBJDUMP.CBOOL fShowRelocations = FALSE;BOOL fShowRawSectionData = FALSE;BOOL fShowSymbolTable = FALSE;BOOL fShowLineNumbers = FALSE;char HelpText[] =PEDUMP - Win32/COFF .EXE/.OBJ file mper - 1993 Matt Pietrek\n\nSyntax: PEDUMP [switches] filename\n\n /A include everything in mp\n /H include hex mp 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 mping routinevoid 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 );elseprintf(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;}

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com