如何将方法作为回调传递给 Windows API 调用(后续)?
接受的答案坚持使用通常的普通旧函数。
这段摘录特别引起我的注意:
实例方法有一个额外的隐式参数,其中包含 实例引用,即Self。
坚信应该有一种方法来使用一种“参数”适配器(重新措辞,摆脱不需要的 Self 隐式引用并提供指向兼容的适配回调函数的指针),我最终找到了这个 文章,标题为回调类 彼得·莫里斯。
综上所述,他使用了thunking技术作为适应技巧。 (免责声明:我从未测试过代码)。
我知道它作为一个解决方案不是很干净,但它允许面向对象设计具有所有假定的好处。
我的问题:
知道TCallbackThunk是基于回调函数签名的,如果像彼得莫里斯那样做的话,上面提到的帖子的答案是什么?
。
This post is a follow-up of a related question posted here by Ran.
The accepted answer sticks to the use of the usual a plain old function.
This excerpt particularly catch my attention:
An instance method has an extra, implicit, parameter containing the
instance reference, i.e. Self.
With the firm conviction that there should be a way to use a kind of "parameters" adapter (to rephrase get rid of the uneeded Self implicit reference and provide a pointer to a complying adapted callback function), I end up finding this article entitled Callback a class by Peter Morris.
To sum up, he uses thunking technique as adaptation trick. (Disclaimer: I never tested the code).
I know it's not very clean as a solution but it allows OO design with all the supposed benefits.
My Question:
Knowing that TCallbackThunk is based on the callback function signature, what would be the answer of the above refered post if doing it as Peter Morris did is the way to go?
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您实际上不需要完成所有这些工作,因为
EnumWindows
(引用问题中的函数)提供了一个数据参数。您可以在那里放置任何您想要的值,例如答案中演示的对象引用。 Morris 的技术更适合不提供任何通用数据参数的回调函数。要调整答案以使用 Morris 的代码,您首先需要确保回调方法的签名与 API 回调函数的签名相匹配。由于我们正在调用
EnumWindows
,因此我们需要一个返回 Bool 的双参数函数。调用约定必须是 stdcall (因为 Morris 的代码假定它,并且很难更改任何其他调用约定)。接下来,我们设置
TCallbackThunk
数据结构,其中包含所有机器代码和引用预期回调方法的跳转偏移量。然而,我们不使用莫里斯描述的方式。他的代码将数据结构放在堆栈上。这意味着我们将可执行代码放在堆栈上。现代处理器和操作系统不再允许这样做 - 操作系统将停止您的程序。我们可以通过调用 VirtualProtect 修改当前堆栈页面的权限,允许其执行来解决这个问题,但这会使整个页面可执行,并且我们不想让程序保持打开状态用于攻击。相反,我们将专门为 thunk 记录分配一块内存,与堆栈分开。
请注意,该记录中的这些是 32 位 x86 指令。我不知道相应的 x86_64 指令是什么。
You don't really need to go through all that work since
EnumWindows
(the function in the referenced question) provides a data parameter. You can put whatever value you want there, such as the object reference demonstrated in the answer. Morris's technique is better suited for callback functions that don't provide any general-purpose data parameter.To adapt the answer to use Morris's code, you'll first need to make sure the signature of the callback method matches the signature of the API's callback function. Since we're calling
EnumWindows
, we need a two-argument function returning Bool. The calling convention needs to be stdcall (because Morris's code assumes it, and it's difficult to thunk any other calling convention).Next, we set up the
TCallbackThunk
data structure with all the machine code and the jump offset referring to the intended callback method.However, we don't use the way Morris described. His code puts the data structure on the stack. That means we're putting executable code on the stack. Modern processors and operating systems don't allow that anymore — the OS will halt your program. We could get around that by calling
VirtualProtect
to modify the permissions of the current stack page, allowing it to be executed, but that makes the whole page executable, and we don't want to leave the program open for attack. Instead, we'll allocate a block of memory especially for the thunk record, separate from the stack.Note that those are 32-bit x86 instructions in that record. I have no idea what the corresponding x86_64 instructions would be.