【问题标题】:Delphi DLL Inject and sharing varsDelphi DLL 注入和共享变量
【发布时间】:2012-07-20 05:53:50
【问题描述】:

我使用 BTMemoryModule 将 DLL 注入进程。 主/父进程可以调用函数/过程,但其他方式呢? dll 可以从主/父进程读取/获取 var 或调用函数吗?

感谢您的帮助。

编辑: 动态链接库

library mydll; // DLL obviously...
uses windows;

procedure Test
begin
 // I need a string/integer/pointer from ParentProcess
end

exports
Test;

begin
 // I need a string/integer/pointer from ParentProcess. (if possible). 
end.

程序:

program myprogram
uses
...
var
 M : PBTMemoryModule;
begin
 BTMemoryLoadLibary (pointer, pointerlength);
 @myMaintest    := BTMemoryGetProcAddress(M, 'Test');
 ...
end;

【问题讨论】:

  • 这可能会有所帮助:MSDN
  • 谢谢。但是如何在 delphi 中使用它?

标签: dll delphi-7 code-injection delphi


【解决方案1】:

首先,这似乎不是通常所说的注入。这只是一个普通的模块加载,尽管来自内存而不是文件。

至于DLL如何从EXE中导入函数,与EXE从DLL中导入时完全一样。

  1. 使用exports 列出EXE 导出的函数。
  2. 调用GetModuleHandle(nil)获取EXE的模块句柄。
  3. 将该模块句柄传递给GetProcAddress 以导入函数。

与更常见的 EXE 链接到 DLL 模式的唯一区别是您使用 GetModuleHandle 而不是 LoadLibrary。这是因为 EXE 必须已经加载,因此您可以简单地询问其模块句柄,而不是要求加载模块。

我会评论说,以这种方式做事很不寻常。通常,EXE 会调用 DLL 并传递 DLL 所需的任何信息。该信息可能包括允许 DLL 查询其主机 EXE 的回调函数、接口等。

【讨论】:

  • +1:用于使用 GetModuleHandle(nil)。相反,我想使用一种由 DLL 导出的初始化过程来获取 EXE 的 HInstance,并在对其他导出的任何引用之前由 EXE 调用(移交 HInstance),因为知道任何调用都需要它EXE 的导出。
  • @menjaraz 这也很好用,是我在最后一段中概述的一般技术的一个例子。
  • 感谢您的确认。
【解决方案2】:

如果子模块(您的 DLL)知道父应用程序的数据结构和功能,这是可能的。这些数据和函数必须在 Parent 端可用。

【讨论】:

  • 那么我应该如何实现呢?当我编译它时,DLL 不知道任何指针(因为它们是动态的):/
  • 你能分享你的部分代码吗?看看codeproject.com/Articles/240/…。当然,有很多方法可以实现此功能。
  • 添加了代码。该链接是 C 的示例,我认为它不是动态的?!共享段是在您不在运行时编译它们时构建的?!谢谢你:)
  • 如前所述,当你想在另一个图像中注入图像时,你必须知道你在期待什么,寻找并准备好场景。您还可以使用 CreateFileMapping (msdn.microsoft.com/en-us/library/windows/desktop/…) 动态共享数据
  • 就像任何丰富的 API 使用这些回调或挂钩一样 - 您的 EXE 调用 DLL 并将数据帧与所有需要的指针一起传递给变量、函数等。然后 DLL 可以使用调用它们。就像你创建新窗口一样,当用户单击它时,你将要调用的函数传递给窗口。在这里,您的应用程序将指针传递给 Windows GDI32.DLL,并且您可以将其传递给您自己的 DLL。
【解决方案3】:

这是为了将我的评论进一步扩展到大卫的回答:


DLL 端:

  1. 在 DLL 中添加 Init 过程
  2. 导出它。
  3. 根据需要添加所需的类型/变量声明

片段代码:

library TheDLL;

...

var
  OwnerAPP: HMODULE; // To be initialized by a call of the exported procedure Init from the EXE

...

type
  TTestCallfromExe = procedure(f_Text: PAnsiChar); stdcall;

var
  OwnerAPP: LongInt;
  l_TestCallfromExe: TTestCallfromExe;

procedure Init(Owner: HMODULE);
begin
  OwnerAPP := Owner;
end;

...

exports
  Init, // This is it and the others exports follow
  ...

TestCallfromExe 的调用与对任何Dll 的导出函数/过程的调用一样。只要 OwnerAPP 正确初始化,就可以根据 OP 的要求在 Dll 导出函数的主体中进行调用。


EXE端:

根据需要导出每个过程/函数(从 DLL 调用),当然你应该实现它们。

program TheEXE;

uses
  ...
  MyExportImplementation; // Refence to implementatio unit

...

exports
  TestCallfromExe, // This is it
  ...

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

示例实现细节:

unit MyExportImplementation;

interface

...

procedure TestCallfromExe(f_Text: PAnsiChar); stdcall;

implementation

...

procedure TestCallfromExe(f_Text: PAnsiChar); stdcall;
begin
  MessageBoxA(0, f_Text, 'Exe Dialog Ansi (stdcall)', 0);
end;

...

end.

把它们放在一起:

这是基于 DemoDLL(来自 BTMemory)示例,例如在 TheEXE.dpr 项目的 MainForm 单元中实现:

procedure TForm1.BtnCAllClick(Sender: TObject);
var
  l_Init: procedure(Owner: HMODULE);
begin
  m_DllHandle := LoadLibrary('TheDLL.dll');
  try
    if m_DllHandle = 0 then
      Abort;

    @l_Init := GetProcAddress(m_DllHandle, 'Init');  // <<<
    if @l_Init = nil then
      Abort;

    // Fetch the remainding exported function(s)/procedure(s) adresses

    l_Init(HInstance); // <<<  Hand EXE's HInstance over to the DLL

    // Call exported function(s)/procedure(s) accordingly
  except
    Showmessage('An error occured while loading the dll');
  end;

  if m_DllHandle <> 0 then
    FreeLibrary(m_DllHandle)
end;

Nota Bene:

我也用 BTMemory 对其进行了测试,它可以工作。

【讨论】:

  • 使用HMODULE 作为模块句柄的类型。否则,由于指针截断,您的代码将在 x64 上失败。
  • @David Heffernan:已编辑。谢谢你的提示。
  • @David Heffernan:我的回答只是你的扩展。多亏了同行评审,它可以得到改进,正如你最近所说,仍有改进的余地。老实说,您的答案比我的答案包含更多有价值的信息。顺便说一句,我在测试期间注意到代码有一个奇怪的 (?) 行为:它可以在没有事先调用 l_Init(HInstance) 的情况下工作。怎么来的?我的猜测是 GetProcAddress 通过 DLL 中 OwnerApp 的地址(加载在 EXE 的地址空间中)来进行智能推理来检索模块实例。我说的对吗?
  • 我看不到您从 EXE 内部调用 GetProcAddress 的代码。你的例子不完整。我不相信调用 GetProcAddress 并将 0 作为模块句柄传递会导致错误以外的任何结果。
猜你喜欢
  • 2016-08-16
  • 2020-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-01
相关资源
最近更新 更多