PE文件格式
PE文件时windows中的32位可执行文件。在linux中是elf。如exe,dll,scr等都是PE文件
基本结构
PE文件中的RVA(相对虚拟地址)一般不是直接转换到真实的虚拟地址的,还要加上一个基准地址(ImageBase).也就是说VA = RVA + ImageBase
这样做主要是因为DLL,DLL动态链接时如果发现这个虚拟地址已经有其他的dll了,那么就要进行重定位到其他位置,如果没有ImageBase那么重定位是很麻烦的。
PE头
DOS头
typedef struct _IMAGE_DOS_HEADER |
上面就是dos头的结构。
- e_magic: DOS签名(魔数)也就是4D5A(ascii的MZ)
- e_lfanew: 指示NT头的偏移(NT头位置)
NT头
结构体:typedef struct _IMAGE_NT_HEADERS
{
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
}IMAGE_NT_HEADER32, *PIMAGE_NT_HEADERS32;
- Signature: 签名(50450000h)
typedef struct _MIAGE_FILE_HEADER |
- Machine: 机器型号码,例如Intel x86是14c。
- NumerOfSections: 节的数量
- SizeOfOptionalHeader
- Characteristics: 用来标识文件的属性,文件是否处于可运行状态,是否是dll文件。可选头,结构体为IMAGE_OPTIONAL_HEADER32,重要成员有9个:
在winnt.h中有Characterristics的信息
IMAGE_FILE_RELOCS_STPIPPED 0X001
IMAGE_FILE_EXECUATABLE_IMAGE 0X002
IMAGE_FILE_LINE_NUMS_STRIPPED 0X004
IMAGE_FILE_LOCAL_SYMS_STRIPPED 0X008
IMAGE_FILE_AGGRSIVE_WS_TRIM 0X0010
IMAGE_FILE_LARGE_ADDRESS_AWARE 0X0020
IMAGE_FILE_BYTES_REVERSED_L0 0X0080
IMAGE_FILE_32BIT_MACHINE 0X0100
IMAGE_FILE_DEBUG_STRIPPED 0X200 - Magic:IMAGE_OPTIONAL_HEADER32为10B,IMAGE_OPTIONAL_HEADER64为20B
- AddressOfEntryPoint:持有EP的RVA值,指出程序最先执行的代码起始地址
- ImageBase:指出文件的优先装入地址(32位进程虚拟内存范围为:0~7FFFFFFF)
- SectionAlignment,FileAlignment:前者制定了节区在内存中的最小单位,后者制定了节区在磁盘文件中的最小单位
- SizeOfImage:指定了PE Image在虚拟内存中所占空间的大小
- SizeOfHeaders:指出整个PE头的大小
- Subsystem:区分系统驱动文件和普通可执行文件
- NumberOfRvaAndSize:指定DataDirectory数组的个数
- DataDirectory:由IMAGE_DATA_DIRECTORY结构体组成的数组
节区头
typedef struct _MIAGE_SECTION_HEADER |
- VirtualSize: 节区所占大小
- VirtualAddress: 节区起始位置
- SizeOfRawData: 磁盘中的大小
- PointerToRwaData: 磁盘中的位置
- Characteristics: 节区.属性
虚拟地址与内存地址之间的转换关系为RAW - PointerToRawData = RVA - VirtualAddress
其中RAW是文件偏移,PointerToRawData是该节在文件中的首地址。RVA是在内存中的地址,VirtualAddress是在节在内存中的首地址
IAT(导入地址表)
IAT是记录程序正在使用库中那些函数的表。
DLL
为了理解IAT,首先要了解DLL(动态链接库,在linux中是.so).它是在程序运行时动态加载的,而不是在链接过程中加载的。
IMAGE_IMPORT_DESCRIPTOR
这个表记录了要导入那些头文件.它的结构体数组的首地址是IMAGE_OPTIONAL_HEADER32.DataDirectory[1].VirtualAddress
typedef struct _IMAGE_IMPORT_DESCRIPTOR |
每一个导入的库的信息使用用一个IMAGE_IMPORT_DESCRIPTOR进行描述
- OriginalFirstThunk: INT地址(RVA)
- Nam: 库名称字符串的地址(RVA)
- FirstThunk: IAT地址(RVA)
- OriginalFirstThunk(INT): INT是包含导入函数信息的结构体指针数组,只有获得了这些信息才有可能在加载到进程的库中获得函数首地址。
EAT
EAT是dll库用来提供函数地址的,IAT记录了导入的dll库的函数地址。
与IAT不同EAT只有一个,位置在IMAGE_OPTIONAL_HEADER32.DataDirectory[0].VirtualAddress中
typedef struct _IMAGE_EXPORT_DIRECTORY |
- NumberOfFunctions: 实际Export函数个数
- NumberOfNames: 实际有名字函数个数
- AddressOfFunctions: Export函数地址数组
- AddressOfNames: 函数名称地址数组
- AddressOfNameOrdinals: Ordinal地址数组