PE文件笔记三 DOS部分
先转载一下怕以后找不到ヽ(✿゚▽゚)ノ
前面学习了PE结构的总体结构,接下来将具体学习PE的各个结构细节
这次学习的结构为DOS 部首
DOS部首
DOS部首结构
DOS部首结构 | 对应C中的结构体 | 说明 |
---|---|---|
DOS ‘MZ’ HEADER | _IMAGE_DOS_HEADER | DOS MZ头 结构体 |
DOS stub | 无 | DOS 存根 |
DOS MZ头
结构体截图
在winnt.h中找到_IMAGE_DOS_HEADER,得到以下截图(具体查找对应C结构体方法在PE文件笔记一 PE介绍中已经说明了,这里不再赘述)
结构体代码
复制代码 隐藏代码typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header |
结构体成员分析
_IMAGE_DOS_HEADER结构体的成员并不少,但在现在需要学习的只有两个
因为:
回顾
DOS部首,可以说是Windows的历史遗留问题了,因为Windows程序最早是在DOS系统(16位系统)上运行的
所以该部分主要是给DOS用的(向下兼容)
更新
目前在32位或64位 WINDOWS系统上还有效的只有两个成员了:
- 第一个成员:e_magic
- 最后一个成员:e_lfanew
成员详情
成员 | 数据宽度 | 注释 | 说明 | 值 |
---|---|---|---|---|
e_magic | WORD(2字节) | Magic number | PE文件判断标识 | 固定为4d 5a (ASCII=’MZ’) |
e_lfanew | LONG(4字节) | File address of new exe header | 存储PE头首地址 | 不定 |
验证其余成员无效性
前面说到在目前的系统中,只有两个成员是有效的,为验证这一点,将其余成员全部置为0试试
1.用WinHex或UltraEdit等十六进制编辑器打开一个程序
这里采用WinHex进行操作,并选中其余成员部分
2.将选中的部分,也就是其余成员部分全部修改为0
右键→编辑→填充选块 (快捷键Ctrl+L)
确定修改后:
3.保存修改的文件
文件→保存(快捷键Ctrl+S)
4.执行修改后的文件
可以看到程序仍然可以正常运行,验证了:其余成员在32位及以上的Windows系统中无效
Dos Stub
Dos Stub在32位及以上的Windows系统中其实也无效,但不妨研究一下他的作用
1.截取出Dos Stub部分的数据
选中部分为Dos Stub,其数据范围由_IMAGE_DOS_HEADER结构体中的最后一个成员e_lfanew决定
2.复制选中部分也就是Dos Stub部分的数据
3.将数据粘贴到记事本中
对应数据
复制代码 隐藏代码 |
对应数据反汇编
复制代码 隐藏代码PUSH CS |
通过16位的反汇编引擎即可得到对应的反汇编代码
这里我们主要关注DB段,也就是汇编中数据段部分有DB 54;DB 68;DB 69 ……
在WINHEX中找到其对应的数据部分,查看其对应的ASCII
数据部分为This program cannot be run in DOS
结合前面的两个INT 21 中断 不难猜测出该段数据对应的16位反汇编为输出数据部分的内容:This program cannot be run in DOS
自写代码解析DOS MZ头
了解了DOS部首的结构以后就可以自己写代码来读取DOS MZ头了
代码
复制代码 隐藏代码// PE.cpp : Defines the entry point for the console application. |
运行结果
可以看到能够正确地得到DOS MZ头对应的第一个成员的值:5A4D(对应ASCII为MZ)
总结
- DOS部首分为两部分:DOS ‘MZ’ HEADER 和 DOS stub
- DOS ‘MZ’ HEADER对应的结构体_IMAGE_DOS_HEADER中仅第一个成员和最后一个成员在32位及以上的WINDOWS系统上有效
- DOS Stub对应为一串反汇编代码,其功能和输出This program cannot be run in DOS相关
- DOS ‘MZ’ HEADER中无效的成员部分可用来填充shellcode来达到其它目的
附件
附上本笔记中分析的EverEdit文件:点我下载
转载自吾爱破解上的一位大佬