Merge branch 'heap'

pull/22/head
Zach Riggle 10 years ago
commit 66e9f40520

@ -23,6 +23,7 @@ import pwndbg.stdio
import pwndbg.color
import pwndbg.typeinfo
import pwndbg.constants
import pwndbg.argv
import pwndbg.commands
import pwndbg.commands.hexdump
import pwndbg.commands.context
@ -43,6 +44,9 @@ import pwndbg.commands.misc
import pwndbg.commands.next
import pwndbg.commands.dumpargs
import pwndbg.commands.cpsr
import pwndbg.commands.argv
import pwndbg.commands.heap
__all__ = [
'arch',

@ -23,6 +23,7 @@ def fix_arch(arch):
arches = ['x86-64', 'i386', 'mips', 'powerpc', 'sparc', 'arm', 'aarch64', arch]
return next(a for a in arches if a in arch)
@pwndbg.events.start
@pwndbg.events.stop
def update():
m = sys.modules[__name__]

@ -0,0 +1,41 @@
import pwndbg.arch
import pwndbg.events
import pwndbg.memory
import pwndbg.regs
argc = None
argv = None
envp = None
envc = None
@pwndbg.events.start
def update():
global argc
global argv
global envp
global envc
pwndbg.arch.update() # :-(
sp = pwndbg.regs.sp
ptrsize = pwndbg.arch.ptrsize
ptrbits = 8 * ptrsize
argc = pwndbg.memory.u(sp, ptrbits)
sp += ptrsize
argv = sp
while pwndbg.memory.u(sp, ptrbits):
sp += ptrsize
sp += ptrsize
envp = sp
envc = 0
while pwndbg.memory.u(sp, ptrbits):
sp += ptrsize
envc += 1

@ -56,6 +56,8 @@ class _ParsedCommand(_Command):
# sys.stdout.write(repr(argv) + '\n')
return list(filter(lambda x: x is not None, map(fix, argv)))
def fix(arg, sloppy=False):
try:
parsed = gdb.parse_and_eval(arg)

@ -0,0 +1,50 @@
import gdb
import pwndbg.argv
import pwndbg.commands
@pwndbg.commands.OnlyWhenRunning
@pwndbg.commands.Command
def argc():
"""
Prints out the number of arguments.
"""
print pwndbg.argv.argc
@pwndbg.commands.OnlyWhenRunning
@pwndbg.commands.Command
def argv():
"""
Prints out the contents of argv.
"""
pwndbg.commands.telescope.telescope(pwndbg.argv.argv, pwndbg.argv.argc+1)
@pwndbg.commands.Command
def args():
"""
Prints out the contents of argv.
"""
argv()
@pwndbg.commands.OnlyWhenRunning
@pwndbg.commands.Command
def envp():
"""
Prints out the contents of the environment.
"""
envp = pwndbg.argv.envp
pwndbg.commands.telescope.telescope(pwndbg.argv.envp, pwndbg.argv.envc+1)
@pwndbg.commands.Command
def env():
"""
Prints out the contents of the environment.
"""
envp()
@pwndbg.commands.Command
def environ():
"""
Prints out the contents of the environment.
"""
envp()

@ -7,6 +7,9 @@ import pwndbg.disasm
@pwndbg.commands.Command
@pwndbg.commands.OnlyWhenRunning
def dumpargs(*a):
"""
If the current instruction is a call instruction, print that arguments.
"""
result = []
# For call instructions, attempt to resolve the target and
@ -16,4 +19,4 @@ def dumpargs(*a):
pretty = pwndbg.chain.format(value, code=code)
result.append('%8s%-10s %s' % ('',arg.name+':', pretty))
print('\n'.join(result))
print('\n'.join(result))

@ -0,0 +1,43 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Heap commands.
"""
import argparse
import gdb
import pwndbg.commands
@pwndbg.commands.OnlyWhenRunning
@pwndbg.commands.ParsedCommand
def brk(n=0):
gdb.execute('call brk(%i)' % n)
@pwndbg.commands.OnlyWhenRunning
@pwndbg.commands.ParsedCommand
def sbrk(n=0):
gdb.execute('call sbrk(%i)' % n)
p = argparse.ArgumentParser(prog='hheap')
p.add_argument('--size',
help='Heap size. May be expressed as an integer or range (e.g. 32-64).')
p.add_argument('--verbose', action='store_true',
help='Print more information')
p.add_argument('--free', action='store_true',
help='Only show free slots')
p.add_argument('address', type=int, default=0,
help='Heap allocation to display')
@pwndbg.commands.OnlyWhenRunning
@pwndbg.commands.Command
def hheap(*a):
"""Prints out heap information.
""" + p.format_help()
try:
args = p.parse_args(a)
except SystemExit:
return

@ -3,11 +3,10 @@ import errno as _errno
import struct
import pwndbg as _pwndbg
import pwndbg.arch as _arch
import pwndbg.commands
import pwndbg.regs
import pwndbg.commands
import pwndbg.regs
_errno.errorcode[0] = 'OK'
@ -42,3 +41,12 @@ def pwndbg():
if docs: docs = docs.splitlines()[0]
print("%-20s %s" % (name, docs))
@_pwndbg.commands.ParsedCommand
def distance(a, b):
a = int(a) & _arch.ptrmask
b = int(b) & _arch.ptrmask
distance = (b-a)
print "%#x->%#x is %#x bytes (%#x words)" % (a, b, distance, distance / _arch.ptrsize)

@ -4,6 +4,8 @@ import capstone
import collections
from capstone import *
CS_OP_IMM
debug = False
groups = {v:k for k,v in globals().items() if k.startswith('CS_GRP_')}

@ -116,7 +116,8 @@ class DisassemblyAssistant(pwndbg.disasm.arch.DisassemblyAssistant):
address = (pwndbg.regs.sp) + (pwndbg.arch.ptrsize * pop)
return int(pwndbg.memory.poi(pwndbg.typeinfo.ppvoid, address))
if pwndbg.memory.peek(address):
return int(pwndbg.memory.poi(pwndbg.typeinfo.ppvoid, address))

@ -64,13 +64,32 @@ class Pause(object):
global pause
pause -= 1
# When performing remote debugging, gdbserver is very noisy about which
# objects are loaded. This greatly slows down the debugging session.
# In order to combat this, we keep track of which objfiles have been loaded
# this session, and only emit objfile events for each *new* file.
objfile_cache = set()
def connect(func, event_handler, name=''):
if debug:
print("Connecting", func.__name__, event_handler)
@functools.wraps(func)
def caller(*a):
if debug: sys.stdout.write('%r %s.%s %r\n' % (name, func.__module__, func.__name__, a))
if debug:
sys.stdout.write('%r %s.%s %r\n' % (name, func.__module__, func.__name__, a))
if a and isinstance(a[0], gdb.NewObjFileEvent):
objfile = a[0].new_objfile
path = objfile.filename
if path in objfile_cache:
return
print path, objfile.is_valid()
objfile_cache.add(path)
if pause: return
with pwndbg.stdio.stdio:
try:
@ -110,3 +129,8 @@ def _start_newobjfile():
@stop
def _start_stop():
gdb.events.start.on_stop()
@exit
def _reset_objfiles():
global objfile_cache
objfile_cache = set()

@ -0,0 +1,17 @@
import pwndbg.heap.heap
import pwndbg.heap.dlmalloc
import pwndbg.heap.ptmalloc
current = pwndbg.heap.heap.Heap()
@pwndbg.events.new_objfile
def update():
global current
if pwndbg.symbol.get('ptmalloc_init'):
current = pwndbg.heap.ptmalloc.Heap()
elif pwndbg.symbol.get('malloc_stats'):
current = pwndbg.heap.dlmalloc.Heap()

@ -0,0 +1,13 @@
import gdb
import pwndbg.events
import pwndbg.typeinfo
malloc_chunk = None
malloc_state = None
mallinfo = None
@pwndbg.events.new_objfile
def update():
malloc_chunk = gdb.lookup_type('struct malloc_chunk')
malloc_state = gdb.lookup_type('struct malloc_state')
mallinfo = gdb.lookup_type('struct mallinfo')

@ -0,0 +1,38 @@
import pwndbg.events
import pwndbg.symbol
class Heap(object):
"""Heap abstraction layer."""
def breakpoint(event):
"""Enables breakpoints on the specific event.
Arguments:
event(str): One of 'alloc','realloc','free'
Returns:
A gdb.Breakpoint object.
"""
raise NotImplementedError()
def summarize(address, **kwargs):
"""Returns a textual summary of the specified address.
Arguments:
address(int): Address of the heap block to summarize.
Returns:
A string.
"""
raise NotImplementedError()
def containing(address):
"""Returns the address of the allocation which contains 'address'.
Arguments:
address(int): Address to look up.
Returns:
An integer.
"""
raise NotImplementedError()

File diff suppressed because it is too large Load Diff

@ -0,0 +1,13 @@
import gdb
import pwndbg.events
import pwndbg.typeinfo
malloc_chunk = None
malloc_state = None
mallinfo = None
@pwndbg.events.new_objfile
def update():
malloc_chunk = gdb.lookup_type('struct malloc_chunk')
malloc_state = gdb.lookup_type('struct malloc_state')
mallinfo = gdb.lookup_type('struct mallinfo')

@ -4,6 +4,7 @@
Reading, writing, and describing memory.
"""
import gdb
import pwndbg.arch
import pwndbg.compat
import pwndbg.typeinfo
@ -73,7 +74,9 @@ def u16(addr): return readtype(pwndbg.typeinfo.uint16, addr)
def u32(addr): return readtype(pwndbg.typeinfo.uint32, addr)
def u64(addr): return readtype(pwndbg.typeinfo.uint64, addr)
def u(addr, size):
def u(addr, size=None):
if size is None:
size = pwndbg.arch.ptrsize * 8
return {
8: u8,
16: u16,
@ -91,7 +94,8 @@ def write(addr, data):
def poi(type, addr): return gdb.Value(addr).cast(type.pointer()).dereference()
def round_down(address, align): return address & ~(align-1)
def round_down(address, align):
return address & ~(align-1)
def round_up(address, align): return (address+(align-1))&(~(align-1))
align_down = round_down

@ -9,7 +9,11 @@ information available.
"""
import gdb
import re
import os
import tempfile
import pwndbg.elf
import pwndbg.events
import pwndbg.file
import pwndbg.ida
import pwndbg.memoize
import pwndbg.memory
@ -17,6 +21,66 @@ import pwndbg.remote
import pwndbg.stack
import pwndbg.vmmap
def get_directory():
"""
Retrieve the debug file directory path.
The debug file directory path ('show debug-file-directory') is a comma-
separated list of directories which GDB will look in to find the binaries
currently loaded.
"""
result = gdb.execute('show debug-file-directory', to_string=True, from_tty=False)
expr = r'The directory where separate debug symbols are searched for is "(.*)".\n'
match = re.search(expr, result)
if match:
return match.group(1)
return ''
def set_directory(d):
gdb.execute('set debug-file-directory %s' % d, to_string=True, from_tty=False)
def add_directory(d):
current = get_directory()
if current:
set_directory('%s:%s' (current, d))
else:
set_directory(d)
remote_files = {}
remote_files_dir = None
@pwndbg.events.on_stop
def reset_remote_files():
global remote_files
global remote_files_dir
remote_files = {}
remote_files_dir = tempfile.mkdtemp()
def autofetch():
"""
"""
global remote_files_dir
if not pwndbg.remote.is_remote():
return
if not remote_files_dir:
remote_files_dir = tempfile.mkdtemp()
add_directory(remote_files_dir)
searchpath = get_directory()
for mapping in pwndbg.vmmap.get():
objfile = mapping.objfile
if not objfile or objfile in remote_files:
continue
data = pwndbg.file.get(objfile)
filename = os.path.basename(objfile)
with open(os.path.join(remote_files_dir))
@pwndbg.memoize.reset_on_objfile
def get(address, gdb_only=False):
@ -91,6 +155,8 @@ def add_main_exe_to_symbols():
if not addr:
return
addr = int(addr)
mmap = pwndbg.vmmap.find(addr)
if not mmap:
return
@ -101,3 +167,6 @@ def add_main_exe_to_symbols():
gdb.execute('add-symbol-file %s %#x' % (path, addr), from_tty=False, to_string=True)
except gdb.error:
pass
if '/usr/lib/debug' not in get_directory():
set_directory(get_directory() + ':/usr/lib/debug')

@ -46,6 +46,9 @@ def find(address):
if address is None or address < pwndbg.memory.MMAP_MIN_ADDR:
return None
if address:
address = int(address)
for page in get():
if address in page:
return page

Loading…
Cancel
Save