F8LEFT 发表于 2014-9-28 16:37:39

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

本帖最后由 F8LEFT 于 2014-10-7 13:06 编辑

      菜鸟在此,大牛飞过~~~~~~~
      以上仅为个人的一点小小的心得,有什么不对的地方还请各位指出。      这次我继续来解析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;



vipcrack 发表于 2014-9-29 08:49:01

{:victory:}对PE一窍不通的路过

4238500 发表于 2014-11-4 13:36:22

基本不够,越看越晕。

hu251405204 发表于 2015-1-22 09:04:50

学习一下,感谢分享了

shiju007 发表于 2015-1-25 10:21:27

PE头好难。。有点看不懂

as399396225 发表于 2015-1-31 08:33:22

谢谢分享。下载收藏

hanyue 发表于 2015-2-1 22:16:05

不错的教程,支持

a1571450748 发表于 2015-2-7 20:08:26

PYG有你更精彩!

taro 发表于 2015-2-25 15:29:51

必须支持一下

sj123 发表于 2015-3-4 00:32:40

写的不错啊,辛苦辛苦
页: [1] 2
查看完整版本: 菜鸟的PE结构学习之路(三) 初步解析PE头