在 DOS 時期的電腦教室,學員誤刪系統檔或重要資料屢見不鮮。作者提出一套「多重 PRI DOS 分區 + 動態切換」方案:硬碟建立多個主分區,每次開機僅啟用一個,其餘隱藏,達到資料隔離與快速還原目的。核心在於直接操作主開機記錄 (MBR) 分區表。
MBR 位於磁柱 0、磁頭 0、扇區 1 (LBA 0),共 512 位元組:
0x55 0xAA單筆分區記錄結構 (位移/長度/含義):
| 位移 | 長度 | 欄位 | 備註 |
|---|---|---|---|
| 0 | 1 | 啟動旗標 | 0x80=啟動, 0x00=非啟動 |
| 1 | 3 | 起始 CHS | 柱面/磁頭/扇區 |
| 4 | 1 | 分區類型 | 0x01=FAT12, 0x04/0x06=FAT16, 0x05=Extended, 0x0B/0x0C=FAT32 |
| 5 | 3 | 結束 CHS | 同上 |
| 8 | 4 | 起始 LBA | 相對起始扇區號 |
| 12 | 4 | 分區大小 | 扇區數 |
FORMAT C:,原 C: 變為 D:,新分區成為 C:。MBR 保留區 0x00DB~0x01BD (228 bytes) 通常全 0。作者將 4 筆分區記錄備份於此區尾端 64 bytes。切換時:
PDOS.CPP 解讀 (關鍵函數)/* 結構定義 */
struct HSC { char hd, sc, cy; }; /* CHS 地址 */
struct PartitionTable {
char Flag; /* 啟動旗標 */
HSC begin; /* 起始 CHS */
char Type; /* 分區類型 */
HSC end; /* 結束 CHS */
long lba_start; /* 起始 LBA */
long size; /* 扇區數 */
};
struct note { /* MBR 完整映射 */
char boot1[366]; /* 開機碼 + 保留區 */
PartitionTable PT[1]; /* 未使用 */
PartitionTable PT1[4]; /* 備份區 */
PartitionTable PT2[4]; /* 作用中分區表 */
char sig[2]; /* 0x55 0xAA */
} dosboot;
/* 將 Extended 分區改為 PRI DOS 並設為啟動 */
void create_pri_dos()
{
biosdisk(2, 0x80, 0, 0, 1, 1, &dosboot); /* 讀 MBR */
for (int i = 0; i < 4; i++) {
if (dosboot.PT2[i].Type != 0 && dosboot.PT2[i].Type != 5)
dosboot.PT2[i].Flag = 0x00; /* 關閉其他啟動旗標 */
if (dosboot.PT2[i].Type == 5) { /* 找到 Extended */
dosboot.PT2[i].Type = 6; /* 改為 FAT16 大分區 */
dosboot.PT2[i].Flag = 0x80; /* 設為啟動 */
}
}
biosdisk(3, 0x80, 0, 0, 1, 1, &dosboot); /* 寫 MBR */
}
/* 備份 4 筆分區記錄到 PT1 */
void set_hidde_dos()
{
biosdisk(2, 0x80, 0, 0, 1, 1, &dosboot);
for (int i = 0; i < 4; i++)
if (dosboot.PT2[i].Type != 0 && dosboot.PT2[i].Type != 5)
dosboot.PT1[i] = dosboot.PT2[i];
biosdisk(3, 0x80, 0, 0, 1, 1, &dosboot);
}
/* 從 PT1 還原到 PT2 */
void recall_dos()
{
biosdisk(2, 0x80, 0, 0, 1, 1, &dosboot);
for (int i = 0; i < 4; i++)
if (dosboot.PT1[i].Type != 0) {
dosboot.PT2[i] = dosboot.PT1[i];
dosboot.PT1[i] = dosboot.PT[0]; /* 清空備份 */
}
biosdisk(3, 0x80, 0, 0, 1, 1, &dosboot);
}
/* 僅保留第 n 筆分區 (n=0..3) */
void change_dos(char n)
{
int idx = n - '1'; /* '1'→0, '2'→1... */
biosdisk(2, 0x80, 0, 0, 1, 1, &dosboot);
if (dosboot.PT1[idx].Type != 0) {
for (int i = 0; i < 4; i++)
if (dosboot.PT1[i].Type != 0)
dosboot.PT2[i] = dosboot.PT[0]; /* 全清零 */
dosboot.PT2[idx] = dosboot.PT1[idx]; /* 還原目標 */
dosboot.PT2[idx].Flag = 0x80; /* 設為啟動 */
}
biosdisk(3, 0x80, 0, 0, 1, 1, &dosboot);
}
FORMAT C: → PDOS S (Extended→PRI) → 重開機 FORMAT C: (原 C: 變 D:)。PDOS S → 重開機 FORMAT C:。PDOS C/S/R/1/2/3/4,錯誤操作直接破壞 MBR 導致全盤資料不可存取。此技術展示了對 x86 開機流程與磁碟結構的深度掌控,雖已成歷史,但「直接操作區塊裝置中繼資料」的思維在韌體開發、資料救援、惡意軟體分析等領域依然核心。