实战DeviceIoControl 之七:在Windows 9X中读写磁盘扇区
来源:互联网 发布:淘宝店铺红包链接地址 编辑:程序博客网 时间:2024/05/14 10:06
实战DeviceIoControl 共7篇,这是我在两年前看到的文章,很不错,现在想把它转载过来。
原作者和其博客的地址是:http://blog.csdn.net/bhw98
他博客里的这些序列文章的格式更好看,如果你觉得这些文章好,不妨去他的博客看,格式比我的随便粘贴好多了 :)
在Windows NT/2K/XP中,直接用CreateFile打开名称类似于"//./A:"的”文件”,就可以与设备驱动打交道,通过ReadFile/WriteFile以绝对地址方式访问磁盘了。但Windows 9X不支持这样的简单方法。本文介绍一种在Windows 9X中实现磁盘直接访问的方法:利用系统的vwin32.vxd,通过DeviceIoControl调用DOS INT21 7305H与440DH功能来完成。该调用支持FAT12、FAT16和FAT32,适用于Windows 95 SR2以及更高版本。
先来了解一下DOS INT21 7305H功能的入口参数:
AX -- 功能号7305HDS:BX -- 读写扇区的信息结构CX -- 必须为-1DL -- 驱动器号: 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 -- 功能号440DHBH -- 锁的级别,0-3级,直接写扇区用1BL -- 驱动器号: 1=A:, 2=B:, 3=C:, ...CH -- 0x08CL -- 0x4ADX -- 0
AX -- 功能号440DHBL -- 驱动器号: 1=A:, 2=B:, 3=C:, ...CH -- 0x08CL -- 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 { DWORD 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 AbsDiskRead( 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 13Description000Other/Unknown.001FAT data.010Directory data.011Normal file data.100Reserved.
如果不按照上述值操作,尽管能够写成功,但系统无法自动完成相关功能,可能会导致FAT数据备份、驱动器数据压缩等方面的问题。
[相关资源]
- 实战DeviceIoControl 之七:在Windows 9X中读写磁盘扇区
- 实战DeviceIoControl 之七:在Windows 9X中读写磁盘扇区
- 实战DeviceIoControl 之七:在Windows 9X中读写磁盘扇区
- 实战DeviceIoControl 之七:在Windows 9X中读写磁盘扇区
- 实战DeviceIoControl 之七:在Windows 9X中读写磁盘扇区
- 实战DeviceIoControl 之七:在Windows 9X中读写磁盘扇区
- 实战DeviceIoControl 之七:在Windows 9X中读写磁盘扇区
- 实战DeviceIoControl 之七:在Windows 9X中读写磁盘扇区
- Windows物理磁盘扇区读写示例总结
- DeviceIoControl 直接从磁盘扇区读文件
- DeviceIoControl 直接从磁盘扇区读文件
- 直接读写磁盘扇区
- linux 读写磁盘扇区
- 不同WINDOWS平台下磁盘逻辑扇区的直接读写
- windows NT/2000读写物理,逻辑磁盘扇区
- 不同WINDOWS平台下磁盘逻辑扇区的直接读写
- 不同WINDOWS平台下磁盘逻辑扇区的直接读写
- 实战DeviceIoControl 之三:制作磁盘镜像文件
- android 移植 一 准备
- DataList实现分页,排序功能
- 实战DeviceIoControl 之五:列举已安装的存储设备
- 实战DeviceIoControl 之六:访问物理端口
- C#与C++谁更强?还是关公战秦琼
- 实战DeviceIoControl 之七:在Windows 9X中读写磁盘扇区
- Reapeter和DataList分页控件编写
- POSIX线程之属性篇
- JDBC编程步骤
- 什么是android
- java学习笔记1——JDK相关
- 《诗盗·燬仙》
- 短信分条
- 成年人必看的六个故事教你学会做人!