def exec_by_address(self, address: int, args: typing.List, init_constraints: typing.List = ()): """Executing a function depends on its address. Args: address: the address of function of store. args: the parameters. init_constraints: initial constraints for symbolic execution. Returns: r: the result. """ # Invoke a function denoted by the function address with the provided arguments. func = self.store.funcs[self.module_instance.funcaddrs[address]] if not isinstance(func, WasmFunc): return None # Mapping check for Python val-type to WebAssembly val-type. for i, e in enumerate(func.functype.args): if e in [bin_format.i32, bin_format.i64]: assert isinstance(args[i], int) or isinstance(args[i], z3.BitVecRef) if e in [bin_format.f32, bin_format.f64]: assert isinstance(args[i], float) or isinstance(args[i], z3.FPRef) args[i] = sym_exec.Value(e, args[i]) stack = sym_exec.Stack() stack.ext(args) logger.infoln(f'Running function address {address}({", ".join([str(e) for e in args])}):') r = sym_exec.call(self.module_instance, address, self.store, stack, init_constraints) if r: return r return None
def __init__(self, module: structure.Module, imps: typing.Dict = None): """Initilize Runtime object. Args: module: constructed by reading WASM file and simply store the content. imps: a dict, the key is the import name and the value is the pointer Returns: Runtime: instance of Runtime class. """ self.module = module self.module_instance = sym_exec.ModuleInstance() self.store = sym_exec.Store() imps = imps if imps else {} externvals = [] for e in self.module.imports: if e.kind == bin_format.extern_func: # The two if branch is used to detect the possibility of random vulnerability. # If the "tapos_block_num" is called while "send_inline"/"send_deferred" is related # and called, it could be considered a bug. if ((e.module in ('env',) and e.name in ('tapos_block_num', 'tapos_block_prefix')) or (e.module in ('ethereum',) and e.name in ('getBlockNumber', 'getBlockHash', 'getBlockTimestamp'))): global_vars.add_tapos_block_function_addr(len(self.store.funcs)) if (e.module in ('env',) and e.name in ('send_inline', 'send_deferred') or e.module in ('ethereum',) and e.name in ('call',)): # current version does not include 'callCode', 'callDelegate', 'callStatic' global_vars.add_send_token_function_addr(len(self.store.funcs)) if e.module in ('env',) and e.name in ('eosio_assert',): global_vars.eosio_assert_addrs.add(len(self.store.funcs)) if e.module in ('env',) and e.name in ('action_data_size',): global_vars.action_data_size_addrs.add(len(self.store.funcs)) if e.module in ('env',) and e.name in ('read_action_data',): global_vars.read_action_data_addrs.add(len(self.store.funcs)) if e.module in ('ethereum',) and e.name in ('callDelegate',): global_vars.add_call_delegate_addr(len(self.store.funcs)) if e.module in ('ethereum',) and e.name in ('getCallValue',): global_vars.add_get_call_value_addr(len(self.store.funcs)) if e.module in ('ethereum',) and e.name in ('revert',): global_vars.add_revert_addr(len(self.store.funcs)) a = sym_exec.HostFunc(self.module.types[e.desc], None) self.store.funcs.append(a) externvals.append(sym_exec.ExternValue(e.kind, len(self.store.funcs) - 1)) continue if e.kind == bin_format.extern_table: a = None self.store.tables.append(a) externvals.append(sym_exec.ExternValue(e.kind, len(self.store.tables) - 1)) continue if e.kind == bin_format.extern_mem: a = None self.store.mems.append(a) externvals.append(sym_exec.ExternValue(e.kind, len(self.store.mems) - 1)) continue if e.kind == bin_format.extern_global: a = sym_exec.GlobalInstance(sym_exec.Value(e.desc.valtype, None), e.desc.mut) self.store.globals.append(a) externvals.append(sym_exec.ExternValue(e.kind, len(self.store.globals) - 1)) continue self.module_instance.instantiate(self.module, self.store, externvals)