def test_fauxware(): amd64 = archinfo.arch_from_id('amd64') args = { 'i386': [ ('authenticate', SimCCCdecl( archinfo.arch_from_id('i386'), args=[SimStackArg(4, 4), SimStackArg(8, 4)], sp_delta=4, ret_val=SimRegArg('eax', 4), ) ), ], 'x86_64': [ ('authenticate', SimCCSystemVAMD64( amd64, args=[SimRegArg('rdi', 8), SimRegArg('rsi', 8)], sp_delta=8, ret_val=SimRegArg('rax', 8), ) ), ], } for arch, lst in args.items(): yield run_fauxware, arch, lst
def test_no_cross_insn_boundary_opt_amd64(): # 0x4020f8: sub rsp, 8 # 0x4020fc: mov rax, qword ptr [rip + 0x221ef5] # 0x402103: test rax, rax # 0x402106: je 0x40210d b = binascii.unhexlify("4883ec08488b05f51e22004885c07405") p = angr.load_shellcode(b, 'amd64', load_address=0x4020f8) # No optimization block = p.factory.block(0x4020f8, size=len(b), opt_level=0) assert len(block.vex.statements) == 32 # Full level-1 optimization block = p.factory.block(0x4020f8, size=len(b), opt_level=1, cross_insn_opt=True) assert len(block.vex.statements) == 20 # Level-1 optimization within each instruction block = p.factory.block(0x4020f8, size=len(b), opt_level=1, cross_insn_opt=False) stmts = block.vex.statements assert len(stmts) == 25 # 12 | ------ IMark(0x402103, 3, 0) ------ assert isinstance(stmts[12], pyvex.IRStmt.IMark) assert stmts[12].addr == 0x402103 # 13 | t6 = GET:I64(rax) assert isinstance(stmts[13], pyvex.IRStmt.WrTmp) assert isinstance(stmts[13].data, pyvex.IRExpr.Get) assert stmts[13].data.offset == archinfo.arch_from_id( 'amd64').registers['rax'][0] # 14 | PUT(cc_op) = 0x0000000000000014 assert isinstance(stmts[14], pyvex.IRStmt.Put) assert stmts[14].offset == archinfo.arch_from_id( 'amd64').registers['cc_op'][0] assert isinstance(stmts[14].data, pyvex.IRExpr.Const) assert stmts[14].data.con.value == 0x14 # 15 | PUT(cc_dep1) = t6 assert isinstance(stmts[15], pyvex.IRStmt.Put) assert stmts[15].offset == archinfo.arch_from_id( 'amd64').registers['cc_dep1'][0] # 16 | PUT(cc_dep2) = 0x0000000000000000 assert isinstance(stmts[16], pyvex.IRStmt.Put) assert stmts[16].offset == archinfo.arch_from_id( 'amd64').registers['cc_dep2'][0] assert isinstance(stmts[16].data, pyvex.IRExpr.Const) assert stmts[16].data.con.value == 0 # 17 | PUT(rip) = 0x0000000000402106 assert isinstance(stmts[17], pyvex.IRStmt.Put) assert stmts[17].offset == archinfo.arch_from_id( 'amd64').registers['rip'][0] assert isinstance(stmts[17].data, pyvex.IRExpr.Const) assert stmts[17].data.con.value == 0x402106 # 18 | ------ IMark(0x402106, 2, 0) ------ assert isinstance(stmts[18], pyvex.IRStmt.IMark) assert stmts[18].addr == 0x402106
def test_fauxware(): amd64 = archinfo.arch_from_id("amd64") args = { 'i386': [ ('authenticate', SimCCCdecl(archinfo.arch_from_id('i386'), )), ], 'x86_64': [ ('authenticate', SimCCSystemVAMD64(amd64, )), ], } for arch, lst in args.items(): yield run_fauxware, arch, lst
def compare_arch(arch_0: str, arch_1: str) -> bool: if arch_0 == arch_1: # fast path return True try: import archinfo except ImportError: _l.warning( "archinfo is not installed. Fall back to exact matching.") return arch_0 == arch_1 arch0 = archinfo.arch_from_id(arch_0) arch1 = archinfo.arch_from_id(arch_1) return arch0.name == arch1.name and arch0.memory_endness == arch1.memory_endness
def test_arg_locs_array(self): arch = archinfo.arch_from_id("amd64") cc = SimCCSystemVAMD64(arch) proto = SimTypeFunction([SimTypeFixedSizeArray(SimTypeInt().with_arch(arch), 2).with_arch(arch)], None) # It should not raise any exception! cc.arg_locs(proto)
def from_string(data, log_level=logging.WARNING, address_offset=None, bad_bytes=None, filter_func=None): gadgets_dict = pickle.loads(data) gadgets_list = [ item for sublist in gadgets_dict.values() for item in sublist ] # Flatten list of lists # Turn the names of the arch back into archinfo classes (Which aren't pickle-able) for gadget in gadgets_list: gadget.arch = archinfo.arch_from_id(gadget.arch) # Filter the gadgets if necessary if filter_func != None: gadgets_list = filter_func(gadgets_list) gl = GadgetList(gadgets_list, log_level) if address_offset != None: gl.adjust_base_address(address_offset) if bad_bytes != None: just_good_gadgets = GadgetList(log_level=log_level, bad_bytes=bad_bytes) for gadget in gl.foreach(): if not gadget.has_bad_address(bad_bytes): just_good_gadgets.add_gadget(gadget) gl = just_good_gadgets return gl
def load_shellcode(shellcode, arch, start_offset=0, load_address=0, thumb=False, **kwargs): """ Load a new project based on a snippet of assembly or bytecode. :param shellcode: The data to load, as either a bytestring of instructions or a string of assembly text :param arch: The name of the arch to use, or an archinfo class :param start_offset: The offset into the data to start analysis (default 0) :param load_address: The address to place the data in memory (default 0) :param thumb: Whether this is ARM Thumb shellcode """ if not isinstance(arch, archinfo.Arch): arch = archinfo.arch_from_id(arch) if type(shellcode) is str: shellcode = arch.asm(shellcode, load_address, thumb=thumb) if thumb: start_offset |= 1 return Project( BytesIO(shellcode), main_opts={ 'backend': 'blob', 'arch': arch, 'entry_point': start_offset, 'base_addr': load_address, }, **kwargs )
def __init__(self, *args, **kwargs): if Xbe is None: raise CLEError( "Run `pip install pyxbe==0.0.2` to support loading XBE files") super().__init__(*args, **kwargs) self.set_arch(archinfo.arch_from_id('x86')) self.os = 'xbox' if self.binary is None: self._xbe = Xbe(data=self._binary_stream.read()) else: self._xbe = Xbe.from_file(self.binary) self._entry = self._xbe.entry_addr self._image_vmem = bytearray(self._xbe.header.image_size) self._min_addr = self._xbe.header.base_addr self._max_addr = self._xbe.header.base_addr + self._xbe.header.image_size - 1 # Add header self._add_xbe_section(0, self._xbe.header.image_header_size, self._xbe.header.base_addr, self._xbe.header.image_header_size, self._xbe.header_data) # Add each section for _, sec in self._xbe.sections.items(): self._add_xbe_section(sec.header.raw_addr, sec.header.raw_size, sec.header.virtual_addr, sec.header.virtual_size, sec.data, sec) self.memory.add_backer(0, bytes(self._image_vmem)) self.mapped_base = self.linked_base = self._xbe.header.base_addr
def test_skipstmts_toomanyexits(): # https://github.com/angr/pyvex/issues/153 old_exit_limit = IRSB.MAX_EXITS IRSB.MAX_EXITS = 32 bytes_ = bytes.fromhex( "0DF1B00B2EAB94E8030008938BE803000DF1C0089AE8030083E80300019B0DF1F00A339AE669E26193E8030085E8030098E8030083E80300069B95E8030088E80300A26993E803004A92002363622362A361E362A36238AC029A069484E8030012AC0998299328932B9303C885E8030092E8030084E803009AE8030082E803002A460A9D26993E910B9941910D9942910C992A93409548AD439194E803008AE8030027983F9927913F909BE803000DF5887B269335938BE803000DF58C7B089903C98BE8030098E8030084E8030095E8030088E803004B993391329394E80300349337933693069C059B4C93049B4E9350ABCDF834C1CDF83CE185E8030094E803004B9683E8030015A94498C4F7E2EA" ) arch = archinfo.arch_from_id("ARMEL") # Lifting the first four bytes will not cause any problem. Statements should be skipped as expected b = IRSB(bytes_[:34], 0xC6951, arch, opt_level=1, bytes_offset=5, skip_stmts=True) nose.tools.assert_greater(len(b.exit_statements), 0) nose.tools.assert_false(b.has_statements, None) # Lifting the entire block will cause the number of exit statements go beyond the limit (currently 32). PyVEX will # automatically relift this block without skipping the statements b = IRSB(bytes_, 0xC6951, arch, opt_level=1, bytes_offset=5, skip_stmts=True) nose.tools.assert_is_not(b.statements, None) nose.tools.assert_greater(len(b.exit_statements), 32) # Restore the setting IRSB.MAX_EXITS = old_exit_limit
def test_simplify_dead_assign_1(): # if a register is used ever, it should not be simplified away arch = archinfo.arch_from_id('AMD64') block = ailment.Block(0x1337, 10) n = count(start=1) important = 0x999 block.statements.extend([ ailment.Assignment( next(n), ailment.Register(next(n), None, arch.registers['rdi'][0], 64), ailment.Const(next(n), None, 0x13371337, 64), ins_addr=0x1337, ), # rdi = 0x13371337 ailment.Stmt.Call( important, ailment.Const(next(n), None, 0x400080, 64), ins_addr=0x1338, ), # Call(0x400080), which uses rdi but also overwrites rdi (since it is a caller-saved argument) ]) b = block_simplify(block) nose.tools.assert_equal(len(b.statements), 2) nose.tools.assert_equal(b.statements[0].idx, 1) nose.tools.assert_equal(b.statements[1].idx, important)
def test_inspect_syscall(): class counts: #pylint:disable=no-init exit_before = 0 exit_after = 0 def handle_syscall_before(state): counts.exit_before += 1 syscall_name = state.inspect.syscall_name nose.tools.assert_equal(syscall_name, "close") def handle_syscall_after(state): counts.exit_after += 1 syscall_name = state.inspect.syscall_name nose.tools.assert_equal(syscall_name, "close") s = simuvex.SimState(arch="AMD64", mode="symbolic") # set up to call so syscall close s.regs.rax = 3 s.regs.rdi = 2 # break on syscall s.inspect.b('syscall', simuvex.BP_BEFORE, action=handle_syscall_before) s.inspect.b('syscall', simuvex.BP_AFTER, action=handle_syscall_after) # step it proc = simuvex.SimProcedures['syscalls']['close'](s.se.any_int(s.ip), archinfo.arch_from_id('AMD64')) simuvex.SimEngineProcedure().process(s, proc, ret_to=s.ip) # check counts nose.tools.assert_equal(counts.exit_before, 1) nose.tools.assert_equal(counts.exit_after, 1)
def __init__(self, *args, **kwargs): super(PE, self).__init__(*args, **kwargs) self._pe = pefile.PE(self.binary) if self.arch is None: self.set_arch(archinfo.arch_from_id(pefile.MACHINE_TYPE[self._pe.FILE_HEADER.Machine])) self.requested_base = self._pe.OPTIONAL_HEADER.ImageBase self._entry = self._pe.OPTIONAL_HEADER.AddressOfEntryPoint if hasattr(self._pe, "DIRECTORY_ENTRY_IMPORT"): self.deps = [entry.dll for entry in self._pe.DIRECTORY_ENTRY_IMPORT] else: self.deps = [] self.provides = os.path.basename(self.binary) if not self.provides.endswith(".dll"): self.provides = None self._exports = {} self._handle_imports() self._handle_exports() self._register_sections() self.linking = "dynamic" if len(self.deps) > 0 else "static" self.jmprel = self._get_jmprel() self.memory.add_backer(0, self._pe.get_memory_mapped_image()) l.warning("The PE module is not well-supported. Good luck!")
def __init__(self, path, **kwargs): super().__init__(path, **kwargs) self.set_arch(archinfo.arch_from_id('x86')) self.os = 'xbox' if self.binary is None: self._xbe = Xbe(data=self.binary_stream.read()) else: self._xbe = Xbe.from_file(path) self._entry = self._xbe.entry_addr self._image_vmem = bytearray(self._xbe.header.image_size) self._min_addr = self._xbe.header.base_addr self._max_addr = self._xbe.header.base_addr + self._xbe.header.image_size # Add header self._add_xbe_section( 0, self._xbe.header.image_header_size, self._xbe.header.base_addr, self._xbe.header.image_header_size, self._xbe.header_data) # Add each section for _, sec in self._xbe.sections.items(): self._add_xbe_section( sec.header.raw_addr, sec.header.raw_size, sec.header.virtual_addr, sec.header.virtual_size, sec.data, sec) self.memory.add_backer(0, bytes(self._image_vmem)) self.mapped_base = self.linked_base = self._xbe.header.base_addr
def __init__(self, *args, **kwargs): super(PE, self).__init__(*args, **kwargs) self._pe = pefile.PE(self.binary) if self.arch is None: self.set_arch( archinfo.arch_from_id( pefile.MACHINE_TYPE[self._pe.FILE_HEADER.Machine])) self.requested_base = self._pe.OPTIONAL_HEADER.ImageBase self._entry = self._pe.OPTIONAL_HEADER.AddressOfEntryPoint if hasattr(self._pe, 'DIRECTORY_ENTRY_IMPORT'): self.deps = [ entry.dll for entry in self._pe.DIRECTORY_ENTRY_IMPORT ] else: self.deps = [] self.soname = os.path.basename(self.binary) if not self.soname.endswith('.dll'): self.soname = None self._exports = {} self._handle_imports() self._handle_exports() self.linking = 'dynamic' if len(self.deps) > 0 else 'static' self.jmprel = self._get_jmprel() self.memory.add_backer(0, self._pe.get_memory_mapped_image()) l.warning('The PE module is not well, supported. Good luck!')
def __init__(self, arch="AMD64", plugins=None, memory_backer=None, permissions_backer=None, mode=None, options=None, add_options=None, remove_options=None, special_memory_filler=None): # the architecture is used for function simulations (autorets) and the bitness if isinstance(arch, str): self.arch = arch_from_id(arch) else: self.arch = arch # the options if options is None: if mode is None: l.warning("SimState defaulting to symbolic mode.") mode = "symbolic" options = o.modes[mode] options = set(options) if add_options is not None: options |= add_options if remove_options is not None: options -= remove_options self.options = options self.mode = mode # plugins self.plugins = { } if plugins is not None: for n,p in plugins.iteritems(): self.register_plugin(n, p) if not self.has_plugin('memory'): # we don't set the memory endness because, unlike registers, it's hard to understand # which endness the data should be read if o.ABSTRACT_MEMORY in self.options: # We use SimAbstractMemory in static mode # Convert memory_backer into 'global' region if memory_backer is not None: memory_backer = {'global': memory_backer} # TODO: support permissions backer in SimAbstractMemory self.register_plugin('memory', SimAbstractMemory(memory_backer, memory_id="mem")) else: self.register_plugin('memory', SimSymbolicMemory(memory_backer, permissions_backer, memory_id="mem")) if not self.has_plugin('registers'): self.register_plugin('registers', SimSymbolicMemory(memory_id="reg", endness=self.arch.register_endness)) # This is used in static mode as we don't have any constraints there self._satisfiable = True # states are big, so let's give them UUIDs for ANA right away to avoid # extra pickling self.make_uuid() self.uninitialized_access_handler = None self._special_memory_filler = special_memory_filler # this is a global condition, applied to all added constraints, memory reads, etc self._global_condition = None self.ip_constraints = []
def check_compatibility(cls, spec, obj): if hasattr(spec, 'read') and hasattr(spec, 'seek'): pe = pefile.PE(data=spec.read(), fast_load=True) else: pe = pefile.PE(spec, fast_load=True) arch = archinfo.arch_from_id(pefile.MACHINE_TYPE[pe.FILE_HEADER.Machine]) return arch == obj.arch
def test_convert_from_pcode_irsb(self): arch = archinfo.arch_from_id('AMD64') manager = ailment.Manager(arch=arch) p = angr.load_shellcode(self.block_bytes, arch, self.block_addr, self.block_addr, engine=angr.engines.UberEnginePcode) irsb = p.factory.block(self.block_addr).vex ablock = ailment.IRSBConverter.convert(irsb, manager) assert ablock # TODO: test if this conversion is valid
def __init__(self, *args, **kwargs): super(PE, self).__init__(*args, **kwargs) self.segments = self.sections # in a PE, sections and segments have the same meaning self.os = 'windows' if self.binary is None: self._pe = pefile.PE(data=self.binary_stream.read()) elif self.binary in self._pefile_cache: # these objects are not mutated, so they are reusable within a process self._pe = self._pefile_cache[self.binary] else: self._pe = pefile.PE(self.binary) if not self.is_main_bin: # only cache shared libraries, the main binary will not be reused self._pefile_cache[self.binary] = self._pe if self.arch is None: self.set_arch( archinfo.arch_from_id( pefile.MACHINE_TYPE[self._pe.FILE_HEADER.Machine])) self.mapped_base = self.linked_base = self._pe.OPTIONAL_HEADER.ImageBase self._entry = AT.from_rva(self._pe.OPTIONAL_HEADER.AddressOfEntryPoint, self).to_lva() if hasattr(self._pe, 'DIRECTORY_ENTRY_IMPORT'): self.deps = [ entry.dll.lower() for entry in self._pe.DIRECTORY_ENTRY_IMPORT ] else: self.deps = [] if self.binary is not None and not self.is_main_bin: self.provides = os.path.basename(self.binary).lower() else: self.provides = None self.tls_used = False self.tls_data_start = None self.tls_data_size = None self.tls_index_address = None self.tls_callbacks = None self.tls_size_of_zero_fill = None self.tls_module_id = None self.tls_data_pointer = None self._exports = {} self._ordinal_exports = {} self._symbol_cache = self._exports # same thing self._handle_imports() self._handle_exports() self._handle_relocs() self._register_tls() self._register_sections() self.linking = 'dynamic' if self.deps else 'static' self.jmprel = self._get_jmprel() self.memory.add_backer(0, self._pe.get_memory_mapped_image())
def set_default_cc(self, arch_name, cc_cls): """ Set the default calling convention used for this library under a given architecture :param arch_name: The string name of the architecture, i.e. the ``.name`` field from archinfo. :parm cc_cls: The SimCC class (not an instance!) to use """ arch_name = archinfo.arch_from_id(arch_name).name self.default_ccs[arch_name] = cc_cls
def get(self, name, arch): if type(arch) is str: arch = archinfo.arch_from_id(arch) if name in self.procedures: proc = copy.deepcopy(self.procedures[name]) self._apply_metadata(proc, arch) return proc else: return self.get_stub(name, arch)
def extract_arch(reader): arch_str = reader['e_machine'] if arch_str == 'ARM': if reader.header.e_flags & 0x200: return archinfo.ArchARMEL('Iend_LE' if reader.little_endian else 'Iend_BE') elif reader.header.e_flags & 0x400: return archinfo.ArchARMHF('Iend_LE' if reader.little_endian else 'Iend_BE') return archinfo.arch_from_id(arch_str, 'le' if reader.little_endian else 'be', reader.elfclass)
def convert_arch(arch): """ Convert an arch ID or an archinfo.Arch instance to an archinfo.Arch instance. """ if isinstance(arch, str): the_arch = archinfo.arch_from_id(arch) else: the_arch = arch return the_arch
def __init__(self, binary, **kwargs): super(ELF, self).__init__(binary, **kwargs) self.reader = elffile.ELFFile(open(self.binary, 'rb')) # Get an appropriate archinfo.Arch for this binary, unless the user specified one if self.arch is None: if self.reader.header.e_machine == 'EM_ARM' and \ self.reader.header.e_flags & 0x200: self.set_arch(archinfo.ArchARMEL('Iend_LE' if 'LSB' in self.reader.header.e_ident.EI_DATA else 'Iend_BE')) elif self.reader.header.e_machine == 'EM_ARM' and \ self.reader.header.e_flags & 0x400: self.set_arch(archinfo.ArchARMHF('Iend_LE' if 'LSB' in self.reader.header.e_ident.EI_DATA else 'Iend_BE')) else: self.set_arch(archinfo.arch_from_id(self.reader.header.e_machine, self.reader.header.e_ident.EI_DATA, self.reader.header.e_ident.EI_CLASS)) self.strtab = None self.dynsym = None self.hashtable = None self._dynamic = {} self.deps = [] self.rela_type = None self._inits_extracted = False self._preinit_arr = [] self._init_func = None self._init_arr = [] self._fini_func = None self._fini_arr = [] self._symbol_cache = {} self.symbols_by_addr = {} self.imports = {} self.resolved_imports = [] self.relocs = [] self.jmprel = {} self._entry = self.reader.header.e_entry self.pic = self.reader.header.e_type == 'ET_DYN' self.tls_used = False self.tls_module_id = None self.tls_block_offset = None self.tls_block_size = None self.tls_tdata_start = None self.tls_tdata_size = None self.__register_segments() self.__register_sections() # call the methods defined by MetaELF self._ppc64_abiv1_entry_fix() self._load_plt()
def test_ctype_tolower_loc(): ''' test_ctype_locale.test_ctype_tolower_loc int32_t * * __ctype_tolower_loc(void); Description: The __ctype_tolower_loc() function shall return a pointer into an array of characters in the current locale that contains lower case equivalents for each character in the current character set. The array shall contain a total of 384 characters, and can be indexed with any signed or unsigned char (i.e. with an index value between -128 and 255). If the application is multithreaded, the array shall be local to the current thread. This interface is not in the source standard; it is only in the binary standard. Return Value: The __ctype_tolower_loc() function shall return a pointer to the array of characters to be used for the ctype() family of functions (see <ctype.h>). ''' # Just load a binary so that we can do the initialization steps from # libc_start_main bin_path = os.path.join(test_location, '../../binaries/tests/x86_64/ctype_tolower_loc') ctype_tolower_loc = lambda state, arguments: simuvex.SimProcedures[ 'libc.so.6']['__ctype_tolower_loc']( FAKE_ADDR, archinfo.arch_from_id('AMD64')).execute( state, arguments=arguments) b = angr.Project(bin_path) p = b.factory.full_init_state() pg = b.factory.path_group(p) # Find main located at 0x400596 to let libc_start_main do its thing main = pg.explore(find=0x400596) state = main.found[0].state tolower_loc_array_ptr = ctype_tolower_loc(state, []).ret_expr table_ptr = state.memory.load(tolower_loc_array_ptr, state.arch.bits / 8, endness=state.arch.memory_endness) result = '' for i in range(-128, 256): result += "%d->0x%x\n" % ( i, state.se.any_int( state.memory.load( table_ptr + (i * 4), 4, endness=state.arch.memory_endness))) # Check output of compiled C program that uses ctype_tolower_loc() output = subprocess.check_output(bin_path, shell=True) nose.tools.assert_equal(result, output)
def _canonicalize(self, number, arch): if type(arch) is str: arch = archinfo.arch_from_id(arch) if type(number) is str: return number, arch mapping = self.syscall_number_mapping[arch.name] if number in mapping: return mapping[number], arch else: return 'sys_%d' % number, arch
def test_x86_noop_blocks(): # nop arch = archinfo.arch_from_id("x86") b = b"\x90\x90\x90\x90\x90\x90\x90\x90" p = angr.load_shellcode(b, arch, load_address=0x400000) block = p.factory.block(0x400000, opt_level=1, cross_insn_opt=False) assert CFGBase._is_noop_block(arch, block) is True block = p.factory.block(0x400000, opt_level=1, cross_insn_opt=True) assert CFGBase._is_noop_block(arch, block) is True
def _canonicalize(self, number, arch, abi_list): if type(arch) is str: arch = archinfo.arch_from_id(arch) if type(number) is str: return number, arch, None for abi in abi_list: mapping = self.syscall_number_mapping[abi] if number in mapping: return mapping[number], arch, abi return 'sys_%d' % number, arch, None
def __init__(self, binary, is_main_bin=False, compatible_with=None, filetype='unknown', **kwargs): """ args: binary kwargs: {load=True, custom_base_addr=None, custom_entry_point=None, custom_offset=None} """ # Unfold the kwargs and convert them to class attributes for k,v in kwargs.iteritems(): setattr(self, k, v) self.binary = binary self.is_main_bin = is_main_bin self._entry = None self.segments = [] # List of segments self.sections = [] # List of sections self.sections_map = {} # Mapping from section name to section self.symbols_by_addr = {} self.imports = {} self.resolved_imports = [] self.relocs = [] self.jmprel = {} self.symbols = None # Object's symbols self.arch = None self.filetype = filetype self.os = 'windows' if self.filetype == 'pe' else 'unix' self.compatible_with = compatible_with # These are set by cle, and should not be overriden manually self.rebase_addr = 0 # not to be set manually - used by CLE self.tls_module_id = None self.object_type = None self.deps = [] # Needed shared objects (libraries dependencies) self.linking = None # Dynamic or static linking self.requested_base = None self.pic = False # Custom options self._custom_entry_point = kwargs.get('custom_entry_point', None) self.provides = None self.memory = None custom_arch = kwargs.get('custom_arch', None) if custom_arch is None: self.arch = None elif isinstance(custom_arch, str): self.set_arch(archinfo.arch_from_id(custom_arch)) elif isinstance(custom_arch, archinfo.Arch): self.set_arch(custom_arch) elif isinstance(custom_arch, type) and issubclass(custom_arch, archinfo.Arch): self.set_arch(custom_arch()) else: raise CLEError("Bad parameter: custom_arch=%s" % custom_arch)
def test_convert_from_vex_irsb(): arch = archinfo.arch_from_id('AMD64') manager = ailment.Manager(arch=arch) irsb = pyvex.IRSB(block_bytes, block_addr, arch, opt_level=0) ablock = ailment.IRSBConverter.convert(irsb, manager) print(str(ablock))
def test_SystemVAMD64_flatten_int(self): arch = archinfo.arch_from_id("amd64") cc = SimCCSystemVAMD64(arch) int_type = SimTypeInt().with_arch(arch) flattened_int = cc._flatten(int_type) self.assertTrue(all(isinstance(key, int) for key in flattened_int)) self.assertTrue(all(isinstance(value, list) for value in flattened_int.values())) for v in flattened_int.values(): for subtype in v: self.assertIsInstance(subtype, SimTypeInt)
def __init__(self, *args, offset=0, **kwargs): """ Loader backend for BF programs :param path: The file path :param offset: Skip this many bytes from the beginning of the file. """ super(BF, self).__init__(*args, arch=arch_from_id("bf"), offset=offset, entry_point=0, **kwargs) self.os = "bf"
def from_string(data, log_level = logging.WARNING, address_offset = None): gadgets_dict = pickle.loads(data) gadgets_list = [item for sublist in gadgets_dict.values() for item in sublist] # Flatten list of lists # Turn the names of the arch back into archinfo classes (Which aren't pickle-able) for gadget in gadgets_list: gadget.arch = archinfo.arch_from_id(gadget.arch) gl = GadgetList(gadgets_list, log_level) if address_offset != None: gl.adjust_base_address(address_offset) return gl
def __init__(self, binary, is_main_bin=False, compatible_with=None, filetype="unknown", **kwargs): # Unfold the kwargs and convert them to class attributes for k, v in kwargs.iteritems(): setattr(self, k, v) self.binary = binary self.is_main_bin = is_main_bin self._entry = None self.segments = [] # List of segments self.sections = [] # List of sections self.sections_map = {} # Mapping from section name to section self.symbols_by_addr = {} self.imports = {} self.resolved_imports = [] self.relocs = [] self.irelatives = [] # list of tuples (resolver, destination), dest w/o rebase self.jmprel = {} self.arch = None self.filetype = filetype self.os = "windows" if self.filetype == "pe" else "unix" self.compatible_with = compatible_with self._symbol_cache = {} # These are set by cle, and should not be overriden manually self.rebase_addr = 0 # not to be set manually - used by CLE self.tls_module_id = None self.object_type = None self.deps = [] # Needed shared objects (libraries dependencies) self.linking = None # Dynamic or static linking self.requested_base = None self.pic = False self.execstack = False # Custom options self._custom_entry_point = kwargs.get("custom_entry_point", None) self.provides = None self.memory = None custom_arch = kwargs.get("custom_arch", None) if custom_arch is None: self.arch = None elif isinstance(custom_arch, str): self.set_arch(archinfo.arch_from_id(custom_arch)) elif isinstance(custom_arch, archinfo.Arch): self.set_arch(custom_arch) elif isinstance(custom_arch, type) and issubclass(custom_arch, archinfo.Arch): self.set_arch(custom_arch()) else: raise CLEError("Bad parameter: custom_arch=%s" % custom_arch)
def __init__(self, *args, **kwargs): super(PE, self).__init__(*args, **kwargs) self.segments = self.sections # in a PE, sections and segments have the same meaning self.os = 'windows' if self.binary is None: self._pe = pefile.PE(data=self.binary_stream.read()) elif self.binary in self._pefile_cache: # these objects are not mutated, so they are reusable within a process self._pe = self._pefile_cache[self.binary] else: self._pe = pefile.PE(self.binary) if not self.is_main_bin: # only cache shared libraries, the main binary will not be reused self._pefile_cache[self.binary] = self._pe if self.arch is None: self.set_arch(archinfo.arch_from_id(pefile.MACHINE_TYPE[self._pe.FILE_HEADER.Machine])) self.mapped_base = self.linked_base = self._pe.OPTIONAL_HEADER.ImageBase self._entry = AT.from_rva(self._pe.OPTIONAL_HEADER.AddressOfEntryPoint, self).to_lva() if hasattr(self._pe, 'DIRECTORY_ENTRY_IMPORT'): self.deps = [entry.dll.decode().lower() for entry in self._pe.DIRECTORY_ENTRY_IMPORT] else: self.deps = [] if self.binary is not None and not self.is_main_bin: self.provides = os.path.basename(self.binary).lower() else: self.provides = None self.tls_index_address = None self.tls_callbacks = None self.supports_nx = self._pe.OPTIONAL_HEADER.DllCharacteristics & 0x100 != 0 self.pic = self.pic or self._pe.OPTIONAL_HEADER.DllCharacteristics & 0x40 != 0 self._exports = {} self._ordinal_exports = {} self._symbol_cache = self._exports # same thing self._handle_imports() self._handle_exports() self.__register_relocs() self._register_tls() self._register_sections() self.linking = 'dynamic' if self.deps else 'static' self.jmprel = self._get_jmprel() self.memory.add_backer(0, self._pe.get_memory_mapped_image())
def test_fauxware(): amd64 = archinfo.arch_from_id('amd64') args = { 'i386': [ ('authenticate', SimCCCdecl( archinfo.arch_from_id('i386'), args=[SimStackArg(4, 4), SimStackArg(8, 4)], sp_delta=4 ) ), ], 'x86_64': [ ('authenticate', SimCCSystemVAMD64( amd64, args=[SimRegArg('rdi', 8), SimRegArg('rsi', 8)], sp_delta=8 ) ), ], } for arch, lst in args.items(): yield run_fauxware, arch, lst
def extract_arch(reader): arch_str = reader['e_machine'] if 'ARM' in arch_str: # Check the ARM attributes, if they exist arm_attrs = ELF._extract_arm_attrs(reader) if arm_attrs and 'TAG_CPU_NAME' in arm_attrs: if arm_attrs['TAG_CPU_NAME'].endswith("-M") \ or 'Cortex-M' in arm_attrs['TAG_CPU_NAME']: return archinfo.ArchARMCortexM('Iend_LE') if reader.header.e_flags & 0x200: return archinfo.ArchARMEL('Iend_LE' if reader.little_endian else 'Iend_BE') elif reader.header.e_flags & 0x400: return archinfo.ArchARMHF('Iend_LE' if reader.little_endian else 'Iend_BE') return archinfo.arch_from_id(arch_str, 'le' if reader.little_endian else 'be', reader.elfclass)
def get(self, name, arch): """ Get an implementation of the given function specialized for the given arch, or a stub procedure if none exists. :param name: The name of the function as a string :param arch: The architecure to use, as either a string or an archinfo.Arch instance :return: A SimProcedure instance representing the function as found in the library """ if type(arch) is str: arch = archinfo.arch_from_id(arch) if name in self.procedures: proc = copy.deepcopy(self.procedures[name]) self._apply_metadata(proc, arch) return proc else: return self.get_stub(name, arch)
def test_skipstmts_toomanyexits(): # https://github.com/angr/pyvex/issues/153 old_exit_limit = IRSB.MAX_EXITS IRSB.MAX_EXITS = 32 bytes_ = bytes.fromhex("0DF1B00B2EAB94E8030008938BE803000DF1C0089AE8030083E80300019B0DF1F00A339AE669E26193E8030085E8030098E8030083E80300069B95E8030088E80300A26993E803004A92002363622362A361E362A36238AC029A069484E8030012AC0998299328932B9303C885E8030092E8030084E803009AE8030082E803002A460A9D26993E910B9941910D9942910C992A93409548AD439194E803008AE8030027983F9927913F909BE803000DF5887B269335938BE803000DF58C7B089903C98BE8030098E8030084E8030095E8030088E803004B993391329394E80300349337933693069C059B4C93049B4E9350ABCDF834C1CDF83CE185E8030094E803004B9683E8030015A94498C4F7E2EA") arch = archinfo.arch_from_id("ARMEL") # Lifting the first four bytes will not cause any problem. Statements should be skipped as expected b = IRSB(bytes_[:34], 0xC6951, arch, opt_level=1, bytes_offset=5, skip_stmts=True) nose.tools.assert_greater(len(b.exit_statements), 0) nose.tools.assert_false(b.has_statements, None) # Lifting the entire block will cause the number of exit statements go beyond the limit (currently 32). PyVEX will # automatically relift this block without skipping the statements b = IRSB(bytes_, 0xC6951, arch, opt_level=1, bytes_offset=5, skip_stmts=True) nose.tools.assert_is_not(b.statements, None) nose.tools.assert_greater(len(b.exit_statements), 32) # Restore the setting IRSB.MAX_EXITS = old_exit_limit
def __init__(self, *args, **kwargs): if pefile is None: raise CLEError("Install the pefile module to use the PE backend!") super(PE, self).__init__(*args, **kwargs) if self.binary is not None: self._pe = pefile.PE(data=self.binary_stream.read()) else: self._pe = pefile.PE(self.binary) if self.arch is None: self.set_arch(archinfo.arch_from_id(pefile.MACHINE_TYPE[self._pe.FILE_HEADER.Machine])) self.requested_base = self._pe.OPTIONAL_HEADER.ImageBase self._entry = self._pe.OPTIONAL_HEADER.AddressOfEntryPoint if hasattr(self._pe, 'DIRECTORY_ENTRY_IMPORT'): self.deps = [entry.dll for entry in self._pe.DIRECTORY_ENTRY_IMPORT] else: self.deps = [] if self.binary is not None and not self.is_main_bin: self.provides = os.path.basename(self.binary) else: self.provides = None self._exports = {} self._handle_imports() self._handle_exports() self._handle_relocs() self._register_sections() self.linking = 'dynamic' if len(self.deps) > 0 else 'static' self.jmprel = self._get_jmprel() self.memory.add_backer(0, self._pe.get_memory_mapped_image()) l.warning('The PE module is not well-supported. Good luck!')
def from_string(data, log_level = logging.WARNING, address_offset = None, bad_bytes = None, filter_func = None): gadgets_dict = pickle.loads(data) gadgets_list = [item for sublist in gadgets_dict.values() for item in sublist] # Flatten list of lists # Turn the names of the arch back into archinfo classes (Which aren't pickle-able) for gadget in gadgets_list: gadget.arch = archinfo.arch_from_id(gadget.arch) # Filter the gadgets if necessary if filter_func != None: gadgets_list = filter_func(gadgets_list) gl = GadgetList(gadgets_list, log_level) if address_offset != None: gl.adjust_base_address(address_offset) if bad_bytes != None: just_good_gadgets = GadgetList(log_level = log_level, bad_bytes = bad_bytes) for gadget in gl.foreach(): if not gadget.has_bad_address(bad_bytes): just_good_gadgets.add_gadget(gadget) gl = just_good_gadgets return gl
def __init__(self, binary, **kwargs): super(ELF, self).__init__(binary, **kwargs) try: self.reader = elffile.ELFFile(open(self.binary, 'rb')) except ELFError: raise CLECompatibilityError # Get an appropriate archinfo.Arch for this binary, unless the user specified one if self.arch is None: arch_str = self.reader['e_machine'] if arch_str == 'ARM': if self.reader.header.e_flags & 0x200: self.set_arch(archinfo.ArchARMEL('Iend_LE' if self.reader.little_endian else 'Iend_BE')) elif self.reader.header.e_flags & 0x400: self.set_arch(archinfo.ArchARMHF('Iend_LE' if self.reader.little_endian else 'Iend_BE')) else: self.set_arch(archinfo.arch_from_id(arch_str, 'le' if self.reader.little_endian else 'be', self.reader.elfclass)) self.strtab = None self.dynsym = None self.hashtable = None self._dynamic = {} self.deps = [] self.rela_type = None self._inits_extracted = False self._preinit_arr = [] self._init_func = None self._init_arr = [] self._fini_func = None self._fini_arr = [] self._nullsymbol = Symbol(self, '', 0, 0, None, 'STT_NOTYPE', 0) self._symbol_cache = {} self.symbols_by_addr = {} self.demangled_names = {} self.imports = {} self.resolved_imports = [] self.relocs = [] self.jmprel = {} self._entry = self.reader.header.e_entry self.pic = self.reader.header.e_type == 'ET_DYN' self.tls_used = False self.tls_module_id = None self.tls_block_offset = None self.tls_block_size = None self.tls_tdata_start = None self.tls_tdata_size = None self.__parsed_reloc_tables = set() self.__register_segments() self.__register_sections() # call the methods defined by MetaELF self._ppc64_abiv1_entry_fix() self._load_plt() self._populate_demangled_names()
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 given state, not only from the initial 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 isinstance(thing, cle.Loader): self.loader = thing self.filename = self.loader._main_binary_path 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 if load_options is None: load_options = {} 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.loader.add_object(self._extern_obj) self._cfg = None self._vfg = None self._cdg = None self.entry = self.loader.main_bin.entry self.factory = AngrObjectFactory(self, translation_cache=translation_cache) self.analyses = Analyses(self) self.surveyors = Surveyors(self) self.kb = KnowledgeBase(self, self.loader.main_bin) 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()
import logging, collections import rop_compiler.factories as factories import argparse parser = argparse.ArgumentParser(description="Run the gadget locator on the supplied binary") parser.add_argument('filename', type=str, default=None, help='The file (executable/library) to load gadgets from') parser.add_argument('-arch', type=str, default="AMD64", help='The architecture of the binary') parser.add_argument('-big_endian', required=False, action='store_true', help="Whether the architecture is big endian or not") parser.add_argument('-finder_type', type=str, default="mem", help='The type of gadget finder (memory, file)') parser.add_argument('-o', type=str, default=None, help='File to write the gadgets to') parser.add_argument('-parser_type', type=str, default="cle", help='The type of file parser (cle, pyelf, radare)') parser.add_argument('-v', required=False, action='store_true', help='Verbose mode') parser.add_argument('-validate', required=False, action='store_true', help='Validate gadgets with z3') args = parser.parse_args() finder_type = factories.get_finder_from_name(args.finder_type) logging_level = logging.DEBUG if args.v else logging.WARNING arch = archinfo.arch_from_id(args.arch, 'Iend_BE' if args.big_endian else 'Iend_LE') finder = finder_type(args.filename, arch, 0, logging_level, args.parser_type) gadget_list = finder.find_gadgets(args.validate) if args.o == None: for gadget in gadget_list.foreach(): print gadget else: fd = open(args.o, "w") fd.write(gadget_list.to_string()) fd.close()
def __init__(self, project=None, arch=None, plugins=None, memory_backer=None, permissions_backer=None, mode=None, options=None, add_options=None, remove_options=None, special_memory_filler=None, os_name=None, plugin_preset='default', **kwargs): if kwargs: l.warning("Unused keyword arguments passed to SimState: %s", " ".join(kwargs)) super(SimState, self).__init__() self.project = project # Arch if self._is_java_jni_project: self._arch = { "soot" : project.arch, "vex" : project.simos.native_simos.arch } # This flag indicates whether the current ip is a native address or # a soot address descriptor. # Note: We cannot solely rely on the ip to make that decsision, # because the registers (storing the ip) are part of the # plugins that are getting toggled (=> mutual dependence). self.ip_is_soot_addr = False else: self._arch = arch if arch is not None else project.arch.copy() if project is not None else None if type(self._arch) is str: self._arch = archinfo.arch_from_id(self._arch) # the options if options is None: if mode is None: l.warning("SimState defaulting to symbolic mode.") mode = "symbolic" options = o.modes[mode] if isinstance(options, (set, list)): options = SimStateOptions(options) if add_options is not None: options |= add_options if remove_options is not None: options -= remove_options self._options = options self.mode = mode if plugin_preset is not None: self.use_plugin_preset(plugin_preset) if plugins is not None: for n,p in plugins.items(): self.register_plugin(n, p, inhibit_init=True) for p in plugins.values(): p.init_state() if not self.has_plugin('memory'): # We don't set the memory endness because, unlike registers, it's hard to understand # which endness the data should be read. # If they didn't provide us with either a memory plugin or a plugin preset to use, # we have no choice but to use the 'default' plugin preset. if self.plugin_preset is None: self.use_plugin_preset('default') # Determine memory backend if self._is_java_project and not self._is_java_jni_project: sim_memory_cls = self.plugin_preset.request_plugin('javavm_memory') sim_memory = sim_memory_cls(memory_id='mem') elif o.ABSTRACT_MEMORY in self.options: # We use SimAbstractMemory in static mode. # Convert memory_backer into 'global' region. if memory_backer is not None: memory_backer = {'global': memory_backer} # TODO: support permissions backer in SimAbstractMemory sim_memory_cls = self.plugin_preset.request_plugin('abs_memory') sim_memory = sim_memory_cls(memory_backer=memory_backer, memory_id='mem') elif o.FAST_MEMORY in self.options: sim_memory_cls = self.plugin_preset.request_plugin('fast_memory') sim_memory = sim_memory_cls(memory_backer=memory_backer, memory_id='mem') else: sim_memory_cls = self.plugin_preset.request_plugin('sym_memory') sim_memory = sim_memory_cls(memory_backer=memory_backer, memory_id='mem', permissions_backer=permissions_backer) # Add memory plugin if not self._is_java_jni_project: self.register_plugin('memory', sim_memory) else: # In case of the JavaVM with JNI support, we add two `memory` plugins; one for modeling the # native memory and another one for the JavaVM memory. native_sim_memory = sim_memory javavm_sim_memory_cls = self.plugin_preset.request_plugin('javavm_memory') javavm_sim_memory = javavm_sim_memory_cls(memory_id='mem') self.register_plugin('memory_soot', javavm_sim_memory) self.register_plugin('memory_vex', native_sim_memory) if not self.has_plugin('registers'): # Same as for 'memory' plugin. if self.plugin_preset is None: self.use_plugin_preset('default') # Get register endness if self._is_java_jni_project: register_endness = self._arch['vex'].register_endness else: register_endness = self.arch.register_endness # Determine register backend if self._is_java_project and not self._is_java_jni_project: sim_registers_cls = self.plugin_preset.request_plugin('keyvalue_memory') sim_registers = sim_registers_cls(memory_id='reg') elif o.FAST_REGISTERS in self.options: sim_registers_cls = self.plugin_preset.request_plugin('fast_memory') sim_registers = sim_registers_cls(memory_id="reg", endness=register_endness) else: sim_registers_cls = self.plugin_preset.request_plugin('sym_memory') sim_registers = sim_registers_cls(memory_id="reg", endness=register_endness) # Add registers plugin if not self._is_java_jni_project: self.register_plugin('registers', sim_registers) else: # Analog to memory, we add two registers plugins native_sim_registers = sim_registers javavm_sim_registers_cls = self.plugin_preset.request_plugin('keyvalue_memory') javavm_sim_registers = javavm_sim_registers_cls(memory_id='reg') self.register_plugin('registers_soot', javavm_sim_registers) self.register_plugin('registers_vex', native_sim_registers) # OS name self.os_name = os_name # This is used in static mode as we don't have any constraints there self._satisfiable = True self.uninitialized_access_handler = None self._special_memory_filler = special_memory_filler # this is a global condition, applied to all added constraints, memory reads, etc self._global_condition = None self.ip_constraints = []
def __init__(self, binary, is_main_bin=False, compatible_with=None, filetype='unknown', **kwargs): """ :param binary: The path to the binary to load :param is_main_bin: Whether this binary should be loaded as the main executable :param compatible_with: An optional Backend object to force compatibility with :param filetype: The format of the file to load """ # Unfold the kwargs and convert them to class attributes # TODO: do we need to do this anymore? for k,v in kwargs.iteritems(): setattr(self, k, v) if hasattr(binary, 'seek') and hasattr(binary, 'read'): self.binary = None self.binary_stream = binary else: self.binary = binary try: self.binary_stream = open(binary, 'rb') except IOError: self.binary_stream = None self.is_main_bin = is_main_bin self._entry = None self.segments = [] # List of segments self.sections = [] # List of sections self.sections_map = {} # Mapping from section name to section self.symbols_by_addr = {} self.imports = {} self.resolved_imports = [] self.relocs = [] self.irelatives = [] # list of tuples (resolver, destination), dest w/o rebase self.jmprel = {} self.arch = None self.filetype = filetype self.os = 'windows' if self.filetype == 'pe' else 'unix' self.compatible_with = compatible_with self._symbol_cache = {} self.aslr = kwargs['aslr'] if 'aslr' in kwargs else False self.rebase_addr_symbolic = 0 # These are set by cle, and should not be overriden manually self.rebase_addr = 0 # not to be set manually - used by CLE self.tls_module_id = None self.deps = [] # Needed shared objects (libraries dependencies) self.linking = None # Dynamic or static linking self.requested_base = None self.pic = False self.execstack = False # Custom options self._custom_entry_point = kwargs.get('custom_entry_point', None) self.provides = None self.memory = None custom_arch = kwargs.get('custom_arch', None) if custom_arch is None: self.arch = None elif isinstance(custom_arch, str): self.set_arch(archinfo.arch_from_id(custom_arch)) elif isinstance(custom_arch, archinfo.Arch): self.set_arch(custom_arch) elif isinstance(custom_arch, type) and issubclass(custom_arch, archinfo.Arch): self.set_arch(custom_arch()) else: raise CLEError("Bad parameter: custom_arch=%s" % custom_arch)
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, store_function=None, load_function=None, analyses_preset=None, concrete_target=None, engines_preset=None, **kwargs): # Step 1: Load the binary if load_options is None: load_options = {} load_options.update(kwargs) if arch is not None: load_options.update({'arch': arch}) if isinstance(thing, cle.Loader): if load_options: l.warning("You provided CLE options to angr but you also provided a completed cle.Loader object!") self.loader = thing self.filename = self.loader.main_object.binary 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, 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, concrete_target=concrete_target, **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_object.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.concrete_target = concrete_target # It doesn't make any sense to have auto_load_libs # if you have the concrete target, let's warn the user about this. if self.concrete_target and load_options.get('auto_load_libs', None): l.critical("Incompatible options selected for this project, please disable auto_load_libs if " "you want to use a concrete target.") raise Exception("Incompatible options for the project") if self.concrete_target and self.arch.name not in ['X86', 'AMD64']: l.critical("Concrete execution does not support yet the selected architecture. Aborting.") raise Exception("Incompatible options for the project") 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._ignore_functions = ignore_functions self._support_selfmodifying_code = support_selfmodifying_code self._translation_cache = translation_cache self._executing = False # this is a flag for the convenience API, exec() and terminate_execution() below self._is_java_project = None self._is_java_jni_project = None if self._support_selfmodifying_code: if self._translation_cache is True: self._translation_cache = False l.warning("Disabling IRSB translation cache because support for self-modifying code is enabled.") self.entry = self.loader.main_object.entry self.storage = defaultdict(list) self.store_function = store_function or self._store self.load_function = load_function or self._load # Step 4: Set up the project's plugin hubs # Step 4.1: Engines. Get the preset from the loader, from the arch, or use the default. engines = EngineHub(self) if engines_preset is not None: engines.use_plugin_preset(engines_preset) elif self.loader.main_object.engine_preset is not None: try: engines.use_plugin_preset(self.loader.main_object.engine_preset) except AngrNoPluginError: raise ValueError("The CLE loader asked to use a engine preset: %s" % \ self.loader.main_object.engine_preset) else: try: engines.use_plugin_preset(self.arch.name) except AngrNoPluginError: engines.use_plugin_preset('default') self.engines = engines self.factory = AngrObjectFactory(self) # Step 4.2: Analyses self.analyses = AnalysesHub(self) self.analyses.use_plugin_preset(analyses_preset if analyses_preset is not None else 'default') # Step 4.3: ...etc self.kb = KnowledgeBase(self, self.loader.main_object) # Step 5: determine the guest OS if isinstance(simos, type) and issubclass(simos, SimOS): self.simos = simos(self) #pylint:disable=invalid-name elif isinstance(simos, str): self.simos = os_mapping[simos](self) elif simos is None: self.simos = os_mapping[self.loader.main_object.os](self) else: raise ValueError("Invalid OS specification or non-matching architecture.") # Step 6: Register simprocedures as appropriate for library functions if isinstance(self.arch, ArchSoot) and self.simos.is_javavm_with_jni_support: # If we execute a Java archive that includes native JNI libraries, # we need to use the arch of the native simos for all (native) sim # procedures. sim_proc_arch = self.simos.native_arch else: sim_proc_arch = self.arch for obj in self.loader.initial_load_objects: self._register_object(obj, sim_proc_arch) # Step 7: Run OS-specific configuration self.simos.configure_project()
def _regs_to_offsets(arch_name, regs): offsets = set() arch = archinfo.arch_from_id(arch_name) for r in regs: offsets.add(arch.registers[r][0]) return offsets
def __init__(self, binary, **kwargs): super(ELF, self).__init__(binary, **kwargs) patch_undo = None try: self.reader = elffile.ELFFile(self.binary_stream) except ELFError: self.binary_stream.seek(5) ty = self.binary_stream.read(1) if ty not in ('\1', '\2'): raise CLECompatibilityError patch_data = (0x20, '\0\0\0\0') if ty == '\1' else (0x28, '\0\0\0\0\0\0\0\0') self.binary_stream.seek(patch_data[0]) patch_undo = (patch_data[0], self.binary_stream.read(len(patch_data[1]))) self.binary_stream = PatchedStream(self.binary_stream, [patch_data]) l.error("PyReadELF couldn't load this file. Trying again without section headers...") try: self.reader = elffile.ELFFile(self.binary_stream) except ELFError: raise CLECompatibilityError # Get an appropriate archinfo.Arch for this binary, unless the user specified one if self.arch is None: arch_str = self.reader['e_machine'] if arch_str == 'ARM': if self.reader.header.e_flags & 0x200: self.set_arch(archinfo.ArchARMEL('Iend_LE' if self.reader.little_endian else 'Iend_BE')) elif self.reader.header.e_flags & 0x400: self.set_arch(archinfo.ArchARMHF('Iend_LE' if self.reader.little_endian else 'Iend_BE')) else: self.set_arch(archinfo.arch_from_id(arch_str, 'le' if self.reader.little_endian else 'be', self.reader.elfclass)) self.strtab = None self.dynsym = None self.hashtable = None self._dynamic = {} self.deps = [] self.rela_type = None self._inits_extracted = False self._preinit_arr = [] self._init_func = None self._init_arr = [] self._fini_func = None self._fini_arr = [] self._nullsymbol = Symbol(self, '', 0, 0, None, 'STT_NOTYPE', 0) self._symbol_cache = {} self.symbols_by_addr = {} self.demangled_names = {} self.imports = {} self.resolved_imports = [] self.relocs = [] self.jmprel = {} self._entry = self.reader.header.e_entry self.pic = self.reader.header.e_type == 'ET_DYN' self.tls_used = False self.tls_module_id = None self.tls_block_offset = None self.tls_block_size = None self.tls_tdata_start = None self.tls_tdata_size = None self.__parsed_reloc_tables = set() self.__register_segments() self.__register_sections() # call the methods defined by MetaELF self._ppc64_abiv1_entry_fix() self._load_plt() self._populate_demangled_names() if patch_undo is not None: self.memory.write_bytes(self.get_min_addr() + patch_undo[0], patch_undo[1])
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, **kwargs): # Step 1: Load the binary if load_options is None: load_options = {} load_options.update(kwargs) if isinstance(thing, cle.Loader): if load_options: l.warning("You provided CLE options to angr but you also provided a completed cle.Loader object!") self.loader = thing self.filename = self.loader.main_object.binary 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_object.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._executing = False # this is a flag for the convenience API, exec() and terminate_execution() below 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.") # Look up the default engine. engine_cls = get_default_engine(type(self.loader.main_object)) if not engine_cls: raise AngrError("No engine associated with loader %s" % str(type(self.loader.main_object))) engine = engine_cls( stop_points=self._sim_procedures, use_cache=translation_cache, support_selfmodifying_code=support_selfmodifying_code) procedure_engine = SimEngineProcedure() hook_engine = SimEngineHook(self) failure_engine = SimEngineFailure(self) syscall_engine = SimEngineSyscall(self) unicorn_engine = SimEngineUnicorn(self._sim_procedures) self.entry = self.loader.main_object.entry self.factory = AngrObjectFactory( self, engine, procedure_engine, [failure_engine, syscall_engine, hook_engine, unicorn_engine, engine]) self.analyses = Analyses(self) self.surveyors = Surveyors(self) self.kb = KnowledgeBase(self, self.loader.main_object) if self.filename is not None: projects[self.filename] = self # Step 4: determine the guest OS 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_object.os](self) else: raise ValueError("Invalid OS specification or non-matching architecture.") # Step 5: Register simprocedures as appropriate for library functions for obj in self.loader.initial_load_objects: self._register_object(obj) # Step 6: Run OS-specific configuration self._simos.configure_project()
def __init__(self, project=None, arch=None, plugins=None, memory_backer=None, permissions_backer=None, mode=None, options=None, add_options=None, remove_options=None, special_memory_filler=None, os_name=None, plugin_preset='default'): super(SimState, self).__init__() self.project = project self.arch = arch if arch is not None else project.arch.copy() if project is not None else None if type(self.arch) is str: self.arch = arch_from_id(self.arch) # the options if options is None: if mode is None: l.warning("SimState defaulting to symbolic mode.") mode = "symbolic" options = o.modes[mode] if isinstance(options, (set, list)): options = SimStateOptions(options) if add_options is not None: options |= add_options if remove_options is not None: options -= remove_options self._options = options self.mode = mode if plugin_preset is not None: self.use_plugin_preset(plugin_preset) if plugins is not None: for n,p in plugins.iteritems(): self.register_plugin(n, p, inhibit_init=True) for p in plugins.itervalues(): p.init_state() if not self.has_plugin('memory'): # We don't set the memory endness because, unlike registers, it's hard to understand # which endness the data should be read. # If they didn't provide us with either a memory plugin or a plugin preset to use, # we have no choice but to use the 'default' plugin preset. if self.plugin_preset is None: self.use_plugin_preset('default') if o.ABSTRACT_MEMORY in self.options: # We use SimAbstractMemory in static mode. # Convert memory_backer into 'global' region. if memory_backer is not None: memory_backer = {'global': memory_backer} # TODO: support permissions backer in SimAbstractMemory sim_memory_cls = self.plugin_preset.request_plugin('abs_memory') sim_memory = sim_memory_cls(memory_backer=memory_backer, memory_id='mem') elif o.FAST_MEMORY in self.options: sim_memory_cls = self.plugin_preset.request_plugin('fast_memory') sim_memory = sim_memory_cls(memory_backer=memory_backer, memory_id='mem') else: sim_memory_cls = self.plugin_preset.request_plugin('sym_memory') sim_memory = sim_memory_cls(memory_backer=memory_backer, memory_id='mem', permissions_backer=permissions_backer) self.register_plugin('memory', sim_memory) if not self.has_plugin('registers'): # Same as for 'memory' plugin. if self.plugin_preset is None: self.use_plugin_preset('default') if o.FAST_REGISTERS in self.options: sim_registers_cls = self.plugin_preset.request_plugin('fast_memory') sim_registers = sim_registers_cls(memory_id="reg", endness=self.arch.register_endness) else: sim_registers_cls = self.plugin_preset.request_plugin('sym_memory') sim_registers = sim_registers_cls(memory_id="reg", endness=self.arch.register_endness) self.register_plugin('registers', sim_registers) # OS name self.os_name = os_name # This is used in static mode as we don't have any constraints there self._satisfiable = True # states are big, so let's give them UUIDs for ANA right away to avoid # extra pickling self.make_uuid() self.uninitialized_access_handler = None self._special_memory_filler = special_memory_filler # this is a global condition, applied to all added constraints, memory reads, etc self._global_condition = None self.ip_constraints = []
def Iop_Add64(self, left, right): return utils.mask(left + right) def Iop_Add32(self, left, right): return utils.mask(left + right, 32) def Iop_Add8(self, left, right): return utils.mask(left + right, 8) def Iop_Sub64(self, left, right): return utils.mask(left - right) def Iop_Sub32(self, left, right): return utils.mask(left - right, 32) def Iop_Shl64(self, left, right): return utils.mask(left << right) def Iop_Shl32(self, left, right): return utils.mask(left << right, 32) def Iop_CmpEQ64(self, left, right): return 1 if utils.mask(left, 64) == utils.mask(right, 64) else 0 def Iop_CmpEQ32(self, left, right): return 1 if utils.mask(left, 32) == utils.mask(right, 32) else 0 def Iop_CmpNE64(self, left, right): return 1 if utils.mask(left, 64) != utils.mask(right, 64) else 0 def Iop_CmpNE32(self, left, right): return 1 if utils.mask(left, 32) != utils.mask(right, 32) else 0 if __name__ == "__main__": import sys if len(sys.argv) < 3: print "Usage: classifier.py architecture filename [-v]" sys.exit(1) arch = archinfo.arch_from_id(sys.argv[1]).__class__ code = utils.get_contents(sys.argv[2]) classifier = GadgetClassifier(arch, log_level = logging.DEBUG if len(sys.argv) > 3 else logging.WARNING) gadgets = classifier.create_gadgets_from_instructions(code, 0x40000) for g in gadgets: print g
def test_ctype_tolower_loc(): ''' test_ctype_locale.test_ctype_tolower_loc int32_t * * __ctype_tolower_loc(void); Description: The __ctype_tolower_loc() function shall return a pointer into an array of characters in the current locale that contains lower case equivalents for each character in the current character set. The array shall contain a total of 384 characters, and can be indexed with any signed or unsigned char (i.e. with an index value between -128 and 255). If the application is multithreaded, the array shall be local to the current thread. This interface is not in the source standard; it is only in the binary standard. Return Value: The __ctype_tolower_loc() function shall return a pointer to the array of characters to be used for the ctype() family of functions (see <ctype.h>). ''' # Just load a binary so that we can do the initialization steps from # libc_start_main bin_path = os.path.join(test_location, '../../binaries/tests/x86_64/ctype_tolower_loc') ctype_tolower_loc = lambda state, arguments: simuvex.SimProcedures['libc.so.6']['__ctype_tolower_loc'](FAKE_ADDR, archinfo.arch_from_id('AMD64')).execute(state, arguments=arguments) b = angr.Project(bin_path) p = b.factory.full_init_state() pg = b.factory.path_group(p) # Find main located at 0x400596 to let libc_start_main do its thing main = pg.explore(find=0x400596) state = main.found[0].state tolower_loc_array_ptr = ctype_tolower_loc(state, []).ret_expr table_ptr = state.memory.load(tolower_loc_array_ptr, state.arch.bits/8, endness=state.arch.memory_endness) result = '' for i in range(-128, 256): result += "%d->0x%x\n" % (i, state.se.any_int(state.memory.load(table_ptr + (i*4), 4, endness=state.arch.memory_endness))) # Check output of compiled C program that uses ctype_tolower_loc() output = subprocess.check_output(bin_path, shell=True) nose.tools.assert_equal(result, output)