什么是文件及文件的结构和简述(转载)indows还是inux

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 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);

for ( i=1; i < argc; i++ ){strupr(argv[i]);

// Is it a switch character?if ( (argv[i][0] = = '-') || (argv[i][0] = = '/') ){if ( argv[i][1] = = 'A' ){ fShowRelocations = TRUE;fShowRawSectionData = TRUE;fShowSymbolTable = TRUE;fShowLineNumbers = TRUE; }else if ( argv[i][1] = = 'H' )fShowRawSectionData = TRUE;else if ( argv[i][1] = = 'L' )fShowLineNumbers = TRUE;else if ( argv[i][1] = = 'R' )fShowRelocations = TRUE;else if ( argv[i][1] = = 'S' )fShowSymbolTable = TRUE;}else // Not a switch character. Must be the filename{ return argv[i]; }}}

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 基本概念让我们复习一下几个透过PE文件的设计了解到的基本概念(见图1)。我用术语"MODULE"来表示一个可执行文件或一个DLL载入内存的代码(CODE)、数据(DATA)、资源(RESOURCES),除了代码和数据是你的程序直接使用的,一个模块还可以由WINDOWS用来确定数据和代码载入的位置的支撑数据结构组成。在16位WINDOWS中,这些支撑数据结构在模块数据库(用一个HMODULE来指示的段)中。在WIN32里面,这些数据结构在PE文件头中,这些我将会简要地解释一下。

图1 PE文件略图

关于PE文件最重要的是,磁盘上的可执行文件和它被WINDOWS调入内存之后是非常相像的。WINDOWS载入器不必为从磁盘上载入一个文件而辛辛苦苦创建一个进程。载入器使用内存映射文件机制来把文件中相似的块映射到虚拟空间中。用一个构造式的分析模型,一个PE文件类似一个预制的屋子。它本质上开始于这样一个空间,这个空间后面有几个把它连到其余空间的机件(就是说,把它联系到它的DLL上,等等)。这对PE格式的DLL是一样容易应用的。一旦这个模块被载入,Windows 就可以有效的把它和其它内存映射文件同等对待。和16位Windows不同的是。16位NE文件的载入器读取文件的一部分并且创建完全不同的数据结构在内存中表示模块。当数据段或者代码段需要载入时,载入器必须从全局堆中新申请一个段,从可执行文件中找出生鲜数据,转到这个位置,读入这些生鲜数据,并且要进行适当的修正。除此而外,每个16位模块都有责任记住当前它使用的所有段选择器,而不管这个段是否被丢弃了,如此等等。对Win32来讲,模块所使用的所有代码,数据,资源,导入表,和其它需要的模块数据结构都在一个连续的内存块中。在这种形势下,你只需要知道载入器把可执行文件映射到了什么地方。通过作为映像的一部分的指针,你可以很容易的找到这个模块所有不同的块。另一个你需要知道的概念是相对虚拟地址(RVA)。PE文件中的许多域都用术语RVA来指定。一个RVA只是一些项目相对于文件映射到内存的偏移。比如说,载入器把一个文件映射到虚拟地址0x10000开始的内存块。如果一个映像中的实际的表的首址是0x10464,那么它的RVA就是0x464。(虚拟地址 0x10464)-(基地址 0x10000)=RVA 0x00464为了把一个RVA转化成一个有用的指针,只需要把RVA值加到模块的基地址上即可。基地址是内存映射EXE和DLL文件的首址,在Win32中这是一个很重要的概念。为了方便起见,WindowsNT 和Windows9x用模块的基地址作为这个模块的实例句柄(HINSTANCE)。在Win32中,把模块的基地址叫做HINSTANCE可能导致混淆,因为术语"实例句柄"来自16位Windows。一个程序在16位Windows中的每个拷贝得到它自己分开的数据段(和一个联系起来的全局句柄)来把它和这个程序其它的拷贝分别开来,就形成了术语"实例句柄"。在Win32中,每个程序不必和其它程序区别开来,因为他们不共享相同的地址空间。术语INSTANCE仍然保持16位windows和32位Windows之间的连续性。在Win32中重要的是你可以对任何DLL调用GetModuleHandle()得到一个指针去访问它的组件(译注)。译注:如果 dllname 为 NULL,则得到执行体自己的模块句柄。这是非常有用的,如通常编译器产生的启动代码将取得这个句柄并将它作为一个参数hInstance传给WinMain !你最终需要理解的PE文件的概念是"块(Section)"。PE文件中的一个块和NE文件中的一个段或者资源等价。块可以包含代码或者数据。和段不同的是,块是内存中连续的空间,而没有尺寸限制。当你的连接器和库为你建立,并且包含对操作系统非常重要的信息的其它的数据块时,这些块包含你的程序直接声明和使用的代码或数据。在一些PE格式的描述中,块也叫做对象。术语对象有如此多的涵义,以至于只能把代码和数据叫做"块"。2 PE首部和其它可执行文件格式一样,PE文件在众所周知的地方有一些定义文件其余部分面貌的域。首部就包含这样象代码和数据的位置和尺寸的地方,操作系统要对它进行干预,比如初始堆栈大小,和其它重要的块的信息,我将要简短的介绍一下。和微软其它可执行格式相比,主要的首部不是在文件的最开始。典型的PE文件最开始的数百个字节被DOS残留部分占用。这个残留部分是一个可以打印如"这个程序不能在DOS下运行!"这类信息的小程序。所以,你在一个不支持Win32的系统中运行这个程序,便可以得到这类错误信息。当载入器把一个Win32程序映射到内存,这个映射文件的第一个字节对应于DOS残留部分的第一个字节。那是无疑的。和你启动的任一个基于Win32 的程序一起,都有一个基于DOS的程序连带被载入。和微软的其它可执行格式一样,你可以通过查找它的起始偏移来得到真实首部,这个偏移放在DOS残留首部中。WINNT.H头文件包含了DOS残留程序的数据结构定义,使得很容易找到PE首部的起始位置。e_lfanew 域是PE真实首部的偏移。为了得到PE首部在内存中的指针,只需要把这个值加到映像的基址上即可。file://忽/略类型转化和指针转化 ...pNTHeader = dosHeader + dosHeader->e_lfanew;一旦你有了PE主首部的指针,游戏就可以开始了!PE主首部是一个IMAGE_NT_HEADERS的结构,在WINNT.H中定义。这个结构由一个双字(DWORD)和两个子结构组成,布局如下:DWORD Signature;IMAGE_FILE_HEADER FileHeader;IMAGE_OPTIONAL_HEADER OptionalHeader;标志域用ASCII表示就是"PE\0\0"。如果在DOS首部中用了e_lfanew域,你得到一个NE标志而不是PE,那么这是16位NE文件。同样的,在标志域中的LE表示这是一个Windows3.x 的虚拟设备驱动程序(VxD)。LX表示这个文件是OS/2 2.0文件。PEDWORD标志后的是结构 IMAGE_FILE_HEADER。这个域只包含这个文件最基本的信息。这个结构表现为并未从它的原始COFF实现更改过。除了是PE首部的一部分,它还表现在微软Win32编译器生成的COFF OBJ 文件的最开始部分。IMAGE_FILE_HEADER的这个域显示在下面:表2 IMAGE_FILE_HEADER Fields WORD Machine 表示CPU的类型,下面定义了一些CPU的ID0x14d Intel i8600x14c Intel I386 (same ID used for 486 and 586)0x162 MIPS R30000x166 MIPS R40000x183 DEC Alpha AXP

WORD NumberOfSections 这个文件中的块数目。

DWORD TimeDateStamp 连接器产生这个文件的日期(对OBJ文件是编译器),这个域保存的数是从1969年12月下午4:00开始到现在经过的秒数。

DWORD PointerToSymbolTable COFF符号表的文件偏移量。这个域只用于有COFF调试信息的OBJ文件和PE文件,PE文件支持多种调试信息格式,所以调试器应该指向数据目录的IMAGE_DIRECTORY_ENTRY_DEBUG条目。

DWORD NumberOfSymbols COFF符号表的符号数目。见上面。

WORD SizeOfOptionalHeader 这个结构后面的可选首部的尺寸。在OBJ文件中,这个域是0。在可执行文件中,这是跟在这个结构后的IMAGE_OPTIONAL_HEADER结构的尺寸。

WORD Characteristics 关于这个文件信息的标志。一些重要的域如下:

0x0001 这个文件中没有重定位信息0x0002 可执行文件映像(不是OBJ或LIB文件)0x2000 文件是动态连接库,而非程序

其它域定义在WINNT.H中。PE首部的第三个组成部分是一个IMAGE_OPTIONAL_HEADER型的结构。对PE文件,这一部分当然不是"可选的"。COFF格式允许单独实现来定义一个超出标准IMAGE_FILE_HEADER附加信息的结构。IMAGE_OPTIONAL_HEADER里面的域是PE的实现者感到超出IMAGE_FILE_HEADER基本信息以外非常关键的信息。并非 IMAGE_OPTIONAL_HEADER 的所有域都是重要的(见图4)。比较重要,需要知道的是ImageBase 和 SubSystem 域。你可以忽略其它域的描述。表3 IMAGE_FILE_HEADER 的域:WORD Magic 表现为一些类别的标志字,通常是0X010B 。BYTE MajorLinkerVersion BYTE MinorLinkerVersion 生成这个文件的连接器的版本。这个数字以十进制显示比用十六进制好。一个典型的连接器版本是2.23。

DWORD SizeOfCode 所有代码块的进位尺寸。通常大多数文件只有一个代码块,所以这个域和 .TEXT 块匹配。

DWORD SizeOfInitializedData 已初始化的数据组成的块的大小(不包括代码段)。然而,和它在文件中的表现形式并不一致。

DWORD SizeOfUninitializedData 载入器在虚拟内存中申请空间,但在磁盘上的文件中并不占用空间的块的尺寸。这些块在程序启动时不需要指定初值,因此术语名就是"未初始化的数据"。未初始化的数据通常在一个名叫 .bss 的块中。

DWORD AddressOfEntryPoint 载入器开始执行这个程序的地址,即这个PE文件的入口地址。这是一个RVA,通常在 .text 块中。

DWORD BaseOfCode 代码块起始地址的RVA 。在内存中,代码块通常在PE首部之后,数据块之前。在微软的连接器产生的EXE文件中,这个值通常是0x1000 。Borland 的连接器 TLINK32 也一样,把映像第一个代码块的RVA和映像基址相加,填入这个域。译注:这个域好像一直没有什么用

DWORD BaseOfData 数据块起始地址的RVA 。在内存中,数据块经常在最后,在PE首部和代码块之后。译注:这个域好像也一直没有什么用

DWORD ImageBase 连接器创建一个可执行文件时,它假定这个文件被映射到内存中的一个指定的地方,这个地址就存在这个域中,假定一个载入地址可以使连接器优化以便节省空间。如果载入器真的把这个文件映射到了这个地方,在运行之前代码不需要任何改变。在为WindowsNT 创建的可执行文件中,默认的ImageBase是0x10000。对DLL,默认是0x40000。在Window95中,地址0x10000不能用来载入32位EXE文件,因为这个区域在一个被所有进程共享的线性地址空间中。因此,微软把Win32可执行文件的默认基址改为0x40000,假定基址为0x10000的老程序坐在Windows95 中需要更长的载入时间,这是因为载入器需要重定位基址。译注:这个域即"Prefered Load Address",如果没有什么意外,这就是该PE文件载入内存后的地址。

DWORD SectionAlignment 映射到内存中时,每个块都必须保证开始于这个值的整数倍。为了分页的目的,默认的SectionAlignment 是 0x1000。

DWORD FileAlignment 在PE文件中,组成每个块的生鲜数据必须保证开始于这个值的整数倍。默认值是0x200 字节,也许是为了保证块都开始于一个磁盘扇区(一个扇区通常是 512字节)。这个域和NE文件中的段/资源对齐(segment/resourcealignment)尺寸是等价的。和NE文件不同的是,PE文件通常没有数百个的块,所以,为了对齐而浪费的通常空间很少。

WORD MajorOperatingSystemVersion WORD MinorOperatingSystemVersion 这个程序运行需要的操作系统的最小版本号。这个域有点含糊,因为Subsystem 域(后面将会说到)可以提供类似的功能。这个域在到目前为止的Win32中默认是1.0。

WORD MajorSubsystemVersion WORD MinorSubsystemVersion 这个程序运行需要的最小子系统版本号。这个域的一个典型值是3.10 (表示WindowsNT 3.1)。

DWORD SizeOfImage 载入器必须关心的这个映像所有部分的大小总和。是从映像的开始到最后一个块结尾这段区域的大小。最后一个块结尾按SectionAlignment进位。译注:这个很重要,可以大,但不可以小!

DWORD SizeOfHeaders PE首部和块表的大小。块的实际数据紧跟在所有首部组件之后。

DWORD CheckSum 这个文件的CRC校验和。在微软可执行格式中,这个域被忽略并且置为0 。这个规则的一个例外情况是信任服务,这类EXE文件必须有一个合法的校验和。

WORD Subsystem 可执行文件的用户界面使用的子系统类型。WINNT.H 定义了下面这些值: NATIVE 1 不需要子系统(比如设备驱动)WINDOWS_GUI 2 在Windows图形用户界面子系统下运行WINDOWS_CUI 3 在Windows字符子系统下运行(控制台程序)OS2_CUI 5 在OS/2字符子系统下运行(仅对OS/2 1.x)POSIX_CUI 7 在 Posix 字符子系统下运行

WORD DllCharacteristics 指定在何种环境下一个DLL的初始化函数(比如DllMain)将被调用的标志变量。这个值经常被置为0 。但是操作系统在下面四种情况下仍然调用DLL的初始化函数。

下面的值定义为:1 DLL第一次载入到进程中的地址空间中时调用2 一个线程结束时调用4 一个线程开始时调用8 退出DLL时调用

DWORD SizeOfStackReserve 为初始线程保留的虚拟内存总数。然而并不是所有这些内存都被提交(见下一个域)。这个域的默认值是0x100000(1Mbytes)。如果你在CreateThread 中把堆栈尺寸指定为 0 ,结果将是用这个相同的值(0x10000)。

DWORD SizeOfStackCommit 开始提交的初始线程堆栈总数。对微软的连接器,这个域默认是0x1000字节(一页),TLINK32 是两页。

DWORD SizeOfHeapReserve 为初始进程的堆保留的虚拟内存总数。这个堆的句柄可以用GetPocessHeap 得到。并不是所有这些内存都被提交(见下一个域)。

DWORD SizeOfHeapCommit 开始为进程堆提交的内存总数。默认是一页。

DWORD LoaderFlags 从WINNT.H中可以看到,这些标志是和调试支持相联系的。我从没有见到过在哪个可执行文件中这些位都置位了,清除它让连接器来设置它。下面的值定义为: 1. 在开始进程前调用一个端点指令2. 进程被载入时调用一个调试器

DWORD NumberOfRvaAndSizes 数据目录数组中的的条目数目(见下面)。当前的工具通常把这个值设为16。 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] 一个IMAGE_DATA_DIRECTORY结构数组。初始数组元素包含可执行文件的重要部分的起始RVA和大小。这个数组最末的一些元素现在没有使用。这个数组的第一个元素经常时导出函数表的地址和尺寸。第二个数组条目是导入函数表的地址和尺寸,等等。对一个完整的、已定义的数组条目,见IMAGE_DIRECTORY_ENTRY_XXX在WINNT.H中的定义。这个数组允许载入器迅速查找这个映像的一个指定的块(例如,导入函数表),而不需要遍历映像的每个块,通过比较名字来确定。大部分数组条目描述一整块数据。然而,IMAGE_DIRECTORY_ENTRY_DEBUG项只包括 .rdata 块的一小部分字节。

02 .bss VirtSize: 00001438 VirtAddr: 00007000raw data offs: 00000000 raw data size: 00001600relocation offs: 00000000 relocations: 00000000line # offs: 00000000 line #'s: 00000000characteristics: C0000080UNINITIALIZED_DATA MEM_READ MEM_WRITE

03 .rdata VirtSize: 0000015C VirtAddr: 00009000raw data offs: 00006000 raw data size: 00000200relocation offs: 00000000 relocations: 00000000line # offs: 00000000 line #'s: 00000000characteristics: 40000040INITIALIZED_DATA MEM_READ

04 .data VirtSize: 0000239C VirtAddr: 0000A000raw data offs: 00006200 raw data size: 00002400relocation offs: 00000000 relocations: 00000000line # offs: 00000000 line #'s: 00000000characteristics: C0000040INITIALIZED_DATA MEM_READ MEM_WRITE

05 .idata VirtSize: 0000033E VirtAddr: 0000D000raw data offs: 00008600 raw data size: 00000400relocation offs: 00000000 relocations: 00000000line # offs: 00000000 line #'s: 00000000characteristics: C0000040INITIALIZED_DATA MEM_READ MEM_WRITE

06 .reloc VirtSize: 000006CE VirtAddr: 0000E000raw data offs: 00008A00 raw data size: 00000800relocation offs: 00000000 relocations: 00000000line # offs: 00000000 line #'s: 00000000characteristics: 42000040INITIALIZED_DATA MEM_DISCARDABLE MEM_READ 表 5 一个典型OBJ文件的块表01 .drectve PhysAddr: 00000000 VirtAddr: 00000000raw data offs: 000000DC raw data size: 00000026relocation offs: 00000000 relocations: 00000000line # offs: 00000000 line #'s: 00000000characteristics: 00100A00LNK_INFO LNK_REMOVE

02 .debug$S PhysAddr: 00000026 VirtAddr: 00000000raw data offs: 00000102 raw data size: 000016D0relocation offs: 000017D2 relocations: 00000032line # offs: 00000000 line #'s: 00000000characteristics: 42100048INITIALIZED_DATA MEM_DISCARDABLE MEM_READ

03 .data PhysAddr: 000016F6 VirtAddr: 00000000raw data offs: 000019C6 raw data size: 00000D87relocation offs: 0000274D relocations: 00000045line # offs: 00000000 line #'s: 00000000characteristics: C0400040INITIALIZED_DATA MEM_READ MEM_WRITE

04 .text PhysAddr: 0000247D VirtAddr: 00000000raw data offs: 000029FF raw data size: 000010DArelocation offs: 00003AD9 relocations: 000000E9line # offs: 000043F3 line #'s: 000000D9characteristics: 60500020CODE MEM_EXECUTE MEM_READ

05 .debug$T PhysAddr: 00003557 VirtAddr: 00000000raw data offs: 00004909 raw data size: 00000030relocation offs: 00000000 relocations: 00000000line # offs: 00000000 line #'s: 00000000characteristics: 42100048INITIALIZED_DATA MEM_DISCARDABLE MEM_READ

每个IAMGE_SECTION_HEADER都有一个如图7描述的格式。注意每个块中存储的信息缺失了什么是很有趣的。首先,注意没有指明任何预载入的属性。NE文件格式允许你指定应该和模块一起载入的预载入段的属性。OS/2? 2.0 LX 格式有点类似,允许你指定预载入八页(内存页:译注,下同)。PE格式就没有任何类似的东西。微软必须确保Win32 需求页面的载入性能。表 6 IMAGE_SECTION_HEADER 的格式BYTE Name[IMAGE_SIZEOF_SHORT_NAME] 这是一个为块命名的8字节ANSI名字(不UNICODE)。大部分块名开始于一个 "."(比如".text"),但这并非必须的,就像你可能相信的一些PE文档一样。你可以在汇编语言中用任何一个段指示你自己的块。或者在微软C/C++编译器中用"#pragma data_seg"来指示。需要注意的是如果块名占满8个字节,就没有NULL结束字节了。如果你热衷于 printf,你可以用 %8s来避免把这个名字拷贝到一个缓冲区中,然后又在结尾加上一个NULL字节。union { DWORD PhysicalAddress DWORD VirtualSize } Misc; 在EXE和OBJ中,这个域的意义不同。在EXE中,它保存代码或者数据的实际尺寸。这个尺寸是未经过校准文件对齐尺寸并进位的。后面要讲到的这个结构的SizeOfRawData 域(这个词有点不确切)保存了校准文件对齐尺寸并进位后的尺寸。Borland的连接器调换了这两个域的意思,于是看上去就是正确的了。对OBJ文件,这个域指示块的物理尺寸。第一个块开始于地址0 。为找到OBJ文件中的下一个块,把SizeOfRawData加到当前块基址上即可。

DWORD VirtualAddress 在EXE中,这个域保存决定载入器把这个块映射到内存中哪个位置的RVA。为计算一个给定的块在内存中的实际起始地址,把这个映像的基址加上存储在这个域的VirtualAddress即可。用微软的工具,第一个块的默认RVA是0x1000 。在OBJ文件中,这个域没有意义,被置为0 。

DWORD SizeOfRawData 在EXE中,这个域包含这个块按文件对齐尺寸进位后的尺寸。比如说,假定一个文件的对齐尺寸是0x200 。如果这个块的VirtualAddress域(前面那个域)的是0x35a,那么这个域就是0x400 。在OBJ文件中,这个域包含由编译器或汇编器提供的块的精确尺寸。换句话说,对OBJ,它等价于EXE中的VirtualSize域。

DWORD PointerToRawData 这是一个基于文件的偏移,通过这个偏移,可以找到由编译器或汇编器产生的生鲜数据。如果你的程序自己要把一个PE或COFF文件映射到内存(而不是让操作系统来载入),那么这个域比VirtualAddress更重要。在这种情况下你有一个完全线性的文件映射,所以你会在这个偏移处找到块的数据,而不是在VirtualAddress域指定的RVA 处找到。DWORD PointerToRelocations 在OBJ中,这是指向块的重定位信息的基于文件的偏移值。每个OBJ块的重定位信息紧跟在这个块的生鲜数据之后。在EXE中,这个域(和后面的)是没有意义的,被置为0。连接器产生EXE时,它解决了大部分的这种修正值,只剩下基址的重定位和导入函数,将在载入时解决。关于基本重定位信息和导入函数保留在他们自己的块中,所以对一个EXE ,没有必要在每个块的生鲜数据之后都紧跟它的重定位信息。

DWORD PointerToLinenumbers 这是行号表基于文件的偏移量。行号表把源文件的一行和(编译器)为这一行产生的(机器)代码的首址联系起来。在如CodeView格式的现代调试格式中,行号信息存储为调试信息的一部分。然而,在COFF调试格式中,行号信息和符号名/型信息的存储是分开的。通常只有代码块(如 .text)有行号信息。在EXE文件中,行号信息在块的生鲜数据之后,朝着文件的结尾方向收集。在OBJ文件中,一个块的行号信息跟在生鲜块数据和这个块的重定位表之后。

WORD NumberOfRelocations 块的重定位表中的重定位项的数目(参考上面的PointerToRelocations域)。这个域似乎只和OBJ文件有关。

WORD NumberOfLinenumbers 块的行号表中的行号项的数目(参考上面的PointerToLinenumbers域)。

DWORD Characteristics 大部分程序员的称之为标志,COFF/PE格式称之为特征。这个域是指示块属性的标志集(如代码/数据,可读,可写)。一个对所有可能的块属性的完整的列表,见WINNT.H中的IMAGE_SCN_XXX_XXX的定义。如下是比较重要的一些标志:

0x00000020 这个块包含代码。通常和可执行标志(0x80000000)一起置位。0x00000040 这个块包含已初始化的数据。除了可执行块和 .bss 块之外几乎所有的块的这个标志都置位。0x00000080 这个块包含未初始化的数据(如 .bss 块)0x00000200 这个块包含注释或其它的信息。这个块的一个典型用法是编译器产生的 .drectve 块,包含链接器命令。0x00000800 这个块的内容不应放进最终的EXE文件中。这些块是编译器或汇编器用来给连接器传递信息的。0x02000000 这个块可以被丢弃,因为一旦它被载入,其进程就不需要它了。最通常的可丢弃块是基本重定位块( .reloc )。0x10000000这个块是可共享的。和DLL一起使用时,这个块的数据可以在使用这个DLL的进程之间共享。默认时数据块是非共享的,这意味着使用这个DLL的各个进程都有自己对这个块的数据的副本。在更专业的术语中,共享块告诉内存管理器把使用这个DLL的所有进程把的这个块的页面映射到内存中相同的物理页面。为使一个块可共享,在连接时用SHARE属性。如:LINK /SECTION:MYDATA,RWS ...告诉连接器叫做"MYDATA"的块是可读的,可写的,共享的。0x20000000 这个块是可执行的。这个标志通常在"包含代码"标志(0x00000020)被置位时置位。0x40000000 这个块是可读的。在EXE文件中,这个域几乎总被置位。0x80000000 这个块是可写的。如果在一个EXE块中这个块未被置位,载入器会把这块的内存映射页面标为只读或"只执行"。有此属性的典型的块是 .data 和 .bss 。有趣的是,.idata 块也有这个属性。PE格式中还缺少"页表"的概念。在LX格式中,OS/2的IMAGE_SECTION_TABLE等价物不直接指向文件中的代码或数据块。代替的,它指向一个指示块中特定范围的属性和位置的页查找表。PE格式分配所有的,并且确保所有的块中的数据将连续的存储在文件中。比较这两种格式:LX可以允许更大的灵活性,但PE风格更简单,更容易协同工作。我已经写了这两种文件的Dumper 。PE格式另一个值得欢迎的改变是所有项目的位置都存储为简单的双字(DWORD)偏移。在NE格式中,几乎所有东西的位置都存储为它们的扇区值。为了得到实际的偏移,你第一步需要查找NE首部的对齐单元尺寸并把它转化为扇区尺寸(典型的是 16 和512字节)。然后你需要把扇区尺寸乘以指定的扇区偏移才得到实际的文件偏移。如果NE文件的某些东西偶然存储为一个扇区偏移,这可能是相对于NE首部的。因为NE首部并不在文件的开始,你需要在自己的代码中调整这个文件的NE首部。总之,PE格式比NE,LX,或LE格式更容易协同工作(假定你能使用内存映像文件)。

4 通用块已经看到了大体上块是什么和它们位于何处,让我们看一下你将会在EXE和OBJ文件中找到的通用块。这个列表决不是完整的,但包含了你每天都碰到的块(甚至你没有意识到的)。.text块是编译器或汇编器结束时产生的通用代码块。因为PE文件运行在32位模式下,并且没有16位段的限制,没有理由根据分开的源文件把代码分为分开的块。代替的,连接器把从不同的OBJ文件得来的 .text 块连接起来放到EXE文件中的一个大 .text 块中。如果你用 Borland C++,编译器把产生的代码放到名为 CODE 的块中。Borland C++ 生成的PE文件有一个名为 CODE 的块而不是名为 .text。我将会简短的解释一下。

5 PE文件的导入表前面,我描述了函数调用怎样到一个外部DLL中而不直接调用这个DLL 。代替的,在执行体中的 .text 块中(如果你用Borland C++ 就是 .icode 块),CALL指令到达一条 JMP DWORD PTR [XXXXXXXX] 指令处。JMP指令寻找的地址把控制转移到实际的目标地址。PE文件的 .idata 会包含一些必要的信息,这些信息是载入器用来确定目标函数的地址以及在执行体映像中去修正他们的。.idata块(或称导入表,我更喜欢这样叫)开始于一个IMAGE_IMPORT_DESCRIPTOR数组。每个DLL都有一个PE文件隐含链接上的IMAGE_IMPORT_DESCRIPTOR。没有指定这个数组中结构的数目的域。代替的,这个数组的最后一个元素是一个全NULL的IMAGE_IMPORT_DESCRIPTOR 。IMAGE_IMPORT_DESCRIPTOR的格式显示在表8 。表 8 IMAGE_IMPORT_DESCRIPTOR Format DWORD Characteristics 在一个时刻,这可能已是一个标志集。然而,微软改变了它的涵义并不再糊涂地升级WINNT.H 。这个月实际上是一个指向指针数组的偏移(RVA)。其中每个指针都指向一个IMAGE_IMPORT_BY_NAME结构。

PIMAGE_THUNK_DATA FirstThunk 这个域是指向IMAGE_THUNK_DATA联合的偏移(RVA)。几乎在任何情况下,这个域都解释为一个指向的IMAGE_IMPORT_BY_NAME结构的指针。如果这个域不是这些指针中的一个,那它就被当作一个将从这个被导入的DLL的导出序数值。如果你实际上可以从序数导入一个函数而不是从名字导入,从文档看,这是不清楚的。IMAGE_IMPORT_DESCRIPTOR的一个重要部分是导入的DLL的名自和两个IMAGE_IMPORT_BY_NAME指针数组。在EXE文件中,这两个数组(由Characteristics域和FirstThunk域指向)是相互平行的,都是以NULL指针作为数组的最后一个元素。两个数组中的指针都指向IMAGE_IMPORT_BY_NAME 结构。表3以图形显示了这种布局。表12显示了PEDUMP对一个导入表的输出。

THE END
0.PE文件格式详细解析(一)pe格式本文深入解析Windows下的PE文件格式,包括PE文件的种类、位置标识、整体结构等内容,并通过WinHex和PEtools等工具进行实例演示。 PE文件格式详细解析 本篇文章将会详解Windows操作平台下PE文件格式,同时以具体的示例辅佐大家更好理解PE文件格式。本文章主要使用到以下两个工具:WinHex:用于将PE文件以16进制和ASCII码显示;PEjvzquC41dnuh0lxfp0tfv8|gkzooa=<976>:68ftvkimg8igvcomu864336:;>5
1.PE文件结构详解本文深入解析PE文件结构,包括DOS头部、PE头部、节表、节数据等内容,阐述PE文件在磁盘与内存中的状态差异,以及如何利用PE文件进行代码修改、节的扩展与合并等高级操作。 PE 视频学习 1.认识PE 首先,先介绍什么是可执行文件(executable file):可以由操作系统进行加载执行的文件 jvzquC41dnuh0lxfp0tfv8vsa7764:7421gsvrhng1jfvjnnu1734997:9>
2.PE文件结构详解针对在硬盘上存储文件中的地址,称为原始存储地址或物理地址,表示距离文件头的偏移。 针对加载到内存以后映象中的地址,称为相对虚拟地址(RVA),表示相对内存映象头的偏移。 RVA 是当PE 文件被装到内存中后,某个数据位置相对于文件头的偏移量。 举个例子:如果 Windows 装载器将一个PE 文件装入到 00400000h 处的内jvzquC41z|4bnr~wp0ipo8sgyu524;;9
3.PE文件整体结构介绍吾爱破解1、本文章使用的将PE文件编译为十六进制字节码格式用的是C32Asm,但大家实际操作还是推荐使用WinHex,工具均取自于爱盘。2、这篇文章主要是讲PE文件的整体结构,还有数据目录表没有具体讲解,数据目录之后会以单独的形式一个个讲解。PE文件是可移植的可执行的文件,什么是可执行文件?可执行文件是为进程创建所服务的,jvzquC41yy}/7;uqlkk/ew4vjtkbf6698796966/30nuou
4.PE文件详解(C制作PE格式解析器)pe文件解析器本文介绍了PE文件的基本结构,包括DOS头部、PE文件头、节表等,并深入探讨了导入表和导出表的工作原理。此外,还提供了一个使用C语言编写的简易PE文件解析器示例。 0x00:前言 PE文件可以说是在逆向的各个领域都有涉及,特别是病毒领域,如果你是一名病毒制造者,那你肯定是对PE文件有详细的了解,那么这里我就详细介绍一jvzquC41dnuh0lxfp0tfv8HjctrfuPtfZ1gsvrhng1jfvjnnu1>97B<625
5.PE文件格式分析pe文件格式详解本文详细解析了PE文件的基本概念、结构分析、区块对齐、文件偏移与RVA转换、输入表与输出表、基址重定位等核心内容,提供了深入理解PE文件的全面指南。 一、PE的基本概念 PE(Portable Execute)文件是Windows下可执行文件的总称,常见的有DLL,EXE,OCX,SYS等,事实上,一个文件是否是PE文件与其扩展名无关,PE文件可以是任何jvzquC41dnuh0lxfp0tfv8xjkvjci8ftvkimg8igvcomu89;95:5;>
6.PE文件格式详细解析(二)pe头的大小本文深入解析PE文件结构,包括NT头、可选头、节区表等关键组件,揭示PE文件如何组织代码与数据。 3.PE文件的结构 3.2 NT头 由一个IMAGE_NT_HEADERS结构组成,该结构中包含了PE文件被载入内存时需要用到的重要域。通过DOSheader中的e_lfanew,可以直接定位到真正的PE Header部分。该结构体的大小为0xf8字节。 jvzquC41dnuh0lxfp0tfv8|gkzooa=<976>:68ftvkimg8igvcomu86433715@:
7.PE文件结构解析DOS Stub(存根)实际上是个有效的 MS-DOS .EXE 或者.COM 程序(如果文件格式不对会报错),在不支持 PE文件格式的操作系统中,它将通过简单调用中断21h服务9来显示字符串"This program cannot run in DOS mode"或者根据程序员自己的意图实现完整的 DOS 代码。它的大小一般不能确定。利用链接器(linker)的 /STUB:fijvzquC41dnuh0lxfp0tfv8~i{cthi~fpi1gsvrhng1jfvjnnu1;33?;:4
8.PE文件结构详解快速的计算方法是从文件的偏移0x3C(第59字节)处获得一个4字节的PE文件签名的偏移地址,这个偏移地址就是本文所定义的DOS头的大小。NT头在32位系统是244字节,在64位系统是260字节。节头的大小由NT头的第1部分的NumberOfSections(节的数量)*40字节(每个节头是40字节)得出。如此,DOS头、NT头、节头3个头的大小jvzquC41dnuh0lxfp0tfv8vkokthaƒmcpi5bt}neng5eg}fknu5859>;2;
9.C++PE文件格式解析类(轻松制作自己的PE文件解析器)pe文件绑定(c++本文介绍了一个用C++封装的高效PE文件格式解析类,提供了丰富的接口函数,便于理解和使用。适用于学习PE文件结构及开发PE文件解析软件。 PE是Portable ExecutableFileFormat(可移植的执行体)简写,它是目前Windows平台上的主流可执行文件格式。 PE文件中包含的内容很多,具体我就不在这解释了,有兴趣的可以参看之后列出的参考jvzquC41dnuh0lxfp0tfv8ucuenfp8ftvkimg8igvcomu8:286654:
10.Windows基础知识PE结构之初始PE当执行体在支持PE文件结构的操作系统中执行时,PE装载器将从IMAGE_DOS_HEADER结构的e_lfanew字段里找到NT头的起始偏移量,用其加上基址,得到PE文件头的指针。 在C++中Signature会被预处理为IMAGE_NT_SIGNATURE #define IMAGE_NT_SIGNATURE 0x00004550// PE00 FileHeader 文件头,表现jvzquC41z|4bnr~wp0ipo8sgyu526=98
11.有效利用PE文件内部空间植入用户程序windowspe广告应用植入本文介绍了一种利用PE文件内部空间植入用户程序的方法。通过在PE文件的节间空隙存储额外代码,实现代码的隐蔽植入。该技术适用于寄生型病毒程序,能够有效避免因文件体积增大而被轻易检测。 【文章标题】: 有效利用PE文件内部空间植入用户程序 【文章作者】: 空手剑客 jvzquC41dnuh0lxfp0tfv8hpalkwqwx1ctzjeuj1fgzbkux143624A<
12.PE文件查看器(PeViewer)电脑版下载2025最新文件分割口碑排行榜 PDF猫分割合并软件 小说分割器(TXT文本) peview.exe Ultra Video Splitter 下载服务协议见页面底部 基本简介 PE文件查看器(PeViewer)是一款强大的PE文件查看器,PeViewer作为国人研制开发十分的强大并便捷,下载使用这款PeViewer文件,可以任意的dll等文件,马上下载PeViewer吧。 jvzq<84yyy4ppunpgfuxp7sgv1yph}4;997777mvo
13.LordPE下载LordPE(PE文件编辑器)v1.4绿色汉化版下载LordPE v1.4绿色汉化版是一款非常好用PE文件编辑工具,winwin7小编听闻该软件在网上享有“最好的PE文件修改工具”的称号!LordPE是一款相当专业功能强大的pe文件修改器工具,支持用户快速方便的修改pe文件,并且软件是完全汉化的,我们使用起来也完全不会因为不懂英文而烦恼,如有需要的用户快来下载这款反编译预处理的利器jvzq<84yyy4xkw|kp94dqv4uqhz06<950jznn
14.逆向基础PE文件结构windowspe结构本文详细介绍了PE文件的结构,包括DOS头、NT头、文件头、可选PE头、区段头等关键部分,并通过代码示例展示了如何解析这些头信息。同时,解释了PE文件在Windows平台上的执行过程,如DOS头的兼容性、PE头的标志、可选PE头中的入口点和内存基址等。此外,还涵盖了导出表、导入表、重定位表和TLS(线程局部存储)的概念及其jvzquC41dnuh0lxfp0tfv8FrrYnjvndUvcx0c{ykenk0fnyckny03;;295:18
15.pe文件结构PE文件的全称是Portable Executable,意为可移植的可执行文件,是微软Windows操作系统上广泛使用的程序文件格式(包括间接被执行的文件,如DLL)。PE文件被称为“可移植的”是因为在所有平台(如x86、Alpha、MIPS等)上实现的Windows NT及其后续版本(如Windows 95、Windows 2000、Windows XP、Windows Vista、Windows 7、WindowsjvzquC41dnuh0lxfp0tfv87525e93:;757>0c{ykenk0fnyckny03=5992>56
16.深入解析WindowsPE文件结构及其关键组成部分本文详细介绍了WindowsPE文件的基本概念,包括PE文件头、DOS头部、区块数据、虚拟地址和RVA等关键部分,展示了PE文件的内存映射和地址转换机制,以及如何通过API获取模块信息。 部分PE文件结构 一.PE文件基本概念 ​ PE文件是windows系统中遵循PE结构的文件,比如以.exe .dll .ocx .sys .com为后缀名的文件以及系统驱动jvzquC41dnuh0lxfp0tfv8r2a9;36<8841gsvrhng1jfvjnnu1748@76;6;
17.PE文件(一)PE结构概述PE文件(一)PE结构概述 本文详细介绍了Windows操作系统下的PE结构文件,包括.exe文件的内存分配、虚拟内存、PE文件的节和节表、DOS头与NT头的作用,以及编译器对文件对齐的影响。展示了不同操作系统文件结构的区别,以及如何手动解析PE文件的DOS头和NT头。 PE结构简述jvzquC41dnuh0lxfp0tfv87523e8:A8:86=0c{ykenk0fnyckny03<<;5;827
18.详解PE文件(一):PE文件基础概念详解PE文件(一):PE文件基础概念 PE(Portable Executable)文件格式是Windows操作系统中用于可执行文件(.exe)、动态链接库(.dll)和系统驱动程序(.sys)的标准文件格式。它是Windows平台上软件执行的基础,理解PE文件格式对于系统编程、逆向工程、恶意软件分析和软件安全等领域都很重要。jvzquC41dnuh0lxfp0tfv8lggukiq€ftf461294ctvodnn4fgvgjn|4376=53@55
19.PE文件格式详解:深入理解Windows可执行文件结构// 执行PE文件时,PE装载器先创建进程,再将文件载入内存,// 然后把EIP寄存器的值设置为ImageBase+AddressOfEntryPoint''// PE文件的Body部分被划分成若干节段,这些节段储存着不同类别的数据。'DWORD SectionAlignment;'// SectionAlignment指定了节段在内存中的最小单位, -> 00 00 10 00'DWORD FileAlignment;'//jvzquC41dnuh0lxfp0tfv8|gkzooa?75;3=478ftvkimg8igvcomu86676;82B7
20.PE文件结构剖析基本结构pe结构主模块基址PE文件衍生于早期建立的COFF文件格式,EXE和DLL文件实际上用的是同一种文件格式,唯一的区别就是用一个字段标识出这个文件是EXE还是DLL。64位Windows格式为PE32+。只是简单的将以前的32位字段扩展到64位。 重要要点 要认识到PE文件不是作为单一内存映射文件被装入内存的。 jvzquC41dnuh0lxfp0tfv8vsa669;9<781gsvrhng1jfvjnnu1>3:>>9;;