菜鸟的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;
{:victory:}对PE一窍不通的路过 基本不够,越看越晕。 学习一下,感谢分享了 PE头好难。。有点看不懂 谢谢分享。下载收藏 不错的教程,支持 PYG有你更精彩! 必须支持一下 写的不错啊,辛苦辛苦
页:
[1]
2