mirror of https://github.com/pwndbg/pwndbg
Cleanup find_fake_fast
This commit is contained in:
parent
e6574f447f
commit
9a783c08ce
|
@ -544,49 +544,110 @@ def tcachebins(addr=None, verbose=False):
|
||||||
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.description = "Find candidate fake fast chunks overlapping the specified address."
|
parser.description = "Find candidate fake fast or tcache chunks overlapping the specified address."
|
||||||
parser.add_argument("addr", type=int, help="Address of the word-sized value to overlap.")
|
parser.add_argument("addr", type=int, help="Address of the word-sized value to overlap.")
|
||||||
parser.add_argument("size", nargs="?", type=int, default=None, help="Size of fake chunks to find.")
|
parser.add_argument(
|
||||||
|
"size", nargs="?", type=int, default=None, help="Maximum size of fake chunks to find."
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--align",
|
||||||
|
"-a",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
help="Whether the fake chunk must be aligned to MALLOC_ALIGNMENT. This is required for tcache "
|
||||||
|
+ "chunks and for all chunks when Safe Linking is enabled",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pwndbg.commands.ArgparsedCommand(parser)
|
@pwndbg.commands.ArgparsedCommand(parser)
|
||||||
@pwndbg.commands.OnlyWhenRunning
|
@pwndbg.commands.OnlyWhenRunning
|
||||||
@pwndbg.commands.OnlyWithResolvedHeapSyms
|
@pwndbg.commands.OnlyWithResolvedHeapSyms
|
||||||
@pwndbg.commands.OnlyWhenHeapIsInitialized
|
@pwndbg.commands.OnlyWhenHeapIsInitialized
|
||||||
def find_fake_fast(addr, size=None):
|
def find_fake_fast(addr, size=None, align=False):
|
||||||
"""Find candidate fake fast chunks overlapping the specified address."""
|
"""Find candidate fake fast chunks overlapping the specified address."""
|
||||||
psize = pwndbg.gdblib.arch.ptrsize
|
psize = pwndbg.gdblib.arch.ptrsize
|
||||||
allocator = pwndbg.heap.current
|
allocator = pwndbg.heap.current
|
||||||
align = allocator.malloc_alignment
|
malloc_alignment = allocator.malloc_alignment
|
||||||
|
|
||||||
min_fast = allocator.min_chunk_size
|
min_fast = allocator.min_chunk_size
|
||||||
max_fast = allocator.global_max_fast
|
max_fast = allocator.global_max_fast
|
||||||
max_fastbin = allocator.fastbin_index(max_fast)
|
max_fastbin = allocator.fastbin_index(max_fast)
|
||||||
start = int(addr) - max_fast + psize
|
|
||||||
if start < 0:
|
if size is None:
|
||||||
|
size = max_fast
|
||||||
|
elif size > addr:
|
||||||
|
print(message.warn("Size of 0x%x is greater than the target address 0x%x", (size, addr)))
|
||||||
|
size = addr
|
||||||
|
elif size > max_fast:
|
||||||
print(
|
print(
|
||||||
message.warn(
|
message.warn(
|
||||||
"addr - global_max_fast is negative, if the max_fast is not corrupted, you gave wrong address"
|
"0x%x is greater than the global_max_fast value of 0x%x" % (size, max_fast)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
start = 0 # TODO, maybe some better way to handle case when global_max_fast is overwritten with something large
|
elif size < min_fast:
|
||||||
mem = pwndbg.gdblib.memory.read(start, max_fast - psize, partial=True)
|
print(
|
||||||
|
message.warn(
|
||||||
|
"0x%x is smaller than the minimum fastbin chunk size of 0x%x" % (size, min_fast)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
size = min_fast
|
||||||
|
|
||||||
|
# Clear the flags
|
||||||
|
size &= ~0xF
|
||||||
|
|
||||||
|
start = int(addr) - size + psize
|
||||||
|
|
||||||
|
if align:
|
||||||
|
# If a chunk is aligned to MALLOC_ALIGNMENT, the size field should be at
|
||||||
|
# offset `psize`. First we align up to a multiple of `psize`
|
||||||
|
new_start = pwndbg.lib.memory.align_up(start, psize)
|
||||||
|
|
||||||
|
# Then we make sure we're at a multiple of `psize` but not `psize*2` by
|
||||||
|
# making sure the bottom nibble gets set to `psize`
|
||||||
|
new_start |= psize
|
||||||
|
|
||||||
|
# We should not have increased `start` by more than `psize*2 - 1` bytes
|
||||||
|
distance = new_start - start
|
||||||
|
assert distance < psize * 2
|
||||||
|
|
||||||
|
# If we're starting at a higher address, we still only want to read
|
||||||
|
# enough bytes to reach our target address
|
||||||
|
size -= distance
|
||||||
|
|
||||||
|
# Clear the flags
|
||||||
|
size &= ~0xF
|
||||||
|
|
||||||
|
start = new_start
|
||||||
|
|
||||||
|
print(
|
||||||
|
message.notice(
|
||||||
|
"Searching for fastbin sizes up to 0x%x starting at 0x%x resulting in an overlap of 0x%x"
|
||||||
|
% (size, start, addr)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Only consider `size - psize` bytes, since we're starting from after `prev_size`
|
||||||
|
mem = pwndbg.gdblib.memory.read(start, size - psize, partial=True)
|
||||||
|
|
||||||
fmt = {"little": "<", "big": ">"}[pwndbg.gdblib.arch.endian] + {4: "I", 8: "Q"}[psize]
|
fmt = {"little": "<", "big": ">"}[pwndbg.gdblib.arch.endian] + {4: "I", 8: "Q"}[psize]
|
||||||
|
|
||||||
if size is None:
|
|
||||||
sizes = range(min_fast, max_fast + 1, align)
|
|
||||||
else:
|
|
||||||
sizes = [int(size)]
|
|
||||||
|
|
||||||
print(C.banner("FAKE CHUNKS"))
|
print(C.banner("FAKE CHUNKS"))
|
||||||
for size in sizes:
|
step = malloc_alignment if align else 1
|
||||||
fastbin = allocator.fastbin_index(size)
|
for i in range(0, len(mem), step):
|
||||||
for offset in range((max_fastbin - fastbin) * align, max_fast - align + 1):
|
candidate = mem[i : i + psize]
|
||||||
candidate = mem[offset : offset + psize]
|
if len(candidate) == psize:
|
||||||
if len(candidate) == psize:
|
value = struct.unpack(fmt, candidate)[0]
|
||||||
value = struct.unpack(fmt, candidate)[0]
|
|
||||||
if allocator.fastbin_index(value) == fastbin:
|
# Clear any flags
|
||||||
malloc_chunk(start + offset - psize, fake=True)
|
value &= ~0xF
|
||||||
|
|
||||||
|
if value < min_fast:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# The value must be less than or equal to the max size we're looking
|
||||||
|
# for, but still be able to reach the target address
|
||||||
|
if value <= size and i + value >= size:
|
||||||
|
malloc_chunk(start + i - psize, fake=True)
|
||||||
|
|
||||||
|
|
||||||
pwndbg.gdblib.config.add_param(
|
pwndbg.gdblib.config.add_param(
|
||||||
|
|
Loading…
Reference in New Issue