如何用INT25读取磁盘扇区?

trcd2000 2004-01-08 01:37:35
//我用Int13可以读取软盘上的内容,但用INT25却不能读取硬盘上的内容。原因可能是不知道如何用25号中断,(我用了INT13_REGISTERS 的内容赋值的,但不行。)
哪位能给个用INT25的例子?谢谢!!



Vc++下如何读取磁盘扇区!
---------------------------------------------------------------

参见:
http://www.csdn.net/develop/Read_Article.asp?Id=13507
其中主要内容如下:

二、一个读取软盘扇区的例子
WINDOWS操作系统对所有的存储设备实行了统一管理,而且为了安全起见,操作系统还不允许在WIN32应用程序(工作在Ring3级)中直接调用中断功能,如INT13、INT21、INT25、INT26等。但它同时也提供了一些服务来弥补这种缺憾,在WIN95/98中,VWIN32服务就是其中一种。VWIN32服务是通过一个VXD来实现的,它提供了设备IO功能,通过它,使用API函数DeviceIoControl便可以实现WIN32应用程序和磁盘设备驱动程序间的通信,从而实现对磁盘的存取。VWIN32提供的服务是一系列的控制命令字,它们实现诸如DOS操作系统下的INT13、INT25、INT26和INT21等功能调用。下面是它定义的一些控制命令字:
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执行相应命令即可,下面的例子用来读取软盘的一个扇区(使用INT13):
第一步:打开VWIN32服务,HANDLE hDev=CreateFile("\\\\.\\VWIN32",0,0,0,0,FILE_FLAG_DELETE_ON_CLOSE,NULL);
第二步:填充中断所用到的相关寄存器。这里将寄存器放在一个结构中,结构定义如下(有关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; //读取
第三步:调用设备IO API函数DeviceIoControl执行4号命令(即VWIN32_DIOC_DOS_INT13), BOOL b_ret=DeviceIoControl(hDev,4,®,sizeof(INT13_REGISTERS),®,sizeof(INT13_REGISTERS),&lpRet,0);
如果其返回值不等于零,调用成功,进一步处理....否则调用失败。
第四步:关闭服务,CloseHandle(hDev);

三、限制或局限
上面是使用INT13读取软盘扇区的完整步骤,在WIN95/98下它是可以工作的。那么,是否将上面的寄存器结构中的Drive置为0x80就可以读取逻辑硬盘C盘的扇区了呢?回答是否定的。INT13用来存取硬盘的功能在WINDOWS中被忽略了。另外,INT25、INT26虽然可以存取硬盘,但是它们不能工作在FAT32格式的硬盘上。下面的列表将详细列举与磁盘操作相关的中断调用的限制情况(不特殊说明,指的是在WIN95/98操作系统下):

中断功能 限制及使用情况

INT13 不可以读写硬盘,仅支持软盘
INT25/INT26 不可以读/写FAT32硬盘,支持FAT12、FAT16
INT21(440DH-41H/61H) 不可用(文档资料中说支持FAT12、FAT16、FAT32,实际上没有实现)
INT21(7305H) 可以读写软盘、硬盘,支持FAT12、FAT16、FAT32,但要求WIN95OSR2及以后版本

值得一提的是上表中的INT21--7305H功能是专门提供用来支持FAT32的,并且用来替换INT25/INT26,对应的控制命令字是6(即VWIN32_DIOC_DOS_DRIVEINFO),它和INT13、INT25、INT26等中断功能的一个显著区别是:它不使用寄存器来传递参数(INT21--440DH-41H/61H类同),而是使用一个称为DISKIO的结构,寄存器EBX用来保存指向该结构的地址。DISKIO的定义如下:
typedef struct _DISKIO {
DWORD dwStartSector; // 要读写的起始扇区号
WORD wSectors; // 要读写的扇区数
DWORD dwBuffer; // 用来保存读/写数据的缓冲区
}DISKIO, * PDISKIO;

另外,在使用该功能时还需要特别设置一些寄存器,如ECX必须为-1,用ESI来表示读写。下面的例子是使用该功能来实现上面的例子功能,即读软盘A的一个扇区。首先定义一个新的寄存器结构供本例使用:
typedef struct _DIOC_REGISTERS{
DWORD EBX;
DWORD EDX;
DWORD ECX;
DWORD EAX;
DWORD EDI;
DWORD ESI;
DWORD Flags;
}DIOC_REGISTERS;

其实该结构和上面的INT13_REGISTERS是一样的,只不过INT13_REGISTERS将寄存器细分开了,可读性更强些。本例从步骤上说和上面的例子相同,只有寄存器设置一步在内容上有差异。
第一步:打开VWIN32服务。
第二步:设置寄存器。
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)&//参数结构的地址
reg.ECX = -1;//必须是-1
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 x x 保留。bit15必须是0

第三步:调用API。BOOL b_ret=DeviceIoControl(hDev,6,®, sizeof(DIOC_REGISTERS),®,sizeof(DIOC_REGISTERS),&cb,0);
第四步:关闭服务。

可以发现,两种方法读到的数据完全一致。

四、WIN2000中的磁盘扇区读写
在WINNT和WIN2000中磁盘被看做一种标准设备,可以使用CreateFile象打开文件一样打开并存取。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"表示第一块硬盘,其它依此类推。大家可能马上会想起,利用这种机制可以对硬盘的分区表进行存取了。确实如此,此时便可以对硬盘的主引导扇区(独立存在的一个扇区,包含分区表信息,不同于磁盘分区的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);
...全文
223 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
trcd2000 2004-01-09
  • 打赏
  • 举报
回复
问题解决了,谢谢大家!
alphapiao 2004-01-08
  • 打赏
  • 举报
回复
通过vwin32.vxd的VWIN32_DIOC_DOS_INT13,可以调用BIOS功能,但它只支持软盘,而不支持硬盘
To work around this problem, Win32 applications must thunk to a Win16 DLL and have that DLL call the DOS Protected Mode Interface (DPMI) Simulate Real Mode Interrupt function to call Int 13h BIOS disk functions on hard disks. When you use DPMI to call Int 13h BIOS disk functions, you bypass BIOSXLAT.VXD and call the real-mode BIOS. Note that you cannot call DPMI from 32-bit code.
Win32程序如果需要调用int 13,win16的dll能调用DPMI(DOS保护模式接口)模拟实模式中断,从而能调用int 13h,当你使用DPMI来调用bios int 13的功能,你就越过了BIOSXLAT.VXD(因为BIOSXLAT.VXD不传递BIOS请求到从保护模式到V86模式),你不能调用DPMI从32位的代码.

int25读写硬盘只能对逻辑硬辑盘进行操作,不能对物理盘操作,而且写硬盘还需要lockvolume,所以真正读写硬盘,不是写vxd吧.
theone 2004-01-08
  • 打赏
  • 举报
回复
写的部分
/*------------------------------------------------------------------
WriteLogicalSectors (hDev, bDrive, dwStartSector, wSectors, lpSectBuff)

Purpose:
Writes sectors to a logical drive. Uses Int 26h

Parameters:
hDev
Handle of VWIN32

bDrive
The MS-DOS logical drive number. 1 = A, 2 = B, 3 = C, etc.

dwStartSector
The first logical sector to write

wSectors
The number of sectors to write

lpSectBuff
The caller-supplied buffer that contains the sector data

Return Value:
Returns TRUE if successful, or FALSE if failure.

Comments:
This function does not validate its parameters.
------------------------------------------------------------------*/
BOOL WriteLogicalSectors (HANDLE hDev,
BYTE bDrive,
DWORD dwStartSector,
WORD wSectors,
LPBYTE lpSectBuff)
{
BOOL fResult;
DWORD cb;
DIOC_REGISTERS reg = {0};
DISKIO dio = {0};

dio.dwStartSector = dwStartSector;
dio.wSectors = wSectors;
dio.dwBuffer = (DWORD)lpSectBuff;

reg.reg_EAX = bDrive - 1; // Int 26h drive numbers are 0-based.
reg.reg_EBX = (DWORD)&dio;
reg.reg_ECX = 0xFFFF; // use DISKIO struct

fResult = DeviceIoControl(hDev, VWIN32_DIOC_DOS_INT26,
®, sizeof(reg),
®, sizeof(reg), &cb, 0);

// Determine if the DeviceIoControl call and the write succeeded.
fResult = fResult && !(reg.reg_Flags & CARRY_FLAG);

return fResult;
}
yaolan1999 2004-01-08
  • 打赏
  • 举报
回复
#define FP_OFF(fp) ((WORD)((DWORD)fp & 0x0000FFFFl))
#define FP_SEG(fp) ((WORD)((DWORD)fp >> 16))
typedef struct
{
BYTE PacketSize; //must be 16
BYTE Reserved; //must be 0
int BlockCount;
DWORD Address;
DWORD dwSectorLow;
DWORD dwSectorHight;
}DISK_ADDR_PACKET;

void BiosRWDisk(long sectorlow, long sectorhigh, int nsector,
char *temp, unsigned char drivernumber,
unsigned char opType)
{
DISK_ADDR_PACKET packet;
int i, j;

if((opType != 0x42) && (opType != 0x43))
return;

packet.Address = temp;
packet.BlockCount = nsector;
packet.dwSectorHight = sectorhigh;
packet.dwSectorLow = sectorlow;
packet.PacketSize = 16;
packet.Reserved = 0;

i = FP_SEG(&packet);
j = FP_OFF(&packet);

_asm
{
push ax
push ds
mov ah, opType
mov al,0
mov dl, drivernumber
mov ds, i
mov si, j
int 13h
pop ds
pop ax
}

}
opType為0x42為讀,0x43為寫。sectorlow邏輯扇區低位。sectorhigh邏輯扇區高位。nsector
讀寫的扇區數。drivernumber一般為0x80,char *temp為讀入的緩沖區。讀一個扇區可定義為
char str[512].
我使用過沒問題。但在2000windows環境下的Dos不行。
trcd2000 2004-01-08
  • 打赏
  • 举报
回复
那写呢,怎么写啊,我在网上已经找到了读的方法
具体跟 theone()的相同,但用的是 21 (7305)的功能 但它附带的写扇区函数有问题啊,每次一运行写操作,就会弹出说什么“You are using a disk utility design for an old version of MS_DOS or Windows.
Your File May be Demaged if....”
这是怎么回事啊,我已经将reg_ESI置为0X6001了(6 表示一般数据 1 表示写,扇区的读写就这里不同)
我用的是Win98操作系统,读的是U盘(读软盘也不对,虽然没有那个错误提示框,DeviceIOControl的返回值也是1,但fResult = fResult && !(reg.reg_Flags & CARRY_FLAG);之后的返回值为0了)
救命啊
theone 2004-01-08
  • 打赏
  • 举报
回复
MSDN里的sample code

#include <windows.h>

#define VWIN32_DIOC_DOS_INT25 2
#define VWIN32_DIOC_DOS_INT26 3
#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;

#define CARRY_FLAG 1

#pragma pack(1)
typedef struct _DISKIO {
DWORD dwStartSector; // starting logical sector number
WORD wSectors; // number of sectors
DWORD dwBuffer; // address of read/write buffer
} DISKIO, * PDISKIO;
#pragma pack()

/*------------------------------------------------------------------
ReadLogicalSectors (hDev, bDrive, dwStartSector, wSectors, lpSectBuff)

Purpose:
Reads sectors from a logical drive. Uses Int 25h.

Parameters:
hDev
Handle of VWIN32

bDrive
The MS-DOS logical drive number. 1 = A, 2 = B, 3 = C, etc.

dwStartSector
The first logical sector to read

wSectors
The number of sectors to read

lpSectBuff
The caller-supplied buffer that will contain the sector data

Return Value:
Returns TRUE if successful, or FALSE if failure.

Comments:
This function does not validate its parameters.
------------------------------------------------------------------*/
BOOL ReadLogicalSectors (HANDLE hDev,
BYTE bDrive,
DWORD dwStartSector,
WORD wSectors,
LPBYTE lpSectBuff)
{
BOOL fResult;
DWORD cb;
DIOC_REGISTERS reg = {0};
DISKIO dio = {0};

dio.dwStartSector = dwStartSector;
dio.wSectors = wSectors;
dio.dwBuffer = (DWORD)lpSectBuff;

reg.reg_EAX = bDrive - 1; // Int 25h drive numbers are 0-based.
reg.reg_EBX = (DWORD)&dio;
reg.reg_ECX = 0xFFFF; // use DISKIO struct

fResult = DeviceIoControl(hDev, VWIN32_DIOC_DOS_INT25,
®, sizeof(reg),
®, sizeof(reg), &cb, 0);

// Determine if the DeviceIoControl call and the read succeeded.
fResult = fResult && !(reg.reg_Flags & CARRY_FLAG);

return fResult;
}
yaolan1999 2004-01-08
  • 打赏
  • 举报
回复
用int 13h的擴展功能0x42根據邏輯扇區可以讀到任意扇區,而不僅僅1024柱面以內。
yaolan1999 2004-01-08
  • 打赏
  • 举报
回复
說一下0x80不是硬盘c而是操作系統讀到的第一塊硬盤。在Dos環境下int 13h是能讀到硬盤的任意扇區的。

2,643

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 硬件/系统
社区管理员
  • 硬件/系统社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧