摘要 我需要在我的软件中嵌入可执行文件。这个可执行文件是由我的客户端提供的,客户端希望可执行文件应该嵌入到我正在开发的软件中,并且应该被提取到内存中并从那里执行。
详情 我可以在这里透露的细节:
我们已经构建了一个自动化Adobe Photoshop以执行某些任务的软件。在这个软件中,我们的客户要求我们添加工具以将用户选择的照片写入/记录到DVD / CD。因此录制的DVD / CD不可复制!
为了执行此任务,客户端为我们提供了一个可执行文件,可以根据提供给它的文本文件(包含要刻录的文件列表)将内容记录到DVD / CD!我们正在使用此可执行文件进行写入/录制。
现在客户希望我们将这个文件嵌入到我们开发的软件中,当用户选择写入/录制到DVD / CD的选项时,可执行文件应该在内存中提取并从内存中执行。
当我们尝试使用可用的软件保护来保护此可执行文件时,SoftLocx,Enigma,SoftDog,WinICE等软件可执行文件崩溃,这就是我们决定将其嵌入软件的原因。
我希望现在我已经提供了足够的细节。
我们可以在VB6 / Delphi中做这样的事情吗?
答案 0 :(得分:2)
您是否尝试过最新版本的Enigma Virtual Box?我已经能够使用这个免费工具调用捆绑的EXE。我认为虚拟盒技术的最新增强功能首先出现在EVB上。如果您尝试,请确保单击“将虚拟系统共享到子进程”。
http://enigmaprotector.com/en/aboutvb.html
如果您想从内存中运行EXE,我会找到一些(未经测试的)代码。也许这会有所帮助。
unit uExecFromMem;
{ uExecFromMem
Author: steve10120
Description: Run an executable from another's memory.
Credits: Tan Chew Keong: Dynamic Forking of Win32 EXE; Author of BTMemoryModule: PerformBaseRelocation().
Reference: http://www.security.org.sg/code/loadexe.html
Release Date: 26th August 2009
Website: http://ic0de.org
History: First try
Additions by testest 15th July 2010:
- Parameter support
- Win7 x64 support
}
interface
uses Windows;
function ExecuteFromMem(szFilePath, szParams: string; pFile: Pointer):DWORD;
implementation
function NtUnmapViewOfSection(ProcessHandle:DWORD; BaseAddress:Pointer):DWORD; stdcall; external 'ntdll';
type
PImageBaseRelocation = ^TImageBaseRelocation;
TImageBaseRelocation = packed record
VirtualAddress: DWORD;
SizeOfBlock: DWORD;
end;
procedure PerformBaseRelocation(f_module: Pointer; INH:PImageNtHeaders; f_delta: Cardinal); stdcall;
var
l_i: Cardinal;
l_codebase: Pointer;
l_relocation: PImageBaseRelocation;
l_dest: Pointer;
l_relInfo: ^Word;
l_patchAddrHL: ^DWord;
l_type, l_offset: integer;
begin
l_codebase := f_module;
if INH^.OptionalHeader.DataDirectory[5].Size > 0 then
begin
l_relocation := PImageBaseRelocation(Cardinal(l_codebase) + INH^.OptionalHeader.DataDirectory[5].VirtualAddress);
while l_relocation.VirtualAddress > 0 do
begin
l_dest := Pointer((Cardinal(l_codebase) + l_relocation.VirtualAddress));
l_relInfo := Pointer(Cardinal(l_relocation) + 8);
for l_i := 0 to (trunc(((l_relocation.SizeOfBlock - 8) / 2)) - 1) do
begin
l_type := (l_relInfo^ shr 12);
l_offset := l_relInfo^ and $FFF;
if l_type = 3 then
begin
l_patchAddrHL := Pointer(Cardinal(l_dest) + Cardinal(l_offset));
l_patchAddrHL^ := l_patchAddrHL^ + f_delta;
end;
inc(l_relInfo);
end;
l_relocation := Pointer(cardinal(l_relocation) + l_relocation.SizeOfBlock);
end;
end;
end;
function AlignImage(pImage:Pointer):Pointer;
var
IDH: PImageDosHeader;
INH: PImageNtHeaders;
ISH: PImageSectionHeader;
i: WORD;
begin
IDH := pImage;
INH := Pointer(Integer(pImage) + IDH^._lfanew);
GetMem(Result, INH^.OptionalHeader.SizeOfImage);
ZeroMemory(Result, INH^.OptionalHeader.SizeOfImage);
CopyMemory(Result, pImage, INH^.OptionalHeader.SizeOfHeaders);
for i := 0 to INH^.FileHeader.NumberOfSections - 1 do
begin
ISH := Pointer(Integer(pImage) + IDH^._lfanew + 248 + i * 40);
CopyMemory(Pointer(DWORD(Result) + ISH^.VirtualAddress), Pointer(DWORD(pImage) + ISH^.PointerToRawData), ISH^.SizeOfRawData);
end;
end;
function Get4ByteAlignedContext(var Base: PContext): PContext;
begin
Base := VirtualAlloc(nil, SizeOf(TContext) + 4, MEM_COMMIT, PAGE_READWRITE);
Result := Base;
if Base <> nil then
while ((DWORD(Result) mod 4) <> 0) do
Result := Pointer(DWORD(Result) + 1);
end;
function ExecuteFromMem(szFilePath, szParams:string; pFile:Pointer):DWORD;
var
PI: TProcessInformation;
SI: TStartupInfo;
CT: PContext;
CTBase: PContext;
IDH: PImageDosHeader;
INH: PImageNtHeaders;
dwImageBase: DWORD;
pModule: Pointer;
dwNull: DWORD;
begin
if szParams <> '' then szParams := '"'+szFilePath+'" '+szParams;
Result := 0;
IDH := pFile;
if IDH^.e_magic = IMAGE_DOS_SIGNATURE then
begin
INH := Pointer(Integer(pFile) + IDH^._lfanew);
if INH^.Signature = IMAGE_NT_SIGNATURE then
begin
FillChar(SI, SizeOf(TStartupInfo), #0);
FillChar(PI, SizeOf(TProcessInformation), #0);
SI.cb := SizeOf(TStartupInfo);
if CreateProcess(PChar(szFilePath), PChar(szParams), nil, nil, FALSE, CREATE_SUSPENDED, nil, nil, SI, PI) then
begin
CT := Get4ByteAlignedContext(CTBase);
if CT <> nil then
begin
CT.ContextFlags := CONTEXT_FULL;
if GetThreadContext(PI.hThread, CT^) then
begin
ReadProcessMemory(PI.hProcess, Pointer(CT.Ebx + 8), @dwImageBase, 4, dwNull);
if dwImageBase = INH^.OptionalHeader.ImageBase then
begin
if NtUnmapViewOfSection(PI.hProcess, Pointer(INH^.OptionalHeader.ImageBase)) = 0 then
pModule := VirtualAllocEx(PI.hProcess, Pointer(INH^.OptionalHeader.ImageBase), INH^.OptionalHeader.SizeOfImage, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE)
else
pModule := VirtualAllocEx(PI.hProcess, nil, INH^.OptionalHeader.SizeOfImage, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
end
else
pModule := VirtualAllocEx(PI.hProcess, Pointer(INH^.OptionalHeader.ImageBase), INH^.OptionalHeader.SizeOfImage, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if pModule <> nil then
begin
pFile := AlignImage(pFile);
if DWORD(pModule) <> INH^.OptionalHeader.ImageBase then
begin
PerformBaseRelocation(pFile, INH, (DWORD(pModule) - INH^.OptionalHeader.ImageBase));
INH^.OptionalHeader.ImageBase := DWORD(pModule);
CopyMemory(Pointer(Integer(pFile) + IDH^._lfanew), INH, 248);
end;
WriteProcessMemory(PI.hProcess, pModule, pFile, INH.OptionalHeader.SizeOfImage, dwNull);
WriteProcessMemory(PI.hProcess, Pointer(CT.Ebx + 8), @pModule, 4, dwNull);
CT.Eax := DWORD(pModule) + INH^.OptionalHeader.AddressOfEntryPoint;
SetThreadContext(PI.hThread, CT^);
ResumeThread(PI.hThread);
Result := PI.hThread;
end;
end;
VirtualFree(CTBase, 0, MEM_RELEASE);
end;
if Result = 0 then
TerminateProcess(PI.hProcess, 0);
end;
end;
end;
end;
end.
使用示例:
procedure TMainFrm.BtnStartClick(Sender: TObject);
var
Reg: TRegistry;
CommandLine: string;
ABuffer: array of byte;
Res: TResourceStream;
LauncherMS: TStream;
begin
...
...
...
...
Res := TResourceStream.Create(HInstance,'MEXE','Data');
LauncherMS := TMemoryStream.Create;
LauncherMS.CopyFrom(Res,Res.Size);
LauncherMS.Position := 0;
CommandLine := '';
try
SetLength(ABuffer, LauncherMS.Size);
LauncherMS.ReadBuffer(ABuffer[0], LauncherMS.Size);
ExecuteFromMem(ExtractFilePath(Application.ExeName)+'m.exe', 'connect', @ABuffer[0]);
finally
LauncherMS.Free;
end;
end;
答案 1 :(得分:1)
您可以将可执行文件另存为资源并在运行时将其解压缩,但是您无法将其直接加载到内存中并执行它。 Windows中没有从内存加载可执行文件的功能。
您需要先将其保存到磁盘,然后执行它。
从技术上讲,你可能会溢出你自己的缓冲区,但这是一个黑客攻击并且不可靠。
对于.dll也是如此。在Windows中没有从内存加载DLL的功能。
如果实用程序需要被复制保护,那么它应该内置了复制保护。也许,与主应用程序共享相同的复制保护方案是理想的。
有一些方法可以确保只有你的程序可以调用它来确保只有你的程序可以调用它,但如果没有更好地解释你的目标是什么,我不愿意进一步深入研究它,以免浪费你的时间。
还有很多用于CD / DVD刻录的Delphi库。
有关加载和提取资源的详细信息,请参阅此前一个答案:
https://stackoverflow.com/questions/8349989/add-extract-file-to-exe-post-build/8351808#8351808