1.常见PE文件
可执行文件:EXE,SCR,COM
驱动程序:SYS,VSD
库文件:DLL,OCX,CPL,DRV
对象文件:OBJ
2.PE32(32位)、PE32+或者PE+(64位)
3.PE组成:
DOS头
DOS存根
NT头
节区头(代码段)
节区头(数据段)
节区头(资源段)
节区(代码段)
节区(数据段)
节区(资源段)
4.VA(virtual address:虚拟地址)&RVA(relative virtual address:相对虚拟地址)
VA=RVA+ImageBase(映象基址)
5.DOS头
IMAGE_DOS_HEADER STRUCT
{
+0h WORD e_magic // Magic DOS signature MZ(4Dh 5Ah) DOS可执行文件标记
+2h WORD e_cblp // Bytes on last page of file 最后一页大小
+4h WORD e_cp // Pages in file 文件页数
+6h WORD e_crlc // Relocations
+8h WORD e_cparhdr // Size of header in paragraphs 头的段大小
+0ah WORD e_minalloc // Minimun extra paragraphs needs 最小额外段需求
+0ch WORD e_maxalloc // Maximun extra paragraphs needs 最大额外段需求
+0eh WORD e_ss // intial(relative)SS value DOS代码的初始化堆栈SS
+10h WORD e_sp // intial SP value DOS代码的初始化堆栈指针SP
+12h WORD e_csum // Checksum 校验和
+14h WORD e_ip // intial IP value DOS代码的初始化指令入口[指针IP]
+16h WORD e_cs // intial(relative)CS value DOS代码的初始堆栈入口
+18h WORD e_lfarlc // File Address of relocation table 重定位表的文件地址
+1ah WORD e_ovno // Overlay number
+1ch WORD e_res[4] // Reserved words 保留字
+24h WORD e_oemid // OEM identifier(for e_oeminfo)
+26h WORD e_oeminfo // OEM information;e_oemid specific
+29h WORD e_res2[10] // Reserved words 保留字
+3ch DWORD e_lfanew //Offset to start of PE header NT头地址
} IMAGE_DOS_HEADER ENDS
6.DOS存根
DOS存根是16位的汇编指令,用以在DOS中运行
7.NT头
typedef struct _IMAGE_NT_HEADERS {
+00h DWORD Signature; //PE签名 固定为 "PE"00(0X50450000)
+04h IMAGE_FILE_HEADER FileHeader; //文件头 大小为0xF8
+18h IMAGE_OPTIONAL_HEADER32 OptionalHeader;//可选头
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
//文件头
typedef struct _IMAGE_FILE_HEADER {
+00h WORD Machine; //CPU机器码,I386对应为0x014c
+02h WORD NumberOfSections; //节区数量
+04h DWORD TimeDateStamp; //PE文件的创建时间,一般有连接器填写。
+08h DWORD PointerToSymbolTable; //COFF文件符号表在文件中的偏移。
+0ch DWORD NumberOfSymbols; //符号表的数量。
+10h WORD SizeOfOptionalHeader; //可选头大小
+12h WORD Characteristics; //文件属性标志(用或计算) 常见:0x0002:可执行文件 0x2000:DLL文件
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
//可选头,以32位下可选头为例
typedef struct _IMAGE_OPTIONAL_HEADER {
+00h WORD Magic; //可选头类型
+02h BYTE MajorLinkerVersion; //连接器版本号
+03h BYTE MinorLinkerVersion; //连接器版本号
+04h DWORD SizeOfCode; //代码段的长度,如果有多个代码段,则是代码段长度的总和。
+08h DWORD SizeOfInitializedData; //初始化的数据长度。
+0ch DWORD SizeOfUninitializedData; //未初始化的数据长度。
+10h DWORD AddressOfEntryPoint; //程序的EP(RVA表示)
+14h DWORD BaseOfCode; //代码段起始地址的RVA。
+18h DWORD BaseOfData; //数据段起始地址的RVA。
+1ch DWORD ImageBase; //映象(加载到内存中的PE文件)的基地址,这个基地址是建议,对于DLL来说,如果无法加载到这个地址,系统会自动为其选择地址。
+20h DWORD SectionAlignment; //节对齐,PE中的节被加载到内存时会按照这个域指定的值来对齐,比如这个值是0x1000,那么每个节的起始地址的低12位都为0。
+24h DWORD FileAlignment;//节在文件中按此值对齐,SectionAlignment必须大于或等于FileAlignment。
+28h WORD MajorOperatingSystemVersion; //操作系统版本号
+2ah WORD MinorOperatingSystemVersion; //操作系统版本号
+2ch WORD MajorImageVersion; //映象的版本号,这个是开发者自己指定的,由连接器填写。
+2eh WORD MinorImageVersion; //映象的版本号,这个是开发者自己指定的,由连接器填写。
+30h WORD MajorSubsystemVersion; //所需子系统版本号。
+32h WORD MinorSubsystemVersion; //所需子系统版本号。
+34h DWORD Win32VersionValue; //保留,必须为0。
+38h DWORD SizeOfImage; //映象的大小,PE文件加载到内存中空间是连续的,这个值指定占用虚拟空间的大小。
+3ch DWORD SizeOfHeaders; //所有文件头(包括节表)的大小,这个值是以FileAlignment对齐的。
+40h DWORD CheckSum; //映象文件的校验和。
+44h WORD Subsystem; //运行该PE文件所需的子系统(1.系统驱动,2.窗口应用程序,3.控制台应用)
+46h WORD DllCharacteristics; //DLL的文件属性
+48h DWORD SizeOfStackReserve; //运行时为每个线程栈保留内存的大小。
+4ch DWORD SizeOfStackCommit; //运行时每个线程栈初始占用内存大小。
+50h DWORD SizeOfHeapReserve; //运行时为进程堆保留内存大小。
+54h DWORD SizeOfHeapCommit; //运行时进程堆初始占用内存大小。
+58h DWORD LoaderFlags; //保留,必须为0。
+5eh DWORD NumberOfRvaAndSizes; //数据目录的项数,即下面这个数组的项数
+60h IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; //数据目录,这是一个数组,第i项含义在下边
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
typedef struct {
+00h DWORD VirtualAddress; //RVA
+04h DWORD Size; //大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
#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
// IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of 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
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor
8.节区头
typedef struct _IMAGE_SECTION_HEADER {
+00h BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; //8个字节的区块名
+08h union { //区块尺寸
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
+0ch DWORD VirtualAddress; //区块的RVA地址
+10h DWORD SizeOfRawData; //文件对齐后的尺寸
+14h DWORD PointerToRawData; //文件偏移
+18h DWORD PointerToRelocations;
+1ch DWORD PointerToLinenumbers;
+20h WORD NumberOfRelocations;
+22h WORD NumberOfLinenumbers;
+24h DWORD Characteristics; //区块的属性
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
RVA与RAW换算(内存地址与文件偏移的转换)
RAW=RVA-VirtualAddress+PointerToRawData
9.IAT(Import Address Table:导入地址表):
INT和IAT是以NULL为结束的长整型数组,保存的是_IMAGE_IMPORT_BY_NAME, IMAGE_THUNK_DATA 的地址
_IMAGE_IMPORT_DESCRIPTOR:结构体中记录着PE文件要导入哪些库文件
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics; //
DWORD OriginalFirstThunk; // INT地址(RVA)
};
DWORD TimeDateStamp; //
DWORD ForwarderChain; //
DWORD Name; // RVA,指向字符串,是这个可执行文件的名字。例如"ACE.dll"
DWORD FirstThunk; // IAT地址(RVA)
} IMAGE_IMPORT_DESCRIPTOR;
typedef struct _IMAGE_IMPORT_BY_NAME {
WORD Hint; ///该函数的导出序数
BYTE Name[1]; ///该函数的名字
} `, *PIMAGE_IMPORT_BY_NAME;
typedef struct _IMAGE_THUNK_DATA32 {
union {
DWORD ForwarderString; // 一个RVA地址,指向forwarder string
DWORD Function; // PDWORD,被导入的函数的入口地址
DWORD Ordinal; // 该函数的序数
DWORD AddressOfData; // 一个RVA地址,指向IMAGE_IMPORT_BY_NAME
} u1;
} IMAGE_THUNK_DATA32;
IMAGE_THUNK_DATA64与IMAGE_THUNK_DATA32的区别,仅仅是把DWORD换成了64位整数。
10.EAT
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name; //模块的内部名称,如果DLL文件的名字被用户改了,那么PE加载器会使用这个内部名称
DWORD Base; //序号的起始编号,注意:起始序号可以不为0
DWORD NumberOfFunctions; //导出函数的个数
DWORD NumberOfNames; //导出函数中具名函数个数
DWORD AddressOfFunctions; //导出函数地址表所在地址(大小等于NumberOfNames)
DWORD AddressOfNames; //导出函数名称表所在地址(大小等于NumberOfNames)
DWORD AddressOfNameOrdinals; //导出函数序数表所在地址(大小等于NumberOfNames)
} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY;
PE文件结构(懒的写博客我直接贴代码还不行么!)
最新推荐文章于 2023-09-11 10:16:19 发布