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