Sei sulla pagina 1di 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.

Potrebbero piacerti anche