Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

Set of number which **not** change after format computer

Posted on 2006-04-09
8
Medium Priority
?
400 Views
Last Modified: 2010-04-05
Hi Experts!

I'm writing application which is shareware (30 days trial) and have a registration system,
in this system, at first I will get volume information (GetVolumeInformation) and use this
set of number to calculate (with my own equation) an Activation Code to register

Problem is, after user format their haddisk, and re-install my program again. This Volume Number changed.
That means user must register again (pay for licence again). I don't want to do this, so i try to find some
set of number which NOT change when user format their drive...

The last one, if you have my answer, will your answer compatible with ALL Windows Version?

Please, someone tell me some direction?

Thanks!
0
Comment
Question by:xtrue
8 Comments
 
LVL 28

Accepted Solution

by:
2266180 earned 1500 total points
ID: 16411790
well .. one way to go that really doesn't change too often is using some otehr programs serial or activation key (like windows ;) ). because hardware changes occure generally once 1-2 years. anotehr way to go is using the MAC of the network interface. this again is only changing when the network card dies (very very rare) or the user spoofs it (in which case it's his fault)
you could of course use multiple such numbers (MAC, windows activation key (it's in the registry by the way) and some otehr hardware serial number or ID (like the CPU)) and compute 3 -4 activation codes and the final activation code will be the 3-4 codes put one after another. then, if 1 changes, you can see which one changed and if the other ones are the same, you update the on ethat changed (it's very rare when the person is changing the whole PC)
of course, there is no perfect way to achieve what you want, you will have to leave a small niche.

an idea would be to send the user a cd with the software, and on the cd try to hide the key in such a manner that it will not be copied over anotehr cd when doing an image (like simulating "bad sectors" or othervise exploit some weaknesses in the cd filesystem: never looked at it so I don't know if it can be done, but it looks like a good idea). in this case, the user will have to install always from it's original disk. And, if you keep a list with your customers, then you can give them the possibility of replacing the original cd with a new one in case they damage it in some way (and of course you can control and see if indeed it's the original cd or not)

Thelast way would be the one that I would choose if being in your situation :)
0
 
LVL 12

Expert Comment

by:AmigoJack
ID: 16411961
one system device which changes rarely is the processor. the advantage is: the user can reformat anything and also install every windows-version. you could get a string of infos out of this:

var
  s: _system_info;
  s1: string;
begin
  getsysteminfo(s);
 
  s1:= inttohex(s.wProcessorArchitecture, 4)
//     + inttohex(s.wProcessorLevel, 4)
//     + inttohex(s.wProcessorRevision, 4)
     + inttohex(s.wReserved, 4)
     + inttohex(s.dwPageSize, 8)
     + inttohex(s.dwProcessorType, 8);
end;

the lines which are commented out will give different values based on the windows type (95 versus NT). but the info above is very little and i think many users will come up with the same string.

you could combine it with GetVolumeInformation() - but dont get the serial of the formatted drive - get instead its capacity (because that will not change - got it?).

other methods would be to get the vendor description of one harddisk or the processor, that wont change too.

a classic (but also not perfect) way is to simply compute a value out of the users name and its birth date. that requires interaction of course, like writing a mail to register
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 16420440
Hi xtrue, I know this is already a PAQ, but if you really need the serial number of the hard disk which *doesn't* change even after a formatting, try this code:

unit HDD_Serial;
interface
uses Windows, SysUtils;
function GetHddSerial: String;
implementation
function GetIdeDiskSerialNumber: 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 for future use.  Must be zero.
end;
IDEREGS   = TIDERegs;
PIDERegs  = ^TIDERegs;
TSendCmdInParams = packed record
  cBufferSize  : DWORD;                // Buffer size in bytes
  irDriveRegs  : 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 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; // 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;
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 := '';
FillChar(Buffer,BufferSize,#0);
if Win32Platform=VER_PLATFORM_WIN32_NT then
  begin // Windows NT, Windows 2000
    // 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;
  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 := PChar(@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;
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..SizeOf(TScsiPassThroughWithBuffers)+SizeOf(TScsiPassThrough)-1] 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;
function GetHddSerial: String;
var
 NumTry: Byte;
 FinalStr: String;
 hDevice: THandle;
 sDeviceName: String;
begin
 NumTry := 1;
 Repeat
    Case NumTry Of
       1:
          Begin
             FinalStr := Trim(GetIdeDiskSerialNumber);
          End;
       2:
          Begin
             sDeviceName := 'C:';
             hDevice := GetDeviceHandle(sDeviceName);
             If hDevice <> INVALID_HANDLE_VALUE Then Begin
                Try
                   FinalStr := Trim(ScsiHddSerialNumber(hDevice));
                Finally
                   CloseHandle(hDevice);
                End;
             End;
          End;
       3: Begin
             FinalStr := 'Error!';
          End;
    End;
    Inc(NumTry);
 Until (FinalStr <> '') Or (NumTry > 3);
 Result := FinalStr;
end;



Regards,
DragonSlayer.
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:xtrue
ID: 16423680
Hi DragonSlayer!

Can this code compat with all Windows Version?

By the way, thanks for your help!
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 16424208
Yup :-)
0
 

Author Comment

by:xtrue
ID: 16424780
Again, DragonSlaver!

In your code i got both number and character (14 lengths), is that right ?

So i have to convert character to number because in my case i want this set of number
to calculate (+,-,*,/)


Thanks,



0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 16427473
Yup. You can always treat it as a sequence of 7 hex pairs, or do your own conversion to numbers.

Regardless, it will always be able to correctly and uniquely identify the same hard disk :-)



DragonSlayer.
0
 

Author Comment

by:xtrue
ID: 16433025
thanks!
0

Featured Post

[Webinar On Demand] Database Backup and Recovery

Does your company store data on premises, off site, in the cloud, or a combination of these? If you answered “yes”, you need a data backup recovery plan that fits each and every platform. Watch now as as Percona teaches us how to build agile data backup recovery plan.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
this video summaries big data hadoop online training demo (http://onlineitguru.com/big-data-hadoop-online-training-placement.html) , and covers basics in big data hadoop .
In a question here at Experts Exchange (https://www.experts-exchange.com/questions/29062564/Adobe-acrobat-reader-DC.html), a member asked how to create a signature in Adobe Acrobat Reader DC (the free Reader product, not the paid, full Acrobat produ…
Suggested Courses

581 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question