前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PE文件和COFF文件格式分析--MS-DOS 2.0兼容Exe文件段

PE文件和COFF文件格式分析--MS-DOS 2.0兼容Exe文件段

作者头像
方亮
发布2019-01-16 10:22:52
1.3K3
发布2019-01-16 10:22:52
举报
文章被收录于专栏:方亮方亮

        MS 2.0节是PE文件格式中第一个“节”。其大致结构如下:(转载请指明来源于breaksoftware的csdn博客

        在VC\PlatformSDK\Include\WinNT.h文件中有对MS-DOS 2.0兼容EXE文件头的完整定义

代码语言:javascript
复制
typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

        这个结构占用0x40个字节,其中我们将主要关注两个成员变量:e_magic和e_lfanew。

       以我xp电脑上notepad为例,我们使用UE打开C:\windows\notepad.exe

        可以发现IMAGE_DOS_HEADER结构中e_magic对应的数据位0x5A4D(MZ),e_lfanew对应的是0x000000E0。这个两个数据是这个结构体中最需要关心的两个成员变量。幻数(Magic Num)这个概念是用于区分一个格式文件的类型,就像一个人的姓,知道你姓啥之后,就可以明确你是不是我们族人。同样,解析这些文件的程序也会去尝试读取这样的幻数,以确认这个文件符合它要求的。在我所知道的一些格式中,他们的幻数往往是这个格式发明者的名称缩写(或者是格式后缀)。我们这个MS-Dos 2.0兼容EXE文件头中的幻数MZ也是纪念他的发明者,可以想到,这个名字应该不是盖茨,因为MZ和Bill Gates(BG)一点也没关系,也不是Paul Allen(PA),更不可能是销售出生的Steve Ballmer。它是Mark Zbikowski,中文翻译是马克·茨柏克沃斯基

        那么为什么PE格式文件会有个Dos文件头呢?Dos系统时代,有两种(我所知道的,我压根没经历过那个年代)可执行文件格式,一种是.exe为后缀的文件,其结构是MZ格式。另一种是以.com为后缀的文件,其结构是COM格式。从Wiki上对MZ格式的介绍可以看出来,MZ格式要比COM格式要新,MZ格式头中包含了重定向信息(本文第一个图中),且其支持可执行体大于64KiB。如今我们电脑上PE可执行文件的后缀也是.exe,为了让该后缀程序在Dos和Nt间有个过渡,我们需要让Dos系统能知道它不能“正确”执行该Exe文件。于是我们PE可执行文件一开始处便插入了一个MS-Dos 2.0兼容Exe文件头,Dos系统加载我们PE文件时,从一开始读取我们文件,发现是“DOS下可执行程序”,于是成功且顺利的执行我们的程序中DOS系统可执行部分,这部分DOS程序输出“该程序不能在DOS上”执行的提示。

        现在我们来看下MS-2.0节结构图和我们结构体的对应关系:

        MS-Dos 2.0兼容Exe文件头   对应于IMAGE_DOS_HEADER中e_magic到e_ovno

        未使用 对应于 e_res[4],虽说这段没使用,但是我还是觉得这段很有意思的。我在做注册表沙箱时,研究了下某公司的沙箱,可是它的沙箱不让regedit.exe进入沙箱运行,于是我就改了e_res[4]这段数据中部分,从而让修改后的regedit.exe在它的沙箱中运行。为什么呢?很容易想象,“MD5+签名”是安全公司一大“安全准绳”。我改了这个没啥用的数据段,不会影响程序运行,但是会使MD5不同,且签名被破坏。这段地址是(文件起始偏移0x1C)

        OEM标志 对应于 e_oemid

        OEM信息 对应于 e_oeminfo

        OEM信息和PE文件头偏移 之间存在一段空白,这段空白对应于 e_res2[10],这段数据和之前e_res[4]一样,改改也无妨。这段地址是(偏移0x28)

        PE文件头偏移 对应于 e_lfanew,其位于0x3C偏移处。

        MS-Dos 2.0占位程序和重定向表和未使用数据段如下图,因为我也没仔细研究过这个结构,所以也不能准确区分出哪块是占位程序,哪块是重定向表,哪块是未使用段。

       从上面的数据我们可以看到,如果我们程序运行在Dos下,会输出“This program connot be run in Dos mode"。

       那么NT系统加载我们的PE可执行程序呢?它不会去执行DOS占位程序,而会跳到PE头位置继续读取和执行。PE头位置就是e_lfanew字段的值,该值是PE头和文件头的之间的偏移量。如本例中就是0x000000E0。我们去该偏移去查看数据

       看到PE了么?这个PE是PE头的Magic Num。我会在之后介绍PE文件头及其相关知识。

       以上是非常常见的MS-DOS 2.0兼容Exe文件段,似乎有点枯燥。那我们现在思考一个问题,应该很有意思的。MS-DOS 2.0兼容Exe文件段是为了程序在DOS环境下运行时提示“不兼容”。但是目前DOS环境真的很少了,似乎我们真的没必要去纠结于我们的程序是否会在DOS下提示“不兼容”,即使在DOS不能运行,也没什么大不了的——反正功能也用不了。那么这么一大块空间,我们是不是可以放点别的?是的,我们可以。举个例子,我电脑上PPTV有个.ax文件叫(.ax文件就是DirectShow Filters的DLL文件)CoreAVC.ax。它就将它的导入表放在这段空间里!

       看到了?导入表是使用了Kernerl32.dll中的LoadLibraryA和GetProcessAddress两个函数。再仔细看,而除了e_magic和e_lfanew两个字段要保证OK外,其他字段和DOS代码空间都可以被利用!那么不禁有人要问,这样做有什么好处呢?首先,减少了PE文件大小(虽然只是那么一点点)。其次,它可以让一些非常强大的分析工具分析出错,比如我电脑上的PE Explorer,因为它足够“较真”,所以它识别不出来该文件的信息。至于原因,我会在之后介绍导入表的时候给出来。这儿再废话几句,研究完PE文件格式,我发现一个道理:标准是标准,即使标准很严谨,但是如果标准实现不完善,那么也会产生各种有趣的漏洞和利用。

       贴一下代码

代码语言:javascript
复制
#define DOSMAGIC     0x5A4D

BOOL CGetPEInfo::IsMzFile() {

    size_t unWordSize = sizeof(WORD);
    ULONG ulFileSize =(ULONG)( m_lpFileEnd - m_lpFileStart );
    if ( ulFileSize < unWordSize ) {
        return FALSE;
    }
    WORD wMagic = 0;

    SafeCopy( &wMagic, m_lpFileStart, unWordSize );
    
    return (DOSMAGIC == wMagic) ? TRUE : FALSE;
}

BOOL CGetPEInfo::GetDOSHeaderInfo() {

    if ( FALSE == IsMzFile() ) {
        return FALSE;
    }

    size_t unDosHeader = sizeof(IMAGE_DOS_HEADER);

    memset( &m_DosHeader, 0, unDosHeader );

    BOOL bSuc = SafeCopy( &m_DosHeader,m_lpFileStart, unDosHeader );

    if ( FALSE == bSuc ) {
        _ASSERT(FALSE);
    }
    else {
        m_dwInfoMask |= DOSHEADER;
    }

    return bSuc;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2012年07月03日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档