Various enhancements to Enhance

pull/3/head
Zach Riggle 11 years ago
parent 27180e0dfa
commit 3b7a6a3a1e

@ -25,12 +25,26 @@ def get(address, limit=5):
def format(value):
chain = get(value)
# Enhance the last entry
end = [pwndbg.enhance.enhance(chain[-1])]
# Colorize the rest
rest = list(map(pwndbg.color.get, chain[:-1]))
return ' --> '.join(rest + end)
try:
chain = get(value)
# Enhance the last entry
# If there are no pointers (e.g. eax = 0x41414141), then enhance
# the only element there is.
if len(chain) == 1:
enhanced = pwndbg.enhance.enhance(chain[-1])
# Otherwise, the last element in the chain is the non-pointer value.
# We want to enhance the last pointer value.
else:
enhanced = pwndbg.enhance.enhance(chain[-2])
end = [enhanced]
# Colorize the rest
rest = list(map(pwndbg.color.get, chain[:-1]))
return ' --> '.join(rest + end)
except:
import pdb
pdb.post_mortem()

@ -82,5 +82,5 @@ def context_backtrace():
frame = gdb.selected_frame()
for i in range(0,10):
if frame:
print(pwndbg.ui.addrsz(frame.pc()), frame.name() or '???')
print('f', i, pwndbg.ui.addrsz(frame.pc()), frame.name() or '???')
frame = frame.older()

@ -113,9 +113,10 @@ def get_ehdr(pointer):
# Align down to a page boundary, and scan until we find
# the ELF header.
base = pwndbg.memory.page_align(pointer)
data = pwndbg.memory.read(base, 4)
try:
data = pwndbg.memory.read(base, 4)
while data != b'\x7FELF':
base -= pwndbg.memory.PAGE_SIZE
data = pwndbg.memory.read(base, 4)
@ -166,7 +167,6 @@ def iter_phdrs(ehdr):
p_phdr = pwndbg.memory.poi(PhdrType, p_phdr)
yield p_phdr
@pwndbg.memoize.reset_on_stop
def map(pointer, objfile=''):
"""
Given a pointer into an ELF module, return a list of all loaded
@ -188,6 +188,14 @@ def map(pointer, objfile=''):
Page('7ffff79a6000-7ffff79ad000 rw-p 0x7000 1bf000')]
"""
ei_class, ehdr = get_ehdr(pointer)
return map_inner(ei_class, ehdr, objfile)
@pwndbg.memoize.reset_on_stop
def map_inner(ei_class, ehdr, objfile):
if not ehdr:
return []
base = int(ehdr.address)
# For each Program Header which would load data into our
# address space, create a representation of each individual

@ -10,8 +10,29 @@ import pwndbg.memoize
import pwndbg.arch
import string
bad_instrs = [
'.byte',
'.long',
'rex.R',
'rex.XB',
'(bad)'
]
def good_instr(i):
return not any(bad in i for bad in bad_instrs)
@pwndbg.memoize.reset_on_stop
def enhance(value):
"""
Given the last pointer in a chain, attempt to characterize
Note that 'the last pointer in a chain' may not at all actually be a pointer.
Additionally, optimizations are made based on various sources of data for
'value'. For example, if it is set to RWX, we try to get information on whether
it resides on the stack, or in a RW section that *happens* to be RWX, to
determine which order to print the fields.
"""
value = int(value)
name = pwndbg.symbol.get(value) or None
@ -29,42 +50,66 @@ def enhance(value):
# Try to unpack the value as a string
packed = pwndbg.arch.pack(int(value))
if all(c in string.printable.encode('utf-8') for c in packed):
retval = '%s (%r)' % (retval, packed.decode())
if len(retval) > 4:
retval = '%s (%r)' % (retval, packed.decode())
return retval
# It's mapped memory, or we can at least read it.
# Try to find out if it's a string.
instr = None
exe = page and page.execute
rwx = page and page.rwx
if exe:
instr = pwndbg.disasm.get(value, 1)[0].asm
# However, if it contains bad instructions, bail
if not good_instr(instr):
instr = None
szval = pwndbg.strings.get(value) or None
if szval and len(szval) > 5:
szval = repr(szval)
else:
# It's mapped memory, or we can at least read it.
# Try to find out if it's a string.
data = None
if page and page.execute:
data = pwndbg.disasm.get(value, 1)[0].asm
szval = None
# However, if it contains bad instructions, bail
if '.byte' in data or '.long' in data:
data = None
intval = int(pwndbg.memory.poi(pwndbg.types.pvoid, value))
intval0 = intval
if intval >= 16:
intval = hex(intval)
else:
intval = str(intval)
retval = []
# If it's on the stack, don't display it as code in a chain.
if instr and rwx and 'stack' in page.objfile:
retval = [intval, szval]
if data is None:
data = pwndbg.strings.get(value) or None
if data:
data = repr(data)
# If it's RWX but a small value, don't display it as code in a chain.
elif instr and rwx and intval0 > 0x1000:
retval = [instr, intval, szval]
if data is None:
data = pwndbg.memory.poi(pwndbg.types.pvoid, value)
# If it's an instruction and *not* RWX, display it unconditionally
elif instr:
retval = [instr, intval, szval]
# Otherwise strings have preference
elif szval:
retval = [szval, intval]
# And then integer
else:
retval = [intval]
# Try to unpack the value as a string
try:
packed = pwndbg.arch.pack(int(data))
if all(c in string.printable.encode('utf-8') for c in packed):
data = repr(packed.decode())
except:
data = str(data)
colored = pwndbg.color.get(value)
retval = tuple(filter(lambda x: x is not None, retval))
if data and name: return "%s (%s: %s)" % (colored, name, data)
elif name: return "%s (%s)" % (colored, name)
elif data: return "%s (%s)" % (colored, data)
if len(retval) == 0:
return "???"
return colored
if len(retval) == 1:
return retval[0]
return retval[0] + ' /* {} */'.format('; '.join(retval[1:]))
Loading…
Cancel
Save