裸__declspec上的 memcpy 返回意外的字节

memcpy on __declspec naked returns unexpected bytes

本文关键字:意外 字节 返回 memcpy declspec 上的      更新时间:2023-10-16

我正在尝试获取__declspec(naked)函数的原始字节,但memcpy返回了我不期望的字节。

我使用调试器来检查字节/地址。一切看起来都很好,但memcpy的结果会产生不同的、看似不变的字节。

void __declspec(naked) widget_click_fix_asm()
{
__asm {
nop
call patched_widget_handler
}
}
void test_patch()
{
char buf[7];
::memcpy(&buf, &widget_click_fix_asm, 7);
}

在VS调试器中,在中间窗口中,我执行了:

&widget_click_fix_asm
0x778816f0

导航到该内存位置将显示以下字节:

778816F0 90
778816F1 FF 15 38 91 88 77

我希望buf是以下字节的容器:

[0x90, 0xFF, 0x15, 0x38, 0x91, 0x88, 0x77]

相反,每次测试时buf都包含以下常量字节:

[0xE9, 0xD8, 0x05, 0x00, 0x00, 0xE9, 0x63]

为什么我没有得到预期的字节数?

您观察到的是由于 MSVC 调试模式下的增量链接。widget_click_fix_asm的地址实际上不是函数本身,而是JMP输出表中JMP指令的地址。此表用于将新版本的函数修补到现有可执行文件中。这是通过在可执行文件中具有足够空间的可用区域中编写新函数,然后使用新地址更新JMP thunk表来完成的。这有助于Visual Studio中的编辑和继续调试功能。

在您的示例中,您对memcpy的调用最终将 JMP Thunk 表的一部分复制到buf而不是函数本身。您可能希望考虑关闭增量链接功能,以获得所需的行为。