【问题标题】:Removing function call from application using a debugger使用调试器从应用程序中删除函数调用
【发布时间】:2019-01-01 19:34:02
【问题描述】:

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

我想我大致定位了函数应该基于其中的一些字符串的位置。

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

【问题讨论】:

    标签: debugging reverse-engineering


    【解决方案1】:

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

    我会举几个例子,难度越来越大。

    一个简单的例子

    假设您要避免的函数具有以下原型:

    void bad_function();
    

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

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

    附注:尽管大多数指令集定义了 nop 指令,但它们通常只是已经存在但没有副作用的指令的约定。例如,常见的 x86 nop 指令是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-out 所有四个指令直到not_bad_function(这是两个calls,testjz 指令)。 我们也可以使跳转无条件,并保持testcalls 不变。如果我们确实想要执行bad_function,这可能会很方便,因为它确实会产生我们感兴趣的某些副作用。

    “清理”堆栈

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

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

    【讨论】:

      猜你喜欢
      • 2011-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-31
      • 1970-01-01
      • 2019-06-30
      相关资源
      最近更新 更多