A: On WinXP
001bff00 7732e489 ntdll!_RtlUserThreadStart+0x1b
001bff04 00ac1576 dbgex4!mainCRTStartup
001bff08 7ffd4000
001bff0c 00000000
001bff10 00000000
001bff14 00000000
001bff18 00000000
001bff1c 00ac1576 dbgex4!mainCRTStartup ; start address
001bff20 7ffd4000 ; optional parameter
On Vista
0088fb20 7782e489 ntdll!_RtlUserThreadStart+0x1b
0088fb24 7713361f kernel32!LoadLibraryW
0088fb28 00080000
0088fb2c 00000000
0088fb30 00000000
0088fb34 00000000
0088fb38 00000000
0088fb3c 7713361f kernel32!LoadLibraryW ; start address
0088fb40 00080000 ; optional parameter
They are 7th and 8th parameters.
(Excerpted from http://blogs.msdn.com/ntdebugging/archive/2009/03/06/it-s-not-my-fault-a-case-of-remote-code-injection-gone-bad.aspx)
Q: How to convert the time (System.DateTime, a value type) to an actual timestamp?
A: dq {address of the time} (dump the content of the time as a quad word to get the number of ticks)
.formats {quad word} & 0x3FFFFFFFFFFFFFFF (run .formats on the number of ticks with the 2 highest bits filtered out)
Q: How to find out the corresponding kernel object using the handle from the user mode?
A: The process id, thread id, and handle in the user mode are recognizable in kernel mode. They can be used to look for the corresponding kernel object in the kernel debugger.
For instance, the following is the output from the user mode debugger.
0:000> !handle 7b0 ff
Handle 7b0
Type Event
...
0:000> |
. 0 id: b24 create name: 07sample.exe
The following is the output from the local kernel debugger. The handle and process id from the user mode debugger are used directly in the kernel debugger.
lkd> !handle 7b0 7 0b24
processor number 0, process 00000b24
Searching for Process with Cid == b24
PROCESS 89490760 SessionId: 0 Cid: 0b24 Peb: 7ffda000 ParentCid: 0670
DirBase: 51c9e000 ObjectTable: e82902c8 HandleCount: 22.
Image: 07sample.exe
Handle table at e1839000 with 22 Entries in use
07b0: Object: 887a08e8 GrantedAccess: 001f0003 Entry: e1839f60
Object: 887a08e8 Type: (89befbf8) Event
ObjectHeader: 887a08d0 (old version)
HandleCount: 1 PointerCount: 2
Directory Object: e16a1368 Name: 07sample
Q: How to track down an invalid handle error?
A: Before we get into troubleshooting let’s look at a couple of scenarios for bad handles.
In the first bad handle scenario, let’s say your application closes handle 2 using CloseHandle(), however your application keeps the value 2 in a variable somewhere. In this scenario we will assume no other code has come along and opened a new object that is occupying element 2 of the handle table. If you go to make a file I/O call using handle 2 the object manager will catch this and your app will get an invalid handle exception. This is somewhat harmless but your app may crash if you don’t catch the exception and your I/O will obviously not complete.
In the second scenario we’ll say that your file I/O code closes the handle, and holds on to that handle value. Meanwhile another part of your application opens a registry key or some other object that is not a file object. Now your file I/O code goes to use handle 2 again. The problem is it’s not a handle to a file now. When the registry code opened the registry key element 2 was available so we now have a registry object in that location. If you go to do a file I/O on handle 2 you will get an invalid handle message.
Now in our final scenario, we close a file handle in our file I/O code and keep the handle around. In this case though we have different code that is also doing file I/O, It opens a file and gets handle value 2. Now you have big trouble because if the first file I/O code now writes to handle 2, and it should not be because it closed it! This handle now belongs to a different file. This means you have code basically doing a write into an unknown region for that code’s context and file format. This will result in file corruption and no invalid handle error.
So this really comes down to best practice. If you’re writing code and close a handle NULL IT OUT! That way you guarantee it will not be reused accidently at some other point.
CloseHandle(MyHandle);
MyHandle = NULL;
The following action plan can be used to track down the invalid handle.
1.Start gflags and under the image file tab, enter your application name in the image edit control.
2.Check Create User mode stack trace database.
3.Start the process under windbg. “WinDBG processname.exe”
4.In windbg Run !htrace -enable
5.Do a sxe ch. This will cause windbg to break on an invalid handle exception.
6.Run sx to confirm “ch - Invalid handle – break” should be set.
7.Enter g for go.
8.Let the process run until you get an invalid handle message. The debugger should break in.
9.Now all you have to do is run !htrace
Htrace will dump out all the call stacks for each handle that was opened or closed.
You need to take the invalid handle value and search backward to see where it was last opened, and where it was closed before that. It’s likely that the close before the last open is your culprit code path. Make sure that suspect close nulls that handle value out so it does not reuse it.
(Excerpted from http://blogs.msdn.com/ntdebugging/archive/2008/05/19/ntdebugging-puzzler-0x00000006-invalid-handle-can-you-handle-it.aspx)
Q: How to find out what service is hosted in svchost.exe?
A: 0:006> x /v svchost!*service*name*
pub global 010040b4 0 svchost!ServiceNames =
0:006> du poi(010040b4)
0009add0 "DnsCache"
Q: How to find out what type a kernel dispatcher object is when the !object extension command fails?
A: From the !thread command, we have the following display,
0: kd> !thread 89238998
THREAD 89238998 Cid 0a90.05fc Teb: 7ffad000 Win32Thread: 00000000 WAIT: (UserRequest) UserMode Non-Alertable
89238a88 NotificationTimer
[...]
0: kd> !object 89238a88
89238a88: Not a valid object (ObjectType.Name at 0x2710 invalid)
0: kd> dt _DISPATCHER_HEADER 89238a88
nt!_DISPATCHER_HEADER
+0x000 Type : 0x8 '' ;
+0x002 Size : 0xa ''
+0x003 Inserted : 0x1 ''
+0x004 SignalState : 0
+0x008 WaitListHead : _LIST_ENTRY [ 0x89238a50 - 0x89238a50 ]
Type codes of kernel dispatcher objects:
Type Object
0 NOTIFICATION_EVENT
1 SYNCHRONIZATION_EVENT
2 MUTANT
3 PROCESS
4 QUEUE
5 SEMAPHORE
6 THREAD
7 (not assigned?)
8 NOTIFICATION_TIMER
9 SYNCHRONIZATION_TIMER
Q: How to check stack overflow?
A: 0:000> dt _TEB 7ffde000
ntdll!_TEB
+0x000 NtTib : _NT_TIB
[...]
+0xe0c DeallocationStack : 0x00040000
[...]
0:000> dt _NT_TIB 7ffde000
MSVCR71!_NT_TIB
+0x000 ExceptionList : 0x0007ffb0 _EXCEPTION_REGISTRATION_RECORD
+0x004 StackBase : 0x00080000
+0x008 StackLimit : 0x0006f000
+0x00c SubSystemTib : (null)
+0x010 FiberData : 0x00001e00
+0x010 Version : 0x1e00
+0x014 ArbitraryUserPointer : (null)
+0x018 Self : 0x7ffde000 _NT_TIB
0:000> ? 0x00080000 - 0x0006f000 ; Current stack size = StackBase - StackLimit
Evaluate expression: 69632 = 00011000
0:000> ? 0x00080000 - 0x00040000
Evaluate expression: 262144 = 00040000 ; Max stack size = StackBase - DeallocationStack
There is more than adequate stack space left.
(Excerpted from http://msdn.microsoft.com/en-us/library/cc267849.aspx)
Q: How to dump memory addresses that have the "nt" string?
A: .foreach(obj {s -[1]a 0 0FFFFFFF "nt"}) {da /c 0n100 ${obj}}
Q: How to count a specified string in a file or output of commands?
A: .shell -i c:\handle.txt FIND /C "licensestatus"
.shell -i - -ci "dps 00226000 00230000" FIND /C "ntdll!"
.shell -i - -ci "~* kb" FIND /C "RaiseException"
Q: How to track the reference count of an object?
A: Assume
ba w4 @esi+0x8 "[WinDBG script] @esi poi(@esi+8);k;g"
The WinDBG script takes the object and its reference count and prints them out.
.printf "this=%p",${$arg1}
.printf "\t"
.printf "refcount=%d",${$arg2}
.printf "\r\n"
Q: How to dump all the .NET exceptions on the heap?
A:
Q: How to set a breakpoint on dynamically generated code?
A: Set a native breakpoint on mscorjit!CILJit::compileMethod
ChildEBP RetAddr Args to Child
001de8d0 7028722c 70bc7268 001dea90 001dea08 mscorjit!CILJit::compileMethod
Dump the third parameter to the function, where the first DWORD contains the method descriptor.
0:000> dd 001dea08 L1
001dea08 002b2ff8
0:000> !bpmd -md 002b2ff8
MethodDesc = 002b2ff8
Adding pending breakpoints...
0:000> !dumpmd 002b2ff8
Method Name: Advanced.NET.Debugging.Chapter4.TypeCast.Main(System.String[])
Class: 002b12f8
MethodTable: 002b300c
mdToken: 06000004
Module: 002b2c5c
IsJitted: no
CodeAddr: ffffffff
Q: How to determine the range of user space and system space?
A: lkd> x nt!mmhighestuseraddress
80567edc nt!MmHighestUserAddress
lkd> dp nt!mmhighestuseraddress l1
80567edc 7ffeffff
This indicates that user space ranges from the address 0x00000000 to 0x7FFEFFFF, and system space therefore ranges from 0x80000000 up to the highest possible address (which is 0xFFFFFFFF on a standard 32-bit Windows installation).
The same method can be used on 64-bit Windows as well.
lkd> dp nt!mmhighestuseraddress l1
fffff800`011b2748 000007ff`fffeffff
Q: How to find out which function returns a specific value?
A: wt -oR or tct; z(eax!=0xc000000d)
A: The following command combination does not work for me although some blogs claim it works for them.
Q: How to identify a module header from the raw memory?
A: 0:000> dc 00400000
00400000 00905a4d 00000003 00000004 0000ffff MZ..............
00400010 000000b8 00000000 00000040 00000000 ........@.......
00400020 00000000 00000000 00000000 00000000 ................
00400030 00000000 00000000 00000000 00000080 ................
00400040 0eba1f0e cd09b400 4c01b821 685421cd ........!..L.!Th
00400050 70207369 72676f72 63206d61 6f6e6e61 is program canno
00400060 65622074 6e757220 206e6920 20534f44 t be run in DOS
00400070 65646f6d 0a0d0d2e 00000024 00000000 mode....$.......
Identify the header by the “MZ” string at the beginning of the header. Then use !dh to display the headers