2005. február 12., szombat
How to embed binary data in an executable
Problem/Question/Abstract:
I have a very specialized script language which requires an executable program (The Engine) to load and process scripts. This works on the basis that each script requires its own copy of the executable processing engine (for reasons about to be explained). I want to take this a step further by embedding a script inside the executable at runtime. This will be done from my existing script editor. Something like a compile script function. How can I open an executable file, safely add a block of binary data which can then be read when the executable is running? I know this can be done. If virus writers can put additional executable code into an *.exe file, then I must be able to put binary data in.
Answer:
I wrote this component to embed data in forms or datamodules. Drop the component in the form, double click it and select the file to embed. I have written a version that compresses the data also, but I lost it, anyway, is not complicated to do so if you want compressed data.
unit uBinaryData;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, DsgnIntf;
type
TBinaryData = class(TComponent)
private
MemStream: TStream;
TempFileName: string;
procedure WriteData(Stream: TStream);
procedure ReadData(Stream: TStream);
procedure SetStream(Stream: TStream);
function GetDataSize: Longint;
procedure SetDataSize(ASize: Longint);
protected
procedure DefineProperties(Filer: TFiler); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function GetTempFile(const Ext: string): string;
procedure DeleteTempFile;
procedure SaveToFile(const FName: string);
property Stream: TStream read MemStream write SetStream;
published
property DataSize: Longint read GetDataSize write SetDataSize;
end;
TBinaryDataEditor = class(TComponentEditor)
protected
function GetVerbCount: Integer; override;
function GetVerb(index: Integer): string; override;
procedure ExecuteVerb(index: Integer); override;
procedure Edit; override;
end;
procedure Register;
implementation
{ TBinaryData }
constructor TBinaryData.Create;
begin
inherited;
MemStream := TMemoryStream.Create;
end;
destructor TBinaryData.Destroy;
begin
MemStream.Free;
if TempFileName <> '' then
DeleteTempFile;
inherited;
end;
function TBinaryData.GetDataSize;
begin
Result := MemStream.Size;
end;
procedure TBinaryData.SetDataSize;
begin
(MemStream as TMemoryStream).SetSize(ASize);
end;
procedure TBinaryData.DefineProperties;
begin
inherited;
Filer.DefineBinaryProperty('TheData', ReadData, WriteData, true);
end;
procedure TBinaryData.ReadData;
var
ASize: Longint;
begin
Stream.Read(ASize, sizeof(ASize));
if ASize > 0 then
begin
(MemStream as TMemoryStream).SetSize(ASize);
Stream.Read((MemStream as TMemoryStream).Memory^, ASize);
end;
end;
procedure TBinaryData.WriteData;
var
ASize: Longint;
begin
ASize := MemStream.Size;
Stream.Write(ASize, sizeof(ASize));
if ASize > 0 then
Stream.Write((MemStream as TMemoryStream).Memory^, ASize);
end;
procedure TBinaryData.SetStream;
begin
if Stream <> nil then
(MemStream as TMemoryStream).LoadFromStream(Stream)
else
(MemStream as TMemoryStream).SetSize(0);
end;
function TBinaryData.GetTempFile;
const
FirstChars: PChar = 'AAA';
var
PathBuffer: array[0..255] of char;
FileName: array[0..MAX_PATH] of char;
FileStream: TFileStream;
begin
GetTempPath(256, PathBuffer);
if GetTempFileName(PathBuffer, FirstChars, 0, FileName) = 0 then
raise Exception.Create('No se pudo crear el archivo temporal');
Result := StrPas(FileName);
DeleteFile(Result);
Result := ChangeFileExt(Result, Ext);
TempFileName := Result;
FileStream := TFileStream.Create(Result, fmCreate);
try
MemStream.Seek(0, 0);
FileStream.CopyFrom(MemStream, MemStream.Size);
finally
FileStream.Free;
end;
end;
procedure TBinaryData.DeleteTempFile;
begin
DeleteFile(TempFileName);
TempFileName := '';
end;
procedure TBinaryData.SaveToFile;
var
s: TFileStream;
begin
s := TFileStream.Create(FName, fmCreate);
try
Stream.Seek(0, 0);
s.CopyFrom(Stream, Stream.Size);
finally
s.Free;
end;
end;
{ TBinaryDataEditor }
function TBinaryDataEditor.GetVerbCount;
begin
Result := 1;
end;
function TBinaryDataEditor.GetVerb;
begin
Result := 'Load File...';
end;
procedure TBinaryDataEditor.ExecuteVerb;
begin
Edit;
end;
procedure TBinaryDataEditor.Edit;
var
OpenDialog: TOpenDialog;
FileStream: TFileStream;
begin
OpenDialog := TOpenDialog.Create(Application);
try
OpenDialog.Filter := '*.*';
if OpenDialog.Execute then
if FileExists(OpenDialog.Filename) then
begin
FileStream := TFileStream.Create(OpenDialog.Filename, fmOpenRead);
try
(Component as TBinaryData).Stream := FileStream;
Designer.Modified;
finally
FileStream.Free;
end;
end;
finally
OpenDialog.Free;
end;
end;
procedure Register;
begin
RegisterComponents('Misc', [TBinaryData]);
RegisterComponentEditor(TBinaryData, TBinaryDataEditor);
end;
end.
Feliratkozás:
Megjegyzések küldése (Atom)
Nincsenek megjegyzések:
Megjegyzés küldése