调教pwndbg

最近由于某些原因,更新了一下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.pyget的代码

修改后代码如下

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 = [address]
result = [] ##patch 1
for i in range(limit):
# Don't follow cycles, except to stop at the second occurrence.
if result.count(address) >= 2:
break

if hard_stop is not None and address == hard_stop:
result.append(hard_end)
break

result.append(address) ##patch 2
try:
address = address + offset

# Avoid redundant dereferences in bare metal mode by checking
# if address is in any of vmmap pages
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
##result.append(address) ##patch 3
except gdb.MemoryError:
break

return result

世界终于正常了.
















































但这远远没有结束.既然魔改了,就把之前不爽的地方都魔改一遍好了233333333

首先是heap命令打印chunk的时候,prevsize和size是十进制打印的,实际比赛中你还得把他转换成hex才有意义…

不过这不是pwndbg的错,因为gdb print malloc_chunk的时候就是这样打印的(真的怪

通过修改pwndbg/chain.pymalloc_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')
## edit start
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)
## edit end
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 │....│....│....│....│