Skip to content

Commit

Permalink
command robustness improvements and graceful errors (#185)
Browse files Browse the repository at this point in the history
* search: fix --word -2 param and allow --short in reflect to --type short

Search failed when using the --word (-2) parameter as 'word' was
not found in the type lookup. Using 'word' instead of 'short' seems
to be the better option as that matches better in this context.

* search: more robust and graceful error messages for invalid input

This makes error messages for wrong input more graceful instead of
dying and printing an ugly full traceback exception.

* harden hexdump and telescope commands against malformed arguments

* only allow retaddr and canary commands when in running mode

* xor: gracefully complain on invalid memory address

* next: check if proc is alive while continuing to avoid exceptions

If the program terminates while we are still looping/continuing for
the according next command, then an internal gdb.error is thrown as
the program is not being run.
We avoid such situations by adding the proc.alive to the looping
conditions.

* memory: force write_memory to be bytes for python2 gdb

* catch general gdb.error instead of specific gdb.MemoryError
  • Loading branch information
anthraxx authored and zachriggle committed Mar 22, 2017
1 parent 1869b8a commit 433bf23
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 17 deletions.
9 changes: 7 additions & 2 deletions pwndbg/commands/hexdump.py
Expand Up @@ -6,6 +6,7 @@
from __future__ import unicode_literals

import argparse
import gdb

import pwndbg.arch
import pwndbg.commands
Expand All @@ -32,13 +33,17 @@
def hexdump(address=None, count=pwndbg.config.hexdump_bytes):
address = int(address)
address &= pwndbg.arch.ptrmask
count = int(count)
count = max(int(count), 0)
width = int(pwndbg.config.hexdump_width)

if count > address > 0x10000:
count -= address

data = pwndbg.memory.read(address, count, partial=True)
try:
data = pwndbg.memory.read(address, count, partial=True)
except gdb.error as e:
print(e)
return

for line in pwndbg.hexdump.hexdump(data, address=address, width=width):
print(line)
1 change: 1 addition & 0 deletions pwndbg/commands/misc.py
Expand Up @@ -77,6 +77,7 @@ def distance(a, b):
print("%#x->%#x is %#x bytes (%#x words)" % (a, b, distance, distance // _arch.ptrsize))

@_pwndbg.commands.Command
@_pwndbg.commands.OnlyWhenRunning
def canary():
"""Print out the current stack canary"""
auxv = _pwndbg.auxv.get()
Expand Down
2 changes: 1 addition & 1 deletion pwndbg/commands/next.py
Expand Up @@ -53,7 +53,7 @@ def next_syscall(*args):
"""
Breaks at the next syscall.
"""
while not pwndbg.next.break_next_interrupt() and pwndbg.next.break_next_branch():
while pwndbg.proc.alive and not pwndbg.next.break_next_interrupt() and pwndbg.next.break_next_branch():
continue
pwndbg.commands.context.context()

Expand Down
19 changes: 15 additions & 4 deletions pwndbg/commands/search.py
Expand Up @@ -6,6 +6,7 @@
from __future__ import unicode_literals

import argparse
import binascii
import codecs
import os
import struct
Expand Down Expand Up @@ -50,11 +51,11 @@ def print_search_hit(address):
parser = argparse.ArgumentParser(description='''
Search memory for byte sequences, strings, pointers, and integer values
''')
parser.add_argument('-t', '--type', choices=['byte','short','dword','qword','pointer','string','bytes'],
parser.add_argument('-t', '--type', choices=['byte','short','word','dword','qword','pointer','string','bytes'],
help='Size of search target', default='bytes', type=str)
parser.add_argument('-1', '--byte', dest='type', action='store_const', const='byte',
help='Search for a 1-byte integer')
parser.add_argument('-2', '--word', dest='type', action='store_const', const='word',
parser.add_argument('-2', '--word', '--short', dest='type', action='store_const', const='word',
help='Search for a 2-byte integer')
parser.add_argument('-4', '--dword', dest='type', action='store_const', const='dword',
help='Search for a 4-byte integer')
Expand Down Expand Up @@ -95,7 +96,11 @@ def search(type, hex, string, executable, writable, value, mapping, save, next):
save = bool(pwndbg.config.auto_save_search)

if hex:
value = codecs.decode(value, 'hex')
try:
value = codecs.decode(value, 'hex')
except binascii.Error as e:
print('invalid input for type hex: {}'.format(e))
return

# Convert to an integer if needed, and pack to bytes
if type not in ('string', 'bytes'):
Expand All @@ -107,11 +112,17 @@ def search(type, hex, string, executable, writable, value, mapping, save, next):
}[pwndbg.arch.endian] + {
'byte': 'B',
'short': 'H',
'word': 'H',
'dword': 'L',
'qword': 'Q'
}[type]

value = struct.pack(fmt, value)
try:
value = struct.pack(fmt, value)
except struct.error as e:
print('invalid input for type {}: {}'.format(type, e))
return


# Null-terminate strings
elif type == 'string':
Expand Down
1 change: 1 addition & 0 deletions pwndbg/commands/stack.py
Expand Up @@ -19,6 +19,7 @@
''')

@pwndbg.commands.ArgparsedCommand(p)
@pwndbg.commands.OnlyWhenRunning
def retaddr():
sp = pwndbg.regs.sp
stack = pwndbg.vmmap.find(sp)
Expand Down
30 changes: 22 additions & 8 deletions pwndbg/commands/xor.py
Expand Up @@ -16,12 +16,12 @@ def xor_memory(address, key, count):
Helper function for xorring memory in gdb
"""
mem = pwndbg.memory.read(address, count, partial=True)

for index, byte in enumerate(mem):
key_index = index % len(key)
mem[index] = byte ^ ord(key[key_index])

return mem
return mem

@pwndbg.commands.Command
@pwndbg.commands.OnlyWhenRunning
Expand All @@ -31,10 +31,17 @@ def xor(address, key, count):
XOR ``count`` bytes at ``address`` with the key ``key``.
'''
if not isinstance(address, six.integer_types):
address = int(address, 16)
try:
address = int(address, 0)
except ValueError:
print('Invalid address %s' % address)
return

xorred_memory = xor_memory(address, key, count)
pwndbg.memory.write(address, xorred_memory)
try:
xorred_memory = xor_memory(address, key, count)
pwndbg.memory.write(address, xorred_memory)
except gdb.error as e:
print(e)

@pwndbg.commands.Command
@pwndbg.commands.OnlyWhenRunning
Expand All @@ -44,7 +51,14 @@ def memfrob(address, count):
Run the memfrob command on a region of memory
'''
if not isinstance(address, six.integer_types):
address = int(address, 16)
try:
address = int(address, 0)
except ValueError:
print('Invalid address %s' % address)
return

xorred_memory = xor_memory(address, '*', count)
pwndbg.memory.write(address, xorred_memory)
try:
xorred_memory = xor_memory(address, '*', count)
pwndbg.memory.write(address, xorred_memory)
except gdb.error as e:
print(e)
3 changes: 2 additions & 1 deletion pwndbg/memory.py
Expand Up @@ -38,6 +38,7 @@ def read(addr, count, partial=False):
or ``None``.
"""
result = b''
count = max(int(count), 0)

try:
result = gdb.selected_inferior().read_memory(addr, count)
Expand Down Expand Up @@ -96,7 +97,7 @@ def write(addr, data):
addr(int): Address to write
data(str,bytes,bytearray): Data to write
"""
gdb.selected_inferior().write_memory(addr, data)
gdb.selected_inferior().write_memory(addr, bytes(data))

def peek(address):
"""peek(address) -> str
Expand Down
2 changes: 1 addition & 1 deletion pwndbg/next.py
Expand Up @@ -79,7 +79,7 @@ def break_next_interrupt(address=None):
return ins

def break_next_call(address=None):
while True:
while pwndbg.proc.alive:
ins = break_next_branch(address)

if not ins:
Expand Down

0 comments on commit 433bf23

Please sign in to comment.