转载:DOS下exe头文件解析
原文地址:http://www.asmedu.net/bbs/pasteinfo.jsp?part=1&level=free&kind=1020&qkSg=2&qID=17819
/****************************************************************************************************************************
DOS下EXE文件头分析
Author:Thinkred
Date:2008/05/29
****************************************************************************************************************************/
最近在学习8086汇编的时候,研究了DOS下exe文件的文件头。具体的分析结果如下:
标准的EXE文件头结构如下:
EXEHEADER STRUC
exSignature dw 5A4Dh ; exe的文件标识 ---------------------magic number
exExraBytes dw ? ; exe文件最后一个扇区的的字节数-----bytes on last page of file
exPages dw ? ; exe的扇区总数----pages in file
exRelocItems dw ? ; 重定位表的表项个数---relocations
exHeaderSize dw ? ; 文件头大小,以字节为单位--size of header in paragraphs
exMinAlloc dw ? ; 运行程序时,所需的最小内存分配空间--min extra paragraphs needed
exMaxAlloc dw ? ; 运行程序时,所需的最大内存分配空间--max extra paragraphs needed
exInitSS dw ? ; 程序被载入时,堆栈段SS的偏移地址--initail ss value
exInitSP dw ? ; 程序被载入时,SP的初值--initial (relative) sp value
exChechSum dw ? ; 补码校验值---checknum
exInitIP dw ? ; 程序被载入时,IP的初值--intial ip value
exInitCS dw ? ; 程序被载入时,代码段CS的偏移地址-initial cs value
exRelocTable dw ? ; 重定位表起点在头部信息块中的偏移位置--file address of relocation table
exOverlay dw ? ; 覆盖号 --overlay num
EXEHEADER ENDS
这里以masm5文件夹下的cref.exe来具体分析,这里我们需要用到UltraEdit和debug两个工具。用UltraEdit打开cref.exe前面30H的数据如下:
00000000h:4D 5A D6 01 1F 00 03 00 20 00 CB 00 FF FF 08 04
00000010H:00 08 88 90 86 11 00 00 1E 00 00 00 01 00 D2 01
00000020H:2F 03 9D 11 00 00 11 15 00 00 00 00 00 00 00 00
然后用debug载入cref.exe时,各个寄存器数据如下:
C:\MASM5>debug cref.exe
-r
AX=0000 BX=0000 CX=3BD6 DX=0000 SP=0800 BP=0000 SI=0000 DI=0000
DS=153C ES=153C SS=1954 CS=154C IP=1186 NV UP EI PL NZ NA PO NC
154C:1186 B430 MOV AH,30
1、偏移00-01H的数据是:4D 5A ,这两个字节是exe的文件标识,转换为ASCII码就是MZ,代表DOS的主要开发者Mark Zbikowski
2、偏移02-03H的数据是:D6 01, 表示cref.exe最后一个扇区的字节数,可以用"文件大小 mod 512"来计算。cref.exe的文件大小是15830字节,15830 mod 512 = 470, 转换成16进制就是01D6,根据高高低低的原则存放
3、偏移04-05H的数据是:1F 00, 表示cref.exe一共有31个扇区。一个扇区大小默认是512字节,cref.exe的文件大小是15830字节,15830 整除 512 = 30,剩下的470个字节占据一个扇区,所以一共是31个扇区,转换成16进制就是00 1F
4、偏移06-07H的数据是:03 00, 表示cref.exe的重定位表有3个表项。每次将exe载入内存时,载入地址都不是固定的,因此需要对exe进行重定位操作。重定位表每一个表项为4个字节。根据偏移06-07H重定位表的表项个数和偏移18-19H重定位表在文件头的偏移,我们可以知cref.exe有3个表项,起始位置是偏移1E,内容分别是:D2 01 2F 03 9D 11 00 00 11 15 00 00
5、偏移08-09H的数据是:20 00, 表示cref.exe的文件头有20H个字节
6、偏移0A-0BH的数据是:CB 00, 表示cref.exe运行时所需的最小分配内存是00CBH字节
7、偏移0C-0DH的数据是:FF FF, 表示cref.exe运行时所需的最大分配内存是FFFFH字节。一般情况下,除非被LINK命令行开关覆盖,连接程序将它设置为FFFFH
8、偏移0E-OFH的数据是:08 04,表示cref.exe被载入后SS的相对偏移地址是:0408H 。这里的偏移是相对于DS后256个字节处的偏移。我们知道exe载入分配内存后,在该内存的头256字节建立一个PSP。debug中,SS=1954,DS=153C,所以SS - DS - 10h = 1954h - 153ch - 10h = 0408h
9、偏移10-11H的数据是:00 08,表示cref.exe被载入后SP的初值是0800H。在debug中,我们可以看到SP=0800
10、偏移12-13H的数据是:88 90,表示cref.exe的补码校验值是:9088H
11、偏移14-15H的数据是:86 11,表示cref.exe被载入后IP的初值是:1186H。在debug中,我们可以看到IP=1186
12、偏移16-17H的数据是:00 00,表示cref.exe被载入后CS的相对偏移地址是:0000H。这里的偏移是相对于DS后256个字节处的偏移。我们知道exe载入分配内存后,在该内存的头256字节建立一个PSP。debug时,CS=154C,DS=153C,所以CS - DS - 10h = 154ch - 153ch - 10h =
0000h
13、偏移18-19H的数据是:1E 00,表示cref.exe的重定位项表在文件头的的偏移位置是1EH,内容分别是:D2 01 2F 03 9D 11 00 00 11 15 00 00
14、偏移1A-1BH的数据是: 00 00,这是一个覆盖号。对于一个程序,这个值为零
15、偏移1C-1DH的数据是: 01 00,对于所有DOS下所有的exe文件,这个值都是0001H,但具体含义并不清楚
16、偏移1E-29H的数据是:D2 01 2F 03 9D 11 00 00 11 15 00 00,放的是cref.exe的重定位项表的内容
至此,文件头的所有内容就分析完了,剩下数据从偏移2AH-1FFH都用00来填充,从偏移200H开始,就是放的是程序执行时的机器码。最后来分析下,DOS将exe载入的过程。在将exe文件载入后,DOS创建了新的PSP,因而,除EXE文件头外,将整个EXE文件可执行的机器码装入内存中位于PSP之上的位置,我们称此位置为装载地址。随后,把DS和ES寄存器设置成指向此PSP,通过EXE文件头的值来设置CS:IP和SS:SP寄存器。 最后,用EXE头中的重定位表修改内存映象中的段引用。