Exe文件裝載過程

 

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之   上,把控制轉移到位于調整后地址處的程序.