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

Windows 底層磁碟存取:從 DOS 中斷到 DeviceIoControl 的演進與實作

     編輯:VC 教學

前言:跨越時代的磁碟存取技術

從 DOS 時代的 BIOS 中斷 INT 13h 到 Windows NT 核心的 DeviceIoControl,磁碟底層存取方式經歷了從實模式到保護模式、從特權指令直接執行到受管核心物件的根本變革。本文對比兩種時代的程式碼實作,解析 Windows 如何封裝硬體操作並提供安全的介面。


DOS 時代:直接操作硬體的 INT 13h

在實模式下,程式擁有完整硬體控制權。讀取開機磁區 (Cylinder 0, Head 0, Sector 1) 典型程式碼:

char buffer[512];
regs.x.dx = 0;              // 驅動器 A: (0=軟碟, 0x80=硬碟)
regs.x.cx = 0x0001;         // 柱面 0, 扇區 1 (CH=0, CL=1)
regs.x.bx = FP_OFF(buffer); // 緩衝區偏移
regs.es = FP_SEG(buffer);   // 緩衝區段地址
regs.x.ax = 0x0201;         // AH=02h 讀取, AL=01h 扇區數
int86x(0x13, ®s, ®s, &sregs); // 呼叫 BIOS 中斷

關鍵點: 直接設定暫存器、分段地址轉換 (FP_OFF/FP_SEG)、攜帶旗標暫存器 (CF=進位旗標表示錯誤)。程式碼簡潔但極度危險,任意存取可破壞檔案系統。


Windows NT 核心:受保護的 DeviceIoControl 模型

Windows 禁止使用者模式直接執行特權指令或存取 I/O 埠。所有硬體操作必須透過核心模式驅動程式,使用者模式以 DeviceIoControl 發送控制碼 (IOCTL) 請求核心代為執行。

核心資料結構:DIOC_REGISTERS

模擬 x86 暫存器組,用於傳遞 INT 13h 參數給 VWIN32 虛擬裝置驅動程式 (VxD):

#pragma pack(push, 1)
typedef struct _DIOC_REGISTERS {
    DWORD reg_ebx;
    DWORD reg_edx;
    DWORD reg_ecx;
    DWORD reg_eax;
    DWORD reg_edi;
    DWORD reg_esi;
    DWORD reg_flags;  // 包含 CF (Carry Flag)
} DIOC_REGISTERS;
#pragma pack(pop)

完整操作流程:開啟 VWIN32 → 重置磁碟 → 尋軌 → 讀取扇區

// 1. 開啟 VWIN32 虛擬裝置
HANDLE hDevice = CreateFile("\\\\.\\VWIN32", 0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, NULL);
if (hDevice == INVALID_HANDLE_VALUE) return FALSE;

// 2. 重置磁碟控制器 (INT 13h AH=00h)
DIOC_REGISTERS reg = {0};
reg.reg_eax = 0x0000;           // 功能碼: 重置
reg.reg_edx = driveNumber;      // 驅動器號
reg.reg_flags = 0x0001;         // 預設 CF=1 (假設錯誤)
DWORD cbReturned;
DeviceIoControl(hDevice, VWIN32_DIOC_DOS_INT13, ®, sizeof(reg), ®, sizeof(reg), &cbReturned, NULL);

// 3. 磁頭定位 (INT 13h AH=0Ch)
reg.reg_eax = 0x0C00;           // 功能碼: 尋軌
reg.reg_ecx = (cylinder << 8) | sector;   // CH=柱面, CL=扇區
reg.reg_edx = (head << 8) | driveNumber;  // DH=磁頭, DL=驅動器
DeviceIoControl(hDevice, VWIN32_DIOC_DOS_INT13, ®, sizeof(reg), ®, sizeof(reg), &cbReturned, NULL);

// 4. 讀取扇區 (INT 13h AH=02h)
reg.reg_eax = 0x0200 | sectorCount; // AH=02h 讀取, AL=扇區數
reg.reg_ecx = (cylinder << 8) | sector;
reg.reg_edx = (head << 8) | driveNumber;
reg.reg_ebx = (DWORD)buffer;        // 緩衝區線性地址 (保護模式下為平坦地址)
DeviceIoControl(hDevice, VWIN32_DIOC_DOS_INT13, ®, sizeof(reg), ®, sizeof(reg), &cbReturned, NULL);

if (!cbReturned || (reg.reg_flags & 0x0001)) {
    // CF=1 表示錯誤
    // 錯誤碼在 reg.reg_eax 低位元組 (AH)
}

關鍵差異深度解析

維度 DOS INT 13h Windows DeviceIoControl
執行模式 實模式 (Ring 0),直接特權指令 使用者模式 (Ring 3) → 核心模式 (Ring 0) 切換
記憶體定址 分段地址 (Segment:Offset),需 FP_OFF/FP_SEG 轉換 32/64 位元平坦線性地址,直接使用緩衝區指標
參數傳遞 CPU 暫存器 (AH/AL/CH/CL/DH/DL/ES:BX) 結構體 DIOC_REGISTERS 模擬暫存器
錯誤處理 旗標暫存器 CF (Carry Flag),AH=錯誤碼 回傳值 FALSE + GetLastError(),或結構體 reg_flags CF 位
安全性 無保護,可任意讀寫實體磁碟 需管理員權限,受物件管理器 DACL 控制,可被防毒軟體攔截
適用場景 開機載入器、磁碟工具、病毒 (MBR 感染) 磁碟備份軟體、分割區管理、取證工具、惡意軟體分析

現代 Windows 開發建議

  1. 優先使用高層 API: CreateFile 開啟 \\.\PhysicalDriveN 或 \\.\X:,配合 ReadFile/WriteFile + SetFilePointerEx 進行邏輯扇區存取,自動處理檔案系統鎖定與快取一致性。
  2. IOCTL 直接控制: 僅在需要繞過檔案系統 (如讀取 MBR/GPT、SMART 資料、廠商特定指令) 時使用 IOCTL_DISK_*、IOCTL_STORAGE_* 等標準控制碼。
  3. 權限最小化: 應用程式清單 (Manifest) 宣告 requireAdministrator,避免全域提權。
  4. 64 位元相容: 結構體對齊、指標寬度、DWORD vs ULONG_PTR 需嚴格區分,使用 #pragma pack 確保跨編譯器一致。

總結

從 INT 13h 到 DeviceIoControl,不僅是 API 風格變更,更反映了作業系統從「信任程式」到「不信任程式、核心仲裁一切」的安全哲學演進。理解這段歷史,有助於在維護舊系統、開發安全工具、分析惡意程式碼時做出正確技術判斷。

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