http://hqiangbo.blog.163.com/blog/static/42933253200831062318739/
大家都害怕病毒,但都想了解病毒。要了解病毒,以及病毒的機理,就必須先了解一些文件的結構和原理,下面把COM/EXE文件的結構介紹一下:
一 .COM文件結構及原理
com文件結構比較簡單,它包含程序的一個絕對映像,即爲了運行程序準確的處理器指令和內存中的數據,MS-DOS通過直接把該映像從文件直接複製到內存,從而加載com程序,而不做任何改變。
爲加載一個com程序,MS-DOS首先試圖分配內存,因爲com程序必須位於一個64KB的段中,所以com文件的大小不能超過65024(64KB減去用於PSP的256B和用於一個起始堆棧的至少256B)。如果MS-DOS不能爲程序、一個PSP、一個起始堆棧分配足夠的內存,則分配嘗試失敗。否則,MS-DOS分配儘可能多的內存(直至所有保留內存),即使com程序本身不能大於64KB。在試圖運行另一個程序或分配另外的內存之前,大部分com程序釋放任何不需要的內存。
分配內存後,MS-DOS在該內存的前256B建立一個PSP,如果PSP中的第一個FCB含有一個有效驅動器標識符,則置AL爲00H,否則置位0FFH。MS-DOS還置AH爲00或0FFH,這依賴於第二個FCB是否含有一個有效驅動器標識符。建造PSP後,MS-DOS在PSP後立即開始(偏移100H)加載com文件,它置SS、DS和ES爲PSP的段地址,接着創建一個堆棧。爲創建這個堆棧,在已分配了至少64KB內存的情況下,MS-DOS置SP爲0000H;否則它置寄存器比所分配的自己總數大2的值。最後,將0000H進棧(這是爲了保證與在早期MS-DOS版本上設計的程序的兼容性)。
MS-DOS通過把控制傳遞給偏移100H處的指令而啓動程序。程序設計者必須保證COM文件的第一條指令是程序的入口點。
注意:因爲程序是在偏移100H處加載,因此所有代碼和數據偏移也必須相對於100H。彙編語言程序設計者可通過設置程序的初值爲100H而保證這一點(例如通過在源程序的開始使用語句org 100h)。
二.exe文件結構及原理
exe文件比較複雜,屬於一種多段的結構,是DOS最成功和複雜的設計之一。要了解exe文件,首先需要了解exe文件的文件頭結構。
每個exe文件包含一個文件頭和一個可重定位程序的映像。文件頭包含MS-DOS用於加載程序的信息,例如程序的大小和寄存器的初始值。文件頭還指向一個重定位表,該表包含指向程序映像中可重定位段地址的指針鏈表。exe文件的文件頭結構如表所示:
偏移量 含義
00h~01h MZ,exe文件標記
02h~03h 文件長度除以512的餘數
04h~05h 文件長度除以512的商
06h~07h 重定位項的個數
08h~09h 文件頭除以16的商
0ah~0bh 程序運行所需最小段數
0ch~0dh 程序運行所需最大段數
0eh~0fh 堆棧段的段值(SS)
10h~11h 堆棧段的段值(SP)
12h~13h 文件校驗和
14h~15h 裝入模塊入口時的IP值
16h~17h 裝入模塊代碼相對段值(CS)
18h~19h 重定位表,開始位置,以位移地址表示
1ah~1bh 覆蓋號(程序駐留爲零)
1ch 重定位表,起點由偏移18h~19h給出,項數由06h~07h標明
一、DOS EXE文件頭數據結構
struct DOSEXEHEAD_t
{
unsigned char Mark1; // LINK簽名0x4D
unsigned char Mark2; // LINK簽名0x5A
unsigned short VolumeInLastPage; // 最後一扇區字節數
unsigned short CountOfPage; // 扇區數
unsigned short CountOfReallocItem; //重定位表的項數
unsigned short SizeOfHeadInPara; // 以節爲單位的EXE頭大小
unsigned short min_para; // 程序下方所需最小節數
unsigned short max_para; // 程序下方所需最大節數
unsigned short Start_SS; // 入口點SS,相對值
unsigned short Start_SP; // 入口點SP
unsigned short Reserved; // 保留,目前爲0x0000
unsigned short Start_IP; // 入口點IP
unsigned short Start_CS; // 入口點CS,相對值
unsigned short FirstReallocPtr; // 首重定位表項距頭首部的字節數
}; 程序映像包含處理代碼和程序的初始數據,緊接在文件頭之後。它的大小以字節爲單位,等於exe文件的大小減去文件頭的大小,也等於exHeaderSize的域的值乘以16。MS-DOS通過把該映像直接從文件複製到內存加載exe程序,然後調整定位表中說明的可重定位段地址。
定位表是一個重定位指針數組,每個指向程序映像中的可重定位段地址。文件頭中的exRelocItems域說明了數組中指針的個數,exRelocTable域說明了分配表的起始文件偏移量。每個重定位指針由兩個16位值組成:偏移量和段值。爲加載exe程序,MS-DOS首先讀文件頭以確定exe標誌並計算程序映像的大小,然後它試圖申請內存。首先,它計算程序映像文件的大小加上PSP的大小,再加上EXEHEADER結構中的exMinAlloc域說明的內存大小這3者之和。如果總和超過最大可用內存塊的大小,則MS-DOS停止加載程序並返回一個出錯值。否則,它計算程序映像的大小加上PSP的大小再加上EXEHEADER結構中exMaxAlloc域說明的內存大小之和,如果第二個總和小於最大可用內存塊的大小,則MS-DOS分配計算得到的內存量。否則,它分配最大可用內存塊。
分配完內存後,MS-DOS確定段地址,也稱爲起始段地址,MS-DOS從此處加載程序映像。如果exMinAlloc域和exMaxAlloc域中的值都爲零,則MS-DOS把映像儘可能地加載到內存最高端。否則,它把映像加載到緊挨着PSP域之上。
接下來,MS-DOS讀取重定位表中的項目調整所有由重定位指針說明的段地址。對於重定位表的每個指針,MS-DOS尋找指針映像中相應的可重定位段地址,並把起始段地址加到它之上。一旦調整完畢,段地址便指向了內存中被加載程序的代碼和數據段。MS-DOS在所分配內存的最低部分建造256B的PSP,把AL和AH設置爲加載com程序時所設置的值。MS-DOS使用文件頭中的值設置SP與SS,調整SS初始值,把起始地址加載到它之上。MS-DOS還把EX和DS設置爲PSP的段地址。最後,MS-DOS從程序文件頭讀取CS和IP的初始值,把起始段地址加到CS之上,把控制轉移到位於調整後的地址處的程序。
三.什麼是psp
事實上,無論是"COM"還是"EXE"文件,DOS在調入它們時都要保留256字節來預置一些數據,我們把這256字節稱爲"程序段前綴"(PSP--Program Segment Prefix),對於一個"COM"文件,由於只有一個段,所以PSP、代碼、數據和堆棧都在這個段中,PSP在頭部,堆棧在尾部,中間是代碼和數據,一個"COM"程序在調入內存執行時DOS會自動在堆棧中存入一個0,所以"COM"程序只需使用近程的RET指令就能返回DOS,並且無需自己初始化堆棧。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/idy_10000/archive/2011/03/05/6225612.aspx