Using PyKd for Private Symbols

x BlueRobot

Administrator
Staff member
Joined
May 7, 2013
Posts
10,400
There's a really good Python library called PyKd which is used for creating custom debugger scripts with Python. It also has the really nice feature of being able to define structures and pass an address to help parse those which are only defined with private symbols.

Here's an example of where I've attempted to parse the DXGKARG_SUBMITCOMMAND structure:

Code:
6: kd> !py c:\users\bsodt\pykd-debug.py ffff878c651fa860


struct/class: _DXGKARG_SUBMITCOMMAND at 0xffff878c651fa860
   +0000 m_union                 : union_DXGARG  
   +0008 DmaBufferSegmentId      : UInt4B   0xc220000 (203554816)
   +000c DmaBufferPhysicalAddress: PHYSICAL_ADDRESS  
   +0014 DmaBufferSize           : UInt4B   0 (0)
   +0018 DmaBufferSubmissionStartOffset: UInt4B   0x9c5c1000 (2623279104)
   +001c DmaBufferSubmissionEndOffset: UInt4B   0xffffa188 (4294943112)
   +0020 pDmaBufferPrivateData   : Void*   0 (0)
   +0028 DmaBufferPrivateDataSize: UInt4B   0x1c32 (7218)
   +002c DmaBufferPrivateDataSubmissionStartOffset: UInt4B   0 (0)
   +0030 DmaBufferPrivateDataSubmissionEndOffset: UInt4B   0 (0)
   +0034 SubmissionFenceId       : UInt4B   0x1 (1)
   +0038 VidPnSourceId           : UInt4B   0 (0)
   +003c FlipInterval            : UInt4B   0x4 (4)
   +0040 Flags                   : UInt4B   0 (0)
   +0044 EngineOrdinal           : UInt4B   0 (0)
   +0048 DmaBufferVirtualAddress : UInt4B   0 (0)
   +004c NodeOrdinal             : UInt4B   0 (0)

My script needs to be perfected but I think it seems to be correct?

Code:
from pykd import *
import sys

union_DXGARG_SUBMITCOMMAND = createUnion("union_DXGARG", 0)
union_DXGARG_SUBMITCOMMAND.append("hDevice", baseTypes.VoidPtr)
union_DXGARG_SUBMITCOMMAND.append("hContext", baseTypes.VoidPtr)

dummy_struct = createStruct("DummyStruct", 0)
dummy_struct.append("LowPart", baseTypes.ULong)
dummy_struct.append("HighPart", baseTypes.Long)

u_struct = createStruct("u", 0)
u_struct.append("LowPart", baseTypes.ULong)
u_struct.append("HighPart", baseTypes.Long)

physical_address = createUnion("PHYSICAL_ADDRESS", 0)
physical_address.append("m_dummystruct", dummy_struct)
physical_address.append("m_ustruct", u_struct)

struct_DXGKARG_SUBMITCOMMAND = createStruct("_DXGKARG_SUBMITCOMMAND", 0)
struct_DXGKARG_SUBMITCOMMAND.append("m_union", union_DXGARG_SUBMITCOMMAND)
struct_DXGKARG_SUBMITCOMMAND.append("DmaBufferSegmentId", baseTypes.UInt4B)
struct_DXGKARG_SUBMITCOMMAND.append("DmaBufferPhysicalAddress", physical_address)
struct_DXGKARG_SUBMITCOMMAND.append("DmaBufferSize", baseTypes.UInt4B)
struct_DXGKARG_SUBMITCOMMAND.append("DmaBufferSubmissionStartOffset", baseTypes.UInt4B)
struct_DXGKARG_SUBMITCOMMAND.append("DmaBufferSubmissionEndOffset", baseTypes.UInt4B)
struct_DXGKARG_SUBMITCOMMAND.append("pDmaBufferPrivateData", baseTypes.VoidPtr)
struct_DXGKARG_SUBMITCOMMAND.append("DmaBufferPrivateDataSize", baseTypes.UInt4B)
struct_DXGKARG_SUBMITCOMMAND.append("DmaBufferPrivateDataSubmissionStartOffset", baseTypes.UInt4B)
struct_DXGKARG_SUBMITCOMMAND.append("DmaBufferPrivateDataSubmissionEndOffset", baseTypes.UInt4B)
struct_DXGKARG_SUBMITCOMMAND.append("SubmissionFenceId", baseTypes.UInt4B)
struct_DXGKARG_SUBMITCOMMAND.append("VidPnSourceId", baseTypes.UInt4B)
struct_DXGKARG_SUBMITCOMMAND.append("FlipInterval", baseTypes.UInt4B)
struct_DXGKARG_SUBMITCOMMAND.append("Flags", baseTypes.UInt4B)
struct_DXGKARG_SUBMITCOMMAND.append("EngineOrdinal", baseTypes.UInt4B)
struct_DXGKARG_SUBMITCOMMAND.append("DmaBufferVirtualAddress", baseTypes.UInt4B)
struct_DXGKARG_SUBMITCOMMAND.append("NodeOrdinal", baseTypes.UInt4B)

def dump(address):
    data = typedVar(struct_DXGKARG_SUBMITCOMMAND, address)
    dprintln("\n")
    dprintln(str(data))

address = sys.argv[1]
address = int(address, 16)
dump(address)
 
In some Stop 0xC4 bugchecks, one of the parameters will provide you with a pointer to the _MI_VERIFIER_DRIVER_ENTRY structure, the public symbol server does not include symbols for this and therefore it can't be dumped directly using the dt command. Instead, I've written a small PyKd script to dump it.

Rich (BB code):
DRIVER_VERIFIER_DETECTED_VIOLATION (c4)
A device driver attempting to corrupt the system has been caught.  This is
because the driver was specified in the registry as being suspect (by the
administrator) and the kernel has enabled substantial checking of this driver.
If the driver attempts to corrupt the system, bugchecks 0xC4, 0xC1 and 0xA will
be among the most commonly seen crashes.
Arguments:
Arg1: 0000000000000062, A driver has forgotten to free its pool allocations prior to unloading.
Arg2: ffffbd8f9d69a1a8, name of the driver having the issue.
Arg3: ffffbd8f9d67adc0, verifier internal structure with driver information.
Arg4: 0000000000000001, total # of (paged+nonpaged) allocations that weren't freed.
    Type !verifier 3 drivername.sys for info on the allocations
    that were leaked that caused the bugcheck.

Code:
from pykd import *
import sys
struct_MI_VERIFIER_DRIVER_ENTRY = createStruct("MI_VERIFIER_DRIVER_ENTRY", 0)
struct_MI_VERIFIER_DRIVER_ENTRY.append("Links", typeInfo("nt!_LIST_ENTRY"))
struct_MI_VERIFIER_DRIVER_ENTRY.append("Loads", baseTypes.ULong)
struct_MI_VERIFIER_DRIVER_ENTRY.append("Unloads", baseTypes.ULong)
struct_MI_VERIFIER_DRIVER_ENTRY.append("BaseName", typeInfo("nt!_UNICODE_STRING"))
struct_MI_VERIFIER_DRIVER_ENTRY.append("StartAddress", baseTypes.VoidPtr)
struct_MI_VERIFIER_DRIVER_ENTRY.append("EndAddress", baseTypes.VoidPtr)
struct_MI_VERIFIER_DRIVER_ENTRY.append("Flags", baseTypes.ULong)
struct_MI_VERIFIER_DRIVER_ENTRY.append("Signature", baseTypes.ULong)
struct_MI_VERIFIER_DRIVER_ENTRY.append("PoolPageHeaders", typeInfo("nt!_SLIST_HEADER"))
struct_MI_VERIFIER_DRIVER_ENTRY.append("PoolTrackers", typeInfo("nt!_SLIST_HEADER"))
struct_MI_VERIFIER_DRIVER_ENTRY.append("CurrentPagedPoolAllocations", baseTypes.ULong)
struct_MI_VERIFIER_DRIVER_ENTRY.append("CurrentNonPagedPoolAllocations", baseTypes.ULong)
struct_MI_VERIFIER_DRIVER_ENTRY.append("PeakPagedPoolAllocations", baseTypes.ULong)
struct_MI_VERIFIER_DRIVER_ENTRY.append("PeakNonPagedPoolAllocations", baseTypes.ULong)
struct_MI_VERIFIER_DRIVER_ENTRY.append("PagedBytes", baseTypes.ULong)
struct_MI_VERIFIER_DRIVER_ENTRY.append("NonPagedBytes", baseTypes.ULong)
struct_MI_VERIFIER_DRIVER_ENTRY.append("PeakPagedBytes", baseTypes.ULong)
struct_MI_VERIFIER_DRIVER_ENTRY.append("PeakNonPagedBytes", baseTypes.ULong)
def dump(address):
    data = typedVar(struct_MI_VERIFIER_DRIVER_ENTRY, address)
    dprintln("\n")
    dprintln(str(data))
    dprintln("[+] BaseName \n")
    dprintln(dbgCommand("dt nt!_UNICODE_STRING %x" % data.BaseName.getAddress()))
    dprintln("[+] PoolPageHeaders \n")
    dprintln(dbgCommand("dt nt!_SLIST_HEADER %x" % data.PoolPageHeaders.getAddress()))
    dprintln("[+] PoolTrackers")
    dprintln(dbgCommand("dt nt!_SLIST_HEADER %x" % data.PoolTrackers.getAddress()))
address = sys.argv[1]
address = int(address, 16)
dump(address)

Although, having said this, the same information can be found in the _VF_TARGET_VERIFIED_DRIVER_DATA, albeit some of the field values are slightly different to the above.
 

Has Sysnative Forums helped you? Please consider donating to help us support the site!

Back
Top