Skip to content

Commit

Permalink
add README
Browse files Browse the repository at this point in the history
  • Loading branch information
comex committed Jul 18, 2011
1 parent e53b542 commit 1386b06
Show file tree
Hide file tree
Showing 2 changed files with 248 additions and 1 deletion.
41 changes: 40 additions & 1 deletion README
Original file line number Diff line number Diff line change
@@ -1 +1,40 @@
This is uglier than the released version.
external repositories:
------------------------------------------------------
data: mach-o handling
white: load dylibs into the kernel
datautils0: make kernel patches, port over symbols


in here:
------------------------------------------------------
catalog:
catalog.py: ROP code and kernel exploit
kcode.S: kernel payload
chain: unused
common:
common.h: _log, _assert, etc
datautils:
dmini.py: python interface to data
dejavu:
gen_dejavu.raw.py: FreeType exploit
dsc:
dsc.c: mount dyld shared cache via fuse
goo:
goop.py: the "string with pointers, relocations, etc." abstraction
goo.py: doing ROP with the abstraction
world1.py: specific gadgets
two.py: creating mach-o files with the abstraction
headers: external headers
install:
install.m: install the jailbreak
locutus:
locutus.c: download files / communicate with locutus_server / run install
inject.c: inject a dylib into a process
locutus_server.m: injected into SpringBoard
mroib: unused
otool: patch to otool that supports "force ARM" mode
starstuff:
build-archive.sh: build the saffron-jailbreak-xxx debian package
mount_nulls.c: do so
upgrade-data: unused

208 changes: 208 additions & 0 deletions datautils/dmini.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
import os, re, sys, atexit
import cPickle, shelve # for cache
from ctypes import *

MUST_FIND, TO_EXECUTE, PRIVATE_SYM, IMPORTED_SYM, EXTEND_RANGE = 1, 2, 4, 8, 16

data_dir = os.path.join(os.path.dirname(__file__), '../data')
if sys.platform == 'darwin':
datar = CDLL(data_dir + '/universal/libdata.dylib')
else:
datar = CDLL(data_dir + '/native/libdata.so')

class DataSegment(Structure):
pass

class DataSym(Structure):
_fields_ = [('name', c_char_p),
('address', c_uint32)]

class Binary(Structure):
_fields_ = [('valid', c_bool),
('segments', POINTER(DataSegment)),
('nsegments', c_uint32),
('actual_cpusubtype', c_int),
('the_rest', c_char * 200)]

class Range(Structure):
_fields_ = [('binary', POINTER(Binary)),
('start', c_uint32),
('size', c_size_t)]
def data(self):
return data.rangeconv(self).data()
def data_as(self, typ):
return cast(data.rangeconv(self).start, POINTER(typ))
def __repr__(self):
return 'Range(%r, %x, %x)' % (self.binary, self.start, self.size)

class Prange(Structure):
_fields_ = [('start', c_void_p),
('size', c_size_t)]

def data(self):
return string_at(self.start, self.size)

DataSegment._fields_ = [('file_range', Range),
('vm_range', Range),
('native_segment', c_void_p)]

datar.b_init.argtypes = [POINTER(Binary)]
datar.b_load_dyldcache.argtypes = [POINTER(Binary), c_char_p]
datar.b_load_macho.argtypes = [POINTER(Binary), c_char_p]
datar.b_dyldcache_load_macho.argtypes = [POINTER(Binary), c_char_p, POINTER(Binary)]
datar.b_find_data_anywhere.argtypes = [POINTER(Binary), c_char_p, c_int, c_int]
datar.b_find_data_anywhere.restype = c_uint32
datar.find_data.argtypes = [Range, c_char_p, c_int, c_int]
datar.find_data.restype = c_uint32
datar.b_sym.argtypes = [POINTER(Binary), c_char_p, c_int]
datar.b_sym.restype = c_uint32
datar.b_macho_segrange.argtypes = [POINTER(Binary), c_char_p]
datar.b_macho_segrange.restype = Range
datar.b_macho_sectrange.argtypes = [POINTER(Binary), c_char_p, c_char_p]
datar.b_macho_sectrange.restype = Range
datar.rangeconv.argtypes = [Range]
datar.rangeconv.restype = Prange
datar.b_relocate.argtypes = [POINTER(Binary), POINTER(Binary), c_int, c_void_p, c_uint32]
datar.b_copy_syms.argtypes = [POINTER(Binary), POINTER(POINTER(DataSym)), POINTER(c_uint32), c_int]
datar.data_call_init.argtypes = [c_void_p]
datar.data_call_fini.restype = c_char_p
datar.find_bof.argtypes = [Range, c_uint32, c_int]
datar.find_bof.restype = c_uint32

class DataError(Exception):
pass

class DataWrapper:
def __getattr__(self, attr):
old = getattr(datar, attr)
def func(*args):
datar.data_call_init(old)
datar.data_call.argtypes = old.argtypes
datar.data_call.restype = old.restype
result = datar.data_call(*args)
err = datar.data_call_fini()
if err:
raise DataError(err.rstrip())
else:
return result
return func
#data = DataWrapper()
data = datar

class DminiError(Exception):
pass

def cached(func):
def f2(self, *args):
cache_key = cPickle.dumps((self.path, self.mtime, func.__name__,) + args)
g = self.cache.get(cache_key, None)
if g is None:
g = self.cache[cache_key] = func(self, *args)
return self.wrap(g)
return f2

class Connection:
def __init__(self, path, is_cache=False, use_private_sym=False, rw=False):
self.path = path
self.mtime = os.path.getmtime(path)
self.stack = []
self.cache = {}#shelve.open('/tmp/dmini-cache')
self.binaries = {}
self.use_private_sym = use_private_sym

self.binary = Binary()
self.binary.actual_cpusubtype = 42
data.b_init(byref(self.binary))
self.is_cache = is_cache
if is_cache:
data.b_load_dyldcache(byref(self.binary), path, rw)
self.add_lib('libsystem', '/usr/lib/libSystem.B.dylib')
else:
data.b_load_macho(byref(self.binary), path, rw)

def close(self):
pass

def add_lib(self, short, lib):
assert not self.binaries.has_key(short)
self.binaries[short] = Binary()
data.b_dyldcache_load_macho(byref(self.binary), lib, byref(self.binaries[short]))

def add_43_lib(self, short, lib):
self.add_lib(short, lib)

def explode_name(self, name):
if self.is_cache:
short = 'libsystem'
if '.' in name:
short, name = name.split('.')
return self.binaries[short], name
return self.binary, name

@cached
def find(self, thing):
if isinstance(thing, tuple):
thing = thing[self.binary.actual_cpusubtype != 9]
result = data.b_find_data_anywhere(byref(self.binary), thing, 2 if thing.find('+') != -1 else 4, 0)
if result == 0:
raise DataError("didn't find [%s]" % thing)
return result

@cached
def sym(self, name, type='normal'):
if type == 'normal' and self.use_private_sym: type = 'private'
binary, name = self.explode_name(name)
flags = {'normal': 0, 'private': PRIVATE_SYM, 'imported': IMPORTED_SYM}
result = data.b_sym(byref(binary), name, TO_EXECUTE | flags[type])
if result == 0:
print 'For reference', self._syms(binary, type)
raise DataError('no such sym %s' % name)
return result

def private_sym(self, name):
changeme

def syms(self, b='libsystem'):
return self._syms(self.binaries[b] if self.is_cache else self.binary)

def _syms(self, binary, type='normal'):
syms = POINTER(DataSym)()
nsyms = c_uint32()
data.b_copy_syms(binary, byref(syms), byref(nsyms), TO_EXECUTE | {'normal': 0, 'private': PRIVATE_SYM}[type])
result = {}
for i in xrange(nsyms.value):
result[syms[i].name] = syms[i].address
return result

def wrap(self, num):
return num

def relocate(self, target, slide, my_ls=None):
@CFUNCTYPE(c_uint32, POINTER(Binary), c_char_p)
def lookup_sym(binary, sym):
if my_ls is not None:
result = my_ls(binary, sym)
if result is not None:
return result
return data.b_sym(binary, sym, TO_EXECUTE | MUST_FIND)

data.b_relocate(self.binary, target.binary, 0, lookup_sym, slide)
return self

def nth_segment(self, n):
if n >= self.binary.nsegments: raise DataError
return self.binary.segments[n].vm_range

def segrange(self, segname):
return b_macho_segrange(self.binary, segname)

def sectrange(self, segname, sectname):
return b_macho_sectrange(self.binary, segname, sectname)


cur = None

def init(*args):
global cur
if cur is not None: cur.close()
cur = Connection(*args)

0 comments on commit 1386b06

Please sign in to comment.