diff --git a/pwndbg/arch.py b/pwndbg/arch.py index 7b3d84ea9..c901858aa 100644 --- a/pwndbg/arch.py +++ b/pwndbg/arch.py @@ -60,6 +60,10 @@ def update(): (8, 'big'): '>Q', }.get((m.ptrsize, m.endian)) + # Work around Python 2.7.6 struct.pack / unicode incompatibility + # See https://github.com/pwndbg/pwndbg/pull/336 for more information. + m.fmt = str(m.fmt) + # Attempt to detect the qemu-user binary name if m.current == 'arm' and m.endian == 'big': m.qemu = 'armeb' diff --git a/pwndbg/commands/search.py b/pwndbg/commands/search.py index acb88988d..0ab6e14ed 100644 --- a/pwndbg/commands/search.py +++ b/pwndbg/commands/search.py @@ -118,6 +118,10 @@ def search(type, hex, string, executable, writable, value, mapping_name, save, n 'qword': 'Q' }[type] + # Work around Python 2.7.6 struct.pack / unicode incompatibility + # See https://github.com/pwndbg/pwndbg/pull/336 for more information. + fmt = str(fmt) + try: value = struct.pack(fmt, value) except struct.error as e: diff --git a/pwndbg/heap/libheap.py b/pwndbg/heap/libheap.py deleted file mode 100644 index 88d3459c6..000000000 --- a/pwndbg/heap/libheap.py +++ /dev/null @@ -1,1878 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -The MIT License (MIT) - -Copyright (c) 2015 cloudburst - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - -import struct -import sys -from os import uname - -import gdb - -# bash color support -color_support = True -if color_support: - c_red = "\033[31m" - c_red_b = "\033[01;31m" - c_green = "\033[32m" - c_green_b = "\033[01;32m" - c_yellow = "\033[33m" - c_yellow_b = "\033[01;33m" - c_blue = "\033[34m" - c_blue_b = "\033[01;34m" - c_purple = "\033[35m" - c_purple_b = "\033[01;35m" - c_teal = "\033[36m" - c_teal_b = "\033[01;36m" - c_none = "\033[0m" -else: - c_red = "" - c_red_b = "" - c_green = "" - c_green_b = "" - c_yellow = "" - c_yellow_b = "" - c_blue = "" - c_blue_b = "" - c_purple = "" - c_purple_b = "" - c_teal = "" - c_teal_b = "" - c_none = "" -c_error = c_red -c_title = c_green_b -c_header = c_yellow_b -c_value = c_blue_b - -################################################################################ -# MALLOC CONSTANTS AND MACROS -################################################################################ - -_machine = uname()[4] -if _machine == "x86_64": - SIZE_SZ = 8 -elif _machine in ("i386", "i686"): - SIZE_SZ = 4 - -MIN_CHUNK_SIZE = 4 * SIZE_SZ -MALLOC_ALIGNMENT = 2 * SIZE_SZ -MALLOC_ALIGN_MASK = MALLOC_ALIGNMENT - 1 -MINSIZE = (MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK - -def chunk2mem(p): - "conversion from malloc header to user pointer" - return (p.address + (2*SIZE_SZ)) - -def mem2chunk(mem): - "conversion from user pointer to malloc header" - return (mem - (2*SIZE_SZ)) - -def request2size(req): - "pad request bytes into a usable size" - - if (req + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE): - return MINSIZE - else: - return (int(req + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) - -PREV_INUSE = 1 -IS_MMAPPED = 2 -NON_MAIN_ARENA = 4 -SIZE_BITS = (PREV_INUSE|IS_MMAPPED|NON_MAIN_ARENA) - -def prev_inuse(p): - "extract inuse bit of previous chunk" - return (p.size & PREV_INUSE) - -def chunk_is_mmapped(p): - "check for mmap()'ed chunk" - return (p.size & IS_MMAPPED) - -def chunk_non_main_arena(p): - "check for chunk from non-main arena" - return (p.size & NON_MAIN_ARENA) - -def chunksize(p): - "Get size, ignoring use bits" - return (p.size & ~SIZE_BITS) - -def next_chunk(p): - "Ptr to next physical malloc_chunk." - return (p.address + (p.size & ~SIZE_BITS)) - -def prev_chunk(p): - "Ptr to previous physical malloc_chunk" - return (p.address - p.prev_size) - -def chunk_at_offset(p, s): - "Treat space at ptr + offset as a chunk" - return malloc_chunk(p.address + s, inuse=False) - -def inuse(p): - "extract p's inuse bit" - return (malloc_chunk(p.address + \ - (p.size & ~SIZE_BITS), inuse=False).size & PREV_INUSE) - -def set_inuse(p): - "set chunk as being inuse without otherwise disturbing" - chunk = malloc_chunk((p.address + (p.size & ~SIZE_BITS)), inuse=False) - chunk.size |= PREV_INUSE - chunk.write() - -def clear_inuse(p): - "clear chunk as being inuse without otherwise disturbing" - chunk = malloc_chunk((p.address + (p.size & ~SIZE_BITS)), inuse=False) - chunk.size &= ~PREV_INUSE - chunk.write() - -def inuse_bit_at_offset(p, s): - "check inuse bits in known places" - return (malloc_chunk((p.address + s), inuse=False).size & PREV_INUSE) - -def set_inuse_bit_at_offset(p, s): - "set inuse bits in known places" - chunk = malloc_chunk((p.address + s), inuse=False) - chunk.size |= PREV_INUSE - chunk.write() - -def clear_inuse_bit_at_offset(p, s): - "clear inuse bits in known places" - chunk = malloc_chunk((p.address + s), inuse=False) - chunk.size &= ~PREV_INUSE - chunk.write() - -def bin_at(m, i): - "addressing -- note that bin_at(0) does not exist" - if SIZE_SZ == 4: - offsetof_fd = 0x8 - return (gdb.parse_and_eval("&main_arena.bins[%d]" % \ - ((i -1) * 2)).cast(gdb.lookup_type('unsigned int')) - offsetof_fd) - elif SIZE_SZ == 8: - offsetof_fd = 0x10 - return (gdb.parse_and_eval("&main_arena.bins[%d]" % \ - ((i -1) * 2)).cast(gdb.lookup_type('unsigned long')) - offsetof_fd) - -def next_bin(b): - return (b + 1) - -def first(b): - return b.fd - -def last(b): - return b.bk - -NBINS = 128 -NSMALLBINS = 64 -SMALLBIN_WIDTH = MALLOC_ALIGNMENT -MIN_LARGE_SIZE = (NSMALLBINS * SMALLBIN_WIDTH) - -def in_smallbin_range(sz): - "check if size is in smallbin range" - return (sz < MIN_LARGE_SIZE) - -def smallbin_index(sz): - "return the smallbin index" - - if SMALLBIN_WIDTH == 16: - return (sz >> 4) - else: - return (sz >> 3) - -def largebin_index_32(sz): - "return the 32bit largebin index" - - if (sz >> 6) <= 38: - return (56 + (sz >> 6)) - elif (sz >> 9) <= 20: - return (91 + (sz >> 9)) - elif (sz >> 12) <= 10: - return (110 + (sz >> 12)) - elif (sz >> 15) <= 4: - return (119 + (sz >> 15)) - elif (sz >> 18) <= 2: - return (124 + (sz >> 18)) - else: - return 126 - -def largebin_index_64(sz): - "return the 64bit largebin index" - - if (sz >> 6) <= 48: - return (48 + (sz >> 6)) - elif (sz >> 9) <= 20: - return (91 + (sz >> 9)) - elif (sz >> 12) <= 10: - return (110 + (sz >> 12)) - elif (sz >> 15) <= 4: - return (119 + (sz >> 15)) - elif (sz >> 18) <= 2: - return (124 + (sz >> 18)) - else: - return 126 - -def largebin_index(sz): - "return the largebin index" - - if SIZE_SZ == 8: - return largebin_index_64(sz) - else: - return largebin_index_32(sz) - -def bin_index(sz): - "return the bin index" - - if in_smallbin_range(sz): - return smallbin_index(sz) - else: - return largebin_index(sz) - -BINMAPSHIFT = 5 -BITSPERMAP = 1 << BINMAPSHIFT -BINMAPSIZE = (NBINS / BITSPERMAP) - -def fastbin(ar_ptr, idx): - return ar_ptr.fastbinsY[idx] - -def fastbin_index(sz): - "offset 2 to use otherwise unindexable first 2 bins" - if SIZE_SZ == 8: - return ((sz >> 4) - 2) - else: - return ((sz >> 3) - 2) - -MAX_FAST_SIZE = (80 * SIZE_SZ / 4) -NFASTBINS = (fastbin_index(request2size(MAX_FAST_SIZE)) + 1) - -FASTCHUNKS_BIT = 0x1 - -def have_fastchunks(M): - return ((M.flags & FASTCHUNKS_BIT) == 0) - -def clear_fastchunks(M, inferior=None): - if inferior == None: - inferior = get_inferior() - - M.flags |= FASTCHUNKS_BIT - inferior.write_memory(M.address, struct.pack(" ",c_value,"[ ",fd," ]",c_none), end=' ') - - if fd == 0: #fastbin is empty - print("") - else: - fb_size = ((MIN_CHUNK_SIZE) +(MALLOC_ALIGNMENT)*fb) - print("(%d)" % fb_size) - chunk = malloc_chunk(fd, inuse=False) - while chunk.fd != 0: - if chunk.fd is None: # could not read memory section - break - print("%s%26s0x%08lx%s%s(%d)" % (c_value,"[ ",chunk.fd," ] ",c_none, fb_size)) - chunk = malloc_chunk(chunk.fd, inuse=False) - - if fb_num != None: #only print one fastbin - return - - -################################################################################ -def print_smallbins(inferior, sb_base, sb_num): - "walk and print the small bins" - - print(c_title + "===================================", end=' ') - print("Smallbins ==================================\n" + c_none) - - for sb in range(2,NBINS+2,2): - if sb_num != None and sb_num!=0: - sb = sb_num*2 - - offset = sb_base + (sb-2)*SIZE_SZ - try: - mem = inferior.read_memory(offset, 2*SIZE_SZ) - if SIZE_SZ == 4: - fd,bk = struct.unpack(" ",c_value,"[ ", fd, " | ", bk, " ] ", \ - c_none)) - - while (1): - if fd == (offset-2*SIZE_SZ): - break - - chunk = malloc_chunk(fd, inuse=False) - print("%s%26s0x%08lx%s0x%08lx%s%s" % \ - (c_value,"[ ",chunk.fd," | ",chunk.bk," ] ",c_none), end=' ') - print("(%d)" % chunksize(chunk)) - - fd = chunk.fd - - if sb_num != None: #only print one smallbin - return - - -################################################################################ -def print_bins(inferior, fb_base, sb_base): - "walk and print the nonempty free bins, modified from jp" - - print(c_title + "==================================", end=' ') - print("Heap Dump ===================================\n" + c_none) - - for fb in range(0,NFASTBINS): - print_once = True - p = malloc_chunk(fb_base-(2*SIZE_SZ)+fb*SIZE_SZ, inuse=False) - - while (p.fd != 0): - if p.fd is None: - break - - if print_once: - print_once = False - print(c_header + " fast bin %d @ 0x%lx" % \ - (fb,p.fd) + c_none) - print(" free chunk @ " + c_value + "0x%lx" % p.fd + c_none + \ - " - size" + c_value, end=' ') - p = malloc_chunk(p.fd, inuse=False) - print("0x%lx" % chunksize(p) + c_none) - - for i in range(1, NBINS): - print_once = True - b = sb_base + i*2*SIZE_SZ - 4*SIZE_SZ - p = malloc_chunk(first(malloc_chunk(b, inuse=False)), inuse=False) - - while p.address != b: - if print_once: - print_once = False - if i==1: - try: - print(c_header + " unsorted bin @ 0x%lx" % \ - (b.cast(gdb.lookup_type("unsigned long")) \ - + 2*SIZE_SZ) + c_none) - except: - print(c_header + " unsorted bin @ 0x%lx" % \ - (b + 2*SIZE_SZ) + c_none) - else: - try: - print(c_header + " small bin %d @ 0x%lx" % \ - (i,b.cast(gdb.lookup_type("unsigned long")) \ - + 2*SIZE_SZ) + c_none) - except: - print(c_header + " small bin %d @ 0x%lx" % \ - (i,b + 2*SIZE_SZ) + c_none) - - print(c_none + " free_chunk @ " + c_value \ - + "0x%lx " % p.address + c_none \ - + "- size " + c_value + "0x%lx" % chunksize(p) + c_none) - - p = malloc_chunk(first(p), inuse=False) - - -################################################################################ -def print_flat_listing(ar_ptr, sbrk_base): - "print a flat listing of an arena, modified from jp and arena.c" - - print(c_title + "==================================", end=' ') - print("Heap Dump ===================================\n" + c_none) - print("%s%14s%17s%15s%s" % (c_header, "ADDR", "SIZE", "STATUS", c_none)) - print("sbrk_base " + c_value + "0x%lx" % sbrk_base) - - p = malloc_chunk(sbrk_base, inuse=True, read_data=False) - - while(1): - print("%schunk %s0x%-14lx 0x%-10lx%s" % \ - (c_none, c_value, p.address, chunksize(p), c_none), end=' ') - - if p.address == top(ar_ptr): - print("(top)") - break - elif p.size == (0|PREV_INUSE): - print("(fence)") - break - - if inuse(p): - print("%s" % "(inuse)") - else: - p = malloc_chunk(p.address, inuse=False) - print("(F) FD %s0x%lx%s BK %s0x%lx%s" % \ - (c_value, p.fd, c_none,c_value,p.bk,c_none), end=' ') - - if ((p.fd == ar_ptr.last_remainder) \ - and (p.bk == ar_ptr.last_remainder) \ - and (ar_ptr.last_remainder != 0)): - print("(LR)") - elif ((p.fd == p.bk) & ~inuse(p)): - print("(LC)") - else: - print("") - - p = malloc_chunk(next_chunk(p), inuse=True, read_data=False) - - print(c_none + "sbrk_end " + c_value \ - + "0x%lx" % (sbrk_base + ar_ptr.system_mem) + c_none) - - -################################################################################ -def print_compact_listing(ar_ptr, sbrk_base): - "print a compact layout of the heap, modified from jp" - - print(c_title + "==================================", end=' ') - print("Heap Dump ===================================" + c_none) - p = malloc_chunk(sbrk_base, inuse=True, read_data=False) - - while(1): - if p.address == top(ar_ptr): - sys.stdout.write("|T|\n") - break - - if inuse(p): - sys.stdout.write("|A|") - else: - p = malloc_chunk(p.address, inuse=False) - - if ((p.fd == ar_ptr.last_remainder) \ - and (p.bk == ar_ptr.last_remainder) \ - and (ar_ptr.last_remainder != 0)): - sys.stdout.write("|L|") - else: - sys.stdout.write("|%d|" % bin_index(p.size)) - - p = malloc_chunk(next_chunk(p), inuse=True, read_data=False) - - -################################################################################ -class print_bin_layout(gdb.Command): - "dump the layout of a free bin" - - def __init__(self): - super(print_bin_layout, self).__init__("print_bin_layout", - gdb.COMMAND_DATA, gdb.COMPLETE_NONE) - - def invoke(self, arg, from_tty): - "Specify an optional arena addr: print_bin_layout main_arena=0x12345" - - if len(arg) == 0: - sys.stdout.write(c_error) - print("Please specify the free bin to dump") - sys.stdout.write(c_none) - return - - try: - if arg.find("main_arena") == -1: - main_arena = gdb.selected_frame().read_var('main_arena') - main_arena_address = main_arena.address - else: - arg = arg.split() - for item in arg: - if item.find("main_arena") != -1: - if len(item) < 12: - sys.stdout.write(c_error) - print("Malformed main_arena parameter") - sys.stdout.write(c_none) - return - else: - main_arena_address = int(item[11:],16) - except RuntimeError: - sys.stdout.write(c_error) - print("No frame is currently selected.") - sys.stdout.write(c_none) - return - except ValueError: - sys.stdout.write(c_error) - print("Debug glibc was not found.") - sys.stdout.write(c_none) - return - - if main_arena_address == 0: - sys.stdout.write(c_error) - print("Invalid main_arena address (0)") - sys.stdout.write(c_none) - return - - ar_ptr = malloc_state(main_arena_address) - mutex_lock(ar_ptr) - - sys.stdout.write(c_title) - print("=================================", end=' ') - print("Bin Layout ===================================\n") - sys.stdout.write(c_none) - - b = bin_at(ar_ptr, int(arg)) - p = malloc_chunk(first(malloc_chunk(b, inuse=False)), inuse=False) - print_once = True - print_str = "" - count = 0 - - while p.address != b: - if print_once: - print_once=False - print_str += "--> " + c_value + "[bin %d]" % int(arg) + c_none - count += 1 - - print_str += " <--> " + c_value + "0x%lx" % p.address + c_none - count += 1 - #print_str += " <--> 0x%lx" % p.address - p = malloc_chunk(first(p), inuse=False) - - if len(print_str) != 0: - print_str += " <--" - print(print_str) - print("%s%s%s" % ("|"," " * (len(print_str) - 2 - count*12),"|")) - print("%s" % ("-" * (len(print_str) - count*12))) - else: - print("Bin %d empty." % int(arg)) - - mutex_unlock(ar_ptr) - - -################################################################################ -class check_house_of_mind(gdb.Command): - "print and help validate a house of mind layout" - - def __init__(self): - super(check_house_of_mind, self).__init__("check_house_of_mind", - gdb.COMMAND_DATA, gdb.COMPLETE_NONE) - - def invoke(self, arg, from_tty): - """ - Specify the house of mind method and chunk address (p=mem2chunk(mem)): - check_house_of_mind method=unsortedbin p=0x12345678 - check_house_of_mind method=fastbin p=0x12345678 - """ - - if arg.find("method") == -1: - print("Please specify the House of Mind method to use:") - print("house_of_mind method={unsortedbin, fastbin}") - return - elif arg.find("p") == -1: - print("Please specify the chunk address to use:") - print("house_of_mind p=0x12345678") - return - else: - arg = arg.split() - for item in arg: - if item.find("method") != -1: - if len(item) < 8: - sys.stdout.write(c_error) - print("Malformed method parameter") - print("Please specify the House of Mind method to use:") - print("house_of_mind method={unsortedbin, fastbin}") - sys.stdout.write(c_none) - return - else: - method = item[7:] - if item.find("p") != -1: - if len(item) < 11: - sys.stdout.write(c_error) - print("Malformed chunk parameter") - print("Please specify the chunk address to use:") - print("house_of_mind p=0x12345678") - sys.stdout.write(c_none) - return - else: - p = int(item[2:],16) - - sys.stdout.write(c_title) - print("===============================", end=' ') - print("House of Mind ==================================\n") - sys.stdout.write(c_none) - - if method.find("unsorted") != -1: - self.unsorted_bin_method(p) - elif method.find("fast") != -1: - self.fast_bin_method(p) - - def unsorted_bin_method(self, p): - p = malloc_chunk(addr=p, inuse=True, read_data=False) - - print(c_none + "Checking chunk p") - print(c_none + " [*] p = " + c_value + "0x%x" % p.address + c_none) - - if p.address < gdb.parse_and_eval("(unsigned int)%d" % -chunksize(p)): - print(" [*] size does not wrap") - else: - print(c_error + " [_] ERROR: p > -size" + c_none) - return - - if chunksize(p) >= MINSIZE: - print(" [*] size is > minimum chunk size") - else: - print(c_error + " [_] ERROR: chunksize(p) < MINSIZE" + c_none) - return - - if chunksize(p) > get_max_fast(): - print(" [*] size is not in fastbin range") - else: - print(c_error + " [_] ERROR: size is in fastbin range" + c_none) - return - - if not chunk_is_mmapped(p): - print(" [*] is_mmapped bit is not set") - else: - print(c_error + " [_] ERROR: IS_MMAPPED bit is set" + c_none) - return - - if prev_inuse(p): - print(" [*] prev_inuse bit is set") - else: - print(c_error + " [_] ERROR: PREV_INUSE bit is not set, this will", end=' ') - print("trigger backward consolidation" + c_none) - - if chunk_non_main_arena(p): - print(" [*] non_main_arena flag is set") - else: - print(c_error + " [_] ERROR: p's non_main_arena flag is NOT set") - return - - print(c_none + "\nChecking struct heap_info") - print(c_none + " [*] struct heap_info = " \ - + c_value + "0x%x" % heap_for_ptr(p.address)) - - inferior = get_inferior() - if inferior == -1: - return None - - try: - mem = inferior.read_memory(heap_for_ptr(p.address), SIZE_SZ) - if SIZE_SZ == 4: - ar_ptr = struct.unpack("mutex is zero") - else: - print(c_error + " [_] ERROR: av->mutex is not zero" + c_none) - return - - if p.address != av.top: - print(c_none + " [*] p is not the top chunk") - else: - print(c_error + " [_] ERROR: p is the top chunk" + c_none) - return - - if noncontiguous(av): - print(c_none + " [*] noncontiguous_bit is set") - elif contiguous(av): - print(c_error + \ - " [_] ERROR: noncontiguous_bit is NOT set in av->flags" + c_none) - return - - print(" [*] bck = &av->bins[0] = " + c_value + "0x%x" % (ar_ptr+0x38)) - - if SIZE_SZ == 4: - print(c_none + " [*] fwd = bck->fd = *(&av->bins[0] + 8) =", end=' ') - elif SIZE_SZ == 8: - print(c_none + " [*] fwd = bck->fd = *(&av->bins[0] + 16) =", end=' ') - - fwd = inferior.read_memory(ar_ptr + 0x38 + 2*SIZE_SZ, SIZE_SZ) - if SIZE_SZ == 4: - fwd = struct.unpack("bk (0x%x) != bck (0x%x)" % \ - (fwd, ar_ptr+0x38) + c_error) - print(" - ERROR: This will prevent this attack on glibc 2.11+", end=' ') - print(c_none) - - print(c_none + "\nChecking following chunks") - nextchunk = chunk_at_offset(p, chunksize(p)) - - if prev_inuse(nextchunk): - print(c_none + " [*] prev_inuse of the next chunk is set") - else: - print(c_error + " [_] PREV_INUSE bit of the next chunk is not set" \ - + c_none) - return - - if chunksize(nextchunk) > 2*SIZE_SZ: - print(c_none + " [*] nextchunk size is > minimum size") - else: - print(c_error + " [_] ERROR: nextchunk size (%d) < %d" % \ - (chunksize(nextchunk), 2*SIZE_SZ) + c_none) - return - - if chunksize(nextchunk) < av.system_mem: - print(c_none + " [*] nextchunk size is < av->system_mem") - else: - print(c_error + " [_] ERROR: nextchunk size (0x%x) >" % \ - chunksize(nextchunk), end=' ') - print("av->system_mem (0x%x)" % av.system_mem + c_none) - return - - if nextchunk.address != av.top: - print(c_none + " [*] nextchunk != av->top") - else: - print(c_error + " [_] ERROR: nextchunk is av->top (0x%x)" % av.top \ - + c_none) - return - - if inuse_bit_at_offset(nextchunk, chunksize(nextchunk)): - print(c_none + " [*] prev_inuse bit set on chunk after nextchunk") - else: - print(c_error + " [_] ERROR: PREV_INUSE bit of chunk after", end=' ') - print("nextchunk (0x%x) is not set" % \ - (nextchunk.address + chunksize(nextchunk)) + c_none) - return - - print(c_header + "\np (0x%x) will be written to fwd->bk (0x%x)" \ - % (p.address, fwd+0xC) + c_none) - - def fast_bin_method(self, p): - p = malloc_chunk(addr=p, inuse=True, read_data=False) - - print(c_none + "Checking chunk p") - print(c_none + " [*] p = " + c_value + "0x%x" % p.address + c_none) - - if p.address < gdb.parse_and_eval("(unsigned int)%d" % -chunksize(p)): - print(" [*] size does not wrap") - else: - print(c_error + " [_] ERROR: p > -size" + c_none) - return - - if chunksize(p) >= MINSIZE: - print(" [*] size is >= minimum chunk size") - else: - print(c_error + " [_] ERROR: chunksize(p) < MINSIZE" + c_none) - return - - if chunksize(p) < get_max_fast(): - print(" [*] size is in fastbin range") - else: - print(c_error + " [_] ERROR: size is not in fastbin range" + c_none) - return - - if chunk_non_main_arena(p): - print(" [*] non_main_arena flag is set") - else: - print(c_error + " [_] ERROR: p's non_main_arena flag is NOT set") - return - - if prev_inuse(p): - print(" [*] prev_inuse bit is set") - else: - print(c_error + " [_] ERROR: PREV_INUSE bit is not set, this will", end=' ') - print("trigger backward consolidation" + c_none) - - print(c_none + "\nChecking struct heap_info") - print(c_none + " [*] struct heap_info = " \ - + c_value + "0x%x" % heap_for_ptr(p.address)) - - inferior = get_inferior() - if inferior == -1: - return None - - try: - mem = inferior.read_memory(heap_for_ptr(p.address), SIZE_SZ) - if SIZE_SZ == 4: - ar_ptr = struct.unpack("mutex is zero") - else: - print(c_error + " [_] ERROR: av->mutex is not zero" + c_none) - return - - print(c_none + " [*] av->system_mem is 0x%x" % av.system_mem) - - print(c_none + "\nChecking following chunk") - nextchunk = chunk_at_offset(p, chunksize(p)) - print(" [*] nextchunk = " + c_value + "0x%x" % nextchunk.address) - - if nextchunk.size > 2*SIZE_SZ: - print(c_none + " [*] nextchunk size is > 2*SIZE_SZ") - else: - print(c_error + " [_] ERROR: nextchunk size is <= 2*SIZE_SZ" +c_none) - return - - if chunksize(nextchunk) < av.system_mem: - print(c_none + " [*] nextchunk size is < av->system_mem") - else: - print(c_error + " [_] ERROR: nextchunk size (0x%x) is >= " % \ - chunksize(nextchunk), end=' ') - print("av->system_mem (0x%x)" % (av.system_mem) + c_none) - return - - fb = ar_ptr + (2*SIZE_SZ) + (fastbin_index(p.size)*SIZE_SZ) - print(c_header + "\np (0x%x) will be written to fb (0x%x)" \ - % (p.address, fb) + c_none) - - -################################################################################ -# INITIALIZE CUSTOM GDB CODE -################################################################################ - -heap() -print_malloc_stats() -print_bin_layout() -check_house_of_mind() -gdb.pretty_printers.append(pretty_print_heap_lookup)