如何区分16位MZ和32位MZ

How to differentiate 16 bit MZ and 32 bit MZ

我需要区分 32 位 PE 和 16 位 DOS MZ。 正确的做法是什么? 我可以使用启发式方法,比如寻找 PE header,但我觉得它不一定是确定性的

所有 DOS 风格的 executable 都有一个 'MZ' 作为前两个字节。
要识别 MSDOS executable 与众多其他变体,最好的办法似乎是读取文件中偏移量 0x0018 处重定位 table 的位置,如果它大于 0x0040(进入文件)它不仅仅是普通的 DOS。

为了明确将 executable 标识为 'PE' executable,文件中的偏移量 0x003C 处有一个指针。这是文件中的偏移量,将包含字节 'PE' 和两个空值。其他 MSDOS 'MZ' 变体将使用相同的位置来放置其他代码,例如:'NE'、'W3'、'LE' 等

'PE' 风格的 executable 也有多种形式,我希望您至少会对 32 位与 64 位感兴趣。

可能对这类事情的最终权威是 Unix 'file' 命令,它旨在通过调查其内容可靠地识别任何文件类型。 MSDOS 部分已列出 here。 Microsoft 在这方面不是可靠的权威,因为他们忽略了非 Microsoft 信息。

一个普通的 DOS EXE header 只有 28 (0x1C) 字节长,如果存在,通常后面跟着 DOS 重定位 table。 NT PE header 的 IMAGE_DOS_HEADER struct 更大,为 64 (0x40) 字节,因为它已扩展为各种其他 Windows executable 格式.这种 header 大小差异是@user3710044 的答案不仅最快而且可靠的原因:如果重定位 table [e_lfarlc] < 0x40).

只要你意识到 e_lfanew 成员(一个可能的 "extended" headers 的偏移量)在普通的 DOS executable,也可以用下面的逻辑来区分各种MZ-style格式:

  1. 如果文件开头不是"MZ"或"ZM",则不是DOS或Windowsexecutable映像.否则,您可能拥有以下类型的 executable 格式之一:纯 DOS、NE(Windows 16 位)、LE(16 位 VXD)、PE32 或 PE32+ (PE64)。

  2. 通过查看 e_lfanew 值来确定您是否有普通的 DOS executable。一个普通的 DOS executable 将有一个 out-of-range e_lfanew 指向文件限制之外,一个零,或者如果偏移量恰好在范围内,其偏移量处的签名将获胜'匹配以下任何签名。

  3. 尝试将 e_lfanew 指向的 "in-range" 偏移量的签名与以下 WORD 或 DWORD 值相匹配:

    "PE" followed by two zero bytes if the image is a PE32 or PE32+ (PE64) and is further determined by the "magic" in the NT Optional Header
    "NE" indicates the image is a 16-bit Windows executable
    "LE" indicates the image is a 16-bit Virtual Device Driver (VXD)
    

更多晦涩的签名(引用自Ralph Brown's INT 21/AH=4Bh):

LX     variant of LE used in OS/2 2.x
W3     Windows WIN386.EXE file; a collection of LE files
W4     Windows95 VMM32.VXD file
DL     HP 100LX/200LX system manager compliant executable (.EXM)
MP     old PharLap .EXP
P2     PharLap 286 .EXP
P3     PharLap 386 .EXP