如何修复 C 程序中的 Hook(堆栈的恢复)

How to fix a Hook in a C program (stack's restoration)

这是一种训练任务,因为现在这些方法(我猜)已经行不通了。

使用Win XP和MinGW编译器。不涉及特殊的编译器选项(仅 gcc 声明一个源文件)。

首先保存一个程序退出地址,跳转到某个Hook函数:

// Our system uses 4 bytes for addresses.
typedef unsigned long int DWORD;

// To save an address of the exit from the program.
DWORD addr_ret;

// An entry point.
int main()
{
   // To make a direct access to next instructions.
   DWORD m[1];

   // Saving an address of the exit from the program.
   addr_ret = (DWORD) m[4];

   // Replacing the exit from the program with a jump to some Hook function.
   m[4] = (DWORD) Hook;

   // Status code of the program's execution.
   return 0;
}       

这段代码的目标是获得对系统权限级别的访问权限,因为当我们return(应该return)到系统时,我们只是将我们的程序重定向到我们的一些方法。该方法的代码:

// Label's declaration to make a jump.
jmp_buf label;

void Hook()
{
   printf ("Test\n");

   // Trying to restore the stack using direct launch (without stack's preparation) of the function (we'll wee it later).
   longjmp(label, 1);

   // Just to make sure that we won't return here after jump's (from above) finish, because we are not getting stuck in the infinite loop.
   while(1) {}
}

最后我将说明一个函数(在我看来)应该修复堆栈指针 - ESP 寄存器:

void FixStack()
{
   // A label to make a jump to here.
   setjmp(label);

   // A replacement of the exit from this function with an exit from the whole program.
   DWORD m[1];
   m[2] = addr_ret;
}

当然我们应该将这些包含用于所述程序:

#include <stdio.h>
#include <setjmp.h>

该程序的整个逻辑在我的系统中运行正常,但我无法恢复我的堆栈 (ESP),因此该程序 return 是一个不正确的 return 代码。

在上述解决方案之前,我没有使用跳转和FixStack功能。我的意思是这些行在 Hook 函数中而不是跳转和 while 循环:

DWORD m[1];
m[2] = addr_ret;

但是对于这个变体,我在退出程序之前在 ESP 寄存器中得到了一个不正确的值(它比进入这个程序之前这个寄存器的值大 8 个字节)。所以我决定以某种方式添加这 8 个字节(避免 C 程序中的任何 ASM 代码)。这是跳转到 FixStack 函数并从中适当退出的目的(从堆栈中删除一些值)。但是,正如我所说,它不是 return 使用此命令执行程序的正确状态:

echo %ErrorLevel%

所以我的问题非常广泛:从询问调试实用程序的一些使用建议开始(我只使用 OllyDbg),并以描述的 Hook 实现的可能解决方案结束。

好的,我终于可以让我的程序按预期运行了。现在我们可以使用正确的 return 代码启动编译的(我在 Win XP 中使用 MinGW)程序,没有任何错误。

也许对某人有帮助:

#include <stdio.h>
#include <setjmp.h>

typedef unsigned long int DWORD;

DWORD addr_ret;


int FixStack()
{
    DWORD m[1];
    m[2] = addr_ret;

    // This line is very necessary for correct running!
    return 0;
}


void Hook()
{
    printf("Test\n");

    FixStack();
}


int main()
{
    DWORD m[1];

    addr_ret = (DWORD) m[4];

    m[4] = (DWORD) Hook;
}

当然,您似乎已经意识到这只适用于非常特定的构建环境。它绝对不会在 64 位目标上工作(因为地址不是 DWORD-ish)。

您是否有任何理由不想使用 C 标准库提供的工具来执行此操作? (或与此非常相似的内容。)

#include <stdlib.h>

void Hook()
{
    printf("Test\n");
}

int main()
{
    atexit(Hook);
}