我遇到了弯路问题。众所周知,Detours只能在5个字节的空间之间移动(即一个' jmp'调用和一个4字节地址)。因此,不可能有“钩子”。在一个类(一个方法)中的函数,你不能提供这个'这个'指针,因为根本没有足够的空间(here's问题得到更彻底的解释)。所以我整天都在集思广益寻找解决方案,现在我想要你对这个主题的想法,所以我不会开始3-5天的项目而不知道是否可能。
我最初有3个进球,我想要'勾手'函数是类方法,我希望整个方法是面向对象的(没有静态函数或全局对象),而最坏/最难的部分是完全动态的。这是我的(理论上)解决方案;使用程序集可以在运行时修改函数(一个完美的例子是任何绕行方法)。因为我可以动态修改函数,所以我也不能动态创建它们吗?例如;我分配内存,让我们说~30个字节(通过malloc / new)。是不是可以用对应于不同汇编运算符的二进制数替换所有字节(比如0xE9是' jmp')然后直接调用地址(因为它包含一个函数)? / p>注意:我事先知道返回值,以及我想要绕道的所有函数的所有参数,并且因为我使用GCC,所以thiscall约定实际上与_cdecl一致。
所以这是我的想法/即将实施;我创建了一个'功能'类。此构造函数采用可变量的参数(第一个参数除外,它描述了目标函数的返回值)。
每个参数都是钩子将接收的参数的描述(大小,以及它是否是指针)。所以,我想说我想为int * RandomClass::IntCheckNum(short arg1);
创建一个Function类。然后我就必须这样做:Function func(Type(4, true), Type(4, true), Type(2, false));
。在哪里'类型'定义为Type(uint size, bool pointer)
。然后通过程序集我可以动态创建函数(注意:这将全部使用_cdecl调用约定),因为我可以计算参数的数量和总大小。
编辑:通过这个例子,Type(4, true)
是返回值(int *),scond Type(4, true)
是RandomClass'这个'指针和Type(2, false)
描述了第一个参数(简称arg1)。
通过这种实现,我可以很容易地将类方法作为回调,但是它需要大量的汇编代码(我甚至没有特别经验)。 最后,唯一非动态的东西就是我的回调类中的方法(也需要前后回调)。
所以我想知道;这可能吗?它需要多少工作,我在这里过头了吗?
编辑:对不起,如果我把所有内容都弄得有些模糊,但是如果有什么需要更彻底的解释,那就去问吧!EDIT2:我还想知道,如果我能在某处找到所有汇编运算符的十六进制值?一份清单会有所帮助!和/或如果有可能以某种方式“保存”' asm("");代码在内存地址(我非常怀疑)。
答案 0 :(得分:4)
你所描述的通常被称为“thunking”,并且通常被实现。从历史上看,最常见的目的是在16位和32位代码之间进行映射(通过自动生成一个新的32位函数,调用现有的16位函数,反之亦然)。我相信一些C ++编译器会生成类似的函数来调整基类指针,以便在多继承中调整子类指针。
对你的问题来说,这似乎是一个可行的解决方案,我没有预见到任何大问题。只需确保使用操作系统中所需的任何标志分配内存,以确保内存可执行(大多数现代操作系统默认情况下都会提供非可执行内存)。
您可能会发现此链接很有用,尤其是在Win32中工作时:http://www.codeproject.com/Articles/16785/Thunking-in-Win32-Simplifying-Callbacks-to-Non-sta
关于查找汇编操作的十六进制值,我所知道的最佳参考是NASM汇编程序手册的附录(我不只是这样说,因为我帮助编写了它)。这里有一份副本:http://www.posix.nl/linuxassembly/nasmdochtml/nasmdoca.html