中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net 论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

中国DOS联盟论坛
现在时间是 2026-06-16 21:30
中国DOS联盟论坛 » DOS开发编程 & 发展交流 (开发室) » 扩展int13读取 MBR(硬盘主引导区)的原程序,端口读硬盘序列号 查看 8,048 回复 27
16 发表于 2006-07-02 05:30 ·  中国 上海 电信
金牌会员
★★★★
积分 4,639
发帖 2,239
注册 2005-01-30 00:00
UID 35785
性别 男
状态 离线
Originally posted by GOTOmsdos at 2006-6-30 20:41:
还发现个小奇怪:
在测试我的读写小硬盘的程序中,照理只能读写1023(3FF,1111111111)个柱面(0-1022)
但是,却能读写1024个柱面!

百思不得其蠮..

我也不理解你的用意,既然 int13h 扩展调用不再使用CHS参数了,你怎么知道能读写1024个柱面呢?(应该说是1024个柱面吧)难道你还换算过?
17 发表于 2006-07-02 17:47 ·  中国 湖北 宜昌 电信
高级用户
★★
积分 677
发帖 194
注册 2003-09-13 00:00
UID 9778
性别 男
状态 离线
Originally posted by GOTOmsdos at 2006-6-30 07:45 PM:
成功了!

另:
我不懂QB,不知道QB能不能一次就把地址取出来?

,qb45的代码中:
MKI$变量是不是可以从buffdat$中取出一个地址值就可以了?
下頮..


我的程序只是从原理上演示一下,只想能实现扩展INT13的读写,并没有做优化什么的,如果要精简,只有把MKI$(d2%) 改为MKI$(SADD(buffdat$)) 实际上没有什么大的意义,但表面上看确实少了两个变量!

我觉得编程中,做硬盘小工具是很有意思的,而且很有价值。

在486的电脑上,BIOS很老,不支持扩展INT13,所以不能读写大硬盘,但是很有意思,我们可以利用IO端口在486电脑上来实现读写137G以内容量的硬盘。

希望大家能互相研究研究!
18 发表于 2006-07-02 17:50 ·  中国 湖北 宜昌 电信
高级用户
★★
积分 677
发帖 194
注册 2003-09-13 00:00
UID 9778
性别 男
状态 离线
也不知道大家对端口读写硬盘感兴趣不
19 发表于 2006-07-02 18:16 ·  中国 湖南 长沙 电信
中级用户
★★
积分 282
发帖 126
注册 2006-05-17 22:29
UID 55724
状态 离线
Originally posted by qb45 at 2006-7-2 17:50:
也不知道大家对端口读写硬盘感兴趣不



极有兴趣!

找这方面资料找了很久了
人类存在的目的就是试图理解人类为何存在
20 发表于 2006-07-03 00:58 ·  中国 广东 中山 电信
高级用户
★★★
积分 972
发帖 420
注册 2004-05-16 00:00
UID 24467
性别 男
状态 离线
I/O方法, CIH里面似乎有用过
平生进退如飙风
21 发表于 2006-07-03 02:01 ·  中国 北京 联通
铂金会员
★★★★
C++启程者
积分 5,154
发帖 1,827
注册 2003-07-18 00:00
UID 7105
性别 男
状态 离线
Originally posted by DOSforever at 2006-7-2 05:30 AM:

我也不理解你的用意,既然 int13h 扩展调用不再使用CHS参数了,你怎么知道能读写1024个柱面呢?(应该说是1024个柱面吧)难道你还换算过?


对啊,这几天在研究硬盘读写,有以换算到极限进行测试的。。
22 发表于 2006-07-04 00:23 ·  中国 上海 虹口区 电信
高级用户
★★
积分 653
发帖 252
注册 2006-04-16 19:48
UID 53939
状态 离线
Originally posted by DOSforever at 2005-6-30 00:00:
多谢楼上的解答,按照你的方法果然能够成功的读取了!
但是一开始我所得到的资料中确实是写 DI 的,而且在该文中不止一处提到。以下是我找到的 ...


所以说这种技术规范一定要看官方标准的~~
23 发表于 2006-07-06 21:02 ·  中国 广东 中山 电信
高级用户
★★★
积分 972
发帖 420
注册 2004-05-16 00:00
UID 24467
性别 男
状态 离线
24 发表于 2006-07-09 10:56 ·  中国 湖北 宜昌 电信
高级用户
★★
积分 677
发帖 194
注册 2003-09-13 00:00
UID 9778
性别 男
状态 离线
获得硬盘序列号(原程序)
这是一个用端口对硬盘编程例子
本程序在必须在DOS下运行,我在qb4.5版本下运行通过

主板上共有两个IDE接口,每个接口上又分主、从,所以可以接4个IDE设备,这4个端口号各不同,本程序用端口1F0-1F7是主板上的第一个IDE接口上的主接口,最常用的就是这个了。别的只是端口号不一样,编程方法原理一样。

'获得硬盘序列号的程序(非逻辑盘卷标,有的把C盘的卷标说成是硬盘序列号)
'代码:QBASIC,运行环境:DOS

OUT &H1F6, &HA0
OUT &h1F2,1
OUT &H1F3, 1
OUT &h1F4,1
OUT &h1F5,1
OUT &H1F7, &HEC '获得硬盘信息的命令
DO WHILE flag <> &H58
f lag = INP(&H1F7)
if inkey$=chr$(27) then '如果按ESC键,终止程序
print "无法获得硬盘序列号"
end
end if
LOOP
re$ = SPACE$(18)
FOR i% = 1 TO 18
READ a$
H$ = CHR$(VAL("&H" + a$))
MID$(re$, i%, 1) = H$
NEXT i%
duan% = varSEG(re$):offe% = SADD(re$)
DEF SEG = duan%
print "本硬盘的序列号为 ";
FOR i = 1 TO 16
CALL Absolute(r%, offe%) '调用在qb中的内嵌汇编机器码
r1% = r% AND &HFF
r2% = (r% AND &HFF00) / &H100
IF i > 9 AND i < 15THEN PRINT CHR$(r1%); CHR$(r2%);
NEXT i
DEF SEG
END
'此DATA中的数据为机器码,用于读端口字数据(qb中的端口语句只能按字节读写端口,不能按字读写)
DATA 55,89,e5,ba,f0,01,ed,86,e0,8b,5e,06,89,07,5d,ca,02 ,00
25 发表于 2006-07-13 20:40 ·  中国 广东 广州 教育网
铂金会员
★★★★
C++启程者
积分 5,154
发帖 1,827
注册 2003-07-18 00:00
UID 7105
性别 男
状态 离线
支持QB45。。
26 也编了个扩展int13 读硬盘程序(在win98 下测试通过) 发表于 2008-10-27 19:13 ·  中国 江西 南昌 电信
新手上路
积分 12
发帖 5
注册 2007-09-11 16:10
UID 97111
性别 男
来自 山西省太原市小店区
状态 离线
//rdiskc.c
#include <stdio.h>
#include <math.h>
#include <alloc.h>
#include <string.h>
#ifndef NULL
#define NULL 0
#endif



typedef struct DiskAddressPacket{
char PacketSize;
char Reserved;
unsigned int BlockCount;
unsigned long BufferAddr;
int BlockNum[4];
}*DAP,DiskAddrPack;

extern void DREAD(DAP);

int main(int argc,char *argv[]){
int length,i=0,j=0,k=0,line=16;
unsigned char buffer[512];
DAP psi=(DAP)malloc(sizeof(DiskAddrPack));

if(argc==2&&!strcmp(argv[1],"/?")){
printf("\nbdexpen sector(0x,for 4 section) [line]\n\tline the line on show(must be 16 or 32)");
return 0;
}

if(argc!=5&&argc!=6)
return -1;

for(argv++,i=0;i<4;i++){
length=strlen(*argv);
if(length!=4)
return -2;

for(j=0;j<4;j++){
if((*argv)[j]>='0'&&(*argv)[j]<='9')
(*argv)[j]-='0';
else if((*argv)[j]>='a'&&(*argv)[j]<='f')
(*argv)[j]=(*argv)[j]-'a'+10;
else if((*argv)[j]>='A'&&(*argv)[j]<='F')
(*argv)[j]=(*argv)[j]-'A'+10;
else return -3;
}
psi->BlockNum[3-i]=(int)(*argv)[0]*16*16*16+(int)(*argv)[1]*16*16+(int)(*argv)[2]*16+(int)(*argv)[3];
argv++;
}



if(argc==6){
length=strlen(*argv);
for(j=0,k=0,line=0;j<length;){
if((*argv)[k]<48||(*argv)[k]>57)
return -4;
line+=((int)(*argv)[k++]-48)*(int)(pow(10,--length));
}
printf("%d\n",line);
if(line!=16&&line!=32)
line=16;
}


psi->PacketSize=16;
psi->Reserved=0;
psi->BlockCount=1;
psi->BufferAddr=(unsigned long)buffer;


DREAD(psi);

for(j=0;j<512/line;j++){
printf("%3x:",j*line);
for(k=0;k<line;k++){
printf("%4x",buffer[j*line+k]);
if(k==7||k==15&&line==32||k==23)
printf(" -");
}
printf("\t ");
for(k=0;k<line;k++){
if((buffer[j*line+k])<=128&&buffer[j*line+k]!='\n'&&buffer[j*line+k]!='\t')
printf("%c",buffer[j*line+k]);
else printf("\.");
}
printf("\n");
}
free(psi);
return 0;
}
//rdiska.asm
.model small
.data
.code

public _DREAD

_DREAD proc
push bp
mov bp,sp
push ds
push si

mov ah,42h
mov dl,80h
mov si,word ptr [bp+4]
int 13h

pop si
pop ds
pop bp
ret
_DREAD endp
end

编译连接后可以执行,可以像dos命令一样调用,不过没有写使用方法,大概就是把你要读的扇区的线性地址用16位分4段每段4位用空格隔开输入。另外还设置了一个16行/32行显示的切换开关第5个参数。
27 发表于 2008-10-29 16:04 ·  中国 福建 厦门 电信
高级用户
★★★
积分 741
发帖 366
注册 2007-07-25 19:11
UID 94024
性别 男
状态 离线
在测试我的读写小硬盘的程序中,照理只能读写1023(3FF,1111111111)个柱面(0-1022)
但是,却能读写1024个柱面!

对于支持INT13扩展的,只要最后的DAP地址是一样的,它们访问的就是同一个地方,CHS对它来说并没有多少实际意义,不支持的则会不一样,但问题是对于U盘来说,很多BIOS虽然报告支持INT13E,但事实上却是个假相(这也是U潘启动兼容性差的原因),这个问题的罪魁祸首是BIOS,其实符合ATA标准的硬盘真实的就是使用LBA地址来访问(不是古董型的硬盘真正的物理上不同柱面的扇区数不一样,CHS根本就没有意义)。
在486的电脑上,BIOS很老,不支持扩展INT13,所以不能读写大硬盘,但是很有意思,我们可以利用IO端口在486电脑上来实现读写137G以内容量的硬盘。

不可能的事,486的硬盘控制器芯片最多也就提供LBA28的地址,LBA48所需要的LBA地址是48位,所以无论如何也访问不了>137G的硬盘。

[ Last edited by netwinxp on 2008-11-5 at 17:46 ]
28 发表于 2008-11-20 17:53 ·  中国 湖南 邵阳 电信
新手上路
积分 11
发帖 6
注册 2008-11-06 19:09
UID 130201
性别 男
状态 离线
有没有最简单的修改硬盘号的工具?
论坛跳转: