2024年5月2日发(作者:)
用简单C程序分析DOS下的EXE文件
DOS下的EXE文件格式比较简单,所以咱们先把Windows下的那个复杂的EXE文件放一边,挑个软
柿子捏捏(以下EXE如不特殊说明均指DOS下的EXE文件格式)。
其实网上关于EXE格式的说明很多,大都是哗啦列出大批格式说明,看得人是头晕脑胀的。等自己搞懂
了,总觉的其中个别说明不太精确导致自己误解浪费了不少时间。所以,咱们要自己动手去实践一下,边
动手边理解就容易多了。至于本次分析为什么用C,这个嘛,咱们随便分析一下C语言与汇编的联系,
尤其是子程序的调用,这跟什么什么标准有关。好,废话少说,切入正题!
1.软件准备
①既然跟DOS有关,得有个DOS系统吧。现在盛行虚拟机,安装简单并且系统崩溃的话跟自己电脑的
硬件没关联,安全方便。至于怎么安装,请参阅本人拙文:
VMware上安装MS-DOS 6.22之一:基本系统的安装
VMware上安装MS-DOS 6.22之二:光驱驱动及其他的安装
②另外还要安装上Turbo C。初学C的大概都用过这个东东吧。安装在DOS上吧。我用的是Turbo
C++ 3。
③还得有个能查看文件16进制的软件。例如UltraEdit。
2.生成EXE文件
我们要从最简单的分析起,所以C程序尽量简单,只包含一个子程序调用。如下
int sum(int x,int y)
{
return x+y;
}
main()
{
int x,y,s;
x=1;
y=2;
s=sum(x,y);
}
怎么样,够简单的吧。编译链接生成EXE文件。
3.小样,来吧,让我分析分析你
①用UltraEdit打开生成的EXE文件如下图(只截取了开头一部分)
下面着重说几个重要的偏移。
②上图的被红框圈的两个字母看见了没,这个就是EXE文件的标示,它占用了文件最开头的俩字节。可
能你纳闷了为什么用MZ呢?哈哈,自己上网查查吧。
③再往下看,在偏移02-03h的地方存放了000C(不要告诉我存放的是0C00),在偏移04-04h的地
方存放了0009(请不要替我纠“错”)。通过这两个数据可以计算出文件大小,在这里0009指出该文件
用了9个块(1个块是512B),000C指出最后一个块(第9个块)没有用完只用了000C个字节。明
白了吧。来,实际计算一下(9﹣1)×512B=4096,再加上12(000Ch)等于4108B。跟DOS里显
示的一样。
④偏移06-07h处为重定向项目的个数。什么叫重定向呢,简单的说就是:EXE文件必须要加载到内存
中才能执行,但是文件中数据的偏移地址跟内存中偏移是不一样的,重定向就是达到重新修改偏移的目
的。可以看出我们这个文件中重定向项的个数为1。在这里我们也应该看一下偏移18-19h处的数据,它
指出了第一个重定向项目在本文件中的偏移,在本文件中为003Eh。即,在本文件003Eh偏移处存放了
第一个重定向项目的内容,它的结构体声明为:
struct EXE_RELOC
{
unsigned short offset;
unsigned short segment;
};
⑤偏移08-09h处:该处数据指出了EXE头部大小,一般EXE头部后面紧跟着的就是程序数据了。本文
件中为0020h,注意它的单位是节,一个节为16个字节,也即程序数据开始于文件偏移200h处。
⑥偏移0A-0Bh处:该处数据指出了运行该程序所需的最小内存,如果小于这个内存,程序将不会被加
载执行。
⑦偏移0C-0Dh处:该处数据指出了运行该程序所需的最大内存,一般为FFFFh。
⑧偏移0E-0Fh处:堆栈段在装入模块中的偏移,本文件中为:00E5h
偏移10-11h处:SP初始值,本文件中为:0080h
即SS:SP=00E5:0080
⑨偏移14-15h处:IP初始值,本文件中为:0
偏移16-17h处:CS在装入模块中的偏移,本文件中为:0
我们看看实际加载到内存中是SS、SP和CS、IP是如何分配的
发布评论