不同WINDOWS平臺下磁盤邏輯扇區的直接讀寫
來源:程序員人生 發布時間:2015-06-11 08:29:43 閱讀次數:2950次
不同WINDOWS平臺下磁盤邏輯扇區的直接讀寫 關鍵字:VWIN32、中斷、DeviceIoControl 1、概述 在DOS操作系統下,通過BIOS的INT13、DOS的INT25(絕對讀)、INT26(絕對寫)等功能調用實現對磁盤邏輯扇區或物理扇區的讀寫是很方便的,C語言中還有對應上述功能調用的函數:biosdisk、absread和abswrite等。但在WINDOWS操作系統下編寫WIN32利用程序時卻不再能直接使用上述的中斷調用或函數了。那末,在WINDOWS操作系統下能不能實現磁盤扇區的直接讀寫呢?如何實現磁盤扇區的讀寫呢?為了解決這些問題,筆者查閱了1些相干資料后發現,WINDOWS操作系統也提供了讀寫磁盤扇區的方法,只是在不同的版本中有著不同的方式和使用限制。最后,筆者編寫了1個磁盤扇區直接讀寫類,不敢獨專,特提供出來,希望能對大家有所幫助。 注:這里INT13表示INT 13H,其它類同。 2、1個讀取軟盤扇區的例子 WINDOWS操作系統對所有的存儲裝備實行了統1管理,而且為了安全起見,操作系統還不允許在WIN32利用程序(工作在Ring3級)中直接調用中斷功能,如INT13、INT21、INT25、INT26等。但它同時也提供了1些服務來彌補這類缺憾,在WIN95/98中,VWIN32服務就是其中1種。VWIN32服務是通過1個VXD來實現的,它提供了裝備IO功能,通過它,使用API函數DeviceIoControl即可以實現WIN32利用程序和磁盤裝備驅動程序間的通訊,從而實現對磁盤的存取。VWIN32提供的服務是1系列的控制命令字,它們實現諸如DOS操作系統下的INT13、INT25、INT26和INT21等功能調用。下面是它定義的1些控制命令字: VWIN32_DIOC_DOS_IOCTL (1) 實現INT21 功能 VWIN32_DIOC_DOS_INT25 (2) 實現INT25 功能 VWIN32_DIOC_DOS_INT26 (3) 實現INT26 功能 VWIN32_DIOC_DOS_INT13 (4) 實現INT13 功能 VWIN32_DIOC_DOS_DRIVEINFO (6) 實現INT21 730x 功能 如果要對磁盤進行讀寫,只要使用DeviceIoControl履行相應命令便可,下面的例子用來讀取軟盤的1個扇區(使用INT13): 第1步:打開VWIN32服務,HANDLE hDev=CreateFile("\.VWIN32",0,0,0,0,FILE_FLAG_DELETE_ON_CLOSE,NULL); 第2步:填充中斷所用到的相干寄存器。這里將寄存器放在1個結構中,結構定義以下(有關INT13使用的寄存器情況,請參閱相干資料): typedef struct INT13Regs{ PVOID buffer; // ebx 寄存器 BYTE Drive; // 磁
盤號 dl BYTE Head; //磁
頭號 dh WORD EDX_High; // edx 寄存器 BYTE Sector; //起
始扇區 cl BYTE Track; //磁
道號 ch WORD ECX_High; //ecx
寄存器 BYTE Number; //要
讀寫的扇取數 al BYTE CMD; //命
令:2--讀,3--寫,5--格式化 ah WORD EAX_High; //eax
寄存器 DWORD EDI; // edi 寄存器 DWORD ESI; // esi DWORD EFLAG; // flags }INT13_REGISTERS; unsigned char Buffer[512];//定義緩沖區,放置讀取扇區數據 INT13_REGISTERS reg={0};//定義寄存器結構變量 reg.buffer =(void *)Buffer; reg.Drive =0;//0-軟盤A 1-軟盤B 0x80-硬盤c reg.Head =0; reg.Track=0; reg.Sector=1; reg.Number=1; reg.CMD=2; //讀
取 第3步:調用裝備IO API函數DeviceIoControl履行4號命令(即VWIN32_DIOC_DOS_INT13), BOOL b_ret=DeviceIoControl(hDev,4,®,sizeof(INT13_REGISTERS),®,sizeof(INT13_REGISTERS),&lpRet,0); 如果其返回值不等于零,調用成功,進1步處理....否則調用失敗。 第4步:關閉服務,CloseHandle(hDev); 3、限制或局限 上面是使用INT13讀取軟盤扇區的完全步驟,在WIN95/98下它是可以工作的。那末,是不是將上面的寄存器結構中的Drive置為0x80就能夠讀取邏輯硬盤C盤的扇區了呢?回答是不是定的。INT13用來存取硬盤的功能在WINDOWS中被疏忽了。另外,INT25、INT26雖然可以存取硬盤,但是它們不能工作在FAT32格式的硬盤上。下面的列表將詳細羅列與磁盤操作相干的中斷調用的限制情況(不特殊說明,指的是在WIN95/98操作系統下): 中斷功能 限制及使用情況 INT13 不可以讀寫硬盤,僅支持軟盤 INT25/INT26 不可以讀/寫FAT32硬盤,支持FAT12、FAT16 INT21(440DH⑷1H/61H) 不可用(文檔資料中說支持FAT12、FAT16、FAT32,實際上沒有實現) INT21(7305H) 可以讀寫軟盤、硬盤,支持FAT12、FAT16、FAT32,但要求WIN95OSR2及以后版本 值得1提的是上表中的INT21-⑺305H功能是專門提供用來支持FAT32的,并且用來替換INT25/INT26,對應的控制命令字是6(即VWIN32_DIOC_DOS_DRIVEINFO),它和INT13、INT25、INT26等中斷功能的1個顯著區分是:它不使用寄存器來傳遞參數(INT21-⑷40DH⑷1H/61H類同),而是使用1個稱為DISKIO的結構,寄存器EBX用來保存指向該結構的地址。DISKIO的定義以下: typedef struct _DISKIO { DWORD dwStartSector; // 要讀寫的起始扇區號 WORD wSectors; // 要讀寫的扇區數 DWORD dwBuffer; // 用來保存讀/寫數據的緩沖區 }DISKIO, * PDISKIO; 另外,在使用該功能時還需要特別設置1些寄存器,如ECX必須為⑴,用ESI來表示讀寫。下面的例子是使用該功能來實現上面的例子功能,即讀軟盤A的1個扇區。首先定義1個新的寄存器結構供本例使用: typedef struct _DIOC_REGISTERS{ DWORD EBX; DWORD EDX; DWORD ECX; DWORD EAX; DWORD EDI; DWORD ESI; DWORD Flags; }DIOC_REGISTERS; 其實該結構和上面的INT13_REGISTERS是1樣的,只不過INT13_REGISTERS將寄存器細分開了,可讀性更強些。本例從步驟上說和上面的例子相同,只有寄存器設置1步在內容上有差異。 第1步:打開VWIN32服務。 第2步:設置寄存器。 DIOC_REGISTERS reg = {0}; DISKIO dio; unsigned char Buffer[512]; //設
置參數結構 dio.dwStartSector = 0;//注意:和上例不同,不是1,從0開始編號 dio.wSectors = 1; dio.dwBuffer = (DWORD)Buffer; //設
置寄存器 reg.EAX = 0x7305; //功
能上類似于INT25,絕對讀 reg.EBX = (DWORD)&dio;//參數結構的地址 reg.ECX = ⑴;//必須是⑴ reg.EDX = 1; //注
意:和上例不同,驅動器編號變了,0--缺省 1--A、2--B、3--C reg.ESI = 0; //ESI
的bit0表示讀寫,0--讀、1--寫 在寫狀態時SI的bit1--bit12,bit15必須是0,bit13、bit14、bit15共同來表示所寫數據的類型,具體見下表: 15 14 13 類型描寫 0 0 0 其它或不知道. 0 0 1 FAT數據 0 1 0 目錄數據 0 1 1 1般數據 1 x x 保存。bit15必須是0 第3步:調用API。BOOL b_ret=DeviceIoControl(hDev,6,®, sizeof(DIOC_REGISTERS),®,sizeof(DIOC_REGISTERS),&cb,0); 第4步:關閉服務。 可以發現,兩種方法讀到的數據完全1致。 4、WIN2000中的磁盤扇區讀寫 在WINNT和WIN2000中磁盤被看作1種標準裝備,可使用CreateFile象打開文件1樣打開并存取。CreateFile支持兩種方式的磁盤裝備--邏輯磁盤(格式為".C:")和物理磁盤(格式為".PHYSICALDRIVEx",其中x為數字),例如打開A:盤進行讀取操作,只要這樣: HANDLE hDev=CreateFile("\.A:",GENERIC_READ,FILE_SHARE_WRITE,0,OPEN_EXISTING,0,0); 如果得到的句柄有效,就能夠使用ReadFile來讀取了, ReadFile(hDev,Buffer,512,&dwRet,0); 讀取結束要關閉該句柄, CloseHandle(hDev); 這比WIN95/98下的磁盤扇區讀取方便多了。 另外,上面的例子是操作邏輯磁盤的,它包括軟驅、硬盤分區等;物理磁盤指的是實際的硬盤,它不關心該硬盤被分成幾個區,硬盤的編號是從0開始的,".PHYSICALDRIVE0"表示第1塊硬盤,其它依此類推。大家可能馬上會想起,利用這類機制可以對硬盤的分區表進行存取了。確切如此,此時即可以對硬盤的主引導扇區(獨立存在的1個扇區,包括分區表信息,不同于磁盤分區的BOOT區)進行操作了。 unsigned char Buffer[512]={0}; HANDLE hDev=CreateFile("\.PHYSICALDRIVE0",GENERIC_WRITE,FILE_SHARE_WRITE,0,OPEN_EXISTING,0,0); WriteFile(hDev,Buffer,512,&dwRet,0); CloseHandle(hDev); 危險!!!千萬別這么做!!! 5、1個自適應的磁盤讀寫類 由上面的例子可以看出,不同的操作系統下對磁盤扇區的讀寫有不同的方式,為了能夠在各類操作系統下能夠使用統1的方法讀寫磁盤扇區,特設計了1個通用類。該類的設計思想以下:首先編寫各類操作系統下的磁盤扇區存取函數,然后通過GetVersionEx來判斷操作系統,進而選取對應的函數來實現磁盤扇區的讀寫。由上面的分析可知,WINDOWS操作系統對INT13的支持是最差的,所以在這里只使用INT25、INT26、INT21-⑺305等中斷調用來實現。類的定義以下: class CDiskInfo{ public: CDiskInfo(); ~CDiskInfo(); private: HANDLE hDev; DWORD dwCurrentPlatform; void GetPlatform(); //取
得操作系統,并存入變量dwCurrentPlatform BOOL Win2000_AccessSectors(WORD CMD,BYTE bDrive,DWORD dwStartSector,WORD wSectors,LPBYTE lpSectBuff);//用于WIN2000、WINNT等操作系統, BOOL Int25_ReadSectors(BYTE bDrive,DWORD dwStartSector,WORD wSectors,LPBYTE lpSectBuff); BOOL Int26_WriteSectors(BYTE bDrive,DWORD dwStartSector,WORD wSectors,LPBYTE lpSectBuff);//用于WIN95之前的操作系統 BOOL Int21_AccessSectors(WORD CMD,BYTE bDrive,DWORD dwStartSector,WORD wSectors,LPBYTE lpSectBuff);//7305功能實現,用于WIN95OSR2、WIN98等操作系統 public: //對
外統1提供Read和Write操作,類內部根據平臺選用合適的函數調用 BOOL ReadSectors(BYTE bDrive,DWORD dwStartSector,WORD wSectors,LPBYTE lpSectBuff); BOOL WriteSectors(BYTE bDrive,DWORD dwStartSector,WORD wSectors,LPBYTE lpSectBuff); }; 該類對外提供了兩個接口,即ReadSectors和WriteSectors,其參數是1樣的,分別是要讀寫的磁盤編號bDrive,要存取磁盤的開始扇區號dwStartSector,要讀取的扇區數wSectors和讀寫扇區數據的緩沖區lpSectBuff。這里磁盤編號是從1開始的,即1代表A:,2代表B:,3代表C:,依此類推。扇區的編號從0開始。使用時也很簡單,只要作以下聲明便可: BYTE Buffer[1024]; CDiskInfo A; BOOL bRet=A.ReadSectors(1,0,2,Buffer); 詳細情況見附帶的類文件及測試程序。 6、補充說明 嚴格來講,在對磁盤進行讀寫時,應當遵守以下順序:打開裝備(WIN95/98下為VWIN32服務,WIN2000下為磁盤裝備)、鎖卷、驗證卷的有效性、讀/寫、開鎖卷、關閉裝備。這里為了描寫上的簡潔,疏忽了鎖卷/開鎖卷及驗證有效性等操作。有興趣的朋友可以自行添加。 另外,該類僅實現了邏輯驅動器的讀寫,要想實現諸如對物理硬盤的主引導扇區的讀寫,還需要其它技術,如thunk技術,即編寫兩個動態庫,1個是WIN32動態庫,1個是WIN16動態庫(thunk技術只可以用動態庫實現),其中WIN16動態庫轉到DPMI模式,調用INT13(或擴大INT13)來實現物理磁盤扇區的讀寫。有關thunk技術請參閱相干文檔資料。 所有的例子在WIN98、WIN2000操作系統、VC6集成環境下調試通過。
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
------分隔線----------------------------
------分隔線----------------------------