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

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

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE headerWORD   e_magic;                     // Magic numberWORD   e_cblp;                      // Bytes on last page of fileWORD   e_cp;                        // Pages in fileWORD   e_crlc;                      // RelocationsWORD   e_cparhdr;                   // Size of header in paragraphsWORD   e_minalloc;                  // Minimum extra paragraphs neededWORD   e_maxalloc;                  // Maximum extra paragraphs neededWORD   e_ss;                        // Initial (relative) SS valueWORD   e_sp;                        // Initial SP valueWORD   e_csum;                      // ChecksumWORD   e_ip;                        // Initial IP valueWORD   e_cs;                        // Initial (relative) CS valueWORD   e_lfarlc;                    // File address of relocation tableWORD   e_ovno;                      // Overlay numberWORD   e_res[4];                    // Reserved wordsWORD   e_oemid;                     // OEM identifier (for e_oeminfo)WORD   e_oeminfo;                   // OEM information; e_oemid specificWORD   e_res2[10];                  // Reserved wordsLONG   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文件格式,我发现一个道理:标准是标准,即使标准很严谨,但是如果标准实现不完善,那么也会产生各种有趣的漏洞和利用。

贴一下代码

#define DOSMAGIC     0x5A4DBOOL 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;
}

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

  1. PE文件和COFF文件格式分析——导出表的应用——一种摘掉Inline钩子(Unhook)的方法

    在日常应用中,某些程序往往会被第三方程序下钩子(hook).如果被下钩子的进程是我们的进程,并且第三方钩子严重影响了我们的逻辑和流程,我们就需要把这些钩子摘掉(Unhook).本件讲述一种在32位系统 ...

  2. PE文件和COFF文件格式分析——导出表的应用——通过导出表隐性加载DLL

    通过导出表隐性加载DLL?导出表?加载DLL?还隐性?是的.如果觉得不可思议,可以先看<PE文件和COFF文件格式分析--导出表>中关于"导出地址表"的详细介绍.(转载 ...

  3. PE文件和COFF文件格式分析——导出表的应用——一种插件模型

    可能在很多人想想中,只有DLL才有导出表,而Exe不应该有导出表.而在<PE文件和COFF文件格式分析--导出表>中,我却避开了这个话题.我就是想在本文中讨论下载Exe中存在导出表的场景. ...

  4. PE文件和COFF文件格式分析——导出表

    在之前的<PE可选文件头>相关博文中我们介绍了可选文件头中很多重要的属性,而其中一个非常重要的属性是(转载请指明来源于breaksoftware的CSDN博客) IMAGE_DATA_DI ...

  5. PE文件和COFF文件格式分析——RVA和RA相互计算

    之前几节一直是理论性质的东西非常多.本文将会讲到利用之前的知识得出一个一个非常有用的一个应用.(转载请指明来源于breaksoftware的csdn博客) 首先我们说下磁盘上A.exe文件和正在内存中 ...

  6. PE文件和COFF文件格式分析——节信息

    在<PE文件和COFF文件格式分析--签名.COFF文件头和可选文件头3>中,我们看到一些区块的信息都有偏移指向.而我们本文讨论的节信息是没有任何偏移指向的,所以它是紧跟在可选文件头后面的 ...

  7. PE文件和COFF文件格式分析--概述

    刚工作的时候,我听说某某大牛在做病毒分析时,只是用notepad打开病毒文件,就能大致猜到病毒的工作原理.当时我是佩服的很啊,同时我也在心中埋下了一个种子:我也得有这天.随着后来的工作进行,一些任务的 ...

  8. PE文件和COFF文件格式分析——签名、COFF文件头和可选文件头1

    本文将讨论PE文件中非常重要的一部分信息.(转载请指明来源于breakSoftware的CSDN博客) 首先说一下VC中对应的数据结构."签名.COFF文件头和可选文件头"这三部分 ...

  9. PE文件和COFF文件格式分析——签名、COFF文件头和可选文件头3

    <PE2>中介绍了一些可选文件头中重要的属性,为了全面起见,本文将会讲解那些不是那么重要的属性.虽然不重要,但是还是可以发现很多好玩的情况.首先看一下32位的可选文件头详细定义.(转载请指 ...

最新文章

  1. python pandas DataFrame 转置
  2. [WebGL入门]十二,模型数据和顶点属性
  3. Javascript:前端利器 之 JSDuck
  4. 微信开发博客——柳峰
  5. HTML如何实现斜体字
  6. HBase之Region上Spilt流程分析
  7. windows oracle .msb not found,oracle安装, Message file sp1lang.msb not found
  8. 微信公众号的开发 Senparc.Weixin.dll使用
  9. mysql 所有外键_mysql中的外键
  10. Solidity教程:初学Solidity
  11. 论文阅读:Instance Weighting in Dialogue Systems
  12. PHP fwrite和file_put_contents 性能对比测试
  13. MacBook Pro设置外接显示器竖屏显示,2k 字体小
  14. live2d_碧蓝航线:老婆们在外服都长啥样?她惊艳四座,Live2D独此一家
  15. PayPal收款后的注意事项(PAYPAL用户必看)
  16. 蓝牙 - 苹果iOS所支持的profile
  17. 虚拟机设置静态ip(固定ip地址)
  18. Java基本数据类型默认值和取值范围详解
  19. 自动驾驶感知——激光雷达基本概念|激光雷达点云|激光雷达的标定
  20. 图像处理(八)——图像重建

热门文章

  1. Ubuntu解决开机屏幕默认亮度偏低问题
  2. Java学习路线图,如何学习Java事半功倍?
  3. C语言中的指针和内存泄漏
  4. A and B and Lecture Rooms CodeForces - 519E LCA+dfs序
  5. Keywords Search AC自动机QAQ
  6. 实验三 Gmapping建图
  7. 在CentOS 6.6 64bit上升级GCC到4.8.2版本
  8. 通过python的ConfigParse模块读写ini配置文件
  9. 全流程游戏模型制作学习教程
  10. linux系统目录树/内核源码目录树