Link to home
Start Free TrialLog in
Avatar of wilmsoft
wilmsoft

asked on

Protect software by writing to hard drive sector

I need to protect my software by writing to a couple of sectors and then reading those sectors to make sure those sectors have what I put there.

Where and How do I do this with Delphi on Windows 2000 or XP?

This will software will be on a removable drive so network cards or CPU ID's is not an option.
Avatar of Hypoviax
Hypoviax
Flag of Australia image

I thought windows blocked direct hard disk writing. Correct me if i am wrong
Sorry, you said on a removable drive so what i said above would not apply
try to use NTFS Alternate Data Streams.. an amazing feature to hide things.
Alternate data streams is a great option, but if you really want to write directly to disk visit http://atlas.csd.net/~cgadd/knowbase/DRIVES.htm 

There is a lots of different disk handling routines including Read/Write Sectors/Boot Records.
Use unique MAC address:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Buttons, StdCtrls;

type
  TForm1 = class(TForm)
    SpeedButton1: TSpeedButton;
    MemoMAC: TMemo;
    procedure SpeedButton1Click(Sender: TObject);
  private{ Private declarations }
  public { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses
  NB30;


{$R *.dfm}

function GetAdapterInfo(Lana: Char): string;
var
  Adapter: TAdapterStatus;
  NCB: TNCB;
begin
  FillChar(NCB, SizeOf(NCB), 0);
  NCB.ncb_command := Char(NCBRESET);
  NCB.ncb_lana_num := Lana;
  if Netbios(@NCB) <> Char(NRC_GOODRET) then
  begin
    Result := 'MAC not found';
    Exit;
  end;

  FillChar(NCB, SizeOf(NCB), 0);
  NCB.ncb_command := Char(NCBASTAT);
  NCB.ncb_lana_num := Lana;
  NCB.ncb_callname := '*';

  FillChar(Adapter, SizeOf(Adapter), 0);
  NCB.ncb_buffer := @Adapter;
  NCB.ncb_length := SizeOf(Adapter);
  if Netbios(@NCB) <> Char(NRC_GOODRET) then
  begin
    Result := 'MAC not found';
    Exit;
  end;
  Result :=
    IntToHex(Byte(Adapter.adapter_address[0]), 2) + '-' +
    IntToHex(Byte(Adapter.adapter_address[1]), 2) + '-' +
    IntToHex(Byte(Adapter.adapter_address[2]), 2) + '-' +
    IntToHex(Byte(Adapter.adapter_address[3]), 2) + '-' +
    IntToHex(Byte(Adapter.adapter_address[4]), 2) + '-' +
    IntToHex(Byte(Adapter.adapter_address[5]), 2);
end;

function GetMACAddress: string;
var
  AdapterList: TLanaEnum;
  NCB: TNCB;
begin
  FillChar(NCB, SizeOf(NCB), 0);
  NCB.ncb_command := Char(NCBENUM);
  NCB.ncb_buffer := @AdapterList;
  NCB.ncb_length := SizeOf(AdapterList);
  Netbios(@NCB);
  if Byte(AdapterList.length) > 0 then
    Result := GetAdapterInfo(AdapterList.lana[0])
  else
    Result := 'MAC not found';
end;

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
  MemoMAC.Lines.Add(GetMACAddress);
end;

end.
1) Direct access to HDD is not enabled in NT/2000/XP. There are some code which are supposed to do that, but they don't work on NT platforms, only on 9x.
2) Writing directly to disk sector can damage the disk integrity if it is not used properly.
3) Why don't you use the Windows registry to store something inside ???
Get HDD Physical Serial Number under Windows 2000 or Windows XP:

//........

unit Unit1_Q_21076454;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Buttons, DBT, StdCtrls;

const
     IDE_ID_FUNCTION            = $EC; // Returns ID sector for ATA.
     CAP_IDE_ID_FUNCTION        = 1;   // ATAPI ID command supported
     IDENTIFY_BUFFER_SIZE       = 512;
     DFP_RECEIVE_DRIVE_DATA     = $0007c088;

type
  THDD_SN_Rec = record
    Root:      string[2];
    Hex:       string[40];
    Dec:       string[40];
  end;
  TForm1 = class(TForm)
    SpeedButton1: TSpeedButton;
    Memo1:    TMemo;
    procedure SpeedButton1Click(Sender: TObject);
  private   { Private declarations }
  public    { Public declarations }
  end;

  USHORT = Word;
  TIdBuffer    = array [0..IDENTIFY_BUFFER_SIZE-1] of Byte;
     TGetVersionOutParams = packed record
          bVersion      : BYTE;                 // Binary driver version.
          bRevision     : BYTE;                 // Binary driver revision.
          bReserved     : BYTE;                 // Not used.
          bIDEDeviceMap : BYTE;                 // Bit map of IDE devices.
          fCapabilities : DWORD;                // Bit mask of driver capabilities.
          dwReserved    : Array[0..3] of DWORD; // For future use.
     end;

     TIdSector = packed record
          wGenConfig                 : USHORT;
          wNumCyls                   : USHORT;
          wReserved                  : USHORT;
          wNumHeads                  : USHORT;
          wBytesPerTrack             : USHORT;
          wBytesPerSector            : USHORT;
          wSectorsPerTrack           : USHORT;
          wVendorUnique              : Array[0..2] of USHORT;
          sSerialNumber              : Array[0..19] of CHAR;
          wBufferType                : USHORT;
          wBufferSize                : USHORT;
          wECCSize                   : USHORT;
          sFirmwareRev               : Array[0..7] of CHAR;
          sModelNumber               : Array[0..39] of CHAR;
          wMoreVendorUnique          : USHORT;
          wDoubleWordIO              : USHORT;
          wCapabilities              : USHORT;
          wReserved1                 : USHORT;
          wPIOTiming                 : USHORT;
          wDMATiming                 : USHORT;
          wBS                        : USHORT;
          wNumCurrentCyls            : USHORT;
          wNumCurrentHeads           : USHORT;
          wNumCurrentSectorsPerTrack : USHORT;
          ulCurrentSectorCapacity    : ULONG;
          wMultSectorStuff           : USHORT;
          ulTotalAddressableSectors  : ULONG;
          wSingleWordDMA             : USHORT;
          wMultiWordDMA              : USHORT;
          bReserved                  : Array[0..127] of BYTE;
     end;

     TDriverStatus = packed record
          bDriverError : Byte;                 // Error code from driver, or 0 if no error.
          bIDEStatus   : Byte;                 // Contents of IDE Error register. Only valid when bDriverError is SMART_IDE_ERROR.
          bReserved    : Array[0..1] of Byte;  // Reserved for future expansion.
          dwReserved   : Array[0..1] of DWORD; // Reserved for future expansion.
     end;

     TSendCmdOutParams = packed record
          cBufferSize  : DWORD;               // Size of bBuffer in bytes
          DriverStatus : TDriverStatus;       // Driver status structure.
          bBuffer      : Array[0..0] of BYTE; // Buffer of arbitrary length in which to store the data read from the drive.
     end;

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

var
  Form1: TForm1;

var
  aIdBuffer: TIdBuffer;
  Id_Sector: TIdSector absolute aIdBuffer;
function  DirectIdentify(I: DWORD): Boolean;

implementation

{$R *.dfm}

var
  OSVersionInfo: TOSVersionInfo;

function GetPhysicalDriveHandle(DriveNum: Byte; DesireAccess: ACCESS_MASK): THandle;
var
  S:     string;
begin
  OSVersionInfo.dwOSVersionInfoSize := SizeOf(OSVersionInfo);
  GetVersionEx(OSVersionInfo);
  if OSVersionInfo.dwPlatformId=VER_PLATFORM_WIN32_NT then // Windows NT, Windows 2000
  begin
    Str(DriveNum,s); // avoid SysUtils
    Result := CreateFile( PChar('\\.\PhysicalDrive'+S), DesireAccess, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0 );
  end
  else // Windows 95 OSR2, Windows 98
    Result := CreateFile( '\\.\SMARTVSD', 0, 0, nil, CREATE_NEW, 0, 0 );
  {$ifdef debug}
  if Result=INVALID_HANDLE_VALUE then
    OutputDebugString(PChar('Error on CreateFile: '+SysErrorMessage(GetLastError)));
  {$endif}
end;

function SmartIdentifyDirect( hDevice : THandle; bDriveNum : Byte; bIDCmd : Byte; var IdSector : TIdSector; var IdSectorSize : LongInt ) : BOOL;
const
  BufferSize = SizeOf(TSendCmdOutParams)+IDENTIFY_BUFFER_SIZE-1;
var
  SCIP:        TSendCmdInParams;
            Buffer : Array [0..BufferSize-1] of Byte;
            SCOP : TSendCmdOutParams absolute Buffer;
            dwBytesReturned : DWORD;
begin
  FillChar(SCIP,SizeOf(TSendCmdInParams)-1,#0);
  FillChar(Buffer,BufferSize,#0);
  dwBytesReturned := 0;
  IdSectorSize := 0;
  // Set up data structures for IDENTIFY command.
  with SCIP do
  begin
    cBufferSize  := IDENTIFY_BUFFER_SIZE;
    bDriveNumber := bDriveNum;
    with irDriveRegs do
    begin
      bFeaturesReg     := 0;
      bSectorCountReg  := 1;
      bSectorNumberReg := 1;
      bCylLowReg       := 0;
      bCylHighReg      := 0;
      bDriveHeadReg := $A0 or ((bDriveNum and 1) shl 4);
      bCommandReg      := bIDCmd;     // The command can either be IDE identify or ATAPI identify.
    end;
  end;
  Result := DeviceIoControl( hDevice, DFP_RECEIVE_DRIVE_DATA, @SCIP, SizeOf(TSendCmdInParams)-1, @SCOP, BufferSize, dwBytesReturned, nil );
  if Result then
  begin
    IdSectorSize := dwBytesReturned-SizeOf(TSendCmdOutParams)+1;
    if IdSectorSize<=0 then IdSectorSize := 0 else System.Move(SCOP.bBuffer,IdSector,IdSectorSize);
  end;
end;

function  DirectIdentify(I: DWORD): Boolean;
var
  B:               Boolean;
  hDevice:         THandle;
  nIdSectorSize:   LongInt;
begin
  B := False;
  FillChar(aIdBuffer, SizeOf(aIdBuffer), #0);
  try
    hDevice := GetPhysicalDriveHandle(I, GENERIC_READ or GENERIC_WRITE);
    try
      {$ifdef debug}
      OutputDebugString(PChar('GetPhysicalDriveHandle return '+IntToHex(hDevice,8)));
      {$endif}
      if (hDevice<>INVALID_HANDLE_VALUE) then
      try
        B := SmartIdentifyDirect(hDevice, 0, IDE_ID_FUNCTION, Id_Sector, nIdSectorSize);
      finally
        {$ifdef debug}
        OutputDebugString('PrintIdSectorInfo end');
        {$endif}
      end;
    finally
      Result := B;
      CloseHandle(hDevice);
    end;
  except
    Result := False;
  end;
end;

function  Hex_To_Dec(S: string): Int64;
var
  C:      Char;
  J:      Integer;
  II:     Int64;
  IH:     Int64;
begin
  IH := 0;
  try
    II := 1;
    while (S<>'') do
    begin
      C := S[Length(S)];
      if (C in ['0'..'9']) then
        J := StrToInt(C)
      else
        J := Ord(C) - 55;
      IH := IH + II * J;
      Delete(S,Length(S),1);
      II := II * 16;
    end;
  finally
    Result := IH;
  end;
end;

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;

function  Physical_SN(Id: Integer): THDD_SN_Rec;
type
  TacOutBuffer  =  array[0..40] of Char;
var
  I:               Integer;
  IH:              Int64;
  acOutBuffer:     TacOutBuffer;
  T:               string;
begin
  IH := 0;
  try
    DirectIdentify(Id);
    //................................
    with Id_Sector do
    begin
      ChangeByteOrder(sSerialNumber, SizeOf(sSerialNumber));
      acOutBuffer[SizeOf(sSerialNumber)] := #0;
      StrLCopy(acOutBuffer, sSerialNumber, SizeOf(sSerialNumber));
      I := 0;
      T := '';
      while (acOutBuffer[I] in [#32..#127]) do
      begin
        T := T + acOutBuffer[I];
        Inc(I);
      end;
      T := Trim(T);
      IH := Hex_To_Dec(T);
    end;
  finally
    Result.Root := Char(Id+67) + ':';
    Result.Dec := IntToStr(IH);
    Result.Hex := T;
  end;
end;

procedure TForm1.SpeedButton1Click(Sender: TObject);
var
  S:             string;
  HDD_SN_Rec:    THDD_SN_Rec;
begin
  Memo1.Clear;
  S := '//................................................................';

  HDD_SN_Rec := Physical_SN(0); // C:
  Memo1.Lines.Add(HDD_SN_Rec.Root);
  Memo1.Lines.Add('Hex. Serial num:' + HDD_SN_Rec.Hex);
  Memo1.Lines.Add('Dec. Serial num:' + HDD_SN_Rec.Dec);
  Memo1.Lines.Add(S);

  HDD_SN_Rec := Physical_SN(1); // D:
  Memo1.Lines.Add(HDD_SN_Rec.Root);
  Memo1.Lines.Add('Hex. Serial num:' + HDD_SN_Rec.Hex);
  Memo1.Lines.Add('Dec. Serial num:' + HDD_SN_Rec.Dec);
  Memo1.Lines.Add(S);
end;

end.

//........

object Form1: TForm1
  Left = 256
  Top = 128
  BorderIcons = [biSystemMenu, biMinimize]
  BorderStyle = bsSingle
  Caption = 'Form1'
  ClientHeight = 293
  ClientWidth = 344
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  Position = poDesktopCenter
  PixelsPerInch = 96
  TextHeight = 13
  object SpeedButton1: TSpeedButton
    Left = 16
    Top = 8
    Width = 128
    Height = 22
    Caption = 'Get physical SN'
    OnClick = SpeedButton1Click
  end
  object Memo1: TMemo
    Left = 16
    Top = 32
    Width = 256
    Height = 256
    ReadOnly = True
    TabOrder = 0
  end
end
Avatar of DavidBirch2dotCom
DavidBirch2dotCom

If you did write to the harddrive or even an external one, what happens when you defragment it ?
Copy protection using hardware dependant methods eventually fail, any user will want/have to upgrade his/her system in time.

Writing to a disc sector directly will require different code/methods for different operating systems, (Windows 9x/XP ...) this means you will have to write and debug much more code. And this scheme may fail if user uses defrag or other disk analyzing/recovery tools.

Your copy protection scheme should not affect your legitimate users. And you probably would not want giving new keys/etc for every user again and again because your program does not work when they changed their disks.

My hard learned advice to you will be: use registration information with user specific data, and store it in an ordinary way, (key files, registry etc.). That user spesific data can be user/company name and you can put this info on every screen or report they print out.

If computers have a network connection you can broadcast this data to network periodically and check how many instances of your program is being used in a network.

Avatar of wilmsoft

ASKER

Yes, I know all of the problems with this type of protection system, HOWEVER. My program is on a USB stick. I don't want people to copy the program to another USB stick. The stick can be run on any computer the protection needs to be on the stick. So, any of the key files, registry, NIC card or CPU approach will cause the software to fail....
One answer may be reading the starting sector of your executable and then recording it somewhere, checking it in every run, but this will be fairly easy to circumvent.

Some USB flash memory products comes with proprietary security software that can enable users to create a secure, password protected partition. If you can contact the vendor of such a product they may provide you an API to set up and access this secure partition in your program. Then you can use this partition to keep copy protection information. Since users cannot access this partition without a password it will not be possible to copy your software to another disk.

Of course this means you will be able to use only one vendor's USB media.

The security software provided by USB vendors require thier software to be loaded on the users computer to access the protected partition. I can't have that be a requirement on every possible computer this MAY run on.
Avatar of Wim ten Brink
Doesn't the USB stick have some unique ID somewhere, just like other disks? Some kind of serial number? Can't you check if the software is installed on the USB and the USB is of brand "X" with serial number "Y"?

And USB flash devices will require installation of drivers on any pre-W2K system... And some even for W2K itself.
the idea is good
if the stick has a unique id then you can use the same prodedures as if you would
install them programm on a normal harddrive and the user has to re-register if he
changes the hardware
Ordinary memory sticks do not have an unique ID. They have some sort of hardwareID but it is not unique, and is used to identify usb hardware to host computer.

There are some memory sticks with unique id feature but they also require installation of drivers to host system.
then you are screwed
as the medium your software runs on is not unique you have no chance of
detecting that the media you are just running on is not the same as before.

i think you need a workaround and think about other possibilities
normal copyprotection doesnt look viable to me
"then you are screwed " and "i think you need a workaround"...

You are missing the point!

I want to write a unique number my self to a couple of sectors on the drive. Then I don't have to worry about the vendor. Thus the question! How do I write to a couple of sectors on the USB stick?

I thought you people were the "experts"?
being an expert doesnt mean to be able to do impossible things
normally its always a tradeoff between money and quality
you can get all you want if you just pay enough
but most people want "good enough" quality so that it fits their needs
and is affordable.
if there is a way to write on a storage media in the way you suggest there
would be no need for copy protection on cd.
as the media the program is on is not distinct from other medias
you need to make it different. but that means you have to change it
and if you can change it others can change it too.
that is the reason why the harddisk numbers are used as they
are not changeable.

if you spend enough time, effort and maybe money you'll eventually get your solution
but it looks like you won't get it for free as long as you don't accept and think
about a workaround
I ran the following compiled exe on my keydrive and it worked fine. It might be of use to you:

Drop two EditBoxes onto a form and use the following code:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  StartDir, SerialNum: String;
  DriveLetter: Char;
  Serialcode: dword;
implementation

{$R *.DFM}

function GetDiskVolSerialID(DriveID: char ): DWord;
var
  Temp : DWord;
begin
  GetVolumeInformation(PChar(DriveID + ':\'), Nil, 0, @Result, Temp, Temp, Nil, 0);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  GetDir(0,StartDir);
  Edit1.Text := StartDir;
  DriveLetter := StartDir[1];
  Serialcode := GetDiskVolSerialID(DriveLetter);          // Drive Serial Number
  SerialNum:=Format('%X',[Serialcode]);
  Edit2.Text := SerialNum;
end;

end.

The string SerialNum contains the HD serial number of the drive your program is run on. Keydrives, being a form of drive also have serial numbers, so you can check those just like hard disks.

If you are installing your program on each keydrive, you can hardcode a check for the correct serial number of the keydrive you install it onto. If a different serial number is returned, (ie it's copied to another keydrive or the hard disk), then you can prevent all or some of the programs functions from working.

Alternatively, use some encryption method to generate an ID number and request an unlock key. You can then supply the key.

This method works OK, but is not failsafe. It will stop casual users from copying your program, but anyone with the correct skills will be able to get around it - but that is true of *ANY* protection method!

TDK_Man

tdk_man

Yea, I first went this route. but, I still have no control over the number. If I would change manufacture I would have to change the code. I could NOT find any way to WRITE or change the serial number....

Do you know of any way to change the serial code? Then your code would work great!
I've recently read a post on some forum somewhere saying that it was impossible to change a disk's serial number, but it is possible. The point is, why would you want to change the serial number?

You want each keydrive to have a different number so that your program only runs on the keydrive you install it onto. The more keydrives you have with the same number, the more keydrives your program will run on.

The whole idea behind the method is that when your program runs, it checks to see if the serial number of the drive it has been run from is what your program thinks it should be. If it isn't, it's a copied version, so the program quits.

For example, you write a little utility which you copy to the keydrive you want to install your program onto and then run it. It tells you the keydrive's serial number.

You then code that number into your program, compile it and put the exe on that keydrive. Your program will then only run on that keydrive.

If you want to put the program onto another keydrive, you repeat the process, code the new serial number it gives you into your program, compile and put the exe onto that keydrive. And so on.

I may be misunderstanding your question, but this is a simple way to stop people copying your program off the keydrive and using it somewhere else.

The only 'control' you could have over the serial number is by doing what I do to my programs - encrypt the serial number from the users machine to create an 'ID' number which they supply to me. I have a utility which I enter their ID code into and it generates a 'license key'. When they purchase a key, they enter it into the program which allows them to use it.

If the program is copied to another machine, the ID created is different, their existing key will no longer work and the program will either not run or has limited functionality.

Isn't this what you are after?

TDK_Man
Oops - forgot to mention that the serial number is device independant. Every keydrive from the same manufacturer will have a different serial number!

"If I would change manufacture I would have to change the code."

I think you are under the assumption that all keydrives from the same manufacturer have the same serial number - which is not true.

TDK_Man
Your close there are few problems:

1) I have 150 Keys from a manufacture. They all have the same serial number. However, the manufacture can't tell me that it will stay that way forever.

2) I can't use any machine ID because the program IS design to run on any computer the key is plugged in to. So, the copy protection must stay with the key.

3) The key is purchased with the software on it so, registration and encrypted key code that I supply them is out of the question as they already paid and such.

So, I want to:
On start up of the program create a unique ID, stamp the drive with it (any way possible). Store the ID in my encrypted Database. Now I can check the ID of the drive with the ID of the EXE and test if it has been copied. Changing the serial number to me is a great idea. but, I can't figure out how to change it, only read it.

And sure, somebody could figure out that the serial number is the key, change the next drive to match but, like it was said "if you can change it others can change it too." but, I'll slow them down a little...  ; )
 
OK, can you confirm something for me please?

When you run the exe produced with my code above on your keydrives, do they *all* return the same serial number?

I'm not suggesting that you are mixing the two up, but the keydrive serial number and the disk volume serial number may not be the same thing. (I'd be very surprised if they all have the same disk volume serial number).

Assuming that you are correct and I'm not, I'll see if I can find the code for changing the serial number for you.

In response...

2) I'm not suggesting you use the machine's ID. I'm suggesting that you create an ID number from the disk volume serial number of the keydrive your software is installed on and tell your program only to run if it's startup directory is on a volume with the same ID.

If you are correct and they all have the same serial number, your program would only run on those keydrives - but not on someone's hard disk or a keydrive from another manufacturer. It would apparently run on another keydrive from the same manufacturer though.

TDK_Man
TO: tdk_man

Just to make sure I was not confusing the two. I ran your sample code on two USB drives. BOTH report:

221416EE

as the serial number...

Which is what I thought but, in all of these posts, I WAS getting confused! (Your effort has been greatly appreachated!)

We are on the same page I want to:

"create an ID number from the disk volume serial number of the keydrive your software is installed on and tell your program only to run if it's startup directory is on a volume with the same ID. "

Accept that I want to make sure the number is Unique because some who gets the same drives could copy the program! (which I believe, is what your suggesting as well)

but, I can't find any code anywhere to change the drive serial number and some posts here suggest that it can't be done at all so, my 2nd thougt was the orginal post which was (if I can't do that then) write to a couple of sectors and then reading those sectors to make sure those sectors have what I put there.

BUT, if you think I can change the serial number I would like to go that way.

Thanks for your input!
OK, no problem. It's very late here now, so I'll dig out my archive disks tomorrow and see if I can find the code for you.

TDK_Man
Just to chip in a bit... if you are able to change the serial number of the drive, what is to stop other people from copying your software and modifying their drive's serial number to match yours?
wilmsoft:

changing volume serial id is possible and easy. you even do not have to write any code to do it. Sys Internals have a little program that does just this for FAT and NTFS file systems

http://www.sysinternals.com/ntw2k/source/misc.shtml#volumeid

since anyone can change this id, it is a very weak form of copy protection.
Hi wilmsoft,
as I posted into my 2 comments at 07/30/2004 you can:
1.1. Use unique MAC address;
or
1.2. Get HDD Physical Serial Number under Windows 2000 or Windows XP;

1. let's say this is UNIQUE_NUM (1.1. or 1.2.)

2. Encrypt the UNIQUE_NUM and save it into your database (if you have one) or into the registry, or into the .txt file;

3. When your application would be started every time it will :
3.1. Get the UNIQUE_NUM;
3.2. Encrypt it;
3.3. Read saved previously Encrypted one from the database (if you have one) or into the registry, or into the .txt file;
3.4. Compare just extracted & encrypted value 3.2. with readed value 3.3. and if they are EQUAL the programm will work, otherwise will halt.
>> if you are able to change the serial number of the drive what is to stop other people from copying your software ...

1) you'd have to know how to. (and I'm still not sure that you can)
2) you'd have to know that's what I'm doing.
3) you'd have to know WHAT to change it to. (nothing stopping me from doing a "rolling" key, like your garage door openers do)
4) of course. That's what hackers do and I can't stop all of them but, I'd like to slow them down.

as to esoftbg,
Maybe I don't understand what your saying but, it seems to me like your using hard ware on the computer to check. IF that is what your saying, then we are not on the same page. You see, the software on the USB key can NOT be copied to another USB drive. But, the USB drive needs to run on ANY hardware. So, if I store something in the registery (for example, point 2) and then take the USB key to the next computer, it would not run. But, it has to run on the next computer. Which didn't have the Register edit...

Thus, my need to have the security on the USB drive. NOT the compter. Otherwise I'd be done with this code all ready...

Thanks for your input though... this site ROCKS....
I forgot this question ....
>You see, the software on the USB key can NOT be copied to another USB drive. But, the USB drive needs to run on ANY hardware. So, if I store something in the registery (for example, point 2) and then take the USB key to the next computer, it would not run. But, it has to run on the next computer.

O.k. if you would like to run the software on every computer, then you don't need a protection for that software ....
If you need a protection for the software you need to identify the computers where the software is rightful and where is not:
1). On the computer where you'd like to start the software you may get the hardware serial number of the primary HDD and to save in any encrypted format into the registry, or into and .ini file or .... (it's your decision);
2). On every start of the software it would read the serial number of the primary HDD, encrypt it and to compare with the saved one: if they are identical software will work, but if the are not, the software will not work
3). This way your software will be protected !
one way to prevent the copying of software is to present the licensing information in a way
that the users dont want to give it away.
like a screen where you tell the user that this program is licensed for ... ( with name adress and phone number)
for the legitimate user it will pose no problem and it will make it harder for him to give it
away as he will have no control about the spreading around of the software and he will be
held responsible for any actions.

one disadvantage is that you have to license every single copy but with any usb copy protection
you would hava nearly the same amount of work
to esoftbg,

>>>O.k. if you would like to run the software on every computer, then you don't need a protection for that software

I'm sorry, I'm not making my self clear. Please. Think out of the box here for a moment. If you own the USB drive, purchased from me, you can run it on any computer. This does NOT suggest I don't need protection for the software. It means I need protection from some one copying the software off of my USB drive to another USB drive or a different hard drive.

Yes, I need software protection. TO THE DRIVE ITSELF NOT THE COMPUTER!

It's not impossible just out of the box a bit...
its the same problem in another context

if you dont want users to be able to copy your usb content onto another drive, then that is like implementing a copy protection for your software
and that can be accomplished via registryinformation. it wont prevent copying but it will discourage the user from spreading around his personal informations

and maybe it is possible but if you want a fast solution i think this is they way to go as
it look like the other experts here also dont know a way to identify an usb stick
"it wont prevent copying...."

Yes, then it won't achieve what I'm after.

Thanks for the input though!
I never have been see an USB drive, so excuse my lack of knowledge about ....
to esoftbg,

No problem.

The USB drive, once plugged in, looks to the computer as just another Drive. So, my software resides on the USB drive and is never copied to the "host" computer, just executed from the USB drive. This way you can licesene the USB drive, give it some copy protection, and let the user run the software where ever they needed becuase the USB drive and thus the software has been paid for.

BUT, if they just copy the software to a USB drive that is not from me, I don't want it to work any more.

All I need to figure out is to change the USB drive Serial Number. I see where you can do it in C++, I just haven't the time or knowage to convert it to Delphi. But, some "expert" must have done this before... No?


OK, the code for changing the serial number of a drive is DOS only and doesn't work in Windows - well my version doesn't anyway.

However, there is a way to do it in Windows - format the Key drive!

Using the code I posted earlier, you can then read the serial number that the format created and hardcode it into the exe you put on that keydrive so that it doesn't run if you try to run it off any other drive.

This means that you have to recompile a version for every keydrive you format, though this isn't too much of a problem if there aren't too many of them.

If there are, you can write a routine in your main program to produce a 'computer ID' from the serial number of the keydrive it is run off. (You can write a keygen program which will generate a license key from the ID your program provides).

Your exe would only run when the correct license key is present and moving the prog onto a different drive will mean that the ID generated from that serial number and the current key will no longer match. Result - the prog will no longer run.

TDK_Man
TDK_Man,

Are you saying that formating the drive changes the serial number?
Well, I did a test, and indeed the serial number changed!!!

That rocks...

Okay, now my question would be how do I write a program to format a drive. Because I do have a bunch (1000's) of keys to load but, I have a loader program. All I need to do is add format the drive to the loader and that would be good.

How random is the serial number?

TDK_Man, You rock!

ASKER CERTIFIED SOLUTION
Avatar of tdk_man
tdk_man

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks TDK_MAN!

You've re-newed my faith in experts-exchange. It seems every time I asked a tougher question, there was no help!

I will accept your answer!

Oh, yea, and Windows vs my loader program: We have 1000's of keys to load and some "help" that just plugs in multi-keys to a fixture, hits a button and loads the software. Then they unplugs all the keys and packages them to ship. So, I don't want to format these one at a time.

Thanks again!
Glad I could help...

and good luck!

TDK_Man
@wilmsoft you do not need to format your keydrive to change the serial number of your disk, you (and everyone else) can change the drive serial id with the program I said in my previous comment.

http://www.sysinternals.com/ntw2k/source/misc.shtml#volumeid
to: alikoank,

Yes, but, "This is a command-line program that you must run from a command-prompt window."

Correct me if I'm wrong but, that means I can't write a Delphi unit and build it in to my program.  Even if you suggest that my program opens a DOS window to do so, Feedback from DOS is a bitch (ie function fails, or when it's complete etc...)

Or am I missing something?


It is not a DOS program it is a windows program that uses console for input. Spawning it from your program is no diffferent from spawning format.exe
alikoank,

True, it's no different then spawning 'format.exe' but, it IS a lot different then using an API call like 'SHFormatDrive' where I get the results to know when it's done or if it failed.