Stack overwrite when calling GetThreadContext in 64bit application

G

George Hicken

I'm seeing a stack overwrite when I call GetThreadContext in a 64bit
application XP/Server 2003 systems with SP2.

Is this a known problem, does anyone know a workaround?

Test case follows:
#include <windows.h>
#include <stdio.h>
#include <process.h>
#include <tlhelp32.h>
#include <Psapi.h>
#include <DbgHelp.h>


unsigned __stdcall SecondThreadFunc( void* pArguments )
{
HANDLE handle = *(HANDLE*)pArguments;

printf( "In second thread...\n" );


WaitForSingleObject( handle, INFINITE );


_endthreadex( 0 );
return 0;
}


int main()
{
HANDLE hThread, currentThread, thread_handle;
unsigned threadID;
char buffer[600];
CONTEXT tmpContext;
STACKFRAME64 stackFrame = {0};
int frameNumber = 0;
int rc = 1;
int i = 0;
BOOLEAN damaged = FALSE;

currentThread = GetCurrentThread();

printf( "Creating second thread...\n" );

printf( "&buffer=%p - %p, &tmpContext=%p - %p\n", buffer, buffer +
sizeof(buffer), &tmpContext, (char*)&tmpContext + sizeof(tmpContext));
// Create the second thread.
hThread = (HANDLE)_beginthreadex( NULL, 0, &SecondThreadFunc,
&currentThread, 0, &threadID );

if (hThread == (HANDLE)-1L) {
printf ("error creating thread\n");
goto cleanup;
}

Sleep(1000);

if (SuspendThread(hThread) == -1) {
printf ("error suspending thread\n");
goto cleanup;
}

thread_handle = OpenThread(THREAD_GET_CONTEXT|THREAD_QUERY_INFORMATION,
FALSE, GetThreadId(hThread));
tmpContext.ContextFlags = CONTEXT_FULL;

memset(buffer, 0xFF, sizeof(buffer));


for (i = 0; i < sizeof(buffer); i++) {
if (buffer != (char)0xFF) {
printf ("sanity failed at buffer[%i], = %i\n", i, buffer);
goto cleanup;
}
}

if (GetThreadContext(thread_handle , &tmpContext) == FALSE) {
printf ("error getting context, %i\n", GetLastError());
goto cleanup;
}


for (i = sizeof(buffer) - 1; i >= 0; i--) {
if (buffer != (char)0xFF) {
printf ("overflowed %i bytes of buffer, total overflow is %i
bytes\n", i+1, (size_t)&buffer - (size_t)&tmpContext - sizeof(tmpContext));
goto cleanup;
}
}



/* initialize the stackframe */
stackFrame.AddrPC.Mode = AddrModeFlat;
stackFrame.AddrStack.Mode = AddrModeFlat;
stackFrame.AddrFrame.Mode = AddrModeFlat;

stackFrame.AddrPC.Offset = tmpContext.Rip;
stackFrame.AddrStack.Offset = tmpContext.Rsp;
stackFrame.AddrFrame.Offset = tmpContext.Rbp;


/* now walk the stack and maintain a count of the frames */
for (frameNumber = 0; rc != FALSE; frameNumber++) {
DWORD64 disp64;
BYTE buffer[256];
PSYMBOL_INFO symbol_info = (PSYMBOL_INFO)buffer;
memset(symbol_info, 0, sizeof(buffer));
symbol_info->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);

rc = StackWalk64(
IMAGE_FILE_MACHINE_AMD64,
GetCurrentProcess(),
thread_handle,
&stackFrame,
&tmpContext,
NULL,
SymFunctionTableAccess64,
SymGetModuleBase64,
NULL );

if (rc == 0) {
printf ("stack walk failed\n");
break;
}

if (SymFromAddr(GetCurrentProcess(), tmpContext.Rip, &disp64,
symbol_info) == FALSE) {
printf("failed to get symbol for %p\n", tmpContext.Rip);
} else {
printf("%s\n", symbol_info->Name);
}

printf ("got frame %i\n", frameNumber);
}

cleanup:
// Destroy the thread object.
ResumeThread( hThread );
CloseHandle( hThread );
CloseHandle(thread_handle);
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top