|
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
21
22
24 - def __init__(self, imm, heapddr = 0, restore = False):
25 """
26 Windows 32 Heap Class
27
28 @rtype: PHEAP object
29 """
30 self.imm = imm
31 self.address = heapddr
32 self.chunks = []
33 self.restore = restore
34 self.Segments = []
35 if heapddr:
36 self._grabHeap()
37
38
39
41 try:
42 heaps = self.imm.readMemory( self.address, 0x588 )
43 except WindowsError, msg:
44 raise Exception, "Failed to get heap at address : 0x%08x" % heapaddr
45
46 index = 0x8
47 (self.Signature, self.Flags, self.ForceFlags, self.VirtualMemoryThreshold,\
48 self.SegmentReserve, self.SegmentCommit, self.DeCommitFreeBlockThreshold, self.DeCommitTotalBlockThreshold,\
49 self.TotalFreeSize, self.MaximumAllocationSize, self.ProcessHeapListIndex, self.HeaderValidateLength,\
50 self.HeaderValidateCopy,self.NextAvailableTagIndex, self.MaximumTagIndex, self.TagEntries, \
51 self.UCRSegments, self.UnusedUnCommittedRanges, self.AlignRound, self.AlignMask) =\
52 struct.unpack("LLLLLLLLLLHHLHHLLLLL", heaps[ index : index + (0x50-8) ])
53
54 index+= 0x50-8
55 self.VirtualAllocedBlock = struct.unpack("LL", heaps[ index : index + 8 ])
56 index+=8
57 self._Segments = struct.unpack("L" * 64, heaps[ index: index+ 64*4 ])
58 index+=64*4
59 self.FreeListInUseLong = struct.unpack("LLLL" , heaps[ index : index + 16 ])
60 index+=16
61 (self.FreeListInUseTerminate,self.AllocatorBackTraceIndex) = struct.unpack("HH", heaps[ index : index + 4 ])
62 index+=4
63 self.Reserved1= struct.unpack("LL", heaps[ index : index + 8 ])
64 index+=8
65 self.PseudoTagEntries= struct.unpack("L", heaps[ index : index + 4])
66 index+=4
67 self.FreeList=[]
68
69
70 for a in range(0, 128):
71 free_entry = []
72
73 (prev, next) = struct.unpack("LL", heaps[ index + a*8 : index + a*8 + 8 ])
74
75 free_entry.append((self.address + index+ a * 8, prev, next))
76 base_entry = self.address + index + a * 8
77
78
79 while next != base_entry:
80 tmp = next
81 try:
82 (prev,next) = struct.unpack("LL", self.imm.readMemory(next, 0x8))
83 except:
84 break
85
86 free_entry.append( (tmp, prev,next) )
87
88 self.FreeList.append(free_entry)
89
90 index+=256*4
91 (self.LockVariable, self.CommitRoutine, self.Lookaside, self.LookasideLockCount)=\
92 struct.unpack("LLLL", heaps[index:index+16])
93
94
95
96 for a in range(0, 64):
97 if self._Segments[a] == 0x0:
98 break
99 s = Segment( self.imm, self._Segments[a] )
100 self.Segments.append( s )
101
102
103 if self.restore:
104 self.getRestoredChunks( s.BaseAddress )
105 else:
106 self.getChunks( s.BaseAddress )
107 for idx in s.Pages:
108 self.imm.Log("> 0x%08x" % idx)
109 if self.restore:
110 self.getRestoredChunks( idx )
111 else:
112 self.getChunks( idx )
113
115 """
116 Print the Heap's FreeListInUse bitmask
117
118 @type uselog: Log Function
119 @param uselog: (Optional, Def: Log Window) Log function that display the information
120 """
121 tbl= ["FreeListInUse %s %s"% (immutils.decimal2binary(self.FreeListInUseLong[0]), immutils.decimal2binary(self.FreeListInUseLong[1])),\
122 " %s %s" % (immutils.decimal2binary(self.FreeListInUseLong[2]), immutils.decimal2binary(self.FreeListInUseLong[3]))]
123 if uselog:
124 for a in tbl:
125 uselog(a)
126 return tbl
127
129 """
130 Print the Heap's FreeList
131
132 @type uselog: Log Function
133 @param uselog: (Optional, Def: Log Window) Log function that display the information
134 """
135 log = self.imm.Log
136 if uselog:
137 log = uselog
138 for a in range(0, 128):
139 entry= self.FreeList[a]
140 e=entry[0]
141
142 log("[%03x] 0x%08x -> [ 0x%08x | 0x%08x ] " % (a, e[0], e[1], e[2]), address = e[0])
143 for e in entry[1:]:
144 try:
145 sz = self.get_chunk( e[0] - 8 ).size
146 except:
147 sz = 0
148 log(" 0x%08x -> [ 0x%08x | 0x%08x ] (%08x)" % (e[0], e[1], e[2], sz), address= e[0])
149 return 0x0
150
151
153 """
154 Enumerate Chunks of the current heap using a restore heap
155
156 @type address: DWORD
157 @param address: Address where to start getting chunks
158
159 @rtype: List of win32heapchunks
160 @return: Chunks
161 """
162
163 imm = self.imm
164
165 oldheap = imm.getKnowledge("saved_heap_%08x" % self.address)
166 if not oldheap:
167 imm.Log("Coudln't use restore mode: No saved Heap")
168 return self.getChunks(address)
169
170 ptr = address
171
172 backchunk = self.get_chunk(imm, ptr, self.address)
173
174 backchunk.size = backchunk.psize
175 backchunk.usize = backchunk.upsize
176
177 while 1:
178
179 try:
180 c = self.get_chunk(imm, ptr, self.address)
181 except:
182 return self.chunks
183
184
185 next = ptr + c.usize
186
187 try:
188 sizes = imm.readLong( next )
189 previous = (sizes>>16) & 0xffff
190 except Exception:
191 previous = 0
192
193
194
195
196
197
198
199 if (not c.size) or (c.size != previous and not c.istop()) or (not previous and not c.istop()) or (backchunk.size != c.psize) :
200 restoredchunk = oldheap.findChunkByAddress(ptr)
201
202 if restoredchunk:
203 c = restoredchunk
204 c.setRestored()
205 next = ptr + c.usize
206 ptr = next
207 self.chunks.append(c)
208 backchunk = c
209
210
211 if c.istop() or c.size == 0:
212 break
213
214 backchunk = c
215
216 return self.chunks
217
219 """
220 Find a Chunks by its address
221
222 @type address: DWORD
223 @param address: Address to search for
224
225 @rtype: win32heapchunks
226 @return: Chunk
227 """
228
229 for a in self.chunks:
230 if a.addr == addr:
231 return a
232 return None
233
234 - def getChunks(self, address, size = 0xffffffffL):
235 """
236 Enumerate Chunks of the current heap
237
238 @type address: DWORD
239 @param address: Address where to start getting chunks
240
241 @type size: DWORD
242 @param size: (Optional, Def: All) Amount of chunks
243
244 @rtype: List of win32heapchunks
245 @return: Chunks
246 """
247 imm = self.imm
248
249 ptr = address
250
251 while size:
252
253 try:
254 c = self.get_chunk( ptr )
255 except Exception, msg:
256 imm.Log("Failed to grab chunks> " + str(msg) )
257 return self.chunks
258
259 self.chunks.append(c)
260
261
262 ptr+= c.usize
263 if c.istop() or c.size == 0:
264 break
265 size -= 1
266
267 return self.chunks
268
270 return win32heapchunk(self.imm, addr, self)
271
274 self.address = addr
275 addr += 8
276 mem = imm.readMemory(addr, 0x34)
277
278 (self.Signature, self.Flags, self.Heap, self.LargestUnCommitedRange, self.BaseAddress,\
279 self.NumberOfPages, self.FirstEntry, self.LastValidEntry, self.NumberOfUnCommittedPages,\
280 self.NumberOfUnCommittedRanges, self.UnCommittedRanges, self.AllocatorBackTraceIndex,\
281 self.Reserved, self.LastEntryInSegment) = struct.unpack("LLLLLLLLLLLHHL", mem)
282
283
284
285
286 self.Pages = []
287 if self.UnCommittedRanges:
288 i = 0
289 addr = self.UnCommittedRanges
290 while addr != 0:
291 mem = imm.readMemory( addr, 0x10 )
292 ( C_Next, C_Addr, C_Size, C_Filler) = struct.unpack( "LLLL", mem )
293
294 self.Pages.append( C_Addr + C_Size )
295 addr = C_Next
296
298 - def __init__(self, imm, heapddr = 0, restore = False):
300
302 try:
303 heapmem = self.imm.readMemory( self.address + 8 , 0x120 )
304 except WindowsError, msg:
305 raise Exception, "Failed to get heap at address : 0x%08x" % heapaddr
306 index = 8
307 (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)
308
309 self.imm.Log("FreeList: 0x%08x | 0x%08x" % (self.FreeList_Flink, self.FreeList_Blink) )
310 head = self.address +0x10
311 addr = self.SegmentList_Blink
312 self.Segments.append( self.address )
313 self.getChunks( self.address )
314 self.imm.Log("segment: 0x%08x 0x%08x" % (self.SegmentList_Flink, self.SegmentList_Blink) )
315 while head != addr:
316 self.Segments.append( addr - 0x10 )
317 self.getChunks( addr - 0x10 )
318 addr = self.imm.readLong( addr )
319
320
321
322 self.getBlocks( self.BlocksIndex )
323 if self.FrontEndHeap:
324 self.LFH = LFHeap( self.imm, self.FrontEndHeap )
325
327 self.blocks = []
328 addr = startaddr
329
330 while addr:
331 block = Blocks( self.imm, addr )
332 self.blocks.append( block )
333 block.FreeList=[]
334 memory = self.imm.readMemory( block.Buckets, 0x80*8 )
335 if block.FreeListInUsePtr:
336 block.setFreeListInUse( struct.unpack("LLLL", self.imm.readMemory( block.FreeListInUsePtr, 4*4 )) )
337
338
339 for a in range(0, 128):
340 free_entry = []
341
342 (fwlink, heap_bucket) = struct.unpack("LL", memory[a *8 : a *8 + 8] )
343 if fwlink:
344 try:
345 (next, prev) = struct.unpack("LL", self.imm.readMemory( fwlink, 8) )
346 except:
347 next, prev = (0,0)
348 self.imm.Log("Error with 0x%x" % fwlink)
349 free_entry.append( (fwlink, next, prev) )
350 base_entry = fwlink
351
352 while next and next != base_entry:
353 tmp = next
354 chunk = win32vistaheapchunk( self.imm, next - 8, self )
355
356 if a == 127:
357 if chunk.size <= a:
358 break
359 else:
360 if chunk.size != a:
361 break
362
363 next = chunk.nextchunk
364 free_entry.append( (tmp, chunk.nextchunk, chunk.prevchunk) )
365
366 else:
367 free_entry = [ (fwlink, 0x0, 0x0) ]
368
369
370
371 block.FreeList.append(free_entry)
372
373 addr = block.FwLink
374
376 return win32vistaheapchunk(self.imm, addr, self)
377
379 """
380 Print the Heap's FreeList
381
382 @type uselog: Log Function
383 @param uselog: (Optional, Def: Log Window) Log function that display the information
384 """
385 log = self.imm.Log
386 if uselog:
387 log = uselog
388 for block in self.blocks:
389 f = block.FreeListInUse
390 log("** Block 0x%08x StartSize: %d MaxSize: %d CtrZone: %d **" % ( block.address, block.StartSize, block.MaxSize, block.CtrZone ) )
391 log("FreeListInUse: %s %s" % (immutils.decimal2binary(f[0]),\
392 immutils.decimal2binary(f[1]) ) )
393 log(" %s %s" % (immutils.decimal2binary(f[2]),\
394 immutils.decimal2binary(f[3]) ) )
395
396 for a in range(0, 128):
397 entry= block.FreeList[a]
398 e=entry[0]
399 if e[0]:
400 log("[%03d] 0x%08x -> [ 0x%08x | 0x%08x ] " % (a, e[0], e[1], e[2]), address = e[0])
401 for e in entry[1:]:
402 log(" 0x%08x -> [ 0x%08x | 0x%08x ] " % (e[0], e[1], e[2]), address= e[0])
403 return 0x0
404
405
408 mem = imm.readMemory( addr, 0x300 )
409 if not mem:
410 raise Exception, "Can't read Low Fragmentation Heap at 0x%08x" % addr
411 index = 0
412 self.address = addr
413 imm.Log("Low Fragmented Heap: 0x%08x" % addr)
414 (self.Lock, self.field_4, self.field_8, self.field_c,\
415 self.field_10, field_14, self.SubSegmentZone_Flink,
416 self.SubSegmentZone_Blink, self.ZoneBlockSize,\
417 self.Heap, self.SegmentChange, self.SegmentCreate,\
418 self.SegmentInsertInFree, self.SegmentDelete, self.CacheAllocs,\
419 self.CacheFrees) = struct.unpack("L" * 0x10, mem[ index : index +0x40 ])
420 index += 0x40
421 self.UserBlockCache = []
422 for a in range(0,12):
423 umc = UserMemoryCache( addr + index, mem[ index : index + 0x10] )
424 index+= 0x10
425 self.UserBlockCache.append( umc )
426 self.Buckets = []
427 for a in range(0, 128):
428 entry = mem[ index : index + 4 ]
429 b = Bucket( addr + index, entry)
430 index = index + 4
431 self.Buckets.append( b )
432
433 self.LocalData = LocalData(imm, addr + index )
434
437 self.address = addr
438
439 mem = imm.readMemory( addr, 0x18 + 0x68*128 )
440 (self.Next, self.Depth, self.Seq, self.CtrZone, self.LowFragHeap,\
441 self.Sequence1, self.Sequence2) = struct.unpack("LHHLLLL", mem[:0x18])
442 index = 0x18
443 self.SegmentInfo = []
444 for a in range(0, 128):
445 l = LocalSegmentInfo( imm, self.address + index,\
446 mem[ index : index + 0x68] )
447 index+= 0x68
448 self.SegmentInfo.append( l )
449
450
452 - def __init__(self, imm, addr, mem = ""):
453 self.address = addr
454 self.SubSegment = []
455 self.imm = imm
456 if not mem:
457 mem = imm.readMemory( self.address, 0x68 )
458
459 (self.Hint, self.ActiveSubsegment) = struct.unpack("LL", mem[0:8] )
460 index = 8
461 self.CachedItems = struct.unpack("L" * 0x10, mem[ index : index + 0x10*4])
462 index += 0x10*4
463 (self.Next, self.Depth, self.Seq, self.TotalBlocks,\
464 self.SubSegmentCounts, self.LocalData, self.LastOpSequence,\
465 self.BucketIndex, self.LastUsed, self.Reserved) = struct.unpack("LHHLLLLHHL", mem[index: index + 0x20])
466
467 if self.Hint:
468 self.SubSegment.append( self.getSubSegment( self.Hint, "Hint" ) )
469 if self.ActiveSubsegment and self.ActiveSubsegment != self.Hint:
470 self.SubSegment.append( self.getSubSegment( self.ActiveSubsegment, "ActiveSS") )
471 for a in range( 0, len(self.CachedItems) ):
472 item = self.CachedItems[a]
473 if item and item not in (self.Hint, self.ActiveSubsegment):
474 self.SubSegment.append( self.getSubSegment( item, "Cache_%02x" % a) )
475
476
477
480
482 - def __init__(self, imm, address, type=""):
483 self.address = address
484 self.type = type
485 self.chunks = []
486 mem = imm.readMemory( address, 0x20 )
487 (self.LocalInfo, self.UserBlocks, self.AggregateExchg,\
488 self.Aggregate_Sequence, self.BlockSize, self.Flags,\
489 self.BlockCount, self.SizeIndex, self.AffinityIndex,
490 self.Next, self.Lock) = struct.unpack("LLLLHHHBBLL", mem)
491 self.Offset = self.AggregateExchg >> 0xD
492 self.Offset = self.Offset & 0x7FFF8
493 self.Depth = self.AggregateExchg & 0xFFFF
494
495 if self.UserBlocks:
496 self.UserDataHeader = self.getUserData( imm, self.UserBlocks )
497
498
499 list = self.grabBusyList( imm, self.UserBlocks, self.Offset, self.Depth)
500 self.chunks = self.getChunks( imm, self.UserBlocks + self.UserDataHeader.getSize(), list )
501
503 list = {}
504 i = 1
505 for a in range(0, depth):
506 address = base_addr + offset
507 dword = imm.readLong( address + 8 )
508 offset = dword & 0xFFFF
509 offset *=8
510 list[ address ] = a + 1
511 return list
512
515
517
518 addr = address
519 chunks = []
520 for a in range(0, self.BlockCount):
521 c = win32vistaheapchunk(imm, addr, BlockSize = self.BlockSize)
522 s = "B"
523 if list.has_key(addr):
524 c.setFreeOrder( list[addr] )
525 s = "F(%02d)" % list[addr]
526
527 addr += self.BlockSize*8
528 chunks.append( c )
529 return chunks
530
533 self.address = addr
534 mem = imm.readMemory(addr, 0x10)
535 (self.SubSegment, self.Reserved, self.SizeIndex, self.Signature) =\
536 struct.unpack("LLLL", mem)
539
542 self.address = addr
543 (self.BlockUnits, self.SizeIndex, Flag) =\
544 struct.unpack("HBB", mem[:4])
545
546 self.UseAffinity = Flag & 0x1
547 self.DebugFlags = (Flag >1) & 0x3
548
551 self.address = addr
552 (self.Next, self.Depth, self.Sequence, self.AvailableBlocks,\
553 self.Reserved) = struct.unpack("LHHLL", mem[ 0 : 16 ])
554
557 mem = imm.readMemory( addr, 0x24 )
558 if not mem:
559 raise Exception, "Can't read Block at 0x%08x" % addr
560 self.address = addr
561 self.FreeListInUse = None
562 self.FreeList = []
563 (self.FwLink, self.MaxSize, self.CtrZone, self.field_c,
564 self.field_10, self.StartSize, self.FreeListPtr,\
565 self.FreeListInUsePtr, self.Buckets) =\
566 struct.unpack( "L" * 9, mem )
568 self.FreeListInUse = inuse
569
571 self.FreeList = flist
572
573 SHOWCHUNK_FULL = 0x1
574 CHUNK_ANALIZE = 0x2
576 FLAGS = { 'EXTRA PRESENT':('E', 0x2), 'FILL PATTERN':('FP', 0x4),\
577 'VIRTUAL ALLOC': ('V', 0x8), 'TOP': ('T', 0x10),
578 'FFU1':('FFU1',0x20), 'FFU2': ('FFU2', 0x40),\
579 'NO COALESCE':('NC', 0x80) }
580 BUSY = ('BUSY', ('B', 0x1))
581 - def __init__(self, imm, addr, heap = None):
582 """ Win32 Chunk """
583 self.imm = imm
584
585 self.restored = False
586
587 if heap:
588 self.heap_addr = heap.address
589 else:
590 self.heap_addr = 0
591 self.nextchunk=0
592 self.prevchunk=0
593 self.addr = addr
594
595 try:
596 dword1 = self.imm.readLong(addr)
597 dword2 = self.imm.readLong(addr+4)
598 except Exception:
599 raise Exception, "Failed to read chunk at address: 0x%08x" % addr
600
601 self._get( dword1, dword2, addr )
602
603
604 - def _get(self, size, flags, addr):
605 self.size = size & 0xffff
606 self.usize = self.size * 8
607
608 self.psize = ( size >> 16 ) & 0xffff
609 self.upsize = self.psize * 8
610
611 self.field4 = flags & 0xff
612 self.flags = (flags >> 8) & 0xff
613 self.other = (flags >> 16) & 0xffff
614 mem_addr = addr + 8
615 if not (self.flags & self.BUSY[1][1] ):
616 if self.flags & self.FLAGS['VIRTUAL ALLOC'][1]:
617 pass
618 else:
619 try:
620 self.nextchunk= self.imm.readLong(addr+8)
621 self.prevchunk= self.imm.readLong(addr+12)
622 except WindowsError:
623 raise Exception, "Failed to read chunk at address: 0x%08x" % addr
624
625 mem_addr +=8
626
627 self.data_addr = mem_addr
628 self.data_size = self.upsize - (addr - mem_addr)
629
630 try:
631 self.sample = self.imm.readMemory(self.data_addr, 0x10)
632 except WindowsError:
633 raise Exception, "Failed to read chunk at address: 0x%08x" % addr
634
635 self.properties= {'size': self.usize, 'prevsize': self.upsize, 'field4': self.field4,\
636 'flags':self.flags, 'other':self.other, 'address':self.addr,\
637 'next': self.nextchunk, 'prev': self.prevchunk}
638
641
644
645 - def get(self, what):
646 try:
647 return self.properties[string.lower(what)]
648 except KeyError:
649 return None
650
651 - def printchunk(self, uselog= None, option=0, dt= None):
652 ret = []
653 if self.isRestore():
654 restore = "<R>"
655 else:
656 restore = ""
657 ret.append((self.addr, "0x%08x> " % self.addr + "size: 0x%08x (%04x) prevsize: 0x%08x (%04x) %s" % (self.usize, self.size, \
658 self.upsize, self.psize, restore) ))
659 ret.append((self.addr, " heap: *0x%08x* flags: 0x%08x (%s)" % (self.heap_addr, self.flags,\
660 self.getflags(self.flags))))
661
662
663 if not (self.flags & self.BUSY[1][1]):
664 ret.append((self.addr, " next: 0x%08x prev: 0x%08x" % (self.nextchunk, self.prevchunk)))
665 if option & SHOWCHUNK_FULL:
666 dump = immutils.hexdump(self.sample)
667 for a in range(0, len(dump)):
668 if not a:
669 ret.append((self.addr, " (%s %s)" % (dump[a][0], dump[a][1])))
670 if dt:
671 result = dt.Discover(self.imm.readMemory(self.data_addr, self.data_size), self.data_addr)
672
673 for obj in result:
674 msg = obj.Print()
675 ret.append((obj.address, " > %s: %s " % (obj.name, msg) ))
676
677
678 if uselog:
679 for adr, msg in ret:
680 uselog(msg, address = adr)
681
682 return ret
683
685 f=""
686 if self.flags & self.BUSY[1][1]:
687 f+=self.BUSY[1][0]
688 else:
689 f+="F"
690
691 for a in self.FLAGS.keys():
692 if self.FLAGS[a][1] & self.flags:
693 f+="|" + self.FLAGS[a][0]
694 return f
695
697 if self.flags & self.FLAGS['TOP'][1]:
698 return 1
699 return 0
700
702 if self.psize == 0:
703 return 1
704 return 0
705
706
708 FLAGS = { 'FILL PATTERN':('FP', 0x4), 'DEBUG': ('D', 0x8),\
709 'TOP': ('T', 0x10), 'FFU1':('FFU1',0x20),\
710 'FFU2': ('FFU2', 0x40), 'NO COALESCE':('NC', 0x80) }
711 LFHMASK = 0x3F
712 LFHFLAGS = { 'TOP': ('T', 0x3), 'BUSY': ('B', 0x18) }
713
714 - def __init__(self, imm, addr, heap = None, BlockSize = 0):
715 self.heap = heap
716 self.freeorder = -1
717 self.isLFH = False
718 if BlockSize:
719 self.isLFH = True
720 self.size = BlockSize
721 win32heapchunk.__init__(self, imm, addr, heap)
722
724 self.freeorder = freeorder
725
726 - def _get(self, dword1, dword2, addr):
727 heap = self.heap
728 self.nextchunk= 0
729 self.prevchunk= 0
730 if heap and heap.EncodeFlagMask:
731 dword1 ^= heap.EncodingKey
732 dword2 = dword2 ^ heap.EncodingKey2
733
734 self.subsegmentcode = self.SubSegmentCode = dword1
735 if self.isLFH:
736 self.upsize = self.usize = self.size << 3
737 self.psize = self.size
738 else:
739 self.size = dword1 & 0xffff
740 self.usize = self.size << 3
741 self.psize = dword2 & 0xffff
742 self.upsize = self.psize << 3
743
744 self.flags = (dword1 >> 16 & 0xff)
745 self.smalltagindex = (dword1 >> 24 & 0xff)
746
747 self.segmentoffset = (dword2 >> 16 & 0xff)
748 self.unused = (dword2 >> 24 & 0xff)
749 self.flags2 = self.unused
750 self.lfhflags = self.flags2
751
752
753 self.data_addr = addr + 8
754
755 self.properties= {'size': self.usize, 'prevsize': self.upsize, 'smalltagindex': self.smalltagindex,\
756 'flags':self.flags, 'subsegmentcode':self.subsegmentcode, 'address':self.addr,\
757 'next': self.nextchunk, 'prev': self.prevchunk, 'lfhflags': self.flags2,\
758 'segmentoffset': self.segmentoffset }
759 self.data_size = self.usize - (self.addr - self.data_addr)
760
761 try:
762 self.sample = self.imm.readMemory(self.data_addr, 0x10)
763 except WindowsError:
764 raise Exception, "Failed to read chunk at address: 0x%08x" % addr
765
767 f=""
768 if not self.isLFH:
769 if self.flags & self.BUSY[1][1]:
770 f+=self.BUSY[1][0]
771 else:
772 f+="F"
773
774 for a in self.FLAGS.keys():
775 if self.FLAGS[a][1] & self.flags:
776 f+="|" + self.FLAGS[a][0]
777 else:
778 for k in self.LFHFLAGS.keys():
779 if self.flags2 == self.LFHFLAGS[k][1]:
780 return self.LFHFLAGS[k][0]
781 return f
782
784 if self.flags2 == self.LFHFLAGS['TOP'][1] :
785 return 1
786 else:
787 return 0
788
789 - def printchunk(self, uselog= None, option=0, dt= None):
790 ret = []
791 if self.isRestore():
792 restore = "<R>"
793 else:
794 restore = ""
795 if self.isLFH:
796 s = "B"
797 if self.freeorder != -1:
798 s="F(%02x)" % self.freeorder
799 ret.append( (self.addr, "Chunk size: 0x%x lfhflag: 0x%x %s" % ( self.psize, self.lfhflags, s )) )
800 else:
801 ret.append((self.addr, "0x%08x> " % self.addr + "size: 0x%08x (%04x) prevsize: 0x%08x (%04x) %s" % (self.usize, self.size, \
802 self.upsize, self.psize, restore) ))
803 ret.append((self.addr, " heap: *0x%08x* flags: 0x%02x 0x%02x (%s)" % (self.heap_addr, self.flags, self.flags2,\
804 self.getflags(self.flags))))
805 if not self.isLFH and not (self.flags2 & self.BUSY[1][1]):
806 ret.append((self.addr, " next: 0x%08x prev: 0x%08x" % (self.nextchunk, self.prevchunk)))
807 if option & SHOWCHUNK_FULL:
808 dump = immutils.hexdump(self.sample)
809 for a in range(0, len(dump)):
810 if not a:
811 ret.append((self.addr, " (%s %s)" % (dump[a][0], dump[a][1])))
812 if dt:
813 if not self.isLFH or (self.isLFH and self.freeorder == -1) :
814 result = dt.Discover(self.imm.readMemory(self.data_addr, self.data_size), self.data_addr)
815 for obj in result:
816 msg = obj.Print()
817 ret.append((obj.address, " > %s: %s " % (obj.name, msg) ))
818
819 if uselog:
820 for adr, msg in ret:
821 uselog(msg, address = adr)
822
823 return ret
824
825
827 - def __init__(self, imm, addr, heap = 0x0, log = None ):
828 """ Win32 Heap Lookaside list """
829 UserList.__init__(self)
830 if not log:
831 log = imm.Log
832 self.log = log
833 self.imm = imm
834 self.heap = heap
835 self.Lookaside = []
836
837 LookSize = PLook(self.imm, 0x0).getSize()
838 mem = imm.readMemory(addr, LookSize * HEAP_MAX_FREELIST)
839
840 for ndx in range(0, HEAP_MAX_FREELIST):
841 base_addr = addr + ndx * LookSize
842 l = PLook(self.imm, base_addr, mem[ ndx * LookSize : ndx * LookSize + LookSize ], self.heap )
843
844 self.data.append(l)
845 next = l.ListHead
846 while next and next != base_addr:
847 l.append( next )
848 try:
849 next = self.imm.readLong(next)
850 except:
851 break
852
853
855 - def __init__(self, imm, addr, data = None, heap = 0x0, log= None):
856 self.log = log
857 self.addr = addr
858 self.List = []
859 self.fmt = "LLHHLLLLLL12s"
860 self.imm = imm
861 self.heap = heap
862
863
864 if data:
865 (self.ListHead, none, self.Depth, self.MaxDepth, self.TotalAlloc, self.AllocMiss, self.TotalFrees,
866 self.FreeMiss, self.AllocLastTotal, self.LastAllocateMiss, self.Unknown) = \
867 struct.unpack(self.fmt, data[:struct.calcsize(self.fmt)])
868 elif addr:
869 data = self.imm.readMemory(addr, self.getSize() )
870 (self.ListHead, none, self.Depth, self.MaxDepth, self.TotalAlloc, self.AllocMiss, self.TotalFrees,
871 self.FreeMiss, self.AllocLastTotal, self.LastAllocateMiss, self.Unknown1, self.Unknown2) = \
872 struct.unpack(self.fmt, data[:struct.calcsize(self.fmt)])
873
875 return self.ListHead == 0x0
876
878 return struct.calcsize(self.fmt)
879
882
884 """get a the single linked list of the Lookaside entry
885 @return: A list of the address of the linked list"""
886 return self.List
887
889 """get a the single linked list of the Lookaside entry
890 @return: A list of the Chunks on the linked list"""
891
892 chunks = []
893 for addr in self.List:
894
895
896 chunks.append( win32heapchunk(self.imm, addr - 8, self.heap ) )
897
898 return chunks
899
901 - def __init__(self, imm, what, action, value, heap = 0x0, restore = False, option = 0):
902 """
903 Search the Heap for specific Chunks
904
905 @type imm: Debugger Object
906 @param imm: Initialized debugged object
907
908 @type what: STRING
909 @param what: Chunk property to search from (size, prevsize, field4, flags, other, address, next, prev)
910
911 @type action: STRING
912 @param action: Type of search ( =, >, <, >=, <=, &, not, !=)
913
914 @type value: DWORD
915 @param value: Value to search for
916
917 @type heap: DWORD
918 @param heap: (Optional, Def=None) Filter by Heap
919
920 @type restore: BOOLEAN
921 @param restore: (Optional, Def: False) Flag whether or not use a restore heap (Useful if you want to search on a broken heap)
922
923 @type option: DWORD
924 @param option: (Optional, Def: None) Chunk's display option
925 """
926 self.functions = { '=': lambda a, b: a==b,
927 '>': lambda a,b : a>b,
928 '<': lambda a,b : a<b,
929 '>=': lambda a,b : a>=b,
930 '<=': lambda a,b : a<=b,
931 '&': lambda a,b : a&b,
932 'not': lambda a,b: a & ~b,
933
934 '!=': lambda a,b : a!=b
935 }
936 for a in imm.getHeapsAddress():
937 if a==heap or not heap:
938
939 p = imm.getHeap( a, restore )
940 if not what or not action:
941 for c in p.chunks:
942 c.printchunk(uselog = imm.Log, option = option)
943 else:
944 for c in p.chunks:
945 if self.functions[action](c.get(what) , value):
946 c.printchunk(uselog = imm.Log, option = option)
947