本文转自: [url]http://blog.csdn.net/bhw98/archive/2003/09/12/19674.aspx[/url]
 
 
在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 -- 功能号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 {
    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 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数据备份、驱动器数据压缩等方面的问题。

[相关资源]

  • bhw98的专栏:[url]http://www.csdn.net/develop/author/netauthor/bhw98/[/url]
  • 职场 休闲 DeviceIoControl windows

    0

    收藏

    上一篇:实战DeviceIoContro... 下一篇:×××与字符串的相互转换
    hello_world

    74篇文章,144W+人气,0粉丝

    关注

    Ctrl+Enter 发布

    发布

    取消

    推荐专栏更多

    带你玩转高可用

    前百度高级工程师的架构高可用实战

    共15章 | 曹林华

    ¥51.00 513人订阅
    订   阅
    负载均衡高手炼成记

    高并发架构之路

    共15章 | sery

    ¥51.00 587人订阅
    订   阅
    基于Python的DevOps实战

    自动化运维开发新概念

    共20章 | 抚琴煮酒

    ¥51.00 554人订阅
    订   阅
    网工2.0晋级攻略 ——零基础入门Python/Ansible

    网络工程师2.0进阶指南

    共30章 | 姜汁啤酒

    ¥51.00 1979人订阅
    订   阅
    全局视角看大型园区网

    路由交换+安全+无线+优化+运维

    共40章 | 51CTOsummer

    ¥51.00 2437人订阅
    订   阅

    猜你喜欢

    linux XFRM整体框架简单分析 linux send recv函数详解 磁盘性能指标--IOPS、吞吐量及测试 MBR与GPT分区格式(实例-创建大于2TB的分区) 用UltraISO制作U盘启动盘,支持windows 7 linux磁盘分区fdisk命令详解 Linux文件系统只读Read-only file system 用Java写算法之五:快速排序 体验vSphere 6之5-添加虚拟交换机及iSCSI存储 DELL服务器 RAID 配置详解 Linux 查看磁盘分区、文件系统、使用情况的命令和相关工具介绍 Raid 0 1 5 10的原理、特点、性能区别 基于IIS的OA网站监控及自动重启脚本 WINDOWS程序监控及故障自动重启思路及bat脚本实现 Cirtix Workspace Environment Management环境搭建。 虚拟机关机,强制关闭任务的方法 Zabbix 上Windows性能监控 该有的矜持---域控CPU长期飙60-80%问题源头确认过程 Windows server 2016 搭建RDS服务 Windows 设置 VMware workstation 虚拟机开机启动

    扫一扫,领取大礼包

    0

    分享
    实战DeviceIoControl 之七:在Windows 9X中读写磁盘扇区_第2张图片
    关注
    hello_world