Package Libs ::
Module libheap
|
|
1
2 """
3 Immunity Heap API for Immunity Debugger
4
5 (c) Immunity, Inc. 2004-2006
6
7
8 U{Immunity Inc.<http://www.immunityinc.com>} Debugger Heap Library for python
9
10
11 """
12
13 __VERSION__ = '1.3'
14
15 import immutils
16 import struct
17 import string
18 from UserList import UserList
19 HEAP_MAX_FREELIST = 0x80
20 DEBUG = False
21
22
23
25 - def __init__(self, imm, heapddr = 0, restore = False):
26 """
27 Windows 32 Heap Class
28
29 @rtype: PHEAP object
30 """
31 self.imm = imm
32 self.address = heapddr
33 self.chunks = []
34 self.restore = restore
35 self.Segments = []
36 self.HeapCache = None
37 self.Lookaddr = None
38 self.Lookaside = None
39
40 if heapddr:
41 self._grabHeap()
42
44 try:
45 heaps = self.imm.readMemory( self.address, 0x588 )
46 except WindowsError, msg:
47 raise Exception, "Failed to get heap at address : 0x%08x" % heapaddr
48
49 index = 0x8
50 (self.Signature, self.Flags, self.ForceFlags, self.VirtualMemoryThreshold,\
51 self.SegmentReserve, self.SegmentCommit, self.DeCommitFreeBlockThreshold, self.DeCommitTotalBlockThreshold,\
52 self.TotalFreeSize, self.MaximumAllocationSize, self.ProcessHeapListIndex, self.HeaderValidateLength,\
53 self.HeaderValidateCopy,self.NextAvailableTagIndex, self.MaximumTagIndex, self.TagEntries, \
54 self.UCRSegments, self.UnusedUnCommittedRanges, self.AlignRound, self.AlignMask) =\
55 struct.unpack("LLLLLLLLLLHHLHHLLLLL", heaps[ index : index + (0x50-8) ])
56
57 index+= 0x50-8
58 self.VirtualAllocedBlock = struct.unpack("LL", heaps[ index : index + 8 ])
59 index+=8
60 self._Segments = struct.unpack("L" * 64, heaps[ index: index+ 64*4 ])
61 index+=64*4
62 self.FreeListInUseLong = struct.unpack("LLLL" , heaps[ index : index + 16 ])
63 index+=16
64 (self.FreeListInUseTerminate,self.AllocatorBackTraceIndex) = struct.unpack("HH", heaps[ index : index + 4 ])
65 index+=4
66 (self.Reserved1, self.LargeBlocksIndex)= struct.unpack("LL", heaps[ index : index + 8 ])
67 index+=8
68 if self.LargeBlocksIndex:
69 self.HeapCache = HeapCache( self.imm, self.LargeBlocksIndex)
70
71 self.PseudoTagEntries= struct.unpack("L", heaps[ index : index + 4])
72 index+=4
73 self.FreeList=[]
74
75
76 for a in range(0, 128):
77 free_entry = []
78
79 (next, prev) = struct.unpack("LL", heaps[ index + a*8 : index + a*8 + 8 ])
80
81 free_entry.append((self.address + index+ a * 8, prev, next) )
82 base_entry = self.address + index + a * 8
83
84
85 tmp = 0
86 while next != base_entry:
87 if tmp == next:
88 break
89 tmp = next
90 try:
91 (next, prev) = struct.unpack("LL", self.imm.readMemory(next, 0x8))
92 except:
93 break
94
95 free_entry.append( (tmp, prev,next) )
96
97 self.FreeList.append(free_entry)
98
99 index+=256*4
100 (self.LockVariable, self.CommitRoutine, self.Lookaddr, self.LookasideLockCount)=\
101 struct.unpack("LLLL", heaps[index:index+16])
102
103 if self.Lookaddr:
104 self.Lookaside = PHeapLookaside(self.imm, self.Lookaddr)
105
106
107
108 for a in range(0, 64):
109 if self._Segments[a] == 0x0:
110 break
111 s = Segment( self.imm, self._Segments[a] )
112 self.Segments.append( s )
113
114
115 if self.restore:
116 self.getRestoredChunks( s.BaseAddress )
117 else:
118 self.getChunks( s.BaseAddress )
119 for idx in s.Pages:
120 self.imm.log("> 0x%08x" % idx)
121 if self.restore:
122 self.getRestoredChunks( idx )
123 else:
124 self.getChunks( idx )
125
127 if not self.Lookaside:
128 return None
129
130 if not uselog:
131 uselog = imm.log
132
133 for ndx in range(0, len(self.Lookaside)):
134 entry = self.Lookaside[ndx]
135 if not entry.isEmpty():
136
137 uselog("(%02x) Depth: %d: MaxDepth: %d FreeMiss: %d" % (ndx, entry.Depth, entry.MaxDepth, entry.FreeMiss), address = entry.addr)
138 for a in entry.getList():
139 uselog(" > 0x%08x (0x%03x)" % (a, ndx * 8), address = a)
140
142 if num == 0:
143 return '0'*32
144 if num < 0 :
145 return ''
146 ret = []
147
148 for a in range(32,-1, -1):
149 ret.append( str(num&0x1) )
150 num = num >> 1
151 if not swap:
152 ret.reverse()
153 return "".join(ret)
154
156 ret = []
157 uselog("HeapCache Bitmask:")
158 for a in range(0, self.HeapCache.NumBuckets/32/4):
159 ret.append(self.decimal2binary(self.HeapCache.Bitmask[a]))
160
161 if a%2:
162 uselog( " %s" % str(" ".join(ret) ) )
163 ret = []
164
165 for a in range(0, self.HeapCache.NumBuckets):
166 if self.HeapCache.Buckets[a]:
167 uselog("HEAP_CACHE[%04x] = 0x%08x" % (a+0x80, self.HeapCache.Buckets[a]), address = self.HeapCache.Buckets[a])
168
170 """
171 Print the Heap's FreeListInUse bitmask
172
173 @type uselog: Log Function
174 @param uselog: (Optional, Def: Log Window) Log function that display the information
175 """
176 tbl= ["FreeListInUse %s %s"% (self.decimal2binary(self.FreeListInUseLong[0]), self.decimal2binary(self.FreeListInUseLong[1])),\
177 " %s %s" % (self.decimal2binary(self.FreeListInUseLong[2]), self.decimal2binary(self.FreeListInUseLong[3]))]
178 if uselog:
179 for a in tbl:
180 uselog(a)
181 return tbl
182
184 """
185 Print the Heap's FreeList
186
187 @type uselog: Log Function
188 @param uselog: (Optional, Def: Log Window) Log function that display the information
189 """
190 log = self.imm.log
191 if uselog:
192 log = uselog
193 for a in range(0, 128):
194 entry= self.FreeList[a]
195 e=entry[0]
196
197 log("[%03x] 0x%08x -> [ 0x%08x | 0x%08x ] " % (a, e[0], e[1], e[2]), address = e[0])
198 for e in entry[1:]:
199 try:
200 sz = self.get_chunk( e[0] - 8 ).size
201 except:
202 sz = 0
203 log(" 0x%08x -> [ 0x%08x | 0x%08x ] (%08x)" % (e[0], e[1], e[2], sz), address= e[0])
204 return 0x0
205
206
208 """
209 Enumerate Chunks of the current heap using a restore heap
210
211 @type address: DWORD
212 @param address: Address where to start getting chunks
213
214 @rtype: List of win32heapchunks
215 @return: Chunks
216 """
217
218 imm = self.imm
219
220 oldheap = imm.getKnowledge("saved_heap_%08x" % self.address)
221 if not oldheap:
222 imm.log("Coudln't use restore mode: No saved Heap")
223 return self.getChunks(address)
224
225 ptr = address
226
227 backchunk = self.get_chunk(imm, ptr, self.address)
228
229 backchunk.size = backchunk.psize
230 backchunk.usize = backchunk.upsize
231
232 while 1:
233
234 try:
235 c = self.get_chunk(imm, ptr, self.address)
236 except:
237 return self.chunks
238
239
240 next = ptr + c.usize
241
242 try:
243 sizes = imm.readLong( next )
244 previous = (sizes>>16) & 0xffff
245 except Exception:
246 previous = 0
247
248
249
250
251
252
253
254 if (not c.size) or (c.size != previous and not c.istop()) or (not previous and not c.istop()) or (backchunk.size != c.psize) :
255 restoredchunk = oldheap.findChunkByAddress(ptr)
256
257 if restoredchunk:
258 c = restoredchunk
259 c.setRestored()
260 next = ptr + c.usize
261 ptr = next
262 self.chunks.append(c)
263 backchunk = c
264
265
266 if c.istop() or c.size == 0:
267 break
268
269 backchunk = c
270
271 return self.chunks
272
274 """
275 Find a Chunks by its address
276
277 @type address: DWORD
278 @param address: Address to search for
279
280 @rtype: win32heapchunks
281 @return: Chunk
282 """
283
284 for a in self.chunks:
285 if a.addr == addr:
286 return a
287 return None
288
289 - def getChunks(self, address, size = 0xffffffffL):
290 """
291 Enumerate Chunks of the current heap
292
293 @type address: DWORD
294 @param address: Address where to start getting chunks
295
296 @type size: DWORD
297 @param size: (Optional, Def: All) Amount of chunks
298
299 @rtype: List of win32heapchunks
300 @return: Chunks
301 """
302 imm = self.imm
303
304 ptr = address
305
306 while size:
307
308 try:
309 c = self.get_chunk( ptr )
310 except Exception, msg:
311 imm.log("Failed to grab chunks> " + str(msg) )
312 return self.chunks
313
314 self.chunks.append(c)
315
316
317 ptr+= c.usize
318 if c.istop() or c.size == 0:
319 break
320 size -= 1
321
322 return self.chunks
323
325 return win32heapchunk(self.imm, addr, self)
326
329 self.address = addr
330 addr += 8
331 imm.log(" segment 0x%08x " % addr)
332 mem = imm.readMemory(addr, 0x34)
333
334 (self.Signature, self.Flags, self.Heap, self.LargestUnCommitedRange, self.BaseAddress,\
335 self.NumberOfPages, self.FirstEntry, self.LastValidEntry, self.NumberOfUnCommittedPages,\
336 self.NumberOfUnCommittedRanges, self.UnCommittedRanges, self.AllocatorBackTraceIndex,\
337 self.Reserved, self.LastEntryInSegment) = struct.unpack("LLLLLLLLLLLHHL", mem)
338 if DEBUG:
339 imm.log("SEGMENT: 0x%08x Sig: %x" % (self.address, self.Signature), address = self.address )
340 imm.log("Heap: %08x LargetUncommit %08x Base: %08x" % (self.Heap, self.LargestUnCommitedRange, self.BaseAddress))
341 imm.log("NumberOfPages %08x FirstEntry: %08x LastValid: %08x" % (self.NumberOfPages, self.FirstEntry, self.LastValidEntry))
342 imm.log("Uncommited: %08x" % self.UnCommittedRanges)
343 self.Pages = []
344 if self.UnCommittedRanges:
345 i = 0
346 addr = self.UnCommittedRanges
347 while addr != 0:
348 mem = imm.readMemory( addr, 0x10 )
349 ( C_Next, C_Addr, C_Size, C_Filler) = struct.unpack( "LLLL", mem )
350 if DEBUG:
351 imm.log( ">> Memory: 0x%08x Address: 0x%08x (a: %08x) Size: %x" % ( addr, C_Next, C_Addr,C_Size) )
352 self.Pages.append( C_Addr + C_Size )
353 addr = C_Next
354
356 LFH = None
357 - def __init__(self, imm, heapddr = 0, restore = False):
359
361 try:
362 heapmem = self.imm.readMemory( self.address + 8 , 0x120 )
363 except WindowsError, msg:
364 raise Exception, "Failed to get heap at address : 0x%08x" % heapaddr
365 index = 8
366 (self.SegmentSignature, self.SegmentFlags, self.SegmentListEntry_Flink, self.SegmentListEntry_Blink, self.Heap, self.BaseAddress, self.NumberOfPages, self.FirstEntry, self.LastValidEntry, self.NumberofUncommitedPages, self.NumberofUncommitedRanges, self.SegmentAllocatorBackTraceIndex, self.Reserved, self.UCRSegmentList_Flink, self.UCRSegmentList_Blink, self.Flags, self.ForceFlags, self.CompatibilityFlags, self.EncodeFlagMask, self.EncodingKey, self.EncodingKey2, self.PointerKey, self.Interceptor_debug, self.VirtualMemoryThreshold, self.Signature, self.SegmentReserve, self.SegmentCommit, self.DeCommitThresholdBlock, self.DeCommitThresholdTotal, self.TotalFreeSize, self.MaxAllocationSize, self.ProcessHeapsListIndex, self.HeaderValidateLength, self.HeaderValidateCopy, self.NextAvailableTagIndex, self.MaximumTagIndex, self.TagEntries, self.UCRList_Flink, self.UCRList_Blink, self.AlignRound, self.AlignMask, self.VirtualAlloc_Flink, self.VirtualAlloc_Blink, self.SegmentList_Flink, self.SegmentList_Blink, self.AllocatorBackTraceIndex, self.NonDedicatedListLenght, self.BlocksIndex, self.UCRIndex, self.PseudoTagEntries, self.FreeList_Flink, self.FreeList_Blink, self.LockVariable, self.CommitRoutine, self.FrontEndHeap, self.FrontHeapLockCount, self.FrontEndHeapType, self.TotalMemoryReserved, self.TotalMemoryCommited, self.TotalMemoryLargeUCR, self.TotalSizeInVirtualBlocks, self.TotalSegments, self.TotalUCRs, self.CommitOps, self.DecommitOps, self.LockAcquires, self.LockCollisions, self.CommitRate, self.DeCommitRate, self.CommitFailures, self.InBlockCommitFailures, self.CompactHeapCalls, self.CompactedUCRs, self.InBlockDecommits, self.InBlockDecommitSize, self.TunningParameters) = struct.unpack("L" * 11 + "HH" + "L" *18 + "HHLHH" + "L" * 19 + "HH" + "L" * 19, heapmem)
367 head = self.address
368 addr = self.SegmentListEntry_Flink
369 self.Segments.append( VistaSegment( self.imm, self.address) )
370 self.getChunks( self.address )
371
372 if addr !=0 :
373 while head != (addr& ~0xff):
374 self.Segments.append( VistaSegment(self.imm, addr - 0x10 ) )
375 self.getChunks( addr & ~0xff )
376 addr = self.imm.readLong( addr )
377 else:
378 self.imm.log("Error: HEAP_SEGMENT address is 0x00000000")
379
380 self.getBlocks( self.BlocksIndex )
381 if self.FrontEndHeap:
382 if self.imm.isWin7:
383 self.LFH = Win7LFHeap(self.imm, self.FrontEndHeap)
384 else:
385 self.LFH = LFHeap( self.imm, self.FrontEndHeap )
386
387
389 self.blocks = []
390 addr = startaddr
391
392 while addr:
393 block = Blocks( self.imm, addr )
394 self.blocks.append( block )
395 block.FreeList=[]
396
397
398 num_of_freelists = block.ArraySize - block.BaseIndex
399
400 memory = self.imm.readMemory( block.ListHints, num_of_freelists * 8 )
401
402
403 if block.ListsInUseUlong:
404 block.setFreeListInUse( struct.unpack("LLLL", self.imm.readMemory( block.ListsInUseUlong, 4*4 )) )
405
406
407 for a in range(0, num_of_freelists):
408 free_entry = []
409
410 (fwlink, heap_bucket) = struct.unpack("LL", memory[a *8 : a *8 + 8] )
411 if fwlink:
412 try:
413 (next, prev) = struct.unpack("LL", self.imm.readMemory( fwlink, 8) )
414 except:
415 next, prev = (0,0)
416 self.imm.log("Error with 0x%x" % fwlink)
417 free_entry.append( (fwlink, next, prev) )
418 base_entry = fwlink
419
420 while next and next != base_entry:
421 tmp = next
422 try:
423 chunk = win32vistaheapchunk( self.imm, next - 8, self )
424 except Exception:
425 break
426 self.imm.log("size: %d addr: 0x%08x 0x%08x 0x%08x" % (chunk.size, next-8, chunk.nextchunk, chunk.prevchunk))
427
428 if a == 127:
429 if chunk.size <= a:
430 break
431 else:
432 if chunk.size != a:
433 break
434
435 next = chunk.nextchunk
436 free_entry.append( (tmp, chunk.nextchunk, chunk.prevchunk) )
437
438 else:
439 free_entry = [ (fwlink, 0x0, 0x0) ]
440
441
442
443 block.FreeList.append(free_entry)
444
445 addr = block.ExtendedLookup
446
448 return win32vistaheapchunk(self.imm, addr, self)
449
451 """
452 Print the Heap's FreeList
453
454 @type uselog: Log Function
455 @param uselog: (Optional, Def: Log Window) Log function that display the information
456 """
457 log = self.imm.log
458 if uselog:
459 log = uselog
460 for block in self.blocks:
461 f = block.FreeListInUse
462 log("** Block 0x%08x BaseIndex: %d ArraySize: %d ExtraItem: %d **" % ( block.address, block.BaseIndex, block.ArraySize, block.ExtraItem ) )
463 if DEBUG:
464 log("** ListInUse: 0x%08x" % block.ListsInUseUlong)
465 if f:
466 log("FreeListInUse: %s %s" % (immutils.decimal2binary(f[0]),\
467 immutils.decimal2binary(f[1]) ) )
468 log(" %s %s" % (immutils.decimal2binary(f[2]),\
469 immutils.decimal2binary(f[3]) ) )
470
471 for a in range(0, 128):
472 entry= block.FreeList[a]
473 e=entry[0]
474 if e[0]:
475 log("[%03d] 0x%08x -> [ 0x%08x | 0x%08x ] " % (a, e[0], e[1], e[2]), address = e[0])
476 for e in entry[1:]:
477 log(" 0x%08x -> [ 0x%08x | 0x%08x ] " % (e[0], e[1], e[2]), address= e[0])
478 return 0x0
479
482
483 self.address = addr
484 addr += 8
485 mem = imm.readMemory(addr+8, 0x38)
486
487 (self.SegmentSignature, self.SegmentFlags, self.SegmentListEntry_Flink, self.SegmentListEntry_Blink,\
488 self.Heap, self.BaseAddress, self.NumberOfPages, self.FirstEntry, self.LastValidEntry,\
489 self.NumberofUncommitedPages, self.NumberofUncommitedRanges, self.SegmentAllocatorBackTraceIndex,\
490 self.Reserved,self.UCRSegmentList_Flink,self.UCRSegmentList_Blink)=\
491 struct.unpack( "L" * 11 + "HH" + "L" *2, mem)
492 self.Entry = win32vistaheapchunk(imm, addr)
493
494
495
498 mem = imm.readMemory( addr, 0x310 )
499 if not mem:
500 raise Exception, "Can't read Low Fragmentation Heap at 0x%08x" % addr
501 index = 0
502 self.address = addr
503 imm.log("Low Fragmentation Heap: 0x%08x" % addr)
504 (self.Lock, self.field_4, self.field_8, self.field_c,\
505 self.field_10, field_14, self.SubSegmentZone_Flink,
506 self.SubSegmentZone_Blink, self.ZoneBlockSize,\
507 self.Heap, self.SegmentChange, self.SegmentCreate,\
508 self.SegmentInsertInFree, self.SegmentDelete, self.CacheAllocs,\
509 self.CacheFrees, self.SizeInCache, self.Padding) = struct.unpack("L" * 0x12, mem[ index : index +0x48 ])
510
511 index += 0x48
512
513
514 self.RunInfo = HeapBucketRunInfo(addr + index, mem[index : index + 8])
515 index += 0x8
516
517 self.UserBlockCache = []
518 for a in range(0,12):
519 umc = UserMemoryCache( addr + index, mem[ index : index + 0x10] )
520 index+= 0x10
521 self.UserBlockCache.append( umc )
522 self.Buckets = []
523 for a in range(0, 128):
524 entry = mem[ index : index + 4 ]
525 b = Bucket( addr + index, entry)
526 index = index + 4
527 self.Buckets.append( b )
528
529 self.LocalData = LocalData(imm, addr + index )
530
533 self.address = addr
534 (self.Bucket, self.RunLength) = struct.unpack("LL", mem[ 0 : 0x8 ])
535
536
539 mem = imm.readMemory( addr, 0x300 )
540 if not mem:
541 raise Exception, "Can't read Low Fragmentation Heap at 0x%08x" % addr
542 index = 0
543 self.address = addr
544 imm.log("Low Fragmented Heap: 0x%08x" % addr)
545 (self.Lock, self.field_4, self.field_8, self.field_c,\
546 self.field_10, field_14, self.SubSegmentZone_Flink,
547 self.SubSegmentZone_Blink, self.ZoneBlockSize,\
548 self.Heap, self.SegmentChange, self.SegmentCreate,\
549 self.SegmentInsertInFree, self.SegmentDelete, self.CacheAllocs,\
550 self.CacheFrees) = struct.unpack("L" * 0x10, mem[ index : index +0x40 ])
551 index += 0x40
552 self.UserBlockCache = []
553 for a in range(0,12):
554 umc = UserMemoryCache( addr + index, mem[ index : index + 0x10] )
555 index+= 0x10
556 self.UserBlockCache.append( umc )
557 self.Buckets = []
558 for a in range(0, 128):
559 entry = mem[ index : index + 4 ]
560 b = Bucket( addr + index, entry)
561 index = index + 4
562 self.Buckets.append( b )
563
564 self.LocalData = LocalData(imm, addr + index )
565
568 self.address = addr
569
570 mem = imm.readMemory( addr, 0x18 + 0x68*128 )
571 (self.Next, self.Depth, self.Seq, self.CtrZone, self.LowFragHeap,\
572 self.Sequence1, self.Sequence2) = struct.unpack("LHHLLLL", mem[:0x18])
573 index = 0x18
574 self.SegmentInfo = []
575 for a in range(0, 128):
576 l = LocalSegmentInfo( imm, self.address + index,\
577 mem[ index : index + 0x68] )
578 index+= 0x68
579 self.SegmentInfo.append( l )
580
581
583 - def __init__(self, imm, addr, mem = ""):
584 self.address = addr
585 self.SubSegment = []
586 self.imm = imm
587 if not mem:
588 mem = imm.readMemory( self.address, 0x68 )
589
590 (self.Hint, self.ActiveSubsegment) = struct.unpack("LL", mem[0:8] )
591 index = 8
592 self.CachedItems = struct.unpack("L" * 0x10, mem[ index : index + 0x10*4])
593 index += 0x10*4
594 (self.Next, self.Depth, self.Seq, self.TotalBlocks,\
595 self.SubSegmentCounts, self.LocalData, self.LastOpSequence,\
596 self.BucketIndex, self.LastUsed, self.Reserved) = struct.unpack("LHHLLLLHHL", mem[index: index + 0x20])
597
598 if self.Hint:
599 self.SubSegment.append( self.getSubSegment( self.Hint, "Hint" ) )
600 if self.ActiveSubsegment and self.ActiveSubsegment != self.Hint:
601 self.SubSegment.append( self.getSubSegment( self.ActiveSubsegment, "ActiveSS") )
602 for a in range( 0, len(self.CachedItems) ):
603 item = self.CachedItems[a]
604 if item and item not in (self.Hint, self.ActiveSubsegment):
605 self.SubSegment.append( self.getSubSegment( item, "Cache_%02x" % a) )
606
607
608
611
613 - def __init__(self, imm, address, type=""):
614 self.address = address
615 self.type = type
616 self.chunks = []
617 mem = imm.readMemory( address, 0x20 )
618 (self.LocalInfo, self.UserBlocks, self.AggregateExchg,\
619 self.Aggregate_Sequence, self.BlockSize, self.Flags,\
620 self.BlockCount, self.SizeIndex, self.AffinityIndex,
621 self.Next, self.Lock) = struct.unpack("LLLLHHHBBLL", mem)
622 self.Offset = self.AggregateExchg >> 0xD
623 self.Offset = self.Offset & 0x7FFF8
624 self.Depth = self.AggregateExchg & 0xFFFF
625
626 if self.UserBlocks:
627 self.UserDataHeader = self.getUserData( imm, self.UserBlocks )
628
629
630 list = self.grabBusyList( imm, self.UserBlocks, self.Offset, self.Depth)
631 self.chunks = self.getChunks( imm, self.UserBlocks + self.UserDataHeader.getSize(), list )
632
634 list = {}
635 i = 1
636 for a in range(0, depth):
637 address = base_addr + offset
638 dword = imm.readLong( address + 8 )
639 offset = dword & 0xFFFF
640 offset *=8
641 list[ address ] = a + 1
642 return list
643
646
648
649 addr = address
650 chunks = []
651 for a in range(0, self.BlockCount):
652 c = win32vistaheapchunk(imm, addr, BlockSize = self.BlockSize)
653 s = "B"
654 if list.has_key(addr):
655 c.setFreeOrder( list[addr] )
656 s = "F(%02d)" % list[addr]
657 if DEBUG:
658 imm.log("Chunk size: 0x%x lfhflag: 0x%x %s" % ( self.BlockSize, c.lfhflags, s ), address = addr)
659 addr += self.BlockSize*8
660 chunks.append( c )
661 return chunks
662
665 self.address = addr
666 mem = imm.readMemory(addr, 0x10)
667 (self.SubSegment, self.Reserved, self.SizeIndex, self.Signature) =\
668 struct.unpack("LLLL", mem)
671
674 self.address = addr
675 (self.BlockUnits, self.SizeIndex, Flag) =\
676 struct.unpack("HBB", mem[:4])
677
678 self.UseAffinity = Flag & 0x1
679 self.DebugFlags = (Flag >1) & 0x3
680
683 self.addr = addr
684 self.fmt = "LLQQQLLQQLLLLLLLLLLQ"
685 size = struct.calcsize(self.fmt)
686 mem = imm.readMemory(addr, size)
687 imm.log(" 0x%08x - %d - %d" % (addr, size, len(mem)) )
688 (self.NumBuckets, self.CommittedSize, self.CounterFrequency, self.AverageAllocTime, self.AverageFreeTime,
689 self.SampleCounter, self.field_24, self.AllocTimeRunningTotal, self.FreeTimeRunningTotal, self.AllocTimeCount, self.FreeTimeCount,
690 self.Depth, self.HighDepth, self.LowDepth, self.Sequence, self.ExtendCount, self.CreateUCRCount, self.LargestHighDepth, self.HighLowDifference,
691 self.pBitmap) = struct.unpack(self.fmt, mem)
692
693 addr += size
694 self.Buckets = struct.unpack("L"* self.NumBuckets, imm.readMemory(addr, self.NumBuckets*4))
695 addr += self.NumBuckets*4
696 self.Bitmask = struct.unpack("L"* (self.NumBuckets/32/4), imm.readMemory(addr, self.NumBuckets/32))
697
698 for a in range(0, len(self.Buckets)):
699 if self.Buckets[a]:
700 imm.log("HEAP_CACHE[%04x] = 0x%08x" % (a+0x80, self.Buckets[a]) )
701
702
703
704
705
706
707
708
711 self.address = addr
712 (self.Next, self.Depth, self.Sequence, self.AvailableBlocks,\
713 self.Reserved) = struct.unpack("LHHLL", mem[ 0 : 16 ])
714
717 mem = imm.readMemory( addr, 0x24 )
718 if not mem:
719 raise Exception, "Can't read Block at 0x%08x" % addr
720 self.address = addr
721 self.FreeListInUse = None
722 self.FreeList = []
723 (self.ExtendedLookup, self.ArraySize, self.ExtraItem, self.ItemCount,
724 self.OutOfRangeItems, self.BaseIndex, self.ListHead,\
725 self.ListsInUseUlong, self.ListHints) =\
726 struct.unpack( "L" * 9, mem )
727
729 self.FreeListInUse = inuse
730
732 self.FreeList = flist
733
734 SHOWCHUNK_FULL = 0x1
735 CHUNK_ANALIZE = 0x2
737 FLAGS = { 'EXTRA PRESENT':('E', 0x2), 'FILL PATTERN':('FP', 0x4),\
738 'VIRTUAL ALLOC': ('V', 0x8), 'TOP': ('T', 0x10),
739 'FFU1':('FFU1',0x20), 'FFU2': ('FFU2', 0x40),\
740 'NO COALESCE':('NC', 0x80) }
741 BUSY = ('BUSY', ('B', 0x1))
742 - def __init__(self, imm, addr, heap = None):
743 """ Win32 Chunk """
744 self.imm = imm
745
746 self.restored = False
747 self.Lookaside = False
748
749 if heap:
750 self.heap_addr = heap.address
751 else:
752 self.heap_addr = 0
753 self.nextchunk=0
754 self.prevchunk=0
755 self.addr = addr
756 try:
757 dword1 = self.imm.readLong(addr)
758 dword2 = self.imm.readLong(addr+4)
759 except Exception:
760 raise Exception, "Failed to read chunk at address: 0x%08x" % addr
761
762 self._get( dword1, dword2, addr, heap)
763
764 - def _get(self, size, flags, addr, heap):
765 self.size = size & 0xffff
766 self.usize = self.size * 8
767
768 self.psize = ( size >> 16 ) & 0xffff
769 self.upsize = self.psize * 8
770
771 self.field4 = flags & 0xff
772 self.flags = (flags >> 8) & 0xff
773 self.other = (flags >> 16) & 0xffff
774 mem_addr = addr + 8
775 if not (self.flags & self.BUSY[1][1] ):
776
777 if self.flags & self.FLAGS['VIRTUAL ALLOC'][1]:
778 pass
779 else:
780 try:
781 self.nextchunk= self.imm.readLong(addr+8)
782 self.prevchunk= self.imm.readLong(addr+12)
783 except WindowsError:
784 raise Exception, "Failed to read chunk at address: 0x%08x" % addr
785
786 mem_addr +=8
787 else:
788 if self.size < 0x80:
789 if heap:
790 if heap.Lookaside:
791 if addr in heap.Lookaside[self.size].getList():
792 self.Lookaside = True
793
794 self.data_addr = mem_addr
795 self.data_size = self.upsize - (addr - mem_addr)
796
797 try:
798 self.sample = self.imm.readMemory(self.data_addr, 0x10)
799 except WindowsError:
800 raise Exception, "Failed to read chunk at address: 0x%08x" % addr
801
802 self.properties= {'size': self.usize, 'prevsize': self.upsize, 'field4': self.field4,\
803 'flags':self.flags, 'other':self.other, 'address':self.addr,\
804 'next': self.nextchunk, 'prev': self.prevchunk}
805
808
811
812 - def get(self, what):
813 try:
814 return self.properties[string.lower(what)]
815 except KeyError:
816 return None
817
818 - def printchunk(self, uselog= None, option=0, dt= None):
819 ret = []
820 if self.isRestore():
821 restore = "<R>"
822 else:
823 restore = ""
824 ret.append((self.addr, "0x%08x> " % self.addr + "size: 0x%08x (%04x) prevsize: 0x%08x (%04x) %s" % (self.usize, self.size, \
825 self.upsize, self.psize, restore) ))
826 ret.append((self.addr, " heap: *0x%08x* flags: 0x%08x (%s)" % (self.heap_addr, self.flags,\
827 self.getflags(self.flags))))
828
829
830 if not (self.flags & self.BUSY[1][1]):
831 ret.append((self.addr, " next: 0x%08x prev: 0x%08x" % (self.nextchunk, self.prevchunk)))
832 if option & SHOWCHUNK_FULL:
833 dump = immutils.hexdump(self.sample)
834 for a in range(0, len(dump)):
835 if not a:
836 ret.append((self.addr, " (%s %s)" % (dump[a][0], dump[a][1])))
837 if dt:
838 result = dt.Discover(self.imm.readMemory(self.data_addr, self.data_size), self.data_addr)
839
840 for obj in result:
841 msg = obj.Print()
842 ret.append((obj.address, " > %s: %s " % (obj.name, msg) ))
843
844
845 if uselog:
846 for adr, msg in ret:
847 uselog(msg, address = adr)
848
849 return ret
850
852 f=""
853 if self.flags & self.BUSY[1][1]:
854 f+=self.BUSY[1][0]
855 else:
856 f+="F"
857
858 for a in self.FLAGS.keys():
859 if self.FLAGS[a][1] & self.flags:
860 f+="|" + self.FLAGS[a][0]
861 if self.Lookaside:
862 f += "$"
863
864 return f
865
867 if self.flags & self.FLAGS['TOP'][1]:
868 return 1
869 return 0
870
872 if self.psize == 0:
873 return 1
874 return 0
875
876
878 FLAGS = { 'FILL PATTERN':('FP', 0x4), 'DEBUG': ('D', 0x8),\
879 'TOP': ('T', 0x10), 'FFU1':('FFU1',0x20),\
880 'FFU2': ('FFU2', 0x40), 'NO COALESCE':('NC', 0x80) }
881 LFHMASK = 0x3F
882 LFHFLAGS = { 'TOP': ('T', 0x3), 'BUSY': ('B', 0x18) }
883
884 - def __init__(self, imm, addr, heap = None, BlockSize = 0):
885 self.heap = heap
886 self.freeorder = -1
887 self.isLFH = False
888 if BlockSize:
889 self.isLFH = True
890 self.size = BlockSize
891 win32heapchunk.__init__(self, imm, addr, heap)
892
894 self.freeorder = freeorder
895
896 - def _get(self, dword1, dword2, addr, heap):
897 heap = self.heap
898 self.nextchunk= 0
899 self.prevchunk= 0
900 if heap and heap.EncodeFlagMask:
901 dword1 ^= heap.EncodingKey
902 dword2 = dword2 ^ heap.EncodingKey2
903
904 self.subsegmentcode = self.SubSegmentCode = dword1
905 if self.isLFH:
906 self.upsize = self.usize = self.size << 3
907 self.psize = self.size
908 else:
909 self.size = dword1 & 0xffff
910 self.usize = self.size << 3
911 self.psize = dword2 & 0xffff
912 self.upsize = self.psize << 3
913
914 self.flags = (dword1 >> 16 & 0xff)
915 self.smalltagindex = (dword1 >> 24 & 0xff)
916
917 self.segmentoffset = (dword2 >> 16 & 0xff)
918 self.unused = (dword2 >> 24 & 0xff)
919 self.flags2 = self.unused
920 self.lfhflags = self.flags2
921
922 if not (self.flags & 0x1):
923 try:
924 (self.nextchunk, self.prevchunk) = struct.unpack("LL", self.imm.readMemory( addr+8, 8) )
925 except:
926 pass
927
928
929 self.data_addr = addr + 8
930
931 self.properties= {'size': self.usize, 'prevsize': self.upsize, 'smalltagindex': self.smalltagindex,\
932 'flags':self.flags, 'subsegmentcode':self.subsegmentcode, 'address':self.addr,\
933 'next': self.nextchunk, 'prev': self.prevchunk, 'lfhflags': self.flags2,\
934 'segmentoffset': self.segmentoffset }
935 self.data_size = self.usize - (self.addr - self.data_addr)
936 if DEBUG:
937 self.imm.log("Datasize: 0x%08x 0x%d" % (self.data_addr, self.data_size), address = self.addr)
938 try:
939 self.sample = self.imm.readMemory(self.data_addr, 0x10)
940 except WindowsError:
941 raise Exception, "Failed to read chunk at address: 0x%08x" % addr
942
944 f=""
945 if not self.isLFH:
946 if self.flags & self.BUSY[1][1]:
947 f+=self.BUSY[1][0]
948 else:
949 f+="F"
950
951 for a in self.FLAGS.keys():
952 if self.FLAGS[a][1] & self.flags:
953 f+="|" + self.FLAGS[a][0]
954 else:
955 for k in self.LFHFLAGS.keys():
956 if self.flags2 == self.LFHFLAGS[k][1]:
957 return self.LFHFLAGS[k][0]
958 return f
959
961 if self.flags2 == self.LFHFLAGS['TOP'][1] :
962 return 1
963 else:
964 return 0
965
966 - def printchunk(self, uselog= None, option=0, dt= None):
967 ret = []
968 if self.isRestore():
969 restore = "<R>"
970 else:
971 restore = ""
972 if self.isLFH:
973 s = "B"
974 if self.freeorder != -1:
975 s="F(%02x)" % self.freeorder
976 ret.append( (self.addr, "Chunk size: 0x%x lfhflag: 0x%x %s" % ( self.psize, self.lfhflags, s )) )
977 else:
978 ret.append((self.addr, "0x%08x> " % self.addr + "size: 0x%08x (%04x) prevsize: 0x%08x (%04x) %s" % (self.usize, self.size, \
979 self.upsize, self.psize, restore) ))
980 ret.append((self.addr, " heap: *0x%08x* flags: 0x%02x 0x%02x (%s)" % (self.heap_addr, self.flags, self.flags2,\
981 self.getflags(self.flags))))
982 if not self.isLFH and not (self.flags2 & self.BUSY[1][1]):
983 ret.append((self.addr, " next: 0x%08x prev: 0x%08x" % (self.nextchunk, self.prevchunk)))
984 if option & SHOWCHUNK_FULL:
985 dump = immutils.hexdump(self.sample)
986 for a in range(0, len(dump)):
987 if not a:
988 ret.append((self.addr, " (%s %s)" % (dump[a][0], dump[a][1])))
989 if dt:
990 if not self.isLFH or (self.isLFH and self.freeorder == -1) :
991 result = dt.Discover(self.imm.readMemory(self.data_addr, self.data_size), self.data_addr)
992 for obj in result:
993 msg = obj.Print()
994 ret.append((obj.address, " > %s: %s " % (obj.name, msg) ))
995
996 if uselog:
997 for adr, msg in ret:
998 uselog(msg, address = adr)
999
1000 return ret
1001
1002
1004 - def __init__(self, imm, addr, heap = 0x0, log = None ):
1005 """ Win32 Heap Lookaside list """
1006 UserList.__init__(self)
1007 if not log:
1008 log = imm.log
1009 self.log = log
1010 self.imm = imm
1011 self.heap = heap
1012 self.Lookaside = []
1013
1014 LookSize = PLook(self.imm, 0x0).getSize()
1015 mem = imm.readMemory(addr, LookSize * HEAP_MAX_FREELIST)
1016
1017 for ndx in range(0, HEAP_MAX_FREELIST):
1018 base_addr = addr + ndx * LookSize
1019 l = PLook(self.imm, base_addr, mem[ ndx * LookSize : ndx * LookSize + LookSize ], self.heap )
1020
1021 self.data.append(l)
1022 next = l.ListHead
1023 while next and next != base_addr:
1024 l.append( next - 8 )
1025 try:
1026 next = self.imm.readLong(next)
1027 except:
1028 break
1029
1030
1032 - def __init__(self, imm, addr, data = None, heap = 0x0, log= None):
1033 self.log = log
1034 self.addr = addr
1035 self.List = []
1036 self.fmt = "LHHLLLLLLL12s"
1037 self.imm = imm
1038 self.heap = heap
1039
1040
1041 if data:
1042 (self.ListHead, self.Depth, self.MaxDepth, none, self.TotalAlloc, self.AllocMiss, self.TotalFrees,
1043 self.FreeMiss, self.AllocLastTotal, self.LastAllocateMiss, self.Unknown) = \
1044 struct.unpack(self.fmt, data[:struct.calcsize(self.fmt)])
1045 elif addr:
1046 data = self.imm.readMemory(addr, self.getSize() )
1047 (self.ListHead, self.Depth, self.MaxDepth, none, self.TotalAlloc, self.AllocMiss, self.TotalFrees,
1048 self.FreeMiss, self.AllocLastTotal, self.LastAllocateMiss, self.Unknown1, self.Unknown2) = \
1049 struct.unpack(self.fmt, data[:struct.calcsize(self.fmt)])
1050
1052 return self.ListHead == 0x0
1053
1055 return struct.calcsize(self.fmt)
1056
1059
1061 """get a the single linked list of the Lookaside entry
1062 @return: A list of the address of the linked list"""
1063 return self.List
1064
1066 """get a the single linked list of the Lookaside entry
1067 @return: A list of the Chunks on the linked list"""
1068
1069 chunks = []
1070 for addr in self.List:
1071
1072
1073 chunks.append( win32heapchunk(self.imm, addr - 8, self.heap ) )
1074
1075 return chunks
1076
1078 - def __init__(self, imm, what, action, value, heap = 0x0, restore = False, option = 0):
1079 """
1080 Search the Heap for specific Chunks
1081
1082 @type imm: Debugger Object
1083 @param imm: Initialized debugged object
1084
1085 @type what: STRING
1086 @param what: Chunk property to search from (size, prevsize, field4, flags, other, address, next, prev)
1087
1088 @type action: STRING
1089 @param action: Type of search ( =, >, <, >=, <=, &, not, !=)
1090
1091 @type value: DWORD
1092 @param value: Value to search for
1093
1094 @type heap: DWORD
1095 @param heap: (Optional, Def=None) Filter by Heap
1096
1097 @type restore: BOOLEAN
1098 @param restore: (Optional, Def: False) Flag whether or not use a restore heap (Useful if you want to search on a broken heap)
1099
1100 @type option: DWORD
1101 @param option: (Optional, Def: None) Chunk's display option
1102 """
1103 self.functions = { '=': lambda a, b: a==b,
1104 '>': lambda a,b : a>b,
1105 '<': lambda a,b : a<b,
1106 '>=': lambda a,b : a>=b,
1107 '<=': lambda a,b : a<=b,
1108 '&': lambda a,b : a&b,
1109 'not': lambda a,b: a & ~b,
1110
1111 '!=': lambda a,b : a!=b
1112 }
1113 for a in imm.getHeapsAddress():
1114 if a==heap or not heap:
1115
1116 p = imm.getHeap( a, restore )
1117 if not what or not action:
1118 for c in p.chunks:
1119 c.printchunk(uselog = imm.log, option = option)
1120 else:
1121 for c in p.chunks:
1122 if self.functions[action](c.get(what) , value):
1123 c.printchunk(uselog = imm.log, option = option)
1124