1.PE文件格式
PE文件是win操作系统下的可执行文件格式
PE文件指32位可执行文件(PE32),PE+/PE32+指64位的可执行文件
1.1.PE文件种类
可执行:EXE,SCR
驱动程序:SYS,VXD
库:DLL,OCX,CPL,DRV
对象文件:OBJ(除了OBJ外所有文件都是可执行的,在逆向分析中几乎不需要关注它)
1.2.基本结构
DOS头(DOS header)到节区头(Section header)是PE的头部分,其下的节区合称节区体。各节区头定义了节区在文件或内存中的大小、位置、属性等
文件中使用偏移(offset),内存中使用VA(虚拟地址)来表示位置
文件加载到内存时,节区的位置大小等就会发生变化
文件的内容一般可分为代码(.text)、数据(.data)、资源(.rsrc)节,分别保存下来
PE头和各节区的尾部存在一个区域(NULL填充)
1.3.VA(进程虚拟内存的绝对地址)&RVA(从某个基准位置开始的相对虚拟地址)
PE头内部信息大多以RVA形式存在
1.4.PE头
1.4.1.DOS头
为了充分考虑PE文件对DOS文件的兼容性,在PE头在前面添加一个IMAGE_DOS_HEADER结构体,用来扩展DOS EXE头
结构体的大小为40个字节
typedef struct _IMAGE_DOS_HEADER {
WORD e_magic; //DOS签名: 4D5A("MZ")
WORD e_cblp;
WORD e_cp;
WORD e_crlc;
WORD e_cparhdr;
WORD e_minalloc;
WORD e_maxalloc;
WORD e_ss;
WORD e_sp;
WORD e_csum;
WORD e_ip;
WORD e_cs;
WORD e_lfarlc;
WORD e_ovno;
WORD e_res[4];
WORD e_oemid;
WORD e_oeminfo;
WORD e_res2[10];
WORD e_lfanew; //指向NT头的所在位置
1.4.2.DOS存根
在DOS头下方,可选项,大小不固定,由代码和数据混合而成
1.5.NT头(IMAGE_NT_HEADERS)
typedef struct _IMAGE_NT_HEADERS {
DOWRD Signature; //签名结构体,其值为50450000h("PE" 00)
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader; //文件头
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; //可选头
1.5.1.文件头
表现文件大致属性的IMAGE_FILE_HEADER结构体
typedef struct _IMAGE_FILE_HEADER {
WORD Machine; //每一个cpu都有唯一的Machine码
WORD NumberOfSections; //PE文件把代码、数据、资源等依据属性分类到各节区存储,所以NumberOfSections用来指出文件中存在的节区数量
DWORD TimeDateStamp; //记录编译器创建此文件的时间
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader; //用来指出IMAGE_OPTIONAL_HEADER32结构体体的长度
WORD Characteristics; //用于标识文件的属性,是否可运行、是否为DLL文件等
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
1.5.2.可选头(IMAGE_OPTIONAL_HEADER32)
PE头结构体中最大的
typedef struct _IMAGE_DATA_DIECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIECTORY, *PIMAGE_DATA_DIECTORY;
#define IMAGE_NUMBEROF_DIECTORY_ENTRIES 16
typedef struct _IMAGE_OPTIONAL_HEADER {
WORD Magic; //32结构体时为10B,64结构体时为20B
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfcode;
DWORD SizeOfInitializedDate;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint; //持有EP的RVA值,指出程序最先执行的代码起始地址,十分重要
DWORD BaseOfCode;
DWORD BaseOfData;
DWORD ImageBase; //指出文件的优先装入地址
DWORD SectionAlignment; //PE文件的Body部分划分为若干节区,存储不同类型的数据,SectionAlignment制定了节区在内存中的最小单位
DWORD FileAlignment; //指定了节区在磁盘文件的最小单位
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage; //指定了PE Image在虚拟内存的所占空间大小
DWORD SizeOfHeaders; //指出整个PE头的大小
DWORD CheckSum;
WORD Subsystem; //区分系统驱动文件(*.sys)与普通可执行文件(*.exe,*.dll)
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes; //指定DataDirectory数组的个数
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBER_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
1.6.IAT(导入地址表)
IAT保存的内容与WIn的核心进程、内存、DLL结构等有关,简言之,IAT是一种表格,记录程序正在使用哪些库中的函数
1.6.2.DLL(动态链接库)
不要把库包含到程序中,单独构成DLL文件,需要时调用即可
内存映射技术使加载后的DLL代码、资源在多个进程中实现共享
更新库时只要替换相关DLL文件
加载DLL方式:
a.显式链接:程序使用DLL时加载,使用完毕后释放内存
b.隐式链接:开始时一同加载DLL,程序终止时释放占用的内存,IAT提供的机制即与此方式有关