【问题标题】:Execute an EXE File from Resource into Memory将资源中的 EXE 文件执行到内存中
【发布时间】:2011-09-17 17:43:42
【问题描述】:

我想执行一个用我的应用程序作为资源编译的 EXE 文件。我想直接在内存中执行。

我看过这个话题:

Is it possible to embed and run exe file in a Delphi executable app?

还有这段代码:

http://www.coderprofile.com/networks/source-codes/138/execute-resource-directly-in-memory

我使用了这个代码:

type
 TSections = array [0..0] of TImageSectionHeader;

...

{$IMAGEBASE $10000000}

function GetAlignedSize(Size: dword; Alignment: dword): dword;
begin
  if ((Size mod Alignment) = 0) then
    Result := Size
  else
    Result := ((Size div Alignment) + 1) * Alignment;
end;

function ImageSize(Image: pointer): dword;
var
  Alignment: dword;
  ImageNtHeaders: PImageNtHeaders;
  PSections: ^TSections;
  SectionLoop: dword;
begin
  ImageNtHeaders := pointer(dword(dword(Image)) + dword(PImageDosHeader(Image)._lfanew));
  Alignment := ImageNtHeaders.OptionalHeader.SectionAlignment;
  if ((ImageNtHeaders.OptionalHeader.SizeOfHeaders mod Alignment) = 0) then
  begin
    Result := ImageNtHeaders.OptionalHeader.SizeOfHeaders;
  end
  else
  begin
    Result := ((ImageNtHeaders.OptionalHeader.SizeOfHeaders div Alignment) + 1) * Alignment;
  end;
  PSections := pointer(pchar(@(ImageNtHeaders.OptionalHeader)) + ImageNtHeaders.FileHeader.SizeOfOptionalHeader);
  for SectionLoop := 0 to ImageNtHeaders.FileHeader.NumberOfSections - 1 do
  begin
    if PSections[SectionLoop].Misc.VirtualSize <> 0 then
    begin
      if ((PSections[SectionLoop].Misc.VirtualSize mod Alignment) = 0) then
      begin
        Result := Result + PSections[SectionLoop].Misc.VirtualSize;
      end
      else
      begin
        Result := Result + (((PSections[SectionLoop].Misc.VirtualSize div Alignment) + 1) * Alignment);
      end;
    end;
  end;
end;

procedure CreateProcessEx(FileMemory: pointer);
var
  BaseAddress, Bytes, HeaderSize, InjectSize,  SectionLoop, SectionSize: dword;
  Context: TContext;
  FileData: pointer;
  ImageNtHeaders: PImageNtHeaders;
  InjectMemory: pointer;
  ProcInfo: TProcessInformation;
  PSections: ^TSections;
  StartInfo: TStartupInfo;
begin
  ImageNtHeaders := pointer(dword(dword(FileMemory)) + dword(PImageDosHeader(FileMemory)._lfanew));
  InjectSize := ImageSize(FileMemory);
  GetMem(InjectMemory, InjectSize);
  try
    FileData := InjectMemory;
    HeaderSize := ImageNtHeaders.OptionalHeader.SizeOfHeaders;
    PSections := pointer(pchar(@(ImageNtHeaders.OptionalHeader)) + ImageNtHeaders.FileHeader.SizeOfOptionalHeader);
    for SectionLoop := 0 to ImageNtHeaders.FileHeader.NumberOfSections - 1 do
    begin
      if PSections[SectionLoop].PointerToRawData < HeaderSize then HeaderSize := PSections[SectionLoop].PointerToRawData;
    end;
    CopyMemory(FileData, FileMemory, HeaderSize);
    FileData := pointer(dword(FileData) + GetAlignedSize(ImageNtHeaders.OptionalHeader.SizeO  fHeaders, ImageNtHeaders.OptionalHeader.SectionAlignment));
    for SectionLoop := 0 to ImageNtHeaders.FileHeader.NumberOfSections - 1 do
    begin
      if PSections[SectionLoop].SizeOfRawData > 0 then
      begin
        SectionSize := PSections[SectionLoop].SizeOfRawData;
        if SectionSize > PSections[SectionLoop].Misc.VirtualSize then SectionSize := PSections[SectionLoop].Misc.VirtualSize;
        CopyMemory(FileData, pointer(dword(FileMemory) + PSections[SectionLoop].PointerToRawData), SectionSize);
        FileData := pointer(dword(FileData) + GetAlignedSize(PSections[SectionLoop].Misc.VirtualSize, ImageNtHeaders.OptionalHeader.SectionAlignment));
      end
      else
      begin
        if PSections[SectionLoop].Misc.VirtualSize <> 0 then FileData := pointer(dword(FileData) + GetAlignedSize(PSections[SectionLoop].Misc.VirtualSize, ImageNtHeaders.OptionalHeader.SectionAlignment));
      end;
    end;
    ZeroMemory(@StartInfo, SizeOf(StartupInfo));
    ZeroMemory(@Context, SizeOf(TContext));
    CreateProcess(nil, pchar(ParamStr(0)), nil, nil, False, CREATE_SUSPENDED, nil, nil, StartInfo, ProcInfo);
    Context.ContextFlags := CONTEXT_FULL;
    GetThreadContext(ProcInfo.hThread, Context);
    ReadProcessMemory(ProcInfo.hProcess, pointer(Context.Ebx + 8), @BaseAddress, 4, Bytes);
    VirtualAllocEx(ProcInfo.hProcess, pointer(ImageNtHeaders.OptionalHeader.ImageBase), InjectSize, MEM_RESERVE or MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    WriteProcessMemory(ProcInfo.hProcess, pointer(ImageNtHeaders.OptionalHeader.ImageBase), InjectMemory, InjectSize, Bytes);
    WriteProcessMemory(ProcInfo.hProcess, pointer(Context.Ebx + 8), @ImageNtHeaders.OptionalHeader.ImageBase, 4, Bytes);
    Context.Eax := ImageNtHeaders.OptionalHeader.ImageBase + ImageNtHeaders.OptionalHeader.AddressOfEntryPoint;
    SetThreadContext(ProcInfo.hThread, Context);
    ResumeThread(ProcInfo.hThread);
  finally
    FreeMemory(InjectMemory);
  end;
end;

procedure Execute;
var
  RS : TResourceStream;      
begin
   RS := TResourceStream.Create(HInstance, 'MrResource', RT_RCDATA);
  try
   CreateProcessEx(RS.Memory);
  finally
   RS.Free;
  end;
end;

但我在这一行(在 CreateProcessEX 中)出现“内存不足”错误:

  GetMem(InjectMemory, InjectSize);

有人可以帮我解决这个错误吗?或者给我一些工作代码/解决方案?

感谢之前...

【问题讨论】:

  • InjectSize 的值是多少?也许内存不足错误就是它看起来的样子
  • 为什么这个问题被否决了?
  • 这是一个有趣的问题,但是,哇,工作量真大。为什么不with 与操作系统一起工作,而不是反对 它,然后将文件放在临时目录中。
  • 您是否尝试从您的 coderprofile-link 编译并运行完整示例?如果可行,那么您应该从那里开始并将其更改为使用您的可执行文件。但就像 Ian 建议的那样,将其放入 temp 并从那里执行要简单得多,用户不会注意到其中的差异。除非您这样做是为了绕过病毒扫描程序。
  • @David Heffernan : InjectSize := ImageSize(FileMemory); , 如果出错,我认为“ImageSize”函数可能有问题

标签: delphi memory resources


【解决方案1】:

您预期的 API 指针布局听起来不正确,返回的大小也不正确。

您是如何定义所有 PImageNtHeaders 和此类 TSections 类型的?什么是记录对齐?它不应该需要以某种粒度打包或对齐吗?也许您在将原始代码复制/粘贴到您的单元时忘记了一些 {$A..} 或枚举大小...

没有完整的源代码很难猜测。

【讨论】:

  • PImageNtHeaders 是标准类型
  • 谢谢,我想你所说的都已经在代码中显示出来了! ,没有更多的代码...
  • 你试过不同的exe吗? Calc.Exe 可能是 64 位 exe,因此 NT 32 位标头不再匹配。
【解决方案2】:

一个出色的单元已经完成了对 Windows 64 位的支持。

你可以在这里找到它: uExecFromMem by steve10120 fixed by test

如果您不想使用该单元,这是我编写的一种简单方法

var
eu:array of byte;
FS:TFileStream;
CONT:TContext;
imgbase,btsIO:DWORD;
IDH:PImageDosHeader;
INH:PImageNtHeaders;
ISH:PImageSectionHeader;
i:Integer;
PInfo:TProcessInformation;
SInfo:TStartupInfo;
begin
if OpenDialog1.Execute then
  begin
    FS:=TFileStream.Create(OpenDialog1.FileName,fmOpenRead or fmShareDenyNone);
    SetLength(eu,FS.Size);
    FS.Read(eu[0],FS.Size);
    FS.Free;
    Sinfo.cb:=Sizeof(TStartupInfo);
    CreateProcess(nil,Pchar(paramstr(0)),nil,nil,FALSE,CREATE_SUSPENDED,nil,nil,SInfo,PInfo);
    IDH:=@eu[0];
    INH:=@eu[IDH^._lfanew];
    imgbase:=DWORD(VirtualAllocEx(PInfo.hProcess,Ptr(INH^.OptionalHeader.ImageBase),INH^.OptionalHeader.SizeOfImage,MEM_COMMIT or MEM_RESERVE,PAGE_EXECUTE_READWRITE));
    ShowMessage(IntToHex(imgbase,8));
    WriteProcessMemory(PInfo.hProcess,Ptr(imgbase),@eu[0],INH^.OptionalHeader.SizeOfHeaders,btsIO);
    for i:=0 to INH^.FileHeader.NumberOfSections - 1 do
      begin
          ISH:=@eu[IDH^._lfanew + Sizeof(TImageNtHeaders) + i * Sizeof(TImageSectionHeader)];
          WriteProcessMemory(PInfo.hProcess,Ptr(imgbase + ISH^.VirtualAddress),@eu[ISH^.PointerToRawData],ISH^.SizeOfRawData,btsIO);
      end;
    CONT.ContextFlags:=CONTEXT_FULL;
    GetThreadContext(PInfo.hThread,CONT);
    CONT.Eax:=imgbase + INH^.OptionalHeader.AddressOfEntryPoint;
    WriteProcessMemory(PInfo.hProcess,Ptr(CONT.Ebx+8),@imgbase,4,btsIO);
    ShowMessage('Press ok on ENTER');
    SetThreadContext(PInfo.hThread,CONT);
    ResumeThread(PInfo.hThread);
    CloseHandle(Pinfo.hThread);
    CloseHandle(PInfo.hProcess);
  end;
end;

【讨论】:

  • 谢谢,但没有声明“SInfo”和“PInfo”
  • 我添加了它们...不过,如果您尝试一下,您应该会想出来,顺便说一句,不要忘记将 imagebase 设置为 $1000000
  • @opc0de 请为 64 位 PE 文件提供可行的解决方案。
  • @user2665920 你做错了什么,代码已经过测试或者可执行文件有一些特殊的地方。你设置了 IMAGE BASE 吗?
  • @opc0de 不,我没有设置它:D。那么这段代码可以用于 32 位和 64 位 PE 文件吗?
【解决方案3】:

要在 32 位和 64 位平台上获得 opc0de's 答案,请更改上下文设置,如下所示,

   GetThreadContext(PInfo.hThread,CONT);
   {$IFDEF WIN64}
      CONT.P6Home:=imgbase + INH^.OptionalHeader.AddressOfEntryPoint;
      WriteProcessMemory(PInfo.hProcess,Ptr(CONT.P3Home+8),@imgbase,4,btsIO);
   {$ELSE}
      CONT.Eax:=imgbase + INH^.OptionalHeader.AddressOfEntryPoint;
      WriteProcessMemory(PInfo.hProcess,Ptr(CONT.Ebx+8),@imgbase,4,btsIO);
   {$ENDIF}
   ShowMessage('Press ok on ENTER');
   SetThreadContext(PInfo.hThread,CONT);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-23
    • 2013-01-16
    • 1970-01-01
    • 1970-01-01
    • 2017-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多