diff --git a/pwndbg/commands/heap.py b/pwndbg/commands/heap.py index 83fd7fc48..dfd657d53 100644 --- a/pwndbg/commands/heap.py +++ b/pwndbg/commands/heap.py @@ -422,7 +422,7 @@ def malloc_chunk(addr, fake=False, verbose=False, simple=False) -> None: if verbose: fields_to_print.update(["prev_size", "size", "fd", "bk", "fd_nextsize", "bk_nextsize"]) else: - out_fields += f"Size: 0x{chunk.size:02x}\n" + out_fields += f"Size: 0x{chunk.real_size:02x} (with flag bits: 0x{chunk.size:02x})\n" prev_inuse, is_mmapped, non_main_arena = allocator.chunk_flags(chunk.size) if prev_inuse: @@ -434,7 +434,14 @@ def malloc_chunk(addr, fake=False, verbose=False, simple=False) -> None: fields_ordered = ["prev_size", "size", "fd", "bk", "fd_nextsize", "bk_nextsize"] for field_to_print in fields_ordered: - if field_to_print in fields_to_print: + if field_to_print not in fields_to_print: + continue + if field_to_print == "size": + out_fields += ( + message.system("size") + + f": 0x{chunk.real_size:02x} (with flag bits: 0x{chunk.size:02x})\n" + ) + else: out_fields += ( message.system(field_to_print) + f": 0x{getattr(chunk, field_to_print):02x}\n" ) diff --git a/tests/gdb-tests/tests/heap/test_find_fake_fast.py b/tests/gdb-tests/tests/heap/test_find_fake_fast.py index 22794cd14..de67999d6 100644 --- a/tests/gdb-tests/tests/heap/test_find_fake_fast.py +++ b/tests/gdb-tests/tests/heap/test_find_fake_fast.py @@ -68,10 +68,10 @@ def test_find_fake_fast_command(start_binary): # setup_mem(0x2F, 0x8) result = gdb.execute("find_fake_fast &target_address", to_string=True) - check_result(result, 0x2F) + check_result(result, 0x28) result = gdb.execute("find_fake_fast --align &target_address", to_string=True) - check_result(result, 0x2F) + check_result(result, 0x28) gdb.execute("continue") # setup_mem(0x20, 0x9) diff --git a/tests/gdb-tests/tests/heap/test_heap.py b/tests/gdb-tests/tests/heap/test_heap.py index 3ab77d950..c30a82a2b 100644 --- a/tests/gdb-tests/tests/heap/test_heap.py +++ b/tests/gdb-tests/tests/heap/test_heap.py @@ -14,42 +14,83 @@ HEAP_MALLOC_CHUNK = tests.binaries.get("heap_malloc_chunk.out") def generate_expected_malloc_chunk_output(chunks): expected = {} + + size = int( + chunks["allocated"][ + "mchunk_size" + if "mchunk_size" in (f.name for f in chunks["allocated"].type.fields()) + else "size" + ] + ) + real_size = size & (0xFFFFFFFFFFFFFFF - 0b111) expected["allocated"] = [ "Allocated chunk | PREV_INUSE", f"Addr: {chunks['allocated'].address}", - f"Size: 0x{int(chunks['allocated']['mchunk_size' if 'mchunk_size' in (f.name for f in chunks['allocated'].type.fields()) else 'size']):02x}", + f"Size: 0x{real_size:02x} (with flag bits: 0x{size:02x})", "", ] + size = int( + chunks["tcache"][ + "mchunk_size" + if "mchunk_size" in (f.name for f in chunks["tcache"].type.fields()) + else "size" + ] + ) + real_size = size & (0xFFFFFFFFFFFFFFF - 0b111) expected["tcache"] = [ f"Free chunk ({'tcachebins' if pwndbg.heap.current.has_tcache else 'fastbins'}) | PREV_INUSE", f"Addr: {chunks['tcache'].address}", - f"Size: 0x{int(chunks['tcache']['mchunk_size' if 'mchunk_size' in (f.name for f in chunks['tcache'].type.fields()) else 'size']):02x}", + f"Size: 0x{real_size:02x} (with flag bits: 0x{size:02x})", f"fd: 0x{int(chunks['tcache']['fd']):02x}", "", ] + size = int( + chunks["fast"][ + "mchunk_size" + if "mchunk_size" in (f.name for f in chunks["fast"].type.fields()) + else "size" + ] + ) + real_size = size & (0xFFFFFFFFFFFFFFF - 0b111) expected["fast"] = [ "Free chunk (fastbins) | PREV_INUSE", f"Addr: {chunks['fast'].address}", - f"Size: 0x{int(chunks['fast']['mchunk_size' if 'mchunk_size' in (f.name for f in chunks['fast'].type.fields()) else 'size']):02x}", + f"Size: 0x{real_size:02x} (with flag bits: 0x{size:02x})", f"fd: 0x{int(chunks['fast']['fd']):02x}", "", ] + size = int( + chunks["small"][ + "mchunk_size" + if "mchunk_size" in (f.name for f in chunks["small"].type.fields()) + else "size" + ] + ) + real_size = size & (0xFFFFFFFFFFFFFFF - 0b111) expected["small"] = [ "Free chunk (smallbins) | PREV_INUSE", f"Addr: {chunks['small'].address}", - f"Size: 0x{int(chunks['small']['mchunk_size' if 'mchunk_size' in (f.name for f in chunks['small'].type.fields()) else 'size']):02x}", + f"Size: 0x{real_size:02x} (with flag bits: 0x{size:02x})", f"fd: 0x{int(chunks['small']['fd']):02x}", f"bk: 0x{int(chunks['small']['bk']):02x}", "", ] + size = int( + chunks["large"][ + "mchunk_size" + if "mchunk_size" in (f.name for f in chunks["large"].type.fields()) + else "size" + ] + ) + real_size = size & (0xFFFFFFFFFFFFFFF - 0b111) expected["large"] = [ "Free chunk (largebins) | PREV_INUSE", f"Addr: {chunks['large'].address}", - f"Size: 0x{int(chunks['large']['mchunk_size' if 'mchunk_size' in (f.name for f in chunks['large'].type.fields()) else 'size']):02x}", + f"Size: 0x{real_size:02x} (with flag bits: 0x{size:02x})", f"fd: 0x{int(chunks['large']['fd']):02x}", f"bk: 0x{int(chunks['large']['bk']):02x}", f"fd_nextsize: 0x{int(chunks['large']['fd_nextsize']):02x}", @@ -57,10 +98,18 @@ def generate_expected_malloc_chunk_output(chunks): "", ] + size = int( + chunks["unsorted"][ + "mchunk_size" + if "mchunk_size" in (f.name for f in chunks["unsorted"].type.fields()) + else "size" + ] + ) + real_size = size & (0xFFFFFFFFFFFFFFF - 0b111) expected["unsorted"] = [ "Free chunk (unsortedbin) | PREV_INUSE", f"Addr: {chunks['unsorted'].address}", - f"Size: 0x{int(chunks['unsorted']['mchunk_size' if 'mchunk_size' in (f.name for f in chunks['unsorted'].type.fields()) else 'size']):02x}", + f"Size: 0x{real_size:02x} (with flag bits: 0x{size:02x})", f"fd: 0x{int(chunks['unsorted']['fd']):02x}", f"bk: 0x{int(chunks['unsorted']['bk']):02x}", "",