分享
 
 
 

实战DeviceIoControl 之七:在Windows 9X中读写磁盘扇区

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

P.bhw98

{

PADDING-RIGHT: 0px;

PADDING-LEFT: 0px;

FONT-SIZE: 9pt;

PADDING-BOTTOM: 0px;

MARGIN: 10px 0px 5px;

LINE-HEIGHT: normal;

PADDING-TOP: 0px;

FONT-FAMILY: Verdana, Arial

}

PRE.bhw98

{

FONT-SIZE: 9pt;

PADDING-RIGHT: 5px;

PADDING-LEFT: 5px;

PADDING-BOTTOM: 5px;

MARGIN: 5px 0px;

LINE-HEIGHT: normal;

PADDING-TOP: 5px;

BACKGROUND-COLOR: #f0f0f0

}

PRE.diag

{

FONT-SIZE: 9pt;

PADDING-RIGHT: 5px;

PADDING-LEFT: 5px;

PADDING-BOTTOM: 5px;

MARGIN: 5px 0px;

LINE-HEIGHT: normal;

PADDING-TOP: 5px;

}

CODE.bhw98

{

FONT-SIZE: 9pt;

COLOR: #000000

}

TABLE.bhw98

{

BORDER-RIGHT: #808080 1px solid;

BORDER-TOP: #808080 1px solid;

FONT-SIZE: 9pt;

MARGIN: 3px 0px 10px;

BORDER-LEFT: #808080 1px solid;

LINE-HEIGHT: normal;

BORDER-BOTTOM: #808080 1px solid;

FONT-FAMILY: Verdana, Arial

}

TD.bhw98

{

BORDER-RIGHT: darkgray 1px solid;

PADDING-RIGHT: 10px;

BORDER-TOP: darkgray 1px solid;

PADDING-LEFT: 5px;

FONT-SIZE: 9pt;

PADDING-BOTTOM: 0px;

MARGIN: 0px;

BORDER-LEFT: darkgray 1px solid;

LINE-HEIGHT: normal;

PADDING-TOP: 3px;

BORDER-BOTTOM: darkgray 1px solid;

FONT-FAMILY: Verdana, Arial;

BACKGROUND-COLOR: #f0f0f0

}

STRONG.bhw98

{

FONT-WEIGHT: bolder;

FONT-SIZE: 20pt;

COLOR: #228b22;

FONT-STYLE: italic;

FONT-FAMILY: Verdana, Arial

}

LI.bhw98

{

FONT-SIZE: 9pt;

MARGIN: 3px 0px 0px 3px;

LINE-HEIGHT: normal;

FONT-FAMILY: Verdana, Arial

}

H1.bhw98

{

MARGIN-TOP: 25px;

FONT-WEIGHT: bolder;

FONT-SIZE: 12pt;

MARGIN-BOTTOM: 5px;

LINE-HEIGHT: normal;

FONT-FAMILY: Verdana, Arial

}

H2.bhw98

{

MARGIN-TOP: 20px;

FONT-WEIGHT: bolder;

FONT-SIZE: 10.5pt;

MARGIN-BOTTOM: 5px;

LINE-HEIGHT: normal;

FONT-FAMILY: Verdana, Arial

}

H3.bhw98

{

MARGIN-TOP: 15px;

FONT-WEIGHT: bolder;

FONT-SIZE: 9pt;

MARGIN-BOTTOM: 5px;

LINE-HEIGHT: normal;

FONT-FAMILY: Verdana, Arial

}

SPAN.key

{

COLOR: #0000ff

}

SPAN.num

{

COLOR: #800000

}

SPAN.str

{

COLOR: #8b008b

}

SPAN.rem

{

COLOR: #008000

}

在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(&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数据备份、驱动器数据压缩等方面的问题。

[相关资源]

bhw98的专栏:http://www.csdn.net/develop/author/netauthor/bhw98/

首次发布: 2003-08-20

最后修订: 2003-09-12

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有