Log in

View Full Version : Test for stack or heap


Silver
April 18th, 2007, 05:23
Hi all,

Been mulling this one over for a bit and I can't quite find a satisfactory answer. C/C++ question.

Assuming I have a pointer to "something", how can I programmatically determine whether that something is created on the stack or the heap.

Consider this code:

Code:
LoadLibrary(....blah...);
pfnExport = GetProcAddress("RandomFunc", ....blah...);

int nReturn = pfnExport();


nReturn now has either a pointer or a value in it, depending what RandomFunc returns. All fine so far. Now here's the kicker. How do I differentiate between this code in the RandomFunc export returning a heap ptr:

Code:
void* RandomFunc()
{
char* pszNew = new char[10];
strcpy(blah into pszNew);
return (void*)pszNew;
}


and this code returning a string literal:

Code:
void* RandomFunc()
{
return "blah1234";
}


The first example would require my code to do this:

Code:
int nReturn = pfnExport();
void* ptr = (void*)nReturn;
delete ptr


But doing this on the second example will die horribly. Programmatically, if the DLL is a black box DLL I don't have docs or info for, I have no simple way to determine this.

I tried using _CrtIsValidHeapPointer() on the pointer but this just breaks and chucks "Invalid address specified to RtlValidateHeap()" at me, which I can't catch with an exception.

Anyone have an idea?

Thanks!

0xf001
April 18th, 2007, 05:33
how about to measure offset from ebp?

regards, 0xf001

Maximus
April 18th, 2007, 05:56
as long as DLL is not packed (in case, you need to... ) you might be able to walk the heap tree (see heap32first/list) and check it. DLL is in your process space, so cant escape.

If you need a faster solution, eh.... run the DLL in Olly, and check the loaded length after load (after it's unpacked in memory). Since all its memory is consecutive, you will be able to know its true 'length' in memory.

Take the handle of dll (in win32==memory address), add effective length and check if it's in that space or not. If it is, avoid freeing it

Maximus

0xf001
April 18th, 2007, 06:53
hi,

do you want to do it at runtime? you know where your stack is. you know where your heap is (hopefully). if not, allocate some mem

talking about

Code:
void* RandomFunc()
{
return "blah1234";
}


neither on heap, nor on stack. its in a (ro)data segment.

regards, 0xf001

Silver
April 18th, 2007, 07:10
Quote:
how about to measure offset from ebp?


Of the returned ptr? That wouldn't necessarily guarantee whether it's in the heap or not though, would it?


Quote:
you might be able to walk the heap tree (see heap32first/list) and check it.


Hey, those are handy - I never knew they existed. Thanks! You're right that it might be a bit slow. Heap space isn't guaranteed to be contiguous is it, so I can't just find the first and last and check if the ptr is within those.

Re: olly suggestion, it has to be programmatic at runtime. No manual intervention unfortunately


Quote:
neither on heap, nor on stack. its in a (ro)data segment.


Yes, you're right, sorry. My question is better phrased as "How do I know if a ptr is in the heap" - if it is, then I need to delete it, if it's not then I don't care. The literal was just an example of something I don't care about

Thanks!

Maximus
April 18th, 2007, 07:17
YOu need to fire olly once, to eval the length at design time. You could read it by processing PE header sections, but it won't work on packed files. But you can check it manually 'once' with olly, take the length and then just doing the '+' math and the check at runtime

If there are more versions of that DLL, you might want to eval the lengtrh of all and make a table out of it in your app.

0xf001
April 18th, 2007, 07:42
hi,

my idea was, when its "close enough" (ahem ) to ebp it should be on stack.

after rephrasing, walking heap tree might be most suitable i think. when its "just" stack vs heap, u could measure offsets from ebp, and from some allocated mem on heap, and determine good borders it should theoretically work, as you dont need an exact pointer or so. you need the range where it is. i did not try this!

regards, 0xf001

Silver
April 19th, 2007, 04:38
Thanks guys.

Maximus, I can't really use Olly because I don't want to have to add code/manage a table for different versions. Otherwise your suggestion would be perfect


Quote:
my idea was, when its "close enough" (ahem ) to ebp it should be on stack.




I think I'll write the code to walk the heap - it seems like the most sensible solution, and speed isn't a massive issue for this.

Cheers!

OHPen
April 19th, 2007, 07:10
Hi,

im not sure but it shouldnt be difficult to determine.
What about this:
Get the heap starting address by win32 api,
allocate something to the heap
compare the address you want to check whether its inside the range of allocated space - heap start. More shouldnt be necessary if im not wrong.
If it is not inside the range you can consider that it is normally allocated memory

Correct me if im wrong please...

OHPen

deroko
April 19th, 2007, 13:46
Code:

kd> dt nt!_NT_TIB
+0x000 ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD
+0x004 StackBase : Ptr32 Void
+0x008 StackLimit : Ptr32 Void

+0x00c SubSystemTib : Ptr32 Void
+0x010 FiberData : Ptr32 Void
+0x010 Version : Uint4B
+0x014 ArbitraryUserPointer : Ptr32 Void
+0x018 Self : Ptr32 _NT_TIB
kd>


do you need anything else :P

fuex
April 19th, 2007, 14:39
Quote:
[Originally Posted by OHPen;65026]to check whether its inside the range of allocated space - heap start.

this would require all the heap space to be contiguous. but the heap consists of blocks of memory, as far as I know.

evlncrn8
April 19th, 2007, 16:53
to check if its on the stack, u could also check the stack range
fs:[8] and fs:[4].... (in 64 bit its gs:[8] and gs:[0ch] if i remember right)

heap is also usually below the base address of the process, stack is usually above it ( > base address of the process + image size) .. at least on win2k or higher

Silver
April 20th, 2007, 04:16
Quote:
do you need anything else :P


Stack only, though. What I really need is "is this pointer on the heap or not". I don't care where it is if it's not, just that it's not on the heap. I think my badly worded original post caused a bit of confusion, sorry.


Quote:
this would require all the heap space to be contiguous. but the heap consists of blocks of memory, as far as I know.


Correct. That's why I'd have to walk it with Maximus' suggestion, rather than take the first/last and see if the ptr is in the middle.


Quote:
heap is also usually below the base address of the process, stack is usually above it ( > base address of the process + image size) .. at least on win2k or higher


That's not guaranteed though, is it? And happens about a DLL though, especially one with a shared segment... (I say "what happens" as a theoretical, I haven't done any investigation into it).


This problem is a bit stickier than it first looks Plus, get it wrong and delete something off the stack -

evlncrn8
April 20th, 2007, 05:52
maybe a virtualquery on the mem area / ptr might give some results?

as for the guaranteed thing, it seems consistant from 2k onwards, so
while its not exactly a 'rule of thumb', it could be worth investigating
to see if it fits your needs.. at least its something ... possibly

OHPen
April 20th, 2007, 06:50
@fuex: ok didnt know that, then i agree with maximus, best would be to walk through the ranges and test your pointer if it is insider a blocks range.
Shouldn't be a difficult problem i think

Regards, OHPen.

gera
May 19th, 2007, 15:23
I guess you have two options, and both start with using GetProcessHeaps() to list the existing heaps.

Then you can manually follow the heap structures, or use HeapWalk() to follow all the blocks in the heap until you find yours (or you are in a higher address).

Another options would be to set an exception handler and free the block on every heap, and see what side effects this may have. Or set a SEH and use HeapSize(). Or maybe even try to full HeapWalk() to start from your block and see if it can tell if the block is real or not.

In any case, I guess the most complete solution is to walk the heap and see if your block is in the list.

Now, depending on the application, you could also hook RtlAllocateHeap() and save all its answers, and then compare to see if your block was or wasn't answered by that function.

PS: If your program is a normal program, I don't really think you need to do all this, you should better put the responsibility of freeing the block in the function/code that knows where the block came from