Author: GuyHoozdis
Subject: Thread Start Address and Call Stack
Posted: 15 June 2013 at 5:03pm
Remember: You want to install Debugging Tools for Windows and then configure Process Explorer/Monitor (or any debugging tools) to use Microsoft's symbol server so that the stack traces are not gibberish.
I think that you will see the "module+offset" form when it is the main executable (e.g. iTunesHelper.exe+0x17C0 or SomeThirdPartyApp.exe+0x1390) of an application that you do not have the debugging symbols for. In contrast, take a look at notepad after you are configured to use MS symbols. You should see notepad.exe!WinMainCRTStartup as the thread's start address.
If you have ever written a C/C++ program it is important to note that WinMainCRTStartup is not the same as the main entry point you defined, typically WinMain for applications based on the Windows API and simply main for applications based on the Standard Library. when you wrote your application. WinMainCRTStartup is some boilerplate code that your compiler adds in for you to setup the runtime environment and invokes the main thread for your application.
Part of your confusion might be due to the complex nature of the application you are looking at for an example. Notepad is a much simpler example to start with and the same ideas still apply when you consider more complex applications.
Below is a stack trace for the single thread that is created when notepad.exe is executed. I have symbols installed, but for all intents and purposes this is the same as the stack trace that you provided in your post.
From our thread, which started at offset WinMainCRTStartup, we see the stack trace below citing the OS's ring-0 and ring-3 (kernel and userland respectively) code that gets called/executed every time a process/thread is started. Moreover, you can see that the newly created thread calls into WinMain where, if this were an application that you wrote, the code you actually wrote would begin.
[code]
ntoskrnl.exe!KiSwapContext+0x7a
ntoskrnl.exe!KiCommitThreadWait+0x1d2
ntoskrnl.exe!KeWaitForSingleObject+0x19f
win32k.sys!memset+0x7a47
win32k.sys!memset+0x7ae9
win32k.sys!memset+0x6138
win32k.sys!memset+0x623d
win32k.sys!memset+0x7c11
ntoskrnl.exe!KiSystemServiceCopyEnd+0x13
USER32.dll!NtUserGetMessage+0xa
USER32.dll!GetMessageW+0x34
notepad.exe!WinMain+0x182
kernel32.dll!BaseThreadInitThunk+0xd
ntdll.dll!RtlUserThreadStart+0x1d
[/code\
The offsets that you see here, take WinMain+0x182 as an example, are the points where another call instruction (that's an assembly language instruction) was executed. Here we see that WinMain called into GetMessageW which called into .... it goes on and on.
One final point concerning modules, function names, offsets, and why you should be using symbols if possible. Consider the example you started off with; chrome.exe!SetPrinterInfo+0x62D0. You should be interpreting that as "SetPrinterInfo is the closest human-friendly symbol that I can give you and the instruction pointer, right now, is 25,296 bytes past that symbol". If you had symbols for chrome you would find that you are inside an entirely different function and that the SetPrinterInfo function is no where near 25,296 bytes long- there are several functions defined between there and here.
I hope that all makes sense.
There is no substitute for tracing through some simple code with a debugger. I highly recommend doing that- it is very insightful.
Good luck!
Subject: Thread Start Address and Call Stack
Posted: 15 June 2013 at 5:03pm
Remember: You want to install Debugging Tools for Windows and then configure Process Explorer/Monitor (or any debugging tools) to use Microsoft's symbol server so that the stack traces are not gibberish.
![]() |
I think that you will see the "module+offset" form when it is the main executable (e.g. iTunesHelper.exe+0x17C0 or SomeThirdPartyApp.exe+0x1390) of an application that you do not have the debugging symbols for. In contrast, take a look at notepad after you are configured to use MS symbols. You should see notepad.exe!WinMainCRTStartup as the thread's start address.
If you have ever written a C/C++ program it is important to note that WinMainCRTStartup is not the same as the main entry point you defined, typically WinMain for applications based on the Windows API and simply main for applications based on the Standard Library. when you wrote your application. WinMainCRTStartup is some boilerplate code that your compiler adds in for you to setup the runtime environment and invokes the main thread for your application.
![]() |
Part of your confusion might be due to the complex nature of the application you are looking at for an example. Notepad is a much simpler example to start with and the same ideas still apply when you consider more complex applications.
Below is a stack trace for the single thread that is created when notepad.exe is executed. I have symbols installed, but for all intents and purposes this is the same as the stack trace that you provided in your post.
From our thread, which started at offset WinMainCRTStartup, we see the stack trace below citing the OS's ring-0 and ring-3 (kernel and userland respectively) code that gets called/executed every time a process/thread is started. Moreover, you can see that the newly created thread calls into WinMain where, if this were an application that you wrote, the code you actually wrote would begin.
[code]
ntoskrnl.exe!KiSwapContext+0x7a
ntoskrnl.exe!KiCommitThreadWait+0x1d2
ntoskrnl.exe!KeWaitForSingleObject+0x19f
win32k.sys!memset+0x7a47
win32k.sys!memset+0x7ae9
win32k.sys!memset+0x6138
win32k.sys!memset+0x623d
win32k.sys!memset+0x7c11
ntoskrnl.exe!KiSystemServiceCopyEnd+0x13
USER32.dll!NtUserGetMessage+0xa
USER32.dll!GetMessageW+0x34
notepad.exe!WinMain+0x182
kernel32.dll!BaseThreadInitThunk+0xd
ntdll.dll!RtlUserThreadStart+0x1d
[/code\
The offsets that you see here, take WinMain+0x182 as an example, are the points where another call instruction (that's an assembly language instruction) was executed. Here we see that WinMain called into GetMessageW which called into .... it goes on and on.
One final point concerning modules, function names, offsets, and why you should be using symbols if possible. Consider the example you started off with; chrome.exe!SetPrinterInfo+0x62D0. You should be interpreting that as "SetPrinterInfo is the closest human-friendly symbol that I can give you and the instruction pointer, right now, is 25,296 bytes past that symbol". If you had symbols for chrome you would find that you are inside an entirely different function and that the SetPrinterInfo function is no where near 25,296 bytes long- there are several functions defined between there and here.
I hope that all makes sense.
There is no substitute for tracing through some simple code with a debugger. I highly recommend doing that- it is very insightful.
Good luck!