實戰DeviceIoControl 之七:在Windows 9X中讀寫磁碟扇區 (轉)

worldblog發表於2007-08-16
實戰DeviceIoControl 之七:在Windows 9X中讀寫磁碟扇區 (轉)[@more@]

在 NT/2K/XP中,直接用CreateFile開啟名稱類似於".A:"的””,就可以與裝置打交道,透過ReadFile/WriteFile以絕對地址方式訪問了。但Windows 9X不支援這樣的簡單方法。本文介紹一種在Windows 9X中實現磁碟直接訪問的方法:利用的v.vxd,透過DeviceIoControlDINT21 7305H與440DH功能來完成。該呼叫支援12、FAT16和FAT32,適用於Windows 95 SR2以及更高版本。

先來了解一下DOS INT21 7305H功能的入口引數:

AX -- 功能號7305H DS:BX -- 讀寫扇區的資訊結構 CX -- 必須為-1 DL -- 驅動器號: 1=A:, 2=B:, 3=C:, ... SI -- 讀寫標誌: 最低位0=讀, 1=寫


若呼叫成功,清除C標誌;否則設定C標誌。

DS:BX指向一個結構,此結構定義如下:

DISKIO STRUC dwStartSector dd ? ; 起始扇區 wSector dw ? ; 扇區數 lpBuffer dd ? ; 資料緩衝區地址 DISKIO ENDS


在寫操作下,需要“鎖定”驅動器。DOS INT21 440DH的4AH/6AH功能可實現邏輯驅動器的加鎖/解鎖。其入口引數為:

AX -- 功能號440DH BH -- 鎖的級別,0-3級,直接寫扇區用1 BL -- 驅動器號: 1=A:, 2=B:, 3=C:, ... CH -- 0x08 CL -- 0x4A DX -- 0


AX -- 功能號440DH BL -- 驅動器號: 1=A:, 2=B:, 3=C:, ... CH -- 0x08 CL -- 0x6A


以上兩個呼叫,若呼叫成功,清除C標誌;否則設定C標誌。

透過IOCTL碼VWIN32_DIOC_DOS_DRIVEINFO等呼叫上述中斷。實現絕對磁碟讀寫的關鍵程式碼如下:

// INT21的IOCTL碼 #define VWIN32_DIOC_DOS_IOCTL 1 #define VWIN32_DIOC_DOS_DRIVEINFO 6 // 暫存器組 typedef struct _DIOC_REGISTERS { D reg_EBX; DWORD reg_EDX; DWORD reg_ECX; DWORD reg_EAX; DWORD reg_EDI; DWORD reg_ESI; DWORD reg_Flags; } DIOC_REGISTERS, *PDIOC_REGISTERS; // IO引數(注意位元組對齊方式) #pragma pack(1) typedef struct _DISKIO { DWORD dwStartSector; // 起始扇區 WORD wSectors; // 扇區數 void* pBuffer; // 緩衝區指標 } DISKIO, *PDISKIO; #pragma pack() BOOL AiskRead( BYTE nDiskNumber, // 盤號, 1=A:, 2=B:, 3= C:, ... DWORD dwStartSector, // 起始扇區 WORD wSectors, // 扇區數 void* pBuffer) // 資料緩衝區指標 { HANDLE hDevice; DIOC_REGISTERS regs; DISKIO dio; DWORD dwOutBytes; BOOL bResult; // 開啟裝置,獲得VxD控制程式碼 hDevice = CreateFile("\.vwin32", // 裝置路徑 GENERIC_READ | GENERIC_WRITE, // 讀寫方式 FILE_SHARE_READ | FILE_SHARE_WRITE, // 共享方式 NULL, // 預設的描述符 OPEN_EXISTING, // 建立方式 FILE_ATTRIBUTE_NORMAL, // 檔案屬性 NULL); // 不需參照模板檔案 if(hDevice == INVALID_HANDLE_VALUE) { return FALSE; } // 填充DISKIO引數結構 dio.dwStartSector = dwStartSector; dio.wSectors = wSectors; dio.pBuffer = pBuffer; // 填充暫存器組--中斷入口引數 memset(&regs, 0, sizeof(DIOC_REGISTERS)); regs.reg_EAX = 0x7305; // AX=0x7305 regs.reg_EBX = (DWORD)&dio; // EBX=DS:BX=引數指標 regs.reg_ECX = 0xffff; // CX=-1 regs.reg_EDX = nDiskNumber; // DL=盤號 regs.reg_ESI = 0; // SI=0 -- 讀操作 // 用VWIN32_DIOC_DOS_DRIVEINFO讀磁碟 dwOutBytes = 0; bResult = DeviceIoControl(hDevice, // 裝置控制程式碼 VWIN32_DIOC_DOS_DRIVEINFO, // INT21 &regs, sizeof(regs), // 輸出資料緩衝區與長度 &regs, sizeof(regs), // 輸出資料緩衝區與長度 &dwOutBytes, // 輸出資料長度 NULL); // 用同步I/O // 確定DeviceIoControl與INT21都無錯誤 bResult = bResult && !(regs.reg_Flags & 1); CloseHandle(hDevice); return bResult; } BOOL AbsDiskWrite( BYTE nDiskNumber, // 盤號, 1=A:, 2=B:, 3= C:, ... DWORD dwStartSector, // 起始扇區 WORD wSectors, // 扇區數 void* pBuffer) // 資料緩衝區指標 { HANDLE hDevice; DIOC_REGISTERS regs; DISKIO dio; DWORD dwOutBytes; BOOL bResult; // 開啟裝置,獲得VxD控制程式碼 hDevice = CreateFile("\.vwin32", // 裝置路徑 GENERIC_READ | GENERIC_WRITE, // 讀寫方式 FILE_SHARE_READ | FILE_SHARE_WRITE, // 共享方式 NULL, // 預設的安全描述符 OPEN_EXISTING, // 建立方式 FILE_ATTRIBUTE_NORMAL, // 檔案屬性 NULL); // 不需參照模板檔案 if(hDevice == INVALID_HANDLE_VALUE) { return FALSE; } // 填充DISKIO引數結構 dio.dwStartSector = dwStartSector; dio.wSectors = wSectors; dio.pBuffer = pBuffer; // 填充暫存器組--中斷入口引數 memset(&regs, 0, sizeof(DIOC_REGISTERS)); regs.reg_EAX = 0x7305; // AX=0x7305 regs.reg_EBX = (DWORD)&dio; // EBX=DS:BX=引數指標 regs.reg_ECX = 0xffff; // CX=-1 regs.reg_EDX = nDiskNumber; // DL=盤號 regs.reg_ESI = 0x6001; // SI=0x6001 -- 普通寫操作 // 用VWIN32_DIOC_DOS_DRIVEINFO寫磁碟 dwOutBytes = 0; bResult = DeviceIoControl(hDevice, // 裝置控制程式碼 VWIN32_DIOC_DOS_DRIVEINFO, // INT21 &regs, sizeof(regs), // 輸出資料緩衝區與長度 &regs, sizeof(regs), // 輸出資料緩衝區與長度 &dwOutBytes, // 輸出資料長度 NULL); // 用同步I/O // 確定DeviceIoControl與INT21都無錯誤 bResult = bResult && !(regs.reg_Flags & 1); CloseHandle(hDevice); return bResult; } BOOL LockVolume( BYTE nDiskNumber) // 盤號, 1=A:, 2=B:, 3=C:, ... { HANDLE hDevice; DIOC_REGISTERS regs; DWORD dwOutBytes; BOOL bResult; // 開啟裝置,獲得VxD控制程式碼 hDevice = CreateFile("\.vwin32", // 裝置路徑 GENERIC_READ | GENERIC_WRITE, // 讀寫方式 FILE_SHARE_READ | FILE_SHARE_WRITE, // 共享方式 NULL, // 預設的安全描述符 OPEN_EXISTING, // 建立方式 FILE_ATTRIBUTE_NORMAL, // 檔案屬性 NULL); // 不需參照模板檔案 if(hDevice == INVALID_HANDLE_VALUE) { return FALSE; } // 填充暫存器組--中斷入口引數 memset(&regs, 0, sizeof(DIOC_REGISTERS)); regs.reg_EAX = 0x440D; // AX=0x440D regs.reg_EBX = 0x0100 | nDiskNumber; // BH=鎖的級別,BL=盤號 regs.reg_ECX = 0x084A; regs.reg_EDX = 0; // 用VWIN32_DIOC_DOS_DRIVEINFO讀磁碟 dwOutBytes = 0; bResult = DeviceIoControl(hDevice, // 裝置控制程式碼 VWIN32_DIOC_DOS_IOCTL, // INT21 &regs, sizeof(regs), // 輸入資料緩衝區與長度 &regs, sizeof(regs), // 輸出資料緩衝區與長度 &dwOutBytes, // 輸出資料長度 NULL); // 用同步I/O // 確定DeviceIoControl與INT21都無錯誤 bResult = bResult && !(regs.reg_Flags & 1); CloseHandle(hDevice); return bResult; } BOOL UnlockVolume( BYTE nDiskNumber) // 盤號, 1=A:, 2=B:, 3=C:, ... { HANDLE hDevice; DIOC_REGISTERS regs; DWORD dwOutBytes; BOOL bResult; // 開啟裝置,獲得VxD控制程式碼 hDevice = CreateFile("\.vwin32", // 裝置路徑 GENERIC_READ | GENERIC_WRITE, // 讀寫方式 FILE_SHARE_READ | FILE_SHARE_WRITE, // 共享方式 NULL, // 預設的安全描述符 OPEN_EXISTING, // 建立方式 FILE_ATTRIBUTE_NORMAL, // 檔案屬性 NULL); // 不需參照模板檔案 if(hDevice == INVALID_HANDLE_VALUE) { return FALSE; } // 填充暫存器組--中斷入口引數 memset(&regs, 0, sizeof(DIOC_REGISTERS)); regs.reg_EAX = 0x440D; // AX=0x440D regs.reg_EBX = nDiskNumber; // BL=盤號 regs.reg_ECX = 0x086A; // 用VWIN32_DIOC_DOS_DRIVEINFO讀磁碟 dwOutBytes = 0; bResult = DeviceIoControl(hDevice, // 裝置控制程式碼 VWIN32_DIOC_DOS_IOCTL, // INT21 &regs, sizeof(regs), // 輸入資料緩衝區與長度 &regs, sizeof(regs), // 輸出資料緩衝區與長度 &dwOutBytes, // 輸出資料長度 NULL); // 用同步I/O // 確定DeviceIoControl與INT21都無錯誤 bResult = bResult && !(regs.reg_Flags & 1); CloseHandle(hDevice); return bResult; }


下面的例子,從A盤的0扇區開始,讀取10個扇區的資料,並儲存在檔案中:

unsigned char buf[512 * 10]; if (AbsDiskRead(1, 0, 10, buf)) { FILE* fp = fopen("a.dat", "w+b"); fwrite(buf, 512, 10, fp); fclose(fp); }


下面的例子,讀取D驅動器的第8888扇區,然後寫回去:

unsigned char buf[512]; LockVolume(4); if (AbsDiskRead(4, 8888, 1, buf)) { ... ... if (AbsDiskWrite(4, 8888, 1, buf)) { ... ... } } UnlockVolume(4);


在寫方式下,SI暫存器的位0設定為1,位15-13在磁碟的不同區域需要有不同的值: Bit 15Bit 14Bit 13Description 000Other/Unknown. 001FAT data. 010Directory data. 011Normal file data. 100Reserved.

如果不按照上述值操作,儘管能夠寫成功,但系統無法自動完成相關功能,可能會導致FAT資料、驅動器資料等方面的問題。

 

[相關資源]

  • bhw98的專欄:/develop/author/netauthor/bhw98/">http://www.csdn.net/develop/author/netauthor/bhw98/

    首次釋出: -08-20
    最後修訂: 2003-09-12

     


  • 來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-961038/,如需轉載,請註明出處,否則將追究法律責任。

    相關文章