Log in

View Full Version : A problem while using GetThreadContext


Hero
October 7th, 2006, 06:28
Hi all
I wrote a small code in my VS,but I saw an strange result.Here is my code:
Code:

int main(int argv,char* argc)
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory(&si,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.wShowWindow = SW_NORMAL;
CreateProcess("d:\\winnt\\system32\\calc.exe","",NULL,NULL,TRUE,CREATE_SUSPENDED,NULL,NULL,&si,&pi);
CONTEXT c;
c.ContextFlags = CONTEXT_FULL;
HANDLE h = OpenThread(THREAD_QUERY_INFORMATION | THREAD_GET_CONTEXT | THREAD_SET_CONTEXT, TRUE, pi.dwThreadId);
BOOL res = GetThreadContext(h,&c);
}

The code is simple,And I get TRUE for result of GetThreadContext,but when I checked the value of Eip in CONTEXT structure(c),I see that its value is starnge and equal to:
Eip = 0x7c4e87b3
What happen?Is there anything wrong with my code?What is the problem?

sincerely yours

blabberer
October 7th, 2006, 11:08
if i remember correctly i dont think you need all those openThread etc

you can simply call GetThreadContext(pi.hThread,&context)

and do myEip = context.regeip;

also keep in mind the address need not be what you expect it be (i mean if you are thinking it would be ox401000 or something similar i dont think that would be the case

it probably will be ntdll.DbgBreak address or may be ntdll!KiFastSystemCallRet

ntdll!NtSetInformationObject
ntdll!NtSetInformationProcess
ntdll!NtSetInformationThread
ntdll!NtSetInformationToken

somewhere in system not in userland

also i just noticed this in hlp files not sure if it applies to your code but just make sure

If you call GetThreadContext for the current thread, the function returns successfully; however, the context returned is not valid.

blabberer
October 7th, 2006, 13:45
ok i was right you dont need all those open thread things this code gets the eip and the eip like i stated is at

the eip after create process is 7c810867

Code:

7C810867 kernel32.BaseProcessStartThunk 33ED XOR EBP, EBP
7C810869 50 PUSH EAX
7C81086A 6A 00 PUSH 0
7C81086C E9 BB640000 JMP kernel32.BaseProcessStart



your code modified to work here

Code:

#include <windows.h>
#include <stdio.h>
#pragma argsused
int main(int argv,char* argc)
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
CONTEXT c;
ULONG myEip;
ZeroMemory(&si,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.wShowWindow = SW_NORMAL;
CreateProcess("C:\\Windows\\system32\\calc.exe","",NULL,NULL,TRUE,CREATE_SUSPENDED,NULL,NULL,&si,&pi);
GetThreadContext(pi.hThread,&c);
myEip = c.Eip;
printf("the eip after create process is %x",myEip);
//c.ContextFlags = CONTEXT_FULL;
//HANDLE h = OpenThread(THREAD_QUERY_INFORMATION | THREAD_GET_CONTEXT | THREAD_SET_CONTEXT, TRUE, pi.dwThreadId);
//BOOL res = GetThreadContext(h,&c);
}


anyway i did this long back in 9x and in 9x i was able to attach the suspended process with another ollydbg

and could resume the thread from ollydbg thread window (the eip in 9x was at return to kernelfunction ordinal number #8 bffsomewhere

but testing this now in xp-sp2 i see i cant attach to the suspended process
it is not even visible in ollydbgs attach window

in windbg f6 i see the suspended process as ERROR
and if i force attach it windbg says there is no thread or process blah blah blah and many of the debugger commands dont work

any one want to check i attached both the src and compiled exe if some one wants to shed some information on why the suspended process isnt visible in another ollydbg hexedit exe path to suit your calc.exes path in ollydbg

Hero
October 7th, 2006, 21:18
hi blabberer
thanks for checkup.
In the first I should say that I were tested that code without OpenThread,but becuase there was that strange result,I thought perhaps this process has not enough privilege to get and set context,then I used OpenThread.
I tested this code in windows 2000,and it connects to suspended process as well,but it seems that you got another strange result in win Xp-SP2.I think I should find a way for dolving this before continuing my code.
bu in addition of this problem,here is another question:
If I want to change Debug registers using SetTheadContext and for example for a program that makes 5 threads using CreateThread,I should change these registers for each thread at creation of it?Or it is enough to do this only in program main thread?

Edit:
Is there anybody who can make a small change in this code for testing SetThreadContext?
I mean a small change that sets a breakpoint on execution on entry point of suspended process,that cause a break after resuming it using ResumeThread.

sincerely yours

autarky
October 9th, 2006, 03:52
Threads created by the CreateProcess and CreateThread APIs do not actually start at the entry point you specify. These APIs pass the entry point as a parameter to an actual thread that is created that starts iside kernel32.dll. This thread then wraps a frame based exception handler around the process/thread, and then calls the thread/process entry point. If you return from a process or thread, you will return back into this primordial code, and see an ExitThread or ExitProcess.

If you want to know more, look at CreateProcessInternalW (and I mean literally take a look at it, you can backtrack the original entry point to the thread creation code), or check out Windows internals (or something similar).

blabberer
October 9th, 2006, 14:27
Quote:
[Originally Posted by Hero]Edit:
Is there anybody who can make a small change in this code for testing SetThreadContext?
I mean a small change that sets a breakpoint on execution on entry point of suspended process,that cause a break after resuming it using ResumeThread.

sincerely yours


i dont understand why you want to change the eip with SetThreadContext
the process has not been fully initialised when it has stopped on CreateSuspended
the seh prolog hasnt been initialised the NtSetThreadInformation hasnt been called yet ZwTestAlert that notifies system hasnt been called yet
all of them are pending and if you change eip with SetThreadContext you should have contingency measures to emulate or detour to all of them

the process is still in ghost state when it is in initial suspended state

well you can do change with SetthreadContext but you should be prepared to deal with all this things yet

if you aim is just to break on Eip (do you have a hardcoded eip ?? that you can pass ?? how do you propose to break ? use any just in time debugger ???

if answers to all my questions above is yes

you can use the code below it simply writes to process memory an int3 on eip

eip is hardcoded in the program for calc.exe of my machine (yours may be different

for w2k i used vpc to catch the int3 (kernel debugger gets invoked before AeDebug Debugger)
Code:

kd> g
Break instruction exception - code 80000003 (first chance)
01012420 cc int 3
kd> !process -1 0
PROCESS ffaa7d60 SessionId: 0 Cid: 037c Peb: 7ffdf000 ParentCid: 0390
DirBase: 026b0000 ObjectTable: ffabff48 TableSize: 20.
Image: calc.exe

kd> g


for xp i used ollydbg (you need to tell ollydbg to attach without confirmation
in options ->debugging options -> justin time debugging)
else wer (windows error reporting)will attach before ollydbg and show you the infamous do you want to send bs to ms


now if you dont have hardcoded eip you should be prepared to parse the
process headers to find the Address of Entry Point in pe header
and then set a 0xcc on the entry point.


as to several threads are all of them created suspended ? if not you have to suspend them all and then GetThreadContext , SetThreadContext
might be too late the bombs would have left thier pods before you hit Suspend

also i dont know (havent tried yet if just in time debugger will catch the hardware bps the you set with SetThreadContext if you try and find jit catches hardware bps then do post back (yeah ill test it some time but if i get info before i test that would be good )

anyway here is the modified code

Code:

#include <windows.h>
#include <stdio.h>
#pragma argsused
int main(int argv,char* argc)
{
char buffer[200] = {0};
PROCESS_INFORMATION pi = {0};
STARTUPINFO si = {0};
CONTEXT c = {0};
ULONG myEip;
LPVOID base;
char wrbuff[20] = {0xcc};
char wxppath[] = {"c:\\windows\\system32\\calc.exe"};
char w2kpath[] = {"c:\\winnt\\system32\\calc.exe"};
int wxpeip = 0x1012475;
int w2keip = 0x1012420;
int result;
char path[MAX_PATH];
int eip;


result = MessageBox(NULL,"CHOOSE YES IF OS == WINXP or NO if OS == W2k","os chooser",MB_YESNO | MB_ICONQUESTION);
if(result == IDYES)
{
strncpy(path,wxppath,MAX_PATH-1);
eip = wxpeip;
}
else if(result == IDNO)
{
strncpy(path,w2kpath,MAX_PATH-1);
eip = w2keip;
}

c.ContextFlags = CONTEXT_FULL;
si.cb = sizeof(STARTUPINFO);
si.wShowWindow = SW_NORMAL;
CreateProcess(path,NULL,NULL,NULL,TRUE,CREATE_SUSPENDED,NULL,NULL,&si,&pi);
GetThreadContext(pi.hThread,&c);
myEip = c.Eip;
sprintf(buffer,"the eip after create process is %x",myEip);
MessageBox(0,buffer,"the eip register",0);
(int)base = eip;
WriteProcessMemory(pi.hProcess,base,&wrbuff,1,NULL);
ResumeThread(pi.hThread);
}


the above code works on both xp and w2k
before you double click them you need to set the jit debugger
and if it still didnt work you have to debug them and change the hardcoded eip to make it work

Hero
October 10th, 2006, 00:51
hi blabberer
Thanks for code,but main reason of this question was How I can use Hardware breakpoint and eip were only a good sample for testing that Hardware breakpoint.
I now write a plugin for VS to add Harware breakpoint support to it,but it seems that the address that you should place in Debug registers is somehow deferent from normal addressing.
Then I asked that question to learn how I should translate the address that I want to set a breakpoint to the address that I should place in Debug registers.
The entry point was only a sample for placing breakpoint on execution.

sincerely yours

blabberer
October 10th, 2006, 05:50
vs plugin i dont know vs but it seems there already exists what you are trying to do a c class that lets you set hardware bps on the fly in vc whatever

check out

http://www.morearty.com/code/breakpoint/

if you yourself want to add a hardware break point on Execution
all you have to do in mycode above is
Code:

c.Context_Flags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS
GetThreadContext(pi.hThread,&c);
c.Dr0 = "YOUR ADDRESS OF EIP"
SetThreadContext(pi.Hthread,&c)
ResumeTHread(pi.hThread);


Execution break point is defined as 0 and for Execution breakpoint len = 0
so you dont have to touch Dr7 if you want to set Execution hardware breakpoints

if you want to do HardwareBreakpoints on read and write just check out the link i posted above it explains the naunces pretty neat


ok ill edit this as there is no answer yet
setting a hardware break from remote process doesnt result in debugger getting notified and as such no jit break

as to the eip that you get in the initial process suspended state
all the memory places including the GetThreadContext () show as MEM_FREE if i do a virtualquery
the allocation base , allocation protect and Type all return undefined
so that would explain the cant attach problem
if i force attach the dlls relocate and crash coz the memory is
already eaten up by the yet to beinitialised ghost process

Code:

0012F740 |hProcess = 00000050 (window)
0012F744 |Address = kernel32.7C810867
0012F748 |Buffer = 0012F75C
0012F74C \BufSize = 1C (28.)

before
0012F75C 00000000 00000000 00000000 00000000
0012F76C 00000000 00000000 00000000

after

0012F75C 7C810000 00000000 00000000 000F0000
0012F76C 00010000 00000001 00000000


so you cant change the protection status and write an 0xcc also to initial eip pointed by GetThreadContext()

i spalshed the code to printf the results
and the eip after Resuspension is kiFastSystemCallRet and thats fine

>w2khero.exe
you chose winxp as your os
the eip after create process is 7c810867
the Dr0 after resuspending is 1012475
the eip after resuspending process is 7c90eb94

>

in w2k
C:\DOCUME~1\ADMINI~1\Desktop>w2khero
you chose w2k as your os
the eip after create process is 7c4e87b3
the Dr0 after resuspending is 1012420
the eip after resuspending process is 77e12f5c

and 77e12f5c in w2k is return from ntuserGetmessage and thats fine too
77E12F51 _NtUserGetMes> B8 9A110000 MOV EAX,119A
77E12F56 8D5424 04 LEA EDX,DWORD PTR SS:[ESP+4]
77E12F5A CD 2E INT 2E
77E12F5C C2 1000 RETN 10 <---------

Call stack of main thread, item 0
Address=0006FDEC
Stack=77E12F86
Procedure / arguments=USER32._NtUserGetMessage@16
Called from=USER32.77E12F81
Frame=0006FE04




C:\DOCUME~1\ADMINI~1\Desktop>


the final code is as below put here for referance if anyone chooses to see

Code:

#include <windows.h>
#include <stdio.h>
#pragma argsused
int main(int argv,char* argc)
{
char buffer[200] = {0};
PROCESS_INFORMATION pi = {0};
STARTUPINFO si = {0};
CONTEXT c = {0};
CONTEXT cnew = {0};
ULONG myEip;
ULONG myDr0;
LPVOID base;
char wrbuff[20] = {0xcc};
char wxppath[] = {"c:\\windows\\system32\\calc.exe"};
char w2kpath[] = {"c:\\winnt\\system32\\calc.exe"};
int wxpeip = 0x1012475;
int w2keip = 0x1012420;
int result;
char path[MAX_PATH] = {0};
int eip;
void *status;
MEMORY_BASIC_INFORMATION mbi = {0};
DWORD lpOld;


result = MessageBox(NULL,"CHOOSE YES IF OS == WINXP or NO if OS == W2k","os chooser",MB_YESNO | MB_ICONQUESTION);
if(result == IDYES)
{
strncpy(path,wxppath,MAX_PATH-1);
eip = wxpeip;
printf("you chose winxp as your os\n";
}
else if(result == IDNO)
{
strncpy(path,w2kpath,MAX_PATH-1);
eip = w2keip;
printf("you chose w2k as your os\n";
}

c.ContextFlags = CONTEXT_FULL|CONTEXT_DEBUG_REGISTERS;
si.cb = sizeof(STARTUPINFO);
si.wShowWindow = SW_NORMAL;
CreateProcess(path,NULL,NULL,NULL,TRUE,CREATE_SUSPENDED,NULL,NULL,&si,&pi);
GetThreadContext(pi.hThread,&c);
myEip = c.Eip;
sprintf(buffer,"the eip after create process is %x",myEip);
printf(buffer);
printf("\n";
MessageBox(0,buffer,"the eip register",0);
(int)base = myEip;
c.Dr0 = eip;
SetThreadContext(pi.hThread,&c);
VirtualQueryEx(pi.hProcess,(LPCVOID)myEip,&mbi,sizeof(mbi));
VirtualProtectEx(pi.hProcess,mbi.BaseAddress,mbi.RegionSize,PAGE_EXECUTE_READWRITE,&lpOld);
WriteProcessMemory(pi.hProcess,base,&wrbuff,1,NULL);
VirtualProtectEx(pi.hProcess,mbi.BaseAddress,mbi.RegionSize,lpOld,&lpOld);
ResumeThread(pi.hThread);
Sleep(5000);
SuspendThread(pi.hThread);
cnew.ContextFlags = CONTEXT_FULL|CONTEXT_DEBUG_REGISTERS;
GetThreadContext(pi.hThread,&cnew);
myDr0 = cnew.Dr0;
myEip = cnew.Eip;
sprintf(buffer,"the Dr0 after resuspending is %x",myDr0);
MessageBox(0,buffer,"the eip register",0);

printf(buffer);
printf("\n";

sprintf(buffer,"the eip after resuspending process is %x",myEip);
MessageBox(0,buffer,"the eip register",0);
printf(buffer);
printf("\n";
ResumeThread(pi.hThread);
}

upb
October 18th, 2006, 17:15
Quote:
[Originally Posted by blabberer]
If you call GetThreadContext for the current thread, the function returns successfully; however, the context returned is not valid.


this really refers to the calling thread, which he's not trying to do.