Exe文件裝載過程
一、程序段前綴 PSP. 1
二、 程序加載及實現... 4
三、重定位過程... 4
四、在DOS下,重定位指的是重新定位在你的程序中所引用的段值。... 4
五、exe文件結構... 5
一、程序段前綴 PSP
PSP ( Program segment prefix )
稱為程序段前綴,是 DOS 在加載外部命令或應用程序 ( .EXE 或 .COM 文件 ) 時,在加載的程序段前面設置的一個固定長度的信息區
( 共 100H 字節 ), PSP 包括以下四個組成部分:
l 供進程調用的 DOS 入口 PSP+0 , +2 , +5, +50H 和 +2CH 字段
l 供進程使用的傳遞參數 PSP+5CH, +6CH 和 +80H 字段
l 為 DOS 保存的中斷向量 PSP+0AH, +0EH , 和 +12H 字段
l 由 DOS 專用的保留區域 PSP+16H ~ 2BH 和 2EH ~ 37H 字段
PSP 的某些關鍵字段涉及到系統內部管理,所以使用者不得更改
偏移
|
字節數
|
說 明
|
0000
|
02
|
中斷20H
|
0002
|
02
|
以節計算的內存大?。ɡ眠@個可看出是否感染引導型病毒)
|
0004
|
01
|
保留
|
0005
|
05
|
至DOS的長調用
|
000A
|
02
|
INT 22H 入口 IP
|
000C
|
02
|
INT 22H 入口 CS
|
000E
|
02
|
INT 23H 入口 IP
|
0010
|
02
|
INT 23H 入口 CS
|
0012
|
02
|
INT 24H 入口 IP
|
0014
|
02
|
INT 24H 入口 CS
|
0016
|
02
|
父進程的PSP段值(可測知是否被跟蹤)
|
0018
|
14
|
存放20個SOFT號
|
002C
|
02
|
環境塊段地址(從中可獲知執行的程序名)
|
002E
|
04
|
存放用戶棧地址指針
|
0032
|
1E
|
保留
|
0050
|
03
|
DOS調用 ( INT 21H / RETF )
|
0053
|
02
|
保留
|
0055
|
07
|
擴展的FCB頭
|
005C
|
10
|
格式化的FCB1
|
006C
|
10
|
格式化的FCB2
|
007C
|
04
|
保留
|
0080
|
80
|
命令行參數長度(不包含總為最后的0D)及參數
也是程序運行期間缺省的DTA
|
一個操作示例:
D:\Masm615>dir jch ;顯示計算階乘的程序
Volume in drive D has no label
Volume Serial Number is 18F0-186B
Directory of D:\Masm615
JCH OBJ 371 04-10-03 20:58 JCH.obj
JCH ASM 3,637 04-03-03 20:46 jch.asm
JCH COM 12,486 04-10-03 20:58 Jch.com
3 file(s) 16,494 bytes
0 dir(s) 915,632,128 bytes free
D:\Masm615>jch 7 ;計算7的階乘
5040
D:\Masm615>debug jch.com 7 ;用DEBUG查看命令行參數情況
-d80 L10 ;可看出命令行參數長度為02,參數是:2037 0D
128D:0080 02 20 37 0D 68 2E 63 6F-6D 20 37 0D 00 00 00 00 . 7.h.com 7.....
-
-D0 7F ;顯示PSP數據
128D:0000 CD 20 00 9D 00 9A F0 FE-1D F0 4F 03 F2 0B 8A 03
128D:0010 F2 0B 17 03 F2 0B E1 0B-01 01 01 00 02 FF FF FF ;父進程的PSP
128D:0020 FF FF FF FF FF FF FF FF-FF FF FF FF 7E 12 4C 01 ;環境塊段地址
128D:0030 F9 0F 14 00 18 00 8D 12-FF FF FF FF 00 00 00 00
128D:0040 07 0A 00 00 00 00 00 00-00 00 00 00 00 00 00 00
128D:0050 CD 21 CB 00 00 00 00 00-00 00 00 00 00 37 20 20
128D:0060 20 20 20 20 20 20 20 20-00 00 00 00 00 20 20 20
128D:0070 20 20 20 20 20 20 20 20-00 00 00 00 00 00 00 00
-D127E:0 ;顯示環境塊的內容(在DOS提示符下可用SET命令查看環境信息)
127E:0000 54 4D 50 3D 43 3A 5C 57-49 4E 44 4F 57 53 5C 54 TMP=C:\WINDOWS\T
127E:0010 45 4D 50 00 54 45 4D 50-3D 43 3A 5C 57 49 4E 44 EMP.TEMP=C:\WIND
127E:0020 4F 57 53 5C 54 45 4D 50-00 50 52 4F 4D 50 54 3D OWS\TEMP.PROMPT=
127E:0030 24 70 24 67 00 77 69 6E-62 6F 6F 74 64 69 72 3D $p$g.winbootdir=
127E:0040 43 3A 5C 57 49 4E 44 4F-57 53 00 50 41 54 48 3D C:\WINDOWS.PATH=
127E:0050 43 3A 5C 57 49 4E 44 4F-57 53 3B 43 3A 5C 57 49 C:\WINDOWS;C:\WI
127E:0060 4E 44 4F 57 53 5C 43 4F-4D 4D 41 4E 44 00 43 4F NDOWS\COMMAND.CO
127E:0070 4D 53 50 45 43 3D 43 3A-5C 57 49 4E 44 4F 57 53 MSPEC=C:\WINDOWS
127E:0080 5C 43 4F 4D 4D 41 4E 44-2E 43 4F 4D 00 77 69 6E \COMMAND.COM.win
127E:0090 64 69 72 3D 43 3A 5C 57-49 4E 44 4F 57 53 00 42 dir=C:\WINDOWS.B
127E:00A0 4C 41 53 54 45 52 3D 41-32 32 30 20 49 35 20 44 LASTER=A220 I5 D
127E:00B0 31 20 54 34 20 50 33 30-30 00 43 4D 44 4C 49 4E 1 T4 P300.CMDLIN
127E:00C0 45 3D 64 65 62 75 67 20-6A 63 68 2E 63 6F 6D 20 E=debug jch.com
127E:00D0 37 00 00 01 00 4A 43 48-2E 43 4F 4D 00 FF 1E 8E 7....JCH.COM....
(環境塊中可找到當前執行的程序名)
-d be1:0 ;顯示父進程的PSP(利用父進程PSP可測知程序是否被其他程序加載跟蹤)
0BE1:0000 CD 20 00 A0 00 9A F0 FE-1D F0 14 03 0F 0A 6D 01 . ............m.
0BE1:0010 0F 0A 78 01 0F 0A 0F 0A-01 01 01 00 02 FF FF FF ..x.............
0BE1:0020 FF FF FF FF FF FF FF FF-FF FF FF FF CF 0B 2E 3E ...............>
0BE1:0030 EF 0B 14 00 18 00 DE 0B-FF FF FF FF 00 00 00 00 ................
0BE1:0040 07 0A 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0BE1:0050 CD 21 CB 00 00 00 00 00-00 00 00 00 00 4A 43 48 .!...........JCH
0BE1:0060 20 20 20 20 20 43 4F 4D-00 00 00 00 00 37 20 20 .....COM.....7
0BE1:0070 20 20 20 20 20 20 20 20-00 00 00 00 00 00 00 00 ........
0BE1:0080 0A 20 6A 63 68 2E 63 6F-6D 20 37 0D 00 00 00 00 . jch.com 7.....
;父進程中的命令行參數
另外:保存INT 22/INT 23/INT 24H的值使得用戶在程序中可修改這些中斷的值,病毒就曾利用這種技術防止不能傳染時引起出錯信息。在程序退出時根據PSP中保存的值恢復各中斷的值。
當可執行文件加載后,根據其不同的類型,系統會采用相應的方式進行處理。若用戶程序是 .COM 文件,則加載后把程序裝入程序段偏移量為 100H
處,并把所有的段寄存器指向 PSP,實際上,由于 .COM 文件是以長度小于 64K 為要求設計的,所有的程序,數據包括 PSP
都在同一段內。對于 .EXE 文件,加載后把程序的 DS 和 ES 指向 PSP 段,若要使用 PSP
,例如,要利用輸入參數,可在程序的開始利用 DS或 ES 實現獲取。當然,獲取 PSP 的段址也可以利用以下介紹的系統調用實現。
對編程者而言,在 PSP
中較為有用的是參數區,參數是通過在程序執行開始時,利用空格與之分隔的字符串,用回車表示結束,具體的說,就是程序和參數在同一行輸入。當程序加載時,
系統將參數及參數長度填入 PSP+80H 開始的參數區,其中 80H 處是參數長度,參數由 81H 開始存放。
二、 程序加載及實現
所謂 "加載" 就是在 DOS 環境下,PC 機從磁盤上將可執行文件(即
DOS 下的 .EXE 文件和 .COM 文件)裝入到內存的過程。加載的過程包括程序裝入內存的分配方案,加載是否成功,裝入后 CPU
各寄存器內容及包括的信息等,對編程者而言,掌握一般的加載后信息分配,在某些應用場合中,了解和掌握如何在自己的程序中加載新的程序并使之運行的方法是
非常有用的。
我們知道, DOS 下允許用戶鍵入的命令有 DOS 內部命令,DOS
外部命令,可執行的應用程序及批處理文件,對同名的可執行文件按 .COM 到 .EXE 的優先順序處理,具體的說,DOS 加載可執行文件是通過
EXEC 子功能實現的 ( 即 INT 21H 的 AH=4BH )。由于 .COM 和 .EXE
文件的結構不同,它們在加載的實際過程及裝入內存方式是不同的,所以,對待不同的文件應有不同的處理方式。
加載 .EXE 文件后,各寄存器的初值設置
1) DS 和 ES 指向 PSP 的段地址
2) CS 指向代碼段的絕對段址
3) SS 指向堆棧段的絕對段址
4) IP 指向代碼段入口時第一條指令的偏移地址
5) SP 指向堆棧段如口時深度,此值由文件頭位移 10H 的字域決定
6) BX, CX 是加載程序的字節長度
加載 .COM 文件后,各寄存器的初值設置
1) CS,DS,ES 和 SS 指向 PSP 的段地址
2) IP 固定為 100H
3) SP 位 FFFEH ,并在棧頂出壓入一全 0 字
4) BX, CX 是 COM 文件的字節長度
A DOS 下 EXEC 子功能的應用
B 加載程序的設計和實現
三、重定位過程
假如說在生成的exe文件頭里的重定位表中有一項是0000:0030,0000H是高字
段,0030H是低字段。用高字段加上起始段值,也就是exe文件加載到內存里的起始地址段(假如是1000H),則結果為1000H,再加上低字段作為
偏移量,則結果為10030H,這個20位的地址指向內存地址為10030H的單元。把指向的這個地址里的字取出來(假設是0010H),加上起始段值,
再放回去。這就完成了一次重定位。即10030H里存放的是1010H。
四、在DOS下,重定位指的是重新定位在你的程序中所引用的段值。
例如,在你的程序(Large Mode)中,有一處需要調用C的庫函數,你的程序編譯后可能是下面的樣子:
0000:0000 9A78563412 call far 1234:5678
~~~~ ~~~~
其中,下劃線的段值部分,就是需要在程序加載時重新定位的。
程序加載器所作的重定位工作,就是將程序中需要重定位的地方,都加上程序的加載地址。
還是上面的例子,假如這個程序被加載到了內存中的1111段處。那么完成重定位后,代碼應該是這樣:
1111:0000 9A78564523 call far 2345:5678
~~~~ ~~~~
OK,DOS下的重定位就是這么簡單。那么,程序加載器如何找到重定位項呢?這就需要EXE文件頭中的
重定位表的幫助。
重定位表是一個非常簡單的4字節結構數組:
typedef struct tagRTABLE
{
WORD wOffset
WORD wSegment
}RELOCATIONTABLE, * PRELOCATIONTABLE;
編譯器(或自己手工)先計算程序中需要重定位的地方在文件中的偏移量,將此偏移量減去文件頭的大小,
然后換算為 Segment:Offset 的形式,填入EXE文件頭中的重定位表,就完成了一個重定位項的建立。
還是上面的例子,這個重定項在重定位表中應該是這個樣子:
.
.
.
---------
| 0003 |
---------
| 0000 |
---------
五、exe文件結構
Dos exe file structure
offset size description
00 word "mz" - link file .exe signature (mark zbikowski?)
02 word length of image mod 512
04 word size of file in 512 byte pages
06 word number of relocation items following header
08 word size of header in 16 byte paragraphs, used to locate
the beginning of the load module
0a word min # of paragraphs needed to run program
0c word max # of paragraphs the program would like
0e word offset in load module of stack segment (in paras)
10 word initial sp value to be loaded
12 word negative checksum of pgm used while by exec loads pgm
14 word program entry point, (initial ip value)
16 word offset in load module of the code segment (in paras)
18 word offset in .exe file of first relocation item
1a word overlay number (0 for root program)
- relocation table and the program load module follow the header
- relocation entries are 32 bit values representing the offset
into the load module needing patched
- once the relocatable item is found, the cs register is added to
the value found at the calculated offset
registers at load time of the exe file are as follows:
ax: contains number of characters in command tail, or 0
bx:cx 32 bit value indicating the load module memory size
dx zero
ss:sp set to stack segment if defined else, ss = cs and
sp=ffffh or top of memory.
ds set to segment address of exe header
es set to segment address of exe header
cs:ip far address of program entry point, (label on "end"
statement of program).
EXE文件包含一個文件頭和一個可重定位程序映象.文件頭包含MS-DOS
用于加載程序的信息,例如程序的大小和寄存器的初始值.文件頭還指向一個
重定位表,該表包含指向程序映象中可重定位段地址的指針鏈表.文件頭的形
式與EXEHEADER結構對應:
EXEHEADER STRUC
exSignature dw 5A4Dh ;.EXE標志
exExraBytes dw ? ;最后(部分)頁中的字節數
exPages dw ? ;文件中的全部和部分頁數
exRelocItems dw ? ;重定位表中的指針數
exHeaderSize dw ? ;以字節為單位的文件頭大小
exMinAlloc dw ? ;最小分配大小
exMaxAlloc dw ? ;最大分配大小
exInitSS dw ? ;初始SS值
exInitSP dw ? ;初始SP值
exChechSum dw ? ;補碼校驗值
exInitIP dw ? ;初始IP值
exInitCS dw ? ;初始CS值
exRelocTable dw ? ;重定位表的字節偏移量
exOverlay dw ? ;覆蓋號
EXEHEADER ENDS
程序映象,包含處理器代碼和程序的初始數據,緊接在文件頭之后.它的
大小,以字節為單位,等于.EXE文件的大小減去文件頭的大小,也等于exHeaderSize
的域的值乘以16.MS-DOS通過把該映象直接從文件拷貝到內存加載.EXE程序
然后調整定位表中說明的可重定位段地址.
定位表是一個重定位指針數組,每個指向程序映象中的可重定位段地址.
文件頭中的exRelocItems域說明了數組中指針的個數,exRelocTable域說明了
分配表的起始文件偏移量.每個重定位指針由兩個16位值組成:偏移量和段值.
為加載.EXE程序,MS-DOS首先讀文件頭以確定.EXE標志并計算程序映象的
大小,然后它試圖申請內存.首先,它計算程序映象文件的大小加上PSP的大小
再加上EXEHEADER結構中的exMinAlloc域說明的內存大小這三者之和,如果總 和超過最大可
用內存塊的大小,則MS-DOS停止加載程序并返回一個出錯值.否
則,它計算程序映象的大小加上PSP的大小再加上EXEHEADER結構中exMaxAlloc
域說明的內存大小之和,如果第二個總和小于最大可用內存塊的大小,則MS-DOS 分配計算得到的內存量.否則,它分配最大可用內存塊.
分配完內存后,MS-DOS確定段地址;也稱為起始段地址,MS-DOS從此處加載
程序映象.如果exMinAlloc域和exMaxAlloc域中的值都為零,則MS-DOS把映象
盡可能地加載到內存最高端.否則,它把映象加載到緊挨著PSP域之上. 接下來,MS-DOS讀取重定位表中的項目調
整所有由可重定位指針說明的段 地址.對于重定位表中的每個指針,MS-DOS尋找程序映象中相應的可重定位段
地址,并把起始段地址加到它之上.一旦調整完畢,段地址便指向了內存中被加 載程序的代碼和數據段.
MS-DOS在所分配內存的最低部分建造256字節的PSP,把AL和AH設置為加載
.COM程序時所設置的值.MS-DOS使用文件頭中的值設置SP與SS,調整SS初始值,
把起始地址加到它之上.MS-DOS還把ES和DS設置為PSP的段地址.
最后,MS-DOS從程序文件頭讀取CS和IP的初始值,把起始段地址加到CS之 上,把控制轉移到位于調整后地址處的程序.