Debugger commands (!object) that make my life easier (part 3)
Today I am going to write about !object. One of the tools you can get from sysinternals is WinObj.exe. This allows you to traverse the internal object hierarchy in Windows. It's a neat tool, but it uses internal undocumented APIs which means that when a new OS release comes out, the tool needs to be revised to match the OS properly. This can be problematic if you rely on this tool to debug your driver.
As an alternative to WinObj, I suggest that you use !object instead. You can use !object to manually traverse the object hierarchy. !object's command line can accept either the string name of an object or an object pointer. Since object directories are objects themselves, you can view the contents of object directories using !object as well. !object also works from a live kd.exe session, so you don't even need a second machine to use it, you can do it all locally (assuming that the version of Windows supports live debugging).
Let's get started. First, let's see what lives in the root of the hierarchy of a current build of Vista (abbreviated for clarity).
lkd> !object \
Object: 85607628 Type: (82b227b0) Directory
ObjectHeader: 85607610
HandleCount: 0 PointerCount: 59
Directory Object: 00000000 Name: \
Hash Address Type Name
---- ------- ---- ----
00 8560a788 Directory ArcName
83218c68 Device Ntfs
01 88149b00 ALPC Port SeLsaCommandPort
[...]
10 85607748 SymbolicLink DosDevices
[...]
16 85649928 Directory Driver
[...]
19 8560a2f0 Directory Device
[...]
24 85654b38 Directory FileSystem
856032a0 Directory GLOBAL??
8399c228 Event DSYSDBG.Debug.Trace.Memory.220
[...]
35 880ea760 Directory KnownDlls
You can see a few different things from the output. First is that the there are many different types of objects. You have Directory, ALPC Port, Device, Driver, Symbolic Link, and Event to name a few. Each one of these objects has their own characteristics and properties. I will not go into each, but I will talk about Driver, Device, Directory, and Symbolic Link.
A common question I see in the community is "My call to IoGetDeviceObjectPointer(\Device\Xxxx, ...); works on XP, but does not on Server 2003." It is difficult for the person asking the question to figure out if the device exists and permission was denied or that the device does not exist at all. You can use !object to tell you if the device object exists, just execute !object \Device to enumerate the Directory object named "Device."
lkd> !object \Device
Object: 8560a2f0 Type: (82b227b0) Directory
ObjectHeader: 8560a2d8
HandleCount: 0 PointerCount: 222
Directory Object: 85607628 Name: Device
Hash Address Type Name
---- ------- ---- ----
00 8324e258 Device KsecDD
83487520 Device Beep
83214be8 Device Ndis
834483d8 Device SrvNet
87e85fe0 SymbolicLink ScsiPort2
[...]
This works well, but you will have a ton of names to parse through. You can get lost very easily. So, instead of passing the directory name, we pass a specific name (\Device\Xxxx in the example above) and we can quickly check if it exists. I picked \Device\Serial0 as an example of a device that does exist.
lkd> !object \Device\Serial0
Object: 83399520 Type: (82b23388) Device
ObjectHeader: 83399508
HandleCount: 0 PointerCount: 3
Directory Object: 8560a2f0 Name: Serial0
Notice the object pointer value itself that is given, 0x83399520. The object pointer is the PDEVICE_OBJECT pointer itself! (This is also true if you are dumping a Driver object which we will see later.)
lkd> !devobj 83399520
Device object (83399520) is for:
Serial0 \Driver\Serial DriverObject 8344ef38
[...]
Device queue is not busy.
So, we now know that \Device\Serial0 exists. What about its symbolic link name? Let's find that. Symbolic link names can exist globally and can be unique to a particular session; I will only look at the global symbolic links here. These live in \Global?? on XP and later (and in \?? on Win2K IIRC). For brevity, I am not going to show the entire sym link directory, rather the output of !object once you have the sym link name you are interested in.
lkd> !object \GLOBAL??\Com1
Object: 8706ebb0 Type: (82b22640) SymbolicLink
ObjectHeader: 8706eb98
HandleCount: 0 PointerCount: 1
Directory Object: 856032a0 Name: COM1
Target String is '\Device\Serial0'
So not only do you get the standard info about the object, but you also can see what it links too. That's pretty cool in my book. Finally, let's take a look at the driver object. To view all the driver objects on the system, you can run !object \Driver on your own. Here is what !object will show you for a driver object. I followed up the !object command with a !drvobj command. Note that one of the device objects listed in the output of !drvobj is the PDEVICE_OBJECT we looked at before, 0x83399520.
lkd> !object \Driver\Serial
Object: 8344ef38 Type: (82b24040) Driver
ObjectHeader: 8344ef20
HandleCount: 0 PointerCount: 4
Directory Object: 85649928 Name: Serial
lkd> !drvobj 8344ef38
Driver object (8344ef38) is for: \Driver\Serial
Driver Extension List: (id , addr)
Device Object list:
834b98a0 83399520
UPDATE: Peter Wieland pointed out to me how to dump the security descriptor, you can read about how to do that