pull/3/head
Zach Riggle 11 years ago
parent be8fdab940
commit ca801c0d6d

@ -9,4 +9,3 @@ sys.path.append(directory)
import gef
gef.main()

@ -1,3 +1,4 @@
import gdb
import gef.arch
import gef.vmmap
import gef.dt
@ -6,6 +7,34 @@ import gef.elf
import gef.proc
import gef.regs
import gef.stack
import gef.commands
import gef.commands.hexdump
import gef.commands.context
import gef.commands.telescope
import gef.commands.vmmap
import gef.commands.dt
def main():
pass
pre_commands = """
set confirm off
set verbose off
set output-radix 0x10
set prompt geef>
set height 0
set history expansion on
set history save on
set disassembly-flavor intel
set follow-fork-mode child
set backtrace past-main on
set step-mode on
set print pretty on
set width 0
set print elements 15
set input-radix 16
handle SIGALRM print nopass
handle SIGSEGV stop print nopass
""".strip()
for line in pre_commands.splitlines():
if line:
gdb.execute(line)

@ -1,3 +1,5 @@
import struct
import sys
import gdb
import gef.memoize
import gef.events
@ -5,10 +7,33 @@ import gef.types
current = None
ptrmask = 0xfffffffff
endian = 'little'
ptrsize = gef.types.ptrsize
fmt = '=i'
@gef.events.stop
def update():
global current
global ptrmask
current = gdb.selected_frame().architecture().name()
ptrmask = (1 << 8*gef.types.ptrsize)-1
m = sys.modules[__name__]
m.current = gdb.selected_frame().architecture().name()
m.ptrsize = gef.types.ptrsize
m.ptrmask = (1 << 8*gef.types.ptrsize)-1
if 'little' in gdb.execute('show endian', to_string=True):
m.endian = 'little'
else:
m.endian = 'big'
m.fmt = {
(4, 'little'): '<I',
(4, 'big'): '>I',
(8, 'little'): '<Q',
(8, 'big'): '>Q',
}.get((m.ptrsize, m.endian))
def pack(integer):
return struct.pack(fmt, integer & ptrmask)
def unpack(data):
return struct.unpack(fmt, data)[0]

@ -128,6 +128,8 @@ def use_info_auxv():
def walk_stack():
sp = gef.regs.sp
print("BAD SP")
if not sp:
return None
@ -167,6 +169,8 @@ def walk_stack():
# Scan them into our structure
auxv = AUXV()
print("STARTING AT %s" % p)
print("STOPPING AT %s" % AT_NULL)
while p < AT_NULL:
const, value = p.dereference(), (p+1).dereference()
const = int(const)

@ -1,6 +1,9 @@
import gdb
import gef.types
import gef.color
import gef.enhance
import gef.memory
import gef.types
import gef.vmmap
def get(address, limit=5):
@ -10,21 +13,24 @@ def get(address, limit=5):
Returns:
A list containing ``address``, followed by up to ``limit`` valid pointers.
"""
result = [int(address)]
result = []
for i in range(limit):
result.append(address)
try:
# Convert the current address to a void**
address = gef.memory.poi(gef.types.ppvoid, address)
# Ensure that it's a valid pointer by dereferencing it
# *AND* attempting to get the resulting value.
#
# GDB will let you .dereference() anything, the int() throws
# the gdb.MemoryError.
int(address.dereference())
# Save it off
result.append(int(address))
address = int(gef.memory.poi(gef.types.ppvoid, address))
except gdb.MemoryError:
break
return result
def format(value):
chain = get(value)
# Enhance the last entry
end = [gef.enhance.enhance(chain[-1])]
# Colorize the rest
rest = list(map(gef.color.get, chain[:-1]))
return ' --> '.join(rest + end)

@ -9,15 +9,23 @@ YELLOW = "\x1b[33m"
BLUE = "\x1b[34m"
PURPLE = "\x1b[35m"
CYAN = "\x1b[36m"
GREY = GRAY = "\x1b[37m"
GREY = GRAY = "\x1b[90m"
BOLD = "\x1b[1m"
UNDERLINE = "\x1b[4m"
STACK = BLUE
HEAP = BLUE + BOLD
STACK = YELLOW
HEAP = BLUE
CODE = RED
RWX = RED + BOLD
DATA = YELLOW
RWX = RED + BOLD + UNDERLINE
DATA = PURPLE
def normal(x): return NORMAL + x
def bold(x): return BOLD + x + NORMAL
def red(x): return RED + x + NORMAL
def blue(x): return BLUE + x + NORMAL
def gray(x): return GRAY + x + NORMAL
def green(x): return GREEN + x + NORMAL
def yellow(x): return YELLOW + x + NORMAL
def get(address, text = None):
"""
@ -33,14 +41,26 @@ def get(address, text = None):
if page is None: color = NORMAL
elif '[stack' in page.objfile: color = STACK
elif '[heap' in page.objfile: color = HEAP
elif page.rwx: color = RWX
elif page.execute: color = CODE
elif page.rw: color = DATA
else: color = NORMAL
if page.rwx:
color = color + UNDERLINE
if text is None and isinstance(address, int) and address > 255:
text = hex(address)
if text is None:
text = address
return "%s%s%s" % (color, text, NORMAL)
def legend():
return 'LEGEND: ' + ' | '.join((
STACK + 'STACK' + NORMAL,
HEAP + 'HEAP' + NORMAL,
CODE + 'CODE' + NORMAL,
DATA + 'DATA' + NORMAL,
UNDERLINE + 'RWX' + NORMAL,
'RODATA'
))

@ -1,2 +1,67 @@
import traceback
import gdb
class Command(gdb.Command):
import gef.regs
import gef.memory
import gef.hexdump
import gef.color
import gef.chain
import gef.enhance
import gef.symbol
import gef.ui
import gef.proc
debug = True
class ParsedCommand(gdb.Command):
def __init__(self, function):
super(ParsedCommand, self).__init__(function.__name__, gdb.COMMAND_USER, gdb.COMPLETE_EXPRESSION)
self.function = function
def invoke(self, argument, from_tty):
argv = gdb.string_to_argv(argument)
for i,arg in enumerate(argv):
try:
argv[i] = gdb.parse_and_eval(arg)
continue
except Exception:
pass
try:
arg = gef.regs.fix(arg)
argv[i] = gdb.parse_and_eval(arg)
except Exception:
pass
try:
self.function(*argv)
except TypeError:
if debug: print(traceback.format_exc())
pass
def __call__(self, *args):
self.function(*args)
def OnlyWhenRunning(func):
def wrapper(*a):
func.__doc__
if not gef.proc.alive:
pass
else:
func(*a)
wrapper.__name__ = func.__name__
wrapper.__module__ = func.__module__
return wrapper
@ParsedCommand
@OnlyWhenRunning
def searchmem(searchfor):
if isinstance(searchfor, gdb.Value):
try:
searchfor = gef.memory.read(searchfor.address, searchfor.sizeof)
except:
searchfor = 0
print(searchfor)

@ -0,0 +1,86 @@
import gdb
import gef.commands
import gef.color
import gef.vmmap
import gef.symbol
import gef.regs
import gef.ui
import gef.disasm
import gef.chain
import gef.commands.telescope
import gef.events
@gef.commands.ParsedCommand
@gef.commands.OnlyWhenRunning
@gef.events.stop
def context(*args):
if len(args) == 0:
args = ['reg','code','stack','backtrace']
args = [a[0] for a in args]
print(gef.color.legend())
if 'r' in args: context_regs()
if 'c' in args: context_code()
if 's' in args: context_stack()
if 'b' in args: context_backtrace()
def context_regs():
print(gef.color.blue(gef.ui.banner("registers")))
for reg in gef.regs.gpr + (gef.regs.frame, gef.regs.stack, '$pc'):
if reg is None:
continue
value = gef.regs[reg]
# Make the register stand out
regname = gef.color.bold(reg.ljust(4).upper())
print("%s %s" % (regname, gef.chain.format(value)))
def context_code():
print(gef.color.blue(gef.ui.banner("code")))
pc = gef.regs.pc
instructions = gef.disasm.near(gef.regs.pc, 5)
# In case $pc is in a new map we don't know about,
# this will trigger an exploratory search.
gef.vmmap.find(pc)
# Ensure screen data is always at the same spot
for i in range(11 - len(instructions)):
print()
# Find all of the symbols for the addresses
symbols = []
for i in instructions:
symbol = gef.symbol.get(i.address)
if symbol:
symbol = '<%s> ' % symbol
symbols.append(symbol)
# Find the longest symbol name so we can adjust
longest_sym = max(map(len, symbols))
# Pad them all out
for i,s in enumerate(symbols):
symbols[i] = s.ljust(longest_sym)
# Print out each instruction
for i,s in zip(instructions, symbols):
asm = gef.disasm.color(i)
prefix = ' =>' if i.address == pc else ' '
print(prefix, s + hex(i.address), asm)
def context_stack():
print(gef.color.blue(gef.ui.banner("stack")))
gef.commands.telescope.telescope(gef.regs.sp)
def context_backtrace():
print(gef.color.blue(gef.ui.banner("backtrace")))
frame = gdb.selected_frame()
for i in range(0,10):
if frame:
print(gef.ui.addrsz(frame.pc()), frame.name() or '???')
frame = frame.older()

@ -0,0 +1,10 @@
import gdb
import gef.vmmap
import gef.commands
import gef.color
import gef.dt
@gef.commands.ParsedCommand
@gef.commands.OnlyWhenRunning
def dt(typename, address=None):
print(gef.dt.dt(typename, addr=address))

@ -0,0 +1,19 @@
import gef.regs
import gef.commands
import gef.memory
import gef.hexdump
@gef.commands.ParsedCommand
@gef.commands.OnlyWhenRunning
def hexdump(address=None, count=64):
"""Hexdumps some data"""
if address is None:
address = gef.regs.sp
int(address)
data = gef.memory.read(address, count)
for line in gef.hexdump.hexdump(data, address=address):
print(line)

@ -0,0 +1,4 @@
import struct
import gdb
def pack(data, size=None):

@ -0,0 +1,29 @@
import gdb
import gef.commands
@gef.commands.ParsedCommand
@gef.commands.OnlyWhenRunning
def start():
entries = ["main"]
main_addr = peda.main_entry()
if main_addr:
entries += ["*0x%x" % main_addr]
entries += ["__libc_start_main@plt"]
entries += ["_start"]
entries += ["_init"]
started = 0
for e in entries:
out = peda.execute_redirect("tbreak %s" % e)
if out and "breakpoint" in out:
peda.execute("run %s" % ' '.join(arg))
started = 1
break
if not started: # try ELF entry point or just "run" as the last resort
elf_entry = peda.elfentry()
if elf_entry:
out = peda.execute_redirect("tbreak *%s" % elf_entry)
peda.execute("run")

@ -0,0 +1,44 @@
import gef.memory
import gef.regs
import gef.types
import gef.commands
import gef.chain
@gef.commands.ParsedCommand
@gef.commands.OnlyWhenRunning
def telescope(address=None, count=8):
if address is None:
address = gef.regs.sp
if address < 100:
count = address
address = gef.regs.sp
address = int(address)
count = int(count)
reg_values = {r:v for (r,v) in gef.regs.items()}
# address = gef.memory.poi(gef.types.ppvoid, address)
ptrsize = gef.types.ptrsize
start = address
stop = address + (count*ptrsize)
step = ptrsize
# Find all registers which show up in the trace
regs = {}
for i in range(start, stop, step):
regs[i] = []
for reg, regval in reg_values.items():
if i <= regval < i+ptrsize:
regs[i].append(reg)
regs[i] = ' '.join(regs[i])
# Find the longest set of register information
longest_regs = max(map(len, regs.values())) + 1
# Print everything out
for i,addr in enumerate(range(start, stop, step)):
print("%02i:%04i|" % (i, addr-start),
regs[addr].ljust(longest_regs),
gef.chain.format(addr))

@ -0,0 +1,24 @@
import gdb
import gef.vmmap
import gef.commands
import gef.color
@gef.commands.ParsedCommand
@gef.commands.OnlyWhenRunning
def vmmap(map=None):
int_map = None
str_map = None
if isinstance(map, str):
str_map = map
elif isinstance(map, (int, gdb.Value)):
int_map = int(map)
for page in gef.vmmap.get():
if str_map and str_map not in page.objfile:
continue
if int_map and int_map not in page:
continue
print(gef.color.get(page.vaddr, text=str(page)))
print(gef.color.legend())

@ -0,0 +1,5 @@
import gdb
import gef.commands
@gef.commands.ParsedCommand
@gef.commands.OnlyWhenRunning

@ -1,5 +1,6 @@
import gdb
import collections
import gef.color
Instruction = collections.namedtuple('Instruction', ['address', 'length', 'asm'])
@ -10,3 +11,67 @@ def get(address, instructions=1):
for insn in raw:
retval.append(Instruction(insn['addr'],insn['length'], insn['asm']))
return retval
def near(address, instructions=1):
# Find out how far back we can go without having a page fault
distance = instructions * 8
for start in range(address-distance, address):
if gef.memory.peek(start):
break
# Disassemble more than we expect to need, move forward until we have
# enough instructions and we start on the correct spot
insns = []
while start < address:
insns = get(start, instructions)
last = insns[-1]
if last.address + last.length == address:
break
start += 1
return insns[-instructions:] + get(address, instructions + 1)
branches = set([
# Unconditional x86 branches
'call', 'callq',
'jmp',
'ret',
# Conditional x86 branches
'ja', 'jna',
'jae', 'jnae',
'jb', 'jnb',
'jbe', 'jnbe',
'jc', 'jnc',
'je', 'jne',
'jg', 'jng',
'jge', 'jnge',
'jl', 'jnl',
'jle', 'jnle',
'jo', 'jno',
'jp', 'jnp',
'jpe', 'jpo',
'js', 'jns',
'jz', 'jnz',
# ARM branches
'b', 'bl', 'bx', 'blx', 'bxj', 'b.w',
'beq', 'beq.w', 'bne', 'bmi', 'bpl', 'blt',
'ble', 'bgt', 'bge', 'bxne',
# MIPS branches
'j', 'jal', 'jr'
# PowerPC has too many, don't care
# http://llvm.org/klaus/llvm/raw/e48e8c7a6069374daee4c9be1e17b8ed31527f5e/test/MC/PowerPC/ppc64-encoding-ext.s
# SPARC
'ba', 'bne', 'be', 'bg', 'ble', 'bge', 'bl', 'bgu', 'bleu',
'jmpl'
])
def color(ins):
asm = ins.asm
if asm.split()[0] in branches:
asm = gef.color.yellow(asm)
asm += '\n'
return asm

@ -1,11 +1,15 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import gdb
import glob
import os
import re
import subprocess
import tempfile
import gef.memory
import gef.types
def get_type(v):
t = v.type
while not t.name:
@ -75,7 +79,7 @@ def dt(name='', addr=None, obj = None):
# Lookup the type name specified by the user
else:
t = gdb.lookup_type(name)
t = gef.types.load(name)
# If it's not a struct (e.g. int or char*), bail
if t.code not in (gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_TYPEDEF):
@ -91,17 +95,37 @@ def dt(name='', addr=None, obj = None):
if obj: header = "%s @ %s" % (header, hex(int(obj.address)))
rv.append(header)
if t.strip_typedefs().code != gdb.TYPE_CODE_STRUCT:
t = {name: obj or gdb.Value(0).cast(t)}
for name, field in t.items():
# Offset into the parent structure
o = field.bitpos/8
o = getattr(field, 'bitpos', 0)/8
extra = str(field.type)
if obj:
ftype = field.type.strip_typedefs()
if obj and obj.type.strip_typedefs().code == gdb.TYPE_CODE_STRUCT:
v = obj[name]
if field.type.strip_typedefs().code == gdb.TYPE_CODE_INT:
if ftype.code == gdb.TYPE_CODE_INT:
v = hex(int(v))
if ftype.code in (gdb.TYPE_CODE_PTR, gdb.TYPE_CODE_ARRAY) \
and ftype.target() == gef.types.uchar:
data = gef.memory.read(v.address, ftype.sizeof)
v = ' '.join('%02x' % b for b in data)
extra = v
# Adjust trailing lines in 'extra' to line up
# This is necessary when there are nested structures.
# Ideally we'd expand recursively if the type is complex.
extra_lines = []
for i, line in enumerate(str(extra).splitlines()):
if i == 0: extra_lines.append(line)
else: extra_lines.append(35*' ' + line)
extra = '\n'.join(extra_lines)
line = " +0x%04x %-20s : %s" % (o, name, extra)
rv.append(line)
return ('\n'.join(rv))
return ('\n'.join(rv))

@ -258,8 +258,7 @@ def map(pointer, objfile=''):
for page in pages:
page.objfile = objfile
pages.sort()
return pages
return tuple(sorted(pages))
@gef.events.stop
def update_main_exe():

@ -1,11 +1,14 @@
import gdb
import string
import gef.symbol
import gef.memory
import gef.color
import gef.types
import gef.string
import gef.strings
import gef.disasm
import gef.memoize
import gef.arch
import string
@gef.memoize.reset_on_stop
def enhance(value):
@ -17,31 +20,51 @@ def enhance(value):
# If it's not in a page we know about, try to dereference
# it anyway just to test.
can_read = True
if not page and None == gef.memory.poke(value):
if not page and None == gef.memory.peek(value):
can_read = False
if not can_read:
return hex(int(value))
retval = hex(int(value))
# 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 = gef.disasm.get(value, 1)[0].asm
# Try to unpack the value as a string
packed = gef.arch.pack(int(value))
if all(c in string.printable.encode('utf-8') for c in packed):
retval = '%s (%r)' % (retval, packed.decode())
if data is None:
data = gef.string.get(value)
if data:
data = repr(data)
return retval
if data is None and isinstance(data, int):
data = hex(data)
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 = gef.disasm.get(value, 1)[0].asm
# However, if it contains bad instructions, bail
if '.byte' in data or '.long' in data:
data = None
if data is None:
data = gef.strings.get(value) or None
if data:
data = repr(data)
if data is None:
data = gef.memory.poi(gef.types.pvoid, value)
# Try to unpack the value as a string
try:
packed = gef.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 = gef.color.get(value)
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 data and name: return "%s (%s: %s)" % (colored, name, data)
elif name: return "%s (%s)" % (colored, name)
elif data: return "%s (%s)" % (colored, data)
return colored

@ -1,6 +1,7 @@
import gdb
import traceback
debug = True
debug = False
def connect(func, event_handler):
def caller(*a):
@ -9,7 +10,7 @@ def connect(func, event_handler):
try:
func()
except Exception as e:
print("Exception occurred", e)
if debug: print(traceback.format_exc())
raise e
caller.name = func.__name__
event_handler.connect(caller)

@ -0,0 +1,80 @@
import copy
import string
import gef.color
def groupby(array, count, fill=None):
array = copy.copy(array)
while fill and len(array) % count:
array.append(fill)
for i in range(0, len(array), count):
yield array[i:i+count]
#
# We want to colorize the hex characters
#
color_scheme = {i:gef.color.normal("%02x" % i) for i in range(256)}
for c in (string.ascii_letters + string.digits + string.punctuation).encode('utf-8'):
color_scheme[c] = gef.color.bold("%02x" % c)
for c in bytearray(b'\x00\xff'):
color_scheme[c] = gef.color.red("%02x" % c)
color_scheme[-1] = ' '
#
# Only print out printable values on the righ hand side
#
printable = {i:'.' for i in range(256)}
for c in (string.ascii_letters + string.digits + string.punctuation).encode('utf-8'):
printable[c] = chr(c)
printable[-1] = ' '
def hexdump(data, address = 0, width = 16, skip = True):
data = list(bytearray(data))
base = address
last_line = None
skipping = False
for i, line in enumerate(groupby(data, width, -1)):
if skip and line == last_line:
if not skipping:
skipping = True
yield '*'
continue
else:
skipping = False
last_line = line
hexline = []
if address:
hexline.append("+%04x " % (i*width))
hexline.append("%#08x " % (base + (i*width)))
for group in groupby(line, 4):
for char in group:
hexline.append(color_scheme[char])
hexline.append(' ')
hexline.append(' ')
hexline.append('|')
for group in groupby(line, 4):
for char in group:
hexline.append(printable[char])
hexline.append('|')
yield(''.join(hexline))
hexline = []
if address:
hexline.append("+%04x " % len(data))
hexline.append("%#08x " % (base + len(data)))
yield ''.join(hexline)

@ -1,3 +1,4 @@
import copy
import collections
import gdb
import functools
@ -16,6 +17,10 @@ class memoize(object):
value = self.func(*args)
self.cache[args] = value
if isinstance(value, list):
print("Shouldnt cache mutable types! %r" % self.func.__name__)
return value
def __repr__(self):

@ -5,6 +5,7 @@ import gef.compat
import gef.types
PAGE_SIZE = 0x1000
MMAP_MIN_ADDR = 0x10000
def read(addr, count):
result = gdb.selected_inferior().read_memory(addr, count)
@ -17,11 +18,21 @@ def read(addr, count):
def readtype(gdb_type, addr):
return int(gdb.Value(addr).cast(gdb_type.pointer()).dereference())
def write(addr, data):
gdb.selected_inferior().write_memory(addr, data)
def peek(address):
try: return read(address, 1)
try: return read(address, 1)
except: pass
return None
def poke(address):
c = peek(address)
if c is None: return False
try: write(address, c)
except: return False
return True
def byte(addr): return readtype(gef.types.uchar, addr)
def uchar(addr): return readtype(gef.types.uchar, addr)
def ushort(addr): return readtype(gef.types.ushort, addr)
@ -84,8 +95,8 @@ class Page(object):
memsz = 0 #: Size of the address space, in bytes
flags = 0 #: Flags set by the ELF file, see PF_X, PF_R, PF_W
offset = 0 #: Offset into the original ELF file that the data is loaded from
objfile = None #: Path to the ELF on disk
def __init__(self, start, size, flags, offset, objfile=None):
objfile = '' #: Path to the ELF on disk
def __init__(self, start, size, flags, offset, objfile=''):
self.vaddr = start
self.memsz = size
self.flags = flags
@ -114,9 +125,9 @@ class Page(object):
'x' if flags & 1 else '-',
'p'])
def __str__(self):
width = 2*gef.types.ptrsize
fmt_string = "%0x-%0x %s %8x %-6x %s"
# fmt_string = fmt_string.format(width, width)
width = 2 + 2*gef.types.ptrsize
fmt_string = "%#{}x %#{}x %s %8x %-6x %s"
fmt_string = fmt_string.format(width, width)
return fmt_string % (self.vaddr,
self.vaddr+self.memsz,
self.permstr,
@ -126,7 +137,7 @@ class Page(object):
def __repr__(self):
return "%s(%r)" % (self.__class__.__name__, self.__str__())
def __contains__(self, a):
return self.vaddr-1 < a < (self.vaddr + self.memsz)
return self.vaddr <= a < (self.vaddr + self.memsz)
def __eq__(self, other):
return self.vaddr == getattr(other, 'vaddr', other)
def __lt__(self, other):

@ -6,7 +6,6 @@ import gef.memoize
class module(ModuleType):
@property
@gef.memoize.reset_on_exit
def pid(self):
i = gdb.selected_inferior()
if i is not None:

@ -1,11 +1,12 @@
import gdb
import sys
import re
from types import ModuleType
import gef.memoize
import gef.arch
class RegisterSet(object):
def __init__(self, pc, stack, frame, retaddr, flags, gpr, misc):
def __init__(self, pc, stack, frame, retaddr, flags, gpr, misc, args):
self.pc = pc
self.stack = stack
self.frame = frame
@ -13,6 +14,7 @@ class RegisterSet(object):
self.flags = flags
self.gpr = gpr
self.misc = misc
self.args = args
arm = RegisterSet('pc',
'sp',
@ -20,7 +22,8 @@ arm = RegisterSet('pc',
('lr',),
('cpsr',),
('r0','r1','r2','r3','r4','r5','r6','r7','r8','r9','r10','r11','r12'),
None)
None,
('r0','r1','r2','r3'))
amd64 = RegisterSet('rip',
'rsp',
@ -30,7 +33,8 @@ amd64 = RegisterSet('rip',
('rax','rbx','rcx','rdx','rdi','rsi',
'r8', 'r9', 'r10','r11','r12',
'r13','r14','r15'),
('cs','ss','ds','es','fs','gs'))
('cs','ss','ds','es','fs','gs'),
('rdi','rsi','rdx','rcx','r8','r9'))
i386 = RegisterSet('eip',
'esp',
@ -38,7 +42,14 @@ i386 = RegisterSet('eip',
None,
('eflags',),
('eax','ebx','ecx','edx','edi','esi'),
('cs','ss','ds','es','fs','gs'))
('cs','ss','ds','es','fs','gs'),
('*((void**)$sp+0)',
'*((void**)$sp+1)',
'*((void**)$sp+2)',
'*((void**)$sp+3)',
'*((void**)$sp+4)',
'*((void**)$sp+5)',
'*((void**)$sp+6)',))
# http://math-atlas.sourceforge.net/devel/assembly/elfspec_ppc.pdf
@ -57,7 +68,8 @@ powerpc = RegisterSet('pc',
('lr','r0'),
('msr','xer'),
tuple('r%i' % i for i in range(3,32)),
('cr','lr','trap','r2'))
('cr','lr','trap','r2'),
tuple())
# http://people.cs.clemson.edu/~mark/sparc/sparc_arch_desc.txt
# http://people.cs.clemson.edu/~mark/subroutines/sparc.html
@ -95,7 +107,8 @@ sparc = RegisterSet('pc',
('o7',),
('psr',),
sparc_gp,
None)
None,
('i0','i1','i2','i3','i4','i5'))
# http://logos.cs.uic.edu/366/notes/mips%20quick%20tutorial.htm
@ -112,12 +125,13 @@ sparc = RegisterSet('pc',
# r30 => frame pointer
# r31 => return address
mips = RegisterSet('pc',
'r29',
'r30',
('r31',),
'sp',
'fp',
('ra',),
None,
tuple('r%i' % i for i in range(1,26)),
None,
('r%i' for i in range(1,26)),
None)
('a0','a1','a2','a3'))
arch_to_regs = {
'i386': i386,
@ -137,7 +151,7 @@ class module(ModuleType):
value = int(gdb.parse_and_eval('$' + attr.lstrip('$')))
return value & gef.arch.ptrmask
except gdb.error:
return 0
return None
def __getitem__(self, item):
return getattr(self, item)
@ -152,7 +166,49 @@ class module(ModuleType):
@property
def retaddr(self):
return arch_to_regs[gef.arch.current].retaddr
return arch_to_regs[gef.arch.current].retaddr
@property
def stack(self):
return arch_to_regs[gef.arch.current].stack
@property
def all(self):
regs = arch_to_regs[gef.arch.current]
retval = []
for regset in (regs.pc, regs.stack, regs.frame, regs.retaddr, regs.flags, regs.gpr, regs.misc):
if regset is None:
continue
elif isinstance(regset, (list, tuple)):
retval.extend(regset)
else:
retval.append(regset)
return retval
def fix(self, expression):
for regname in set(self.all + ['sp','pc']):
expression = re.sub(r'\$?\b%s\b' % regname, r'$'+regname, expression)
return expression
def items(self):
for regname in self.all:
yield regname, self[regname]
@property
def arguments(self):
argnames = arch_to_regs[gef.arch.current].args
retval = []
for arg in argnames:
val = self[arg]
if val is None:
try: val = gdb.parse_and_eval(arg)
except: val = '???'
retval.append(val)
return retval
arch_to_regs = arch_to_regs
# To prevent garbage collection

@ -1,9 +1,17 @@
import gdb
import string
import gef.types
def get(address):
try:
return gdb.Value(value).cast(gef.types.pchar).string()
sz = gdb.Value(address).cast(gef.types.pchar).string()
except Exception as e:
print(e)
return None
return None
if not all(s in string.printable for s in sz):
sz
if len(sz) < 15:
return sz
return sz[:15] + '...'

@ -1,11 +1,15 @@
import gdb
import gef.memoize
import gef.memory
@gef.memoize.reset_on_objfile
def get(address):
"""
Retrieve the textual name for a symbol
"""
# Fast path
if address < gef.memory.MMAP_MIN_ADDR:
return ''
# This sucks, but there's not a GDB API for this.
result = gdb.execute('info symbol %#x' % int(address), to_string=True, from_tty=False)

@ -1,11 +1,16 @@
import os
import sys
import gdb
import glob
import tempfile
import subprocess
import gef.events
import gef.memoize
module = sys.modules[__name__]
@gef.events.new_objfile
@gef.memoize.reset_on_exit
def update():
@ -31,8 +36,78 @@ def update():
module.ptrsize = pvoid.sizeof
if pvoid.sizeof == 4: module.ptrdiff = uint32
if pvoid.sizeof == 8: module.ptrdiff = uint64
# Call it once so we load all of the types
update()
# Reset the cache so that the first load isn't cached.
update.clear()
update.clear()
tempdir = tempfile.gettempdir() + '/gef'
if not os.path.exists(tempdir):
os.mkdir(tempdir)
# Trial and error until things work
blacklist = ['regexp.h', 'xf86drm.h', 'libxl_json.h', 'xf86drmMode.h',
'caca0.h', 'xenguest.h', '_libxl_types_json.h', 'term_entry.h', 'slcurses.h',
'pcreposix.h', 'sudo_plugin.h', 'tic.h', 'sys/elf.h', 'sys/vm86.h',
'xenctrlosdep.h', 'xenctrl.h', 'cursesf.h', 'cursesm.h', 'gdbm.h', 'dbm.h',
'gcrypt-module.h', 'term.h']
def load(name):
try:
return gdb.lookup_type(name)
except gdb.error:
pass
s, _ = gdb.lookup_symbol
# Try to find an architecture-specific include path
arch = gef.arch.current.split(':')[0]
include_dir = glob.glob('/usr/%s*/include' % arch)
if include_dir:
include_dir = include_dir[0]
else:
include_dir = '/usr/include'
source = '#include <fstream>\n'
for subdir in ['', 'sys', 'netinet']:
dirname = os.path.join(include_dir, subdir)
for path in glob.glob(os.path.join(dirname, '*.h')):
if any(b in path for b in blacklist):
continue
source += '#include "%s"\n' % path
source += '''
#ifdef %(name)s
#pragma push("%(name)s")
#undef %(name)s
long long %(name)s =
#pragma pop("%(name)s")
%(name)s;
#else
%(name)s foo;
#endif
'''.format(**locals())
filename = '%s/%s_%s' % (tempdir, arch, name)
if not os.path.exists(filename + '.o'):
with open(filename + '.cc', 'w+') as f:
f.write(source)
f.flush()
subprocess.check_output('g++ -w -c -g %s.cc -o %s.o' % (filename, filename), shell=True)
gdb.execute('add-symbol-file %s.o 0' % filename, from_tty=False, to_string=True)
return gdb.lookup_type(name)

@ -0,0 +1,15 @@
import struct, termios, fcntl, sys
import gef.arch
def banner(title):
title = title.upper()
try:
_height, width = struct.unpack('hh', fcntl.ioctl(sys.stdin.fileno(), termios.TIOCGWINSZ, '1234'))
except:
width = 80
width -= 2
return ("[{:-^%ss}]" % width).format(title)
def addrsz(address):
address = int(address) & gef.arch.ptrmask
return "%{}x".format(2*gef.arch.ptrsize) % address

@ -18,27 +18,84 @@ import gef.proc
import gef.compat
import gef.memoize
import gef.stack
import gef.events
import gef.regs
# List of manually-explored pages which were discovered
# by analyzing the stack or register context.
explored_pages = []
@gef.memoize.reset_on_stop
def get():
pages = proc_pid_maps()
pages = []
pages.extend(proc_pid_maps())
if not pages:
pages = info_auxv()
pages.extend(info_auxv())
if pages: pages += info_sharedlibrary()
else: pages = info_files()
if pages: pages.extend(info_sharedlibrary())
else: pages.extend(info_files())
pages.extend(gef.stack.stacks.values())
pages.extend(explored_pages)
pages.sort()
return pages
@gef.memoize.reset_on_stop
def find(address):
if address < gef.memory.MMAP_MIN_ADDR:
return None
for page in get():
if address in page:
return page
return None
return explore(address)
def explore(address_maybe):
"""
Given a potential address, check to see what permissions it has.
Returns:
Page object
Note:
Adds the Page object to a persistent list of pages which are
only reset when the process dies. This means pages which are
added this way will not be removed when unmapped.
Also assumes the entire contiguous section has the same permission.
"""
address_maybe = gef.memory.page_align(address_maybe)
flags = 4 if gef.memory.peek(address_maybe) else 0
if not flags:
return None
flags |= 2 if gef.memory.poke(address_maybe) else 0
flags |= 1 if not gef.stack.nx else 0
page = find_boundaries(address_maybe)
page.flags = flags
explored_pages.append(page)
return page
# Automatically ensure that all registers are explored on each stop
@gef.events.stop
def explore_registers():
for regname in gef.regs.all:
find(gef.regs[regname])
@gef.events.exit
def clear_explored_pages():
while explored_pages:
explored_pages.pop()
@gef.memoize.reset_on_stop
def proc_pid_maps():
"""
Parse the contents of /proc/$PID/maps on the server.
@ -92,7 +149,7 @@ def proc_pid_maps():
maps, perm, offset, dev, inode_objfile = line.split(None, 4)
try: inode, objfile = inode_objfile.split()
except: objfile = None
except: objfile = ''
start, stop = maps.split('-')
@ -109,9 +166,10 @@ def proc_pid_maps():
page = gef.memory.Page(start, size, flags, offset, objfile)
pages.append(page)
return sorted(pages)
return tuple(pages)
@gef.memoize.reset_on_objfile
def info_sharedlibrary():
"""
Parses the output of `info sharedlibrary`.
@ -156,6 +214,7 @@ def info_sharedlibrary():
return sorted(pages)
@gef.memoize.reset_on_objfile
def info_files():
example_info_files_linues = """
@ -177,7 +236,7 @@ def info_files():
"""
seen_files = set()
pages = []
pages = list()
main_exe = ''
for line in gdb.execute('info files', to_string=True).splitlines():
@ -210,11 +269,11 @@ def info_files():
pages.extend(gef.elf.map(vaddr, objfile))
return sorted(pages)
return tuple(pages)
@gef.memoize.reset_on_exit
def info_auxv(skip_exe=False):
"""
Extracts the name of the executable from the output of the command
@ -251,8 +310,8 @@ def find_boundaries(addr, name=''):
Given a single address, find all contiguous pages
which are mapped.
"""
start = gef.memory.find_upper_boundary(addr)
end = gef.memory.find_lower_boundary(addr)
start = gef.memory.find_lower_boundary(addr)
end = gef.memory.find_upper_boundary(addr)
return gef.memory.Page(start, end-start, 4, 0, name)
aslr = False

Loading…
Cancel
Save