请教关于取得硬盘序列号的API函数或者其他的一些加密工具!(50分)

  • 主题发起人 主题发起人 太平公主
  • 开始时间 开始时间

太平公主

Unregistered / Unconfirmed
GUEST, unregistred user!
请教关于取得硬盘序列号的API函数或者其他的一些加密工具!
 
在DFW上寻得,作者不详。未经测试。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
type
TGate = record
Off2,op,seg,off1:WORD;
end;
const
_dsnlen=20; //硬盘序列号的位数,10个Word,必须是偶数
_dtplen=40; //硬盘生产厂家型号的位数,18个Word
_dcllen=8; //硬盘控制号的位数
var
IDTR : INT64;
SavedGate : TGate;
OurGate : TGate;
dd : array [0..256] of word;
dsn : array [0.._dsnlen-1] of char; //存放硬盘序列号
dtp : array [0.._dtplen-1] of char; //存放硬盘型号
dcl : array [0.._dcllen-1] of char;
// Ring0 中断服务例程 Ring0Proc ,通过端口读取硬盘参数
procedure Ring0Proc();
asm
// Wait for controller not busy
mov dx,01f7h
@1:in al,dx
cmp al,050h
jne @1
// Get first/second drive
dec dx //mov dx,01f6h
mov al,0a0h
out dx,al
// Get drive info data
inc dx //mov dx,01f7h
mov al,0ech
out dx,al
nop
nop
// Wait for data ready
@2:in al,dx
cmp al,058h
jne @2
nop
nop
// Read sector
xor ecx,ecx
mov dx,01f0h
@3:in ax,dx
mov word ptr dd[ecx*2],ax
inc ecx
cmp ecx,256
jne @3
iretd //中断返回
end;
//改变程序运行的特权级,以调用自定义中断程序 Ring0Proc
procedure Change2Ring0();
asm
mov eax, offset Ring0Proc
mov OurGate.off2, ax //将中断函数的地址填入新造的中断门描述符
shr eax, 16
mov OurGate.off1, ax
mov OurGate.op,0028h
mov OurGate.seg,0ee00h
mov ebx,offset IDTR
sidt [ebx]
//将中断描述符表寄存器(IDTR)的内容取出
mov ebx, dword ptr [IDTR+2]
//取出中断描述符表(IDT)基地址
add ebx, 8*3
//计算Int 3 的描述符应放置的地址选用
//Int3 是因为它在Win32 保护模式下未占用
mov edi, offset SavedGate
mov esi, ebx
movsd //保存原来的Int 9 描述符到SavedGate 以便恢复
movsd
mov edi, ebx
mov esi, offset OurGate
cli
movsd //替换原来的中断门描述符以安装中断服务例程
movsd
sti
mov eax,6200h
//用以测试放在EAX 中的数据能否正确传到 Ring0 中断
mov ecx,0
{用以测试放在 ECX 中的数据能否正确传到 Ring0 中断
因为很多VxD 服务都用此二寄存器传递参数}
int 3h
{人为触发中断, 平时会出现保护错误蓝屏或非法操作对话框,
现在安装了中断服务例程后,
就会通过 VMM 在Ring0 调用中断服务例程Ring0Proc}
mov edi, ebx
mov esi, offset SavedGate
cli
movsd //恢复原来的中断门描述符
movsd
sti
end;
//截取硬盘出厂参数:控制号,型号,序列号
procedure GetParameter;
begin
{硬盘的序列号存放于 dd[10] 开始的10个WORD中,使用时需要将每个WORD的
高低字节颠倒一下}
asm
xor ecx,ecx
mov ebx,offset dd[10*2]
@1:mov ax,[ebx]
cmp ah, 0 //
je @2 //
mov byte ptr dsn[ecx],ah
cmp al, 0 //
je @2 //
inc ecx
mov byte ptr dsn[ecx],al
inc ebx
inc ebx
inc ecx
cmp ecx, _dsnlen
jne @1
@2:
end;
{硬盘的型号存放于 dd[27] 开始的18个WORD中}
asm
xor ecx,ecx
mov ebx,offset dd[27*2]
@1:mov ax,[ebx]
cmp ah, 0 //
je @2 //
mov byte ptr dtp[ecx],ah
cmp al, 0 //
je @2 //
inc ecx
mov byte ptr dtp[ecx],al
inc ebx
inc ebx
inc ecx
cmp ecx, _dtplen
jne @1
@2:
end;
{硬盘的控制号存放于 dd[23] 开始的3个WORD中}
asm
xor ecx,ecx
mov ebx,offset dd[23*2]
@1:mov ax,[ebx]
cmp ah, 0 //
je @2 //
mov byte ptr dcl[ecx],ah
cmp al, 0 //
je @2 //
inc ecx
mov byte ptr dcl[ecx],al
inc ebx
inc ebx
inc ecx
cmp ecx, _dcllen
jne @1
@2:
end;
end;
end.
 
这是我找的,作者也不祥
type
MIDPtr = ^MIDRec;
MIDRec = Record
InfoLevel: word;
SerialNum: LongInt;
VolLabel: Packed Array [0..10] of Char;
FileSysType: Packed Array [0..7] of Char;
end;

function GetDriveSerialNum(MID: MIDPtr; drive: Word): Boolean; assembler;
asm
push DS { Just for safety, I dont think its really needed }
mov ax,440Dh { Function Get Media ID }
mov bx,drive { drive no (0-Default, 1-A ...) }
mov cx,0866h { category and minor code }
lds dx,MID { Load pointeraddr. }
call DOS3Call { Supposed to be faster than INT 21H }
jc @@err
mov al,1 { No carry so return TRUE }
jmp @@ok
@@err:
mov al,0 { Carry set so return FALSE }
@@ok:
pop DS { Restore DS, were not supposed to change it }
end;

procedure TForm1.NrBtnClick(Sender: TObject);
var
Info: MIDRec;
begin
Info.InfoLevel:=0; { Information Level }
If GetDriveSerialNum(@Info,0) then { Do something with it... }
ListBox.Items.Add(IntToStr(Info.SerialNum)+' '+Info.VolLabel);
end;



--------------------------------------------------------------------------------
BOOL GetVolumeInformation(

LPCTSTR lpRootPathName, // address of root directory of the file system
LPTSTR lpVolumeNameBuffer, // address of name of the volume
DWORD nVolumeNameSize, // length of lpVolumeNameBuffer
LPDWORD lpVolumeSerialNumber, // address of volume serial number
LPDWORD lpMaximumComponentLength, // address of system's maximum filename length
LPDWORD lpFileSystemFlags, // address of file system flags
LPTSTR lpFileSystemNameBuffer, // address of name of file system
DWORD nFileSystemNameSize // length of lpFileSystemNameBuffer
);



--------------------------------------------------------------------------------


获取SCSI硬盘序列号

问题提出/摘要:

对于IDE硬盘,你可以使用S.M.A.R.T. API的函数来获取序列号。但对SCSI硬盘,它无法工作。但我们可以使用DeviceIoControl来获取DeviceIoControl设备序列号.





回答:

下面是代码:

program ScsiSN;



// 目的:简单的控制台程序来显示SCSI硬盘的序列号



{$APPTYPE CONSOLE}



uses

Windows, SysUtils;



//-------------------------------------------------------------

function GetDeviceHandle( sDeviceName : String ) : THandle;

begin

Result := CreateFile( PChar('//./'+sDeviceName),

GENERIC_READ or GENERIC_WRITE,

FILE_SHARE_READ or FILE_SHARE_WRITE,

nil, OPEN_EXISTING, 0, 0 )

end;



//-------------------------------------------------------------

function ScsiHddSerialNumber( DeviceHandle : THandle ) : String;

{$ALIGN ON}

type

TScsiPassThrough = record

Length : Word;

ScsiStatus : Byte;

PathId : Byte;

TargetId : Byte;

Lun : Byte;

CdbLength : Byte;

SenseInfoLength : Byte;

DataIn : Byte;

DataTransferLength : ULONG;

TimeOutValue : ULONG;

DataBufferOffset : DWORD;

SenseInfoOffset : ULONG;

Cdb : Array[0..15] of Byte;

end;

TScsiPassThroughWithBuffers = record

spt : TScsiPassThrough;

bSenseBuf : Array[0..31] of Byte;

bDataBuf : Array[0..191] of Byte;

end;

{ALIGN OFF}

var dwReturned : DWORD;

len : DWORD;

Buffer : Array[0..255] of Byte;

sptwb : TScsiPassThroughWithBuffers absolute Buffer;

begin

Result := '';

FillChar(Buffer,SizeOf(Buffer),#0);

with sptwb.spt do

begin

Length := SizeOf(TScsiPassThrough);

CdbLength := 6; // CDB6GENERIC_LENGTH

SenseInfoLength := 24;

DataIn := 1; // SCSI_IOCTL_DATA_IN

DataTransferLength := 192;

TimeOutValue := 2;

DataBufferOffset := PChar(@sptwb.bDataBuf)-PChar(@sptwb);

SenseInfoOffset := PChar(@sptwb.bSenseBuf)-PChar(@sptwb);

Cdb[0] := $12; // OperationCode := SCSIOP_INQUIRY;

Cdb[1] := $01; // Flags := CDB_INQUIRY_EVPD; Vital product data

Cdb[2] := $80; // PageCode Unit serial number

Cdb[4] := 192; // AllocationLength

end;

len := sptwb.spt.DataBufferOffset+sptwb.spt.DataTransferLength;

if DeviceIoControl( DeviceHandle, $0004d004, @sptwb, SizeOf(TScsiPassThrough), @sptwb, len, dwReturned, nil )

and ((PChar(@sptwb.bDataBuf)+1)^=#$80)

then

SetString( Result, PChar(@sptwb.bDataBuf)+4,

Ord((PChar(@sptwb.bDataBuf)+3)^) );

end;





//=============================================================

var

hDevice : THandle = 0;

sSerNum, sDeviceName : String;



begin

sDeviceName := ParamStr(1);

if sDeviceName='' then

begin

WriteLn;

WriteLn('Display SCSI-2 device serial number.');

WriteLn;

WriteLn('Using:');

WriteLn;

if Win32Platform=VER_PLATFORM_WIN32_NT then // Windows NT/2000

WriteLn(' ScsiSN PhysicalDrive0')

else

WriteLn(' ScsiSN C:');

WriteLn(' ScsiSN Cdrom0');

WriteLn(' ScsiSN Tape0');

WriteLn;

Exit;

end;

hDevice := GetDeviceHandle(sDeviceName);

if hDevice=INVALID_HANDLE_VALUE then

WriteLn('Error on GetDeviceHandle: ',SysErrorMessage(GetLastError))

else

try

sSerNum := ScsiHddSerialNumber(hDevice);

if sSerNum='' then

WriteLn('Error on DeviceIoControl: ',

SysErrorMessageGetLastError))

else

WriteLn('Device '+sDeviceName

+' serial number = "',sSerNum,'"');

finally

CloseHandle(hDevice);

end;

end.



// 以下站点可获取更多关于SCSI命令的信息:

// ftp://ftp.t10.org/t10/drafts/scsi-1/



// ftp://ftp.t10.org/t10/drafts/spc/



// ftp://ftp.t10.org/t10/drafts/spc2/



--------------------------------------------------------------------------------


获取光盘序列号

uses MMSystem, MPlayer;

procedure TForm1.Button1Click(Sender: TObject);
var
mp : TMediaPlayer;
msp : TMCI_INFO_PARMS;
MediaString : array[0..255] of char;
ret : longint;
begin
mp := TMediaPlayer.Create(nil);
mp.Visible := false;
mp.Parent := Application.MainForm;
mp.Shareable := true;
mp.DeviceType := dtCDAudio;
mp.FileName := 'D:';
mp.Open;
Application.ProcessMessages;
FillChar(MediaString, sizeof(MediaString), #0);
FillChar(msp, sizeof(msp), #0);
msp.lpstrReturn := @MediaString;
msp.dwRetSize := 255;
ret := mciSendCommand(Mp.DeviceId,
MCI_INFO,
MCI_INFO_MEDIA_IDENTITY,
longint(@msp));
if Ret <> 0 then begin
MciGetErrorString(ret, @MediaString, sizeof(MediaString));
Memo1.Lines.Add(StrPas(MediaString));
end else
Memo1.Lines.Add(StrPas(MediaString));
mp.Close;
Application.ProcessMessages;
mp.free;
end;

end.




--------------------------------------------------------------------------------


通过它你可以获取型号名称, firmware revision,序列号以及其它有关IDE硬盘的信息.





回答:

相关构件:

IdeInfo.zip

许多FAQ中推荐使用GetVolumeInformation来获取硬盘序列号。但是那获取的是卷的序列号,而不是硬盘的序列号。卷的序列号是在分区格式化时生成或修改。一些公司使用复制工具来为全部新计算机安装软件----通过将一个硬盘复制到其它硬盘,当然,所有这些计算机上卷的信息(包括序列号)都是相同的。



我建议另外的一个方法:获取真正硬盘的序列号。

不幸的是,下列代码只能工作在IDE硬盘上。





//获取第一个IDE硬盘的序列号

function GetIdeSerialNumber : SerialNumber;

const IDENTIFY_BUFFER_SIZE = 512;

type

TIDERegs = packed record

bFeaturesReg : BYTE; // Used for specifying SMART "commands".

bSectorCountReg : BYTE; // IDE sector count register

bSectorNumberReg : BYTE; // IDE sector number register

bCylLowReg : BYTE; // IDE low order cylinder value

bCylHighReg : BYTE; // IDE high order cylinder value

bDriveHeadReg : BYTE; // IDE drive/head register

bCommandReg : BYTE; // Actual IDE command.

bReserved : BYTE; // reserved for future use. Must be zero.

end;

TSendCmdInParams = packed record

// Buffer size in bytes

cBufferSize : DWORD;

// Structure with drive register values.

irDriveRegs : TIDERegs;

// Physical drive number to send command to (0,1,2,3).

bDriveNumber : BYTE;

bReserved : Array[0..2] of Byte;

dwReserved : Array[0..3] of DWORD;

bBuffer : Array[0..0] of Byte; // Input buffer.

end;

TIdSector = packed record

wGenConfig : Word;

wNumCyls : Word;

wReserved : Word;

wNumHeads : Word;

wBytesPerTrack : Word;

wBytesPerSector : Word;

wSectorsPerTrack : Word;

wVendorUnique : Array[0..2] of Word;

sSerialNumber : Array[0..19] of CHAR;

wBufferType : Word;

wBufferSize : Word;

wECCSize : Word;

sFirmwareRev : Array[0..7] of Char;

sModelNumber : Array[0..39] of Char;

wMoreVendorUnique : Word;

wDoubleWordIO : Word;

wCapabilities : Word;

wReserved1 : Word;

wPIOTiming : Word;

wDMATiming : Word;

wBS : Word;

wNumCurrentCyls : Word;

wNumCurrentHeads : Word;

wNumCurrentSectorsPerTrack : Word;

ulCurrentSectorCapacity : DWORD;

wMultSectorStuff : Word;

ulTotalAddressableSectors : DWORD;

wSingleWordDMA : Word;

wMultiWordDMA : Word;

bReserved : Array[0..127] of BYTE;

end;

PIdSector = ^TIdSector;

TDriverStatus = packed record

// 驱动器返回的错误代码,无错则返回0

bDriverError : Byte;

// IDE出错寄存器的内容,只有当bDriverError 为 SMART_IDE_ERROR 时有效

bIDEStatus : Byte;

bReserved : Array[0..1] of Byte;

dwReserved : Array[0..1] of DWORD;

end;

TSendCmdOutParams = packed record

// bBuffer的大小

cBufferSize : DWORD;

// 驱动器状态

DriverStatus : TDriverStatus;

// 用于保存从驱动器读出的数据的缓冲区,实际长度由cBufferSize决定

bBuffer : Array[0..0] of BYTE;

end;



var hDevice : THandle;

cbBytesReturned : DWORD;

ptr : PChar;

SCIP : TSendCmdInParams;

aIdOutCmd : Array [0..(SizeOf(TSendCmdOutParams)+IDENTIFY_BUFFER_SIZE-1)-1] of Byte;

IdOutCmd : TSendCmdOutParams absolute aIdOutCmd;



procedure ChangeByteOrder( var Data; Size : Integer );

var ptr : PChar;

i : Integer;

c : Char;

begin

ptr := @Data;

for i := 0 to (Size shr 1)-1 do

begin

c := ptr^;

ptr^ := (ptr+1)^;

(ptr+1)^ := c;

Inc(ptr,2);

end;

end;



begin

Result := ''; // 如果出错则返回空串

if SysUtils.Win32Platform=VER_PLATFORM_WIN32_NT then // Windows NT, Windows 2000

begin

// 提示! 改变名称可适用于其它驱动器,如第二个驱动器: '//./PhysicalDrive1/'

hDevice := CreateFile( '//./PhysicalDrive0', GENERIC_READ or GENERIC_WRITE,

FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0 );

end

else // Version Windows 95 OSR2, Windows 98

hDevice := CreateFile( '//./SMARTVSD', 0, 0, nil, CREATE_NEW, 0, 0 );

if hDevice=INVALID_HANDLE_VALUE then Exit;

try

FillChar(SCIP,SizeOf(TSendCmdInParams)-1,#0);

FillChar(aIdOutCmd,SizeOf(aIdOutCmd),#0);

cbBytesReturned := 0;

// Set up data structures for IDENTIFY command.

with SCIP do

begin

cBufferSize := IDENTIFY_BUFFER_SIZE;

// bDriveNumber := 0;

with irDriveRegs do

begin

bSectorCountReg := 1;

bSectorNumberReg := 1;

// if Win32Platform=VER_PLATFORM_WIN32_NT then bDriveHeadReg := $A0

// else bDriveHeadReg := $A0 or ((bDriveNum and 1) shl 4);

bDriveHeadReg := $A0;

bCommandReg := $EC;

end;

end;

if not DeviceIoControl( hDevice, $0007c088, @SCIP, SizeOf(TSendCmdInParams)-1,

@aIdOutCmd, SizeOf(aIdOutCmd), cbBytesReturned, nil ) then Exit;

finally

CloseHandle(hDevice);

end;

with PIdSector(@IdOutCmd.bBuffer)^ do

begin

ChangeByteOrder( sSerialNumber, SizeOf(sSerialNumber) );

(PChar(@sSerialNumber)+SizeOf(sSerialNumber))^ := #0;

Result := PChar(@sSerialNumber);

end;

end;



// 更多关于 S.M.A.R.T. ioctl 的信息可查看:

// http://www.microsoft.com/hwdev/download/respec/iocltapi.rtf



// MSDN库中也有一些简单的例子

// Windows Development -> Win32 Device Driver Kit ->

// SAMPLE: SmartApp.exe Accesses SMART stats in IDE drives



// 还可以查看 http://www.mtgroup.ru/~alexk

// IdeInfo.zip - 一个简单的使用了S.M.A.R.T. Ioctl API的Delphi应用程序



// 注意:



// WinNT/Win2000 - 你必须拥有对硬盘的读/写访问权限



// Win98

// SMARTVSD.VXD 必须安装到 /windows/system/iosubsys

// (不要忘记在复制后重新启动系统)






 
后退
顶部