【问题标题】:64-bit DLL entry point override64 位 DLL 入口点覆盖
【发布时间】:2012-10-17 12:16:23
【问题描述】:

简而言之,问题是这样的。我正在编写一个内核模式 Windows 驱动程序,当加载内核模式 DLL(或其他可执行模块)时会收到通知。在某些情况下,我必须拦截 DLL 入口点例程。也就是说,重写它以便首先调用我的例程,然后我可以将控制权传递给原始入口点。

在 32 位(确切地说是 x86)上,这样做没有问题。我得到了模块基映射地址,它实际上以标准 PE 头(由 Windows 可执行文件使用)开头。 DLL 入口点有一个 RVA(相对于映像库的地址)。我只是用我的例程地址减去模块基地址来覆盖它。瞧!

现在,64 位的情况更加复杂。问题是 RVA 仍然是 32 位整数。这样的 RVA 覆盖了从映像基地址开始到 4GB 偏移量结束的地址范围。引用同一个可执行模块中的任何符号都没有问题(假设它不超过 4GB 大小),但这会给跨模块拦截带来问题。当然,我的可执行模块和我试图挂钩的模块不必落入相同的 4GB 范围内,因此存在问题。

我暂时解决了这个问题,方法是用无条件的jmp 覆盖原始例程序言代码到我的代码中。这在 64 位平台上需要 12 个字节。然后,为了从我的例程中调用原始代码,我恢复了被覆盖的 12 个字节(意味着 - 我在覆盖之前保存它们)。

到目前为止 - 没有问题。但是现在事情正在发生变化,我必须支持多线程访问入口点例程(请不要问为什么,它与加载到所谓的“用户空间”中的多会话DLL有关,单独每个终端会话)。

其中一种解决方案是使用全局锁,但我想避免这种情况。

我知道所谓的“蹦床功能”,但我也想避免这种情况。这样做需要对函数 prolog 代码进行运行时解码,以正确识别指令边界和可能的分支。

最近我想到了另一个想法。如果我能找到原始 DLL 的一些“不需要的”部分,它的长度至少为 12 个字节(大小为mov RAX addr + jmp RAX)。然后这部分可能会被jmp 覆盖到我手中。那么入口点RVA可以设置到这部分!

要使其工作,只需要可以覆盖的适当部分。我想有这样的可能性,因为PE头包含很多几十年都不再使用的历史字段。

这个想法值得一试,还是众所周知的技术?安迪还有其他建议吗?

提前致谢。

【问题讨论】:

  • 你为什么不用蹦床?
  • 这听起来像一个rootkit——但不像我说的那样。
  • @Linuxios:希望不是 :)
  • 确实如此。必须对 64 位驱动程序进行签名才能将它们安装在用户的计算机上。获得证书的唯一方法是将驱动程序提交给 Microsoft 进行验证。在不太可能的情况下,他们不会拒绝驱动程序,那么 PatchGuard 很有可能会阻止这种情况。
  • @HansPassant:您只需要一个有效的威瑞信证书来签署驱动程序。无需将驱动程序提交给 Microsoft。

标签: windows 64-bit kernel hook driver


【解决方案1】:

您有多种选择。不幸的是,您只能从这 3 个中选择 2 个: 100% 固体;易于实施;便宜。

很有可能在 .TEXT 部分的末尾找到未使用的空间。这是因为 Windows 以 4k 的块将图像部分映射到内存中,而 .text 部分通常不是精确乘法。

另一个容易实现的是使用PE头。一个非常安全的覆盖区域是 DOS 存根。问题在于不能保证 PE 标头与入口例程位于同一部分(Microsoft 链接器将其放在同一部分,但不了解 GNU 或其他)。

另一个简单但仅适用于系统 DLL 的方法是执行“热修补”正在执行的操作,并重用每个函数前面设置为“nop”的 15 个字节和“mov edi,edi”指令。随 Windows 一起发布的所有 DLL 都是这种情况,以支持热补丁。

可靠但困难的选择是按照@David Heffeman 的建议去做。这种技术称为“着陆函数”,您将前 12 个字节复制到着陆函数中,然后该函数将跳转到原始函数。

简单可靠的选择是使用 MS Detour。 Microsoft Detour 是 Microsoft Research 的一款产品,它完全可以做到这一点,并且效果很好,并且受到支持,它可以处理可能出现的一堆极端情况和竞争条件(以及其他东西),并且它的 x86 版本是开放的资源。缺点是商业用途非常昂贵 - 我上次检查时是 10k。

【讨论】:

    猜你喜欢
    • 2014-08-08
    • 2020-03-13
    • 2011-07-17
    • 1970-01-01
    • 1970-01-01
    • 2021-08-20
    • 1970-01-01
    • 1970-01-01
    • 2012-09-22
    相关资源
    最近更新 更多