如何根据幻数快速区分PE/DLL/DOS-MZ文件?

逆向工程 聚乙烯 dll 文件格式 dos-exe
2021-06-21 17:06:28

我知道 Microsoft PE/DLL/DOS-MZ 文件的规范指出 PE/DLL/DOS-MZ 文件的前两个字节是MZ(0x4d,0x5a ) orZM (0x5a,0x4d`)。

如此小的签名的问题在于,许多其他文件可能匹配相同的规范,并且仅基于前两个字节的测试很快就会得出结论。

所以,我的问题很简单,在测试前两个字节是MZ(或ZM)之后,还有什么其他更可靠的测试可以执行来检查文件是否为 PE/DLL/DOS-MZ?

2个回答

旧的 DOS EXE 标头只有 28 ( 0x1C) 个字节长,通常后面跟着 DOS 重定位表(如果存在)。IMAGE_DOS_HEADER struct所述NT PE头的是在64(0×40)大很多,因为它已被扩展为其它各种Windows可执行文件格式字节。

尝试按照推荐答案的建议e_lfanew在偏移 60 ( 0x3C)解释普通 DOS 可执行文件是不正确的,因为这会引入恰好位于该偏移处的任何数据,通常来自 DOS 重定位表,但它可能因有效的 DOS 可执行文件而异。使用一些旧的 DOS 可执行文件,这个位置的值可能不为零,因此任何试图使用它作为区分标记的逻辑可能会崩溃或工作不正常。

当试图区分普通的 DOS EXE 时,您不能可靠地查看过去的任何成员e_ovno(覆盖编号),IMAGE_DOS_HEADER struct因为它们是 DOS EXE 标头的 Windows 和 OS/2 扩展,并且不存在于普通的 DOS 可执行文件中。

至于区分 DOS 可执行文件和 PE 可执行文件,我成功地使用了以下逻辑:

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

  2. 通过查看e_lfanew确定您是否有一个普通的 DOS 可执行文件一个普通的 DOS 可执行文件将有一个超出文件范围的e_lfanew指向,一个零,或者如果偏移量恰好在范围内,则其偏移量处的签名将与下面的任何签名都不匹配。

  3. 尝试将 指向的“范围内”偏移的签名e_lfanew与以下 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)
    

那将e_lfanewMZ标题本身中。对于简单的(16位)MSDOS软件,这应该是0,和任何扩展格式它应该指向正确的具体的一个LEPENE标头的标识符(全部正是这两个字符)。在所有这些情况下,标头本身只是一个存根,e_cp(此可执行文件的总大小以页为单位)不应大于e_lfanew. (加上或减去那个 infernal e_cblp,即“文件最后一页上的字节”——我总是忘记它是哪个。)

参见Peering inside the PE,这篇文章尽管年代久远,但仍然非常有用。