天天看點

硬碟主引導記錄詳解

說明:硬碟主引導記錄獨立于作業系統,但又和作業系統息息相關——很多時候它又是由

; 作業系統所提供的工具所生成(例外的情況是您使用了其他的分區工具,不過它又運作在

; 什麼作業系統中呢?;()。

;

; 如果您安裝了Windows 98(我現在暫時不能接觸95下的主引導記錄,總不能用95重裝我的

; 系統吧?)作業系統,那您機器上的主引導記錄已經與以前的大有不同了,通過下面的分析

; 您一定能對Windows 98為什麼要更改主引導記錄有所了解——它已經開始支援擴充Int13h

; 了!并且這個主引導記錄的程式設計技巧更是我們應該學習的。

;

; 主引導記錄包括代碼、資料兩部分。它在被BIOS中斷Int19h裝入記憶體後獲得控制權。資料

; 部分最重要的當然是分區表了!徹底熟悉主引導記錄,可以幫助我們了解系統的引導過程,

; 處理因主引導記錄損壞所造成的無法引導故障,消除引導型計算機病毒,更使我們能通過

; 修改主引導記錄完成我們希望的工作:如多重引導,系統加軟鎖等...

;

; BIOS中斷總是把主引導記錄所在扇區(硬碟的0頭0道1扇區)的内容(包括代碼和資料)

; 裝入記憶體0000:7C00起始的區域,然後檢驗該扇區内容的最後兩個位元組是不是“AA55”,

; 如果不是,那麼對不起,Int19h将不把控制權交給主引導記錄;若是,則下面的主引導記錄

; 才能獲得了控制權了(Int19通過跳轉指令交轉控制權):

;

; 二進制形式的主引導記錄:

0000:0600 33 C0 8E D0 BC 00 7C FB-50 07 50 1F FC BE 1B 7C 3.....|.P.P....|

0000:0610 BF 1B 06 50 57 B9 E5 01-F3 A4 CB BE BE 07 B1 04 ...PW...........

0000:0620 38 2C 7C 09 75 15 83 C6-10 E2 F5 CD 18 8B 14 8B 8,|.u...........

0000:0630 EE 83 C6 10 49 74 16 38-2C 74 F6 BE 10 07 4E AC ....It.8,t....N.

0000:0640 3C 00 74 FA BB 07 00 B4-0E CD 10 EB F2 89 46 25 <.t...........F%

0000:0650 96 8A 46 04 B4 06 3C 0E-74 11 B4 0B 3C 0C 74 05 ..F...<.t...<.t.

0000:0660 3A C4 75 2B 40 C6 46 25-06 75 24 BB AA 55 50 B4 :[email protected]%.u$..UP.

0000:0670 41 CD 13 58 72 16 81 FB-55 AA 75 10 F6 C1 01 74 A..Xr...U.u....t

0000:0680 0B 8A E0 88 56 24 C7 06-A1 06 EB 1E 88 66 04 BF ....V$.......f..

0000:0690 0A 00 B8 01 02 8B DC 33-C9 83 FF 05 7F 03 8B 4E .......3.......N

0000:06A0 25 03 4E 02 CD 13 72 29-BE 2D 07 81 3E FE 7D 55 %.N...r).-..>.}U

0000:06B0 AA 74 5A 83 EF 05 7F DA-85 F6 75 83 BE 1A 07 EB .tZ.......u.....

0000:06C0 8A 98 91 52 99 03 46 08-13 56 0A E8 12 00 5A EB ...R..F..V....Z.

0000:06D0 D5 4F 74 E4 33 C0 CD 13-EB B8 00 00 80 49 12 00 .Ot.3........I..

0000:06E0 56 33 F6 56 56 52 50 06-53 51 BE 10 00 56 8B F4 V3.VVRP.SQ...V..

0000:06F0 50 52 B8 00 42 8A 56 24-CD 13 5A 58 8D 64 10 72 PR..B.V$..ZX.d.r

0000:0700 0A 40 75 01 42 80 C7 02-E2 F7 F8 5E C3 EB 74 B7 [email protected]......^..t.

0000:0710 D6 C7 F8 B1 ED CE DE D0-A7 00 BC D3 D4 D8 B2 D9 ................

0000:0720 D7 F7 CF B5 CD B3 CA B1-B3 F6 B4 ED 00 4D 69 73 .............Mis

0000:0730 73 69 6E 67 20 6F 70 65-72 61 74 69 6E 67 20 73 sing operating s

0000:0740 79 73 74 65 6D 00 00 00-00 00 00 00 00 00 00 00 ystem...........

0000:0750 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

0000:0760 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

0000:0770 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

0000:0780 00 00 00 8B FC 1E 57 8B-F5 CB 00 00 00 00 00 00 ......W.........

0000:0790 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

0000:07A0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

0000:07B0 00 00 00 00 00 00 00 00-86 D8 00 00 00 00 80 01 ................

0000:07C0 01 00 06 3F 3F FD 3F 00-00 00 41 A0 0F 00 00 00 ...??.?...A.....

0000:07D0 01 FE 05 3F FF FE 80 A0-0F 00 C0 4F 2F 00 00 00 ...?.......O/...

0000:07E0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

0000:07F0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 55 AA ..............U.

;

; 反彙編結果

;

; 0000:7C00~0000:7C1A:初始化各個段寄存器、堆棧指針,最後将主引導記錄在記憶體中搬家,騰出其所占内

; 存空間以供裝入分區引導記錄。

0000:7C00 33C0       XOR    AX,AX         ;AX寄存器清0

0000:7C02 8ED0       MOV    SS,AX         ;SS=0

0000:7C04 BC007C     MOV    SP,7C00       ;裝填棧指針——SS:SP=0000:7C00

0000:7C07 FB         STI                  開中斷(裝填棧指針時為避免硬體中斷引起棧混亂應關中斷)

0000:7C08 50         PUSH   AX            

0000:7C09 07         POP    ES            裝填附加資料段寄存器ES=0

0000:7C0A 50         PUSH   AX            

0000:7C0B 1F         POP    DS            裝填資料段寄存器DS=0

0000:7C0C FC         CLD                  規定其後的串操作為正向串操作

0000:7C0D BE1B7C     MOV    SI,7C1B       ;源指針

0000:7C10 BF1B06     MOV    DI,061B       ;目的指針

0000:7C13 50         PUSH   AX            

0000:7C14 57         PUSH   DI            看看0000:7C1A——構造一個跳轉

0000:7C15 B9E501     MOV    CX,01E5       ;

0000:7C18 F3         REPZ                 ;

0000:7C19 A4         MOVSB                0000:7C1B起始的CX位元組傳送至0000:061B起始的區域

0000:7C1A CB         RETF                 ;跳轉到0000:061B(這是一種技巧跳轉)

; 

; 為直覺起見,下面的位址按實際運作時的位址給出。

; 0000:061B~0000:062B:對分區表進行初步檢驗,一旦檢測到某分區表項狀态位元組大于等于80h,就通過(當

; 然,在此之前如果檢測到某項分區表的狀态位元組小于80h,就轉錯誤處理。當然,如果四個分區項的狀态位元組

; 都為零,主引導記錄就會調用BIOS-ROM的INT 18h,顯示"PRESS A KEY TO REBOOT"資訊等待你的操作。

0000:061B BEBE07     MOV    SI,07BE       ;SI指向第一個分區表項,這時CX=0

0000:061E B104       MOV    CL,04         ;分區表共四個表項

0000:0620 382C       CMP    [SI],CH       ;

0000:0622 7C09       JL     062D          大于等于80h轉[注意JL指令:(SF xor OF)=1則轉]

0000:0624 7515       JNZ    063B          不為0則[SI]一定小于80h,隻能轉錯誤處理了!

0000:0626 83C610     ADD    SI,+10        為零則檢查下一表項

0000:0629 E2F5       LOOP   0620          檢查下一表項

0000:062B CD18       INT    18            四表項的狀态位元組都為0,則系統隻好調用INT 18h了!

; 

; 0000:062D~0000:0639:檢查剩餘的分區表項——狀态位元組必須為零,否則顯示錯誤資訊“分區表無效”然

; 後當機!拜托,微軟搞錯沒有,怎麼用中文提示資訊?真TM傻得可愛!

; 這裡還有個小BUG,前面放行原則是隻要狀态位元組大于等于80h,那麼如果這個位元組是諸如A0h、E5h之類數值

; 呢?嘿嘿,這個引導記錄統統認為是有效的可引導分區了!

0000:062D 8B14       MOV    DX,[SI]       ;為讀分區引導記錄做準備:磁頭号→DH,驅動器号→DL

0000:062F 8BEE       MOV    BP,SI         ;SI→BP,儲存可引導分區表項的指針

; 

0000:0631 83C610     ADD    SI,+10        其餘的分區表項還要檢查檢查的

0000:0634 49         DEC    CX            

0000:0635 7416       JZ     064D          CX=0則檢查順利通過,轉繼續

0000:0637 382C       CMP    [SI],CH       ;

0000:0639 74F6       JZ     0631          為零,是合法表項,再查下一表項

; 

; 0000:063B~0000:064B:執行錯誤處理——報告錯誤資訊後當機

0000:063B BE1007     MOV    SI,0710       ;錯誤資訊字元串偏移+1→SI

0000:063E 4E         DEC    SI            SI-1→SI

0000:063F AC         LODSB                SI+1→SI

0000:0640 3C00       CMP    AL,00         ;

0000:0642 74FA       JZ     063E          AL=0則表明一條錯誤資訊顯示完畢,系統陷入一個死循環

0000:0644 BB0700     MOV    BX,0007       ;字元方式顯示

0000:0647 B40E       MOV    AH,0E         ;

0000:0649 CD10       INT    10            以寫電傳方式顯示資訊(隻顯示一個字元)

0000:064B EBF2       JMP    063F          顯示下一個字元,直到遇到提示資訊結束為止

; 

; 0000:064D~0000:0662:判斷可引導分區的分區類型,然後轉相應處理程式。

0000:064D 894625     MOV    [BP+25],AX    BP=指向第一個可引導分區表項的指針,這時AX=0000h

                                          使用長度最短的指令将[BP+25]起始的兩個單元清零

                                          這兩個單元将被用來存放中間變量

0000:0650 96         XCHG   SI,AX         ;此時SI清零的最佳指令選擇(僅1位元組),将服務于0000:06B8

0000:0651 8A4604     MOV    AL,[BP+04]    取分區類型(本例是“06”喽——FAT16主DOS分區)

0000:0654 B406       MOV    AH,06         ;為擴充INT 13h無法使用做好更改分區類型的準備

0000:0656 3C0E       CMP    AL,0E         ;0Eh:需要用擴充INT 13h通路的FAT16主DOS分區

0000:0658 7411       JZ     066B          0Eh類型的分區轉066Bh

0000:065A B40B       MOV    AH,0B         ;

0000:065C 3C0C       CMP    AL,0C         ;0Ch:需要用擴充INT 13h通路的FAT32分區

0000:065E 7405       JZ     0665          0Ch類型的分區轉0665h先行預處理

0000:0660 3AC4       CMP    AL,AH         ;0Bh:用傳統INT 13h就可以通路的FAT32分區

0000:0662 752B       JNZ    068F          其他類型的分區轉068Fh

; 

; 0000:0664~0000:06A1:根據分區類型和分區表表項内容進行讀取分區引導記錄前的處理工作

0000:0664 40         INC    AX            ★★★0Bh類型的分區由此開始處理,此條指令用意是清ZF位

0000:0665 C6462506   MOV    BYTE PTR [BP+25],06 ;★★★0Ch類型的分區由此開始處理

                                          為什麼取值06,一時沒有自圓我說的解釋,請耐心幾天吧。

0000:0669 7524       JNZ    068F          請注意上面指令對ZF位的影響:0Bh類型分區轉,0Ch則不轉

; 0000:066B~0000:068C這段代碼僅當分區類型是0Ch、0Eh才有獲得執行的機會

0000:066B BBAA55     MOV    BX,55AA       ;★★★0Eh類型的分區由此開始處理

0000:066E 50         PUSH   AX            

0000:066F B441       MOV    AH,41         ;擴充INT 13h功能,檢測BIOS是否已經支援擴充INT13h

0000:0671 CD13       INT    13            入口參數:BX=55AAh,DL=驅動器号,AH=41h

0000:0673 58         POP    AX            執行完恢複AX為060Eh

0000:0674 7216       JB     068C          不支援則轉

0000:0676 81FB55AA   CMP    BX,AA55       ;

0000:067A 7510       JNZ    068C          擴充INT13h不可用也轉

0000:067C F6C101     TEST   CL,01         ;測試擴充盤通路是否被支援

0000:067F 740B       JZ     068C          不支援還轉

; 因為擴充INT13h方式讀盤與标準INT13h方式讀盤有很大差别,是以0000:0686處指令修改其後的代碼以保證按

; 照擴充讀方式讀分區引導扇區時能正确跳轉到相應的處理程式中。

0000:0681 8AE0       MOV    AH,AL         ;分區類型→AH

0000:0683 885624     MOV    [BP+24],DL    儲存驅動器号→[BP+24]

0000:0686 C706A106EB1E MOV    WORD PTR [06A1],1EEB ;修改0000:06A1處代碼為"JMP 06C1"

0000:068C 886604     MOV    [BP+04],AH    注意:如果擴充INT13h不能使用則A改分區類型為06,但如果

                                          擴充INT13h能使用,則仍保持原分區類型不變

0000:068F BF0A00     MOV    DI,000A       ;★★★其它類型分區由此開始處理。此條指令初始化計數器

0000:0692 B80102     MOV    AX,0201       ;AH:讀操作,AL:讀取1個扇區的内容

0000:0695 8BDC       MOV    BX,SP         ;SP=7C00→BX,指定分區引導記錄裝入記憶體的位置偏移

0000:0697 33C9       XOR    CX,CX         ;CX清零

0000:0699 83FF05     CMP    DI,+05        注意5 0000:069C 7F03       JG     06A1          大于則轉去讀由分區表指定的分區引導扇區

0000:069E 8B4E25     MOV    CX,[BP+25]    小于則證明所讀分區表指定的引導扇區無合法的引導記錄,

                                          改按???再讀,畢竟多一種選擇多一次機會嘛!;)

; 以下标有①②者請注意它們的位址都是一樣的,就是說實際運作中隻可能是二者之一,但為了分析之友善,我

; 把兩者都列了出來以供對比,閱讀時千萬别看成是兩條指令了啊!

①0000:06A1 034E02     ADD    CX,[BP+02]    擷取分區引導扇區所在的柱面号和實體扇區号

②0000:06A1 EB1E       JMP    06C1          如果分區類型是0Ch、0Eh而且擴充讀能使用則執行該指令

; 

; 0000:06A4:将可引導分區的分區引導記錄裝入記憶體指定區域

; 入口參數:AH=功能号,02為讀盤操作;AL=一次讀取的扇區數

;          ES:BX=讀入記憶體的起始位址

;          CH=10位柱面号的低8位;CL:高兩位是10位柱面号的高兩位,低6位是實體扇區号

;          DH=磁頭号;DL=驅動器号,最高位(即位7)為0是軟碟,為1是硬碟

0000:06A4 CD13       INT    13            讀分區引導記錄到0000:7C00起始的區域

; 

; 

0000:06A6 7229       JB     06D1          不成功轉

0000:06A8 BE2D07     MOV    SI,072D       ;錯誤資訊字元串偏移→SI

0000:06AB 813EFE7D55AA CMP    WORD PTR [7DFE],AA55 ;分區引導記錄合法嗎?

0000:06B1 745A       JZ     070D          合法則轉(這是主引導記錄唯一的正常出口) 
 0000:06B3 83EF05     SUB    DI,+05        不合法則為換讀其他扇區做準備
 0000:06B6 7FDA       JG     0692          隻有一次換讀扇區的機會!
 ; 
 ; 0000:06B8~0000:06BF:錯誤預處理
 0000:06B8 85F6       TEST   SI,SI         ;測試SI值是否為0,其意義在于确定該顯示哪條資訊
 0000:06BA 7583       JNZ    063F          不為0則轉錯誤處理,顯示“Missing operating system”
 0000:06BC BE1A07     MOV    SI,071A       ;錯誤資訊字元串偏移→SI
 0000:06BF EB8A       JMP    064B          轉錯誤處理,顯示“加載作業系統時出錯”
 ; 
 ; 0000:06C1~0000:06CF:整理擴充讀所需入口參數,然後調用擴充讀子程式
 ; 這段代碼隻有在以擴充讀方式讀取分區引導記錄時才有機會獲得執行
 0000:06C1 98         CBW                  轉換位元組AL為字AX,執行後,AX中是一次要讀的扇區數
 0000:06C2 91         XCHG   CX,AX         ;AX→CX,CX→AX,執行後,CX中是一次要讀的扇區數
 0000:06C3 52         PUSH   DX            
 0000:06C4 99         CWD                  将字AX轉換為雙字→DX,AX
 0000:06C5 034608     ADD    AX,[BP+08]    
 0000:06C8 13560A     ADC    DX,[BP+0A]    執行後,DX:AX=LBA絕對實體扇區号
 0000:06CB E81200     CALL   06E0          調用擴充讀子程式
 0000:06CE 5A         POP    DX            
 0000:06CF EBD5       JMP    06A6          
 ; 
 ; 0000:06D1~0000:06D8分區引導記錄裝入失敗時的處理
 0000:06D1 4F         DEC    DI            計數器減1
 0000:06D2 74E4       JZ     06B8          五次讀盤均未成功則轉錯誤處理(注意這時SI=0)
 0000:06D4 33C0       XOR    AX,AX         ;置功能号
 0000:06D6 CD13       INT    13            複位磁盤系統
 0000:06D8 EBB8       JMP    0692          再讀
 ; 
 ; 
 0000:06DA 00 00 80 49 12 00 ...I..
 ; 
 ; 0000:06E0~0000:070C:使用擴充INT 13h功能讀取分區引導記錄的子程式
 ; 調用時,SP=7BFE。這段程式利用壓棧寄存器方式構造了一個磁盤位址包,請注意體會。另外,0000:06FC處
 ; 的一條指令就釋放了幾乎全部由本段程式占用的棧空間,構思之巧妙,絕對需要我們學習!
 ; 是以,分析該段程式,一個重點應放在棧的變化上。
 0000:06E0 56         PUSH   SI            儲存SI——注意,這次壓棧并不構造磁盤位址包
 0000:06E1 33F6       XOR    SI,SI         ;清零
 0000:06E3 56         PUSH   SI            
 0000:06E4 56         PUSH   SI            
 0000:06E5 52         PUSH   DX            
 0000:06E6 50         PUSH   AX            以上四條指令壓棧的是扇區LBA号碼*2
 0000:06E7 06         PUSH   ES            壓棧記憶體目标緩沖區首址段址
 0000:06E8 53         PUSH   BX            壓棧記憶體目标緩沖區首址偏移
 0000:06E9 51         PUSH   CX            壓棧所讀扇區數
 0000:06EA BE1000     MOV    SI,0010       ;注意SI的高8位對應着磁盤位址包的保留位元組,必須為0
 0000:06ED 56         PUSH   SI            壓棧磁盤位址包包長,執行完本條指令一個包已經構造完畢
 0000:06EE 8BF4       MOV    SI,SP         ;規定磁盤位址包偏移指針,這時SP=7BEA
 0000:06F0 50         PUSH   AX            儲存AX
 0000:06F1 52         PUSH   DX            儲存DX
 0000:06F2 B80042     MOV    AX,4200       ;置擴充讀功能号
 0000:06F5 8A5624     MOV    DL,[BP+24]    取驅動器号,參照0000:0683
 ; 入口參數:AH=功能号,02為讀盤操作;DL=驅動器号
 ;          DS:SI=16位元組磁盤位址包——第0位元組:包長度(固定為10h);第1位元組:保留,必須為0;
 ;          第2、3位元組:所讀扇區數;第4~5位元組:記憶體目标緩沖區首址偏移;
 ;          第6~7位元組:記憶體目标緩沖區首址段址; 第8~15位元組:扇區LBA号碼
 ; 出口參數:成功則AH=0;錯誤則AH=錯誤代碼
 0000:06F8 CD13       INT    13            執行擴充讀操作
 0000:06FA 5A         POP    DX            
 0000:06FB 58         POP    AX            
 0000:06FC 8D6410     LEA    SP,[SI+10]    7BEA+10h=7BFA→SP(注意是取偏移而不是取單元内容)
 0000:06FF 720A       JB     070B          擴充讀不成功轉
 0000:0701 40         INC    AX            
 0000:0702 7501       JNZ    0705          
 0000:0704 42         INC    DX            AX加1溢出時(比如0FFFFh+1)DX才加1
 0000:0705 80C702     ADD    BH,02         ;調整BX,使偏移量增加512位元組(剛好一扇區)
 0000:0708 E2F7       LOOP   0701          0701~0708一段代碼暫未明白其真實意圖!
 0000:070A F8         CLC                  
 0000:070B 5E         POP    SI            
 0000:070C C3         RET                  
 ; 
 ; 0000:070D:中繼跳轉
 0000:070D EB74       JMP    0783          
 ; 
 ; 070F~0745是錯誤資訊!果然是中文Windows98生成的主引導記錄,是以我要特别
 ; “感謝”微軟這個傻B,真難為它竟然用中文表述前兩個資訊!可惜真需顯示的時
 ; 候鬼才能看懂是什麼呢!!!我K!——耍弄我們耶!?
 ; 070F~0718:“分區表無效”中文資訊
 ; 071A~072B:“加載作業系統時出錯”中文資訊
 ; 072D~0744:“Missing operating system”英文資訊
 0000:070F B7 . 
 0000:0710 D6 C7 F8 B1 ED CE DE D0-A7 00 BC D3 D4 D8 B2 D9 ................
 0000:0720 D7 F7 CF B5 CD B3 CA B1-B3 F6 B4 ED 00 4D 69 73 .............Mis
 0000:0730 73 69 6E 67 20 6F 70 65-72 61 74 69 6E 67 20 73 sing operating s
 0000:0740 79 73 74 65 6D 00 00 00-00 00 00 00 00 00 00 00 system..........
 0000:0750 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
 0000:0760 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
 0000:0770 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
 0000:0780 00 00 00 ...
 ; 
 ; 0000:0783~0000:0789:控制權移交
 0000:0783 8BFC       MOV    DI,SP         ;
 0000:0785 1E         PUSH   DS            
 0000:0786 57         PUSH   DI            構造一個跳轉位址
 0000:0787 8BF5       MOV    SI,BP         ;
 0000:0789 CB         RETF                 ;交控制權給分區引導記錄(0000:7C00)
 ; 
 ; 
 0000:078A 00 00 00 00 00 00 ......
 0000:0790 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
 0000:07A0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
 ; 
 ; 07B8~07BB四個位元組的内容用于什麼呢?(不同機器此四位元組均不同)
 ; 07BE~07FD為分區表,内含四個分區表項(每表項10h位元組)
 0000:07B0 00 00 00 00 00 00 00 00-86 D8 00 00 00 00 80 01 ................
 0000:07C0 01 00 06 3F 3F FD 3F 00-00 00 41 A0 0F 00 00 00 ...??.?...A.....
 0000:07D0 01 FE 05 3F FF FE 80 A0-0F 00 C0 4F 2F 00 00 00 ...?.......O/...
 0000:07E0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
 0000:07F0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 55 AA ..............U. *1:因為實體扇區号總是從1排列而起
 *2:由此可見,就是使用LBA擴充讀的功能,主引導記錄卻限制了分區引導扇區必須在LBA絕對實體扇區
      0FFFFFFFFh之前才有可能從該分區引導系統!