挂钩末端/功能中间

逆向工程 C++ dll注入
2021-06-24 06:30:21

除了函数的开头,我怎么能在任何地方挂钩?我正在尝试向第三方可执行文件添加功能,我需要它来完全执行它的代码,然后将其数据传递给我的函数。我无法完全想象如何做到这一点。

是否有捷径可寻?我找不到任何实现此功能的挂钩引擎。我在任何地方都找不到关于它的任何信息。

我看到有人说您可以添加非法操作码然后捕获异常,但我不知道该怎么做。

示例(伪代码):

int moveCharacter(int x, int y) {
    x += 5;
    y += 5;
    return 0;
}

假设我想在之前挂钩return 0,并将新变量xy变量传递给我自己的函数(在注入的 DLL 或代码洞穴中),该函数将变量写入日志文件。在我的函数之后,我想回到原来的函数,这样它就可以正常返回了。

3个回答

没有引擎来挂钩函数末尾的原因是因为很难确定它在哪里,或者它是否存在。一个函数只有一个入口点,但它可以有多个出口点,包括一个都没有(考虑 exit())。退出点也可以有多种类型 - return、throw()、longjmp()、C++EH 等。

在函数完成后挂钩的一般想法是绕过调用者,但对于您的需要为时已晚。无论如何,它是这样完成的:首先,绕过感兴趣的函数,它挂钩执行的开始。当您收到控制权时,取消挂接函数,然后从堆栈中读取返回地址(假设该函数将实际返回)。接下来绕过返回地址(调用者),然后让原函数执行。当您再次获得控制权时,该函数已完成其执行。您可以取消挂接返回地址,执行其他操作,然后继续执行。不幸的是,您将无法访问局部变量(根据您的描述,您似乎想要)。避免该问题的一种方法是单步执行该函数,通过安装 Vectored Exception Handler 来接收单步异常。这将允许您检查下一个将执行的指令(因为异常发生在前一条指令执行之后),如果是返回指令,那么您可以记录这些值。

就异常方法而言,您将安装一个向量异常处理程序来指向您的代码,然后在感兴趣的地方放置一个断点指令。同样,问题是确定那个地方在哪里。

Microsoft Detours使这变得非常容易。您可以有效地编写以下代码(为了安全起见,您还需要进行其他调用DetourUpdateThread()):

DetourTransactionBegin();
DetourAttach(&(PVOID&)OriginalFunction, Function);
DetourTransactionCommit();

然后将如下代码作为您的钩子:

int Function(int x)
{
   int r = OriginalFunction(x);

   // Handle r here

   return r;
}

一种更简单的方法是确定代码实际生成所需数据的点。找到该位置后,将接下来的几个字节替换为对您自己的代码的调用或远调用。仔细记下您要覆盖的字节。(顺便说一句,我建议使用 call 或 far call 而不是 jmp,这样我就不必担心代码重定位;我可以引用原始位置以从堆栈返回,而不必担心在哪里我相对于原始代码。)

您的代码应该做的第一件事是保留状态。也许是一个pusha/pushf?现在处理掉。代码的最后几个字节应该执行以下操作,而不是执行返回:

  • 弹出标志和寄存器
  • 从您之前覆盖的原始代码中复制字节
  • 通过调整 SP 以考虑呼叫或远呼叫来展开堆栈
  • jmp 或 far jmp 到当前 SP 正下方的 IP 或 CS:IP

这个过程实际上是传统恶意软件“挂钩”到您的代码的主要方式。你正在绕道而行。