【发布时间】:2011-08-15 01:43:02
【问题描述】:
这个板上的第一个问题已经很长了 - 对此我深表歉意(在此感谢大家从这个平台获得的重要提示)。
我正在尝试hook几个函数(它或多或少是插件代码,所以我要hook的函数不是我写的/不能由我更改,但可以在同一个进程/线程中直接访问)微软绕道。
每个需要挂钩的函数都是由 c 风格的编译器生成的,并且总是有以下汇编“启动”代码:
045A1A85 push ebp
045A1A86 push ebx
045A1A87 push esi
045A1A88 push edi
045A1A89 call 045A1A8E
045A1A8E pop eax
045A1A8F mov ebx,eax
//go on with a little bit more assembler code
正如你所看到的,一些寄存器被压入堆栈,然后调用指令被调用到下一行(请不要要求更改它,因为我已经说过我无权访问这个生成的代码)。 call 指令更改堆栈 - 此堆栈更改保存在 eax 寄存器中并用于进一步处理(!!!)
此方法将被挂钩:
045A1A85 jmp hooking_function (528040h)
045A1A8A int 3
045A1A8B int 3
045A1A8C int 3
045A1A8D int 3
045A1A8E pop eax
钩子函数被定义为一个裸函数,它只是跳转到蹦床函数。
__inline __declspec(naked) void hooking_function()
{
//more code in future
__asm {
jmp org_func_trampoline
}
}
具有以下蹦床功能:
031F0060 push ebp
031F0061 push ebx
031F0062 push esi
031F0063 push edi
031F0064 call 045A1A8E
031F0069 jmp 045A1A8E
主要问题是,蹦床汇编代码中的调用指令 1) 向堆栈添加错误值(在本例中为 031f0064 而不是 045A1A89)--> 使用 eax 进一步处理将收到错误结果 2) 或多或少地破坏堆栈帧,因为下一个“ret”将跳回“031F0069” ==> 相同的处理将执行两次; ret 将被再次调用,导致错误的功能..
请理解,不保证我要挂钩的每个函数都以上述序言开头..因此我无法重写挂钩函数,并忽略蹦床方法...
所以在所有这些文本之后的基本问题: 是否可以将函数与 Microsoft Detour 挂钩,在函数的前 5 个字节中调用调用指令? (如果没有,还有其他选择吗?)
非常感谢您的阅读(希望您的帮助)
【问题讨论】:
-
地址和一切都相对正确吗?为什么您尝试挂钩的函数会调用下一条指令(
call 045A1A8E)? -
哦,是的,Detours 可以挂钩一个函数,其中前 5 个字节中有一个调用,只要你正确调用了蹦床。
-
@Seth Carnegie 感谢您的回答。据我所知,该函数尝试访问寄存器 eip,这可以通过调用下一行并读取堆栈(不是直接)来实现。
-
哦,地址并不总是相同的(相对跳转)——或者你的意思是什么地址? PS:打电话怎么可能绕道?据我了解(虽然我的汇编知识很基础,如果我错了请纠正我),调用指令会影响堆栈帧,下一个“ret”指令==>下一个“ret”指令总是会跳回到蹦床函数,如果蹦床函数包含一个“调用”,这可能不正确?
-
当 Detours 绕过某些东西时,它会复制前 5 个(左右)字节(确保不会将指令切成两半)并将它们保存在缓冲区中,然后放在缓冲区的末尾,
jmp回到它绕过它的地方,但加上它从函数中获取的字节数。那是它给你的“原始”函数的地址,所以当你调用它时,执行会转到缓冲区,然后执行前 5 个字节,然后跳回到原始函数 + 5 个字节,然后继续它是快乐的方式。堆栈没有混乱。原代码调用函数时,(更多来)