def taintAnalysis(self, item): func = item.func if func.ircfg is None: func.ira = BinaryAnalysis.iraType(func.cfg.loc_db) func.ircfg = func.ira.new_ircfg_from_asmcfg(func.cfg) func.defUse = DiGraphDefUse(ReachingDefinitions(func.ircfg)) current_block = func.ircfg.get_block(item.block.loc_key) index = 0 dstArg = None for index, assignblk in enumerate(current_block): if assignblk.instr.offset == item.address: for dst, src in assignblk.items(): dstArg = dst break queue = [AssignblkNode(item.block.loc_key, index, dstArg)] currentPoint = 0 endPoint = 0 while currentPoint <= endPoint: node = queue[currentPoint] currentPoint += 1 assign = func.ircfg.blocks[node.label][node.index] self.focusAddress(assign.instr.offset, False) for node2 in func.defUse.successors(node): endPoint += 1 queue.append(node2)
def _add_2_control_vars(self, primary_loc_keys, affected_lines, merging_var, done, head_vars): # involve cff loops containing compiler "optimization" introducing 2 control variables( # range(0,x,1) and range(0,x,1*y)); there are multiple due to various compiler anomalies, but # only one from affected_irdsts found = False for disp_loc, last_cff_locs in self.analyses.rev_back_edges.items(): if disp_loc not in primary_loc_keys: continue for last_cff_loc in last_cff_locs: preds = self.asmcfg.predecessors(last_cff_loc) succs = self.asmcfg.successors(last_cff_loc) if not len(succs) > 1 and len(preds) == 1 and last_cff_loc not in affected_lines: last_cff_loc = preds[0] succs = self.asmcfg.successors(last_cff_loc) if last_cff_loc not in primary_loc_keys: if len(succs) > 1: primary_loc_keys.add(last_cff_loc) opti_node = AssignblkNode(last_cff_loc, len(self.ircfg.blocks[last_cff_loc].assignblks) - 1, self.ir_arch.IRDst) self._process_affected_irdsts({opti_node}, affected_lines, primary_loc_keys, merging_var, done, head_vars) if last_cff_loc in primary_loc_keys: # otherwise last_cff_loc couldn't be determined and was removed from primaries found = True if last_cff_loc in affected_lines: found = True else: found = True if not found: raise RuntimeError("There must be a back-edge")
def forwardTaint(self, item): queue = [AssignblkNode(item.block.loc_key, item.index, item.dst)] currentPoint = 0 endPoint = 1 while currentPoint < endPoint: node = queue[currentPoint] self.selectLine(node.label, node.index, node.var) currentPoint += 1 for node2 in self.defUse.successors(node): queue.append(node2) endPoint += 1
def _process_assignment(self, ir_block, ind, dst): assignblk_node = AssignblkNode(ir_block.loc_key, ind, dst) # loop id 0 is the default logger.debug("Processing %s" % hex(self.asmcfg.loc_db.get_location_offset(ir_block.loc_key) or 0)) local_affected_lines = {} affected_irdsts, possible_nodes = self._get_affected_ir_destinations(assignblk_node, local_affected_lines) result = False for node in self.asmcfg.walk_breadth_first_forward(LocKey(0)): if node in possible_nodes: filtered_irdsts = self._filter_sequential_loc_keys(node, affected_irdsts) affected_lines = {} result |= self._create_flattening_loop(node, filtered_irdsts, affected_lines) return result
def backwardTaint(self, item): arg = item.args[self.lastClickIndex] line = self.findAssign(arg) self.selectionModel().select(self.model.indexFromItem(line), QItemSelectionModel.Select) queue = [AssignblkNode(line.block.loc_key, line.index, line.dst)] currentPoint = 0 endPoint = 1 while currentPoint < endPoint: node = queue[currentPoint] if currentPoint != 0: self.selectLine(node.label, node.index, node.var) currentPoint += 1 for node2 in self.defUse.predecessors(node): queue.append(node2) endPoint += 1
def _track_exprs(self, state, assignblk, line_nb): """Track pending expression in an assignblock""" if self.incorrect: return future_pending = {} node_resolved = set() for dst, src in assignblk.items(): assignblk_node = AssignblkNode(state.loc_key, line_nb, dst) # Only track pending if dst not in state.pending: if type(src) in [ExprId, ExprOp, ExprCompose] and any( src in i for i in state.pending): if assignblk_node in self.defuse_edges: # targets function arguments such as lea eax, var; push eax since constant propagation doesn't # work correctly in miasm; https://github.com/cea-sec/miasm/issues/1197; # https://github.com/cea-sec/miasm/issues/1218; https://github.com/cea-sec/miasm/issues/1259; # TODO when constant propagation is fixed, rework this; elaborate on 1259 for assignblk_node in self.defuse_edges[ assignblk_node]: if is_local_variable(assignblk_node.var, self.ir, self.mn) \ and assignblk_node not in self.defuse_edges: break else: continue elif not is_local_variable(dst, self.ir, self.mn): continue if is_push_param(self.recognizer, assignblk_node.label, assignblk_node.index): # prevents FPs in weird code such as push [ebp+var_18]; call ...; add esp, 4 # where [ebp+var_18] is not param and it's just pushed self.incorrect = True return continue # Track IRDst in implicit mode only if dst == self._ircfg.IRDst and not self._implicit: continue assert dst not in node_resolved node_resolved.add(dst) dependencies = self._follow_apply_cb(src) state.link_element(dst, line_nb) state.link_dependencies(dst, line_nb, dependencies, future_pending) # Update pending nodes state.remove_pendings(node_resolved) state.add_pendings(future_pending)
def _recognize(self, max_loop_num): symb_engine = SymbolicExecutionEngine(self.ir_arch, regs.regs_init) todo = [(LocKey(0), symb_engine.get_state())] done_loc = set() if not max_loop_num: max_loop_num = float('inf') found_loops_num = 0 while todo: loc_key, symb_state = todo.pop() if loc_key in done_loc or loc_key not in self.ircfg.blocks: continue done_loc.add(loc_key) ir_block = self.ircfg.blocks[loc_key] symb_engine.set_state(symb_state) for ind, assignblk in enumerate(ir_block.assignblks): for dst, src in assignblk.items(): if max_loop_num < found_loops_num: return if src.is_int() and int(src) in self.func_addresses: assignblk_node = AssignblkNode(ir_block.loc_key, ind, dst) # no uses if assignblk_node not in self.analyses.defuse_edges or not \ self.analyses.defuse_edges[assignblk_node]: # possible virtual table initialization self.possible_merge_funcs.add( (int(src), frozenset(), loc_key)) elif src.is_op("call_func_stack"): self._process_call(src, dst, symb_engine, assignblk, loc_key) elif (expr_simp(src).is_int() and not is_bad_expr(dst)) \ or (ir_block.loc_key == LocKey(0) and dst == src and (not self._merging_var_candidates or dst in self._merging_var_candidates)): if self._process_assignment(ir_block, ind, dst): self._merging_var_candidates = None found_loops_num += 1 symb_engine.eval_updt_assignblk(assignblk) for succ in self.ircfg.successors(loc_key): todo.append((succ, symb_engine.get_state()))