如何在 VB6/Delphi 程序中嵌入可执行文件

发布于 2024-12-20 10:21:40 字数 596 浏览 3 评论 0原文

总结 我需要在我的软件中嵌入可执行文件。该可执行文件由我的客户提供,客户希望该可执行文件应嵌入到我正在开发的软件中,并应提取到内存中并从那里执行。

详细信息 我可以在这里透露的详细信息:

我们已经构建了一个软件,可以自动执行 Adob​​e Photoshop 的某些任务。在这个软件中,我们的客户要求我们添加将用户选择的照片写入/记录到 DVD/CD 的功能。这样录制的 DVD/CD 不可复制!

为了执行此任务,客户向我们提供了一个可执行文件,该可执行文件可以根据提供给它的文本文件(包含要刻录的文件列表)将内容记录到 DVD/CD!我们正在使用这个可执行文件进行写入/记录。

现在,客户希望我们将此文件嵌入到我们开发的软件中,当用户选择写入/录制到 DVD/CD 的选项时,可执行文件应提取到内存中并从内存中执行。

当我们尝试使用可用的软件保护来保护此可执行文件时,SoftLocx、Enigma、SoftDog、WinICE 等软件会导致可执行文件崩溃,这就是我们决定将其嵌入到我们的软件中的原因。

我希望现在我已经提供了足够的细节。

我们可以在 VB6/Delphi 中做这样的事情吗?

Summary
I have a need to embed an executable in my software. This executable is provided by my client and the client wishes that the executable should be embedded into the software that I am developing and should be extracted into memory and executed from there.

Details
Details that I can reveal here:

We have build a software that is automating Adobe Photoshop for performing some tasks. In this software our client asked us to add facility to write/record user selected photos to a DVD/CD. DVD/CD recorded thus is not copyable!

For performing this task, the client supplied us with an executable that can record content to DVD/CD based on a text file (containing list of files to be burned) supplied to it! We are using this executable for writing/recording.

Now the client want us to embedded this file in the software that we have developed and when the user selects the option for writing/recording to DVD/CD the executable should be extracted in memory and executed from memory.

When we try to protect this executable with available software protection, software like SoftLocx, Enigma, SoftDog, WinICE, etc. the executable crashes that is why we took the decision to embed it in our software.

I hope now I have provided enough details.

Can we do something like this in VB6/Delphi?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

最好是你 2024-12-27 10:21:40

您是否尝试过最新版本的 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;

Have you tried the last version of Enigma Virtual Box? I've been able to invoke a bundled EXE using this free tool. I think the latest enhancements to the virtual box tech shows up EVB first. If you try, make sure click share virtual system to child process.

http://enigmaprotector.com/en/aboutvb.html

Here is some (untested) code I found if you want to run EXE from memory. Maybe this can help.

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.

Example of use:

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;
神妖 2024-12-27 10:21:40

您可以将可执行文件另存为资源并在运行时提取它,但是您将无法将其直接加载到内存中并执行。 Windows 中没有从内存加载可执行文件的功能。

您需要先将其保存到磁盘,然后再执行它。

从技术上讲,您可以溢出自己的缓冲区,但这是一种黑客行为,而且不可靠。

对于 .dll 也是如此。 Windows 中没有从内存加载 dll 的功能。

如果实用程序需要受复制保护,那么它应该内置复制保护。也许,与主应用程序共享相同的复制保护方案是理想的。

有多种方法可以保护对 dll 的调用,以帮助确保只有您的程序可以调用它,但如果没有更好地解释您的目标是什么,我不愿意进一步讨论它,以免浪费您的时间。

还有很多用于 CD/DVD 刻录的 Delphi 库。

有关加载和提取资源的更多信息,请参阅之前的答案:

https://stackoverflow.com/questions/8349989/add-extract-文件到 exe-post-build/8351808#8351808

You can save the executable file as a resource and extract it at run time, however you will not be able to load it directly into memory and execute it. There is no feature in Windows to load an executable from memory.

You'll need to save it to disk first, and then execute it.

Technically, you could overflow your own buffers, but that's a hack and wouldn't be reliable.

This is also true for a .dll. There's no feature to load a dll from memory in Windows.

If the utility program needs to be copy protected, then it should have copy protection built in. Perhaps, it would be ideal to share the same copy protection scheme as the main application.

There are ways of securing calls to a dll to help ensure that only your program can call it, but without a better explanation of what your goal is, I'm reluctant to go into it further, so as not to waste your time.

There are also quite a few Delphi libraries for CD/DVD burning.

See this previous answer for more information about loading and extracting a resource:

https://stackoverflow.com/questions/8349989/add-extract-file-to-exe-post-build/8351808#8351808

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文