views:

57

answers:

2

I've inherited some code that worked on Windows 2000 thats using a small piece of assembly code to locate the base address of the stack, then it uses an offset to grab the parameter value passed to the thread start function.

However this doesnt work in Windows 2008 Server. The offset is obviously different.

#define TEB_OFFSET 4
    DWORD * pStackBase;
    __asm { mov eax,fs:[TEB_OFFSET]}
    __asm { mov pStackBase,eax}

    // Read the parameter off the stack
#define PARAM_0_OF_BASE_THEAD_START_OFFSET -3
    g_dwCtrlRoutineAddr = pStackBase[PARAM_0_OF_BASE_THEAD_START_OFFSET];

After experimenting, I modified the code to look up the stack till it finds the first non-NULL value. hack

DWORD* pStack = pStackBase;
do
{
    pStack--;
}
while (*pStack == NULL);

// Read the parameter off the stack
g_dwCtrlRoutineAddr = *pStack; 

Its works! But I want a 'correct' solution.

Does anyone know a safer/better solution for getting the parameter passed to the starting function of a thread on Windows 2008 Server?

The thread start function is ntdll!_RtlUserThreadStart

And the first parameter I'm trying to locate is the address of the function kernel32!CtrlRoutine

A: 

To get address of kernel32!CtrlRoutine you can get it by RVA, using a table with all (kernel32 version, CtrlRoutine RVA) pairs. It's the most reliable way.

Abyx
+1  A: 

Bizarre. Looking with the debugger, the first non-null value on the thread's stack is the value of the argument, the 4th argument to CreateThread. Which gets handed to you on a silver platter when you write the thread procedure like this:

DWORD WINAPI threadProc(void* arg) {
    // arg is the value you are looking for
    // etc..
}

Not sure how that's related to "kernel32!CtrlRoutine" unless this is a thread used in a service.

Hans Passant