function GetIdeDiskSerialNumber : String;
var
  hDevice : THandle;
  cbBytesReturned : DWORD;
  pInData : PSendCmdInParams;
  pOutData : Pointer; // PSendCmdOutParams
  Buffer : Array[0..BufferSize-1] of Byte;
  srbControl : TSrbIoControl absolute Buffer;
begin
  Result := '';
  FillChar(Buffer,BufferSize,#0);  if Win32Platform=VER_PLATFORM_WIN32_NT then
  begin
    // Windows NT, Windows 2000
    //通过MS的S.M.A.R.T.接口,直接从RING3调用
    //API DeviceIoControl()来获取硬盘信息
    // Get SCSI port handle
    hDevice := CreateFile( '\\.\Scsi0:',
      GENERIC_READ or GENERIC_WRITE,
      FILE_SHARE_READ or FILE_SHARE_WRITE,
      nil, OPEN_EXISTING, 0, 0);
    if hDevice=INVALID_HANDLE_VALUE then Exit;
    try
      srbControl.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^ do
      begin
        cBufferSize := IDENTIFY_BUFFER_SIZE;
        bDriveNumber := 0;
        with irDriveRegs do
        begin
          bFeaturesReg := 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;
    finally
      CloseHandle(hDevice);
    end;
    with PIdSector(PChar(pOutData)+16)^ do
    begin
      ChangeByteOrder(sSerialNumber,SizeOf(sSerialNumber));
      SetString(Result,sSerialNumber,SizeOf(sSerialNumber));
    end;
  end else
  begin
    // Windows 95 OSR2, Windows 98
    //使用类似CIH利用中断异常方法从Ring3转入Ring0层读取DiskSN
    //change2ring0;
    Result:=dsn;
  end;
end;以上程序,适合WIN Me/Win 2000/Win XP如能通过,立即给分。改后的代码给我发EMAIL:[email protected]
谢谢!

解决方案 »

  1.   

    因为一般的SCSI控制器都是不相同的,可能是API不支持的问题,参考SCSI手册
      

  2.   

    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.
     
    网上找到的
      

  3.   

    {获得硬盘序列号}
    Function GetIDESerialNumber(IDECom: Integer): String;
    type
      TSrbIoControl = packed record
        HeaderLength : ULONG;
        Signature : Array[0..7] of Char;
        Timeout : ULONG;
        ControlCode : ULONG;
        ReturnCode : ULONG;
        Length : ULONG;
      end;
      SRB_IO_CONTROL = TSrbIoControl;
      PSrbIoControl = ^TSrbIoControl;
      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. Must be zero.
      end;
      IDEREGS = TIDERegs;
      PIDERegs = ^TIDERegs;
      TSendCmdInParams = packed record
        cBufferSize : 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 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 : ULONG;
        wMultSectorStuff : Word;
        ulTotalAddressableSectors : ULONG;
        wSingleWordDMA : Word;
        wMultiWordDMA : Word;
        bReserved : Array[0..127] of Byte;
      end;
      PIdSector = ^TIdSector;
    const
      IDE_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;
    var
      hDevice : THandle;
      cbBytesReturned : DWORD;
      pInData : PSendCmdInParams;
      pOutData : Pointer; // PSendCmdOutParams
      Buffer : Array[0..BufferSize-1] of Byte;
      srbControl : TSrbIoControl absolute Buffer;  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 := 'LiYunFeng';
      FillChar(Buffer,BufferSize,#0);{填充值#0}
      if Win32Platform=VER_PLATFORM_WIN32_NT then{判断操作系统的版本}
      begin // Windows NT, Windows 2000
        // Get SCSI port handle
        //Scsi0/Scsi1,Scsi2,Scsi3分别代表挂掉的IDE设置口号
        Result:= '\\.\Scsi' + IntToStr(IDECom) + ':';
        hDevice := CreateFile(pChar(Result) , GENERIC_READ or GENERIC_WRITE,
        FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0 );
        Result:= 'LiYunFeng';
        if hDevice=INVALID_HANDLE_VALUE then Exit; {打开设备错误,退出}
        try
          srbControl.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^ do
          begin
            cBufferSize := IDENTIFY_BUFFER_SIZE;
            bDriveNumber := 0;
            with irDriveRegs do
            begin
              bFeaturesReg := 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;
        finally
          CloseHandle(hDevice);
        end;
      end else
      begin // Windows 95 OSR2, Windows 98
        hDevice := CreateFile( '\\.\SMARTVSD', 0, 0, nil,
        CREATE_NEW, 0, 0 );
        if hDevice=INVALID_HANDLE_VALUE then Exit;
        try
          pInData := PSendCmdInParams(@Buffer);
          pOutData := @pInData^.bBuffer;
          with pInData^ do
          begin
            cBufferSize := IDENTIFY_BUFFER_SIZE;
            bDriveNumber := 0;
            with irDriveRegs do
            begin
              bFeaturesReg := 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;
        finally
          CloseHandle(hDevice);
        end;
      end;
      with PIdSector(PChar(pOutData)+16)^ do
      begin
        ChangeByteOrder(sSerialNumber,SizeOf(sSerialNumber));
        SetString(Result,sSerialNumber,SizeOf(sSerialNumber));
      end;
    end;
    在 Win2000下测试通过.
      

  4.   

    程序在WIN2000、ME、XP下都能通过,但在许多98下便不能通过!
    不知为什么?
      

  5.   

    有没有C语言或VB相应的代码?
    另外有的硬盘本身没有序列号,所以如果要用硬盘序列号加密实际上恐怕是不可行的