Example #1
0
    def __init__(self, so_file_name, apk):

        # use radare2's RCore for lib analysis
        core = RCore()

        # load the file with RBin from r2
        self.jni_on_load_vaddr = self.load_file(core, so_file_name, apk)

        if self.jni_on_load_vaddr == "":
            print "ERROR: library file has no JNI_OnLoad method"
            sys.exit(1)

        self.so_file_name = so_file_name
        self.sig = self.get_sig(core)

        print("Sig: %s " % (self.sig))
Example #2
0
    def open(self, path):
        self.r2core = RCore()
        self.r2core.flags.space_set(b'symbols')

        self.r2core.file_open(path.encode('ascii'), False, BASE_ADDR)
        self.r2core.bin_load("", 0)

        self.r2core.anal_all()
        print() # anal_all is noisy

        # clean up function overlaps
        self.r2core.cmd_str('aff')

        self.filePath = path

        arch = self.r2core.config.get('asm.arch')
        if arch == 'x86':
            self.asmFormatter = X86AsmFormatter(self)
        elif arch == 'mips':
            self.asmFormatter = MipsAsmFormatter(self)
        else:
            raise NotImplementedError("asm formatting for {}".format(arch))
Example #3
0
File: main.py Project: C4rt/sonare
class SonareWindow(QMainWindow):
    # TODO: HTML should use settings specified here
    FONT_NAME = 'Monospace'
    FONT_SIZE = 8

    WINDOW_COLOR       = QColor(0x3c, 0x3c, 0x3c)
    BG_COLOR           = QColor(0x50, 0x50, 0x64)
    DEFAULT_TEXT_COLOR = QColor(0xD8, 0xD8, 0xD8)

    # TODO: HTML should use settings specified here
    ADDR_COLOR = QColor(0x7F, 0xEC, 0x91)
    SYMBOL_COLOR = QColor(0xD8, 0xD8, 0xD8)


    def __init__(self, path):
        QMainWindow.__init__(self)
        self.setMinimumSize(QSize(600, 400))

        self.font = QFont(self.FONT_NAME, self.FONT_SIZE)
        self.fontMetrics = QFontMetricsF(self.font)

        palette = self.palette()
        # palette.setColor(QPalette.Window, self.WINDOW_COLOR)
        # palette.setColor(QPalette.WindowText, self.DEFAULT_TEXT_COLOR)
        palette.setColor(QPalette.Base, self.BG_COLOR)
        palette.setColor(QPalette.Text, self.DEFAULT_TEXT_COLOR)
        self.setPalette(palette)

        self._makeMenus()

        self.open(path)

        self._makeScene()
        self._makeFlagList()

        self.funcName = None

        self._updateWindowTitle()

    def viewGoto(self):
        addr = self.inputAddr('Sonare - Goto', 'Enter an address:')
        if addr is None:
            return

        self.gotoAddr(addr)

    def viewGraph(self):
        self.curView.setParent(None)

        if self.curView is self.textView:
            self.curView = self.graphView
        else:
            self.curView = self.textView

        self.setCentralWidget(self.curView)

    def _makeMenus(self):
        fileMenu = self.menuBar().addMenu(u"&File")

        quitAct = QAction(u"&Quit", self)
        quitAct.setShortcuts(QKeySequence.Quit)
        quitAct.triggered.connect(self.close)
        fileMenu.addAction(quitAct)


        viewMenu = self.menuBar().addMenu("&View")

        gotoAct = QAction(u"&Goto", self)
        gotoAct.setShortcuts(QKeySequence(u"Ctrl+G"))
        gotoAct.triggered.connect(self.viewGoto)
        viewMenu.addAction(gotoAct)

        # TODO: should probably be with a check mark
        textGraphAct = QAction(u"Switch text/g&raph view", self)
        textGraphAct.setShortcuts(QKeySequence(u"Ctrl+R"))
        textGraphAct.triggered.connect(self.viewGraph)
        viewMenu.addAction(textGraphAct)

    def _makeScene(self):
        self.textView = textview.SonareTextView(self)

        self.graphScene = graph.SonareGraphScene(self)
        self.graphView = QGraphicsView(self.graphScene)
        self.graphView.setRenderHints(
            QPainter.Antialiasing
            | QPainter.TextAntialiasing
            | QPainter.SmoothPixmapTransform
            | QPainter.HighQualityAntialiasing)

        self.curView = self.textView
        self.setCentralWidget(self.curView)

    def _makeFlagList(self):
        model = FlagListModel(self)

        ftdock = FilteredTreeDock(self, "Flags", model, self)
        ftdock.setFilterKeyColumn(1)                  # filter by name
        ftdock.sortByColumn(0, Qt.AscendingOrder)     # sort by address

        self.addDockWidget(Qt.LeftDockWidgetArea, ftdock)

        def onDblClick(modelIdx):
            addrItemIdx = modelIdx.sibling(modelIdx.row(), 0)

            # this is actually the proxy model
            model = ftdock.treeView.model()
            addr = model.data(addrItemIdx, Qt.UserRole + 1)
            self.gotoAddr(addr)

        ftdock.treeView.doubleClicked.connect(onDblClick)

    def _updateWindowTitle(self):
        self.setWindowTitle('Sonare - {} ({})'
            .format(self.funcName or '?', os.path.basename(self.filePath)))

    def open(self, path):
        self.r2core = RCore()
        self.r2core.flags.space_set(b'symbols')

        self.r2core.file_open(path.encode('ascii'), False, 0)
        self.r2core.bin_load("", 0)

        self.r2core.anal_all()
        print() # anal_all is noisy

        # clean up function overlaps
        self.r2core.cmd_str('aff')

        self.core = Core(self.r2core)

        self.filePath = path

        arch = self.r2core.config.get('asm.arch')
        if arch == 'x86':
            self.asmFormatter = X86AsmFormatter(self)
        elif arch == 'mips':
            self.asmFormatter = MipsAsmFormatter(self)
        else:
            raise NotImplementedError("asm formatting for {}".format(arch))

    def inputAddr(self, title, prompt):
        s, ok = QInputDialog.getText(self, title, prompt)
        if not ok:
            return None

        try:
            return self.getAddr(s)
        except ValueError:
            # TODO: message box
            return None

    def getAddr(self, addrName):
        try:
            return int(addrName, 16)
        except ValueError:
            pass

        if isinstance(addrName, unicode):
            addrName = addrName.encode('ascii')

        return self.r2core.num.get(addrName)

    def gotoFunc(self, funcName):
        funcAddr = self.getAddr(funcName)
        if funcAddr is None:
            raise ValueError("Unknown func '{}'".format(funcName))

        self.gotoAddr(funcAddr)

    def gotoAddr(self, funcAddr):
        func = self.r2core.anal.get_fcn_at(funcAddr, 1) # R_ANAL_FCN_TYPE_FCN
        if func is None:
            self.funcName = '?'
        else:
            self.funcName = func.name
            funcAddr = func.addr

        self.textView.gotoAddr(funcAddr)

        self.graphScene.loadFunc(funcAddr)

        if self.graphScene.myBlocks:
            firstBlock = self.graphScene.myBlocks[0]
            r = self.graphScene.getBlockRect(firstBlock.addr)
            self.graphView.centerOn(r.center().x(), r.top())

        self._updateWindowTitle()

    def getAddrName(self, addr):
        flag = self.r2core.flags.get_i(int(addr) & 0xffffffffffffffff)
        if flag is None:
            return None
        else:
            return flag.name

    @property
    def isBigEndian(self):
        return self.r2core.config.get('cfg.bigendian') == 'true'

    def getBytes(self, addr, size):
        hexStr = self.r2core.cmd_str('p8 {}@{:#x}'.format(size, addr)).strip()
        return unhexlify(hexStr)

    def getWord(self, addr):
        # TODO: use r2 api
        buf = self.getBytes(addr, 4)
        fmt = '>L' if self.isBigEndian else '<L'
        return unpack(fmt, buf)[0]

    def fmtNum(self, val):
        if abs(val) < 10:
            return str(val)


        if abs(val) <= 0xffff:
            return format(val, '#x')
        else:
            hexStr = format(val, '08x')
            # split off last 2 bytes
            return hexStr[:-4] + ':' + hexStr[-4:]
Example #4
0
class SonareWindow(QMainWindow):
    # TODO: HTML should use settings specified here
    FONT_NAME = 'Monospace'
    FONT_SIZE = 8

    WINDOW_COLOR       = QColor(0x3c, 0x3c, 0x3c)
    BG_COLOR           = QColor(0x50, 0x50, 0x64)
    DEFAULT_TEXT_COLOR = QColor(0xD8, 0xD8, 0xD8)

    # TODO: HTML should use settings specified here
    ADDR_COLOR = QColor(0x7F, 0xEC, 0x91)
    SYMBOL_COLOR = QColor(0xD8, 0xD8, 0xD8)


    def __init__(self, path):
        QMainWindow.__init__(self)
        self.setMinimumSize(QSize(600, 400))

        self.font = QFont(self.FONT_NAME, self.FONT_SIZE)
        self.fontMetrics = QFontMetricsF(self.font)

        palette = self.palette()
        # palette.setColor(QPalette.Window, self.WINDOW_COLOR)
        # palette.setColor(QPalette.WindowText, self.DEFAULT_TEXT_COLOR)
        palette.setColor(QPalette.Base, self.BG_COLOR)
        palette.setColor(QPalette.Text, self.DEFAULT_TEXT_COLOR)
        self.setPalette(palette)

        self.open(path)

        self._makeScene()
        self._makeFlagList()

        self.funcName = None

        self._updateWindowTitle()

    def _makeScene(self):
        self.scene = graph.SonareGraphScene(self)
        self.view = QGraphicsView(self.scene)
        self.view.setRenderHints(
            QPainter.Antialiasing
            | QPainter.TextAntialiasing
            | QPainter.SmoothPixmapTransform
            | QPainter.HighQualityAntialiasing)
        self.setCentralWidget(self.view)

    def _makeFlagList(self):
        model = FlagListModel(self)

        ftdock = FilteredTreeDock(self, "Flags", model, self)
        ftdock.setFilterKeyColumn(1)                  # filter by name
        ftdock.sortByColumn(0, Qt.AscendingOrder)     # sort by address

        self.addDockWidget(Qt.LeftDockWidgetArea, ftdock)

        def onDblClick(modelIdx):
            addrItemIdx = modelIdx.sibling(modelIdx.row(), 0)

            # this is actually the proxy model
            model = ftdock.treeView.model()
            addr = model.data(addrItemIdx, Qt.UserRole + 1)
            self.gotoAddr(addr)

        ftdock.treeView.doubleClicked.connect(onDblClick)

    def _updateWindowTitle(self):
        self.setWindowTitle('Sonare - {} ({})'
            .format(self.funcName or '?', os.path.basename(self.filePath)))

    def open(self, path):
        self.r2core = RCore()
        self.r2core.flags.space_set(b'symbols')

        self.r2core.file_open(path.encode('ascii'), False, BASE_ADDR)
        self.r2core.bin_load("", 0)

        self.r2core.anal_all()
        print() # anal_all is noisy

        # clean up function overlaps
        self.r2core.cmd_str('aff')

        self.filePath = path

        arch = self.r2core.config.get('asm.arch')
        if arch == 'x86':
            self.asmFormatter = X86AsmFormatter(self)
        elif arch == 'mips':
            self.asmFormatter = MipsAsmFormatter(self)
        else:
            raise NotImplementedError("asm formatting for {}".format(arch))

    def getAddr(self, addrName):
        if isinstance(addrName, unicode):
            addrName = addrName.encode('ascii')

        return self.r2core.num.get(addrName)

    def gotoFunc(self, funcName):
        funcAddr = self.getAddr(funcName)
        if funcAddr is None:
            raise ValueError("Unknown func '{}'".format(funcName))

        self.gotoAddr(funcAddr)

    def gotoAddr(self, funcAddr):
        func = self.r2core.anal.get_fcn_at(funcAddr, 1) # R_ANAL_FCN_TYPE_FCN
        if func is None:
            self.funcName = '?'
        else:
            self.funcName = func.name
            funcAddr = func.addr

        self.scene.loadFunc(funcAddr)

        firstBlock = self.scene.myBlocks[0]
        r = self.scene.getBlockRect(firstBlock.addr)
        self.view.centerOn(r.center().x(), r.top())

        self._updateWindowTitle()

    def getAddrName(self, addr):
        flag = self.r2core.flags.get_i(int(addr) & 0xffffffffffffffff)
        if flag is None:
            return None
        else:
            return flag.name

    @property
    def isBigEndian(self):
        return self.r2core.config.get('cfg.bigendian') == 'true'

    def getWord(self, addr):
        # TODO: use r2 api
        hexStr = self.r2core.cmd_str('p8 4@{:#x}'.format(addr)).strip()
        buf = unhexlify(hexStr)
        fmt = '>L' if self.isBigEndian else '<L'
        return unpack(fmt, buf)[0]

    def fmtNum(self, val):
        if abs(val) < 10:
            return str(val)


        if abs(val) <= 0xffff:
            return format(val, '#x')
        else:
            hexStr = format(val, '08x')
            # split off last 2 bytes
            return hexStr[:-4] + ':' + hexStr[-4:]
Example #5
0
def init_radare(path):
  import collections
  tags = collections.defaultdict(dict)

  core = RCore()
  desc = core.io.open(path, 0, 0)
  if desc == None:
    print "*** RBIN LOAD FAILED"
    return False
  core.bin.load(path, 0, 0, 0, desc.fd, False)
  print "*** radare bin loaded @",ghex(core.bin.get_baddr())

  """
  for e in core.bin.get_entries():
    print e
  """


  # why do i need to do this?
  info = core.bin.get_info()
  core.config.set("asm.arch", info.arch);
  core.config.set("asm.bits", str(info.bits));
  #core.file_open(path, 0, 0)

  """
  # find functions
  core.search_preludes()
  """


  # you have to file_open to make analysis work
  core.file_open(path, False, 0)
  core.bin_load("", 0)
  core.anal_all()

  import collections
  tags = collections.defaultdict(dict)

  for s in core.bin.get_symbols():
    print ghex(s.vaddr), s.name
    tags[s.vaddr]['name'] = s.name

  for f in core.anal.get_fcns():
    print f.name, ghex(f.addr), f.size

    tags[f.addr]['funclength'] = f.size

    sa = f.addr
    starts = []
    # find bblock starts, haxx
    while sa < (f.addr + f.size):
      op = core.op_anal(sa)
      t = op.type & 0xFFFF
      if t == 1 or t == 2:
        starts.append(op.jump)

      if op.size <= 0:
        break
      else:
        sa += op.size

    sa = f.addr
    will_pass = True
    while sa < (f.addr + f.size):
      #print core.op_str(sa)
      instr = core.op_str(sa)
      op = core.op_anal(sa)
      t = op.type
      t2 = t & 0xFFFF
      t3 = t & 0xFFFF0000

      tags[sa]['len'] = op.size
      tags[sa]['semantics'] = []
      tags[sa]['flow'] = []
      tags[sa]['scope'] = ghex(f.addr)
      tags[sa]['flags'] = 0x10000 if will_pass else 0
      will_pass = True

      if t2 == 1 or t2 == 2 or t2 == 5 or (sa+op.size) in starts:
        tags[sa]['semantics'].append("endbb")

      if t == 1 or t == 2:
        # jmp
        tags[sa]['flow'].append(ghex(op.jump))
        will_pass = False
      elif t3 == 0x80000000 and (t2 == 1 or t2 == 2):
        # cond jmp
        tags[sa]['flow'].append(ghex(op.jump))

      tags[sa]['instruction'] = instr

      print "   ", ghex(sa), op.type & 0xFFFF, instr

      if op.size <= 0:
        break
      else:
        sa += op.size
    #bbs = f.get_bbs()
    """

    for b in f.get_bbs():
      print "  ", ghex(b.addr), b.size
    """

  # fix ctl-c
  import signal
  signal.signal(signal.SIGINT, signal.SIG_DFL)

  return tags
Example #6
0
def init_radare(path):
    import collections
    tags = collections.defaultdict(dict)

    core = RCore()
    desc = core.io.open(path, 0, 0)
    if desc == None:
        print "*** RBIN LOAD FAILED"
        return False
    core.bin.load(path, 0, 0, 0, desc.fd, False)
    print "*** radare bin loaded @", ghex(core.bin.get_baddr())
    """
  for e in core.bin.get_entries():
    print e
  """

    # why do i need to do this?
    info = core.bin.get_info()
    core.config.set("asm.arch", info.arch)
    core.config.set("asm.bits", str(info.bits))
    #core.file_open(path, 0, 0)
    """
  # find functions
  core.search_preludes()
  """

    # you have to file_open to make analysis work
    core.file_open(path, False, 0)
    core.bin_load("", 0)
    core.anal_all()

    import collections
    tags = collections.defaultdict(dict)

    for s in core.bin.get_symbols():
        print ghex(s.vaddr), s.name
        tags[s.vaddr]['name'] = s.name

    for f in core.anal.get_fcns():
        print f.name, ghex(f.addr), f.size

        tags[f.addr]['funclength'] = f.size

        sa = f.addr
        starts = []
        # find bblock starts, haxx
        while sa < (f.addr + f.size):
            op = core.op_anal(sa)
            t = op.type & 0xFFFF
            if t == 1 or t == 2:
                starts.append(op.jump)

            if op.size <= 0:
                break
            else:
                sa += op.size

        sa = f.addr
        will_pass = True
        while sa < (f.addr + f.size):
            #print core.op_str(sa)
            instr = core.op_str(sa)
            op = core.op_anal(sa)
            t = op.type
            t2 = t & 0xFFFF
            t3 = t & 0xFFFF0000

            tags[sa]['len'] = op.size
            tags[sa]['semantics'] = []
            tags[sa]['flow'] = []
            tags[sa]['scope'] = ghex(f.addr)
            tags[sa]['flags'] = 0x10000 if will_pass else 0
            will_pass = True

            if t2 == 1 or t2 == 2 or t2 == 5 or (sa + op.size) in starts:
                tags[sa]['semantics'].append("endbb")

            if t == 1 or t == 2:
                # jmp
                tags[sa]['flow'].append(ghex(op.jump))
                will_pass = False
            elif t3 == 0x80000000 and (t2 == 1 or t2 == 2):
                # cond jmp
                tags[sa]['flow'].append(ghex(op.jump))

            tags[sa]['instruction'] = instr

            print "   ", ghex(sa), op.type & 0xFFFF, instr

            if op.size <= 0:
                break
            else:
                sa += op.size
        #bbs = f.get_bbs()
        """

    for b in f.get_bbs():
      print "  ", ghex(b.addr), b.size
    """

    # fix ctl-c
    import signal
    signal.signal(signal.SIGINT, signal.SIG_DFL)

    return tags