Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get address of base stack pointer

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 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 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;
}

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.

like image 535
Jacob Kristensen Avatar asked Dec 04 '09 13:12

Jacob Kristensen


People also ask

What is base pointer in stack?

The base pointer is conventionally used to mark the start of a function's stack frame, or the area of the stack managed by that function. Local variables are stored below the base pointer and above the stack pointer.

Where is the stack pointer located?

Regardless of the approach, the stack pointer is always located at the top of the stack, providing a reliable starting point for accessing stack memory.

What is the base pointer register?

Base Pointer (BP) − The 16-bit BP register mainly helps in referencing the parameter variables passed to a subroutine. The address in SS register is combined with the offset in BP to get the location of the parameter. BP can also be combined with DI and SI as base register for special addressing.

What is EBP and EIP?

-based practice (EBP) or evidence-informed practice (EIP) is a process for making informed clinical decisions. Research evi- dence is integrated with clinical experience, patient values, prefer- ences and circumstances.


2 Answers

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*/
}

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.

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.

like image 152
SoapBox Avatar answered Nov 15 '22 16:11

SoapBox


You can use the _AddressOfReturnAddress() intrinsic to determine a location in the current frame pointer, assuming it hasn't been completely optimized away. I'm assuming that the compiler will prevent that function from optimizing away the frame pointer if you explicitly refer to it. Or, if you only use a single thread, you can use the IMAGE_NT_HEADER.OptionalHeader.SizeOfStackReserve and IMAGE_NT_HEADER.OptionalHeader.SizeOfStackCommit to determine the main thread's stack size. See this for how to access the IMAGE_NT_HEADER for the current image.

I would also recommend against using IsBadWritePtr to determine the end of the stack. At the very least you will probably cause the stack to grow until you hit the reserve, as you'll trip a guard page. If you really want to find the current size of the stack, use VirtualQuery with the address you are checking.

And if the original use is to walk the stack, you can use StackWalk64 for that.

like image 44
MSN Avatar answered Nov 15 '22 16:11

MSN