指尖博客

记录个人成长

PE文件(一)

PE文件介绍

PE文件是Windows下可执行文件的总称,常见的有DLL,EXE,OCX,SYS等,事实上,一个文件是否是PE文件与其扩展名无关,PE文件可以是任何扩展名。
PE.jpg

基地址

当PE文件通过Windows加载器载入到内存之后,内存中的版本称为模块,映射文件的起始地址称为基地址
.jpg

虚拟地址

在Windows系统中,PE文件被系统加载器映射到内存中。每个程序都有自己的虚拟空间,这个虚拟空间的内存地址称为虚拟地址( Virtual Address,VA )。

相对虚拟地址

假设一个exe文件从400000h处载入,它的代码区块开始于401000h处,那么代码块的相对虚拟地址(Relative Virtual Address,RVA)计算方法如下:
目标地址401000h -载入地址400000h = RVA 1000h
将一个RVA转化成真实地址:
虚拟地址( VA)=基地址( ImageBase )+相对虚拟地址(RVA )

MS-DOS头部

每个PE文件都是以一个DOS程序开始的。DOS头中的重点就是e_magic(MZ标识)和e_lfanew(指出真正PE头文件的偏移位置)

    struct _IMAGE_DOS_HEADER { 
        0x00 WORD e_magic; //Dos可执行文件标记“Mz"
        0x02 WORD e_cblp; 
        0x04 WORD e_cp; 
        0x06 WORD e_crlc; 
        0x08 WORD e_cparhdr; 
        0x0a WORD e_minalloc; 
        0x0c WORD e_maxalloc; 
        0x0e WORD e_ss; 
        0x10 WORD e_sp; 
        0x12 WORD e_csum; 
        0x14 WORD e_ip; //Dos代码入口IP
        0x16 WORD e_cs; //DOs代码入口cs
        0x18 WORD e_lfarlc; 
        0x1a WORD e_ovno; 
        0x1c WORD e_res[4]; 
        0x24 WORD e_oemid; 
        0x26 WORD e_oeminfo; 
        0x28 WORD e_res2[10]; 
        0x3c DWORD e_lfanew; //指向PE文件头"PE",0 , 0
    };

e_magic:"MZ标记" 用于判断是否为可执行文件.
e_lfanew:PE头相对于文件的偏移,用于定位PE文件
4.jpg

PE文件头

紧接着dos头的是PE文件头(PE Header),它是PE相关结构NT映像头(IMAGE_NT_HEADERS)的简称,PE装载器将从IMAGE_DOS_HEADER 结构的e_lfanew字段里找到PE Header的起始偏移量,用其加上基址,得到PE文件头的指针。

  PNTHeader = ImageBase + dosHeader -> e_lfanew
    struct _IMAGE_NT_HEADERS { 
        0x00 DWORD Signature; //PE文件标识
        0x04 _IMAGE_FILE_HEADER FileHeader; 
        0x18 _IMAGE_OPTIONAL_HEADER OptionalHeader; 
    };

在一个有效的PE文件里,Signature字段被设置为0x00004550,ASCII码字符是“PEOO”,

IMAGE_FILE_HEADER结构

    struct _IMAGE_FILE_HEADER { 
        0x00 WORD Machine; //运行平台,可执行文件的目标CPU类型
        0x02 WORD NumberOfSections; //文件区块的数目,块表在NT_Header后面
        0x04 DWORD TimeDateStamp; //文件创建的时间
        0x08 DWORD PointerToSymbolTable; //指向符号表(用于调试)
        0x0c DWORD NumberOfSymbols; //符号表中的符号个数(用于调试)
        0x10 WORD SizeOfOptionalHeader; IMAGE_OPTIONAL_HEADER32结构的大小。
        0x12 WORD Characteristics; //文件属性
    };

Machine:程序运行的CPU型号:0x0 任何处理器/0x14C 386及后续处理器
NumberOfSections:文件中存在的节的总数,如果要新增节或者合并节 就要修改这个值.
SizeOfOptionalHeader:可选PE头的大小,32位PE文件默认E0h 64位PE文件默认为F0h 大小可以自定义.
3.jpg
5.jpg

IMAGE_OPTIONAL_HEAADER

虽然名字是可选PE头,但并不意味它不重要,相反还非常重要!

    struct _IMAGE_OPTIONAL_HEADER { 
        0x00 WORD Magic; //标志字
        0x02 BYTE MajorLinkerVersion; //链接器主版本号
        0x03 BYTE MinorLinkerVersion; //链接器次版本号
        0x04 DWORD SizeOfCode; //所有含有代码的区块的大小
        0x08 DWORD SizeOfInitializedData; //所有初始化数据区块的大小
        0x0c DWORD SizeOfUninitializedData; //所有未初始化数据区块的大小
        0x10 DWORD AddressOfEntryPoint; //**程序执行人口 RVA**
        0x14 DWORD BaseOfCode; //代码区块起始RVA
        0x18 DWORD BaseOfData; //数据区块起始RVA
        0x1c DWORD ImageBase; //**程序默认载入基地址**
        0x20 DWORD SectionAlignment; //内存中区块的对齐值
        0x24 DWORD FileAlignment; //文件中区块的对齐值
        0x28 WORD MajorOperatingSystemVersion; 
        0x2a WORD MinorOperatingSystemVersion; 
        0x2c WORD MajorImageVersion; 
        0x2e WORD MinorImageVersion; 
        0x30 WORD MajorSubsystemVersion; 
        0x32 WORD MinorSubsystemVersion; 
        0x34 DWORD Win32VersionValue; 
        0x38 DWORD SizeOfImage; //映像载入内存后的总尺寸
        0x3c DWORD SizeOfHeaders; //MS-DOS头部、PE文件头、区块表总大小
        0x40 DWORD CheckSum; 
        0x44 WORD Subsystem; 
        0x46 WORD DllCharacteristics; 
        0x48 DWORD SizeOfStackReserve; 
        0x4c DWORD SizeOfStackCommit; 
        0x50 DWORD SizeOfHeapReserve; 
        0x54 DWORD SizeOfHeapCommit; 
        0x58 DWORD LoaderFlags; 
        0x5c DWORD NumberOfRvaAndSizes; 
        0x60 _IMAGE_DATA_DIRECTORY DataDirectory[16]; 
    };

Magic:说明文件类型:10B 32位下的PE文件 20B 64位下的PE文件
AddressOfEntryPoint:程序入口//真在地址要加上内存镜像基址
ImageBase:内存镜像基址/内存中所有数据开始的地址,DOS头开始
SizeOfImage:内存中整个PE文件的映射的尺寸(拉伸后的大小),可以比实际的值大,但必须是SectionAlignment的整数倍
6.jpg

参考书籍:《加密与解密四》

暂无评论

发表评论