正在使用调试器从应用程序中删除函数调用



我有一个应用程序,它为主程序循环的每次迭代调用一个函数。我想使用像OllyDBG这样的调试器来删除这个函数调用。

我想我大概是根据函数中的一些字符串找到了函数的位置

我该如何在不破坏程序的情况下进行此操作?

这实际上取决于程序如何使用函数。您需要一些基本的汇编语言才能成功地做到这一点,还可能需要理解不同的调用约定。

我将举几个越来越难的例子。

一个简单的例子

让我们假设您想要避免的功能具有以下原型:

void bad_function();

我们可以清楚地看到,它没有任何参数,也没有返回任何值。也可以说它不会更改任何全局变量或对程序进行任何其他更改。在这种情况下,我们可以安全地";删除";调用函数,一切都会很好。

然而,我们不能只从流中删除机器代码字节,因为有相对和硬编码的偏移,我们需要根据删除的字节数进行调整。幸运的是(尽管运气与此无关(,有一些被称为nop指令的特定指令,它们只是空的占位符,指示CPU不执行,而是继续执行下一条指令。

附带说明:尽管大多数指令集定义了nop指令,但它们通常只是已经存在但没有副作用的指令的约定。例如,常见的x86nop指令是0x90,在技术上是xchg eax, eax。显然,与自身交换寄存器没有任何作用。

一个简单的返回值

现在,假设函数返回一个布尔值,确定执行应该继续还是突然终止(比如说,因为程序认为发生了不好的事情(。

该函数的原型可能看起来像:

bool bad_function();

使用它的代码将是:

bool bad;
bad = bad_function();
if (bad)
{
ExitProcess();
}

由此产生的组件可能类似于:

call bad_function
test eax, eax
jz not_bad_function
call ExitProcess
not_bad_function:
... some more assembly

您会注意到,在这里,我们希望确保not_bad_function(这是我为方便阅读而命名的标签。实际上,它有一个偏移量(下的代码执行,并避免调用bad_function

我们想用nops替换不需要的指令。有时指令可能大于一个字节,我们会用几个nop指令而不仅仅是一个来替换单个指令。也有多字节长的nop指令,但我们在此不讨论。

在以下情况下,我们将希望nop输出所有四条指令,直到not_bad_function(这是两条calltestjz指令(。我们也可以使跳转无条件,并保持testcall的完整性。如果我们确实希望执行bad_function,这可能很方便,因为的确会产生我们感兴趣的某些副作用。

"清洁";堆栈

现在,假设bad_function接受参数。根据调用约定、传递的参数集、使用的编译器和目标体系结构,在调用bad_function之前,我们可能会得到几个push指令。这些用于将参数推送到堆栈,供调用的函数使用。同样,根据调用约定,调用方可能有责任在之后清理堆栈。在这种情况下,我们需要删除推送指令和函数调用后的清理。

随着代码越来越长,我将创建一个示例作为读者的练习。