最近由于某些原因,更新了一下pwndbg,结果发现原本好好的bins功能被改成了一坨屎!!
去github看了一下issues,果然也有人说到这个问题.
https://github.com/pwndbg/pwndbg/issues/424 
原本是这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 pwndbg> bins fastbins 0x20: 0x602000 ◂— 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x0 smallbins empty largebins empty 
 
后来变成了这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 pwndbg> bins fastbins 0x20: 0x602000 ◂— 0x0 0x30: 0x0 0x40: 0x0 0x50: 0x0 0x60: 0x0 0x70: 0x0 0x80: 0x0 unsortedbin all: 0x7ffff7dd1b78 (main_arena+88) ◂— 0x7ffff7dd1b78 smallbins 0x20: 0x7ffff7dd1b88 (main_arena+104) ◂— 0x7ffff7dd1b88 0x30: 0x7ffff7dd1b98 (main_arena+120) ◂— 0x7ffff7dd1b98 0x40: 0x7ffff7dd1ba8 (main_arena+136) ◂— 0x7ffff7dd1ba8 0x50: 0x7ffff7dd1bb8 (main_arena+152) ◂— 0x7ffff7dd1bb8 ...... 0x3d0: 0x7ffff7dd1f38 (main_arena+1048) ◂— 0x7ffff7dd1f38 0x3e0: 0x7ffff7dd1f48 (main_arena+1064) ◂— 0x7ffff7dd1f48 0x3f0: 0x7ffff7dd1f58 (main_arena+1080) ◂— 0x7ffff7dd1f58 largebins 0x400: 0x7ffff7dd1f68 (main_arena+1096) ◂— 0x7ffff7dd1f68 0x440: 0x7ffff7dd1f78 (main_arena+1112) ◂— 0x7ffff7dd1f78 0x480: 0x7ffff7dd1f88 (main_arena+1128) ◂— 0x7ffff7dd1f88 0x4c0: 0x7ffff7dd1f98 (main_arena+1144) ◂— 0x7ffff7dd1f98 0x500: 0x7ffff7dd1fa8 (main_arena+1160) ◂— 0x7ffff7dd1fa8 ...... 0x28000: 0x7ffff7dd2328 (main_arena+2056) ◂— 0x7ffff7dd2328 0x40000: 0x7ffff7dd2338 (main_arena+2072) ◂— 0x7ffff7dd2338 0x80000: 0x7ffff7dd2348 (main_arena+2088) ◂— 0x7ffff7dd2348 
 
what a shit code !!!
这怎么能忍?
对照comment前的代码,我修改了pwndbg/chain.py中get的代码
修改后代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 def  get (address, limit=LIMIT, offset=0 , hard_stop=None , hard_end=0  ):    """      Recursively dereferences an address. For bare metal, it will stop when the address is not in any of vmmap pages to avoid redundant dereference.     Arguments:         address(int): the first address to begin dereferencing         limit(int): number of valid pointers         offset(int): offset into the address to get the next pointer         hard_stop(int): address to stop at         hard_end: value to append when hard_stop is reached     Returns:         A list representing pointers of each ```address``` and reference     """     limit = int (limit)          result = []      for  i in  range (limit):                  if  result.count(address) >= 2 :             break          if  hard_stop is  not  None  and  address == hard_stop:             result.append(hard_end)             break          result.append(address)          try :             address = address + offset                                       if  not  pwndbg.abi.linux and  not  pwndbg.vmmap.find(address):                 break              address = int (pwndbg.memory.poi(pwndbg.typeinfo.ppvoid, address))             address &= pwndbg.arch.ptrmask                      except  gdb.MemoryError:             break      return  result 
 
世界终于正常了.
但这远远没有结束.既然魔改了,就把之前不爽的地方都魔改一遍好了233333333
首先是heap命令打印chunk的时候,prevsize和size是十进制打印的,实际比赛中你还得把他转换成hex才有意义…
不过这不是pwndbg的错,因为gdb print malloc_chunk的时候就是这样打印的(真的怪
通过修改pwndbg/chain.py中malloc_chunk实现.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 @pwndbg.commands.ParsedCommand @pwndbg.commands.OnlyWhenRunning def  malloc_chunk (addr ):    """      Prints out the malloc_chunk at the specified address.     """     main_heap = pwndbg.heap.current     if  not  isinstance (addr, six.integer_types):         addr = int (addr)     chunk = read_chunk(addr)     size = int (chunk['size' ])     actual_size = size & ~7      prev_inuse, is_mmapped, non_main_arena = main_heap.chunk_flags(size)     arena = None      if  non_main_arena:         arena = main_heap.get_heap(addr)['ar_ptr' ]              fastbins = main_heap.fastbins(arena)     header = M.get(addr)     if  prev_inuse:         if  actual_size in  fastbins:             header += message.hint(' FASTBIN' )         else :             header += message.hint(' PREV_INUSE' )     if  is_mmapped:         header += message.hint(' IS_MMAPED' )     if  non_main_arena:         header += message.hint(' NON_MAIN_ARENA' )          chunk_str='{\n'      for  key in  chunk["value" ].type .keys():         chunk_str+='  %s = %s,\n' %(str (key),hex (int (chunk["value" ][key])))     chunk_str+='}'      print (header, chunk_str)          return  chunk 
 
实际效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 pwndbg> heap Top Chunk: 0x113c0c0 Last Remainder: 0 0x113c000 FASTBIN {   prev_size = 0x0,   size = 0x61,   fd = 0x113c060,   bk = 0x0,   fd_nextsize = 0x0,   bk_nextsize = 0x0, } 0x113c060 FASTBIN {   prev_size = 0x0,   size = 0x61,   fd = 0x113c000,   bk = 0x0,   fd_nextsize = 0x0,   bk_nextsize = 0x0, } 0x113c0c0 PREV_INUSE {   prev_size = 0x0,   size = 0x20f41,   fd = 0x0,   bk = 0x0,   fd_nextsize = 0x0,   bk_nextsize = 0x0, } 
 
 
其次,我认为pwndbg自带的find_fake_fast太鸡肋了,一是要输入你指定的大小,二是还经常无故爆炸,三是还有bug
为此我添加了这样一个commands
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 @pwndbg.commands.ParsedCommand @pwndbg.commands.OnlyWhenRunning def  fake_fastbin_all (addr ):    """      Finds candidate fake fast chunks that will overlap with the specified     address. Used for fastbin dups and house of spirit     """     main_heap = pwndbg.heap.current     max_fast = main_heap.global_max_fast     max_idx  = main_heap.fastbin_index(max_fast)     start    = int (addr) - int (max_fast)     mem      = pwndbg.memory.read(start, max_fast, partial=True )     fmt = {         'little' : '<' ,         'big' : '>'      }[pwndbg.arch.endian] + {         4 : 'I' ,         8 : 'Q'      }[pwndbg.arch.ptrsize]     print (C.banner("FAKE CHUNKS" ))     for  idx in  range (max_idx +1 ):         if  pwndbg.arch.ptrsize == 8 :             print (message.hint(hex ((idx+2 )<<4 ))+": " )         else :             print (message.hint(hex ((idx+2 )<<3 ))+": " )         for  offset in  range (max_fast - pwndbg.arch.ptrsize):             candidate = mem[offset:offset + pwndbg.arch.ptrsize]             if  len (candidate) == pwndbg.arch.ptrsize:                 value = struct.unpack(fmt, candidate)[0 ]                 if  main_heap.fastbin_index(value&0xffffffff ) == idx:                     print ('[+]' ,hex (start+offset-pwndbg.arch.ptrsize),', padding len:' ,hex (int (addr)-start-offset-pwndbg.arch.ptrsize)) 
 
这个命令只要你提供地址,就能打印出所有可行的fake chunk
效果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 pwndbg> p &__malloc_hook $1 = (void *(**)(size_t, const void *)) 0x7f690516ab10 <__malloc_hook> pwndbg> fake_fastbin_all 0x7f690516ab10 FAKE CHUNKS 0x20:  0x30:  0x40:  0x50:  0x60:  0x70:  [+] 0x7f690516aaed , padding len: 0x13 [+] 0x7f690516aafd , padding len: 0x3 0x80:  pwndbg> hex 0x7f690516aaed +0000 0x7f690516aaed  00 00 00 60  92 16 05 69  7f 00 00 00  00 00 00 00  │...`│...i│....│....│ +0010 0x7f690516aafd  00 00 00 20  be e2 04 69  7f 00 00 00  ba e2 04 69  │....│...i│....│...i│ +0020 0x7f690516ab0d  7f 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  │....│....│....│....│ +0030 0x7f690516ab1d  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  │....│....│....│....│