阅读:1909回复:0
转贴:关于PE可执行文件的修改(1)
关于PE可执行文件的修改(1)
[ 作者: ilsy 添加时间: 2001-9-24 9:25:08 ] 原创:ilsy(ILSY) 在windows 9x、NT、2000下,所有的可执行文件都是基于Microsoft设计的一种新的文件格式Portable Executable File Format(可移植的执行体),即PE格式。有一些时候,我们需要对这些可执行文件进行修改,下面文字试图详细的描述PE文件的格式及对PE格式文件的修改。 1、PE文件框架构成 DOS MZ header DOS stub PE header Section table Section 1 Section 2 Section ... Section n 上表是PE文件结构的总体层次分布。所有 PE文件(甚至32位的 DLLs) 必须以一个简单的 DOS MZ header 开始,在偏移0处有DOS下可执行文件的“MZ标志”,有了它,一旦程序在DOS下执行,DOS就能识别出这是有效的执行体,然后运行紧随 MZ header 之后的 DOS stub。DOS stub实际上是个有效的EXE,在不支持 PE文件格式的操作系统中,它将简单显示一个错误提示,类似于字符串 \" This program cannot run in DOS mode \" 或者程序员可根据自己的意图实现完整的 DOS代码。通常DOS stub由汇编器/编译器自动生成,对我们的用处不是很大,它简单调用中断21h服务9来显示字符串\"This program cannot run in DOS mode\"。 紧接着 DOS stub 的是 PE header。 PE header 是PE相关结构 IMAGE_NT_HEADERS 的简称,其中包含了许多PE装载器用到的重要域。可执行文件在支持PE文件结构的操作系统中执行时,PE装载器将从 DOS MZ header的偏移3CH处找到 PE header 的起始偏移量。因而跳过了 DOS stub 直接定位到真正的文件头 PE header。 PE文件的真正内容划分成块,称之为sections(节)。每节是一块拥有共同属性的数据,比如“.text”节等,那么,每一节的内容都是什么呢?实际上PE格式的文件把具有相同属性的内容放入同一个节中,而不必关心类似“.text”、“.data”的命名,其命名只是为了便于识别,所有,我们如果对PE格式的文件进行修改,理论上讲可以写入任何一个节内,并调整此节的属性就可以了。 PE header 接下来的数组结构 section table(节表)。 每个结构包含对应节的属性、文件偏移量、虚拟偏移量等。如果PE文件里有5个节,那么此结构数组内就有5个成员。 以上就是PE文件格式的物理分布,下面将总结一下装载一PE文件的主要步骤: 1、 PE文件被执行,PE装载器检查 DOS MZ header 里的 PE header 偏移量。如果找到,则跳转到 PE header。 2、PE装载器检查 PE header 的有效性。如果有效,就跳转到PE header的尾部。 3、紧跟 PE header 的是节表。PE装载器读取其中的节信息,并采用文件映射方法将这些节映射到内存,同时付上节表里指定的节属性。 4、PE文件映射入内存后,PE装载器将处理PE文件中类似 import table(引入表)逻辑部分。 上述步骤是一些前辈分析的结果简述。 2、PE文件头概述 我们可以在winnt.h这个文件中找到关于PE文件头的定义: typedef struct _IMAGE_NT_HEADERS { DWORD Signature; //PE文件头标志 :“PE\\0\\0”。在开始DOS header的偏移3CH处所指向的地址开始 IMAGE_FILE_HEADER FileHeader; //PE文件物理分布的信息 IMAGE_OPTIONAL_HEADER32 OptionalHeader; //PE文件逻辑分布的信息 } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; typedef struct _IMAGE_FILE_HEADER { WORD Machine; //该文件运行所需要的CPU,对于Intel平台是14Ch WORD NumberOfSections; //文件的节数目 DWORD TimeDateStamp; //文件创建日期和时间 DWORD PointerToSymbolTable; //用于调试 DWORD NumberOfSymbols; //符号表中符号个数 WORD SizeOfOptionalHeader; //OptionalHeader 结构大小 WORD Characteristics; //文件信息标记,区分文件是exe还是dll } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; typedef struct _IMAGE_OPTIONAL_HEADER { WORD Magic; //标志字(总是010bh) BYTE MajorLinkerVersion; //连接器版本号 BYTE MinorLinkerVersion; // DWORD SizeOfCode; //代码段大小 DWORD SizeOfInitializedData; //已初始化数据块大小 DWORD SizeOfUninitializedData; //未初始化数据块大小 DWORD AddressOfEntryPoint; //PE装载器准备运行的PE文件的第一个指令的RVA,若要改变整个执行的流程,可以将该值指定到新的RVA,这样新RVA处的指令首先被执行。(许多文章都有介绍RVA,请去了解) DWORD BaseOfCode; //代码段起始RVA DWORD BaseOfData; //数据段起始RVA DWORD ImageBase; //PE文件的装载地址 DWORD SectionAlignment; //块对齐 DWORD FileAlignment; //文件块对齐 WORD MajorOperatingSystemVersion;//所需操作系统版本号 WORD MinorOperatingSystemVersion;// WORD MajorImageVersion; //用户自定义版本号 WORD MinorImageVersion; // WORD MajorSubsystemVersion; //win32子系统版本。若PE文件是专门为Win32设计的 WORD MinorSubsystemVersion; //该子系统版本必定是4.0否则对话框不会有3维立体感 DWORD Win32VersionValue; //保留 DWORD SizeOfImage; //内存中整个PE映像体的尺寸 DWORD SizeOfHeaders; //所有头+节表的大小 DWORD CheckSum; //校验和 WORD Subsystem; //NT用来识别PE文件属于哪个子系统 WORD DllCharacteristics; // DWORD SizeOfStackReserve; // DWORD SizeOfStackCommit; // DWORD SizeOfHeapReserve; // DWORD SizeOfHeapCommit; // DWORD LoaderFlags; // DWORD NumberOfRvaAndSizes; // IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; //IMAGE_DATA_DIRECTORY 结构数组。每个结构给出一个重要数据结构的RVA,比如引入地址表等 } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; //表的RVA地址 DWORD Size; //大小 } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; |
|
最新喜欢:lsq77
|