[0.3.x] branch : snippets/ntobj.py

git-svn-id: https://pykd.svn.codeplex.com/svn@86278 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
SND\kernelnet_cp 2013-11-05 11:20:45 +00:00 committed by Mikhail I. Izmestev
parent b46b74cb71
commit 6ecf53e19d
4 changed files with 493 additions and 2 deletions

View File

@ -53,11 +53,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "snippets", "snippets", "{AA
snippets\cr4.py = snippets\cr4.py
snippets\ctlcode.py = snippets\ctlcode.py
snippets\export.py = snippets\export.py
snippets\findhandle.py = snippets\findhandle.py
snippets\findtag.py = snippets\findtag.py
snippets\gdt.py = snippets\gdt.py
snippets\help.py = snippets\help.py
snippets\iat.py = snippets\iat.py
snippets\ndis.py = snippets\ndis.py
snippets\ntobj.py = snippets\ntobj.py
snippets\pytowiki.py = snippets\pytowiki.py
EndProjectSection
EndProject

View File

@ -34,6 +34,7 @@ BOOST_PYTHON_FUNCTION_OVERLOADS( startProcess_, startProcess, 1, 2 );
BOOST_PYTHON_FUNCTION_OVERLOADS( detachProcess_, kdlib::detachProcess, 0, 1 );
BOOST_PYTHON_FUNCTION_OVERLOADS( terminateProcess_, kdlib::terminateProcess, 0, 1 );
BOOST_PYTHON_FUNCTION_OVERLOADS( attachKernel_, attachKernel, 0, 1 );
BOOST_PYTHON_FUNCTION_OVERLOADS( evaluate_, evaluate, 1, 2 );
BOOST_PYTHON_FUNCTION_OVERLOADS( dprint_, kdlib::dprint, 1, 2 );
BOOST_PYTHON_FUNCTION_OVERLOADS( dprintln_, kdlib::dprintln, 1, 2 );
@ -119,8 +120,8 @@ BOOST_PYTHON_MODULE( pykd )
python::def( "breakin", &targetBreak,
"Break into debugger" );
python::def( "expr", &evaluate,
"Evaluate windbg expression" );
python::def( "expr", &evaluate, evaluate_( boost::python::args( "expression", "cplusplus" ),
"Evaluate windbg expression" ) );
python::def( "dbgCommand", &debugCommand,
"Run a debugger's command and return it's result as a string" );
python::def( "go", &targetGo,

49
snippets/findhandle.py Normal file
View File

@ -0,0 +1,49 @@
from pykd import *
import ntobj
import sys
nt = module("nt")
def findHanle(objaddr):
processList = typedVarList( nt.PsActiveProcessHead, "nt!_EPROCESS", "ActiveProcessLinks" )
for process in processList:
dprintln( "search in process %x " % process.UniqueProcessId + "".join( [chr(i) for i in process.ImageFileName if i != 0] ) )
if process.ObjectTable == 0:
continue
objects = ntobj.getListByHandleTable( process.ObjectTable )
for obj in objects:
if obj[0] == objaddr:
dprintln("\tHandle: %x" % ( obj[1],) )
def usage():
dprintln("!py findhandle object_address")
def main():
if not isKernelDebugging():
dprintln("This script for kernel debugging only")
return
if len(sys.argv) < 2:
usage();
return;
objaddr = expr(sys.argv[1])
objectType = ntobj.getType(objaddr)
dprintln("Object Type: " + ntobj.getObjectName(objectType) )
dprintln("Object Name: "+ ntobj.getObjectName(objaddr) )
dprintln("")
findHanle( objaddr )
if __name__ == "__main__":
main()

439
snippets/ntobj.py Normal file
View File

@ -0,0 +1,439 @@
"""
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 = module("nt")
# optimization
OBJECT_HEADER = nt.type("_OBJECT_HEADER")
HANDLE_TABLE_ENTRY = nt.type("_HANDLE_TABLE_ENTRY")
OBJECT_DIRECTORY_ENTRY = nt.type("_OBJECT_DIRECTORY_ENTRY")
OBJECT_HEADER_NAME_INFO = nt.type("_OBJECT_HEADER_NAME_INFO")
def getTypeWin7(p):
"""
Get object header by object pointer
Implementation for Win7+
"""
objHeader = 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 = 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 = containingRecord(p, OBJECT_HEADER, "Body")
if (0 == objHeader.NameInfoOffset):
return None
return typedVar(OBJECT_HEADER_NAME_INFO, objHeader.getAddress() - objHeader.NameInfoOffset)
def getObjectNameInfoFromInfoMask(p):
"""
Get object name information from field NameInfoOffset of object header
"""
objHeader = 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 typedVar(OBJECT_HEADER_NAME_INFO, objHeader.getAddress() - offsetNameInfo)
# Select platform-specific function for getting name of object
getObjectNameInfo = None
try:
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 = typedVar( HANDLE_TABLE_ENTRY, entryHandle)
if (0xFFFFFFFE == HandleEntry.NextFreeTableEntry):
return 0
p = ptrPtr(HandleEntry.getAddress()) & 0xFFFFFFFFFFFFFFF8
if (0 == p):
return 0
if (containHeader):
objHeader = 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, HandleEntryIndex*HANDLE_VALUE_INC) )
else:
pCurrentType = getType(p)
if (addr64(objTypeAddr) == addr64(pCurrentType)):
lstObjects.append( ( p, HandleEntryIndex*HANDLE_VALUE_INC) )
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 = 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= <ADDR>] [type= <ADDR>] [headers= <BOOL>]
When (options can be specified in any order):
table= <ADDR> : table of handle address. F.e. address object table
contained in field ObjectTable structure nt!_EPROCESS
default: nt!_EPROCESS.ObjectTable of current processes
type= <ADDR> : address of object type. If specified (!= 0) then print
object of target type only.
default: 0
headers= <BOOL> : 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:
<link cmd=\"!py ntobj\">!py ntobj</link>
Print object table of current process
<link cmd=\"!py ntobj type= poi(nt!IoFileObjectType)\">!py ntobj type= poi(nt!IoFileObjectType)</link>
Print object table (only _FILE_OBJECT *) of current process
<link cmd=\"!py ntobj table= poi(poi(nt!PsInitialSystemProcess)+@@C++(#FIELD_OFFSET(nt!_EPROCESS,ObjectTable)))\">!py ntobj table= poi(poi(nt!PsInitialSystemProcess)+@@C++(#FIELD_OFFSET(nt!_EPROCESS,ObjectTable)))</link>
Print object table for SYSTEM process.
<link cmd=\"!py ntobj table= poi(nt!PspCidTable) headers= False type= poi(nt!PsProcessType)\">!py ntobj table= poi(nt!PspCidTable) headers= False type= poi(nt!PsProcessType)</link>
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
ObjectHandlePairs = [ (p[0], p[1]) for p in getListByHandleTable(tableHandles, objTypeAddr, containHeaders) ]
dprintln("%u objects:" % len(ObjectHandlePairs))
for objectHandle in ObjectHandlePairs:
objectType = getType(objectHandle[0])
if objectType in ViewObjectCommand:
viewCommand = ViewObjectCommand[objectType]
else:
viewCommand = "!object"
dprint("\t<link cmd=\"" + viewCommand + " 0x%x\">" % objectHandle[0] + viewCommand + " 0x%x</link>" % objectHandle[0], True)
objectName = buildObjectName(objectHandle[0])
if len(objectName):
dprint( ", name=`" + objectName + "'" )
elif nt.typedVar("_OBJECT_TYPE", getType(objectHandle[0])).TypeInfo.QueryNameProcedure:
dprint(", <i>custom</i> name", True)
else:
dprint(" , <_unnamed_>")
dprint(", <link cmd=\"!handle 0x%x\">!handle 0x%x</link>\n" % (objectHandle[1], objectHandle[1]), True)
dprint("\ttype is `" + getObjectName(objectType) + "' (<link cmd=\"!object 0x%x\">0x%x</link>)" % (objectType, objectType), True)
dprintln( "\n" )
if (1 == argc):
dprintln("\n<link cmd=\"!py " + sys.argv[0] + " ?\" \">View help for ntobj</link>", True)
if __name__ == "__main__":
main()