pfh = (PIMAGE_FILE_HEADER)PEFHDROFFSET(lpFile); 在这个例子中,lpFile表示一个指向可执行文件内存映像基地址的指针,这就显出了内存映射文件的好处:不需要执行文件的I/O,只需使用指针pfh就能存取文件中的信息。PE文件头结构被定义为: WINNT.H typedef struct _IMAGE_FILE_HEADER { USHORT Machine; USHORT NumberOfSections; ULONG TimeDateStamp; ULONG PointerToSymbolTable; ULONG NumberOfSymbols; USHORT SizeOfOptionalHeader; USHORT Characteristics; } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; #define IMAGE_SIZEOF_FILE_HEADER 20 请注意这个文件头部的大小已经定义在这个包含文件之中了,这样一来,想要得到这个结构的大小就很方便了。但是我觉得对结构本身使用sizeof运算符(译注:原文为“function”)更简单一些,因为这样的话我就不必记住这个常量的名字IMAGE_SIZEOF_FILE_HEADER,而只需要记住结构IMAGE_FILE_HEADER的名字就可以了。另一方面,记住所有结构的名字已经够有挑战性的了,尤其在是这些结构只有WINNT.H中才有的情况下。 PE文件中的信息基本上是一些高级信息,这些信息是被操作系统或者应用程序用来决定如何处理这个文件的。第一个域是用来表示这个可执行文件被构建的目标机器种类,例如DEC(R) Alpha、MIPS R4000、Intel(R) x86或一些其它处理器。系统使用这一信息来在读取这个文件的其它数据之前决定如何处理它。 Characteristics域表示了文件的一些特征。比如对于一个可执行文件而言,分离调试文件是如何操作的。调试器通常使用的方法是将调试信息从PE文件中分离,并保存到一个调试文件(.DBG)中。要这么做的话,调试器需要了解是否要在一个单独的文件中寻找调试信息,以及这个文件是否已经将调试信息分离了。我们可以通过深入可执行文件并寻找调试信息的方法来完成这一工作。要使调试器不在文件中查找的话,就需要用到IMAGE_FILE_DEBUG_STRIPPED这个特征,它表示文件的调试信息是否已经被分离了。这样一来,调试器可以通过快速查看PE文件的头部的方法来决定文件中是否存在着调试信息。
WINNT.H定义了若干其它表示文件头信息的标记,就和以上的例子差不多。我把研究这些标记的事情留给读者作为练习,由你们来看看它们是不是很有趣,这些标记位于WINNT.H中的IMAGE_FILE_HEADER结构之后。 PE文件头结构中另一个有用的入口是NumberOfSections域,它表示如果你要方便地提取文件信息的话,就需要了解多少个段——更明确一点来说,有多少个段头部和多少个段实体。每一个段头部和段实体都在文件中连续地排列着,所以要决定段头部和段实体在哪里结束的话,段的数目是必需的。以下的函数从PE文件头中提取了段的数目: PEFILE.C int WINAPI NumOfSections(LPVOID lpFile) { /* 文件头部中所表示出的段数目 */ return (int)((PIMAGE_FILE_HEADER) PEFHDROFFSET (lpFile))->NumberOfSections); } 如你所见,PEFHDROFFSET以及其它宏用起来非常方便。(未完待续)
|