:)

解决方案 »

  1.   

    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;
          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;
      

  2.   

    上午才加进收藏夹的一片好帖子,什么都有,你看看吧
    http://community.csdn.net/Expert/topic/3550/3550939.xml?temp=.4649622
      

  3.   

    //获取硬盘序列号
    //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;
      

  4.   

    http://community.csdn.net/Expert/topic/3550/3550939.xml?temp=.9558222
      

  5.   

    读取的程序大家都知道,代码如下: 
    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;
      

  6.   


    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.
      

  7.   

    有简单的,到51delphi去下载一个取得硬盘序列号的控件.
      

  8.   

    标题:如何获得硬盘的序列号-程序清单
    声明:不能用于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.