Search This Blog

Showing posts with label windbg. Show all posts
Showing posts with label windbg. Show all posts

Thursday, December 4, 2014

Different ways of using windbg: Learn the code flow and verify the change.

Recently I switched to a different group and hence, I've been trying to ramp up quickly and started to work on bugs to learn the product.
While working on bugs, I learned that debugger is really helpful to understand the code flow and verify the change. Typically, people might use debugger to debug the issue and that's correct. However, there is another advantage of using a debugger. That is to learn how the code flows and verify the change you are making.
What do I mean by that?
First, let me illustrate with an example to show how debugger can be helpful to learn the code.
Say, you understand what the certain function does and noticed that this function is called several places but not sure exactly where the call is coming from and where it goes.
Then, set a breakpoint on that function and try to reproduce the issue. Sure enough, this will hit the function but at the same time, you might be surprised to find how this function is called from different places for other purposes.
As an example, we are learning NtCreateFile function and wanted to see how this is used. Then, set a breakpoint at NtCreateFile and see the callstack as follows:
 0:000> kcn8  
  # Call Site  
 00 ntdll!NtCreateFile  
 01 KERNELBASE!CreateFileInternal  
 02 KERNELBASE!CreateFileW  
 03 KERNEL32!GetDefaultSortFileMapping  
 04 KERNEL32!SetupDefaultSortTables  
 05 KERNEL32!InternalSortGetHandle  
 06 KERNEL32!SortGetHandle  
 07 KERNELBASE!GetSortVersionHandle  

As a trick, you can also give certain commands to breakpoints. For example, you can say, each time we hit NtCreateFile, display callstack and continue.
 bp ntdll!ntcreatefile "kcn; gc"  

Or if we are only interested in NtCreateFile() coming from certain function like CreateFileInternal as in the above example, we can do the following trick.
 0:000> bl  
  0 e 00007ff8`9b641bc0   0001 (0001) 0:**** ntdll!NtCreateFile "bd 0; x; gc"  
  1 e 00007ff8`98af72d0   0001 (0001) 0:**** KERNELBASE!CreateFileInternal "be 0;gc"  

Basically, what we are doing here is that we enable breakpoint #0 when we hit breakpoint #1 and as soon as we hit breakpoint #0, we display local variables and disable itself. This way we can suppress any other noise and quickly understand the code flow for your purpose.

Now that you understand the code and came up with the fix but sometimes it might be pretty difficult to reproduce the issue. Sometimes we can use debugger to change the code flow.
For instance, you have a function that returns boolean value and in order to hit the newly added code path, you need true from the function but you can't really reproduce the issue locally. In that case, you can again take advantage of breakpoint.
Here is how. Say you have a function and try to disassemble the function and see the address of 'ret' instruction. Once you find it, you know that the return value is passed via eax register so you can do the following.
Here is the disassembled code:
 notepad!IsTextUTF8+0x3c:  
 00007ff6`59596e0e 488b5c2408   mov   rbx,qword ptr [rsp+8]  
 00007ff6`59596e13 c3       ret  

Here is breakpoint:
 0:000> bl  
  2 e 00007ff6`59596e13   0001 (0001) 0:**** notepad!IsTextUTF8+0x41 "r eax=1;gc"  

Of course, this may not work all the time but sometimes this could be very handy to verify your change quickly.

In summary, a debugger can be very helpful in learning the code and verifying the fix. Spend some time learning how to use the debugger. It can save much of your time.

Wednesday, October 10, 2012

windbg init script

There are a couple of commands that I always run every time I start up windbg and it just dawns on me that perhaps it's time to put these commands to the script and have windbg execute it automatically.

So in this post, let me show you how to do that.
First, create a file that will contain all the commands that you would like to run.
For this example, let me create a file called 'dbg-prep.cmd'

C:\Users\ilhoye\Desktop\WinDbg> type dbg-prep.cmd
.symfix
.reload
.load mex
.load kdexts
aS !pr !process

Once we have this, we can just launch windbg with '-c' option. '-c' is a command to execute when windbg starts up but for our case, we want to execute several command and that is why I created a script in the first place.
To do that, we still use '-c' option but now this time we want to provide file path as follows.

windbg.exe -c "$$>< C:\Users\ilhoye\Desktop\WinDbg\dbg-prep.cmd

Please note that '-c' option needs to be quoted like the above.
Of course, it is cumbersome to type all these so it would be best to create a shortcut for this and in fact, as for me here is my shortcut command which also specifies the connection for kernel debugging.

"C:\Program Files\Debugging Tools for Windows (x64)\windbg.exe" -k 1394:channel=2 -c "$$>< C:\Users\ilhoye\Desktop\WinDbg\dbg-prep.cmd"

You can also add arguments to the script and for more information, please refer to msdn.

Monday, October 8, 2012

WINDBG: Setting breakpoints for user-mode process from kernel mode debugger

When working with kernel debugger, sometimes we may want to set a breakpoint in the user-mode. Can we do it? Yes, we can. :)

So in this post let me show you how to do that using notepad as an example.
First, let us connect to kernel debugger and in my case I use 1394 debugger connection. Once we are connected, look for a process that we want to set a breakpoint for.

0: kd> !process 0 0 notepad.exe
PROCESS fffffa8012256980
    SessionId: 1  Cid: 0990    Peb: 7f72f0bf000  ParentCid: 07ac
    DirBase: 1babb8000  ObjectTable: fffff8a007c7a040  HandleCount:  68.
    Image: notepad.exe


Once we have located the process that we are interested in. Follow these steps.

0: kd> .process /i fffffa8012256980
You need to continue execution (press 'g' <enter>) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.
0: kd> g
Break instruction exception - code 80000003 (first chance)
nt!DbgBreakPointWithStatus:
fffff802`46e8f930 cc

.process command will set a process context to notepad and '/i' option means that the target process is to be debugged invasively. In other words, once we execute this command, it prompts us to type 'g'. When we type 'g', it will set the target process to be active process and in this context, we can set a user-mode breakpoint.

For instance, let us set a breakpoint at NtCreateFile of ntdll but before we do that, we need to reload the symbols. This will not only reload kernel symbols but it will also reload user-mode symbols which we need to set a breakpoint for.

3: kd> .reload
Connected to Windows 8 9200 x64 target at (Mon Oct  8 18:10:21.107 2012 (UTC - 7:00)), ptr64 TRUE
Loading Kernel Symbols
...............................................................
................................................................
...................
Loading User Symbols
.........................
Loading unloaded module list
......
3: kd> bp /p fffffa8012256980 ntdll!ntcreatefile


Now, let us resume and this time the debugger should be able to break into the user-mode process.

3: kd> g
Breakpoint 3 hit
ntdll!ZwCreateFile:
0033:000007fb`891a30f0 4c8bd1          mov     r10,rcx
1: kd> kcn
 # Call Site
00 ntdll!ZwCreateFile
01 ntdll!LdrpNtCreateFileUnredirected
02 ntdll!LdrpMapResourceFile
03 ntdll!LdrLoadAlternateResourceModuleEx
04 ntdll!LdrpLoadResourceFromAlternativeModule
05 ntdll!LdrpSearchResourceSection_U
06 ntdll!LdrFindResource_U
07 KERNELBASE!FindResourceExW
08 COMDLG32!FindResourceExFallback
09 COMDLG32!FindResourceExMirrorFallback
0a COMDLG32!CFileOpenSave::_GetDialogTemplate
0b COMDLG32!CFileOpenSave::Show
0c notepad!ShowOpenSaveDialog


You can see from the above that the breakpoint was hit and the callstack is actually from the user-mode.
This technique can be used in many different places and one of the place could be when we want to break into certain function of the service process when it was being loaded. I guess that there are probably other places but this will definitely save you from some work of coordinating two different debuggers.