3

我正在尝试从我的程序中动态加载一个 exe 文件,并从该动态加载的 exe 中运行 SomeProcedure。这是我在加载的 exe 中所做的 - library.exe

interface    

procedure SomeProcedure; stdcall;

implementation    

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

这是我加载 library.exe 并尝试从中运行 SomeProcedure 的 exe。

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;

不幸的是它不起作用 - AHandle 有一个地址,但 GetProcAddress 总是返回 nil。我究竟做错了什么?

4

3 回答 3

6

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.

于 2013-08-14T06:24:36.720 回答
1

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 :)

于 2013-08-14T07:18:10.073 回答
-1

“现在我有一个调用 Proc 的 AV”-您忘记在 TProc 的定义中定义“stdcall”。

刚刚创建了一个小示例,演示了从另一个 EXE 加载/执行导出的函数。

应用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.

应用 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;

所以 app2 将 app1 加载到自己的地址空间中(是的,对于 DLL 是可能的),然后获取函数的地址并以与 DLL 相同的方式调用它。

于 2013-08-13T21:04:01.770 回答