Develop Arena class (#1266)

* Develop Arena class

* Remove TODO comments

* Replace type() with isinstance()

* Use __slots__ in Chunk & Arena classes

* Remove unnecessary append()
This commit is contained in:
CptGibbon 2022-10-12 04:01:46 -07:00 committed by GitHub
parent 42caec2552
commit fc33d6fb7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 77 additions and 25 deletions

View File

@ -299,21 +299,16 @@ def malloc_chunk(addr, fake=False, verbose=False, simple=False):
out_fields = ""
verbose = True
else:
arena = allocator.get_arena_for_chunk(chunk.address)
arena_address = None
is_top = False
arena = chunk.arena
if not fake and arena:
arena_address = arena.address
top_chunk = arena["top"]
if chunk.address == top_chunk:
if chunk.is_top_chunk:
headers_to_print.append(message.off("Top chunk"))
is_top = True
if not is_top:
fastbins = allocator.fastbins(arena_address) or {}
smallbins = allocator.smallbins(arena_address) or {}
largebins = allocator.largebins(arena_address) or {}
unsortedbin = allocator.unsortedbin(arena_address) or {}
if not chunk.is_top_chunk:
fastbins = allocator.fastbins(arena.address) or {}
smallbins = allocator.smallbins(arena.address) or {}
largebins = allocator.largebins(arena.address) or {}
unsortedbin = allocator.unsortedbin(arena.address) or {}
if allocator.has_tcache():
tcachebins = allocator.tcachebins(None)

View File

@ -32,8 +32,26 @@ def heap_for_ptr(ptr):
class Chunk:
def __init__(self, addr):
if type(pwndbg.heap.current.malloc_chunk) == gdb.Type:
__slots__ = (
"_gdbValue",
"address",
"_prev_size",
"_size",
"_real_size",
"_flags",
"_non_main_arena",
"_is_mmapped",
"_prev_inuse",
"_fd",
"_bk",
"_fd_nextsize",
"_bk_nextsize",
"_arena",
"_is_top_chunk",
)
def __init__(self, addr, arena=None):
if isinstance(pwndbg.heap.current.malloc_chunk, gdb.Type):
self._gdbValue = pwndbg.gdblib.memory.poi(pwndbg.heap.current.malloc_chunk, addr)
else:
self._gdbValue = pwndbg.heap.current.malloc_chunk(addr)
@ -49,8 +67,8 @@ class Chunk:
self._bk = None
self._fd_nextsize = None
self._bk_nextsize = None
# TODO key, REVEAL_PTR
self._arena = arena
self._is_top_chunk = None
# Some chunk fields were renamed in GLIBC 2.25 master branch.
def __match_renamed_field(self, field):
@ -60,7 +78,7 @@ class Chunk:
}
for field_name in field_renames[field]:
if field_name in (f.name for f in self._gdbValue.type.fields()):
if gdb.types.has_field(self._gdbValue.type, field_name):
return field_name
raise ValueError(f"Chunk field name did not match any of {field_renames[field]}.")
@ -177,22 +195,61 @@ class Chunk:
return self._bk_nextsize
# TODO Other useful methods e.g. next_chunk(), __iter__, __str__
@property
def arena(self):
if self._arena is None:
try:
ar_ptr = pwndbg.heap.current.get_heap(self.address)["ar_ptr"]
ar_ptr.fetch_lazy()
except Exception:
ar_ptr = None
if ar_ptr is not None and ar_ptr in (ar.address for ar in pwndbg.heap.current.arenas):
self._arena = Arena(ar_ptr)
else:
self._arena = Arena(pwndbg.heap.current.main_arena.address)
return self._arena
@property
def is_top_chunk(self):
if self._is_top_chunk is None:
ar = self.arena
if ar is not None and self.address == ar.top:
self._is_top_chunk = True
else:
self._is_top_chunk = False
return self._is_top_chunk
class Arena:
def __init__(self, addr, heaps):
self.addr = addr
__slots__ = ("_gdbValue", "address", "is_main_arena", "_top", "heaps")
def __init__(self, addr, heaps=None):
if isinstance(pwndbg.heap.current.malloc_state, gdb.Type):
self._gdbValue = pwndbg.gdblib.memory.poi(pwndbg.heap.current.malloc_state, addr)
else:
self._gdbValue = pwndbg.heap.current.malloc_state(addr)
self.address = int(self._gdbValue.address)
self.is_main_arena = self.address == pwndbg.heap.current.main_arena.address
self._top = None
self.heaps = heaps
@property
def top(self):
if self._top is None:
try:
self._top = int(self._gdbValue["top"])
except gdb.MemoryError:
pass
return self._top
def __str__(self):
res = []
prefix = "[%%%ds] " % (pwndbg.gdblib.arch.ptrsize * 2)
prefix_len = len(prefix % (""))
arena_name = (
hex(self.addr) if self.addr != pwndbg.heap.current.main_arena.address else "main"
)
res.append(message.hint(prefix % (arena_name)) + str(self.heaps[0]))
arena_name = "main" if self.is_main_arena else hex(self.address)
res = [message.hint(prefix % (arena_name)) + str(self.heaps[0])]
for h in self.heaps[1:]:
res.append(" " * prefix_len + str(h))