Dynamically loading exe file

拟墨画扇 提交于 2019-12-10 18:08:37

问题


I'm trying to dynamically load an exe file from my program and run SomeProcedure from that dynamicaly loaded exe. Here's what I'm doing in loaded exe - library.exe

interface    

procedure SomeProcedure; stdcall;

implementation    

procedure SomeProcedure;
begin
  ShowMessage('Ala has a cat');
end;

And here's my exe that load's library.exe and try to run SomeProcedure from it.

type
  THandle = Integer;
  TProc = procedure();

var
  AHandle: THandle;
  Proc: TProc;

procedure TForm1.Button1Click(Sender: TObject);
begin
  AHandle := LoadLibrary('library.exe');
  if AHandle <> 0 then begin
    @Proc := GetProcAddress(AHandle, 'SomeProcedure');
    if @Proc <> nil then 
      try    
        Proc;
      finally
        FreeLibrary(AHandle);
      end;
    end;
  end;
end;

Unfortunately it's not working - AHandle has an address but GetProcAddress always returns nil. What am I doing wrong?


回答1:


To the very best of my knowledge, what you are attempting is not possible. You cannot use LoadLibrary to load a .exe file, and then call its exported functions. You can only have one .exe file loaded into a process. You'll need to move the functionality into a library, or a COM server, or some other solution.

As Sertac points out, the documentation does cover this:

LoadLibrary can also be used to load other executable modules. For example, the function can specify an .exe file to get a handle that can be used in FindResource or LoadResource. However, do not use LoadLibrary to run an .exe file. Instead, use the CreateProcess function.

You can use GetProcAddress with the module handle of an executable. But you have to obtain the module handle by calling GetModuleHandle(0), for example.




回答2:


As David already pointed out it is nearly impossible. Well not impossible I would say. Just for the sake of understanding you could teoretically call CreateProcess and then hook its call and the calls that follow. One of the calls is also ZwCreateSection. I played with things like that a long time ago and it is theoretically possible to do it. CreateProcess creates an empty process context that then gets filled with other Zw/Nt kernell calls. Knowing the calls you could supply the content.

But that was theory and even that is hacking into the OS. As David pointed out it is impossible to do it in a sane and documented way. What you can do hovewer is extract the exe as a resource to a temporary file and the execute it. You can then wait for it to end and after that delete the file. That is the only way to do it. To do it all in RAM is a no go.

EDIT:

Here is an article on a technique that can be used. But its an ugly hack :)




回答3:


"now I have an AV in call to Proc" - you forget to define "stdcall" in definition of TProc.

Just created small sample demonstrating loading/executing of exported function from another EXE.

Application 1:

program Exe4Export;
uses
  Vcl.Forms,
  Unit3 in 'Unit3.pas' {Form3},
  ExportTypes in 'ExportTypes.pas';

{$R *.res}

function Test:integer; stdcall; export;
begin
  result := 7;
end;

exports
  Test;

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm3, Form3);
  Application.Run;
end.

Application 2:

type
  TExtProc = function: integer; stdcall;

procedure TForm3.FormCreate(Sender: TObject);
var
  h: HMODULE;
  p: TExtProc;
begin
  h := LoadLibrary('Exe4Export.exe');
  p := GetProcAddress(h, 'Test');
  if assigned(p) then
    caption := IntToStr(p);
  FreeLibrary(h);
end;

So app2 loads app1 into own address space (yes, it is possible for DLL), then get address of function and call it in same way like for DLL.



来源:https://stackoverflow.com/questions/18218593/dynamically-loading-exe-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!