获取硬盘号

supershan 2000-01-10 11:28:00
有谁知道获取硬盘号的API函数,请举例说明!
...全文
228 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
supershan 2000-01-10
  • 打赏
  • 举报
回复
感谢二位对以上问题的回答特别感谢tiger对上述问题做的详细回答不过我要的是label,
所以不能给你分再次表示感谢。
渤海海峡 2000-01-10
  • 打赏
  • 举报
回复
function GetHDSerialNumber: LongInt;
{$IFDEF WIN32}
var
pdw : pDWord;
mc, fl : dword;
{$ENDIF}
begin
{$IfDef WIN32}
New(pdw);
GetVolumeInformation(nil,nil,0,pdw,mc,fl,nil,0);
Result := pdw^;
dispose(pdw);
{$ELSE}
Result := GetWinFlags;
{$ENDIF}
end;

tiger 2000-01-10
  • 打赏
  • 举报
回复
你说的是序列号还是label?
label的话有GetVolumeInformation.
序列号的话, 可能没有现成的api, 用汇编吧.
取得ring0级权限, 调用中断
请看下面的例子, DING KAI的作品(www.nease.net/~dingkai/)

硬盘的序列号是厂家设定的,且只能用I/O指令读取,所以,这在以前的DOS时代
根本不是什么问题.方法非常简单,如下面的代码所示:
static int WaitIde()
{
int al;

while ((al=inp(0x1F7))>=0x80) ;
return al;
}

static void ReadIDE()
{
int al;
int i;
WORD pw[256];

WaitIde();
outp(0x1F6,0xA0);
al = WaitIde();
if ((al&0x50)!=0x50) return;

outp(0x1F6,0xA0);
outp(0x1F7,0xEC);
al = WaitIde();
if ((al&0x58)!=0x58) return;

for (i=0;i<256;i++) {
pw[i] = inpw(0x1F0);
}
}

至此,关于IDE硬盘的信息已经在 pw 数组中了,需要注意的是该数组是一个 WORD
类型,硬盘的序列号存放于 pw[10] 开始的10个WORD中,使用时需要将每个WORD的
高低字节颠倒一下。

真正有点麻烦的是在Windows 95/98下,I/O指令作为特权指令在应用程序级别,即
Ring 3是不可使用的,所以上面的代码在执行到 WaitIde()时会陷到死循环中,原
因就是 IN 0x1F7 总是返回 0xFF

容易想到的解决办法是写一个VxD,因为VxD运行Ring 0级别上,即最高特权级上,所以
所有的指令都是可用的。当然,这没有任何问题,事实上我已经写了这样的 VxD,效果
是明显的,如果哪位有兴趣,可与我联系。

如果你是一个编程高手,这没有什么难度,所以不必看下去。
如果你连VxD也不会写,请参阅拙作"VxD入门教程"。

当然,如果连象读取硬盘序列号这样小的问题都要写个VxD,确实是一件令人生厌的事,
且不说既要额外装个Win 95 DDK,又要防止VxD出现错误使系统崩溃这种多余的工作
和担心,旦旦是发行程序时带个这么小的东东就让人看着扎眼(读硬盘序列号无非是为了
防止拷贝,这个小东东明显会提示别人应该如何破解)。

所以我推荐的方法是真接从 Ring 3 完成该功能,即在你的EXE文件中处理这件事,这
样一方面减小了编程难度,另一方面有利于实现防止拷贝的目的。

实现的方法出人意料的简单,不过,也还是需要 100 行左右的代码。

唯一的一个技术难点就是利用 CPU 的异常从 Ring 3 直接切换到 Ring 0。如果解决了
这个问题,那么整个程序就非常简单了,值得一提的是,由于该技术将代码切换到
Ring 0 运行,所以,....., 不用我多说了吧?

不象在实模式下,中断向量表位于内存地址的0:0处,每当中断发生时,无论是硬中断还
是软中断,CPU都会从该表中查找中断的入口位置,并执行相应的中断程序。在保护模式
下(包括V86方式),物理内存0:0处不再有中断向量表,甚至"0:0"这种表示方式也发生了
变化,原来的段址不复存在,代之以段选择器,中断向量也用中断描述符表(IDT)取代了,
这意味着当发生中断或异常时(异常只在保护模式下存在,可以把它当作中断看待),CPU
查找的是IDT,然后再根据查到的入口地址执行相应的中断处理程序。

关于这部分内容请参阅80386 (或以上) CPU的技术手册。

从上面可以看出,虽然查找的内容及方法发生了变化,但原理并没有变,如果要修改中
断入口,所需要修改的地方无非是变成了IDT而已。更妙的是,中断处理程序是运行在
CPU最高特权级Ring 0上,这就使得我们从Ring 3进行Ring 0级别的操作成为可能。

具体方法可以归结如下:
首先,取得系统 IDT,这可用 SIDT 指令一步到位,且不受特权级限制;
然后,修改 IDT 中某一中断的入口,使其指向我们自己的处理程序;虽然理论上IDT表
中的所有中断都可以使用,但我建议使用中断 3, 这个中断是给调试器用的,平常没啥
用(修改的方法请参阅IDT的格)。
最后,执行该中断。可以直接执行代码 INT 3,当然,在 Ring 3 上执行该指令必然会导
致CPU异常,于是,我们的处理程序就这样轻易而举地得到了控制权。

一旦得到CPU最高特权级的控制权,中断处理程序就可以进行任何平常在 Ring 3 级别上
不能够进行的操作了,当然也包括本文的主题:读取硬盘序列号。
说得再具体一些,就是将本文前面提到的代码放到中断处理程序中即可全部搞定了。

至于用 C 语言或是汇编语言,那就完全视个人情况了。

我采用的方法是用 C 语言加上内嵌的汇编,完整的程序代码不列在此处了,需要的话请
直接与本人联系(也省得有人未经允许抄俺的程序 :Q)

最后,需要说明的是,这种方法不可以在 Windows NT 下使用。是什么原因我就不多说
了。

一些题外话,实际上我写这篇文章的目的并不完全是为了读取硬盘的序列号(这东东毕竟
没多大用途,有些硬盘,如三星的 32543A 根本就没有序列号),主要的目的是想在从
Ring 3 获取 Ring 0 特权这个问题上做些尝试,希望有兴趣的朋友能够参予进来,公开
你所掌握的技术,大家共同提高编程水平。

5,379

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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