【问题标题】:How to hook functions that aren't in the Win32 API?如何挂钩不在 Win32 API 中的函数?
【发布时间】:2014-08-31 01:55:09
【问题描述】:

我制作了一个非常简单的程序,它创建了一个窗口并在左上角显示“随机数是:[从 0 到 9 的随机数]”。显示数字的函数如下所示:

void DisplayThings(HDC hdc, HWND hWnd, int randomNum)
{
    std::stringstream text;
    text << "Random number is: " << randomNum;
    TextOut(hdc, 0, 0, text.str().c_str(), text.str().length());
}

在 OllyDBG 中,我在地址 0x11211A0 找到了它:

接下来,我在 Microsoft Detour 的帮助下制作了一个试图绕过 DisplayThings 函数的 dll,下面是 dll 的样子:

#pragma comment(lib, "detours.lib")

#include <Windows.h>
#include <detours.h>
#include <tchar.h>
#include <sstream>

typedef void (*pDisplayThingsFunc)(HDC hdc, HWND hWnd, int randomNum);
void DisplayThingsFunc(HDC hdc, HWND hWnd, int randomNum)
{
    printf("function is being detoured\n");
    TextOut(hdc, 0, 20, L"detoured", 8);
}
pDisplayThingsFunc DisplayThingsFuncToDetour = (pDisplayThingsFunc)(0x11211A0);

BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved  )
{
    //DWORD *hiddenValueAdress = (DWORD*)(*(DWORD*)0x020FAB8);

    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:

        AllocConsole();
        freopen("CONOUT$", "w", stdout);

        DetourTransactionBegin(); 
        DetourUpdateThread(GetCurrentThread());

        DetourAttach(&(PVOID&)DisplayThingsFuncToDetour, DisplayThingsFunc);

        DetourTransactionCommit();

        break;

    case DLL_PROCESS_DETACH:
        FreeConsole();

        DetourTransactionBegin(); 
        DetourUpdateThread(GetCurrentThread());

        DetourDetach(&(PVOID&)DisplayThingsFuncToDetour, DisplayThingsFunc);

        DetourTransactionCommit();
        break;
    }

    return TRUE;
}

一旦我注入了 dll,地址就会被正确地替换为我的新函数的 JMP,但随后发生了一些奇怪的事情......控制台继续打印“函数正在绕行”但 TextOut 函数无法显示任何内容...... .

任何帮助将不胜感激!

【问题讨论】:

  • “继续打印”是什么意思?它会重复打印吗?
  • 你有没有尝试在 Olly 中单步执行你的钩子函数后,它被钩住了? (JMP detour 应该带你到你的钩子函数)当你在 Olly 的钩子函数中时,尝试查看参数是否正确传递给 TextOut 函数。
  • @user35443 - 每 5 秒打印一次“函数正在绕行”,因此它与函数应该绕行的次数相匹配。
  • @blackd0t - 是的,我尝试过单步执行,但参数肯定没有正确传递,但我不知道为什么。例如,我尝试打印第三个参数(int randomNum),虽然它应该是 0 到 9 之间的数字,但它返回 138000...知道为什么吗?
  • 今晚我有两个镜头: 1. 编译器可能使用一些不同的调用约定,也许你可以尝试强制编译器只使用其中一个。 2. 编译器可能正在优化你的函数(将一些参数传递给寄存器)。

标签: c++ assembly hook reverse-engineering dll-injection


【解决方案1】:

编译器正在优化代码,因为它推断它可以安全地为此函数这样做。

  • 未导出。
  • 不与函数指针一起使用。
  • 不在分析范围之外使用。 (取决于编译器设置)
  • 很可能只有一个调用者(如果有更多具有不同设置的不同调用者,则参数被优化掉的可能性较小)。

您可以更改其中一项(例如,通过导出符号、将其分配给函数指针等)。

或者您现在可以尝试按原样连接它。

首先你需要推断出你感兴趣的论点在哪里通过,which is most likely a register. 最简单的方法是分析对 TextOut 的调用并追溯 hdc 参数。 如果幸运的话,只需将其设为 fastcall 即可对其进行优化,请将函数的类型和函数指针都更改为 fastcall,然后就可以完成了。

如果你没有那么幸运,你可能不得不从一个额外的寄存器中使用内联汇编来获取它。

【讨论】:

  • 编译器没有优化代码,你可以看到一半的函数被正确执行,printf调用。失败的是 TextOut 调用,可能是因为未正确传递参数。编译器之所以不优化代码,是因为在调用DetourAttach时取到了函数的地址。
  • 我说的是优化代码,而不是优化功能。
  • 而且编译器完全没有理由不优化代码,因为 DetourAttach 采用的是绝对地址,而不是函数的地址,而且 DetourAttach 在单独的 dll 中,而不是主应用程序。
  • 对不起,我试图对您所说的“优化代码”的意思应用最合理的解释。否则你的帖子毫无意义,因为它没有显示你所说的“优化代码”会导致任何类似于所描述的行为。
  • 从第二部分开始,即它很可能使用寄存器来传递参数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
  • 2020-12-11
  • 2014-05-20
  • 1970-01-01
  • 2022-01-23
相关资源
最近更新 更多