How to view c# variables using windbg - debugging

I have a C# windows service installed on a 32 bit windows server 2003 machine that I wish to debug.
The problem I have is that a log file error message tells me the following:
System.NullReferenceException: Object reference not set to an instance of an object.
at VideoProcessor.ResetCameraProperties(DataServiceObject dso)
at VideoProcessor.AddServer(DataServiceObject dso)
at VideoProcessor.LoadServers()
at VideoProcessor.Start()
atVideoServerComponent.Connect()
The actual code for the function ResetCameraProperties is:
protected void ResetCameraProperties(DataServiceObject dso)
{
// Find the CameraType.
//Type videoCameraType = TypeManager.Instance["XFire.Common.VideoObjects.VideoServer"];
if (_videoCameraType == null) return;
//Load cameras from the Data Service Layer
string whereClause = "ServerID = ?";
object[] args = new object[] { dso["ObjectID"] };
IDataServiceCollection videoCameraDsoCollection = ClientServerConnection.Instance.FindCollection(_videoCameraType, whereClause, args, null, CollectionOptions.FilterByPartitionResponsibility) as IDataServiceCollection;
if (videoCameraDsoCollection == null || 0 == videoCameraDsoCollection.Count)
return;
videoCameraDsoCollection.LoadContainerOnEnumeration = false;
foreach (DataServiceObject camera in videoCameraDsoCollection)
{
if (!(bool)dso[RecorderKey.Online] && (int)dso[RecorderKey.VideoServerAlarm] == (int)VideoServerComponent.GetVideoServerAlarm("Offline"))
{
// If the server is disconnected, then we know everything should be offline.
camera[CameraKey.VideoCameraAlarm] = VideoServerComponent.GetEnumValueOfType("XFire.Common.VideoObjectDefinitions.VideoCameraAlarm", "Unknown");
camera[CameraKey.Videoloss] = true;
}
else if ((bool)dso[RecorderKey.Online] && (int)dso[RecorderKey.VideoServerAlarm] == (int)VideoServerComponent.GetVideoServerAlarm("Online"))
{
camera[CameraKey.VideoCameraAlarm] = VideoServerComponent.GetEnumValueOfType("XFire.Common.VideoObjectDefinitions.VideoCameraAlarm", "Normal");
camera[CameraKey.Videoloss] = false;
}
// Save the camera.
ServerResult result = ClientServerConnection.Instance.PersistObject(camera, null);
if (result.Fault != null)
{
if (VideoTrace.TraceError) Trace.WriteLine(result.Fault.Message);
}
}
I have opened windbg and did File-->Attach to process
I have set breakpoints in the function above using the steps outlined here: https://learn.microsoft.com/en-us/archive/blogs/alejacma/managed-debugging-with-windbg-preparing-the-environment
When the breakpoint is hit I step forward using F10 but all I see is the following:
Setting breakpoint: bp 05A0A260 [VideoProcessor.*ResetCameraProperties (XFire.Common.DataServiceLayer.DataServiceObject)]
Adding pending breakpoints...
0:024> g
DriverWindowsService.OnStop Service stopping...
Breakpoint 0 hit
eax=00000001 ebx=00902870 ecx=00a1e020 edx=01066e78 esi=00affb48 edi=01066e78
eip=05a0a260 esp=0674e68c ebp=0674e6b0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
05a0a260 55 push ebp
0:024> p
eax=00000001 ebx=00902870 ecx=00a1e020 edx=01066e78 esi=00affb48 edi=01066e78
eip=05a0a261 esp=0674e688 ebp=0674e6b0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
05a0a261 8bec mov ebp,esp
0:024> p
eax=00000001 ebx=00902870 ecx=00a1e020 edx=01066e78 esi=00affb48 edi=01066e78
eip=05a0a263 esp=0674e688 ebp=0674e688 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
05a0a263 57 push edi
This means nothign to me at present (I'm a windbg newbie)
I have the pdb file for the windows service (I got from the Visual Studio Debug Output folder) and have copied itto my target machine in a folder C:\Symbols.
In winDbg I did File-->Symbol FIle path and set it to the location of this pdb file I copied over. My symbol path is as follows:
C:\symcache;C:\Symbols;srvc:\symcachehttp://msdl.microsoft.com/download/symbols
In Windbg I did View-->Watch and I typed in the name of a variable that is inside the function above (videoCameraType). But I got the following error:
*** Either you specified an unqualified symbol, or your debugger ***
*** doesn't have full symbol information. Unqualified symbol ***
*** resolution is turned off by default. Please either specify a ***
*** fully qualified symbol module!symbolname, or enable resolution ***
*** of unqualified symbols by typing ".symopt- 100". Note that ***
*** enabling unqualified symbol resolution with network symbol ***
*** server shares in the symbol path may cause the debugger to ***
*** appear to hang for long periods of time when an incorrect ***
*** symbol name is typed or the network symbol server is down. ***
*** For some commands to work properly, your symbol path ***
*** must point to .pdb files that have full type information. ***
*** Certain .pdb files (such as the public OS symbols) do not ***
*** contain the required information. Contact the group that ***
*** provided you with these symbols if you need this command to ***
*** work. ***
*** Type referenced: _videoCameraType ***
How can I view variables and generally see what is going on in my code????
I also have the source code for the windows service if thats any help.
Thanks

First thing is that your symbol files are probably not matching binaries as there is no source file paths and line numbers in your exception stack trace. You mentioned that you copied them from the Visual Studio Debug Output, so I assume that you have binaries compiled in Release (with no symbols) and pdb files from Debug. This won't work. What you need to do is change the project settings for your service, recompile and deploy it (you should now have pdb, dll and exe files in the release output folder). This should generate a much more meaningful stack trace for your exception.
Now, the second part. You need to distinguish a managed environment from the native one. In windbg you are debugging the CLR as it is seen by the operating system, thus you are debugging not only your C# application but the CLR interpreter that compiles your ILASM (compiled C# code) to native CPU instructions and then executes them. So you are a layer below what you normally see in VS (with managed debugger attached). Keeping that in mind you need to either dig into CLR internals and try to figure out what the addresses in registers mean or use some sort of translator which will do this heavy work for you. And this is where SOS comes into play. You've already used it when you set the breakpoint. As you are only interested in knowing a value of your variable you need to first find out at what address the CLR lied it out for you. From what I see the _videoCameraType is a private class member, isn't it? If so you may dump managed objects from the stack using !dso command. You should see something similar to the output below:
> !dso
OS Thread Id: 0xad8 (0)
RSP/REG Object Name
000000000068E8F0 00000000025f2bc8 Program+Test
000000000068E8F8 00000000025f2be0 System.String test
000000000068E910 00000000025f2bc8 Program+Test
000000000068E918 00000000025f2bc8 Program+Test
where Program+Test would be replaced by your class name. Then you may dump the object content using !do command and the address from the Object column:
> !do 00000000025f2bc8
Name: Program+Test
MethodTable: 000007fe58333a08
EEClass: 000007fe584422b8
Size: 24(0x18) bytes
File: D:\temp\Test.exe
Fields:
MT Field Offset Type VT Attr Value Name
000007feb4dcb318 4000001 8 System.String 0 instance 00000000025f2be0 _testVariable
Find the class member by its name and use !do command once again but using address from the Value column (this works for reference types). In our example it would be:
0:000> !do 00000000025f2be0
Name: System.String
MethodTable: 000007feb4dcb318
EEClass: 000007feb4733720
Size: 34(0x22) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String: test
Fields:
MT Field Offset Type VT Attr Value Name
000007feb4dce0c8 40000aa 8 System.Int32 1 instance 4 m_stringLength
000007feb4dcc600 40000ab c System.Char 1 instance 74 m_firstChar
000007feb4dcb318 40000ac 18 System.String 0 shared static Empty
>> Domain:Value 000000000074f960:NotInit <<
Things get trickier if you need to figure out what a value of a local variable is. You may try with !CLRStack -a which usually does not show much in release builds. You are then left with analysis of the generated assembly (!U #rip) in order to find out where the address of your variables landed (registry, stack). After figuring this out, issue again the !do command with the address you've found. Happy debugging :)

Adding to this thread since it shows up in Google searches:
The following worked for me:
(If application uses .net 4 use .loadby sos clr to load the SOS debugger extension)
Once you are on the right thread first use !clrstack -p to dump the stack along with the addresses of the local variables.
Now use the address of the local variable of interest to dump it using !do .
Then using the addresses from the output that you get - you can use !do again (use the Value field here for the address of a specific member). You can continue till you are able to see the value you desire.
(You can also use this approach to dump members of the "this" pointer which you obtain from the stack. This may have some variables of interest based on what you are looking for)
See http://blogs.msdn.com/b/alejacma/archive/2009/08/11/managed-debugging-with-windbg-thread-stacks-part-1.aspx
Debugging is exciting! Have fun with it!

Related

Pending breakpoint in windbg

Remote debugging is not possible & need to debug my code for an issue not reproducible on my system.
I can set a pending breakpoint in gdb on linux. I need something similar on windbg or on windows platform as I cannot share the source file but I need to break in the file at particular line in order to debug.
what do you mean by pending breakpoint ?
does the module in which the function resides loaded dynamically and you need to set a breakpoint beforehand ?
if yes then use bu breakpoints
bu myfoomodule!myblahfunction
this will load the symbols when the module is loaded and set a breakpoint as and when needed
0:000> lm m help*
Browse full module list
start end module name
<<<<<<<<<<<< no results here
lets confirm by forcefully realoding symbols and checking for the existence of
this module
0:000> .reload /f
Reloading current modules
0:000> lm m help*
Browse full module list
start end module name
again no results we cant set a regular breakpoint
our breakpoint needs to be set using unresolved breakpoint
lets set it
0:000> bu HelpPaneProxy!DllMain
let us check
0:000> bl
0 e Disable Clear u 0001 (0001) (HelpPaneProxy!DllMain)
lets continue
0:000> g
ModLoad: 77ac0000 77adf000 C:\Windows\system32\IMM32.DLL
ModLoad: 76f90000 7705c000 C:\Windows\system32\MSCTF.dll
un needed mod load display cut off XXXXXXXXXXXXXXXXXXXX
ModLoad: 67d80000 67d91000 C:\Windows\System32\HelpPaneProxy.dll
bingo our breakpoint hit on the module load triggered after clicking help in calc
Breakpoint 0 hit
eax=00000001 ebx=00000001 ecx=00000001 edx=00000000 esi=00000000 edi=0025cfa8
eip=67d84700 esp=0025ce7c ebp=0025ced8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
HelpPaneProxy!DllMain:
67d84700 8bff mov edi,edi

Unable to get full user-mode stacktrace while kernel debugging in windbg

I have a virtual Windows 7 x64 machine on a Windows 10 host, and I kernel debug it with windbg 10.0.10586.567. I'm running my own application on it, which I have full source and private symbols for. Whenever I break in and ask for stack traces of the app's threads, the backtrace always stops when one of my application's binaries are "hit."
So for instance, if I break in, switch to the process, and request a stacktrace with !thread [thread address] 1f, I get something like this (note the "early" zero return address at the last line):
fffff880`0534e870 fffff800`026d6992 nt!KiSwapContext+0x7a
fffff880`0534e9b0 fffff800`026d81a2 nt!KiCommitThreadWait+0x1d2
fffff880`0534ea40 fffff800`029c7a2e nt!KeDelayExecutionThread+0x186
fffff880`0534eab0 fffff800`026d08d3 nt!NtDelayExecution+0x59
fffff880`0534eae0 00000000`76e7165a nt!KiSystemServiceCopyEnd+0x13 (TrapFrame # fffff880`0534eae0)
00000000`00276708 000007fe`fcf91203 ntdll!NtDelayExecution+0xa
00000000`00276710 00000001`410e7dd9 KERNELBASE!SleepEx+0xab
00000000`002767b0 00000000`00000000 MyApp!MainMessageLoop+0x4b1 [d:\whatever\path\myapplication.cpp # 3024]
This looks very similar to when you you are missing a binary while debugging a user-mode dump (lack of unwind data) of an x64 process, except in that case the stack trace usually does not stop "this sudden", rather it goes astray at that point, and shows bogus values.
Some extra info/things I tried:
I have the correct symbol paths set up (both the Microsoft symbol server, and a local folder on the host with matching PDBs, even though the latter is not needed for just the stack trace)
I have a binary path set up (.exepath) containing matching binaries on the host (I've made absolutely sure of this; copied the binaries directly from the guest to the host machine)
If I put a breakpoint in one of the app's exported DLL functions, then when the debugger breaks in, I get a one-liner stack trace like this: 0000000000274b40 0000000000000000 MyAppDLL!SomeExportedFunction+0x32 [d:\whatever\path\myapplicationDLL.cpp # 232]
I've tried virtually every combination of commands to get a stacktrace (.process /i, .process /r /p, !process -1 7, .reloads, .reload /users, .reload /f MyApp.exe, !thread [address] 1f, etc.) with no success
Tried with an older version of windbg (6.11.0001.404) as well, same result
Also tried on Windows 8.1 as a guest with the very same binaries, same result
!sym noisy output (irrelevant lines omitted):
0: kd>.process /i [address]
0: kd>g
0: kd>.reload /user
0: kd> !process -1 2
0: kd> !thread [address] 1f
[...]
DBGHELP: d:\symbolcache\MyApp.pdb\76931C5A6C284779AD2F916CA324617E1\MyApp.pdb already cached
DBGHELP: MyApp - private symbols & lines
[...]
lmvm MyApp output:
[...]
Loaded symbol image file: MyApp.exe
Image path: C:\MyApp\MyApp.exe
[...]
Any ideas?
I accidentally stumbled into a linker switch that solves this problem: /DEBUGTYPE with the PDATA argument. If you link your binaries with this switch, unwind information will be copied into your PDBs.
I recompiled/relinked the application in question with /DEBUGTYPE:CV,PDATA (/DEBUGTYPE:CV is the default if /DEBUG is specified, see the documentation), now everything works like a charm, I always get full call stacks.
One strange aspect of this: windbg happily uses unwind data found in the PDBs, but ignores the very same data in the mapped binaries (both on the host machine).
This is not a perfect solution to the problem (or any solution at all, one might say), but I'm providing this provisional answer with a workaround.
You should be able to get the information you want, albeit not so well-formatted using something like dps #rsp L10.
In x86-64 you don't have a parallel of the x86 ebp-chain, but the return addresses are still on the stack. Those will give you the functions in the stack, and the values between them will be the arguments passed to the functions (and saved registers on the stack, etc.). A random example from Google (as I'm not on my Windows machine right now):
0:017> dps #rsp
00000000`1bb0fbb8 00000000`00000020
00000000`1bb0fbc0 00000000`00000000
00000000`1bb0fbc8 00000000`008bc6c6 Dolphin!ReadDataFromFifoOnCPU+0xb6 [d:\sources\comex\source\core\videocommon\fifo.cpp # 245]
00000000`1bb0fbd0 00000000`1ba0ffeb
00000000`1bb0fbd8 00000000`00000020
00000000`1bb0fbe0 00000000`00000020
00000000`1bb0fbe8 00000000`00000800
00000000`1bb0fbf0 00000000`1ba0ffeb
00000000`1bb0fbf8 00000000`008c2ff5 Dolphin!InterpretDisplayListPreprocess+0x45 [d:\sources\comex\source\core\videocommon\opcodedecoding.cpp # 87]
00000000`1bb0fc00 00000000`00000000
00000000`1bb0fc08 00000000`008bc041 Dolphin!RunGpu+0x81 [d:\sources\comex\source\core\videocommon\fifo.cpp # 389]
00000000`1bb0fc10 00000000`8064cbc0
00000000`1bb0fc18 00000000`1bb0fcc0
00000000`1bb0fc20 00000000`00000000
00000000`1bb0fc28 00000000`008c2dda Dolphin!OpcodeDecoder_Preprocess+0x14a [d:\sources\comex\source\core\videocommon\opcodedecoding.cpp # 326]
00000000`1bb0fc30 00000000`8064cbe0
Given that you have symbols, the return addresses are easily distinguishable.
The unwind data is lazy loaded for user mode modules, so it's not going to be mapped unless someone needs it. Unfortunately the kernel debugger doesn't force the information to be present for user images, so sometimes you get this behavior. You can see if the data is mapped or not by dumping the PE header (!dh) and checking the state of the Exception Directory (!pte imagename+offset).
Given that you own the app, try forcing the information to be resident by doing a stack walk NOP somewhere in your app:
PVOID stack[2];
(VOID)CaptureStackBackTrace(0, 2, (PVOID*)&stack, NULL);
That doesn't guarantee the entire directory will be present, but usually good enough.

How to break on the entry point of a program when debug in kernel mode with windbg?

I want to debug a program in kernel mode, and I want to break on the entry point of the program like ollydbg. But I can't break it with bp because the program is not start and the symbol can't be loaded. I have found some way to do it but I think it's not so good.
1.Break on the CreateProcess function in kernel. But I don't know which function exactly should I break and I think there is a long way between CreateProcess and the entry point of the program.
2.Change the entry point of the program with cc. But it needs other tools and I should change the code where the byte changed back. I think it is annoying.
3.With the help of ollydbg. Debugging the program with ollydbg in a virtual machine which is debugged with windbg. I don't think that it is a good idea.
4.Use sxe ld. It can be found on Listing 3.29 in <<Advanced Windows Debugging>>. I have tried it but I found that it only works on the first time. And I don't know what exactly should I do after the break.
5.Break on the entry function with bu. But I don't know what exactly I should do either. For example, how to load the symbol?
6.Use .create. I don't know whether it is properly or not to do what I said.
I think that it is a common use to break on the entry point of a program when debug in kernel mode with windbg , and I think that there must be a good way to do that with the powerful windbg. What's the best way to do it?
By the way, I want to debug a program in kernel mode because I want to get the token vaule of the program. I found that the windbg can identify the token with !token in user mode, but I don't know how to get the value of token in user mode. It seems that I can only get the value of token in the kernel mode, right or wrong?
you can run any exe in the target via ntsd -d to debug it from the kernel mode debugger running in the host
assuming you are running a virtual machine mytarget inside myhost
install windbg in myhost
set symbol path for myhost viz srv*x:\xxxx*http:\xxxxxxxxxxxx
create a kernel connection in the host (choose the best shown below is a serial connnection)
X:\xxxx\windbg.exe -k com:pipe,port=\\.\pipe\debugPipe,resets=0,reconnect
install windbg in mytarget
open a shared folder z:\ pointing to the symbolcache folder in myhost
set symbolpath in mytarget pointing to the shared folder
run ntsd -d calc.exe
kd will break on $exentry of calc.exe with Input Prompt
as long as Input prompt is shown you are using kd like a native usermode debugger
so if you set a bp calc!Winmain and issue g kd will break on calc.exe winmain
to get to kd session use .breakin
messy stuff but will work well once you get accustomed (ie memorizing the docs)
a sample run
kd> g <-------------- kd session running in myhost
CommandLine: calc.exe
Symbol search path is: srv*z:\
*http://msdl.microsoft.com/download/symbols
ntdll!DbgBreakPoint:
7c90120e cc int 3
.sympath
NOTE: The symbol path for this ntsd is relative to where
ntsd.exe is running, not where kd.exe is running.
Symbol search path is: srv*z:\
*http://msdl.microsoft.com/download/symbols
Expanded Symbol search path is: srv*z:\
*http://msdl.microsoft.com/download/symbols
.reload /f calc.exe
lm m calc
start end module name
01000000 0101f000 calc (pdb symbols) z:\calc.pdb\3B7D84101\calc.pdb
0:000> version <--------------------usermode session in kd via ntsd -d
version
Windows XP Version 2600 (Service Pack 3) UP Free x86 compatible
Live user mode: <Local>
command line: 'ntsd -d calc.exe' Debugger Process 0x3F8
? $exentry;? calc!WinmainCrtstartup
Evaluate expression: 16852085 = 01012475
Evaluate expression: 16852085 = 01012475
as to your original request i am not sure what token you are interested to find
if getting the EPROCESS->Token of your exe is the only requirement you dont have to run any kd session
you can get the token of all running process in myhost with a local kernel debugging session (either using kd -kl or by using livekd from sysinternals)
here is a simple script which fetches the sid of all running process employing the above technique
:\>cat sid.txt
!for_each_process "r $t0 =(##c++(((nt!_eprocess *) ##Process )->Token.Object)) &
##(~7); r $t1 = ##c++(((nt!_token *) #$t0 )->UserAndGroups->Sid);!sid #$t1 1; ?
? (char *)((nt!_eprocess *) ##Process )->ImageFileName "
:\>kd -kl -c "$$>a< sid.txt;q"
result
WARNING: Local kernel debugging requires booting with kernel
debugging support (/debug or bcdedit -debug on) to work optimally.
lkd> kd: Reading initial command '$$>a< sid.txt;q'
SID is: S-1-5-18 (Well Known Group: NT AUTHORITY\SYSTEM)
char * 0x8ac729a4
"System"
SID is: S-1-5-18 (Well Known Group: NT AUTHORITY\SYSTEM)
char * 0x8a35729c
"smss.exe"
SID is: S-1-5-20 (Well Known Group: NT AUTHORITY\NETWORK SERVICE)
char * 0x8a3619ac
"svchost.exe"
SID is: S-1-5-19 (Well Known Group: NT AUTHORITY\LOCAL SERVICE)
char * 0x8a36ef14
"svchost.exe"
SID is: S-1-5-21-602162358-1801674531-1417001333-1003 (User: XXXXXX\Admin)
char * 0x8a261b64
"explorer.exe"
Use the method described in the Windbg help file for debugging WinLogon. Substitute your user mode app for WinLogon:
Windbg | Help | Contents | Windows Debugging | Debugging Techniques | Specialized Debugging Techniques | Debugging WinLogon
IFEO will start your user mode app and attach ntsd.exe. From ntsd.exe, you can set a break point on image entry with bu $exentry then g to continue.
At any point that ntsd.exe is broken into your user mode process, you can issue .breakin command to switch to kernel mode debugging.

Is CreateProcessW deprecated?

I couldn't find a precise answer so I've decided to ask.
I've been reading the "Inside Windows Debugging" and in the sample it tells me to set a breakpoint on the kernel32!CreateProcessW.
But before that it uses the .symfix debugger command to set the debugger symbols search path to point to the Microsoft online symbols server. When I try to set the breakpoint I get an error that it cannot resolve the function (or something like that). It looks like this.
0:000> bp kernel32!CreateProcessW
Couldn't resolve error at 'kernel32!CreateProcessW'
It's probably because there's no "kernel32!CreateProcessW" in the list below.
0:000> x kernel32!CreateProcess*
76b90cb9 KERNEL32!CreateProcessWithTokenW (void)
76b90d84 KERNEL32!CreateProcessAsUserW (void)
76b90d84 KERNEL32!CreateProcessWithLogonW (void)
76b4e225 KERNEL32!CreateProcessWStub = <no type information>
76b72e04 KERNEL32!CreateProcessInternalAStub = <no type information>
76b72e15 KERNEL32!CreateProcessInternalWStub = <no type information>
76b72de2 KERNEL32!CreateProcessAStub = <no type information>
76b72df3 KERNEL32!CreateProcessAsUserWStub = <no type information>
Everything goes fine if I set the breakpoint to kernel32!CreateProcessWStub but I wondered why I couldn't find and set the breakpoint to the kernel32!CreateProcessW.
This book probably focuses on a reader who's using Windows 7. I'm using Windows 8.1 and thought maybe that kernel32!CreateProcessW got deprecated...
I'm extremely new to this field and apologize if this is a completely stupid question. But thanks for reading it anyway.
CreateProcessW is definitely NOT deprecated. Furthermore, the only documented entry point is still in kernel32.dll, so for all intents and purposes, you should continue calling CreateProcessW through kernel32.dll, and not through kernelbase.dll.
Here is some more details to help understand what you are observing. Windows team often moves code around, and for the last few releases they had strong habit of breaking larger DLL's into smaller ones, which includes kernel32, ole32, user32, gdi32 to name a few. It is not new, Raymond Chen wrote about this in 2006. However the mechanism Raymond describes is based on forwarders, while what you see here with kernel32!CreateProcessW is a stub, i.e. the function that calls kernelbase!CreateProcessW and then returns:
0:014> u kernel32!CreateProcessWStub l14
KERNEL32!CreateProcessWStub:
00007ffd`83cf58a8 4c8bdc mov r11,rsp
00007ffd`83cf58ab 4883ec58 sub rsp,58h
00007ffd`83cf58af 488b8424a8000000 mov rax,qword ptr [rsp+0A8h]
00007ffd`83cf58b7 498943f0 mov qword ptr [r11-10h],rax
... skip ...
00007ffd`83cf58f5 ff1555871100 call qword ptr [KERNEL32!_imp_CreateProcessW (00007ffd`83e0e050)]
00007ffd`83cf58fb 4883c458 add rsp,58h
00007ffd`83cf58ff c3 ret
The function called as you can see is kernelbase!CreateProcessW
0:014> ln poi kernel32!_imp_CreateProcessW
(00007ffd`82f92604) KERNELBASE!CreateProcessW | (00007ffd`82f926d0) KERNELBASE!MakeLocHashNode
Exact matches:
KERNELBASE!CreateProcessW (no parameter info)
I this case I don't know why Windows folks decided to use a stub rather than a forwarder, to me it seems it would be more efficient to simply forward a call, like most of the other refactoring, was done.
Kernel32.dll in Windows 8.1 still contains export symbol CreateProcessW. Command link /dump /exports prints out all export symbols:
c:\>link /dump /exports c:\Windows\System32\kernel32.dll | findstr CreateProcessW
220 DB 000058A8 CreateProcessW = CreateProcessWStub
You can use the same command to determine where you should set a breakpoint to. Similarly for forwarded exports:
c:\>link /dump /exports c:\Windows\System32\kernel32.dll | findstr EnterCriticalSection
298 129 EnterCriticalSection (forwarded to NTDLL.RtlEnterCriticalSection)
1418 589 TryEnterCriticalSection (forwarded to NTDLL.RtlTryEnterCriticalSection)
The reason why WinDbg cannot resolve symbol kernel32!CreateProcess, is probably just a bug in WinDbg. In this case, the symbols is not part of .PDB file, but contained in a special section in PE image, and apparently WinDbg does not handle that. What is interesting is that if .PDB file is not available, WinDbg is happy to use export table of PE image:
0:014> .sympath .
0:014> .reload
Reloading current modules ....
0:014> x kernel32!CreateProcessW
00007ffd`83cf58a8 <b>KERNEL32!CreateProcessW</b> (no parameter info)
Apparently, WinDbg decides to use either PDB symbols or export symbols, but not both.

How to break into WinDBG when ntdll.dll is mapped into the new process

I want to use the following command to break into WinDBG when ntdll.dll is mapped into the new process, and before any of ntdll's process initialization runs.
sxe ld ntdll.dll ;g
However, the trick doesn't work at all,
ModLoad: 7c900000 7c9b0000 ntdll.dll
eax=010043af ebx=7ffde000 ecx=020f18f5 edx=00000034 esi=00c2f720 edi=00c2f6f2
eip=7c810867 esp=0006fffc ebp=00000720 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000200
7c810867 ?? ???
Processing initial command 'sxe ld ntdll.dll ;g'
0:000> sxe ld ntdll.dll ;g
(ae8.6f4): Break instruction exception - code 80000003 (first chance)
eax=00181eb4 ebx=7ffde000 ecx=00000001 edx=00000002 esi=00181f48 edi=00181eb4
eip=7c901230 esp=0006fb20 ebp=0006fc94 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
ntdll!DbgBreakPoint:
7c901230 cc int 3
So, How to break into WinDBG when ntdll.dll is mapped into the new process?
thanks
[UPDATE]
I exactly followed the steps as mentioned by jcopenha, but I don't know why Windbg gives a strange error(Memory access error) where Notepad.exe is running .
Please give me a hand!Thanks a lot!
0:000> .restart /f
CommandLine: C:\WINDOWS\NOTEPAD.EXE
Symbol search path is: D:\Symbols\Symbols;SRV*D:\Symbols\MySymbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
ModLoad: 01000000 01014000 notepad.exe
eax=0100739d ebx=7ffd9000 ecx=020f18f5 edx=0000004e esi=00f7f73a edi=00f7f6f2
eip=7c810867 esp=0007fffc ebp=0000024c iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000200
7c810867 ?? ???
0:000> u 7c810867
7c810867 ?? ???
^ Memory access error in 'u 7c810867'
[UPDATE2]
I found an odd instruction displayed at 7c810867, but p command still can work.
Is it a bug in WinDBG?
If you go to Debug->Event Filters and change "Create process" to "enabled" then restart the application it will start before ntdll.dll shows up in the module list. If you then do sxe ld ntdll.dll;g it will stop in ntdll!RtlUserThreadStart.
0:000> .restart /f
CommandLine: C:\Windows\System32\notepad.exe
Symbol search path is: SRV*d:\symbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
ModLoad: 00000000`ffe00000 00000000`ffe35000 notepad.exe
00000000`7790c500 4883ec48 sub rsp,48h
0:000> sxe ld ntdll.dll;g
ModLoad: 00000000`778e0000 00000000`77a89000 ntdll.dll
ntdll!RtlUserThreadStart:
00000000`7790c500 4883ec48 sub rsp,48h
Regarding the loading of ntdll, I recommend reading this. You can break into the process before any code runs with:
windbg -xe cpr notepad
Or
windbg -xe ld:ntdll notepad
ntdll will still be mapped into the process at this point -- you can't break in before this happens.
As for the memory access error, kernel32 is not loaded into the process yet. The initial thread is queued to run at kernel32!BaseProcessStartThunk, but since kernel32 isn't loaded into the address space yet, you aren't going to see anything at that address.
The reason the thread's start address is able to begin in unmapped memory is because before the thread begins its execution, the very first thing that happens is a user APC runs in the context of that initial thread that takes care of all the process initialization, including loading kernel32. You can see this event occur if you set a similar event, like:
sxe ld kernel32
You will need to load symbols to get the internal functions names in the stack trace.
In addition to the first link, you can read more about process initialization here. Hope this helps.
As far as I remember ntdll is not mapped by the user-mode. If it was mapped in by the user-mode, what would map the module that maps ntdll? ntdll contains a set of stubs for syscalls to enter into the kernel and also contains a few other things such as a COFF loader which is part of process initialisation. It is a bit of a magic dll and it cannot be relocated, thus is always at the same virtual address in every process.
If you want to break before ntdll is mapped I am afraid you will have to use a kernel debugger.
May I ask what you are trying to achieve by breaking before ntdll is mapped?

Resources