예제 #1
0
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 __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 get_symbol_location(elf, name, debug=False):
    s = r2.get(elf, "isj")
    for i in s:
        if i["name"] == name:
            if debug:
                print i
            return i["vaddr"]
    return -1
예제 #4
0
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, 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, 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)
예제 #7
0
def get_symbol_location(elf, name, debug=False):
    s = r2.get(elf, "isj")
    name = u"%s" % name  # convert to unicode
    for i in s:
        if i["name"] == name:
            if debug:
                print i
            return i["vaddr"]
    return -1
def get_symbol_location_start_end(name, stage, debug=False):
    elf = stage.elf
    s = r2.get(elf, "isj")
    for i in s:
        if i["name"] == name:
            addr = i["vaddr"]
            if debug:
                print i
            return (addr, addr + i["size"])
    return (-1, -1)
예제 #9
0
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 get_section_headers(elf):
    ds = r2.get(elf, "iSj")
    index = 0
    headers = []
    for d in ds:
        h = {
            "number": index,
            "name": d["name"],
            "address": d["vaddr"],
            "offset": d["paddr"],
            "size": d['vsize'],
            "filesize": d['size'],
            "flags": d['flags']
        }
        headers.append(h)
        index += 1
    return headers
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 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()
예제 #13
0
def get_section_headers(elf):
    ds = r2.get(elf, "iSj")
    index = 0
    headers = []
    if len(ds) > 0:
        # flags key differs between r2 versions
        if "flags" in ds[0]:
            flags = "flags"
        else:
            flags = "perm"
    for d in ds:
        h = {
            "number": index,
            "name": d["name"],
            "address": d["vaddr"],
            "offset": d["paddr"],
            "size": d['vsize'],
            "filesize": d['size'],
            "flags": d[flags]
        }
        headers.append(h)
        index += 1
    return headers
    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()