Shark_鹏 发表于 2015-3-24 16:02

菜鸟的PE结构学习之路(三)初步解析PE头

      菜鸟在此,大牛飞过~~~~~~~
      以上仅为个人的一点小小的心得,有什么不对的地方还请各位指出。      这次我继续来解析PE头,结构非常的多,不过作用基本上可以从名字上面去看出来,因此实际上没有想象中的困难。
         那么,下面正式开始:
----------------------------------请叫我分割线-------------------------------------分割线-----------------------------------
       鉴于PE头的成员比较多,所以我就不全部介绍呵,就挑重要的部分来讲吧(绝对不是因为懒~~~)。       惯例先讲一点小知识,这次来讲标志位。       我想定义一个区段,并给区段赋予几个属性,因此我定义了一个结构structSectionCharacteristics {      bool HasCode;                        //含可执行代码      bool HasData;                        //含有数据      bool Read;                              //可读      bool Write;                              //可写};       很简单的结构呵。接着,我发现一个问题了,就是空间非常的浪费。假如这4个数据全部为真的时候,内存中是这样的: 0x01, 0x01, 0x01, 0x01。转换为二进制位就是:00000001, 00000001, 00000001, 00000001。看啊,每个字节,就只有一个位是被用到的。于是我把这几个属性压缩到一个字节中: 00001111,完全可以达到想要的效果,同时又节省了空间,这想法挺棒的。       咦,等等,这又遇到了问题。问题就是这些数据不容易提取啊。这也是可以解决的。比如说,我想提取第3位数据,我就这样 data & 00000100,如果结果不为0的话,那么第3位就是1了。想修改也容易: 写0:data = data & ~00000100,写1: data = data |00000100;
      来,继续讲解PE吧。先来看一下IMAGE_FILE_HEADER的数据:
      首先头4个字节为PE标志,”PE\0\0”      先给出IMAGE_FILE_HEADER的定义typedef struct _IMAGE_FILE_HEADER {    WORD    Machine;                     //运行平台    WORD    NumberOfSections;            //PE中节的数量    DWORD   TimeDateStamp;                                 //文件创建日期和时间    DWORD   PointerToSymbolTable;                   //指向符号表(用于调试)    DWORD   NumberOfSymbols;                           //符号表中的符号数量(用于调试)    WORD    SizeOfOptionalHeader;                   //扩展头结构的长度    WORD    Characteristics;                           //文件属性} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;      这样就基础知识就差不多了,下面来逐个解析。
Offset      01234567   89ABCDEF
                                           |PE - Start|Signature       | Machine| NumberOfSections000000C0   00 00 00 00 00 00 00 00 |50 45 00 00|4C 01    | 04 00                                             |PE - Start|幻数”PE\0\0”| 运行平台 | 节数                TimeDataStamp| P~S~Table   | N~O~Symbols | S~O~H | Characteristics000000D0 81 7E 73 4D | 00 00 00 00 | 00 00 00 00   | E0 00    | 0F 01                          时间戳     | 指向符号表| 符号数量         | 扩展头| 文件属性       解析一下较为重要的部分:Signature: 幻数 “PE\0\0”,是PE头的开始标志。NumberOfSections: 节的数目,就是在PEID中看到的区段的数目了TimeDataStamp: 时间戳,是自1970.1.1 到 文件建立时间经过的秒数SizeOfOptionalHeader: 扩展头长度,标志下一个头(IMAGE_OPTIONAL_HEADER)的大小。Characteristics: 描述PE文件的属性,可以由多个标志位进行组合,注意的是,这字段并不是描述文件的隐藏,只读之类的属性的。。。
      接着是下一个头,IMAGE_OPTIONAL_HEADER。这里我就直接借用WindowsPE权威指南里面的图了,里面说明非常的详细。比我做的要好多了。定义比较长,估计给出了也没有人会看,具体可以参考我的程序代码。来,直接上截图:

       可以看到,这个扩展头给出了程序启动的基本的信息,有PE类型、代码段大小,数据段大小、建议装入基址、程序入口RVA。在最后还有一个叫数据目录的信息,是非常重要的,这里我没有截图出来,将放在下一次讲解。
      那么这次就到此为止了,代码我会给出,就当做是国庆节给大家的礼物了,虽然可能有点乱就是了。
      最后补一下IMAGE_OPTIONAL_HEADER的定义:
typedef struct _IMAGE_OPTIONAL_HEADER {
    //
    // Standard fields.
    //

    WORD    Magic;         //幻数107h = ROM Image,10Bh = exe Image
    BYTE    MajorLinkerVersion;         //链接器版本号
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;         //所有含代码的节的总大小
    DWORD   SizeOfInitializedData;         //所有含已初始化数据的节的总大小
    DWORD   SizeOfUninitializedData;      //所有含未初始化数据的节的大小
    DWORD   AddressOfEntryPoint;         //程序执行入口RVA
    DWORD   BaseOfCode;         //代码的节的起始RVA
    DWORD   BaseOfData;         //数据的节的起始RVA

    //
    // NT additional fields.
    //

    DWORD   ImageBase;         //程序的建议装载地址
    DWORD   SectionAlignment;         //内存中的节的对齐粒度
    DWORD   FileAlignment;         //文件中的节的对齐粒度
    WORD    MajorOperatingSystemVersion;//操作系统版本号
    WORD    MinorOperatingSystemVersion;
    WORD    MajorImageVersion;         //该PE的版本号
    WORD    MinorImageVersion;
    WORD    MajorSubsystemVersion;         //所需子系统的版本号
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;         //未用
    DWORD   SizeOfImage;         //内存中的整个PE映像尺寸
    DWORD   SizeOfHeaders;         //所有头 + 节表的大小
    DWORD   CheckSum;         //校验和
    WORD    Subsystem;         //文件的子系统
    WORD    DllCharacteristics;         //DLL文件特性
    DWORD   SizeOfStackReserve;         //初始化时的栈大小
    DWORD   SizeOfStackCommit;         //初始化时实际提交的栈大小
    DWORD   SizeOfHeapReserve;         //初始化时保留的堆大小
    DWORD   SizeOfHeapCommit;         //初始化时实际提交的堆大小
    DWORD   LoaderFlags;         //与调试有关
    DWORD   NumberOfRvaAndSizes;         //下面的数据目录结构的项目数量
    IMAGE_DATA_DIRECTORY DataDirectory;      //数据目录
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;



Shark恒 发表于 2015-3-24 16:03

转的一手好帖!辛苦了!

逍遥绝尘 发表于 2015-3-24 17:26


转的一手好帖!辛苦了!

小筱宁 发表于 2015-3-24 18:08

新手学习学习

Scar-疤痕 发表于 2015-3-24 22:29

小鹏,转的一手好帖啊!

hackysh 发表于 2022-2-9 15:58


[快捷回复]-感谢楼主热心分享!

bnjzzheng 发表于 2022-2-24 14:06

[快捷回复]-学破解防逆向,知进攻懂防守!

别管我了行 发表于 2022-3-10 04:17

凌夏随缘 发表于 2022-6-5 15:13

谢谢分享

曾经沧海 发表于 2022-10-12 07:57

感谢分享,有备无患
页: [1] 2
查看完整版本: 菜鸟的PE结构学习之路(三)初步解析PE头