小甲鱼系统篇PE结构讲解笔记之小甲鱼是帅比:https://fishc.com.cn/(鱼C论坛)
每个PE文件都是以一个DOS程序开始的,一旦在DOS中执行,才能正常识别。
PE文件的第一个字节起始于一个传统的MS-DOS头部,被称作IMAGE_DOS_HEADER。
IMAGE_DOS_HEADER结构:
重点有两个:
+0h WORD e_magic //用于说明DOS文件头
+3ch WORD e_lfanew //指向PE文件头
“MZ”标识了DOS头
偏移3c,000000e0,表示PE头的起始位置。
PE文件头
PE文件头紧挨着DOS首部。
PE Header是PE相关结构的NT映像头(IMAGE_NT_HEADER)的简称,里面包含许多PE装载器用到的重要字段。
执行体在支持PE文件结构的操作系统中执行时,PE装载器从IMAGE_DOS_HEADER结构中的e_lfanew字段里找到PE header的起始偏移量,加上基地址(内存中)就得到了PE文件头的指针。
IMAGE_NT_HEADER:
- IMAGE_NT_HEADERS STRUCT
- {
- +0h DWORD Signature
- +4h IMAGE_FILE_HEADER FileHeader
- +18h IMAGE_OPTIONAL_HEADER32 OptionlHeader //可选择的32位文件头
- }IMAGE_NT_HEADERS ENDS
1、Signature字段:在一个有效的PE文件里,signature字段被设置为00004550和,ASCII码字符为“PE00”,标志一个PE文件头的开始。
2、+4h IMAGE_FILE_HEADER FileHeader //
IMAGE_FILE_HEADER结构:
- typedef struct_IMAGE_FILE_HEADER
- {
- WORD Machine;-----------------//运行平台
- WORD NumberOfSections;---------//文件的区块数目
- DWORD TimeDateStamp;------------//文件创建日期和时间
- DWORD PointerToSymbolTable;-------//指向符号表(主要用于调试)
- DWORD NumberOfSymbols;--------//符号表中符号个数(主要用于调试)
- WORD SizeOfOptionalHeader;-----//IMAGE_FILE_HEADER32结构大小
- WORD Characteristics;//文件属性
- }IMAGE_FILE_HEADER,*PIMAGE_FILE_HEADER;
Machine可执行文件的目标CPU类型:014c表示x86
NumberOfSections:文件区块数目:0005,5个区块。
TimeDateStamp:格林威治时间记录
PointerToSymbolTable
NumberOfSymbols :这两个主要用于调试
SizeOfOptionalHeader:紧跟在IMAGE_FILE_HEADE后边的数据结构(IMAGE_OPTION_HEADER)的大小。(32位PE文件通常是000eh,64位PE+文件通常为00f0h)。
Characteristics:文件属性。DLL文件通常为:210eh,exe文件通常为0100h。
3、+18h IMAGE_OPTIONAL_HEADER32 OptionlHeader:
属于IMAGE_FILE_HEADER的补充结构,用于说明其他的文件属性。
typedef struct _IMAGE_OPTIONAL_HEADER
{
//
// Standard fields.
//
+18h WORD Magic; // 标志字, ROM 映像(0107h),普通可执行文件(010Bh)
+1Ah BYTE MajorLinkerVersion; // 链接程序的主版本号
+1Bh BYTE MinorLinkerVersion; // 链接程序的次版本号
+1Ch DWORD SizeOfCode; // 所有含代码的节的总大小
+20h DWORD SizeOfInitializedData; // 所有含已初始化数据的节的总大小
+24h DWORD SizeOfUninitializedData; // 所有含未初始化数据的节的大小
+28h DWORD AddressOfEntryPoint; // 程序执行入口RVA
+2Ch DWORD BaseOfCode; // 代码的区块的起始RVA
+30h DWORD BaseOfData; // 数据的区块的起始RVA
//
// NT additional fields. 以下是属于NT结构增加的领域。
//
+34h DWORD ImageBase; // 程序的首选装载地址
+38h DWORD SectionAlignment; // 内存中的区块的对齐大小
+3Ch DWORD FileAlignment; // 文件中的区块的对齐大小
+40h WORD MajorOperatingSystemVersion; // 要求操作系统最低版本号的主版本号
+42h WORD MinorOperatingSystemVersion; // 要求操作系统最低版本号的副版本号
+44h WORD MajorImageVersion; // 可运行于操作系统的主版本号
+46h WORD MinorImageVersion; // 可运行于操作系统的次版本号
+48h WORD MajorSubsystemVersion; // 要求最低子系统版本的主版本号
+4Ah WORD MinorSubsystemVersion; // 要求最低子系统版本的次版本号
+4Ch DWORD Win32VersionValue; // 莫须有字段,不被病毒利用的话一般为0
+50h DWORD SizeOfImage; // 映像装入内存后的总尺寸
+54h DWORD SizeOfHeaders; // 所有头 + 区块表的尺寸大小
+58h DWORD CheckSum; // 映像的校检和
+5Ch WORD Subsystem; // 可执行文件期望的子系统
+5Eh WORD DllCharacteristics; // DllMain()函数何时被调用,默认为 0
+60h DWORD SizeOfStackReserve; // 初始化时的栈大小
+64h DWORD SizeOfStackCommit; // 初始化时实际提交的栈大小
+68h DWORD SizeOfHeapReserve; // 初始化时保留的堆大小
+6Ch DWORD SizeOfHeapCommit; // 初始化时实际提交的堆大小
+70h DWORD LoaderFlags; // 与调试有关,默认为 0
+74h DWORD NumberOfRvaAndSizes; // 下边数据目录的项数,这个字段自Windows NT 发布以来 // 一直是16
+78h IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
// 数据目录表
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
重要的字段:
AddressOfEntryPoint 指出文件被执行的入口地址(OEP)。
ImageBase:指出文件优先装入的地址。
SectionAlignment 字段和 FileAlignment字段:SectionAlignment字段指定了节被装入内存后的对齐单位。也就是说,每个节被装入的地址必定是本字段指定数值的整数倍。而FileAlignment字段指定了节存储在磁盘文件中时的对齐单位。
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]:
可以说是最重要的字段之一,它由16个相同的IMAGE_DATA_DIRECTORY结构组成,虽然PE文件中的数据是按照装入内存后的页属性归类而被放在不同的节中的,但是这些处于各个节中的数据按照用途可以被分为导出表、导入表、资源、重定位表等数据块,这16个IMAGE_DATA_DIRECTORY结构就是用来定义多种不同用途的数据块的(如表17.4所示)。IMAGE_DATA_DIRECTORY结构的定义很简单,它仅仅指出了某种数据块的位置和长度。
IMAGE_DATA_DIRECTORY STRUCT
VirtualAddress DWORD ? ;数据的起始RVA
isize DWORD ? ;数据块的长度
IMAGE_DATA_DIRECTORY ENDS
数据目录列表的含义
在PE文件中寻找特定的数据时就是从这些IMAGE_DATA_DIRECTORY结构开始的,比如要存取资源,那么必须从第3个IMAGE_DATA_DIRECTORY结构(索引为2)中得到资源数据块的大小和位置;同理,如果要查看PE文件导入了哪些DLL文件的哪些API函数,那就必须首先从第2个IMAGE_DATA_DIRECTORY结构得到导入表的位置和大小。