def __init__(self, elf, start, end, thumb): r2.run_aab(elf) # run basic block analysis self.valid = True self.start_ins = None self.start_ins_addr = None self.write_ins = None self.write_ins_addr = None self.finish_ins = None self.finish_ins_addr = None self.start = start self.end = end self.elf = elf self.thumb = thumb self.valid = False self.branch_ins_addr = None self.branch_ins = None # grab basic blocks surrounding this region r2.gets(elf, "s 0x%x" % self.start) if self.thumb: # force r2 to use the correct instruction size. sigh. r2.gets(elf, "ahb 16") r2.gets(elf, "e asm.bits=16") else: r2.gets(elf, "ahb 32") r2.gets(elf, "e asm.bits=32") self.bbs = r2.get(elf, "pdbj") next = self.bbs[-1]["offset"] + self.bbs[-1]["size"] while next < end: r2.get(elf, "s 0x%x" % next) self.bbs.extend(r2.get(elf, "pdbj")) next = self.bbs[-1]["offset"] + self.bbs[-1]["size"] # grab one more basic block r2.get(elf, "s 0x%x" % next) self.bbs.extend(r2.get(elf, "pdbj"))
def __init__(self, start, end, inplace, table): self.stage = table.stage self.table = table self.inplace = inplace self.valid = False self.start = start self.end = end self.thumb = self.table.thumbranges.overlaps_point(self.start) self.info = LongWriteInfo(self.stage.elf, self.start, self.end, self.thumb) self.info.calculate_info() ins = self.table.ia.disasm( b"%s" % self.info.write_ins["bytes"].decode("hex"), self.thumb, self.info.write_ins["offset"]) self.write_size = self.table.ia.calculate_store_size(ins) self.breakaddr = self.info.start_ins_addr self.writeaddr = self.info.write_ins_addr self.contaddr = self.info.finish_ins_addr writes = self.table.writestable.where( "(0x%x == pclo) & (0x%x == pchi)" % (utils.addr_lo(self.writeaddr), utils.addr_hi(self.writeaddr))) try: write = next(writes) except Exception as e: print e print "Longwrite not found at %x (%s)" % (self.writeaddr, self.__dict__) return self.valid = True self.writesize = write['writesize'] r2.get(self.stage.elf, "s 0x%x" % self.writeaddr) if self.thumb: r2.get(self.stage.elf, "e asm.bits=16") r2.gets(self.stage.elf, "ahb 16") else: r2.get(self.stage.elf, "e asm.bits=32") r2.gets(self.stage.elf, "ahb 32") r2.get(self.stage.elf, "pd 1") i = r2.get(self.stage.elf, "pdj 1")[0] self.value = b"%s" % i["bytes"] self.disasm = i["disasm"] write['halt'] = False write.update() self.funname = db_info.get(self.stage).addr2functionname( self.writeaddr) self.instr = self.table.ia.disasm(self.value, self.thumb, self.writeaddr) self.table.writestable.flush()
def addr2line(addr, elf, debug=False, fn=None): if fn is None: fn = addr2functionname(addr, elf, debug) addr = get_symbol_location(elf, fn, debug) old = r2.gets(elf, "s") r2.get(elf, "s 0x%x" % addr) s = r2.gets(elf, "CL") r2.get(elf, "s %s" % old) res = s.split() d = r2.gets(elf, "pwd") if debug and res: print "addr2line %s%s:%s" % (d, res[1][2:], res[3]) if res: return "%s%s:%s" % (d, res[1][2:], res[3]) else: return ""
def addr2line(addr, stage, debug=False): fn = addr2functionname(addr, stage) addr = get_symbol_location(fn, stage) elf = stage.elf #print "addr2line 0x%x" % addr old = r2.gets(elf, "s") r2.get(elf, "s 0x%x" % addr) s = r2.gets(elf, "CL") r2.get(elf, "s %s" % old) res = s.split() d = r2.gets(elf, "pwd") if debug and res: print "addr2line %s%s:%s" % (d, res[1][2:], res[3]) if res: return "%s%s:%s" % (d, res[1][2:], res[3]) else: return ""
def __init__(self, controller, r, stage): # controller.gdb_print("creating longwrite break\n") self.emptywrite = {'start': None, 'end': None, 'pc': None} self.writeinfo = self.emptywrite self.breakaddr = r['breakaddr'] self.contaddr = r['contaddr'] self.writeaddr = r['writeaddr'] self.thumb = r['thumb'] r2.gets(stage.elf, "s 0x%x" % self.writeaddr) if self.thumb: self.emu = unicorn.Uc(unicorn.UC_ARCH_ARM, unicorn.UC_MODE_THUMB) r2.gets(stage.elf, "ahb 16") r2.gets(stage.elf, "e asm.bits=16") self.cs = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_THUMB) else: self.emu = unicorn.Uc(unicorn.UC_ARCH_ARM, unicorn.UC_MODE_ARM) r2.gets(stage.elf, "ahb 32") r2.gets(stage.elf, "e asm.bits=32") self.cs = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_ARM) r2.get(stage.elf, "pdj 1") self.cs.detail = True self.info = staticanalysis.LongWriteInfo(stage.elf, r['start'], r['end'], self.thumb) self.inss = [] self.regs = set() self.bytes = b"" self.dst_addrs = [] self.write_size = r['writesize'] for i in self.info.bbs: self.inss.append(i) bs = i["bytes"].decode("hex") self.bytes += b"%s" % bs ci = next(self.cs.disasm(bs, i["offset"], 1)) if i["offset"] == self.writeaddr: self.write_ins = ci (read, write) = ci.regs_access() for rs in (read, write): self.regs.update( [ci.reg_name(rn).encode('ascii') for rn in rs]) self.emu.mem_map(0, 0xFFFFFFFF + 1, unicorn.UC_PROT_ALL) self.emu.mem_write(self.inss[0]["offset"], self.bytes) self.emu.hook_add(unicorn.UC_HOOK_MEM_WRITE, self.write_hook) self.spec = "*(0x%x)" % r['breakaddr'] TargetBreak.__init__(self, self.spec, controller, True, stage, r=r)
def update_from_trace(self, tracewrites): for w in tracewrites: pc = long(w["pc"]) thumb = self.thumbranges.overlaps_point(pc) s = self.srcstable.where("(addrlo == 0x%x) & (addrhi == 0x%x)" % (utils.addr_lo(pc), utils.addr_hi(pc))) try: s = next(s) # is in table, do nothing except StopIteration: r2.gets(self.stage.elf, "s 0x%x" % pc) i = r2.get(self.stage.elf, "pdj 1")[0] ins = b"%s" % i["bytes"] dis = i["disasm"] mne = dis.split()[0] srcr = self.srcstable.row srcr['addr'] = pc srcr['addrlo'] = utils.addr_lo(pc) srcr['addrhi'] = utils.addr_hi(pc) srcr['line'] = utils.addr2line(pc, self.stage) srcr['src'] = utils.line2src(srcr['line']) srcr['ivalue'] = ins srcr['ilength'] = len(ins) srcr['thumb'] = thumb srcr['disasm'] = dis srcr['mne'] = mne srcr.append() ws = self.writestable.row ws['thumb'] = thumb ws['pc'] = pc ws['pclo'] = utils.addr_lo(pc) ws['pchi'] = utils.addr_hi(pc) ws['writesize'] = w['reportedsize'] ws['halt'] = False ws.append self.srcstable.flush() self.srcstable.reindex() self.writestable.flush() self.writestable.reindex() self.h5file.flush()
def addr2functionname(addr, elf, debug=False): old = r2.gets(elf, "s") r2.get(elf, "s 0x%x" % addr) s = r2.get(elf, "afi") r2.get(elf, "s %s" % old) def getname(i): name = i["name"] if i.name.startswith("sym."): name = name[4:] #print "addr2fn %x " % (addr) for i in s: if len(i) > 1: print s print "%x addr func" % addr raise Exception name = getname(i) return name return ""
def addr2disasmobjdump(addr, sz, stage, thumb=True, debug=False): old = r2.gets(stage.elf, "s") r2.gets(stage.elf, "s 0x%x" % addr) if thumb: # force r2 to use the correct instruction size. sigh. r2.gets(stage.elf, "ahb 16") r2.gets(stage.elf, "e asm.bits=16") else: r2.gets(stage.elf, "ahb 32") r2.gets(stage.elf, "e asm.bits=32") r2.get(stage.elf, "pd 1") i = r2.get(stage.elf, "pdj 1")[0] if "disasm" in i or u"invalid" == i["type"] or u"invalid" == i["disasm"]: r2.get(stage.elf, "s %s" % old) return (None, None, None) fn = db_info.get(stage).addr2functionname(addr) r2.get(stage.elf, "s %s" % old) return (i['bytes'], i['disasm'], fn)
def calculate_info(self): # lookup write instruction nwrites = 0 elf = self.elf for i in self.bbs: mne = i["opcode"].split()[0] if InstructionAnalyzer._is_mne_memstore(mne): nwrites += 1 if (self.start <= i["offset"]) and (i["offset"] <= self.end): if self.write_ins is not None: # if there are two write instruction in basic block, don't know what to do self.valid = False break else: self.write_ins = i self.valid = True self.write_ins_addr = self.write_ins["offset"] if nwrites > 1: print "Warning: %s write ins in these blocks" % nwrites if not self.valid: return # look for branch after write to find loop branch = None unconditional = False for b in self.bbs: if b["offset"] < self.write_ins_addr: continue if b["type"] == u"cjmp" or b["type"] == u"jmp": if b["type"] == "jmp": dst = b["jump"] r2.gets(elf, "s 0x%x" % dst) for next in r2.get(elf, "pdbj"): if next["type"] == u"cjmp" or next["type"] == "jmp": if next["type"] == "cjmp": jump = next["jump"] if jump not in [ ii["offset"] for ii in self.bbs ]: self.finish_ins_addr = jump else: self.finish_ins_addr = next[ "offset"] + next["size"] else: # don't handle this case yet self.valid = False break break #branch = r2.get(elf, "pdj 1")[0] #self.finish_ins_addr = branch["offset"] + branch["size"] else: branch = b jump = branch["jump"] if jump not in [ii["offset"] for ii in self.bbs]: self.finish_ins_addr = jump else: self.finish_ins_addr = branch["offset"] + branch["size"] r2.gets(elf, "s 0x%x" % self.finish_ins_addr) self.finish_ins = r2.get(elf, "pdj 1")[0] self.start_ins_addr = self.write_ins_addr self.start_ins = self.write_ins
def get_row_information(self): row = {} labels = WriteSearch.find_labels(labeltool.SkipLabel, "", self.stage, self.name) startaddr = -1 endaddr = -1 start = "" end = "" elf = self.stage.elf srcdir = Main.get_runtime_config("temp_target_src_dir") isfunc = False for l in labels: if not l.name == self.name: continue if l.value == "START": lineno = self.table._get_real_lineno(l, False) start = "%s:%d" % (l.filename, lineno) elif l.value == "END": lineno = self.table._get_real_lineno(l, True) end = "%s:%d" % (l.filename, lineno) elif l.value == "FUNC": isfunc = True lineno = self.table._get_real_lineno(l, False) start = "%s:%d" % (l.filename, lineno) startaddr = self.table._get_line_addr(start, True) f = pytable_utils.get_unique_result(self.table.funcstable, ( "(startaddrlo <= 0x%x) & (0x%x < endaddrlo) & (startaddrhi <= 0x%x) & (0x%x <= endaddrhi)" % (utils.addr_lo(startaddr), utils.addr_lo(startaddr), utils.addr_hi(startaddr), utils.addr_hi(startaddr)))) (startaddr, endaddr) = (f['startaddr'], f['endaddr']) r2.get(elf, "s 0x%x" % startaddr) thumb = False if self.table.thumbranges.overlaps_point(startaddr): thumb = True if thumb: r2.get(self.stage.elf, "e asm.bits=16") r2.gets(self.stage.elf, "ahb 16") else: r2.get(self.stage.elf, "e asm.bits=32") r2.gets(self.stage.elf, "ahb 32") disasm = r2.get(elf, "pd 2") disasm = r2.get(elf, "pdj 2") if disasm[0]["disasm"].startswith("push"): firstins = disasm[1] else: firstins = disasm[0] startaddr = firstins["offset"] #print "start %s,%x" % (startaddr, endaddr) elif l.value == "NEXT": lineno = self.table._get_real_lineno(l, False) start = "%s:%d" % (l.filename, lineno) end = "%s:%d" % (l.filename, lineno) if lineno == -1: return None if (startaddr < 0) and (endaddr < 0): # move startaddr after any push instructions startaddr = self.table._get_line_addr(start, True) endaddr = self.table._get_line_addr(end, False) r2.get(elf, "s 0x%x" % startaddr) thumb = False if self.table.thumbranges.overlaps_point(startaddr): thumb = True if thumb: r2.gets(self.stage.elf, "ahb 16") r2.get(self.stage.elf, "e asm.bits=16") else: r2.gets(self.stage.elf, "ahb 32") r2.get(self.stage.elf, "e asm.bits=32") disasm = r2.get(elf, "pd 2") disasm = r2.get(elf, "pdj 2") if "disasm" in disasm[0]: if (disasm[0][u"disasm"].startswith("push")): # don't include push instruction startins = disasm[1] else: startins = disasm[0] startaddr = startins["offset"] s = long(startaddr + self.adjuststart) e = long(endaddr + self.adjustend) if e < s: t = s s = e e = t row['pc'] = s row['pclo'] = utils.addr_lo(s) row['pchi'] = utils.addr_hi(s) row['resumepc'] = e row['resumepclo'] = utils.addr_lo(e) row['resumepchi'] = utils.addr_hi(e) row['isfunction'] = isfunc row['thumb'] = self.table.thumbranges.overlaps_point(row['pc']) return row
def create_writes_table(self, start=0, stop=0): self.writestable = self.h5file.create_table( self.group, 'writes', WriteEntry, "statically determined pc \ values for write instructions" ) self.smcstable = self.h5file.create_table( self.group, 'smcs', SmcEntry, "statically determined pc values \ for smc instructions") self.srcstable = self.h5file.create_table(self.group, 'srcs', SrcEntry, "source code info") # now look at instructions if not self.is_arm(): return srcdir = Main.get_runtime_config("temp_target_src_dir") allranges = intervaltree.IntervalTree() for s in utils.get_section_headers(self.stage): if s['flags'].endswith('x'): if s['size'] == 0: continue allranges.add( intervaltree.Interval(long(s['address']), long(s['address'] + s['size']))) allranges.merge_overlaps() r = self.writestable.row smcr = self.smcstable.row allranges = self.thumbranges | self.armranges # loop through all instructions as according to debug symbols for (ra, thumb) in [(self.thumbranges, True), (self.armranges, False)]: for ir in ra: pc_next = ir.begin while pc_next < ir.end: pc = pc_next p = False r2.gets(self.stage.elf, "s 0x%x" % pc) if thumb: # force r2 to use the correct instruction size. sigh. r2.gets(self.stage.elf, "ahb 16") r2.gets(self.stage.elf, "e asm.bits=16") else: r2.gets(self.stage.elf, "ahb 32") r2.gets(self.stage.elf, "e asm.bits=32") r2.get(self.stage.elf, "pd 1") ins_info = r2.get(self.stage.elf, "pdj 1")[0] if p: for k, v in ins_info.iteritems(): print "%s: %s" % (k, v) print "offset %x" % ins_info["offset"] insadded = False if not "disasm" in ins_info or u"invalid" == ins_info[ "type"] or u"invalid" == ins_info["disasm"]: print "invalid instruction according to r2: pc: %x, is thumb? %s. Using capstone to disassemble" % ( pc, thumb) if 'bytes' in ins_info: # get results of capstone disassembly inscheck = self.ia.disasm( b"%s" % ins_info['bytes'].decode("hex"), thumb, pc) ins_info[ 'disasm'] = inscheck.mnemonic + " " + inscheck.op_str else: print ins_info raise Exception() pc = ins_info['offset'] dis = ins_info['disasm'] val = ins_info['bytes'] mne = dis.split()[0] ins = b"%s" % val.decode('hex') pc_next += ins_info['size'] #... just in case radare2 doesn't properly report invalid instructions try: inscheck = self.ia.disasm(ins, thumb, pc) except StopIteration: print "Radare2 disassembled invalid instruction 0x%x (%s) as %s" % ( pc, val, ins_info) continue if mne != inscheck.mnemonic: if thumb: r2.gets(self.stage.elf, "e asm.bits=16") r2.gets(self.stage.elf, "ahb 16") else: r2.gets(self.stage.elf, "ahb 32") r2.gets(self.stage.elf, "e asm.bits=32") print "R2 and capstone disagree at %x %s" % (pc, thumb) print "CAPSTONE --->" print "addr: %x" % inscheck.address print "op: %s" % inscheck.op_str print "mne: %s" % inscheck.mnemonic print "byres: %s" % ["%x" % b for b in inscheck.bytes] print "size: %s" % inscheck.size print "r2 ------------------------>" print r2.gets(self.stage.elf, "e asm.bits") for (k, v) in ins_info.iteritems(): print "%s: %s" % (k, v) r2.get(self.stage.elf, "s 0x%x" % pc) print r2.gets(self.stage.elf, "pd 1") if self.ia.is_mne_memstore( mne) or self.ia.is_mne_memstore( inscheck.mnemonic): raise Exception print "... But I guess it doesn't matter because neither instruction modifies memory." if mne and self.ia.is_mne_memstore(mne): if self.dataranges.overlaps_point(pc): continue r['thumb'] = thumb r['pc'] = pc r['pclo'] = utils.addr_lo(pc) r['pchi'] = utils.addr_hi(pc) r['halt'] = True regs = self.ia.needed_regs(inscheck) if len(regs) > 4: raise Exception("Sorry, too many registers") for i in range(len(regs)): r['reg%d' % i] = regs[i] size = self.ia.calculate_store_size(inscheck) r['writesize'] = size insadded = True r.append() elif mne == 'smc': # add to smcs table smcr['pc'] = pc smcr['pclo'] = utils.addr_lo(pc) smcr['pchi'] = utils.addr_hi(pc) mne = 'smc' thumb = False if self.thumbranges.overlaps_point(pc): thumb = True smcr['thumb'] = thumb insadded = True smcr.append() if self.verbose: print "smc at 0x%x" % pc if insadded: # also cache source code information related to instruction s = self.srcstable.where( "(addrlo == 0x%x) & (addrhi == 0x%x)" % (utils.addr_lo(pc), utils.addr_hi(pc))) try: s = next(s) # is in table, do nothing except StopIteration: srcr = self.srcstable.row srcr['addr'] = pc srcr['addrlo'] = utils.addr_lo(pc) srcr['addrhi'] = utils.addr_hi(pc) srcr['line'] = utils.addr2line(pc, self.stage) srcr['src'] = utils.line2src(srcr['line']) srcr['ivalue'] = ins srcr['ilength'] = len(ins) srcr['thumb'] = thumb srcr['disasm'] = dis srcr['mne'] = mne srcr.append() self.srcstable.flush() insadded = False self.writestable.flush() self.writestable.cols.pclo.create_index(kind='full') self.writestable.cols.pchi.create_index(kind='full') self.smcstable.flush() self.smcstable.cols.pclo.create_index(kind='full') self.smcstable.cols.pchi.create_index(kind='full') self.srcstable.flush() self.srcstable.cols.addrlo.create_index(kind='full') self.srcstable.cols.addrhi.create_index(kind='full') self.srcstable.cols.line.create_index(kind='full') self.smcstable.flush() self.h5file.flush()
def get_entrypoint(elf): try: return r2.entrypoint(elf) except KeyError: r2.gets(elf, "s") return r2.entrypoint(elf)