class Slot(SessionElement): def __init__(self, sess, tid, mid, index): SessionElement.__init__(self, sess) self.tid = tid self.mid = mid self.index = index self.name = None def __str__(self): if self.name: return 'slot %s at index %i' % (self.name, self.index) else: return 'slot at index %i' % (self.index) def load_slot(self): self.sess.pool(Class, self.sess, tid).load_slots() firstLoc = defer(load_slot, 'firstLoc') locLength = defer(load_slot, 'locLength') name = defer(load_slot, 'name') jni = defer(load_slot, 'jni') gen = defer(load_slot, 'gen') @property def tag(self): return ord(self.jni[0])
class Object(Value): def __init__(self, sess, oid): if oid == 0: raise VoidError() SessionElement.__init__(self, sess) self.oid = oid def __repr__(self): return '<obj %s #%x>' % (self.jni, self.oid) # def __str__(self): # return str(self.fields.values()) def __str__(self): return str("%s <%s>" % (str(self.jni), str(self.oid))) @classmethod def unpackFrom(impl, sess, buf): oid = buf.unpackObjectId() # oid = 0 indicates a GC omgfuckup in Dalvik # which is NOT as uncommon as we would like.. if not oid: return None return sess.pool(impl, sess, oid) def packTo(self, buf): buf.packObjectId(self.oid) @property def gen(self): return self.refType.gen @property def jni(self): return self.refType.jni def load_refType(self): conn = self.sess.conn buf = conn.buffer() self.packTo(buf) code, buf = conn.request(0x0901, buf.data()) if code != 0: raise RequestError(code) self.refType = RefType.unpackFrom(self.sess, buf) refType = defer(load_refType, 'refType') @property def fieldList(self): r = list(f for f in self.refType.fieldList if not f.static) return r @property def typeTag(self): return self.refType.tag @property def fields(self): sess = self.sess conn = self.conn buf = conn.buffer() buf.packTypeId(self.oid) fields = self.fieldList buf.packInt(len(fields)) for field in fields: buf.packFieldId(field.fid) code, buf = conn.request(0x0902, buf.data()) if code != 0: raise RequestError(code) ct = buf.unpackInt() vals = {} for x in range(ct): f = fields[x] vals[f.name] = unpack_value(sess, buf) return vals
class Session(object): def __init__(self, conn): self.pool = andbug.data.pool() self.conn = conn self.emap = {} self.ectl = Lock() self.evtq = Queue() conn.hook(0x4064, self.evtq) self.ethd = threading.Thread(name='Session', target=self.run) self.ethd.daemon = 1 self.ethd.start() def run(self): while True: self.processEvent(*self.evtq.get()) def hook(self, ident, func=None, queue=None, origin=None): return Hook(self, ident, func, queue, origin) def processEvent(self, ident, buf): pol, ct = buf.unpack('1i') for i in range(0, ct): ek = buf.unpackU8() im = unpack_impl[ek] if im is None: raise RequestError(ek) evt = im(self, buf) with self.ectl: hook = self.emap.get(evt[0]) if hook is not None: hook.put(evt[1:]) def load_classes(self): code, buf = self.conn.request(0x0114) if code != 0: raise RequestError(code) def load_class(): tag, tid, jni, gen, flags = buf.unpack('1t$$i') obj = self.pool(Class, self, tid) obj.tag = tag obj.tid = tid obj.jni = jni obj.gen = gen obj.flags = flags return obj ct = buf.unpackU32() self.classList = andbug.data.view(load_class() for i in range(0, ct)) self.classByJni = andbug.data.multidict() for item in self.classList: self.classByJni[item.jni] = item classList = defer(load_classes, 'classList') classByJni = defer(load_classes, 'classByJni') def classes(self, jni=None): if jni: seq = self.classByJni[jni] else: seq = self.classList return andbug.data.view(seq) def suspend(self): code, buf = self.conn.request(0x0108, '') if code != 0: raise RequestError(code) @property def count(self): code, buf = self.conn.request(0x0108, '') if code != 0: raise RequestError(code) def resume(self): code, buf = self.conn.request(0x0109, '') if code != 0: raise RequestError(code) def exit(self, code=0): conn = self.conn buf = conn.buffer() buf.pack('i', code) code, buf = conn.request(0x010A, '') if code != 0: raise RequestError(code) def threads(self, name=None): pool = self.pool code, buf = self.conn.request(0x0104, '') if code != 0: raise RequestError(code) ct = buf.unpackInt() def load_thread(): tid = buf.unpackObjectId() return pool(Thread, self, tid) seq = (load_thread() for x in range(0, ct)) if name is not None: if rx_dalvik_tname.match(name): seq = (t for t in seq if t.name == name) else: seq = (t for t in seq if t.name.split(' ', 1)[-1] == name) return andbug.data.view(seq)
class RefType(SessionElement): def __init__(self, sess, tag, tid): SessionElement.__init__(self, sess) self.tag = tag self.tid = tid def __repr__(self): return '<type %s %s#%x>' % (self.jni, chr(self.tag), self.tid) def __str__(self): return repr(self) @classmethod def unpackFrom(impl, sess, buf): return sess.pool(impl, sess, buf.unpackU8(), buf.unpackTypeId()) def packTo(self, buf): buf.packObjectId(self.tid) def load_signature(self): conn = self.conn buf = conn.buffer() self.packTo(buf) code, buf = conn.request(0x020d, buf.data()) if code != 0: raise RequestError(code) self.jni = buf.unpackStr() self.gen = buf.unpackStr() gen = defer(load_signature, 'gen') jni = defer(load_signature, 'jni') def load_fields(self): sess = self.sess conn = self.conn buf = conn.buffer() buf.pack("t", self.tid) code, buf = conn.request(0x020E, buf.data()) if code != 0: raise RequestError(code) ct = buf.unpackU32() def load_field(): field = Field.unpackFrom(sess, buf) name, jni, gen, flags = buf.unpack('$$$i') field.name = name field.jni = jni field.gen = gen field.flags = flags return field self.fieldList = andbug.data.view(load_field() for i in range(ct)) fieldList = defer(load_fields, 'fieldList') @property def statics(self): sess = self.sess conn = self.conn buf = conn.buffer() buf.packTypeId(self.tid) fields = list(f for f in self.fieldList if f.static) buf.packInt(len(fields)) for field in fields: buf.packFieldId(field.fid) code, buf = conn.request(0x0206, buf.data()) if code != 0: raise RequestError(code) ct = buf.unpackInt() vals = {} for x in range(ct): f = fields[x] vals[f.name] = unpack_value(sess, buf) return vals def load_methods(self): tid = self.tid sess = self.sess conn = self.conn pool = sess.pool buf = conn.buffer() buf.pack("t", tid) code, buf = conn.request(0x020F, buf.data()) if code != 0: raise RequestError(code) ct = buf.unpackU32() def load_method(): mid, name, jni, gen, flags = buf.unpack('m$$$i') obj = pool(Method, sess, tid, mid) obj.name = name obj.jni = jni obj.gen = gen obj.flags = flags return obj self.methodList = andbug.data.view(load_method() for i in range(0, ct)) self.methodByJni = andbug.data.multidict() self.methodByName = andbug.data.multidict() for item in self.methodList: jni = item.jni name = item.name self.methodByJni[jni] = item self.methodByName[name] = item methodList = defer(load_methods, 'methodList') methodByJni = defer(load_methods, 'methodByJni') methodByName = defer(load_methods, 'methodByName') methodList = defer(load_methods, 'methodList') methodByJni = defer(load_methods, 'methodByJni') methodByName = defer(load_methods, 'methodByName') def methods(self, name=None, jni=None): if name and jni: seq = self.methodByName[name] seq = filter(x in seq, self.methodByJni[jni]) elif name: seq = andbug.data.view(self.methodByName[name]) elif jni: seq = self.methodByJni[jni] else: seq = self.methodList return andbug.data.view(seq) @property def name(self): name = self.jni if name.startswith('L'): name = name[1:] if name.endswith(';'): name = name[:-1] name = name.replace('/', '.') return name
class Method(SessionElement): def __init__(self, sess, tid, mid): SessionElement.__init__(self, sess) self.tid = tid self.mid = mid @property def klass(self): return self.sess.pool(Class, self.sess, self.tid) def __str__(self): return '%s.%s%s' % (self.klass, self.name, self.jni) def __repr__(self): return '<method %s>' % self def load_line_table(self): sess = self.sess conn = sess.conn pool = sess.pool tid = self.tid mid = self.mid data = conn.buffer().pack('om', tid, mid) code, buf = conn.request(0x0601, data) if code != 0: raise RequestError(code) f, l, ct = buf.unpack('88i') if (f == -1) or (l == -1): self.firstLoc = None self.lastLoc = None self.lineTable = andbug.data.view([]) #TODO: How do we handle native methods? self.firstLoc = pool(Location, sess, tid, mid, f) self.lastLoc = pool(Location, sess, tid, mid, l) ll = {} self.lineLocs = ll def line_loc(): loc, line = buf.unpack('8i') loc = pool(Location, sess, tid, mid, loc) loc.line = line ll[line] = loc for i in range(0, ct): line_loc() firstLoc = defer(load_line_table, 'firstLoc') lastLoc = defer(load_line_table, 'lastLoc') lineTable = defer(load_line_table, 'lineTable') def load_method(self): self.klass.load_methods() name = defer(load_method, 'name') jni = defer(load_method, 'jni') gen = defer(load_method, 'gen') flags = defer(load_method, 'flags') def load_slot_table(self): sess = self.sess conn = self.conn pool = sess.pool tid = self.tid mid = self.mid data = conn.buffer().pack('om', tid, mid) code, buf = conn.request(0x0605, data) if code != 0: raise RequestError(code) act, sct = buf.unpack('ii') #TODO: Do we care about the argCnt ? def load_slot(): codeIndex, name, jni, gen, codeLen, index = buf.unpack('l$$$ii') slot = pool(Slot, sess, tid, mid, index) slot.firstLoc = codeIndex slot.locLength = codeLen slot.name = name slot.jni = jni slot.gen = gen return slot self.slots = andbug.data.view(load_slot() for i in range(0, sct)) slots = defer(load_slot_table, 'slots')