What’s NonInvasive debugging?
Non-Invasive debugging is a useful technique to debug hung processes. When NonInvasive debugging is going on the debugger suspends all threads in the process and has access to all threads, memory and register’s of the process. The debugger when NonInvasive debugging is in progress cannot modify process memory, cannot instruct the process to run as well.
NonInvasive debugging via WinDbg
To do non-invasive debugging via windbg/cdb check this link out:
Here let me show you how to do NonInvasive debugging via WinDbg UI.
Open WinDbg, press F6 or File->Attach to a Process. Please make sure you check “Noninvasive” check box in the “Attach to Process” dialog.
While non-invasive debugging is in progress we can have another instance of the debugger attached to the debuggee. This proves that when non-invasive debugging is in progress the debugger is not attached to the debuggee. Note on Windows only one debugger can be attached at any time to a process. Also while debugging non-invasively common windbg commands like ‘g’ won’t work because this debugger is not attached to the debuggee invasively hence cannot instruct the process to resume execution. A debugger invasively attached to a debuggee manipulates it via a thread created in the remote process.
Thread manipulation during NonInvasive debugging
As written already: for non-invasive debugging the debugger suspends all the threads in the process so this also means that we can resume execution of these threads too. The command to do this is as follows…
~m resumes a thread while ~n suspends a thread. If we don’t resume the threads we won’t see the process UI as the UI thread is also in a suspended state.
Viewing debuggee process memory during NonInvasive debugging
Now with two debuggers monitoring the process we can view the process’ memory via the non-invasive debugger as well. For e.g. when you set a breakpoint via the second debugger (attached invasively) its interesting to see how the function code is modified by the debugger to get the breakpoint to work, see below e.g.
This is how code for ntdll!ntopenfile will look like before a breakpoint is set…
0:001> uf ntdll!ntopenfile ntdll!ZwOpenFile: 000007f9`25972f10 4c8bd1 mov r10,rcx <<<<---- This three byte instruction is replaced, see below 000007f9`25972f13 b831000000 mov eax,31h 000007f9`25972f18 0f05 syscall 000007f9`25972f1a c3 ret
This is how code for ntdll!ntopenfile will look like after a breakpoint is set…
0:000> uf ntdll!ntopenfile ntdll!ZwOpenFile: 000007f9`25972f10 cc int 3 <<<<------- Single byte instruction cc, and followed by 000007f9`25972f11 8bd1 mov edx,ecx <<--- 8bd1: remaining two bytes of the above three bytes instruction: 4c8bd1. 4c replaced by cc. 000007f9`25972f13 b831000000 mov eax,31h 000007f9`25972f18 0f05 syscall 000007f9`25972f1a c3 ret
In effect the original three byte instruction (4c8bd1) is replaced by (cc8bd1). The only change: 4c –> cc. cc evaluates to int 3. When the breakpoint is hit (or when we press Ctrl + Break) the breakpoint instruction is replaced by original op code i.e. 4c8bd1.
We could figure this out via the non-Invasive debugger. If a process is hung we can in effect go through the call stacks and find out potential hang scenarios, for e.g. a process waiting on a network drive.