博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
实战DeviceIoControl 之七:在Windows 9X中读写磁盘扇区
阅读量:5972 次
发布时间:2019-06-19

本文共 8385 字,大约阅读时间需要 27 分钟。

在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 -- 0AX -- 功能号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(&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 15 Bit 14 Bit 13 Description
0 0 0 Other/Unknown.
0 0 1 FAT data.
0 1 0 Directory data.
0 1 1 Normal file data.
1 0 0 Reserved.
如果不按照上述值操作,尽管能够写成功,但系统无法自动完成相关功能,可能会导致FAT数据备份、驱动器数据压缩等方面的问题。

转载地址:http://rhfox.baihongyu.com/

你可能感兴趣的文章
DTS-077100 向目标库同步数据时出错
查看>>
并行执行 Job - 每天5分钟玩转 Docker 容器技术(134)
查看>>
数据库的检索(20)
查看>>
rsync深度实战
查看>>
Python直接用字典数组导入到函数的非固定参数
查看>>
How China's Developers Are Defining The Information Age (Infographic 2)
查看>>
Python函数基础(day3)
查看>>
SaxReader读取,更新xml文件
查看>>
linux下软链接与硬链接
查看>>
Java线程:线程中断
查看>>
tomcat学习随笔
查看>>
注重产品与解决方案 看“互联网+”时代脚踏实地的百度
查看>>
saltstack 的基本讲解
查看>>
8.4 类的重写
查看>>
C# 如何实现简单的Socket通信(附示例)
查看>>
logstash通过rsyslog对nginx的日志收集和分析
查看>>
浅谈框架与模式的关系
查看>>
高校学生信息管理系统C#窗体版更新(一)
查看>>
无线路由器的配置实例
查看>>
windows 2008 终端服务网关配置笔记
查看>>