在Visual Studio 2010 C++中使用内联汇编查找代码地址是否可行?

3
假设我想在C++代码中编写一个内联汇编函数,该函数返回其返回地址。
因此,如果我从某个地址调用函数returnAddress()并且需要在函数完成后返回到地址X,则希望returnAddress()返回值X。
returnAddress()的代码示例:
void* getAddress()
{
    __asm {
        pop ebx;     // moving return offset to ebx?
        push ebx;    // restoring stack state
        xor eax, eax;
        mov ax, cs;  // ax <- code segment
        mov ecx, 16;
        mul ecx;     // multiplying the code segment by 16
        add eax, ebx;// adding offset
    }
}

以前的代码不正确,因为当我按alt+8时,我可以清楚地看到我的代码地址与此函数的返回值完全不同。

我想查找内存中代码的地址是因为我想在代码本身正在运行时尝试更改它。如果有其他方法可以找到我的代码地址而不使用内联汇编(也许可以使用Windows API?),请告诉我。

此外,我相当确定我甚至不能使用Visual Studio 2010的CS(代码段)值,所以可能是这导致了我的问题...... CS始终等于35。 VS2010运行虚拟机,会导致汇编视图(alt+8)显示错误的地址吗?

这是我在这里的第一篇帖子,所以可能我没有表达清楚。如果我还可以解释得更清楚,请告诉我。


无论如何,在64位中这是不可能的,因为没有内联汇编。 - SomeWittyUsername
7
只需使用_ReturnAddress 内在函数即可。 - Raymond Chen
@RaymondChen 我收藏这个帖子就是为了那条评论。我从来不知道那个存在。谢谢! - WhozCraig
所以,自修改代码的问题#1已经解决,接下来是问题#2...? - Michael Burr
2个回答

4

实际上,我曾经尝试过理解你用于恢复返回地址的神秘代码。有人建议你可以使用内部函数_ReturnAddress。然而,为了好玩,你也可以使用以下直接的代码:

__declspec(naked) 
void* get_RetAddr()
{
    _asm {
        mov eax, [esp]
        ret
    }
}

4

代码段仅用于16位系统。随着32位的引入,代码段消失了。

您可以使用VisualStudio的内在函数_ReturnAddress()

void * _ReturnAddress(void);
#pragma intrinsic(_ReturnAddress)

void* getAddress()
{
    return _ReturnAddress();
}

如果你想手动完成它,比如在非VisualStudio编译器上,那么32位x86函数调用的调用栈包含完整的32位返回地址,因此你可以直接返回它:

void* __declspec(naked) getAddress()
{
    asm
    {
        mov eax, [esp];
        ret;
    }
}

对于 x64 的函数调用,你应该能够使用相应的 64 位寄存器:

void* __declspec(naked) getAddress()
{
    asm
    {
        mov rax, [rsp];
        ret;
    }
}

  1. 我认为你的第一个例子将返回getAddress内部的地址,而不是实际调用者的地址。
  2. 在64位构建中,据我所知,不允许使用内联汇编。
- valdo
1
@valdo:关于第二点,他确实说过:“如果你想手动完成它,请使用非VisualStudio编译器”。 - Evan Teran
@valdo:阅读MSDN文档:“_ReturnAddress内置函数提供了调用函数中将在控制返回给调用者后执行的指令地址。” 换句话说,_ReturnAddress()返回的是在调用getAddress()时CPU的CALL指令推送到调用堆栈上的地址。 - Remy Lebeau
在32位模式下,段并没有"消失",但Windows使用了一种平面内存模型,其中csdsesss都指向覆盖整个地址空间的4GB平面段。它确实使用了一个线程特定的fs选择器,该选择器为每个线程指向不同的内存。 - Igor Skochinsky
@Remy Lebeau:你说得对。我之前还以为_ReturnAddress只是一个“假”的内置函数,仅用来告诉当前指令指针的位置。同时,我也学到了什么是“IOW”。感谢你的分享 :) - valdo
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接