def sprintf(p, core_taint, plt_path, *_, **__): """ sprintf function summary :param p: angr project :param core_taint: core taint engine :param plt_path: path to the plt entry :return: None """ plt_state = plt_path.active[0] if are_parameters_in_registers(p): frmt_str = getattr(plt_state.regs, arg_reg_name(p, 1)) str_val = get_string(p, frmt_str.args[0], extended=True) n_vargs = str_val.count('%s') for i in range(2, 2 + n_vargs): name = p.arch.register_names[ordered_argument_regs[p.arch.name][i]] reg = getattr(plt_state.regs, name) if (core_taint.is_tainted(reg, path=plt_path) or core_taint.is_tainted( core_taint.safe_load(plt_path, reg), path=plt_path)): return True return False else: raise Exception("implement me")
def _search_data_key_in_bb(self, p, b, caller_node, data_key): """ Searches if a data key in a basic block :param p: angr project :param b: binary name :param caller_node: basic block of a caller node :param data_key: data key to search for :return: True if the data key is in the basic block """ found = False c = caller_node block = p.factory.block(c.addr) # consider the constants in the calling block for con in block.vex.all_constants: val = con.value # check if a string c_string = get_string(p, val) self._binaries_strings[b].append(c_string) if c_string and c_string == data_key: found = True return found
def _search_in_bb(self, caller_node, role_function_info): """ Search for a data key in the passed basic block. :param caller_node: node calling the role function :param role_function_info: role function info :return: """ p = self._p c = caller_node block = p.factory.block(c.addr) # consider the constants in the calling block for con in block.vex.all_constants: val = con.value # check if a string c_string = get_string(p, val) if c_string: if val not in self._role_info: self._role_info[val] = [] new_role_info = dict(role_function_info) new_role_info[RoleInfo.DATAKEY] = c_string new_role_info[RoleInfo.X_REF_FUN] = c.function_address new_role_info[RoleInfo.CALLER_BB] = c.addr new_role_info[RoleInfo.CPF] = self._name if new_role_info not in self._role_info[val]: self._role_info[val].append(new_role_info)
def _run_def_use(self, caller_node, role_function_info): """ Run def-use analysis to find the data-key :param caller_node: node calling an environment function :param role_function_info: role function info :return: None """ if not self._normalized_cfg: self._normalized_cfg = self._p.analyses.CFG(normalize=True) p = self._p cfg = self._normalized_cfg c = caller_node # Reaching definition analysis fun = cfg.functions.function(caller_node.function_address) t = (caller_node.instruction_addrs[-1], angr.analyses.reaching_definitions.OP_AFTER) rd = p.analyses.ReachingDefinitions(func=fun, observation_points=[t,], init_func=True) try: results = rd.observed_results[t] except TimeOutException: raise except: return if are_parameters_in_registers(p): idx = role_function_info[RoleInfo.PAR_N] reg_off = ordered_argument_regs[p.arch.name][idx] for r_def in results.register_definitions.get_objects_by_offset(reg_off): for val in r_def.data.data: if type(val) == angr.analyses.reaching_definitions.undefined.Undefined: continue if type(val) not in (int, long): print("Data value is not what expected. Check me...") continue c_string = get_string(p, val) if c_string: if val not in self._role_info: self._role_info[val] = [] new_role_info = dict(role_function_info) new_role_info[RoleInfo.DATAKEY] = c_string new_role_info[RoleInfo.X_REF_FUN] = c.function_address new_role_info[RoleInfo.CALLER_BB] = c.addr new_role_info[RoleInfo.CPF] = self._name if new_role_info not in self._role_info[val]: self._role_info[val].append(new_role_info) role = self._roles[0] self._roles.append(role) self._data_keys.append(c_string) self._name_funs.append(c.successors[0].name) else: raise Exception("Envirnoment cpf: Parameters not in registers, implement me")
def _search_data_key_in_bb(self, p, b, caller_node, data_key): """ Finds if the given data key is within the calling basic block. :param p: angr project :param b: binary :param caller_node: calling basic block :param data_key: data key value :return: True if found, False otherwise """ found = False c = caller_node block = p.factory.block(c.addr) # consider the constants in the calling block for con in block.vex.all_constants: val = con.value # check if a string c_string = get_string(p, val) self._binaries_strings[b].append(c_string) if c_string and c_string == data_key: found = True return found
def _inet_pton(self, ct, caller_path, plt_path): """ inet_pton summary :param ct: core taint engine :param caller_path: angr path leading to the inet_path :param plt_path: angr path leading to the plt entry of inet_pton :return: """ p = ct.p new_state = plt_path.active[0] old_state = caller_path.active[0] # move data key from argument to destination addr addr_reg = ordered_argument_regs[p.arch.name][1] dst_reg = ordered_argument_regs[p.arch.name][2] addr_str = getattr(plt_path.active[0].regs, p.arch.register_names[addr_reg]) cnt_str = get_string(p, addr_str.args[0], extended=True) # do the inet_pton conversion. # this is not exactly the conversion the inet_pton does, it's a trick we use to keep track of the addresses inet_pton_convesions[self._pton_counter] = cnt_str bits = p.arch.bits to_store = claripy.BVV(self._pton_counter, bits) self._pton_counter += 1 # store it! dst_mem = getattr(plt_path.active[0].regs, p.arch.register_names[dst_reg]) new_state.memory.store(dst_mem, to_store) # restore registers to return from the function call lr = p.arch.register_names[link_regs[p.arch.name]] ret_addr = getattr(new_state.regs, lr) ret_func = getattr(old_state.regs, lr) plt_path.active[0].ip = ret_addr setattr(plt_path.active[0].regs, lr, ret_func) plt_path.active[0].history.jumpkind = "Ijk_FakeRet"
def _search_in_bb(self, caller_node, role_function_info): """ Finds whether the data-key is the called basic block. As we know the protype of nvram functions, if there's a string within the basic block, that's our data key. :param caller_node: caller basic block :param role_function_info: role function info :return: None """ p = self._p c = caller_node block = p.factory.block(c.addr) # consider the constants in the calling block for con in block.vex.all_constants: val = con.value # check if a string c_string = get_string(p, val) if c_string: if val not in self._role_info: self._role_info[val] = [] new_role_info = dict(role_function_info) new_role_info[RoleInfo.DATAKEY] = c_string new_role_info[RoleInfo.X_REF_FUN] = c.function_address new_role_info[RoleInfo.CALLER_BB] = c.addr new_role_info[RoleInfo.CPF] = self._name if new_role_info not in self._role_info[val]: self._role_info[val].append(new_role_info) role = self._roles[0] self._roles.append(role) self._data_keys.append(c_string) self._name_funs.append(c.successors[0].name)
def _save_file_name(self, current_path, guards_info, *_, **__): """ Save and apply taint to the open function :param current_path: angr current path :param guards_info: guards info :return: None """ if not self._ct.taint_applied: # first get the address of the filename next_path = current_path.copy(copy_states=True).step() name_reg = self._p.arch.register_names[ordered_argument_regs[ self._p.arch.name][0]] addr = getattr(next_path.active[0].regs, name_reg) if addr.concrete: self._last_file_name = get_string(self._p, addr.args[0], extended=True) self._ct.apply_taint(current_path, addr, "filename") self._ct.apply_taint(current_path, self._current_key_addr, "key_str") self._check_func(current_path, guards_info, *_, **__)