實戰DeviceIoControl 之七:在Windows 9X中讀寫磁碟扇區 (轉)
在 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(®s, 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 ®s, sizeof(regs), // 輸出資料緩衝區與長度 ®s, 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(®s, 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 ®s, sizeof(regs), // 輸出資料緩衝區與長度 ®s, 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(®s, 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 ®s, sizeof(regs), // 輸入資料緩衝區與長度 ®s, 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(®s, 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 ®s, sizeof(regs), // 輸入資料緩衝區與長度 ®s, 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資料、驅動器資料等方面的問題。
[相關資源]
首次釋出: -08-20
最後修訂: 2003-09-12
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-961038/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 讀寫硬碟扇區的C語言程式 (轉)硬碟C語言
- Linux下4KB扇區磁碟實用指南Linux
- DeviceIoControl介面(轉)dev
- 寫作業系統之開發引導扇區作業系統
- kubebuilder實戰之七:webhookUIWebHook
- 在Linux下使用DOS/Windows磁碟(轉)LinuxWindows
- Windows下磁碟只讀Windows
- 思考與總結:扇區和磁碟塊的區別是什麼
- ShardingSphere(七) 讀寫分離配置,實現分庫讀寫操作
- win10風扇轉速怎麼調節 windows10中控制風扇轉速設定方法Win10Windows
- LINUX和WINDOWS之間的磁碟共享(轉)LinuxWindows
- Nancy簡單實戰之NancyMusicStore(六):寫在最後NaN
- Flink實戰(七) - Time & Windows程式設計Windows程式設計
- 小寫轉大寫金額在C++中的實現 (轉)C++
- 寫在《機器學習實戰》上市之前機器學習
- JavaScript逆向之七麥資料實戰JavaScript
- NTFS磁碟格式讀寫工具:Tuxera NTFS 2021 for Mac NTFS磁碟格式讀寫工具UXMac
- ASR專案實戰-任務佇列在檔案轉寫特性中的應用佇列
- 航圖中的扇區資料生成
- 在Linux中設定磁碟限額(轉)Linux
- socket 實現的 web 伺服器在 Windows 下的讀寫問題Web伺服器Windows
- OpenFaaS實戰之七:java11模板解析Java
- [Docker 系列]docker 學習七,DockerFile 編寫和實戰Docker
- 【Docker 系列】docker 學習七,DockerFile 編寫和實戰Docker
- 國產NTFS 磁碟讀寫工具 - Omi NTFS磁碟專家 for MacMac
- Mac上NTFS磁碟格式讀寫工具Mac
- NTFS 助手 for Mac(讀寫NTFS磁碟工具)Mac
- 在VC中用OLE DB讀寫SQL Server中的BLOB欄位 (轉)SQLServer
- 《Maven實戰》之讀書筆記Maven筆記
- flink實戰--讀寫Hive(Flink on Hive)Hive
- mysql讀寫分離實戰準備一MySql
- TiDB 在轉轉的業務實戰TiDB
- 專案實戰之gradle在實際專案中的使用Gradle
- 在Windows中玩轉Docker ToolboxWindowsDocker
- Linux與Windows之間的“冷戰”(轉)LinuxWindows
- 《鬼泣-巔峰之戰》亮相榮耀9X釋出會 現場大放異彩
- Java Thread實現讀寫同步 (轉)Javathread
- 用Delphi在區域網中實現網上影院 (轉)