Various updates for symbolizing, auxv. Adds aslr command.

pull/10/head
Zach Riggle 11 years ago
parent c08cb916a1
commit 286206d163

@ -8,6 +8,7 @@ import pwndbg.elf
import pwndbg.proc import pwndbg.proc
import pwndbg.regs import pwndbg.regs
import pwndbg.stack import pwndbg.stack
import pwndbg.stdio
import pwndbg.color import pwndbg.color
import pwndbg.function import pwndbg.function
import pwndbg.typeinfo import pwndbg.typeinfo
@ -26,6 +27,7 @@ import pwndbg.commands.ida
import pwndbg.commands.reload import pwndbg.commands.reload
import pwndbg.commands.rop import pwndbg.commands.rop
import pwndbg.commands.shell import pwndbg.commands.shell
import pwndbg.commands.aslr
__all__ = [ __all__ = [
'arch', 'arch',

@ -6,6 +6,7 @@ import pwndbg.events
import pwndbg.info import pwndbg.info
import pwndbg.memory import pwndbg.memory
import pwndbg.regs import pwndbg.regs
import pwndbg.stack
import pwndbg.typeinfo import pwndbg.typeinfo
example_info_auxv_linux = """ example_info_auxv_linux = """
@ -138,7 +139,10 @@ def walk_stack():
if not auxv: if not auxv:
# For whatever reason, sometimes the ARM AUXV under qemu-user is # For whatever reason, sometimes the ARM AUXV under qemu-user is
# not aligned properly. # not aligned properly.
return walk_stack2(1) auxv = walk_stack2(1)
if not auxv['AT_EXECFN']:
auxv['AT_EXECFN'] = get_execfn()
return auxv return auxv
@ -215,3 +219,24 @@ def walk_stack2(offset=0):
p += 2 p += 2
return auxv return auxv
def get_execfn():
# QEMU does not put AT_EXECFN in the Auxiliary Vector
# on the stack.
#
# However, it does put it at the very top of the stack.
#
# 32c:1960| 0x7fffffffefe0 <-- '/home/user/pwndbg/ld....'
# 32d:1968| 0x7fffffffefe8 <-- 'er/pwndbg/ld.so'
# 32e:1970| 0x7fffffffeff0 <-- 0x6f732e646c2f67 /* 'g/ld.so' */
# 32f:1978| 0x7fffffffeff8 <-- 0
# 330:1980| 0x7ffffffff000
addr = pwndbg.stack.find_upper_stack_boundary(pwndbg.regs.sp)
while pwndbg.memory.byte(addr-1) == 0:
addr -= 1
while pwndbg.memory.byte(addr-1) != 0:
addr -= 1
return pwndbg.strings.get(addr, 1024)

@ -1,3 +1,4 @@
import functools
import traceback import traceback
import gdb import gdb
@ -37,11 +38,11 @@ class Command(gdb.Command):
commands = [] commands = []
def __init__(self, function): def __init__(self, function):
self.__doc__ = function.__doc__
super(Command, self).__init__(function.__name__, gdb.COMMAND_USER, gdb.COMPLETE_EXPRESSION) super(Command, self).__init__(function.__name__, gdb.COMMAND_USER, gdb.COMPLETE_EXPRESSION)
self.function = function self.function = function
Command.commands.append(self) Command.commands.append(self)
functools.update_wrapper(self, function)
def split_args(self, argument): def split_args(self, argument):
return gdb.string_to_argv(argument) return gdb.string_to_argv(argument)

@ -0,0 +1,13 @@
import pwndbg.vmmap
import pwndbg.commands
import pwndbg.color
@pwndbg.commands.OnlyWhenRunning
@pwndbg.commands.Command
def aslr():
status = pwndbg.color.red('OFF')
if pwndbg.vmmap.aslr:
status = pwndbg.color.green('ON')
print("ASLR is %s" % status)

@ -130,11 +130,12 @@ def get_ehdr(pointer):
# Do not search more than 4MB of memory # Do not search more than 4MB of memory
for i in range(1024): for i in range(1024):
if data == b'\x7FELF':
break
base -= pwndbg.memory.PAGE_SIZE base -= pwndbg.memory.PAGE_SIZE
data = pwndbg.memory.read(base, 4) data = pwndbg.memory.read(base, 4)
if data == b'\x7FELF':
break
else: else:
print("ERROR: Could not find ELF base!") print("ERROR: Could not find ELF base!")
return None, None return None, None
@ -288,8 +289,3 @@ def map_inner(ei_class, ehdr, objfile):
page.objfile = objfile page.objfile = objfile
return tuple(sorted(pages)) return tuple(sorted(pages))
@pwndbg.events.stop
def update_main_exe():
addr = int(exe().address)
map(addr)

@ -5,6 +5,7 @@ Enables callbacks into functions to be automatically invoked
when various events occur to the debuggee (e.g. STOP on SIGINT) when various events occur to the debuggee (e.g. STOP on SIGINT)
by using a decorator. by using a decorator.
""" """
import functools
import traceback import traceback
import gdb import gdb
import sys import sys
@ -31,16 +32,16 @@ class StartEvent(object):
def disconnect(self, function): def disconnect(self, function):
if function in self.registered: if function in self.registered:
self.registered.remove(function) self.registered.remove(function)
def on_new_objfile(self, o): def on_new_objfile(self):
if self.running or not gdb.selected_thread(): if self.running or not gdb.selected_thread():
return return
self.running = True self.running = True
for function in self.registered: for function in self.registered:
function(o) function()
def on_stop(self, e): def on_stop(self):
self.running = False self.running = False
gdb.events.start = StartEvent() gdb.events.start = StartEvent()
@ -65,19 +66,17 @@ def connect(func, event_handler, name=''):
if debug: if debug:
print("Connecting", func.__name__, event_handler) print("Connecting", func.__name__, event_handler)
@functools.wraps(func)
def caller(*a): def caller(*a):
func.__doc__
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 pause: return if pause: return
try: try:
func() func()
except Exception as e: except Exception as e:
if debug: print(traceback.format_exc()) print(traceback.format_exc())
raise e raise e
registered[event_handler].append(caller) registered[event_handler].append(caller)
caller.name = func.__name__
caller.__name__ = func.__name__
event_handler.connect(caller) event_handler.connect(caller)
return func return func
@ -102,9 +101,9 @@ def on_reload():
registered[event] = [] registered[event] = []
@new_objfile @new_objfile
def _start_newobjfile(o=None): def _start_newobjfile():
gdb.events.start.on_new_objfile(o) gdb.events.start.on_new_objfile()
@stop @stop
def _start_stop(o=None): def _start_stop():
gdb.events.start.on_stop(o) gdb.events.start.on_stop()

@ -5,6 +5,7 @@ Talks to an XMLRPC server running inside of an active IDA Pro instance,
in order to query it about the database. Allows symbol resolution and in order to query it about the database. Allows symbol resolution and
interactive debugging. interactive debugging.
""" """
import functools
import socket import socket
from contextlib import closing from contextlib import closing
@ -46,7 +47,7 @@ setPort(8888)
class withIDA(object): class withIDA(object):
def __init__(self, fn): def __init__(self, fn):
self.fn = fn self.fn = fn
self.__name__ = fn.__name__ functools.update_wrapper(self, fn)
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
if _ida is not None: if _ida is not None:
return self.fn(*args, **kwargs) return self.fn(*args, **kwargs)
@ -55,14 +56,14 @@ class withIDA(object):
class takes_address(object): class takes_address(object):
def __init__(self, fn): def __init__(self, fn):
self.fn = fn self.fn = fn
self.__name__ = fn.__name__ functools.update_wrapper(self, fn)
def __call__(self, address, *args): def __call__(self, address, *args):
return self.fn(l2r(address), *args) return self.fn(l2r(address), *args)
class returns_address(object): class returns_address(object):
def __init__(self, fn): def __init__(self, fn):
self.fn = fn self.fn = fn
self.__name__ = fn.__name__ functools.update_wrapper(self, fn)
def __call__(self, *a, **kw): def __call__(self, *a, **kw):
return r2l(self.fn(*a, **kw)) return r2l(self.fn(*a, **kw))

@ -18,6 +18,12 @@ import pwndbg.events
debug = False debug = False
class memoize(object): class memoize(object):
def __init__(self, func):
self.func = func
self.cache = {}
self.caches.append(self)
functools.update_wrapper(self, func)
def __call__(self, *args): def __call__(self, *args):
how = None how = None
@ -61,11 +67,6 @@ class reset_on_stop(memoize):
caches = [] caches = []
kind = 'stop' kind = 'stop'
def __init__(self, func):
self.func = func
self.cache = {}
self.caches.append(self)
@staticmethod @staticmethod
@pwndbg.events.stop @pwndbg.events.stop
def __reset(): def __reset():
@ -76,13 +77,6 @@ class reset_on_exit(memoize):
caches = [] caches = []
kind = 'exit' kind = 'exit'
def __init__(self, func):
self.func = func
self.cache = {}
self.caches.append(self)
self.__name__ = func.__name__
self.__module__ = func.__module__
@staticmethod @staticmethod
@pwndbg.events.exit @pwndbg.events.exit
def __reset(): def __reset():
@ -93,13 +87,6 @@ class reset_on_objfile(memoize):
caches = [] caches = []
kind = 'objfile' kind = 'objfile'
def __init__(self, func):
self.func = func
self.cache = {}
self.caches.append(self)
self.__name__ = func.__name__
self.__module__ = func.__module__
@staticmethod @staticmethod
@pwndbg.events.new_objfile @pwndbg.events.new_objfile
def __reset(): def __reset():
@ -110,13 +97,6 @@ class reset_on_start(memoize):
caches = [] caches = []
kind = 'start' kind = 'start'
def __init__(self, func):
self.func = func
self.cache = {}
self.caches.append(self)
self.__name__ = func.__name__
self.__module__ = func.__module__
@staticmethod @staticmethod
@pwndbg.events.stop @pwndbg.events.stop
@pwndbg.events.start @pwndbg.events.start

@ -11,9 +11,6 @@ PAGE_SIZE = 0x1000
MMAP_MIN_ADDR = 0x10000 MMAP_MIN_ADDR = 0x10000
def read(addr, count): def read(addr, count):
if count < 0:
import pdb
pdb.set_trace()
result = gdb.selected_inferior().read_memory(addr, count) result = gdb.selected_inferior().read_memory(addr, count)
if pwndbg.compat.python3: if pwndbg.compat.python3:
@ -77,6 +74,8 @@ def find_upper_boundary(addr, max_pages=1024):
try: try:
for i in range(max_pages): for i in range(max_pages):
pwndbg.memory.read(addr, 1) pwndbg.memory.read(addr, 1)
import sys
sys.stdout.write(hex(addr) + '\n')
addr += pwndbg.memory.PAGE_SIZE addr += pwndbg.memory.PAGE_SIZE
except gdb.MemoryError: except gdb.MemoryError:
pass pass

@ -5,6 +5,7 @@ Provides values which would be available from /proc which
are not fulfilled by other modules. are not fulfilled by other modules.
""" """
import sys import sys
import functools
from types import ModuleType from types import ModuleType
import gdb import gdb
@ -28,13 +29,10 @@ class module(ModuleType):
auxv = pwndbg.auxv.get() auxv = pwndbg.auxv.get()
def OnlyWhenRunning(self, func): def OnlyWhenRunning(self, func):
@functools.wraps(func)
def wrapper(*a, **kw): def wrapper(*a, **kw):
func.__doc__
if self.alive: if self.alive:
return func(*a, **kw) return func(*a, **kw)
wrapper.__name__ = func.__name__
wrapper.__module__ = func.__module__
wrapper.__doc__ = func.__doc__
return wrapper return wrapper
# To prevent garbage collection # To prevent garbage collection

@ -27,11 +27,27 @@ def find(address):
Returns a pwndbg.memory.Page object which corresponds to the Returns a pwndbg.memory.Page object which corresponds to the
currently-loaded stack. currently-loaded stack.
""" """
if not stacks:
update()
for stack in stacks: for stack in stacks:
if address in stack: if address in stack:
return stack return stack
def find_upper_stack_boundary(addr, max_pages=1024):
addr = pwndbg.memory.page_align(int(addr))
try:
for i in range(max_pages):
data = pwndbg.memory.read(addr, 4)
if b'\x7fELF' == pwndbg.memory.read(addr, 4):
break
addr += pwndbg.memory.PAGE_SIZE
except gdb.MemoryError:
pass
return addr
@pwndbg.events.stop @pwndbg.events.stop
@pwndbg.memoize.reset_on_stop
def update(): def update():
""" """
For each running thread, updates the known address range For each running thread, updates the known address range
@ -49,7 +65,7 @@ def update():
page = stacks.get(thread.ptid, None) page = stacks.get(thread.ptid, None)
if page is None: if page is None:
start = pwndbg.memory.find_lower_boundary(sp) start = pwndbg.memory.find_lower_boundary(sp)
stop = pwndbg.memory.find_upper_boundary(sp) stop = find_upper_stack_boundary(sp)
page = pwndbg.memory.Page(start, stop-start, 6 if not is_executable() else 7, 0, '[stack]') page = pwndbg.memory.Page(start, stop-start, 6 if not is_executable() else 7, 0, '[stack]')
stacks[thread.ptid] = page stacks[thread.ptid] = page
continue continue
@ -57,7 +73,7 @@ def update():
page.objfile = '[stack]' page.objfile = '[stack]'
# If we *DO* already know about this thread, just # If we *DO* already know about this thread, just
# udpate the lower boundary. # update the lower boundary.
low = pwndbg.memory.find_lower_boundary(page.vaddr) low = pwndbg.memory.find_lower_boundary(page.vaddr)
if low != page.vaddr: if low != page.vaddr:
page.memsz += (page.vaddr - low) page.memsz += (page.vaddr - low)

@ -0,0 +1,18 @@
"""
Provides functionality to circumvent GDB's hooks on sys.stdin and sys.stdout
which prevent output from appearing on-screen inside of certain event handlers.
"""
import gdb
import io
import sys
debug = True
def get(fd, mode):
file = io.open(1, mode=mode, buffering=0, closefd=False)
return io.TextIOWrapper(file, write_through=True)
if debug:
sys.stdin = get(0, 'rb')
sys.stdout = get(1, 'wb')
sys.stderr = get(2, 'wb')

@ -27,7 +27,10 @@ def update_length():
message = message.strip('.') message = message.strip('.')
length = int(message) length = int(message)
def get(address): def get(address, maxlen = None):
if maxlen is None:
maxlen = length
try: try:
sz = gdb.Value(address) sz = gdb.Value(address)
sz = sz.cast(pwndbg.typeinfo.pchar) sz = sz.cast(pwndbg.typeinfo.pchar)
@ -39,7 +42,7 @@ def get(address):
if not all(s in string.printable for s in sz.rstrip('\x00')): if not all(s in string.printable for s in sz.rstrip('\x00')):
return None return None
if len(sz) < length: if len(sz) < maxlen:
return sz return sz
return sz[:length] + '...' return sz[:maxlen] + '...'

@ -12,8 +12,9 @@ import pwndbg.elf
import pwndbg.ida import pwndbg.ida
import pwndbg.memoize import pwndbg.memoize
import pwndbg.memory import pwndbg.memory
import pwndbg.remote
import pwndbg.stack import pwndbg.stack
import pwndbg.vmmap
@pwndbg.memoize.reset_on_objfile @pwndbg.memoize.reset_on_objfile
def get(address): def get(address):
@ -67,3 +68,15 @@ def address(symbol):
return int(address, 0) return int(address, 0)
except gdb.error: except gdb.error:
return None return None
@pwndbg.events.stop
@pwndbg.memoize.reset_on_start
def add_main_exe_to_symbols():
if not pwndbg.remote.is_remote():
return
exe = pwndbg.elf.exe()
addr = exe.address
path = pwndbg.vmmap.find(addr).objfile
if addr and path:
gdb.execute('add-symbol-file %s %#x' % (path, addr), from_tty=False, to_string=True)

@ -322,8 +322,17 @@ def check_aslr():
vmmap = sys.modules[__name__] vmmap = sys.modules[__name__]
vmmap.aslr = False vmmap.aslr = False
system_aslr = True
data = ''
try: data = pwndbg.file.get('/proc/sys/kernel/randomize_va_space')
except OSError: pass
output = gdb.execute('show disable-randomization', to_string=True) output = gdb.execute('show disable-randomization', to_string=True)
if "is off." in output: if "is off." in output:
vmmap.aslr = True vmmap.aslr = True
return vmmap.aslr return vmmap.aslr

Loading…
Cancel
Save