继续PE系列条记的更新
PE其它条记索引可前去:
PE文件条记一 PE介绍
前面学习了PE结构的总体结构,接下来将详细学习PE的各个结构细节
这次学习的结构为DOS 部首
DOS部首
DOS部首结构
DOS部首结构对应C中的结构体说明DOS 'MZ' HEADER_IMAGE_DOS_HEADERDOS MZ头 结构体DOS stub无DOS 存根DOS MZ头
结构体截图
在winnt.h中找到_IMAGE_DOS_HEADER,得到以下截图(详细查找对应C结构体方法在PE文件条记一 PE介绍中已经说明白,这里不再赘述)
结构体代码
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;结构体成员分析
_IMAGE_DOS_HEADER结构体的成员并不少,但在现在需要学习的只有两个
由于:
回顾
DOS部首,可以说是Windows的历史遗留问题 了,由于Windows步伐最早是在DOS系统(16位系统)上运行的
所以该部分主要是给DOS用的 (向下兼容)
更新
现在在32位或64位 WINDOWS系统上还有效的只有两个成员了:
第一个成员:e_magic
末了一个成员:e_lfanew
成员详情
成员数据宽度解释说明值e_magicWORD(2字节)Magic numberPE文件判断标识 固定为4d 5a (ASCII='MZ')e_lfanewLONG(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.将数据粘贴到记事本中
对应数据
0E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000FD661975B9077726B9077726B90777260448E126BB077726B07FE226A2077726A755F326BE077726B07FE426A6077726B9077626E8057726B07FF4267D077726B07FF32651077726A755E326B8077726B907E026BB077726B07FE626B807772652696368B90777260000000000000000对应数据反汇编
PUSH CSPOP DSMOV DX,000EMOV AH,09INT 21MOV AX,4C01INT 21DB 54DB 68DB 69DB 00DB 33DB 70……通过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.//#include "stdafx.h"#include #include 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;}运行结果
可以看到能够正确地得到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文件:点我下载
来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
楼主热帖