""" Work with NT Object tree manager getType(p) Return object type address by object address getObjectNameInfo(p) Return typedVar of nt!_OBJECT_HEADER_NAME_INFO or None getObjectName(p) Return string of object name. If can not get name - empty string buildObjectName(p) Return string of full object name. If can not get name - empty string getListByHandleTable(tableHandles=None, objTypeAddr=0, containHeaders=True) Return list of objects from table of handles getListByDirectoryObject(p, objTypeAddr=0) Return list of objects from object directory getObjectByName(name, caseSensitive=False) Return address of object by full name. If error (f.e. not exist) - None """ from pykd import * nt = loadModule("nt") def getTypeWin7(p): """ Get object header by object pointer Implementation for Win7+ """ objHeader = nt.containingRecord(p, "_OBJECT_HEADER", "Body") tableTypeIndex = nt.ObTypeIndexTable return ptrPtr(tableTypeIndex + (ptrSize() * objHeader.TypeIndex)) def getTypeLegacy(p): """ Get object header by object pointer Implementation for before Win7 """ objHeader = nt.containingRecord(p, "_OBJECT_HEADER", "Body") return objHeader.Type # Select platform-specific function for getting object header # Select key body type: nt!CmpKeyObjectType or nt!CmKeyObjectType if (ptrWord( nt.NtBuildNumber ) >= 7600): getType = getTypeWin7 # _kcbObjectType = expr("poi(nt!CmKeyObjectType)") else: getType = getTypeLegacy # _kcbObjectType = expr("poi(nt!CmpKeyObjectType)") def getObjectNameInfoFromHeader(p): """ Get object name information from field NameInfoOffset of object header """ objHeader = nt.containingRecord(p, "_OBJECT_HEADER", "Body") if (0 == objHeader.NameInfoOffset): return None return nt.typedVar("_OBJECT_HEADER_NAME_INFO", objHeader.getAddress() - objHeader.NameInfoOffset) def getObjectNameInfoFromInfoMask(p): """ Get object name information from field NameInfoOffset of object header """ objHeader = nt.containingRecord(p, "_OBJECT_HEADER", "Body") if (0 == (objHeader.InfoMask & 2)): return None offsetNameInfo = ptrByte( nt.ObpInfoMaskToOffset + (objHeader.InfoMask & 3) ) if (0 == offsetNameInfo): return None return nt.typedVar("_OBJECT_HEADER_NAME_INFO", objHeader.getAddress() - offsetNameInfo) # Select platform-specific function for getting name of object getObjectNameInfo = None try: nt.type("_OBJECT_HEADER").NameInfoOffset getObjectNameInfo = getObjectNameInfoFromHeader except TypeException: getObjectNameInfo = getObjectNameInfoFromInfoMask def getObjectName(p): """ Get object name by name information """ nameInfo = getObjectNameInfo(p) if (None == nameInfo): return "" return loadUnicodeString(nameInfo.Name.getAddress()) def buildObjectName(p): """ Get object name by name information (parent directory handled) """ objectFullName = "" nameInfo = getObjectNameInfo(p) if None == nameInfo: return objectFullName namePart = loadUnicodeString(nameInfo.Name.getAddress()) if namePart != "\\": objectFullName = namePart + "\\" + objectFullName else: objectFullName = "\\" + objectFullName while (0 != nameInfo.Directory): p = nameInfo.Directory nameInfo = getObjectNameInfo(p) if (None == nameInfo): return "...\\" + objectFullName namePart = loadUnicodeString(nameInfo.Name.getAddress()) if namePart != "\\": objectFullName = namePart + "\\" + objectFullName else: objectFullName = "\\" + objectFullName return objectFullName HANDLE_VALUE_INC = 4 HT_PAGE_SIZE = 4096 HT_ENTRY_SIZE = (2 * ptrSize()) HT_LOWLEVEL_COUNT = HT_PAGE_SIZE // HT_ENTRY_SIZE HT_MIDLEVEL_COUNT = HT_PAGE_SIZE // ptrSize() def getListByHandleTable(tableHandles=None, objTypeAddr=0, containHeaders=True): """ Build list of objects from target handle table Parameter objTypeAddr if not 0 used for getting object of specific type, otherwise get object of all types Parameter containHeaders used to interpret table contents: if containHeaders=True then table contains pointers to nt!_OBJECT_HEADER, otherwise table contains pointers to objects """ def getByHandleEntry(entryHandle, containHeader): """ Query object pointer by handle entry from handle table """ if (0 == entryHandle): return 0 HandleEntry = nt.typedVar("_HANDLE_TABLE_ENTRY", entryHandle) if (0xFFFFFFFE == HandleEntry.NextFreeTableEntry): return 0 p = ptrPtr(HandleEntry.getAddress()) & 0xFFFFFFFFFFFFFFF8 if (0 == p): return 0 if (containHeader): objHeader = nt.typedVar("_OBJECT_HEADER", p) p = objHeader.Body.getAddress() return p def getListByHandleTableL0(pTableContent, nMaxHandleIndex, objTypeAddr, containHeaders): """ Build list of objects from target handle table level 0 """ lstObjects = list() nTableLevel0Count = nMaxHandleIndex // HANDLE_VALUE_INC for HandleEntryIndex in range(nTableLevel0Count): pHandleEntry = pTableContent + (HT_ENTRY_SIZE * HandleEntryIndex) p = getByHandleEntry(pHandleEntry, containHeaders) if (0 == p): continue if (0 == objTypeAddr): lstObjects.append(p) else: pCurrentType = getType(p) if (addr64(objTypeAddr) == addr64(pCurrentType)): lstObjects.append(p) return lstObjects def getListByHandleTableL1(pTableContent, nMaxHandleIndex, objTypeAddr, containHeaders): """ Build list of objects from target handle table level 1 """ lstObjects = list() nTableLevel1Count = (nMaxHandleIndex // HANDLE_VALUE_INC) // HT_LOWLEVEL_COUNT for Index in range(nTableLevel1Count): pTableLevel0 = ptrPtr(pTableContent + (Index * ptrSize())) lstObjects += getListByHandleTableL0(pTableLevel0, HT_LOWLEVEL_COUNT * HANDLE_VALUE_INC, objTypeAddr, containHeaders) return lstObjects def getListByHandleTableL2(pTableContent, nMaxHandleIndex, objTypeAddr, containHeaders): """ Build list of objects from target handle table level 2 """ lstObjects = list() nTableLevel2Count = ((nMaxHandleIndex // HANDLE_VALUE_INC) // HT_LOWLEVEL_COUNT) // HT_MIDLEVEL_COUNT for Index in range(nTableLevel2Count): pTableLevel1 = ptrPtr(pTableContent + (Index * ptrSize())) lstObjects += getListByHandleTableL1(pTableLevel1, HT_MIDLEVEL_COUNT * HT_LOWLEVEL_COUNT * HANDLE_VALUE_INC, objTypeAddr, containHeaders) return lstObjects if (None == tableHandles): currProcess = nt.typedVar("_EPROCESS", getCurrentProcess()) if (None == currProcess): dprintln("Get current process failed") return tableHandles = currProcess.ObjectTable tableHandles = nt.typedVar("_HANDLE_TABLE", tableHandles) nMaxHandleIndex = tableHandles.NextHandleNeedingPool & 0xFFFFFFFF nTableLevel = (tableHandles.TableCode & 3) pTableContent = tableHandles.TableCode - nTableLevel if (0 == nTableLevel): return getListByHandleTableL0(pTableContent, nMaxHandleIndex, objTypeAddr, containHeaders) elif (1 == nTableLevel): return getListByHandleTableL1(pTableContent, nMaxHandleIndex, objTypeAddr, containHeaders) elif (2 == nTableLevel): return getListByHandleTableL2(pTableContent, nMaxHandleIndex, objTypeAddr, containHeaders) dprintln("ERROR: Unknown handle table level: %u" % nTableLevel) return list() NUMBER_HASH_BUCKETS = 37 def getListByDirectoryObject(p, objTypeAddr=0): """ Build list of objects from object directory Parameter objTypeAddr if not 0 used for getting object of specific type, otherwise get object of all types """ if getType(p) != ptrPtr( nt.ObpDirectoryObjectType ): return None result = list() for i in range(0, NUMBER_HASH_BUCKETS): bucket = ptrPtr( p + (i * ptrSize()) ) while bucket: bucketVar = nt.typedVar("_OBJECT_DIRECTORY_ENTRY", bucket) if objTypeAddr and (getType(bucketVar.Object) == objTypeAddr): result.append(bucketVar.Object) elif (not objTypeAddr): result.append(bucketVar.Object) bucket = bucketVar.ChainLink return result def getObjectByName(name, caseSensitive=False): """ Query address of object by full name """ def cmpCase(s1, s2): return s1 == s2 def cmpNoCase(s1, s2): return s1.lower() == s2.lower() if not len(name): return None if name[0] != '\\': return None object = ptrPtr( nt.ObpRootDirectoryObject ) cmpFunc = cmpNoCase if caseSensitive: cmpFunc = cmpCase while True: name = name[1:] if not len(name): break tok = name.find("\\") if -1 != tok: namePart = name[:tok] name = name[tok:] else: namePart = name if 0 == len(namePart): return None # FIXME: use name/index hash lstObjects = getListByDirectoryObject(object) if None == lstObjects: return None found = False for p in lstObjects: objName = getObjectName(p) if len(objName) and cmpFunc( namePart, objName ): object = p found = True break if not found: return None if -1 == tok: break return object import sys # Display object kd-command ViewObjectCommand = { addr64( expr("poi(nt!IoFileObjectType)") ) : "!fileobj", addr64( expr("poi(nt!PsProcessType)") ) : "!process", addr64( expr("poi(nt!PsThreadType)") ) : "!thread", addr64( expr("poi(nt!IoDeviceObjectType)") ) : "!devobj", addr64( expr("poi(nt!SeTokenObjectType)") ) : "!token", # addr64( _kcbObjectType ) : "!reg kcb", addr64( expr("poi(nt!IoDriverObjectType)") ) : "!drvobj 7" } def main(): """ Print content of object table (handle table) Usage: !py ntobj [table= ] [type= ] [headers= ] When (options can be specified in any order): table= : table of handle address. F.e. address object table contained in field ObjectTable structure nt!_EPROCESS default: nt!_EPROCESS.ObjectTable of current processes type= : address of object type. If specified (!= 0) then print object of target type only. default: 0 headers= : table of handles format: contain pointer to object or to object header (nt!_OBJECT_HEADER): True or Flase F.e. poi(nt!PspCidTable) contains objects (processes and threads), and nt!_EPROCESS.ObjectTable contains headers default: True Examples: !py ntobj Print object table of current process !py ntobj type= poi(nt!IoFileObjectType) Print object table (only _FILE_OBJECT *) of current process !py ntobj table= poi(poi(nt!PsInitialSystemProcess)+@@C++(#FIELD_OFFSET(nt!_EPROCESS,ObjectTable))) Print object table for SYSTEM process. !py ntobj table= poi(nt!PspCidTable) headers= False type= poi(nt!PsProcessType) Print all process objects from nt!PspCidTable """ if not isWindbgExt(): print "Script is launch out of WinDBG" return if not isKernelDebugging(): dprintln("This script for kernel debugging only") return argc = len(sys.argv) if (2 == argc) and ("help" == sys.argv[1] or "?" == sys.argv[1]): dprintln(main.__doc__, True) return if (0 == (argc % 2)): dprintln("Invalid number of comand line arguments") dprintln(main.__doc__, True) return tableHandles = None objTypeAddr = 0 containHeaders = True for i in range(1, argc, 2): if ("table=" == sys.argv[i]): tableHandles = expr(sys.argv[i + 1]) elif ("type=" == sys.argv[i]): objTypeAddr = expr(sys.argv[i + 1]) elif ("headers=" == sys.argv[i]): containHeaders = ("True" == sys.argv[i + 1]) else: dprintln("Unknown option `" + sys.argv[i] + "'") dprintln(main.__doc__, True) return lstObjects = getListByHandleTable(tableHandles, objTypeAddr, containHeaders) dprintln("%u objects:" % len(lstObjects)) for object in lstObjects: objectType = getType(object) if objectType in ViewObjectCommand: viewCommand = ViewObjectCommand[objectType] else: viewCommand = "!object" dprint("\tobject=" % object + viewCommand + " 0x%x" % object, True) objectName = buildObjectName(object) if len(objectName): dprintln( ", name=`" + objectName + "'" ) elif nt.typedVar("_OBJECT_TYPE", getType(object)).TypeInfo.QueryNameProcedure: dprintln(", custom name", True) else: dprintln(" , <_unnamed_>") dprint("\ttype is `" + getObjectName(objectType) + "' (0x%x)" % (objectType, objectType), True) dprintln( "\n" ) if (1 == argc): dprintln("\nView help for ntobj", True) if __name__ == "__main__": main()