【问题标题】:Hook crashing after trampoline蹦床后钩子坠毁
【发布时间】:2014-12-30 15:52:53
【问题描述】:

我试图创建一种我玩的游戏的叠​​加层,以便实时显示我的 ping,因为存在很多问题并且人们指责 ping,所以我只想要一个简单的解决方案并添加实时 ping 显示在游戏中:)

无论如何,钩子一直是我一直在努力解决的问题,我知道它是如何工作的,但它对我来说从来没有奏效,这是我在无数地方看到的代码,但在经历了蹦床之后崩溃:

void* detour::Hook(BYTE* src, BYTE* dst, int len) {
    BYTE *jmp = (BYTE*)malloc(len+5);
    DWORD dwback;

    VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &dwback);

    memcpy(jmp, src, len);
    jmp += len;

    jmp[0] = 0xE9;
    *(DWORD*)(jmp + 1) = (DWORD)(src + len - jmp) - 5;

    src[0] = 0xE9;
    *(DWORD*)(src+1) = (DWORD)(dst - src) - 5;

    VirtualProtect(src, len, dwback, &dwback);

    return (src + 6);
}

我可以看到它真的很混乱,它使用 malloc 而不是 VirtualAlloc 等。但由于某种原因,它工作了一半:S 无论如何,这只是我用来尝试和获得更好理解的东西钩子,与此同时,我正在编写自己的一些代码:

DWORD detour::SetHook(DWORD src, DWORD dst, int len) {
    BYTE* backup;
    DWORD oldProtection;
    DWORD trampolineAddr;

    VirtualProtectEx(GetModuleHandle(NULL), (void*) dst, 5, PAGE_READWRITE, &oldProtection);

    //Create trampoline backup
    trampolineAddr = (DWORD) VirtualAllocEx(GetModuleHandle(NULL), NULL, 10, MEM_COMMIT |    MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    memcpy((void*) trampolineAddr, (void*) dst, 5);
    memcpy((void*)(trampolineAddr + 5), (void*) 0xE9, 1);
    memcpy((void*)(trampolineAddr + 6), (void*) dst, 4);

    //set API hook
    memcpy((void*)dst, (void*) 0xE9, 1);
    memcpy((void*)(dst + 1), (void*)src, 4);

    VirtualProtectEx(GetModuleHandle(NULL), (void*) dst, 5, oldProtection, &oldProtection);

    return trampolineAddr;
}

它的作用是返回创建蹦床的地址,我只是在调用了替换挂钩函数的函数后跳转到该地址,所有这些都不起作用:/

所以我的问题本质上是真的,为什么第一个钩子只能在中途工作?我的钩子有什么问题?它创建了到地址的跳转,备份了被覆盖的字节并将它们保存在一个蹦床上,我在我的自定义函数之后跳转到它,但它都不起作用:(

非常感谢一些建设性的反馈,因为这是我已经想掌握了很长时间的东西 :) 提前致谢!

【问题讨论】:

  • 这两段代码都将代码的保护更改为read_write_execute,然后又变回原来的样子。 malloc 几乎 100% 肯定不会为您提供可执行内存,并且您没有显示第二个函数用于内存分配的内容,所以不能说,但对于它为什么会崩溃似乎是一个合理的解释。你试过拆解蹦床吗?
  • memcpy(..., (void*)0xE9, 1) 语句应该做什么? 0xE9 肯定不是有效地址吗?
  • 是的,正如我所说的第一个代码不是我的,它是我用来更好地理解它的东西,它在编译时确实有效,尽管它在蹦床后崩溃了,并且用于内存分配第二个我使用VirtualAlloc,它在代码中哈哈,一旦我对它进行修改,我只是恢复旧的保护。我确实给它附加了一个调试器并且钩子被成功放置,它运行我的跳转以正常运行但是当它应该返回到原始函数时它以某种方式崩溃,因为地址只包含垃圾。
  • 0xE9 表示汇编中的跳转,所以我在函数的第一个字节中放置了一个跳转,然后是 4 个字节,即新函数的地址。
  • @Paze:啊哈,我明白了意图是什么——你想将0xE9(操作码)写入缓冲区,而不是使用例如设置它。 trampolineAddr[5] = 0xE9,你正在使用memcpy。但是memcpy 从你给它的地址读取字节,而不是地址本身的值——所以它不会在任何地方复制0xE9,而是试图读取地址@处的一个字节 987654332@,里面有垃圾。原始代码没有这样做。

标签: c++ hook reverse-engineering


【解决方案1】:

这段代码有很多问题:

DWORD detour::SetHook(DWORD src, DWORD dst, int len) {

DWORD 不是类型。您需要查找它,但如果它是真实类型(int,float double 是基础),通常它会变成蓝色。

BYTE* backup;

也不是真正的类型。如果非常大,请使用 int 或 double。

memcpy((void*) trampolineAddr, (void*) dst, 5);
memcpy((void*)(trampolineAddr + 5), (void*) 0xE9, 1);
memcpy((void*)(trampolineAddr + 6), (void*) dst, 4);

//set API hook
memcpy((void*)dst, (void*) 0xE9, 1);
memcpy((void*)(dst + 1), (void*)src, 4);

这可能是你的问题, void * 是不好的做法,在你的代码中是非常糟糕的。祝你好运。

艾哈迈德

【讨论】:

  • DWORDBYTE 在 Win32 编程中肯定是“真正的”类型。 DWORDunsigned int 的别名。 void* 有几个完全有效的用例。
  • BYTE 通常是unsigned char,就像@Cameron 说它是有效类型,如果你查看他们的页面 ^_^ example,微软会大力鼓励它
  • 是的,这些都是可以使用的有效类型,并且在我看来是创建了更清晰和可读的代码,我真的不认为我会选择哪一个会有所不同:) allthought 谢谢你的回复。
猜你喜欢
  • 2012-03-09
  • 2021-09-14
  • 1970-01-01
  • 2011-12-27
  • 1970-01-01
  • 2010-09-16
  • 2018-11-02
  • 1970-01-01
  • 2016-03-24
相关资源
最近更新 更多