关于PE文件中SizeOfHeaders定义的困惑与求证
PE文件SizeOfHeaders的准确定义与计算
核心定义
根据微软官方规范,SizeOfHeaders表示从文件起始位置到第一个节的起始位置的字节数,且必须按PE可选头中的FileAlignment值向上对齐。
组成部分(未对齐时的总长度)
SizeOfHeaders的未对齐总长度包含以下所有部分:
- MS-DOS存根(包括完整的
IMAGE_DOS_HEADER) - 4字节PE签名
IMAGE_FILE_HEADER(固定20字节)IMAGE_OPTIONAL_HEADER(32位PE为224字节,64位PE为240字节)- 所有
IMAGE_SECTION_HEADER(每个40字节,数量由IMAGE_FILE_HEADER.NumberOfSections指定)
对不同说法的澄清
- 错误说法:“仅PE头和节表的大小”——遗漏了MS-DOS存根部分,不符合官方规范。
- 正确说法1:
e_lfanew + 4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER) + sizeof(IMAGE_SECTION_HEADER)*节数后按FileAlignment取整- 解释:
e_lfanew是IMAGE_DOS_HEADER的成员,代表PE签名在文件中的偏移,也就是MS-DOS存根的总长度,加上后续所有头部内容的长度,再对齐就是SizeOfHeaders。
- 解释:
- 正确说法2:MS-DOS存根、PE头(含签名)、节表的总长度按
FileAlignment取整- 解释:PE头本身包含签名、
IMAGE_FILE_HEADER和IMAGE_OPTIONAL_HEADER,和上一种说法本质完全一致。
- 解释:PE头本身包含签名、
你的NASM计算代码问题分析
你使用的代码:
dd (sections_start - dos_stub_start + (FileAlignment - 1)) // FileAlignment
这里存在两个潜在问题:
- 若
sections_start是第一个节的起始偏移,那么sections_start - dos_stub_start本身已经是对齐后的SizeOfHeaders值,再做取整运算会导致结果错误(比如原长度刚好对齐,加FileAlignment-1再整除会多算一个对齐单位)。 - 逻辑上存在循环依赖:节的起始偏移应该由SizeOfHeaders决定,而非反过来用节起始偏移计算SizeOfHeaders,正确的顺序是先计算头部总长度并对齐得到SizeOfHeaders,再以此作为第一个节的文件偏移。
正确的NASM计算方式
假设你已经定义了相关常量:
; 先计算未对齐的头部总长度 mov eax, [IMAGE_DOS_HEADER.e_lfanew] ; MS-DOS存根长度 add eax, 4 ; PE签名 add eax, sizeof IMAGE_FILE_HEADER ; 文件头 add eax, sizeof IMAGE_OPTIONAL_HEADER ; 可选头 add eax, sizeof IMAGE_SECTION_HEADER * NUM_SECTIONS ; 所有节表 ; 按FileAlignment向上取整 add eax, FileAlignment - 1 xor edx, edx div dword [FileAlignment] mul dword [FileAlignment] ; eax即为SizeOfHeaders ; 将结果写入IMAGE_OPTIONAL_HEADER.SizeOfHeaders mov [IMAGE_OPTIONAL_HEADER.SizeOfHeaders], eax
或者用静态计算的方式(如果所有值都是编译期常量):
%define UNALIGNED_HEADERS_LENGTH (e_lfanew_value + 4 + 20 + 224 + 40 * NUM_SECTIONS) %define ALIGNED_HEADERS_LENGTH ((UNALIGNED_HEADERS_LENGTH + FileAlignment - 1) // FileAlignment * FileAlignment) dd ALIGNED_HEADERS_LENGTH
内容的提问来源于stack exchange,提问作者J. Doe
相关产品推荐
相关产品推荐

