mirror of
https://github.com/fast4x/datalock.git
synced 2025-04-13 01:21:58 +02:00
183 lines
3.8 KiB
ObjectPascal
183 lines
3.8 KiB
ObjectPascal
unit UPayload;
|
|
|
|
{$MODE Delphi}
|
|
|
|
interface
|
|
|
|
type
|
|
TPayload = class(TObject)
|
|
private
|
|
fFileName: string;
|
|
fOldFileMode: Integer;
|
|
fFile: File;
|
|
procedure Open(Mode: Integer);
|
|
procedure Close;
|
|
public
|
|
constructor Create(const FileName: string);
|
|
function HasPayload: Boolean;
|
|
function PayloadSize: Integer;
|
|
procedure SetPayload(const Data; const DataSize: Integer);
|
|
procedure GetPayload(var Data);
|
|
procedure RemovePayload;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
ActiveX;
|
|
|
|
type
|
|
TPayloadFooter = packed record
|
|
WaterMark: TGUID;
|
|
ExeSize: LongInt;
|
|
DataSize: LongInt;
|
|
end;
|
|
|
|
const
|
|
cWaterMarkGUID: TGUID =
|
|
'{9FABA105-EDA8-45C3-89F4-369315A947EB}';
|
|
cReadOnlyMode = 0;
|
|
cReadWriteMode = 2;
|
|
|
|
procedure InitFooter(out Footer: TPayloadFooter);
|
|
begin
|
|
FillChar(Footer, SizeOf(Footer), 0);
|
|
Footer.WaterMark := cWaterMarkGUID;
|
|
end;
|
|
|
|
function ReadFooter(var F: File;
|
|
out Footer: TPayloadFooter): Boolean;
|
|
var
|
|
FileLen: Integer;
|
|
begin
|
|
// Check that file is large enough for a footer!
|
|
FileLen := FileSize(F);
|
|
if FileLen > SizeOf(Footer) then
|
|
begin
|
|
// Big enough: move to start of footer and read it
|
|
Seek(F, FileLen - SizeOf(Footer));
|
|
BlockRead(F, Footer, SizeOf(Footer));
|
|
end
|
|
else
|
|
// File not large enough for footer: zero it
|
|
// .. this ensures watermark is invalid
|
|
FillChar(Footer, SizeOf(Footer), 0);
|
|
// Return if watermark is valid
|
|
Result := IsEqualGUID(Footer.WaterMark, cWaterMarkGUID);
|
|
end;
|
|
|
|
procedure TPayload.Close;
|
|
begin
|
|
// close file and restores previous file mode
|
|
CloseFile(fFile);
|
|
FileMode := fOldFileMode;
|
|
end;
|
|
|
|
constructor TPayload.Create(const FileName: string);
|
|
begin
|
|
inherited Create;
|
|
fFileName := FileName;
|
|
end;
|
|
|
|
procedure TPayload.GetPayload(var Data);
|
|
var
|
|
Footer: TPayloadFooter;
|
|
begin
|
|
// open file as read only
|
|
Open(cReadOnlyMode);
|
|
try
|
|
// read footer
|
|
if ReadFooter(fFile, Footer)
|
|
and (Footer.DataSize > 0) then
|
|
begin
|
|
// move to end of exe code and read data
|
|
Seek(fFile, Footer.ExeSize);
|
|
BlockRead(fFile, Data, Footer.DataSize);
|
|
end;
|
|
finally
|
|
// close file
|
|
Close;
|
|
end;
|
|
end;
|
|
|
|
function TPayload.HasPayload: Boolean;
|
|
begin
|
|
// we have a payload if size is greater than 0
|
|
Result := PayloadSize > 0;
|
|
end;
|
|
|
|
procedure TPayload.Open(Mode: Integer);
|
|
begin
|
|
// open file with given mode, recording current one
|
|
fOldFileMode := FileMode;
|
|
AssignFile(fFile, fFileName);
|
|
FileMode := Mode;
|
|
Reset(fFile, 1);
|
|
end;
|
|
|
|
function TPayload.PayloadSize: Integer;
|
|
var
|
|
Footer: TPayloadFooter;
|
|
begin
|
|
// open file and assume no data
|
|
Result := 0;
|
|
Open(cReadOnlyMode);
|
|
try
|
|
// read footer and if valid return data size
|
|
if ReadFooter(fFile, Footer) then
|
|
Result := Footer.DataSize;
|
|
finally
|
|
Close;
|
|
end;
|
|
end;
|
|
|
|
procedure TPayload.RemovePayload;
|
|
var
|
|
PLSize: Integer;
|
|
FileLen: Integer;
|
|
begin
|
|
// get size of payload
|
|
PLSize := PayloadSize;
|
|
if PLSize > 0 then
|
|
begin
|
|
// we have payload: open file and get size
|
|
Open(cReadWriteMode);
|
|
FileLen := FileSize(fFile);
|
|
try
|
|
// seek to end of exec code an truncate file there
|
|
Seek(fFile, FileLen - PLSize - SizeOf(TPayloadFooter));
|
|
Truncate(fFile);
|
|
finally
|
|
Close;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TPayload.SetPayload(const Data;
|
|
const DataSize: Integer);
|
|
var
|
|
Footer: TPayloadFooter;
|
|
begin
|
|
// remove any existing payload
|
|
RemovePayload;
|
|
if DataSize > 0 then
|
|
begin
|
|
// we have some data: open file for writing
|
|
Open(cReadWriteMode);
|
|
try
|
|
// create a new footer with required data
|
|
InitFooter(Footer);
|
|
Footer.ExeSize := FileSize(fFile);
|
|
Footer.DataSize := DataSize;
|
|
// write data and footer at end of exe code
|
|
Seek(fFile, Footer.ExeSize);
|
|
BlockWrite(fFile, Data, DataSize);
|
|
BlockWrite(fFile, Footer, SizeOf(Footer));
|
|
finally
|
|
Close;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end.
|