首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 組合語言

Windows 98 SE MBR 反組譯代碼深度分析:從載入到啟動分區移交

     編輯:組合語言

MBR 執行環境與初始化

BIOS 將 MBR 載入 0000:7C00h,初始暫存器:CS=DS=ES=SS=0, IP=7C00h, SP=0400h。MBR 首要任務是將自身從 7C00h 重定位至 0600h,騰出 7C00h 給啟動扇區(VBR)。

重定位代碼(0600h–061Ah)

start:
    xor  ax, ax
    mov  ss, ax          ; SS=0
    mov  sp, 7C00h       ; 新堆疊指向 7C00h 以上
    sti                  ; 開啟中斷
    push ax
    pop  es              ; ES=0
    push ax
    pop  ds              ; DS=0
    cld                  ; 方向旗標清零(正向複製)
    mov  si, 7C1Bh       ; 來源:原始代碼起始
    mov  di, 061Bh       ; 目的:重定位後位址
    push ax
    push di
    mov  cx, code_end - loc_restart  ; 複製長度
    rep  movsb           ; 複製代碼到 0600h
    retf                 ; 遠程返回到 0:061Bh (loc_restart)

分區表掃描與啟動分區判斷邏輯(061Bh–064Ch)

loc_restart:
    mov  si, 07BEh       ; SI 指向分區表起始 (7BEh)
    mov  cl, 4           ; 4 個分區項

loc_nextpe:
    cmp  [si], ch        ; 比較啟動旗標 [si] 與 0 (CH=0)
    jl   short loc_boot  ; 有號比較:若 <0 (即 80h) 則啟動
    jnz  short loc_bad   ; 不等於 0 且非 80h → 無效值
    add  si, 10h         ; 下一項
    loop loc_nextpe
    int  18h             ; 4 項皆無啟動旗標 → ROM BASIC

loc_boot:
    mov  dx, [si]        ; DX = 啟動旗標(80h) + 起始磁頭
    mov  bp, si          ; BP 保存分區表項指標(傳遞給 VBR)

loc_nextrpe:             ; 檢查剩餘項是否全為 0
    add  si, 10h
    dec  cx
    jz   short loc_tabok ; 全檢查完畢
    cmp  [si], ch        ; 其他項必須為 0
    je   loc_nextrpe
    ; 發現第二個 80h 或非 0/80h 值
loc_bad:
    mov  si, offset msg1+1  ; "Invalid partition table"
    jmp  short loc_halt

關鍵邏輯:

  1. 啟動旗標合法值僅 00h(非啟動)與 80h(啟動中),其他值視為錯誤。
  2. 只允許一個啟動分區,多個則報錯掛機。
  3. 無啟動分區則呼叫 INT 18h 進入 ROM BASIC(古老機制)。

啟動扇區讀取策略:雙模式支援(064Dh–06D8h)

MBR 根據分區系統 ID 選擇讀取模式:

系統 ID檔案系統讀取模式
0EhFAT32 LBA優先 INT 13h AH=42h (LBA 48-bit)
0Bh, 0ChFAT32傳統 INT 13h AH=02h,但第 6 次重試改讀備份扇區(+6 扇區)
其他FAT12/16, NTFS 等傳統 INT 13h AH=02h (CHS)

INT 13h 擴展功能檢測(066Bh–068Ah)

loc_check13ext:
    mov  bx, 55AAh
    push ax
    mov  ah, 41h         ; INT 13h AH=41h:檢測擴展功能
    int  13h
    pop  ax
    jc   short loc_no13ext   ; CF=1 不支援
    cmp  bx, 0AA55h    ; 回傳簽章檢查
    jne  short loc_no13ext
    test cl, 1         ; CL bit 0 = 支援擴展存取
    jz   short loc_no13ext
    ; 支援擴展:修改自我代碼跳過傳統讀取
    mov  ah, al
    mov  [bp+24h], dl  ; 記錄磁碟機號
    mov  word ptr ds:[6A1h], 1EEBh  ; 寫入 JMP SHORT 指令跳過傳統路徑

此處展示了 MBR 的自我修改代碼技術:若支援 LBA,直接在記憶體中修改跳轉指令,避開傳統 CHS 讀取路徑。

傳統 CHS 讀取重試邏輯(068Fh–06D8h)

loc_int13old:
    mov  di, 0Ah         ; 重試計數器 = 10

loc_readin:
    mov  ax, 0201h       ; AH=02h(讀取), AL=01h(1 扇區)
    mov  bx, sp          ; ES:BX = 0:7C00h (堆疊剛好在 7C00h)
    xor  cx, cx
    cmp  di, 5
    jg   short loc_readbackup  ; 前 5 次讀主要扇區
    mov  cx, [bp+25h]  ; 第 6 次起:讀備份扇區 (CH=柱面, CL=扇區)

loc_readbackup:
    add  cx, [bp+2]    ; 起始扇區 + 偏移
    int  13h           ; 呼叫 BIOS 讀取
    jc   short loc_retry       ; CF=1 讀取失敗

    ; 讀取成功:驗證魔術數字
    mov  si, offset msg3       ; "Missing operating system"
    cmp  word ptr ds:[7DFEh], 0AA55h
    je   short loc_gobootrecok ; 驗證通過 → 跳轉執行

    ; 驗證失敗:嘗試備份
    sub  di, 5
    jg   loc_readin

INT 13h AH=42h 擴展讀取子程式(06E0h–070Ch)

int13ext proc near
    ; 輸入:DX:AX = 邏輯扇區號 (LBA), CL = 扇區數, ES:BX = 緩衝區
    push si
    xor  si, si
    push si          ; 保留位元組
    push si          ; 保留位元組
    push dx          ; LBA 高 32 位
    push ax          ; LBA 低 32 位
    push es          ; 緩衝區段地址
    push bx          ; 緩衝區偏移
    push cx          ; 扇區數
    mov  si, 10h     ; 封包大小 = 16 位元組
    push si
    mov  si, sp      ; DS:SI 指向磁碟位址封包 (DAP)
    push ax
    push dx
    mov  ax, 4200h   ; AH=42h, AL=00h
    mov  dl, [bp+24h] ; 磁碟機號
    int  13h
    ; ... 後續處理緩衝區指標推進、返回狀態 ...
    retn
int13ext endp

DAP (Disk Address Packet) 結構:

DAP STRUCT
    cbSize      db 10h      ; 封包大小
    Reserved    db 0
    BlockCount  dw ?        ; 扇區數 (max 127)
    Reserved2   db 0
    BufferPtr   dd ?        ; 緩衝區 32-bit 位址 (段:偏移)
    LBA         dq ?        ; 64-bit 邏輯扇區號
DAP ENDS

錯誤處理與最終移交(06B8h–0789h)

loc_endofretry:           ; 10 次重試全失敗
    test si, si
    jnz  loc_msg           ; SI 有錯誤訊息指標 → 顯示
    mov  si, offset msg2   ; "Error loading operating system"
    jmp  loc_msgh

loc_gobootrecok:          ; 驗證通過
    jmp  short loc_bootrecok

loc_bootrecok:            ; 移交控制權給 VBR (0:7C00h)
    mov  di, sp            ; DI = 7C00h
    push ds
    push di
    mov  si, bp            ; SI = 分區表項指標 (BP 保存的)
    retf                   ; 遠程跳轉到 0:7C00h
    ; 此時暫存器狀態:
    ; CS=DS=ES=SS=0, IP=7C00h, DI=SP=7C00h, SI=BP→分區表項

資料區結構(070Fh–07FFh)

msg1  db 'Invalid partition table', 0
msg2  db 'Error loading operating system', 0
msg3  db 'Missing operating system', 0
; 37 位元組保留區 (多語言訊息)

partition_tab:            ; 位於 7BEh
    ; 第 1 項:啟動中, FAT32 (0Bh), LBA=3Fh, 大小=383B41h 扇區
    db 80h, 01h, 01h, 00h, 0Bh, 7Fh, 7Fh, 0C8h
    dd 0000003Fh, 00383B41h
    ; 第 2 項:非啟動, 擴充分區 (05h)
    db 00h, 00h, 41h, 0C9h, 05h, 7Fh, 0FFh, 13h
    dd 00383B80h, 0028BA80h
    ; 第 3, 4 項:全 0

magicword dw 0AA55h       ; 7FEh: MBR 有效標誌

總結:MBR 核心流程圖

  1. 重定位:7C00h → 0600h,建立堆疊。
  2. 掃描分區表:尋找唯一啟動旗標=80h 的項,檢查其他項合法性。
  3. 選擇讀取模式:根據系統 ID 決定 INT 13h AH=42h (LBA) 或 AH=02h (CHS)。
  4. 讀取啟動扇區:最多 10 次重試,失敗則重置磁碟控制器再試;FAT32 第 6 次起讀備份。
  5. 驗證魔術數字:7DFEh 必須為 AA55h。
  6. 移交控制權:遠程跳轉至 0:7C00h,傳遞分區表項指標於 SI/BP。

Win98 SE MBR 體現了從傳統 CHS 向 LBA 過渡期的設計智慧:自我修改代碼動態選擇最佳讀取路徑、完善的重試與備份機制、嚴格的分區表合法性檢查。這段 446 位元組的代碼(不含分區表與魔術數),是 PC 相容機啟動鏈中最關鍵、最精煉的一環。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved