PE文件笔记三 DOS部分
本帖最后由 lyl610abc 于 2021-4-3 11:51 编辑继续PE系列笔记的更新
PE其它笔记索引可前往:
(https://www.52pojie.cn/thread-1391994-1-1.html)
------
前面学习了PE结构的总体结构,接下来将具体学习PE的各个结构细节
这次学习的结构为DOS 部首
# DOS部首
## DOS部首结构
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210326211401967.png)
------
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210326235719068.png)
------
| DOS部首结构 | 对应C中的结构体 | 说明 |
| --------------- | ----------------- | --------------- |
| DOS 'MZ' HEADER | _IMAGE_DOS_HEADER | DOS MZ头 结构体 |
| DOS stub | 无 | DOS 存根 |
------
## DOS MZ头
### 结构体截图
在winnt.h中找到_IMAGE_DOS_HEADER,得到以下截图(具体查找对应C结构体方法在(https://www.52pojie.cn/forum.php?mod=viewthread&tid=1391994&page=1&extra=#37411342_pe%E5%9C%A8c%E4%B8%AD%E7%9A%84%E5%AE%9A%E4%B9%89)中已经说明了,这里不再赘述)
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210326212749211.png)
------
### 结构体代码
```c
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; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2; // Reserved words
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_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**进行操作,并选中其余成员部分
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210326223305500.png)
------
**2.将选中的部分,也就是其余成员部分全部修改为0**
右键→编辑→填充选块 (快捷键Ctrl+L)
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210326224239328.png)
------
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210326224313607.png)
------
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210326224403422.png)
------
确定修改后:
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210326224440179.png)
------
**3.保存修改的文件**
文件→保存(快捷键Ctrl+S)
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210326224522965.png)
------
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210326224557452.png)
------
**4.执行修改后的文件**
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210326220814513.png)
------
可以看到程序仍然可以正常运行,验证了:其余成员在32位及以上的Windows系统中**无效**
## Dos Stub
Dos Stub在32位及以上的Windows系统中其实也无效,但不妨研究一下他的作用
**1.截取出Dos Stub部分的数据**
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210326224705523.png)
选中部分为Dos Stub,其数据范围由_IMAGE_DOS_HEADER结构体中的最后一个成员e_lfanew决定
------
**2.复制选中部分也就是Dos Stub部分的数据**
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210326224751035.png)
------
**3.将数据粘贴到记事本中**
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210326225328310.png)
------
### 对应数据
```assembly
0E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000FD661975B9077726B9077726B90777260448E126BB077726B07FE226A2077726A755F326BE077726B07FE426A6077726B9077626E8057726B07FF4267D077726B07FF32651077726A755E326B8077726B907E026BB077726B07FE626B807772652696368B90777260000000000000000
```
------
### 对应数据反汇编
```assembly
PUSH CS
POP DS
MOV DX,000E
MOV AH,09
INT 21
MOV AX,4C01
INT 21
DB 54
DB 68
DB 69
DB 00
DB 33
DB 70
……
```
------
通过**16位的反汇编引擎**即可得到对应的反汇编代码
这里我们主要关注DB段,也就是汇编中数据段部分有DB 54;DB 68;DB 69 ……
在WINHEX中找到其对应的数据部分,查看其对应的ASCII
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210326231526001.png)
------
数据部分为This program cannot be run in DOS
结合前面的两个INT 21 中断 不难猜测出该段数据对应的16位反汇编为输出数据部分的内容:This program cannot be run in DOS
## 自写代码解析DOS MZ头
了解了DOS部首的结构以后就可以自己写代码来读取DOS MZ头了
### 代码
```c
// PE.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <malloc.h>
#include <windows.h>
int main(int argc, char* argv[])
{
//创建DOS对应的结构体指针
_IMAGE_DOS_HEADER* dos;
//读取文件,返回文件句柄
HANDLE hFile = CreateFileA("C:\\Documents and Settings\\Administrator\\桌面\\dbghelp.dll",GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,0);
//根据文件句柄创建映射
HANDLE hMap = CreateFileMappingA(hFile,NULL,PAGE_READONLY,0,0,0);
//映射内容
LPVOID pFile = MapViewOfFile(hMap,FILE_MAP_READ,0,0,0);
//类型转换,用结构体的方式来读取
dos=(_IMAGE_DOS_HEADER*)pFile;
//输出结构体的第一个成员,以十六进制输出
printf("%X\n",dos->e_magic);
return 0;
}
```
------
### 运行结果
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210326234752508.png)
可以看到能够正确地得到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文件:[点我下载](https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/EverEdit.zip?versionId=CAEQHhiBgID6g6vXxBciIDMxMjY5Y2Q0NGE5NTRkNmNiNTUwOGM0YjdmZTQxMTI3)
本帖最后由 lyl610abc 于 2021-3-30 16:40 编辑
布衣木人 发表于 2021-3-28 14:15
最好在64位机器上写,同时最好用下vs
代码是通用的,编译环境不同而已
同样的代码,在VS 2019win10 x64下也是可以运行的 aswcy815174418 发表于 2021-4-6 12:39
输出完5a4d后不得CloseHandle嘛
只是读取,读取完程序都停止运行了,这个也只是个demo,我也就懒得加了
出于程序结构的完整性应该是要CloseHandle的
除了CloseHandle还要UnmapViewOfFile lyl610abc 发表于 2021-3-28 14:25
代码是通用的,编译环境不同而已
同样的代码,在VS 2019win10 x64下也是可以运行的
pStrNtHeaders->OptionalHeader.Magic;这个值0x10b、0x20b等,就要区分了,IMAGE_NT_HEADERS、IMAGE_NT_HEADERS64里面的结构就不一样了。所以不如直接用你现在的vs2019 模板大佬 膜拜大佬。感谢分享 点名表扬,更新的非常nice 学习下看看 先收藏,感谢分享。 感谢分享 膜拜大佬。感谢分享 感谢分享{:1_893:}
学习{:1_921:}
感谢分享
学习