2007. november 14., szerda
Easy EXE attached data
Problem/Question/Abstract:
Using resources to include files into your EXE is a great thing, but I prefer using another way...
Answer:
When you compiled your code, and you want to attach 1 file to your file just use this command line:
COPY /B PROJECT1.EXE + DATA.TXT PROJECT2.EXE
A file, called Project2.Exe will be created and it will contain first file with 2nd file attached. That doesn't compromise EXE and it will be still working.
But: how to easly extract that file form the EXE?
First of all, you should use this function:
function GetAttachedData(MS: TMemoryStream): boolean;
var
pMySelf: pChar;
IdX, SectionsCount: integer;
EXESize, EXEOriginalSize: cardinal;
SR: TSearchRec;
FS: TMemoryStream;
EXEName: array[0..MAX_PATH] of char;
begin
result := false;
if MS = nil then
exit;
try
MS.clear;
// Gets EXE/DLL filename.
fillchar(EXEName, sizeof(EXEName), #0);
getmodulefilename(HInstance, EXEName, MAX_PATH);
// Gets file size.
EXESize := 0;
if findfirst(EXEName, faAnyFile, SR) = 0 then
begin
EXESize := SR.size;
sysutils.findclose(SR);
end;
// Gets originalsize.
EXEOriginalSize := 0;
try
pMySelf := pointer(HInstance);
if PImageDosHeader(pMySelf).E_Magic <> $00004550 then
exit;
inc(pMySelf, PImageDosHeader(pMySelf)._lfanew);
if pDWord(pMySelf)^ <> $00004550 then
exit;
inc(pMySelf, sizeof(dword));
SectionsCount := PImageFileHeader(pMySelf).NumberOfSections;
inc(pMySelf, sizeof(TImageFileHeader) + sizeof(TImageOptionalHeader));
for IdX := 1 to SectionsCount do
begin
with PImageSectionHeader(pMySelf)^ do
if (PointerToRawData + SizeOfRawData) > EXEOriginalSize then
EXEOriginalSize := PointerToRawData + SizeOfRawData;
inc(pMySelf, sizeof(TImageSectionHeader));
end;
except
on e: exception do
EXEOriginalSize := 0;
end;
// If there's something attached...
if EXESize > EXEOriginalSize then
begin
FS := TMemoryStream.create;
try
try
// Read it...
FS.loadfromfile(EXEName);
FS.position := EXEOriginalSize;
// and return it in the stream.
MS.copyfrom(FS, EXESize - EXEOriginalSize);
result := true;
except
on e: exception do
result := false;
end;
finally
FS.destroy;
end;
end;
except
on e: exception do
result := false;
end;
end;
Then, you can use it like this:
procedure TForm1.Button1Click(Sender: TObject);
var
s: tmemorystream;
begin
s := tmemorystream.create;
try
if GetAttachedData(s) then
s.SaveToFile('output.txt');
finally
s.destroy;
end;
end;
That's all. You don't need to use constants, resources or anything else.
Note that the code will work also if the EXE file is compressed with tools like UPX or similar.
Thanks to the site U.N.D.U. for some code snippets.
Feliratkozás:
Megjegyzések küldése (Atom)
Nincsenek megjegyzések:
Megjegyzés küldése