PE结构学习
1.。。。DOS头 64字节
typedef struct _IMAGE_DOS_HEADER
{
WORD e_magic; // 魔术数字 ASCII字符MZ 必须为4d 5a 0x00000000-0x00000001
WORD e_cblp; // 文件最后页的字节数 0x00000002-0x00000003
WORD e_cp; // 文件页数 0x00000004- 0x00000005
WORD e_crlc; // 重定位元素个数 0x00000006-0x00000007
WORD e_cparhdr; // 以段落为单位的头部大小 0x00000008-0x00000009
WORD e_minalloc; // 所需的最小附加段 0x0000000A-0x0000000B
WORD e_maxalloc; // 所需的最大附加段 0x0000000C-0x0000000D
WORD e_ss; // 初始的堆栈段(SS)相对偏移量值 0x0000000E-0x0000000F
WORD e_sp; // 初始的堆栈指针(SP)值 0x00000010-0x00000011
WORD e_csum; // 校验和
0x00000012- 0x00000013
WORD e_ip; // 初始的指令指针(IP)值 0x00000014-0x00000015
WORD e_cs; // 初始的代码段(CS)相对偏移量值 0x00000016-0x00000017
WORD e_lfarlc; // 重定位表在文件中的偏移地址 0x00000018-0x00000019
WORD e_ovno; // 覆盖号 0x0000001A- 0x0000001B
WORD e_res[4]; // 保留字(一般都是为确保对齐而预留) 0x0000001C-0x00000023
WORD e_oemid; // OEM 标识符(相对于 e_oeminfo) 0x00000024-0x00000025
WORD e_oeminfo; // OEM 信息,即 e_oemid 的细节 0x00000026-0x00000027
WORD e_res2[10]; // 保留字(一般都是为确保对齐而预留) 0x00000028-0x0000003B
LONG e_lfanew; // 新 exe 头在文件中的偏移地址 0x0000003C-0x0000003F
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
2.。。。DOS STUB 112字节
3.。。。pe头
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature; //50 45
IMAGE_FILE_HEADER FileHeader;------------->
IMAGE_OPTIONAL_HEADER OptionalHeader;--------------?
} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS,PeHeader;
>----------------文件头(20字节)----------------------->
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///#define IMAGE_FILE_MACHINE_UNKNOWN 0
///#define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386.
///#define IMAGE_FILE_MACHINE_R3000 0x0162 // MIPS little-endian, 0x160 big-endian
///#define IMAGE_FILE_MACHINE_R4000 0x0166 // MIPS little-endian
///#define IMAGE_FILE_MACHINE_R10000 0x0168 // MIPS little-endian
///#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 // MIPS little-endian WCE v2
///#define IMAGE_FILE_MACHINE_ALPHA 0x0184 // Alpha_AXP
///#define IMAGE_FILE_MACHINE_POWERPC 0x01F0 // IBM PowerPC Little-Endian
///#define IMAGE_FILE_MACHINE_SH3 0x01a2 // SH3 little-endian
///#define IMAGE_FILE_MACHINE_SH3E 0x01a4 // SH3E little-endian
///#define IMAGE_FILE_MACHINE_SH4 0x01a6 // SH4 little-endian
///#define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian
///#define IMAGE_FILE_MACHINE_THUMB 0x01c2
///#define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64
///#define IMAGE_FILE_MACHINE_MIPS16 0x0266 // MIPS
///#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 // MIPS
///#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 // MIPS
///#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64
///#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
WORD NumberOfSections;////////文件的节数目。如果我们要在文件中增加或删除一个节,就需要修改这个值。
DWORD TimeDateStamp;
//////////文件创建日期和时间。其格式是自从1969年12 月31 日4:00 P.M. 之后的总秒数。据我计算,0xFFFFFFFFh是136.19251950152207001522070015221 年
DWORD PointerToSymbolTable;
/////////COFF 符号表格的偏移位置。此域只对COFF 除错信息有用
DWORD NumberOfSymbols;
//////////COFF 符号表格中的符号个数
WORD SizeOfOptionalHeader;
//////////指示紧随本结构之后的 Optional Header(IMAGE_OPTIONAL_HEADER)结构大小,必须为有效值(224字节E0)
WORD Characteristics;
/////////////关于本文件信息的标记。一些比较重要的性质如下:
////0x0001 文件中没有重定位(relocation)
////0x0002 文件是一个可执行程序exe(也就是說不是OBJ 或LIB)
////0x2000 文件是dll,不是exe。
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
?----------------可选头(224字节)------------------------?
typedef struct _IMAGE_OPTIONAL_HEADER {
WORD Magic;
////用来定义 image 的状态
////0x0107(IMAGE_ROM_OPTIONAL_HDR_MAGIC):一个 ROM image
////0x010B(IMAGE_NT_OPTIONAL_HDR_MAGIC): 一个正常的(一般的)EXE image。大部份PE 文件都含此值
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
////所有code section 的总和大小。大部分程序只有一个 code section,所以此域通常就是 .text section 的大小。
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////这是PE文件开始执行的位置。这是一个RVA,通常会落在 .text section.此域适用于 exe 或 dll。OEP
////RAV 代表相对虚拟地址。RVA是虚拟空间中到参考点的一段距离。RVA就是类似文件偏移量的东西。当然它是相对虚拟空间里的一个地址,而不是文件头部。举例说明,如 ////果PE文件装入虚拟地址(VA)空间的400000h处,且进程从虚址401000h开始执行,我们可以说进程执行起始地址在RVA 1000h。每个RVA都是相对于模块的起始VA的。虛址 ////(VA)0x401000h - 基址(BA)0x400000h = RVA 0x1464h。基址(Base Address)用来描述被映射到内存中的exe或者dll的起始位置。 400000H
//// 为什么PE文件格式要用到RVA呢? 这是为了减少PE装载器的负担。因为每个模块都有可能被重载到任何虚拟地址空间,如果让PE装载器修正每个重定位项,这肯定是个梦 ////魇。相反,如果所有重定位项都使用RVA,那么PE装载器就不必操心那些东西了: 它只要将整个模块重定位到新的起始VA。这就象相对路径和绝对路径的概念: RVA类似相对 ////路径,VA就象绝对路径。
////在PE文件中大多数地址多是RVAs 而 RVAs只有当PE文件被PE装载器装入内存后才有意义。如果直接将文件映射到内存而不是通过PE装载器载入,则不能直接使用那些 ////RVAs。必须先将那些RVAs转换成文件偏移量。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DWORD BaseOfCode;
////一个RVA,表示程序中的 code section 从何开始。code section 通常在 data section 之前,在PE 表头之后。微软链接器所产生的exes 中,此值通常为0x1000。Borland 的////TLINK32则通常指定此值为0x10000。因为预设情况下TLINK时以64k为对齐粒度的,而MS用的是4k。
DWORD BaseOfData;
////一个RVA,表示程序中的 data section 从何开始。data section 一般位于code section 和 PE 表头之后。
DWORD ImageBase;
////PE文件的优先装载地址(Base Address)。比如,如果该值是400000h,PE装载器将尝试把文件装到虚拟地址空间的400000h处。字眼"优先"表示若该地址区域已被其他模块占////用,那PE装载器会选用其他空闲地址。
DWORD SectionAlignment;
////内存中节对齐的粒度。例如,如果该值是4096 (1000h),那么每节的起始地址必须是4096的倍数。若第一节从401000h开始且大小是10个字节,则下一节必定从402000h开始,////即使401000h和402000h之间还有很多空间没被使用。
DWORD FileAlignment;
////文件中节对齐的粒度。例如,如果该值是(200h),,那么每节的起始地址必须是512的倍数。若第一节从文件偏移量200h开始且大小是10个字节,则下一节必定位于偏移量400h////,即使偏移量512和1024之间还有很多空间没被使用或定义。预设值就是0x200h。
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
////MajorSubsystemVersion/MinorSubsystemVersion:WIN32子系统版本。若PE文件是专门为WIN32设计的,该子系统版本必定是4.0否则对话框不会有3维立体感。00 04 00 00
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
////内存中整个PE映像体的尺寸。它是所有头和节经过节对齐处理后的大小。也就是从image base 开始,直到最后一个 section为止。最后一个section 的尾端必需是////SectionAlignment 的倍数。
DWORD SizeOfHeaders;
////所有头 + 节表的大小,也就等于文件尺寸减去文件中所有节的尺寸。可以以此值作为PE文件第一节的文件偏移量。也是对齐后的,因为没个头和节都小于1000那么对齐后都
////按1000处理
DWORD CheckSum;
////此程序的一个CRC 校验和。PE中此域通常被忽略并被设为0。然而,所有的driver DLLs、所有在开机时载入的DLLs、以及server DLLs 都必须有一个合法的 CheckSum。其演////算法可以在IMAGEHLP.DLL中获得。IMAGEHLP.DLL 的代码可以在WIN32 SDK中找到。
WORD Subsystem;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////用来识别PE文件属于哪个子系统。对于大多数Win32程序,只有两类值: Windows GUI 和 Windows CUI (控制台)。WINNT.h中定义如下:
////#define IMAGE_SUBSYSTEM_UNKNOWN 0 Unknown subsystem.
////#define IMAGE_SUBSYSTEM_NATIVE 1 不需要子系統(例如驱动程序)
////#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 在Windows GUI 子系统中运行
////#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 在Windows 字符模式子系统中运行(也就是console 应用程序)
////#define IMAGE_SUBSYSTEM_OS2_CUI 5 在OS/2 字符模式子系统中运行(也就是OS/2 1.x 应用程序)
////#define IMAGE_SUBSYSTEM_POSIX_CUI 7 在Posix 字符模式子系统中运行
////#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 一个Win9x驱动
////#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 在Win CE 子系统中运行
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
WORD DllCharacteristics;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////一组标志位,用来指出dll的初始化函数(例如 DllMain)在什么环境下被调用。这个值总是0,但是操作系统会在四种情况发生式调用dll的初始化函数。此值的四个值的意义如下:
////0x0001:当DLL被载入一个进程的地址空间时
////0x0002:当一个线程结束时
////0x0004:但一个线程开始时
////0x0008:当DLL退出时
////0x2000:一个WDM驱动
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DWORD SizeOfStackReserve;
////线程初始堆栈的保留大小。然而并不是所有的这些内存都被系统指定。此值预设为0x100000(1MB)。如果你的程序中调用CreateThread 并指定其堆栈大小为0,获得的线程////就有一个与此值相同大小的堆栈。
DWORD SizeOfStackCommit;
////一开始就被指定给执行线程初始堆栈的内存数量。微软的链接器预设此值为0x1000(一个page),Borland 的TLINK32把它设为0x2000(两个page)。
DWORD SizeOfHeapReserve;
////保留给最初的进程堆(process heap)的虚拟内存数量。这个堆的句柄可以利用GetProcessHeap 获得。并不是所有的这些内存都被指定。
DWORD SizeOfHeapCommit;
////一开始就被指定给进程堆(process heap)的内存数量。此值预设为0x1000个字节(位元组)。
DWORD LoaderFlags;
////Debug用。可能作用:
////a.在开始这个进程之前引发一个中断?
////b.在进程被载入之后引发一个除错器执行?
DWORD NumberOfRvaAndSizes;
////在DataDirectory(下一个域)数组的成员结构个数。目前的工具总是把此值设为16。
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////一个IMAGE_DATA_DIRECTORY 结构数组,这个数组有16个成员。每个结构给出一个重要数据结构的RVA。数组的第一个元素代表 Exported Function Table(如果有的话)的地址和大小,第二个元素////代表Imported Function Table 的地址和大小,第二个这个成员比较重要,依此类推。下面是其顺序的完整列表:
//// Directory Entries
////#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
////#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
////#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
////#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
////#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
////#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
////#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
////#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // Description String
////#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // Machine Value (MIPS GP)
////#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
////#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
////#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers
///#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
////96/112 8 Export Table Export Table address and size.
////104/120 8 Import Table Import Table address and size
////112/128 8 Resource Table Resource Table address and size.
////120/136 8 Exception Table Exception Table address and size.
////128/144 8 Certificate Table Attribute Certificate Table address and size.
////136/152 8 Base Relocation Table Base Relocation Table address and size.
////144/160 8 Debug Debug data starting address and size.
////152/168 8 Architecture Architecture-specific data address and size.
////160/176 8 Global Ptr Relative virtual address of the value to be stored in the global pointer register. Size member of this structure must be set to 0.
////168/184 8 TLS Table Thread Local Storage (TLS) Table address and size.
////176/192 8 Load Config Table Load Configuration Table address and size.
////184/200 8 Bound Import Bound Import Table address and size.
////192/208 8 IAT Import Address Table address and size.
////200/216 8 Delay Import Descriptor Address and size of the Delay Import Descriptor.
////208/224 8 COM+ Runtime Header COM+ Runtime Header address and size
////216/232 8 Reserved
////每个表8字节
////typedef struct _IMAGE_DATA_DIRECTORY {
//// DWORD VirtualAddress;-----------------起始rva地址10 20 00 00
//// DWORD Size;----------------------------3c 00 00 00
////} IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;
-------导入表---------
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
_ANONYMOUS_UNION union {
//DWORD Characteristics;
DWORD OriginalFirstThunk;//指向IMAGE_THUNK_DATA的一个指针
} DUMMYUNIONNAME;
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name; //动态链接库的Name
DWORD FirstThunk; //指向IMAGE_THUNK_DATA的一个指针
} IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;
这里有两种导入方法,一种是以序号导入,一种是以字符串类型的函数名来导入的。
我们的每一个IMAGE_THUNK_DATA都是定义一个导入函数的信息。
他的结构定义
typedef struct _IMAGE_THUNK_DATA32 {
union {
DWORD ForwarderString; //指向 IMAGE_IMPORT_BY_NAME 结构
DWORD Function;
DWORD Ordinal;
DWORD AddressOfData;
} u1;
} IMAGE_THUNK_DATA32,*PIMAGE_THUNK_DATA32;
typedef struct _IMAGE_IMPORT_BY_NAME {
WORD Hint; //函数的序号
BYTE Name[1]; //函数名
} IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME;
用户系统信息:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 551; .NET CLR 2.0.50727)