函数指针地址与调试器显示的不一致

发布于 2025-01-05 22:34:03 字数 2088 浏览 1 评论 0原文

首先 - 如果这个问题表现出我的无知或者我不知道某些事情,我深表歉意。 我正在尝试做一些涉及读取函数地址下的指令的事情,并且我已经通过检查编译器生成的 .pdb 文件来设法获取函数生成的代码大小。

但有一些事情让我感到困惑,请看下面的例子:

int function(int a, int b)
{
    return a + b;
}

int main(int argc, char* argv[])
{
    // (...)
    void* address = &function;
    function(10, 20);
    // (...)
}

对于在调试器下的特定运行,我将 0x00c011f4 存储在 void* 地址中,并且 VS 的反汇编窗口相应地显示:

int main(int argc, char* argv[])
{
00C04B00  push        ebp  
00C04B01  mov         ebp,esp  
00C04B03  sub         esp,178h  
00C04B09  push        ebx  
00C04B0A  push        esi  
00C04B0B  push        edi  
00C04B0C  lea         edi,[ebp-178h]  
00C04B12  mov         ecx,5Eh  
00C04B17  mov         eax,0CCCCCCCCh  
00C04B1C  rep stos    dword ptr es:[edi]  
    void* address = &function;
00C04B1E  mov         dword ptr [address],offset function (0C011F4h)  
    function(10, 20);
00C04B25  push        14h  
00C04B27  push        0Ah  
00C04B29  call        function (0C011F4h)  
00C04B2E  add         esp,8  

根据 00C04B1E 下的指令,对应的地址function 的开头位于 0C011F4 下 - 这正是存储在 void* 地址中的内容。

现在使用调试器单步执行并跳转到 function(int, int) 给出以下反汇编结果:

int function(int a, int b)
{
00C019C0  push        ebp  
00C019C1  mov         ebp,esp  
00C019C3  sub         esp,0C0h  
00C019C9  push        ebx  
00C019CA  push        esi  
00C019CB  push        edi  
00C019CC  lea         edi,[ebp-0C0h]  
00C019D2  mov         ecx,30h  
00C019D7  mov         eax,0CCCCCCCCh  
00C019DC  rep stos    dword ptr es:[edi]  
    return a + b;
00C019DE  mov         eax,dword ptr [a]  
00C019E1  add         eax,dword ptr [b]  
}
00C019E4  pop         edi  
00C019E5  pop         esi  
00C019E6  pop         ebx  
00C019E7  mov         esp,ebp  
00C019E9  pop         ebp  
00C019EA  ret  

这里 function(int, int) 的请求位于 0x00C019C0 下。这是为什么?相差 1996 个字节。我试图找到任何相关性,但我认为我在这里遗漏了一些基本的东西。有人可以告诉我为什么这两个地址不同吗?

另外,当我复制 void* 地址 (0C011F4) 指向的区域时,我没有获得与 function(int, int) 下的 asm 指令相对应的机器代码。

提前致谢!

环境:Windows x64、VC10

First of all - I apologize if this question shows ignorance or I'm not aware of something.
I'm trying to do something that involves reading the instructions under a function's address and I've already managed to get function's generated code size by examining the .pdb file generated by the compiler.

But there is something that confuses me, look at the following example:

int function(int a, int b)
{
    return a + b;
}

int main(int argc, char* argv[])
{
    // (...)
    void* address = &function;
    function(10, 20);
    // (...)
}

For a particular run under a debugger I've got 0x00c011f4 stored in void* address and VS's dissassembly window was showing accordingly:

int main(int argc, char* argv[])
{
00C04B00  push        ebp  
00C04B01  mov         ebp,esp  
00C04B03  sub         esp,178h  
00C04B09  push        ebx  
00C04B0A  push        esi  
00C04B0B  push        edi  
00C04B0C  lea         edi,[ebp-178h]  
00C04B12  mov         ecx,5Eh  
00C04B17  mov         eax,0CCCCCCCCh  
00C04B1C  rep stos    dword ptr es:[edi]  
    void* address = &function;
00C04B1E  mov         dword ptr [address],offset function (0C011F4h)  
    function(10, 20);
00C04B25  push        14h  
00C04B27  push        0Ah  
00C04B29  call        function (0C011F4h)  
00C04B2E  add         esp,8  

According to the instruction under 00C04B1E, the address that corresponds to the beginning of function is under 0C011F4 - which is exactly what gets stored in void* address.

Now stepping through with the debugger and following the jump to function(int, int) gives me the following disassembly:

int function(int a, int b)
{
00C019C0  push        ebp  
00C019C1  mov         ebp,esp  
00C019C3  sub         esp,0C0h  
00C019C9  push        ebx  
00C019CA  push        esi  
00C019CB  push        edi  
00C019CC  lea         edi,[ebp-0C0h]  
00C019D2  mov         ecx,30h  
00C019D7  mov         eax,0CCCCCCCCh  
00C019DC  rep stos    dword ptr es:[edi]  
    return a + b;
00C019DE  mov         eax,dword ptr [a]  
00C019E1  add         eax,dword ptr [b]  
}
00C019E4  pop         edi  
00C019E5  pop         esi  
00C019E6  pop         ebx  
00C019E7  mov         esp,ebp  
00C019E9  pop         ebp  
00C019EA  ret  

Here the begging of function(int, int) is under 0x00C019C0. Why is that? that's 1996 bytes apart. I've tried to find any correlation but I think that I'm missing something fundamental here. Could someone please tell me why these two addresses are different?

Also when I copy the area pointed by void* address (0C011F4) I don't get the machine code that corresponds to the asm instructions that are under function(int, int).

Thanks in advance!

Env: Windows x64, VC10

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

但可醉心 2025-01-12 22:34:03

这是因为您在调试模式下编译了二进制文件,导致 MSVC 在调用和实际函数之间放置中间跳转(供“编辑并继续”使用)。因此,您获得的地址(和程序集)是指向您的函数的跳转地址。

您可以通过使用发布模式或禁用“编辑和编辑”来删除它。继续。或者,您可以采取长路线并仅反汇编跳转(它应该是 32 位相对跳转),并使用跳转所需的相对位移来调整地址。

This is cause you have compiled the binary in Debug mode, causing MSVC to put an intermediary jump between the call and the actual function (for use by Edit & Continue). So the address that you are getting (and the assembly) is the address of the jump that points to your function.

You can remove this by either using release mode or disabling Edit & Continue. Alternatively you can take the long route and just disassemble the jump (it should be a 32-bit relative jump), and adjust the address using the relative displacement the jump would you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文