說明:硬盤主引導記錄獨立於操作系統,但又和操作系統息息相關——很多時候它又是由
; 操作系統所提供的工具所生成(例外的情況是您使用了其他的分區工具,不過它又運行在
; 什麼操作系統中呢?;()。
;
; 如果您安裝了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 :.u+@.F%.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 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 .@u.B......^..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] ;小於則證明所讀分區表指定的引導扇區無合法的引導記錄,
;改按???再讀,畢竟多一種選擇多一次機會嘛!;)
; 以下標有(1)(2)者請注意它們的地址都是一樣的,就是說實際運行中只可能是二者之一,但為了分析之方便,我
; 把兩者都列了出來以供對比,閱讀時千萬別看成是兩條指令了啊!
(1)0000:06A1 034E02 ADD CX,[BP+02] ;獲取分區引導扇區所在的柱面號和物理扇區號
(2)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之前才有可能從該分區引導系統!
0 意見: