1   1  /  1  页   跳转

[分享] 发发我总结的PE结构

发发我总结的PE结构

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)
分享到:
gototop
 

回复: 发发我总结的PE结构

4。。。节表
下面的这个节表是针对每个节而言的,也就是说每个节不一样的话所赋得成员值也不一样,每个节都40字节
typedef struct _IMAGE_SECTION_HEADER {
  BYTE  Name[IMAGE_SIZEOF_SHORT_NAME]; // 节表名称,如".text"  2E 74 65 78 74 00 00 00
  union {
  DWORD PhysicalAddress;  // 物理地址
  DWORD VirtualSize;  // 真实长度
  } Misc;
  DWORD VirtualAddress;  // RVA某一节在内存中的偏移
  DWORD SizeOfRawData;  // 物理长度,也就是文件中的对齐粒度  之前一般都定义为200
  DWORD PointerToRawData; // 节基于文件的偏移量,也就是节在文件中的偏移量
  DWORD PointerToRelocations; // 重定位的偏移
  DWORD PointerToLinenumbers; // 行号表的偏移
  WORD  NumberOfRelocations; // 重定位项数目
  WORD  NumberOfLinenumbers; // 行号表的数目
  DWORD Characteristics;  // 节属性20 00 60 00可读可写可执行
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
gototop
 
1   1  /  1  页   跳转
页面顶部
Powered by Discuz!NT