PE文件格式学习:可选头的大小SizeOfOptionalHeader

在PE头部,在IMAGE_NT_HEADERS结构中的FileHeader成员中指定了后面的OptionalHeader成员的大小!
IMAGE_NT_HEADERS的结构定义如下:


typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

FileHeader成员是IMAGE_FILE_HEADER结构的一个数据,定义如下:


typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;
    WORD    NumberOfSections;
    DWORD   TimeDateStamp;
    DWORD   PointerToSymbolTable;
    DWORD   NumberOfSymbols;
    WORD    SizeOfOptionalHeader;
    WORD    Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

其中的SizeOfOptionalHeader就是指定了后面的IMAGE_OPTIONAL_HEADER32 OptionalHeader;的大小!
就这个大小而言,其常值都是0xE0,但是总有例外。由于这个值决定了后面的区块表的定位,就微软本身而言,也没有用0xE0这个固定值来定位,我们可以通过一个获取首个区块表位置的一个宏来看出:


#define IMAGE_FIRST_SECTION64( ntheader ) ((PIMAGE_SECTION_HEADER)        \
    ((ULONG_PTR)ntheader +                                                  \
     FIELD_OFFSET( IMAGE_NT_HEADERS64, OptionalHeader ) +                 \
     ((PIMAGE_NT_HEADERS64)(ntheader))->FileHeader.SizeOfOptionalHeader   \
    ))

那么这个值是不是任意设定的呢?
当SizeOfOptionalHeader大于或者等于0xE0时,程序叫是能正常运行起来!看雪的《软件加密技术内幕》的第2章提供了一个示例,将SizeOfOptionalHeader这个值设为0xD0,书本上说这个程序能在Windows9x/2000下很好的运行!
不过可惜,在我的WinXP Sp3上完全不能运行!如图:
[img][attach]230[/attach][/img]

难道是PE格式进行了修正?这个测试程序完全可以用其他的PE文件格式分析结构,但不能运行。是不是SizeOfOptionalHeader这个值必须是大于或者等于0xE0的值??
查看了一下“Microsoft Portable Executable and Common Object File Format Specification-Revision 8.1”,只找到了下面一些相关的说明:
“For image files, this header is required. ”
对镜像文件,这个头(即OptionalHeader)是必须的。
“Note that the size of the optional header is not fixed. The SizeOfOptionalHeader field in the COFF header must be used to validate that a probe into the file for a particular data directory does not go beyond SizeOfOptionalHeader. ”
注意:可选头的大小是不固定的。在COFF头的 SizeOfOptionalHeader 域必须被用于验证,尤其是研究一个没有超出SizeOfOptionalHeader大小的特殊的数据目录。

再次查找了一些资料,在Matt Pietrek的“An In-Depth Look into the Win32 Portable Executable File Format”一文里
(链接见:[url=http://msdn.microsoft.com/en-us/magazine/cc301805.aspx]http://msdn.microsoft.com/en-us/magazine/cc301805.aspx[/url],翻译成中文是:深入剖析 Win32 可移植可执行文件格式 ):
在表述IMAGE_NT_HEADERS 文件头结构的表格里写了这么一句:

IMAGE_FILE_HEADER 结构后面的可选数据的大小。在PE 文件中,这个可选数据就是 IMAGE_OPTIONAL_HEADER。这个大小在32位和64位文件中是不同的。对于32位 PE文件来说,它通常是 224;对于64位PE32+文件来说,它通常是 240。[color=#FF0000]但是,它们只是最小值,可能有更大的值。[/color]

这里引用的是SmartTech的译文,我们可以对比一下原文:

The size of the optional data that follows the IMAGE_FILE_HEADER. In PE files, this data is the IMAGE_OPTIONAL_HEADER. This size is different depending on whether it’s a 32 or 64-bit file. For 32-bit PE files, this field is usually 224. For 64-bit PE32+ files, it’s usually 240. [color=#FF0000]However, these sizes are just minimum values, and larger values could appear.[/color]

留意红色的部分,这表明了 SizeOfOptionalHeader的最小取值是0xE0! 那么《软件加密技术内幕》一书的测试程序设SizeOfOptionHeader为0xD0可以在Win9X/2000上跑起来??或者是那里的加载程序的检测的不严格??如果如此,这样也可以解释为什么在我的XP SP3上跑起来了,呵呵!

附件为《软件加密技术内幕》一书提供的测试程序:
[file][attach]231[/attach][/file]

发表评论