如何获取基堆栈指针的地址 [英] How to get address of base stack pointer

查看:15
本文介绍了如何获取基堆栈指针的地址的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将应用程序从 x86 移植到 x64.我正在使用 Visual Studio 2009;大部分代码是 C++,有些部分是纯 C.编译到 x64 时不支持 __asm 关键字,并且我们的应用程序包含一些内联汇编程序.我没有写这段代码,所以我不知道 et 应该做什么:

I am in the process of porting an application from x86 to x64. I am using Visual Studio 2009; most of the code is C++ and some portions are plain C. The __asm keyword is not supported when compiling towards x64 and our application contains a few portions of inline assembler. I did not write this code so I don't know exactly what et is supposed to do:

int CallStackSize() {
    DWORD Frame;
    PDWORD pFrame;
    __asm
        {
            mov EAX, EBP
            mov Frame, EAX
        }
    pFrame = (PDWORD)Frame;
    /*... do stuff with pFrame here*/
}

EBP 是指向当前函数堆栈的基指针.有什么方法可以在不使用内联 asm 的情况下获取堆栈指针?我一直在研究 Microsoft 提供的作为内联 asm 替代品的内在函数,但我找不到任何对我有用的东西.有什么想法吗?

EBP is the base pointer to the stack of the current function. Is there some way to obtain the stack pointer without using inline asm? I have been looking at the intrinsics that Microsoft offers as a substitute for inline asm but I could not find anything that gave me something usefull. Any ideas?

Andreas 询问 pFrame 做了什么.这是完整的功能:

Andreas asked what stuff is done with pFrame. Here is the complete function:

int CallStackSize(DWORD frameEBP = 0)
{
    DWORD pc;
    int tmpint = 0;
    DWORD Frame;
    PDWORD pFrame, pPrevFrame;

    if(!frameEBP) // No frame supplied. Use current.
    {
        __asm
        {
            mov EAX, EBP
            mov Frame, EAX
        }
    }
    else Frame = frameEBP;

    pFrame = (PDWORD)Frame;
    do
    {
        pc = pFrame[1];
        pPrevFrame = pFrame;
        pFrame = (PDWORD)pFrame[0]; // precede to next higher frame on stack

        if ((DWORD)pFrame & 3) // Frame pointer must be aligned on a DWORD boundary. Bail if not so.
        break;

        if (pFrame <= pPrevFrame)
        break;

        // Can two DWORDs be read from the supposed frame address?
        if(IsBadWritePtr(pFrame, sizeof(PVOID)*2))
        break;

        tmpint++;
    } while (true);
    return tmpint;
}

未使用变量 pc.看起来这个函数沿着堆栈向下走,直到它失败.它假定它无法在应用程序堆栈之外读取,因此当它失败时,它已经测量了调用堆栈的深度.此代码不需要在 _EVERY_SINGLE 编译器上编译.只是VS2009.该应用程序不需要在 EVERY_SINGLE 计算机上运行.我们可以完全控制部署,因为我们自己安装/配置并将整个事情交付给我们的客户.

The variable pc is not used. It looks like this function walks down the stack until it fails. It assumes that it can't read outside the applications stack so when it fails it has measured the depth of the call stack. This code does not need to compile on _EVERY_SINGLE compiler out there. Just VS2009. The application does not need to run on EVERY_SINGLE computer out there. We have complete control of deployment since we install/configure it ourselves and deliver the whole thing to our customers.

推荐答案

真正正确的做法是重写这个函数所做的一切,这样它就不需要访问实际的帧指针.这绝对是不好的行为.

The really right thing to do would be to rewrite whatever this function does so that it does not require access to the actual frame pointer. That is definitely bad behavior.

但是,要做你正在寻找的事情,你应该能够做到:

But, to do what you are looking for you should be able to do:

int CallStackSize() {
    __int64 Frame = 0; /* MUST be the very first thing in the function */
    PDWORD pFrame;

    Frame++; /* make sure that Frame doesn't get optimized out */

    pFrame = (PDWORD)(&Frame);
    /*... do stuff with pFrame here*/
}

这样做的原因是,在 C 语言中,函数所做的第一件事通常是在分配局部变量之前保存基指针 (ebp) 的位置.通过创建一个局部变量(Frame)然后获取 if 的地址,我们就真正得到了这个函数的栈帧的起始地址.

The reason this works is that in C usually the first thing a function does is save off the location of the base pointer (ebp) before allocating local variables. By creating a local variable (Frame) and then getting the address of if, we're really getting the address of the start of this function's stack frame.

注意:某些优化可能会导致框架"变量被删除.可能不会,但要小心.

Note: Some optimizations could cause the "Frame" variable to be removed. Probably not, but be careful.

第二个注意事项:当pFrame"本身在堆栈上时,您的原始代码以及此代码会操纵pFrame"指向的数据.可能会在此处意外覆盖 pFrame,然后您的指针会出错,并且可能会出现一些奇怪的行为.在从 x86 迁移到 x64 时要特别注意这一点,因为 pFrame 现在是 8 个字节而不是 4 个字节,所以如果您的旧使用 pFrame 处理"代码在弄乱内存之前考虑了 Frame 和 pFrame 的大小,您将需要考虑新的更大尺寸.

Second Note: Your original code and also this code manipulates the data pointed to by "pFrame" when "pFrame" itself is on the stack. It is possible to overwrite pFrame here by accident and then you would have a bad pointer, and could get some weird behavior. Be especially mindful of this when moving from x86 to x64, because pFrame is now 8 bytes instead of 4, so if your old "do stuff with pFrame" code was accounting for the size of Frame and pFrame before messing with memory, you'll need to account for the new, larger size.

这篇关于如何获取基堆栈指针的地址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆