【问题标题】:CreateRemoteThread, LoadLibrary, and PostThreadMessage. What's the proper IPC method?CreateRemoteThread、LoadLibrary 和 PostThreadMessage。什么是正确的 IPC 方法?
【发布时间】:2009-07-21 22:17:20
【问题描述】:

好的,我正在使用CreateRemoteThread/LoadLibrary“trick”将一些代码注入另一个进程。

我最终得到了一个线程 ID,以及一个带有我选择的 DLL 的进程。至少在理论上,DLL 目前什么都不做,所以验证这一点有点棘手。暂时我愿意单凭信心接受。此外,在我朝着这个方向努力之前需要回答这个问题。

基本上,您不能在 DllMain 中阻止。但是,我与远程线程通信的只是它的 id。这实际上要求 PostThreadMessage/GetMessage 恶作剧阻塞。我可以在 DllMain 中启动另一个线程,但我无法将其 id 传回创建线程,也无法将另一个线程的 id 传递给远程线程。

简而言之,如果我在一个进程中创建一个远程线程,我应该如何与原始进程通信?

【问题讨论】:

    标签: c++ winapi dll ipc


    【解决方案1】:

    步骤零;注入的 DLL 应该有一个入口点,我们称之为 Init(),它将 LPCWSTR 作为其单个参数并返回一个 int;即与LoadLibrary() 相同的签名,因此作为线程启动函数地址同样有效...

    第一步;使用加载库和远程线程注入。在注入的 DLL DLLMain() 中什么也不做。存储返回的HMODULE作为注入线程的退出码,这个就是注入DLL的HMODULELoadLibrary()的返回值。

    注意,如果 /DYNAMICBASE 和 ASLR(地址空间布局随机化)已启用,因为 x64 上的 HMODULE 已启用,这不再是 x64 上的可靠方法大于从GetThreadExitCode() 返回的DWORD 值,并且地址空间更改意味着HMODULE 的值不再小到足以适合DWORD。有关使用共享内存与HMODULE 进行通信的解决方法,请参阅下面的 cmets 和链接的问题(此处)

    第二步;使用 LoadLibrary 将注入的 DLL 加载到正在进行注入的进程中。然后在地址空间中找到您的Init() 入口点的偏移量,并从中减去您在地址空间中注入的DLL 的HMODULE。您现在有了Init() 函数的相对偏移量。取目标进程中注入的DLL的HMODULE(即你在步骤一中保存的值),并将Init()的相对地址添加到其中。现在,您的目标进程中的地址为 Init()

    第三步;使用与调用LoadLibrary() 相同的“远程线程”方法在目标进程中调用Init()。您可以将字符串传递给 Init() 调用,这可以是您喜欢的任何内容。

    我倾向于传递一个唯一的字符串键,我将其用作命名管道名称的一部分。注入的 DLL 和注入进程现在都知道命名管道的名称,您可以在它们之间进行通信。 Init() 函数不是DLLMain() 并且不受影响DLLMain() 的限制(因为它不是从LoadLibrary 中调用的,等等),所以你可以在其中做正常的事情。一旦注入的 DLL 和注入进程通过命名管道连接,您就可以根据需要来回传递命令和数据结果。由于您向Init() 函数传递了一个字符串,因此您可以确保命名管道对于您的注入进程的这个特定实例和这个特定的注入 DLL 是唯一的,这意味着您可以同时运行注入进程的多个实例,并且每个进程可以注入多个目标进程,并且所有这些通信通道都是唯一且可控的。

    【讨论】:

    • 我看不出将字符串传递给 CreateRemoteThread(...,dllExportAddrInRemoteProcess,stringBuffer,...) 是如何工作的(没有 WriteProcessMemory)。但是,两个进程都知道注入线程的进程 ID 和线程 ID,因此您可以将它们用作与 IPC 一起使用的名称的一部分
    • 是的,您使用 WriteProcessMemory() 的方式与调用 LoadLibrary() 的方式完全相同。我同意你可以通过其他方式伪造一个唯一的 id,但是你需要调用 DLLMain() 以外的东西来允许你进行由于限制而不能在 DLLMain() 中进行的初始化。
    • 退出码的类型是DWORD - 一个32bit unsigned int值,如果进程是64bit,如何获取HMODULE?
    • 好问题。在我的代码中,我只是将其转换为...它的工作原理是 dll 倾向于加载到适合 32 位值的地址空间区域中,因此截断无关紧要。我想知道你是否可以通过将 dll 的首选基地址设置为不适合的东西来打破这一点……我一直在寻找有关 dll 加载地址和进程的虚拟地址空间的明确答案,但找不到任何东西...
    • @amanjiang,请参阅此处:stackoverflow.com/a/27348017/7925 以获得一些建议。
    【解决方案2】:

    您没有远程进程中线程的线程ID,因为当您的模块成功加载到进程的地址空间时,您用来加载dll的那个就退出了。

    您可以轻松使用正常的进程间通信方法,例如命名部分/管道/创建命名窗口/等。与您的“注入”过程进行通信。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-15
      • 2019-05-17
      • 2011-02-23
      • 2014-12-08
      • 1970-01-01
      • 2015-04-01
      相关资源
      最近更新 更多