def static_exits(self, blocks): # Execute those blocks with a blank state, and then dump the arguments blank_state = simuvex.SimState(arch=self.arch, mode="fastpath") # Execute each block state = blank_state for b in blocks: irsb = simuvex.SimEngineVEX().process( state, b, force_addr=next( iter(stmt for stmt in b.statements if isinstance(stmt, pyvex.IRStmt.IMark))).addr) if irsb.successors: state = irsb.successors[0] else: break cc = simuvex.DefaultCC[self.arch.name](self.arch) callfunc = cc.arg(state, 2) retaddr = state.memory.load(state.regs.sp, self.arch.bytes) all_exits = [(callfunc, 'Ijk_Call'), (retaddr, 'Ijk_Ret')] return all_exits
def resolve(self, cfg, addr, func_addr, block): obj = cfg.project.loader.addr_belongs_to_object(addr) if obj is None: return False, [] got_addr = self._got_addr(obj) if got_addr is None: # cannot get the base address of GOT return False, [] state = cfg._initial_state.copy() state.regs.ebx = got_addr successors = simuvex.SimEngineVEX().process(state, block, force_addr=addr) if len(successors.flat_successors) != 1: return False, [] target = state.se.exactly_int(successors.flat_successors[0].ip) return True, [target]
def test_inspect_exit(): class counts: #pylint:disable=no-init exit_before = 0 exit_after = 0 def handle_exit_before(state): counts.exit_before += 1 exit_target = state.inspect.exit_target nose.tools.assert_equal(state.se.any_int(exit_target), 0x3f8) # change exit target state.inspect.exit_target = 0x41414141 nose.tools.assert_equal(state.inspect.exit_jumpkind, "Ijk_Boring") nose.tools.assert_true(state.inspect.exit_guard.is_true()) def handle_exit_after(state): #pylint:disable=unused-argument counts.exit_after += 1 s = simuvex.SimState(arch="AMD64", mode="symbolic") irsb = pyvex.IRSB("\x90\x90\x90\x90\xeb\x0a", mem_addr=1000, arch=archinfo.ArchAMD64()) # break on exit s.inspect.b('exit', simuvex.BP_BEFORE, action=handle_exit_before) s.inspect.b('exit', simuvex.BP_AFTER, action=handle_exit_after) # step it succ = simuvex.SimEngineVEX().process(s, irsb).flat_successors # check nose.tools.assert_equal( succ[0].se.any_int(succ[0].ip), 0x41414141) nose.tools.assert_equal(counts.exit_before, 1) nose.tools.assert_equal(counts.exit_after, 1)
def static_exits(self, blocks): # Execute those blocks with a blank state, and then dump the arguments blank_state = simuvex.SimState(arch=self.arch, mode="fastpath") # set up the stack pointer blank_state.regs.sp = 0x7fffffff # Execute each block state = blank_state for b in blocks: # state.regs.ip = next(iter(stmt for stmt in b.statements if isinstance(stmt, pyvex.IRStmt.IMark))).addr irsb = simuvex.SimEngineVEX().process( state, b, force_addr=next( iter(stmt for stmt in b.statements if isinstance(stmt, pyvex.IRStmt.IMark))).addr) if irsb.successors: state = irsb.successors[0] else: break cc = simuvex.DefaultCC[self.arch.name](self.arch) args = [cc.arg(state, _) for _ in xrange(5)] main, _, _, init, fini = self._extract_args(blank_state, *args) all_exits = [ (init, 'Ijk_Call'), (main, 'Ijk_Call'), (fini, 'Ijk_Call'), ] return all_exits
def __init__(self, thing, default_analysis_mode=None, ignore_functions=None, use_sim_procedures=True, exclude_sim_procedures_func=None, exclude_sim_procedures_list=(), arch=None, simos=None, load_options=None, translation_cache=True, support_selfmodifying_code=False): """ :param thing: The path to the main executable object to analyze, or a CLE Loader object. The following parameters are optional. :param default_analysis_mode: The mode of analysis to use by default. Defaults to 'symbolic'. :param ignore_functions: A list of function names that, when imported from shared libraries, should never be stepped into in analysis (calls will return an unconstrained value). :param use_sim_procedure: Whether to replace resolved dependencies for which simprocedures are available with said simprocedures. :param exclude_sim_procedures_func: A function that, when passed a function name, returns whether or not to wrap it with a simprocedure. :param exclude_sim_procedures_list: A list of functions to *not* wrap with simprocedures. :param arch: The target architecture (auto-detected otherwise). :param simos: a SimOS class to use for this project. :param load_options: a dict of keyword arguments to the CLE loader. See CLE's docs. :param translation_cache: If True, cache translated basic blocks rather than re-translating them. :param support_selfmodifying_code: Whether we support self-modifying code. When enabled, Project.sim_block() will try to read code from the current state instead of the original memory regions. :type support_selfmodifying_code: bool A sample `load_options` value could be: :: { 'auto_load_libs': False, 'skip_libs': 'ld.so.2', 'lib_opts': { 'libc.so.6': { 'custom_base_addr': 0x55555400 } } } """ # Step 1: Load the binary if load_options is None: load_options = {} if isinstance(thing, cle.Loader): self.loader = thing self.filename = self.loader._main_binary_path elif hasattr(thing, 'read') and hasattr(thing, 'seek'): l.info("Loading binary from stream") self.filename = None self.loader = cle.Loader(thing, **load_options) elif not isinstance( thing, (unicode, str)) or not os.path.exists(thing) or not os.path.isfile(thing): raise Exception("Not a valid binary file: %s" % repr(thing)) else: # use angr's loader, provided by cle l.info("Loading binary %s", thing) self.filename = thing self.loader = cle.Loader(self.filename, **load_options) # Step 2: determine its CPU architecture, ideally falling back to CLE's guess if isinstance(arch, str): self.arch = archinfo.arch_from_id( arch) # may raise ArchError, let the user see this elif isinstance(arch, archinfo.Arch): self.arch = arch elif arch is None: self.arch = self.loader.main_bin.arch else: raise ValueError("Invalid arch specification.") # Step 3: Set some defaults and set the public and private properties if not default_analysis_mode: default_analysis_mode = 'symbolic' if not ignore_functions: ignore_functions = [] if isinstance(exclude_sim_procedures_func, types.LambdaType): l.warning( "Passing a lambda type as the exclude_sim_procedures_func argument to Project causes the resulting object to be un-serializable." ) self._sim_procedures = {} self._default_analysis_mode = default_analysis_mode self._exclude_sim_procedures_func = exclude_sim_procedures_func self._exclude_sim_procedures_list = exclude_sim_procedures_list self._should_use_sim_procedures = use_sim_procedures self._support_selfmodifying_code = support_selfmodifying_code self._ignore_functions = ignore_functions self._extern_obj = AngrExternObject(self.arch) self._extern_obj.provides = 'angr externs' self.loader.add_object(self._extern_obj) self._syscall_obj = AngrExternObject(self.arch) self._syscall_obj.provides = 'angr syscalls' self.loader.add_object(self._syscall_obj) if self._support_selfmodifying_code: if translation_cache is True: translation_cache = False l.warning( "Disabling IRSB translation cache because support for self-modifying code is enabled." ) vex_engine = simuvex.SimEngineVEX( stop_points=self._sim_procedures, use_cache=translation_cache, support_selfmodifying_code=support_selfmodifying_code) procedure_engine = SimEngineHook(self) failure_engine = SimEngineFailure(self) syscall_engine = SimEngineSyscall(self) unicorn_engine = simuvex.SimEngineUnicorn(self._sim_procedures) self.entry = self.loader.main_bin.entry self.factory = AngrObjectFactory(self, vex_engine, procedure_engine, [ failure_engine, syscall_engine, procedure_engine, unicorn_engine, vex_engine ]) self.analyses = Analyses(self) self.surveyors = Surveyors(self) self.kb = KnowledgeBase(self, self.loader.main_bin) if self.filename is not None: projects[self.filename] = self # Step 5: determine the host OS and perform additional initialization # in the SimOS constructor if isinstance(simos, type) and issubclass(simos, SimOS): self._simos = simos(self) #pylint:disable=invalid-name elif simos is None: self._simos = os_mapping[self.loader.main_bin.os](self) else: raise ValueError( "Invalid OS specification or non-matching architecture.") # Step 4: Register simprocedures as appropriate for library functions self._use_sim_procedures() self._simos.configure_project()
def test_inspect(): class counts: #pylint:disable=no-init mem_read = 0 mem_write = 0 reg_read = 0 reg_write = 0 tmp_read = 0 tmp_write = 0 expr = 0 statement = 0 instruction = 0 constraints = 0 variables = 0 def act_mem_read(state): #pylint:disable=unused-argument counts.mem_read += 1 def act_mem_write(state): #pylint:disable=unused-argument counts.mem_write += 1 def act_reg_read(state): #pylint:disable=unused-argument counts.reg_read += 1 def act_reg_write(state): #pylint:disable=unused-argument counts.reg_write += 1 def act_tmp_read(state): #pylint:disable=unused-argument counts.tmp_read += 1 def act_tmp_write(state): #pylint:disable=unused-argument counts.tmp_write += 1 def act_expr(state): #pylint:disable=unused-argument counts.expr += 1 def act_statement(state): #pylint:disable=unused-argument counts.statement += 1 def act_instruction(state): #pylint:disable=unused-argument counts.instruction += 1 def act_variables(state): #pylint:disable=unused-argument #print "CREATING:", state.inspect.symbolic_name counts.variables += 1 # def act_constraints(state): #pylint:disable=unused-argument # counts.constraints += 1 s = simuvex.SimState(arch="AMD64", mode="symbolic") s.inspect.b('mem_write', when=simuvex.BP_AFTER, action=act_mem_write) nose.tools.assert_equals(counts.mem_write, 0) s.memory.store(100, s.se.BVV(10, 32)) nose.tools.assert_equals(counts.mem_write, 1) s.inspect.b('mem_read', when=simuvex.BP_AFTER, action=act_mem_read) s.inspect.b('mem_read', when=simuvex.BP_AFTER, action=act_mem_read, mem_read_address=100) s.inspect.b('mem_read', when=simuvex.BP_AFTER, action=act_mem_read, mem_read_address=123) s.inspect.b('mem_read', when=simuvex.BP_BEFORE, action=act_mem_read, mem_read_length=3) nose.tools.assert_equals(counts.mem_read, 0) s.memory.load(123, 4) s.memory.load(223, 3) nose.tools.assert_equals(counts.mem_read, 4) s.inspect.b('reg_read', when=simuvex.BP_AFTER, action=act_reg_read) nose.tools.assert_equals(counts.reg_read, 0) s.registers.load(16) nose.tools.assert_equals(counts.reg_read, 1) s.inspect.b('reg_write', when=simuvex.BP_AFTER, action=act_reg_write) nose.tools.assert_equals(counts.reg_write, 0) s.registers.store(16, s.se.BVV(10, 32)) nose.tools.assert_equals(counts.reg_write, 1) nose.tools.assert_equals(counts.mem_write, 1) nose.tools.assert_equals(counts.mem_read, 4) nose.tools.assert_equals(counts.reg_read, 1) s.inspect.b('tmp_read', when=simuvex.BP_AFTER, action=act_tmp_read, tmp_read_num=0) s.inspect.b('tmp_write', when=simuvex.BP_AFTER, action=act_tmp_write, tmp_write_num=0) s.inspect.b('expr', when=simuvex.BP_AFTER, action=act_expr, expr=1016, expr_unique=False) s.inspect.b('statement', when=simuvex.BP_AFTER, action=act_statement) s.inspect.b('instruction', when=simuvex.BP_AFTER, action=act_instruction, instruction=1001) s.inspect.b('instruction', when=simuvex.BP_AFTER, action=act_instruction, instruction=1000) irsb = pyvex.IRSB("\x90\x90\x90\x90\xeb\x0a", mem_addr=1000, arch=archinfo.ArchAMD64(), opt_level=0) irsb.pp() simuvex.SimEngineVEX().process(s, irsb) nose.tools.assert_equals(counts.reg_write, 7) nose.tools.assert_equals(counts.reg_read, 2) nose.tools.assert_equals(counts.tmp_write, 1) nose.tools.assert_equals(counts.tmp_read, 1) nose.tools.assert_equals(counts.expr, 3) # one for the Put, one for the WrTmp, and one to get the next address to jump to nose.tools.assert_equals(counts.statement, 11) nose.tools.assert_equals(counts.instruction, 2) nose.tools.assert_equals(counts.constraints, 0) nose.tools.assert_equals(counts.mem_write, 1) nose.tools.assert_equals(counts.mem_read, 4) s = simuvex.SimState(arch="AMD64", mode="symbolic") s.inspect.b('symbolic_variable', when=simuvex.BP_AFTER, action=act_variables) s.memory.load(0, 10) nose.tools.assert_equals(counts.variables, 1)