标题:如何获得硬盘的序列号-程序清单 声明:不能用于NT unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Label0: TLabel; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; const hookexceptionno = 5; ErrNo : integer =0; var pw : array [0..255] of WORD;// pw[256]; idtr_1 : array [0..5] of byte; //保存中断描述符表寄存器 oldexceptionhook : dword; //保存原先的中断入口地址 IdeBase : word; SelectDisk: integer; var Form1: TForm1; implementation {$R *.DFM} function inp(rdx:word) : byte; asm mov dx, rdx in al, dx end; function inpw(rdx: word) : word; asm mov dx, rdx in ax, dx end; procedure outp(ral : byte; rdx : word); asm mov dx, rdx mov al, ral out dx, al end; function WaitIde:byte; var al:byte; begin repeat al:=inp(IdeBase+7); until (al<$80) or (al=$a0); //$a0可能就没有硬盘 WaitIde := al; end; procedure ReadIDE; var al : byte; i : integer; begin WaitIde; outp(SelectDisk,IdeBase+6); al := WaitIde; if ((al and $50) <>$50) then begin ErrNo:=1; exit; end; outp(SelectDisk,IdeBase+6); outp($EC,IdeBase+7); al := WaitIde; if ((al and $58)<>$58) then begin ErrNo:=2; exit; end; for i:=0 to 255 do begin pw[i] := inpw(IdeBase); end; end; // 新的中断处理程序 procedure ReadIt; assembler; asm push eax push ebx push ecx push edx push esi push edi // 在这里写读程序 call ReadIDE pop edi pop esi pop edx pop ecx pop ebx pop eax iretd end; procedure GetSerialNo; assembler; begin asm push eax // 获取修改的中断的中断描述符(中断门)地址 sidt idtr_1 mov eax,dword ptr idtr_1+02h add eax,hookexceptionno*08h+04h // 保存原先的中断入口地址 cli push ecx mov ecx,dword ptr [eax] mov cx,word ptr [eax-04h] mov dword ptr oldexceptionhook,ecx pop ecx // 设置修改的中断入口地址为新的中断处理程序入口地址 push ebx lea ebx,ReadIt mov word ptr [eax-04h],bx shr ebx,10h mov word ptr [eax+02h],bx pop ebx // 执行中断,转到ring 0(与cih 病毒原理相似!) push ebx int hookexceptionno pop ebx // 恢复原先的中断入口地址 push ecx mov ecx,dword ptr oldexceptionhook mov word ptr [eax-04h],cx shr ecx,10h mov word ptr [eax+02h],cx pop ecx // 结束 sti pop eax ret end; end; procedure GetPN(DriveNo: integer; var s:string); var i : integer; begin // asm int 3 end; ErrNo:=0; fillchar(pw,sizeof(pw),0); s:='' case DriveNo of //设置基址 0,1:IdeBase:= $1f0; 2,3:IdeBase:= $170; end; case DriveNo of //指定主从 0,2:SelectDisk:=$A0; 1,3:SelectDisk:=$B0; end; GetSerialNo; if ErrNo<>0 then exit; //读错误 if (pw[0]=0) then s := '没有序列号:(' else for i:=10 to 20 do begin s := s+ char(pw[i] shr 8) + char(pw[i] and $ff); end; end; procedure TForm1.Button1Click(Sender: TObject); var s:string; i:integer; begin for i:=0 to 3 do begin GetPN(i, s); if (s<>'') then case i of 0: Label1.Caption := 'IDE1 主盘' +s; 1: Label2.Caption := 'IDE1 从盘' +s; 2: Label3.Caption := 'IDE2 主盘' +s; 3: Label3.Caption := 'IDE2 从盘' +s; end; end; end; end.
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;
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 begin// Windows NT, Windows 2000
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;
with SCIP do begin
cBufferSize := IDENTIFY_BUFFER_SIZE;
with irDriveRegs do begin
bSectorCountReg := 1;
bSectorNumberReg := 1;
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 := strpas(PChar(@sSerialNumber));
end;
end;
http://community.csdn.net/Expert/topic/3550/3550939.xml?temp=.4649622
//win98要 c:\windows\system\的smartvsd.vxd
//copy to c:\windows\system\iosubsys
//reboot your computer and ok
//2000 and nt do not need
function GetIdeSerialNumber: String;
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 begin// Windows NT, Windows 2000
// 提示! 改变名称可适用于其它驱动器,如第二个驱动器: '\\.\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;
ptr := PChar(@sSerialNumber);
Result := Trim(ptr);
end;
end;
unit Unit_Main;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls;typeTSrbIoControl = packed recordHeaderLength: ULONG;Signature: array[0..7] of Char;Timeout: ULONG;ControlCode: ULONG;ReturnCode: ULONG;Length: ULONG;end;SRB_IO_CONTROL = TSrbIoControl;PSrbIoControl = ^TSrbIoControl;TIDERegs = packed recordbFeaturesReg: Byte; // Used for specifying SMART "commands".bSectorCountReg: Byte; // IDE sector count registerbSectorNumberReg: Byte; // IDE sector number registerbCylLowReg: Byte; // IDE low order cylinder valuebCylHighReg: Byte; // IDE high order cylinder valuebDriveHeadReg: Byte; // IDE drive/head registerbCommandReg: Byte; // Actual IDE command.bReserved: Byte; // reserved. Must be zero.end;IDEREGS = TIDERegs;PIDERegs = ^TIDERegs;TSendCmdInParams = packed recordcBufferSize: DWORD;irDriveRegs: TIDERegs;bDriveNumber: Byte;bReserved: array[0..2] of Byte;dwReserved: array[0..3] of DWORD;bBuffer: array[0..0] of Byte;end;SENDCMDINPARAMS = TSendCmdInParams;PSendCmdInParams = ^TSendCmdInParams;TIdSector = packed recordwGenConfig: 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: ULONG;wMultSectorStuff: Word;ulTotalAddressableSectors: ULONG;wSingleWordDMA: Word;wMultiWordDMA: Word;bReserved: array[0..127] of Byte;end;PIdSector = ^TIdSector;constIDE_ID_FUNCTION = $EC;IDENTIFY_BUFFER_SIZE = 512;DFP_RECEIVE_DRIVE_DATA = $0007C088;IOCTL_SCSI_MINIPORT = $0004D008;IOCTL_SCSI_MINIPORT_IDENTIFY = $001B0501;DataSize = sizeof(TSendCmdInParams) - 1 + IDENTIFY_BUFFER_SIZE;BufferSize = SizeOf(SRB_IO_CONTROL) + DataSize;W9xBufferSize = IDENTIFY_BUFFER_SIZE + 16;typeTForm_Main = class(TForm)Edit_HardDiskNumber: TEdit;Label1: TLabel;Button_Get: TButton;procedure Button_GetClick(Sender: TObject);private{ Private declarations }public{ Public declarations }end;varForm_Main: TForm_Main;implementation{$R *.dfm}function GetIdeDiskSerialNumber: string;typeTSrbIoControl = packed recordHeaderLength: ULONG;Signature: array[0..7] of Char;Timeout: ULONG;ControlCode: ULONG;ReturnCode: ULONG;Length: ULONG;end;SRB_IO_CONTROL = TSrbIoControl;PSrbIoControl = ^TSrbIoControl;TIDERegs = packed recordbFeaturesReg: Byte; // Used for specifying SMART "commands".bSectorCountReg: Byte; // IDE sector count registerbSectorNumberReg: Byte; // IDE sector number registerbCylLowReg: Byte; // IDE low order cylinder valuebCylHighReg: Byte; // IDE high order cylinder valuebDriveHeadReg: Byte; // IDE drive/head registerbCommandReg: Byte; // Actual IDE command.bReserved: Byte; // reserved for future use. Must be zero.end;IDEREGS = TIDERegs;PIDERegs = ^TIDERegs;TSendCmdInParams = packed recordcBufferSize: DWORD; // Buffer size in bytesirDriveRegs: TIDERegs; // Structure with drive register values.bDriveNumber: Byte; // Physical drive number to send command to (0,1,2,3).bReserved: array[0..2] of Byte; // Reserved for future expansion.dwReserved: array[0..3] of DWORD; // For future use.bBuffer: array[0..0] of Byte; // Input buffer.end;SENDCMDINPARAMS = TSendCmdInParams;PSendCmdInParams = ^TSendCmdInParams;TIdSector = packed recordwGenConfig: 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: ULONG;wMultSectorStuff: Word;ulTotalAddressableSectors: ULONG;wSingleWordDMA: Word;wMultiWordDMA: Word;bReserved: array[0..127] of Byte;end;PIdSector = ^TIdSector;constIDE_ID_FUNCTION = $EC;IDENTIFY_BUFFER_SIZE = 512;DFP_RECEIVE_DRIVE_DATA = $0007C088;IOCTL_SCSI_MINIPORT = $0004D008;IOCTL_SCSI_MINIPORT_IDENTIFY = $001B0501;DataSize = sizeof(TSendCmdInParams) - 1 + IDENTIFY_BUFFER_SIZE;BufferSize = SizeOf(SRB_IO_CONTROL) + DataSize;W9xBufferSize = IDENTIFY_BUFFER_SIZE + 16;varhDevice: THandle;cbBytesReturned: DWORD;pInData: PSendCmdInParams;pOutData: Pointer; // PSendCmdInParams;Buffer: array[0..BufferSize - 1] of Byte;srbControl: TSrbIoControl absolute Buffer;procedure ChangeByteOrder(var Data; Size: Integer);var ptr: PChar;i: Integer;c: Char;beginptr := @Data;for i := 0 to (Size shr 1) - 1 dobeginc := ptr^;ptr^ := (ptr + 1)^;(ptr + 1)^ := c;Inc(ptr, 2);end;end;beginResult := '';FillChar(Buffer, BufferSize, #0);if Win32Platform = VER_PLATFORM_WIN32_NT thenbegin // Windows NT, Windows 2000// Get SCSI port handlehDevice := CreateFile('\.:', GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);if hDevice = INVALID_HANDLE_VALUE then Exit;trysrbControl.HeaderLength := SizeOf(SRB_IO_CONTROL);System.Move('SCSIDISK', srbControl.Signature, 8);srbControl.Timeout := 2;srbControl.Length := DataSize;srbControl.ControlCode := IOCTL_SCSI_MINIPORT_IDENTIFY;pInData := PSendCmdInParams(PChar(@Buffer) + SizeOf(SRB_IO_CONTROL));pOutData := pInData;with pInData^ dobegincBufferSize := IDENTIFY_BUFFER_SIZE;bDriveNumber := 0;with irDriveRegs dobeginbFeaturesReg := 0;bSectorCountReg := 1;bSectorNumberReg := 1;bCylLowReg := 0;bCylHighReg := 0;bDriveHeadReg := $A0;bCommandReg := IDE_ID_FUNCTION;end;end;if not DeviceIoControl(hDevice, IOCTL_SCSI_MINIPORT, @Buffer, BufferSize, @Buffer, BufferSize, cbBytesReturned, nil) then Exit;finallyCloseHandle(hDevice);end;endelsebegin // Windows 95 OSR2, Windows 98hDevice := CreateFile('\.', 0, 0, nil, CREATE_NEW, 0, 0);if hDevice = INVALID_HANDLE_VALUE then Exit;trypInData := PSendCmdInParams(@Buffer);pOutData := PChar(@pInData^.bBuffer);with pInData^ dobegincBufferSize := IDENTIFY_BUFFER_SIZE;bDriveNumber := 0;with irDriveRegs dobeginbFeaturesReg := 0;bSectorCountReg := 1;bSectorNumberReg := 1;bCylLowReg := 0;bCylHighReg := 0;bDriveHeadReg := $A0;bCommandReg := IDE_ID_FUNCTION;end;end;if not DeviceIoControl(hDevice, DFP_RECEIVE_DRIVE_DATA, pInData, SizeOf(TSendCmdInParams) - 1, pOutData, W9xBufferSize, cbBytesReturned, nil) then Exit;finallyCloseHandle(hDevice);end;end;with PIdSector(PChar(pOutData) + 16)^ dobeginChangeByteOrder(sSerialNumber, SizeOf(sSerialNumber));SetString(Result, sSerialNumber, SizeOf(sSerialNumber));end;end;procedure TForm_Main.Button_GetClick(Sender: TObject);beginEdit_HardDiskNumber.Text := GetIdeDiskSerialNumber;end;end.
声明:不能用于NT
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Label0: TLabel;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
const
hookexceptionno = 5;
ErrNo : integer =0;
var
pw : array [0..255] of WORD;// pw[256];
idtr_1 : array [0..5] of byte; //保存中断描述符表寄存器
oldexceptionhook : dword; //保存原先的中断入口地址
IdeBase : word;
SelectDisk: integer;
var
Form1: TForm1;
implementation
{$R *.DFM}
function inp(rdx:word) : byte;
asm
mov dx, rdx
in al, dx
end;
function inpw(rdx: word) : word;
asm
mov dx, rdx
in ax, dx
end;
procedure outp(ral : byte; rdx : word);
asm
mov dx, rdx
mov al, ral
out dx, al
end;
function WaitIde:byte;
var
al:byte;
begin
repeat
al:=inp(IdeBase+7);
until (al<$80) or (al=$a0); //$a0可能就没有硬盘
WaitIde := al;
end;
procedure ReadIDE;
var
al : byte;
i : integer;
begin
WaitIde;
outp(SelectDisk,IdeBase+6);
al := WaitIde;
if ((al and $50) <>$50) then
begin
ErrNo:=1;
exit;
end;
outp(SelectDisk,IdeBase+6);
outp($EC,IdeBase+7);
al := WaitIde;
if ((al and $58)<>$58) then
begin
ErrNo:=2;
exit;
end;
for i:=0 to 255 do
begin
pw[i] := inpw(IdeBase);
end;
end;
// 新的中断处理程序
procedure ReadIt; assembler;
asm
push eax
push ebx
push ecx
push edx
push esi
push edi
// 在这里写读程序
call ReadIDE
pop edi
pop esi
pop edx
pop ecx
pop ebx
pop eax
iretd
end;
procedure GetSerialNo; assembler;
begin
asm
push eax
// 获取修改的中断的中断描述符(中断门)地址
sidt idtr_1
mov eax,dword ptr idtr_1+02h
add eax,hookexceptionno*08h+04h
// 保存原先的中断入口地址
cli
push ecx
mov ecx,dword ptr [eax]
mov cx,word ptr [eax-04h]
mov dword ptr oldexceptionhook,ecx
pop ecx
// 设置修改的中断入口地址为新的中断处理程序入口地址
push ebx
lea ebx,ReadIt
mov word ptr [eax-04h],bx
shr ebx,10h
mov word ptr [eax+02h],bx
pop ebx
// 执行中断,转到ring 0(与cih 病毒原理相似!)
push ebx
int hookexceptionno
pop ebx
// 恢复原先的中断入口地址
push ecx
mov ecx,dword ptr oldexceptionhook
mov word ptr [eax-04h],cx
shr ecx,10h
mov word ptr [eax+02h],cx
pop ecx
// 结束
sti
pop eax
ret
end;
end;
procedure GetPN(DriveNo: integer; var s:string);
var
i : integer;
begin
// asm int 3 end;
ErrNo:=0;
fillchar(pw,sizeof(pw),0);
s:=''
case DriveNo of //设置基址
0,1:IdeBase:= $1f0;
2,3:IdeBase:= $170;
end;
case DriveNo of //指定主从
0,2:SelectDisk:=$A0;
1,3:SelectDisk:=$B0;
end;
GetSerialNo;
if ErrNo<>0 then
exit; //读错误
if (pw[0]=0) then
s := '没有序列号:('
else
for i:=10 to 20 do
begin
s := s+ char(pw[i] shr 8) + char(pw[i] and $ff);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
s:string;
i:integer;
begin
for i:=0 to 3 do
begin
GetPN(i, s);
if (s<>'') then
case i of
0: Label1.Caption := 'IDE1 主盘' +s;
1: Label2.Caption := 'IDE1 从盘' +s;
2: Label3.Caption := 'IDE2 主盘' +s;
3: Label3.Caption := 'IDE2 从盘' +s;
end;
end;
end;
end.