pykd

Форк
0
/
ntobj.py 
439 строк · 13.9 Кб
1
"""
2
Work with NT Object tree manager
3

4
  getType(p)
5
    Return object type address by object address
6

7
  getObjectNameInfo(p)
8
    Return typedVar of nt!_OBJECT_HEADER_NAME_INFO or None
9

10
  getObjectName(p)
11
    Return string of object name. If can not get name - empty string
12

13
  buildObjectName(p)
14
    Return string of full object name. If can not get name - empty string
15

16
  getListByHandleTable(tableHandles=None, objTypeAddr=0, containHeaders=True)
17
    Return list of objects from table of handles
18

19
  getListByDirectoryObject(p, objTypeAddr=0)
20
    Return list of objects from object directory
21

22
  getObjectByName(name, caseSensitive=False)
23
    Return address of object by full name. If error (f.e. not exist) - None
24

25
"""
26

27
from pykd import *
28

29
nt = module("nt")
30

31
# optimization
32
OBJECT_HEADER = nt.type("_OBJECT_HEADER")
33
HANDLE_TABLE_ENTRY = nt.type("_HANDLE_TABLE_ENTRY")
34
OBJECT_DIRECTORY_ENTRY = nt.type("_OBJECT_DIRECTORY_ENTRY")
35
OBJECT_HEADER_NAME_INFO = nt.type("_OBJECT_HEADER_NAME_INFO")
36

37

38

39
def getTypeWin7(p):
40
  """
41
  Get object header by object pointer
42
  Implementation for Win7+
43
  """
44
  objHeader = containingRecord(p, OBJECT_HEADER, "Body")
45
  tableTypeIndex = nt.ObTypeIndexTable
46
  return ptrPtr(tableTypeIndex + (ptrSize() * objHeader.TypeIndex))
47

48
def getTypeLegacy(p):
49
  """
50
  Get object header by object pointer
51
  Implementation for before Win7
52
  """
53
  objHeader = containingRecord(p, OBJECT_HEADER, "Body")
54
  return objHeader.Type
55

56
# Select platform-specific function for getting object header
57
# Select key body type: nt!CmpKeyObjectType or nt!CmKeyObjectType
58
if (ptrWord( nt.NtBuildNumber ) >= 7600):
59
  getType = getTypeWin7
60
  # _kcbObjectType = expr("poi(nt!CmKeyObjectType)")
61
else:
62
  getType = getTypeLegacy
63
  # _kcbObjectType = expr("poi(nt!CmpKeyObjectType)")
64

65

66
def getObjectNameInfoFromHeader(p):
67
  """
68
  Get object name information from field NameInfoOffset of object header
69
  """
70
  objHeader = containingRecord(p, OBJECT_HEADER, "Body")
71
  if (0 == objHeader.NameInfoOffset):
72
    return None
73
  return typedVar(OBJECT_HEADER_NAME_INFO, objHeader.getAddress() - objHeader.NameInfoOffset)
74

75
def getObjectNameInfoFromInfoMask(p):
76
  """
77
  Get object name information from field NameInfoOffset of object header
78
  """
79
  objHeader = containingRecord(p, OBJECT_HEADER, "Body")
80
  if (0 == (objHeader.InfoMask & 2)):
81
    return None
82
  offsetNameInfo = ptrByte( nt.ObpInfoMaskToOffset + (objHeader.InfoMask & 3) )
83
  if (0 == offsetNameInfo):
84
    return None
85
  return typedVar(OBJECT_HEADER_NAME_INFO, objHeader.getAddress() - offsetNameInfo)
86

87

88
# Select platform-specific function for getting name of object
89
getObjectNameInfo = None
90
try:
91
  OBJECT_HEADER.NameInfoOffset
92
  getObjectNameInfo = getObjectNameInfoFromHeader
93
except TypeException:
94
  getObjectNameInfo = getObjectNameInfoFromInfoMask
95

96

97
def getObjectName(p):
98
  """
99
  Get object name by name information
100
  """
101
  nameInfo = getObjectNameInfo(p)
102
  if (None == nameInfo):
103
    return ""
104
  return loadUnicodeString(nameInfo.Name.getAddress())
105

106
def buildObjectName(p):
107
  """
108
  Get object name by name information (parent directory handled)
109
  """
110
  objectFullName = ""
111

112
  nameInfo = getObjectNameInfo(p)
113
  if None == nameInfo:
114
    return objectFullName
115
  namePart = loadUnicodeString(nameInfo.Name.getAddress())
116
  if namePart != "\\":
117
    objectFullName = namePart + "\\" + objectFullName
118
  else:
119
    objectFullName = "\\" + objectFullName
120

121
  while (0 != nameInfo.Directory):
122
    p = nameInfo.Directory
123
    nameInfo = getObjectNameInfo(p)
124
    if (None == nameInfo):
125
      return "...\\" + objectFullName
126
    namePart = loadUnicodeString(nameInfo.Name.getAddress())
127
    if namePart != "\\":
128
      objectFullName = namePart + "\\" + objectFullName
129
    else:
130
      objectFullName = "\\" + objectFullName
131
  
132
  return objectFullName
133

134

135
HANDLE_VALUE_INC = 4
136
HT_PAGE_SIZE = 4096
137
HT_ENTRY_SIZE = (2 * ptrSize())
138
HT_LOWLEVEL_COUNT = HT_PAGE_SIZE // HT_ENTRY_SIZE
139
HT_MIDLEVEL_COUNT = HT_PAGE_SIZE // ptrSize()
140

141
def getListByHandleTable(tableHandles=None, objTypeAddr=0, containHeaders=True):
142
  """ 
143
  Build list of objects from target handle table
144

145
  Parameter objTypeAddr if not 0 used for getting object of specific type,
146
  otherwise get object of all types
147

148
  Parameter containHeaders used to interpret table contents: 
149
  if containHeaders=True then table contains pointers to nt!_OBJECT_HEADER, 
150
  otherwise table contains pointers to objects
151
  """
152

153
  def getByHandleEntry(entryHandle, containHeader):
154
    """
155
    Query object pointer by handle entry from handle table
156
    """
157
    if (0 == entryHandle):
158
      return 0
159
  
160
    HandleEntry = typedVar( HANDLE_TABLE_ENTRY, entryHandle)
161
    if (0xFFFFFFFE == HandleEntry.NextFreeTableEntry):
162
      return 0
163

164
    p = ptrPtr(HandleEntry.getAddress()) & 0xFFFFFFFFFFFFFFF8
165
    if (0 == p):
166
      return 0
167

168
    if (containHeader):
169
      objHeader = typedVar( OBJECT_HEADER, p)
170
      p = objHeader.Body.getAddress()
171
    return p
172

173
  def getListByHandleTableL0(pTableContent, nMaxHandleIndex, objTypeAddr, containHeaders):
174
    """
175
    Build list of objects from target handle table level 0
176
    """
177
    lstObjects = list()
178
    nTableLevel0Count = nMaxHandleIndex // HANDLE_VALUE_INC
179
    for HandleEntryIndex in range(nTableLevel0Count):
180

181
      pHandleEntry = pTableContent + (HT_ENTRY_SIZE * HandleEntryIndex)
182
      p = getByHandleEntry(pHandleEntry, containHeaders)
183
      if (0 == p):
184
        continue
185

186
      if (0 == objTypeAddr):
187
        lstObjects.append( ( p, HandleEntryIndex*HANDLE_VALUE_INC) )
188
      else:
189
        pCurrentType = getType(p)
190
        if (addr64(objTypeAddr) == addr64(pCurrentType)):
191
          lstObjects.append( ( p, HandleEntryIndex*HANDLE_VALUE_INC) )
192

193
    return lstObjects
194

195
  def getListByHandleTableL1(pTableContent, nMaxHandleIndex, objTypeAddr, containHeaders):
196
    """
197
    Build list of objects from target handle table level 1
198
    """
199
    lstObjects = list()
200
    nTableLevel1Count = (nMaxHandleIndex // HANDLE_VALUE_INC) // HT_LOWLEVEL_COUNT
201
    for Index in range(nTableLevel1Count):
202
      pTableLevel0 = ptrPtr(pTableContent + (Index * ptrSize()))
203
      lstObjects += getListByHandleTableL0(pTableLevel0, HT_LOWLEVEL_COUNT * HANDLE_VALUE_INC, objTypeAddr, containHeaders)
204

205
    return lstObjects
206

207
  def getListByHandleTableL2(pTableContent, nMaxHandleIndex, objTypeAddr, containHeaders):
208
    """
209
    Build list of objects from target handle table level 2
210
    """
211
    lstObjects = list()
212
    nTableLevel2Count = ((nMaxHandleIndex // HANDLE_VALUE_INC) // HT_LOWLEVEL_COUNT) // HT_MIDLEVEL_COUNT
213
    for Index in range(nTableLevel2Count):
214
      pTableLevel1 = ptrPtr(pTableContent + (Index * ptrSize()))
215
      lstObjects += getListByHandleTableL1(pTableLevel1, HT_MIDLEVEL_COUNT * HT_LOWLEVEL_COUNT * HANDLE_VALUE_INC, objTypeAddr, containHeaders)
216

217
    return lstObjects
218

219
  if (None == tableHandles):
220
    currProcess = nt.typedVar("_EPROCESS", getCurrentProcess())
221
    if (None == currProcess):
222
      dprintln("Get current process failed")
223
      return
224
    tableHandles = currProcess.ObjectTable
225

226
  tableHandles = nt.typedVar("_HANDLE_TABLE", tableHandles)
227
  nMaxHandleIndex = tableHandles.NextHandleNeedingPool & 0xFFFFFFFF
228
  nTableLevel = (tableHandles.TableCode & 3)
229
  pTableContent = tableHandles.TableCode - nTableLevel
230

231
  if (0 == nTableLevel):
232
    return getListByHandleTableL0(pTableContent, nMaxHandleIndex, objTypeAddr, containHeaders)
233
  elif (1 == nTableLevel):
234
    return getListByHandleTableL1(pTableContent, nMaxHandleIndex, objTypeAddr, containHeaders)
235
  elif (2 == nTableLevel):
236
    return getListByHandleTableL2(pTableContent, nMaxHandleIndex, objTypeAddr, containHeaders)
237

238
  dprintln("ERROR: Unknown handle table level: %u" % nTableLevel)
239
  return list()
240
  
241
 
242

243
NUMBER_HASH_BUCKETS = 37
244

245
def getListByDirectoryObject(p, objTypeAddr=0):
246
  """ 
247
  Build list of objects from object directory
248

249
  Parameter objTypeAddr if not 0 used for getting object of specific type,
250
  otherwise get object of all types
251
  """
252

253
  if getType(p) != ptrPtr( nt.ObpDirectoryObjectType ):
254
    return None
255

256
  result = list()
257

258
  for i in range(0, NUMBER_HASH_BUCKETS):
259
    bucket = ptrPtr( p + (i * ptrSize()) )
260
    while bucket:
261
      bucketVar = typedVar( OBJECT_DIRECTORY_ENTRY, bucket)
262
      if objTypeAddr and (getType(bucketVar.Object) ==  objTypeAddr):
263
        result.append(bucketVar.Object)
264
      elif (not objTypeAddr):
265
        result.append(bucketVar.Object)
266
      bucket = bucketVar.ChainLink
267

268
  return result
269

270
def getObjectByName(name, caseSensitive=False):
271
  """
272
  Query address of object by full name
273
  """
274

275
  def cmpCase(s1, s2): return s1 == s2
276
  def cmpNoCase(s1, s2): return s1.lower() == s2.lower()
277

278
  if not len(name):
279
    return None
280

281
  if name[0] != '\\':
282
    return None
283

284
  object = ptrPtr( nt.ObpRootDirectoryObject )
285

286
  cmpFunc = cmpNoCase
287
  if caseSensitive:
288
    cmpFunc = cmpCase
289

290
  while True:
291
    name = name[1:]
292
    if not len(name):
293
      break
294

295
    tok = name.find("\\")
296
    if -1 != tok:
297
      namePart = name[:tok]
298
      name = name[tok:]
299
    else:
300
      namePart = name
301

302
    if 0 == len(namePart):
303
      return None
304

305
    # FIXME: use name/index hash
306
    lstObjects = getListByDirectoryObject(object)
307
    if None == lstObjects:
308
      return None
309

310
    found = False
311
    for p in lstObjects:
312
      objName = getObjectName(p)
313
      if len(objName) and cmpFunc( namePart, objName ):
314
        object = p
315
        found = True
316
        break
317

318
    if not found:
319
      return None
320

321
    if -1 == tok:
322
      break
323

324
  return object
325

326

327
import sys
328

329
# Display object kd-command
330
ViewObjectCommand = {
331
  addr64( expr("poi(nt!IoFileObjectType)") )    : "!fileobj",
332
  addr64( expr("poi(nt!PsProcessType)") )       : "!process",
333
  addr64( expr("poi(nt!PsThreadType)") )        : "!thread",
334
  addr64( expr("poi(nt!IoDeviceObjectType)") )  : "!devobj",
335
  addr64( expr("poi(nt!SeTokenObjectType)") )   : "!token",
336
  # addr64( _kcbObjectType )                      : "!reg kcb", 
337
  addr64( expr("poi(nt!IoDriverObjectType)") )  : "!drvobj 7"
338
}
339

340
def main():
341
  """
342
  Print content of object table (handle table)
343
  
344
  Usage:  
345
    !py ntobj [table= <ADDR>] [type= <ADDR>] [headers= <BOOL>]
346

347
  When (options can be specified in any order):
348
    table= <ADDR>   : table of handle address. F.e. address object table 
349
                      contained in field ObjectTable structure nt!_EPROCESS
350
                      default: nt!_EPROCESS.ObjectTable of current processes
351

352
    type= <ADDR>    : address of object type. If specified (!= 0) then print
353
                      object of target type only.
354
                      default: 0
355

356
    headers= <BOOL> : table of handles format: contain pointer to object or to 
357
                      object header (nt!_OBJECT_HEADER): True or Flase 
358
                      F.e. poi(nt!PspCidTable) contains objects (processes and 
359
                      threads), and nt!_EPROCESS.ObjectTable contains headers
360
                      default: True
361
  Examples:  
362
  <link cmd=\"!py ntobj\">!py ntobj</link>
363
  Print object table of current process
364

365
  <link cmd=\"!py ntobj type= poi(nt!IoFileObjectType)\">!py ntobj type= poi(nt!IoFileObjectType)</link>
366
  Print object table (only _FILE_OBJECT *) of current process
367
  
368
  <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>
369
  Print object table for SYSTEM process.
370

371
  <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>
372
  Print all process objects from nt!PspCidTable
373
  """
374

375
  if not isWindbgExt():
376
    print "Script is launch out of WinDBG"
377
    return
378

379
  if not isKernelDebugging():
380
    dprintln("This script for kernel debugging only")
381
    return
382

383
  argc = len(sys.argv)
384

385
  if (2 == argc) and ("help" == sys.argv[1] or "?" == sys.argv[1]):
386
    dprintln(main.__doc__, True)
387
    return
388

389
  if (0 == (argc % 2)):
390
    dprintln("Invalid number of comand line arguments")
391
    dprintln(main.__doc__, True)
392
    return
393

394
  tableHandles = None
395
  objTypeAddr = 0
396
  containHeaders = True
397

398
  for i in range(1, argc, 2):
399
    if ("table=" == sys.argv[i]):
400
      tableHandles = expr(sys.argv[i + 1])
401
    elif ("type=" == sys.argv[i]):
402
      objTypeAddr = expr(sys.argv[i + 1])
403
    elif ("headers=" == sys.argv[i]):
404
      containHeaders = ("True" == sys.argv[i + 1])
405
    else:
406
      dprintln("Unknown option `" + sys.argv[i] + "'")
407
      dprintln(main.__doc__, True)
408
      return
409

410
  ObjectHandlePairs = [ (p[0], p[1]) for p in getListByHandleTable(tableHandles, objTypeAddr, containHeaders) ]
411

412
  dprintln("%u objects:" % len(ObjectHandlePairs))
413
  for objectHandle in ObjectHandlePairs:
414
    objectType = getType(objectHandle[0])
415
    if objectType in ViewObjectCommand:
416
      viewCommand = ViewObjectCommand[objectType]
417
    else:
418
      viewCommand = "!object"
419

420
    dprint("\t<link cmd=\"" + viewCommand + " 0x%x\">" % objectHandle[0] + viewCommand + " 0x%x</link>" % objectHandle[0], True)
421
    objectName = buildObjectName(objectHandle[0])
422
    if len(objectName):
423
      dprint( ", name=`" + objectName + "'" )
424
    elif nt.typedVar("_OBJECT_TYPE", getType(objectHandle[0])).TypeInfo.QueryNameProcedure:
425
      dprint(", <i>custom</i> name", True)
426
    else:
427
      dprint(" , <_unnamed_>")
428

429
    dprint(", <link cmd=\"!handle 0x%x\">!handle 0x%x</link>\n" % (objectHandle[1], objectHandle[1]), True)
430

431
    dprint("\ttype is `" + getObjectName(objectType) + "' (<link cmd=\"!object 0x%x\">0x%x</link>)" % (objectType, objectType), True)
432

433
    dprintln( "\n" )
434

435
  if (1 == argc):
436
    dprintln("\n<link cmd=\"!py " + sys.argv[0] + " ?\" \">View help for ntobj</link>", True)
437

438
if __name__ == "__main__":
439
  main()
440

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.