Delphi Get Serial Number Hardisk

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 10

DELPHI GET SERIAL NUMBER HARDISK

Something like this:


Function:

function GetHDDSerialNumber(NomDrive:byte) : 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
// Error code from driver, or 0 if no error.
bDriverError : Byte;
// Contents of IDE Error register. Only valid when bDriverError is
SMART_IDE_ERROR.
bIDEStatus : Byte;
bReserved : Array[0..1] of Byte;
dwReserved : Array[0..1] of DWORD;
end;
TSendCmdOutParams = packed record
// Size of bBuffer in bytes
cBufferSize : DWORD;
// Driver status structure.
DriverStatus : TDriverStatus;
// Buffer of arbitrary length in which to store the data read from the
drive.
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;
const
IdeDriveNom='\\.\PhysicalDrive';
begin
Result :='Error'; // return empty string on error
if SysUtils.Win32Platform=VER_PLATFORM_WIN32_NT then // Windows NT, Windows
2000
begin
// warning! change name for other drives: ex.: second drive
'\\.\PhysicalDrive1\'
hDevice := CreateFile( PChar(IdeDriveNom+IntToStr(NomDrive)),
{'\\.\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;
Result := PChar(@sSerialNumber);
end;
end;

and get serial into string:

procedure TForm1.btnGetHDinfoClick(Sender: TObject);


var
getHDSerial : string;
begin
getHDSerial := GetHDDSerialNumber(0);
end;

or ShowMessage:

ShowMessage( GetHDDSerialNumber(0));

I am trying to using the following read HDD sn function in delphi:

Code:
function GetHardDiskSerial(const DriveLetter: char): string;
var
NotUsed : dWord;
VolumeFlags : dWord;
VolumeInfo : array[0..MAX_PATH] of char;
VolumeSerialNumber: dWord;
begin
GetVolumeInformation(PChar(DriveLetter + ':\'),
VolumeInfo, SizeOf(VolumeInfo),
@VolumeSerialNumber, NotUsed,
VolumeFlags, nil, 0);
result := Format('%14s | %X |',
[VolumeInfo, VolumeSerialNumber])
// result := IntToStr(VolumeSerialNumber);
end;

This function retrieves a serial number of HDD but it isn't the one provided by the manufacturer.

I say that because if I run this function it returns one serial number but if I format the drive, this
serial number is changing. It is like disk_label (changes on every format). I need the serial
number (unique for every HDD), which is eventually stored in a ROM or something...
Patcher (.pas) unit for Delphi (makes patching easier)

Okay... I want to share my patcher.pas unit.


This unit makes it a lot easier to create a patcher.
This unit is for Delphi programmers.

No more downloadable,
because it's here:

PATCHER.PAS
unit Patcher;

{ Patcher Unit V1.0.0.0 - Patcher.pas }


{ Copyright 2008 Joonas905 / JaX2JoN50. }
{ You can freely use, edit or redistribute this unit, }
{ but this copyright notice must remain. }
{ Unit comes with absolutely NO WARRANTY! }

interface

uses
SysUtils;

type
ByteArray = Array of Byte;
TPatches = Array of Record
Offset: Cardinal;
Bytes: ByteArray;
end;
TPatcher = class
private
fInit: Boolean;
fHandle: Integer;
public
constructor Create( FileName: String );
destructor Destroy; override;
procedure Add( Offset: Cardinal; Bytes: ByteArray );
procedure PatchFile;
end;

implementation

var
Patches: TPatches;

constructor TPatcher.Create( FileName: String );


begin
fInit := False;
if FileExists( FileName ) = True then
begin
inherited Create;
fHandle := FileOpen( FileName, fmOpenReadWrite );
if fHandle <> -1 then
fInit := True;
end;
end;

destructor TPatcher.Destroy;
begin
if fInit = True then
begin
fInit := False;
FileClose( fHandle );
SetLength( Patches, 0 );
inherited Destroy;
end;
end;

procedure TPatcher.Add( Offset: Cardinal; Bytes: ByteArray );


var
Size: Cardinal;
begin
if fInit = True then
begin
Size := Length( Patches );
SetLength( Patches, Size + 1 );
Patches[Size].Offset := Offset;
Patches[Size].Bytes := Bytes;
end;
end;

procedure TPatcher.PatchFile;
var
I, X, Size: Cardinal;
Line: String;
begin
if fInit = True then
begin
Size := Length( Patches );
if Size > 0 then
begin
for I := 0 to ( Size - 1 ) do
begin
FileSeek( fHandle, Patches[I].Offset, 0 );
Line := String( Patches[I].Bytes );
for X := 1 to ( Length( Line ) - 1 ) do
FileWrite( fHandle, Line[X], 1 );
end;
SetLength( Patches, 0 );
end;
end;
end;

end.
EXAMPLE
Code:

unit Unit1;

interface

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

type
TForm1 = class(TForm)
Button1: TButton;
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click( Sender: TObject );


var
Patcher: TPatcher;
Bytes: ByteArray;
begin
// Set length
SetLength( Bytes, 2 );
Bytes[0] := $90; // NOP
Bytes[1] := $90; // NOP
// Let's create a patcher instance
Patcher := TPatcher.Create( {Filename here} );
// Add few patches to be made
// Patcher.Add( {Offset}, {Bytes} );
Patcher.Add( 0, Bytes );
// And we patch
Patcher.PatchFile;
// Finally destroy
Patcher.Destroy;
end;

end.
CRACK BOX

:0041403D eax, eax ; eax=length of serial


:0041403F jne 0041407 ; if not zero, jump to 00414079
:00414041 push 00000010 ; else...
:00414043 push 0042490C; push error messages
:00414048 push 004248BC ; for ..
:0041404D push ebp
:0041404E Call dword ptr [004202AC] ; .. Message
:00414054 push 00000471
:00414059 push ebp
:0041405A Call dword ptr [004202B0]
:00414060 push eax
:00414061 Call dword ptr [004202B4]
:00414067 mov eax, 00000001 ; eax=1 => bad
:0041406C pop edi ; stack
:0041406D pop esi
:0041406E pop ebp
:0041406F pop ebx
:00414070 add esp, 00000784
:00414076 ret 0010 ; leave call with eax=1
:00414079 mov ebx, dword ptr [004202F4] ; we land if serial is entered
:0041407F lea edx, dword ptr [esp+14] ; edx=name
:00414083 push edx
:00414084 lea eax, dword ptr [esp+6C]; eax=first name
:00414088 push 00422170 ; push 'HappyIcon' (constant)
:0041408D push eax
:0041408E lea ecx, dword ptr [esp+5A0]
:00414095 push 004248B4 ; push '%s%s%s'
:0041409A push ecx
:0041409B call ebx ; this make our new string
:0041409D lea edi, dword ptr [esp+5A8] ; and move it to edi
:004140A4 or ecx, FFFFFFFF
:004140A7 xor eax, eax
:004140A9 add esp, 00000014
:004140AC repnz
:004140AD scasb
:004140AE not ecx
:004140B0 sub edi, ecx
:004140B2 lea edx, dword ptr [esp+00000190]
:004140B9 mov eax, ecx
:004140BB mov esi, edi
:004140BD mov edi, edx
:004140BF shr ecx, 02
:004140C2 repz
:004140C3 movsd
:004140C4 mov ecx, eax
:004140C6 lea eax, dword ptr [esp+190] ; new string to eax
:004140CD and ecx, 00000003
:004140D0 repz
:004140D1 movsb
:004140D2 mov cl, byte ptr [esp+190]; CALCULATION BEGINS HERE
:004140D9 test cl, cl ; cl=ascii of first char
:004140DBje 004140FC; if there's no ascii jmp
:004140DD; cmp byte ptr [eax], 5F; cmp ascii with 5Fh ('_')
:004140E0 jne 004140E5 ; if so, ...
:004140E2 mov byte ptr [eax], 20 ; ascii is 20h (' ')
:004140E5 movsx ecx, byte ptr [eax] ; ascii to ecx
:004140E8 xor ecx, dword ptr [esp+10] ; xor ecx with [esp+10]
:004140EC xor ecx, 13579ACE ; xor ecx with 13579ACEh
:004140F2 inc eax ; eax(name) + 1 (next char)
:004140F3 mov dword ptr [esp+10], ecx ; [esp+10] = ecx
:004140F7 cmp byte ptr [eax], 00; cmp name with 00 .. LOOP
:004140FA jne 004140DD if there're some chars, jump back .. LOOP
:004140FC lea edx, dword ptr [esp+0BC] ; serial to edx
:00414103 push edx
:00414104 call 0041637C ; serial test (if avaible etc.)
:00414109 mov ecx, dword ptr [esp+14]; mov [esp+10] (from calculation)
to ecx
:0041410D add esp, 00000004
:00414110 xor ecx, 2468BDF0 ; xor ecx (= [esp+10]) with
2468BDF0h
:00414116 cmp eax, ecx ; cmp serial(? eax) with real(?
ecx)
:00414118 je 00414148

uses crt; ; standart


var ; declare variables
name, fname, endname: string ; all strings
ecx, i : longint; ; register as longint
esp: longword; ; MUST BE longword ...
; or you get negative
code
begin ; code start
writeln('KeyGen for 3ds max 9 by FureiYa'); ; Text=xGenerate
writeln;
write('Name: ');
readln(name); ; read in your name
write('First Name: ');
readln(fname); ; read in first name
endname:= fname, 'Autodesk', name; ; make string
esp:= $FFFFFFFF; ; first value of esp

For i:= 1 to length(endname) do ; start loop


begin
ecx:= ord(endname[i]); ;\
If ecx = $5F then ecx:= $20; ; \
ecx:= ecx ord esp; ; > Calculation
ecx:= ecx ord $13579ACE; ; /
esp:= ecx; ;/
end;

esp:= esp xor $2468BDF0; ; xor loop result

writeln('Serial: ', esp); ; post serial


end.

You might also like