Esempio n. 1
0
  def do_export(self, f):
    func = get_func(f)
    if func is None:
      return None

    # Variables that will be stored in the database
    func_name = GetFunctionName(f)
    prototype = GetType(f)
    if prototype is None:
      prototype = GuessType(f)

    prototype2 = None
    ti = GetTinfo(f)
    if ti:
      prototype2 = idc_print_type(ti[0],ti[1], func_name, PRTYPE_1LINE)

    conditions = 0
    constants = set()
    externals = set()
    switches = []
    calls = set()
    callees = {}
    loops = 0
    recursive = False
    indirects = 0
    globals_uses = set()

    # Variables required for calculations of previous ones
    bb_relations = {}

    # Iterate through each basic block
    ea = func.startEA
    flow = FlowChart(func)
    for block in flow:
      block_ea = block.startEA

      # ...and each instruction on each basic block
      for ea in list(Heads(block.startEA, block.endEA)):
        # Remember the relationships
        bb_relations[block_ea] = []

        # Iterate the succesors of this basic block
        for succ_block in block.succs():
          bb_relations[block_ea].append(succ_block.startEA)

        # Iterate the predecessors of this basic block
        for pred_block in block.preds():
          try:
            bb_relations[pred_block.startEA].append(block.startEA)
          except KeyError:
            bb_relations[pred_block.startEA] = [block.startEA]

        # Get the conditionals
        is_cond = is_conditional_branch_or_jump(ea)
        if is_cond:
          conditions += 1

        if is_call_insn(ea) and len(list(CodeRefsFrom(ea, 0))) == 0:
          indirects += 1

        # Get the constants, externals and globals
        constants, externals, globals_uses = self.parse_operands(ea, constants, externals)

        # Get the switches information
        switches = self.parse_switches(ea, switches)

        # Get the calls
        xrefs = list(CodeRefsFrom(ea, 0))
        if len(xrefs) == 1:
          tmp_func = GetFunctionName(xrefs[0])
          if tmp_func not in BANNED_FUNCTIONS and ".%s" % tmp_func not in BANNED_FUNCTIONS:
            func_obj = get_func(xrefs[0])
            if func_obj is not None:
              if func_obj.startEA != func.startEA:
                tmp_ea = xrefs[0]
                calls.add(tmp_ea)
                name = GetFunctionName(tmp_ea)
                try:
                  callees[name] += 1
                except:
                  callees[name] = 1
              else:
                recursive = True

    # Calculate the strongly connected components
    try:
      strongly_connected = strongly_connected_components(bb_relations)
    except:
      print("Exception:", str(sys.exc_info()[1]))
      return False

    # ...and get the number of loops out of it
    for sc in strongly_connected:
      if len(sc) > 1:
        loops += 1
      else:
        if sc[0] in bb_relations and sc[0] in bb_relations[sc[0]]:
          loops += 1

    if self.debug:
      print("Name        : %s" % func_name)
      print("Prototype   : %s" % prototype)
      print("Prototype2  : %s" % prototype2)
      print("Conditionals: %d" % conditions)
      print("Constants   : %d" % len(constants))
      print("Switches    : %d" % len(switches))
      print("Calls       : %s" % len(calls))
      print("Callees     : %s" % len(callees))
      print("Loops       : %d" % loops)
      print("Globals     : %d" % len(externals))
      print("Recursive   : %d" % recursive)
      print("Indirects   : %d" % indirects)
      print("Global uses : %d" % len(globals_uses))
      print()

    cur = self.db.cursor()
    sql = """insert into functions(
                         ea, name, prototype, prototype2, conditions,
                         constants, constants_json, loops, switchs,
                         switchs_json, calls, externals, recursive,
                         indirects, globals, callees_json
                         )
                         values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"""
    args = (str(f), func_name, prototype, prototype2, conditions,
            len(constants), json_dump(list(constants)), loops, len(switches),
            json_dump(list(switches)), len(calls), len(list(externals)),
            recursive, int(indirects), len(globals_uses),
            json_dump(callees))
    cur.execute(sql, args)
    rowid = cur.lastrowid

    sql = "insert into callgraph (caller, callee) values (?, ?)"
    for callee in calls:
      cur.execute(sql, (str(f), str(callee)))

    sql = "insert into constants (func_id, constant) values (?, ?)"
    for constant in constants:
      if type(constant) is str and len(constant) > 4:
        cur.execute(sql, (rowid, constant))

    cur.close()
Esempio n. 2
0
    def calculate(self, f):
        func = get_func(f)
        if func is None:
            return "NO-FUNCTION"

        flow = FlowChart(func)
        if flow is None:
            return "NO-FLOW-GRAPH"

        hash = 1

        # Variables required for calculations of previous ones
        bb_relations = {}

        # Iterate through each basic block
        for block in flow:
            block_ea = block.startEA
            if block.endEA == 0:
                continue

            succs = list(block.succs())
            preds = list(block.preds())

            hash *= self.get_node_value(len(succs), len(preds))
            hash *= self.get_edges_value(block, succs, preds)

            # ...and each instruction on each basic block
            for ea in list(Heads(block.startEA, block.endEA)):

                if is_call_insn(ea):
                    hash *= FEATURE_CALL

                l = DataRefsFrom(ea)
                hash *= FEATURE_DATA_REFS

                for xref in CodeRefsFrom(ea, 0):
                    tmp_func = get_func(xref)
                    if tmp_func is None or tmp_func.startEA != func.startEA:
                        hash *= FEATURE_CALL_REF

                # Remember the relationships
                bb_relations[block_ea] = []

                # Iterate the succesors of this basic block
                for succ_block in block.succs():
                    bb_relations[block_ea].append(succ_block.startEA)

                # Iterate the predecessors of this basic block
                for pred_block in block.preds():
                    try:
                        bb_relations[pred_block.startEA].append(block.startEA)
                    except KeyError:
                        bb_relations[pred_block.startEA] = [block.startEA]

        # Calculate the strongly connected components
        try:
            strongly_connected = strongly_connected_components(bb_relations)
            # ...and get the number of loops out of it
            for sc in strongly_connected:
                if len(sc) > 1:
                    hash *= FEATURE_LOOP
                else:
                    if sc[0] in bb_relations and sc[0] in bb_relations[sc[0]]:
                        hash *= FEATURE_LOOP

            # And, also, use the number of strongly connected components
            # to calculate another part of the hash.
            hash *= (FEATURE_STRONGLY_CONNECTED**len(strongly_connected))
        except:
            print("Exception:", str(sys.exc_info()[1]))

        flags = GetFunctionFlags(f)
        if flags & FUNC_NORET:
            hash *= FEATURE_FUNC_NO_RET
        if flags & FUNC_LIB:
            hash *= FEATURE_FUNC_LIB
        if flags & FUNC_THUNK:
            hash *= FEATURE_FUNC_THUNK

        return str(hash)