def locate_transfer(vm, name): """Using specific parameters to locate transfer function. Args: vm: virtual machine includes all env information name: the name of contract Returns: """ if global_vars.apply_function_address is None: return # check whether the type is valid transfer type apply_func_type = structure.FunctionType() apply_func_type.args = bytearray([bin_format.i64, bin_format.i64, bin_format.i64]) apply_func_type.rets = bytearray() apply_func = vm.store.funcs[vm.module_instance.funcaddrs[global_vars.apply_function_address]] global_vars.locate() if apply_func.functype == apply_func_type: params = [utils.eos_abi_to_int(name), utils.eos_abi_to_int('eosio.token'), utils.eos_abi_to_int('transfer')] global_vars.locate() try: vm.exec_by_address(global_vars.apply_function_address, params) except AssertionError as e: logger.println(f'unreachable transfer: {e}') except SystemExit as e: logger.debugln(f'transfer found') global_vars.sym_exec()
def detect_fake_eos(vm, name) -> None: """Fake eos transfer vulnerability analysis function. Args: name: the name of current contract vm: WebAssembly module execution environment Returns: """ if global_vars.apply_function_address is None: return global_vars.fake_detect() # set flag for fake detection func_type = structure.FunctionType() func_type.args = bytearray( [bin_format.i64, bin_format.i64, bin_format.i64]) func_type.rets = bytearray() apply_func = vm.store.funcs[vm.module_instance.funcaddrs[ global_vars.apply_function_address]] global_vars.fake_detect() if apply_func.functype == func_type: params = utils.gen_symbolic_args(apply_func) global_vars.apply_params = params params[0] = utils.eos_abi_to_int(name) params[2] = utils.eos_abi_to_int('transfer') init_constraints = [ params[0] != params[1], params[1] != utils.eos_abi_to_int('eosio.token') ] vm.exec_by_address(global_vars.apply_function_address, params, init_constraints) global_vars.sym_exec() # set the detection mode to False
def fake_eos_analysis(store, frame, stack, expr, pc, solver=None): global_vars.pc = pc transfer_int64 = utils.eos_abi_to_int('transfer') action_param = 2 end = len(expr.data) if _check_n_call(expr, pc): local_number = expr.data[pc + 7].immediate_arguments frame.locals[local_number] = Value.from_i64( _get_encoding(expr.data[pc + 4].immediate_arguments)) pc = expr.composition[pc + 8][-1] elif expr.data[pc].code == bin_format.call and expr.data[ pc].immediate_arguments in global_vars.eosio_assert_addrs: cond = stack.data[-2].n if utils.is_all_real(cond): if not cond: pc = end else: solver.push() solver.add(z3.simplify(cond == 1)) if utils.check_sat(solver) == z3.unsat: pc = end solver.pop() elif ((expr.data[pc].code == bin_format.get_local and expr.data[pc].immediate_arguments == action_param and expr.data[pc + 1].code == bin_format.i64_const and expr.data[pc + 1].immediate_arguments == transfer_int64) or (expr.data[pc].code == bin_format.i64_const and expr.data[pc].immediate_arguments == transfer_int64 and expr.data[pc + 1].code == bin_format.get_local and expr.data[pc + 1].immediate_arguments == action_param)): if (expr.data[pc + 2].code in (bin_format.i64_eq, bin_format.i64_ne) and expr.data[pc + 3].code == bin_format.br_if): transfer_block_pc = (_get_branch_pc( expr.data[pc + 3].immediate_arguments, stack) if expr.data[pc + 2].code == bin_format.i64_eq else pc + 4) for i in range(transfer_block_pc, end - 2): if (expr.data[i].code == bin_format.call and expr.data[i + 1].code == bin_format.drop and expr.data[i + 2].code in (bin_format.br, bin_format.end)): global_vars.find_fake_eos_transfer() if expr.data[i].code not in (bin_format.get_local, bin_format.i32_const, bin_format.i32_store, bin_format.i64_load, bin_format.i64_store, bin_format.i32_add): break global_vars.pc = pc
def _get_encoding(data_index: int) -> int: string = global_vars.data_addr_dict[data_index] return utils.eos_abi_to_int(string)
def set_name_int64(self, name): self.contract_name_int64 = utils.eos_abi_to_int(name)