def test_arm_postprocess_ret(): for i in xrange(3): # e91ba8f0 # ldmdb R11, {R4,R11,SP,PC} irsb = pyvex.IRSB(data=b'\xe9\x1b\xa8\xf0', mem_addr=0xed4028, arch=archinfo.ArchARMEL(endness=archinfo.Endness.BE), num_inst=1, opt_level=i) nose.tools.assert_equal(irsb.jumpkind, 'Ijk_Ret') # e91badf0 # ldmdb R11, {R4-R8,R10,R11,SP,PC} irsb = pyvex.IRSB(data=b'\xe9\x1b\xa8\xf0', mem_addr=0x4d4028, arch=archinfo.ArchARMEL(endness=archinfo.Endness.BE), num_inst=1, opt_level=i) nose.tools.assert_equal(irsb.jumpkind, 'Ijk_Ret') # 00a89de8 # ldmfd SP, {R11,SP,PC} # Fixed by Fish in the VEX fork, commit 43c78f608490f9a5c71c7fca87c04759c1b93741 irsb = pyvex.IRSB(data=b'\x00\xa8\x9d\xe8', mem_addr=0xc800b57c, arch=archinfo.ArchARMEL(endness=archinfo.Endness.LE), num_inst=1, opt_level=1) nose.tools.assert_equal(irsb.jumpkind, 'Ijk_Ret')
def test_arm_postprocess_ret(): for i in range(3): # e91ba8f0 # ldmdb R11, {R4,R11,SP,PC} irsb = pyvex.IRSB( data=b"\xe9\x1b\xa8\xf0", mem_addr=0xED4028, arch=archinfo.ArchARMEL(endness=archinfo.Endness.BE), num_inst=1, opt_level=i, ) assert irsb.jumpkind == "Ijk_Ret" # e91badf0 # ldmdb R11, {R4-R8,R10,R11,SP,PC} irsb = pyvex.IRSB( data=b"\xe9\x1b\xa8\xf0", mem_addr=0x4D4028, arch=archinfo.ArchARMEL(endness=archinfo.Endness.BE), num_inst=1, opt_level=i, ) assert irsb.jumpkind == "Ijk_Ret" # 00a89de8 # ldmfd SP, {R11,SP,PC} # Fixed by Fish in the VEX fork, commit 43c78f608490f9a5c71c7fca87c04759c1b93741 irsb = pyvex.IRSB( data=b"\x00\xa8\x9d\xe8", mem_addr=0xC800B57C, arch=archinfo.ArchARMEL(endness=archinfo.Endness.LE), num_inst=1, opt_level=1, ) assert irsb.jumpkind == "Ijk_Ret"
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 __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_arm_postprocess_ret(): for i in xrange(3): # e91ba8f0 # ldmdb R11, {R4,R11,SP,PC} irsb = pyvex.IRSB(data='\xe9\x1b\xa8\xf0', mem_addr=0xed4028, arch=archinfo.ArchARMEL(endness=archinfo.Endness.BE), num_inst=1, opt_level=i) nose.tools.assert_equal(irsb.jumpkind, 'Ijk_Ret') # e91badf0 # ldmdb R11, {R4-R8,R10,R11,SP,PC} irsb = pyvex.IRSB(data='\xe9\x1b\xa8\xf0', mem_addr=0x4d4028, arch=archinfo.ArchARMEL(endness=archinfo.Endness.BE), num_inst=1, opt_level=i) nose.tools.assert_equal(irsb.jumpkind, 'Ijk_Ret')
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 detect_arm_ivt(stream): """ :param stream: :type stream: file :return: """ min_arm_sp = 0x20000000 max_arm_sp = 0x20100000 # TODO: We're just looking at the front for now try: maybe_sp = stream.read(4) maybe_le_sp = struct.unpack('<I', maybe_sp)[0] maybe_be_sp = struct.unpack(">I", maybe_sp)[0] if min_arm_sp < maybe_le_sp < max_arm_sp: maybe_arch = archinfo.ArchARMEL(endness=archinfo.Endness.LE) l.debug( "Found possible Little-Endian ARM IVT with initial SP %#08x" % maybe_le_sp) maybe_entry = struct.unpack('<I', stream.read(4))[0] l.debug("Reset vector at %#08x" % maybe_entry) maybe_base = maybe_entry & 0xffff0000 # A complete guess l.debug("Guessing base address at %#08x" % maybe_base) return maybe_arch, maybe_base, maybe_entry elif min_arm_sp < maybe_be_sp < max_arm_sp: maybe_arch = archinfo.ArchARM(endness=archinfo.Endness.BE) l.debug("Found possible Big-Endian ARM IVT with initial SP %#08x" % maybe_be_sp) maybe_entry = struct.unpack('>I', stream.read(4))[0] l.debug("Reset vector at %#08x" % maybe_entry) maybe_base = maybe_entry & 0xffff0000 # A complete guess l.debug("Guessing base address at %#08x" % maybe_base) return maybe_arch, maybe_base, maybe_entry else: # Nope return (None, None, None) except: l.exception("Something died") return (None, None, None) finally: stream.seek(0)
def test_arm_postprocess(): for i in xrange(3): # Thumb # push {r7} # add r7, sp, #0 # mov.w r1, #6 # mov r0, pc # add.w lr, r0, r1 # b.w 10408 irsb = pyvex.IRSB(data=('\x80\xb4' '\x00\xaf' '\x4f\xf0\x06\x01' '\x78\x46' '\x00\xeb\x01\x0e' '\xff\xf7\xec\xbf'), mem_addr=0x1041f, arch=archinfo.ArchARMEL(), num_inst=6, bytes_offset=1, opt_level=i) nose.tools.assert_equals(irsb.jumpkind, 'Ijk_Call') # mov lr, pc # b.w 10408 irsb = pyvex.IRSB(data=('\xfe\x46' '\xe9\xe7'), mem_addr=0x10431, arch=archinfo.ArchARMEL(), num_inst=2, bytes_offset=1, opt_level=i) nose.tools.assert_equals(irsb.jumpkind, 'Ijk_Call') # add r2, pc, #0 # add.w lr, r2, #4 # ldr.w pc, [pc, #52] irsb = pyvex.IRSB(data=('\x00\xa2' '\x02\xf1\x06\x0e' '\xdf\xf8\x34\xf0'), mem_addr=0x10435, arch=archinfo.ArchARMEL(), num_inst=3, bytes_offset=1, opt_level=i) nose.tools.assert_equals(irsb.jumpkind, 'Ijk_Call') # ldr r0, [pc, #48] # mov r1, pc # add.w r2, r1, #4 # add.w r3, r2, #4 # add.w r4, r3, #4 # add.w lr, r4, #4 # mov pc, r0 irsb = pyvex.IRSB(data=('\x0c\x48' '\x79\x46' '\x01\xf1\x04\x02' '\x02\xf1\x04\x03' '\x03\xf1\x04\x04' '\x04\xf1\x04\x0e' '\x87\x46'), mem_addr=0x1043f, arch=archinfo.ArchARMEL(), num_inst=7, bytes_offset=1, opt_level=i) nose.tools.assert_equals(irsb.jumpkind, 'Ijk_Call') # eor.w r0, r0, r0 # mov lr, pc # b.n 10460 irsb = pyvex.IRSB(data=('\x80\xea\x00\x00' '\x86\x46' '\x01\xe0'), mem_addr=0x10455, arch=archinfo.ArchARMEL(), num_inst=3, bytes_offset=1, opt_level=i) nose.tools.assert_equals(irsb.jumpkind, 'Ijk_Boring') # Thumb compiled with optimizations (gcc -O2) # mov.w r1, #6 # mov r0, pc # add.w lr, r0, r1 # b.w 104bc irsb = pyvex.IRSB(data=('\x4f\xf0\x06\x01' '\x78\x46' '\x00\xeb\x01\x0e' '\x00\xf0\xc5\xb8'), mem_addr=0x10325, arch=archinfo.ArchARMEL(), num_inst=4, bytes_offset=1, opt_level=i) nose.tools.assert_equals(irsb.jumpkind, 'Ijk_Call') # ldr r0, [pc, #56] # mov r1, pc # add.w r2, r1, #4 # add.w r3, r2, #4 # add.w r4, r3, #4 # add.w lr, r4, #4 # mov pc, r0 irsb = pyvex.IRSB(data=('\x0e\x48' '\x79\x46' '\x01\xf1\x04\x02' '\x02\xf1\x04\x03' '\x03\xf1\x04\x04' '\x04\xf1\x04\x0e' '\x87\x46'), mem_addr=0x10333, arch=archinfo.ArchARMEL(), num_inst=7, bytes_offset=1, opt_level=i) nose.tools.assert_equals(irsb.jumpkind, 'Ijk_Call') # add r2, pc, #0 # add.w lr, r2, #6 # ldr.w pc, [pc, #28] irsb = pyvex.IRSB(data=('\x00\xa2' '\x02\xf1\x06\x0e' '\xdf\xf8\x1c\xf0'), mem_addr=0x10349, arch=archinfo.ArchARMEL(), num_inst=3, bytes_offset=1, opt_level=i) nose.tools.assert_equals(irsb.jumpkind, 'Ijk_Call') # mov lr, pc # b.w 104bc irsb = pyvex.IRSB(data=('\xfe\x46' '\xb2\xe0'), mem_addr=0x10353, arch=archinfo.ArchARMEL(), num_inst=2, bytes_offset=1, opt_level=i) nose.tools.assert_equals(irsb.jumpkind, 'Ijk_Call') # eor.w r0, r0, r0 # mov lr, pc # b.n 10362 irsb = pyvex.IRSB(data=('\x80\xea\x00\x00' '\x86\x46' '\x01\xe0'), mem_addr=0x10357, arch=archinfo.ArchARMEL(), num_inst=3, bytes_offset=1, opt_level=i) nose.tools.assert_equals(irsb.jumpkind, 'Ijk_Boring') # ARM compiled with optimizations (gcc -O2) # mov r1, #4 # mov r0, pc # add lr, r0, r1 # ldr pc, [pc, #56] irsb = pyvex.IRSB(data=('\x04\x10\xa0\xe3' '\x0f\x00\xa0\xe1' '\x01\xe0\x80\xe0' '\x38\xf0\x9f\xe5'), mem_addr=0x10298, arch=archinfo.ArchARMEL(), num_inst=4, opt_level=i) nose.tools.assert_equals(irsb.jumpkind, 'Ijk_Call') # add r1, pc, #0 # add r2, r1, #4 # add r3, r2, #4 # add r4, r3, #4 # add lr, r4, #4 # b 10414 irsb = pyvex.IRSB(data=('\x00\x10\x8f\xe2' '\x04\x20\x81\xe2' '\x04\x30\x82\xe2' '\x04\x40\x83\xe2' '\x04\xe0\x84\xe2' '\x54\x00\x00\xea'), mem_addr=0x102a8, arch=archinfo.ArchARMEL(), num_inst=6, opt_level=i) nose.tools.assert_equals(irsb.jumpkind, 'Ijk_Call') # mov lr, pc # b 10414 irsb = pyvex.IRSB(data=('\x0f\xe0\xa0\xe1' '\x52\x00\x00\xea'), mem_addr=0x102c0, arch=archinfo.ArchARMEL(), num_inst=2, opt_level=i) nose.tools.assert_equals(irsb.jumpkind, 'Ijk_Call') # eor r0, r0, r0 # mov lr, r0 # b 102d8 irsb = pyvex.IRSB(data=('\x00\x00\x20\xe0' '\x00\xe0\xa0\xe1' '\x00\x00\x00\xea'), mem_addr=0x102c8, arch=archinfo.ArchARMEL(), num_inst=3, opt_level=i) nose.tools.assert_equals(irsb.jumpkind, 'Ijk_Boring') # ARM # push {fp} # add fp, sp, #0 # mov r1, #4 # mov r0, pc # add lr, r0, r1 # ldr pc, [pc, #68] irsb = pyvex.IRSB(data=('\x04\xb0\x2d\xe5' '\x00\xb0\x8d\xe2' '\x04\x10\xa0\xe3' '\x0f\x00\xa0\xe1' '\x01\xe0\x80\xe0' '\x44\xf0\x9f\xe5'), mem_addr=0x103e8, arch=archinfo.ArchARMEL(), num_inst=6, opt_level=i) nose.tools.assert_equals(irsb.jumpkind, 'Ijk_Call') # add r1, pc, #0 # add r2, r1, #4 # add r3, r2, #4 # add r4, r3, #4 # add lr, r4, #4 # b 103c4 irsb = pyvex.IRSB(data=('\x00\x10\x8f\xe2' '\x04\x20\x81\xe2' '\x04\x30\x82\xe2' '\x04\x40\x83\xe2' '\x04\xe0\x84\xe2' '\x54\xff\xff\xea'), mem_addr=0x10400, arch=archinfo.ArchARMEL(), num_inst=6, opt_level=i) nose.tools.assert_equals(irsb.jumpkind, 'Ijk_Call') # mov lr, pc # b 103c4 irsb = pyvex.IRSB(data=('\x0f\xe0\xa0\xe1' '\xe8\xff\xff\xea'), mem_addr=0x10418, arch=archinfo.ArchARMEL(), num_inst=2, opt_level=i) nose.tools.assert_equals(irsb.jumpkind, 'Ijk_Call') # eor r0, r0, r0 # mov lr, r0 # b 10430 irsb = pyvex.IRSB(data=('\x00\x00\x20\xe0' '\x00\xe0\xa0\xe1' '\x00\x00\x00\xea'), mem_addr=0x10420, arch=archinfo.ArchARMEL(), num_inst=3, opt_level=i) nose.tools.assert_equals(irsb.jumpkind, 'Ijk_Boring')
def test_arm_postprocess_call(): for i in range(3): # Thumb # push {r7} # add r7, sp, #0 # mov.w r1, #6 # mov r0, pc # add.w lr, r0, r1 # b.w 10408 irsb = pyvex.IRSB( data=( b"\x80\xb4" b"\x00\xaf" b"\x4f\xf0\x06\x01" b"\x78\x46" b"\x00\xeb\x01\x0e" b"\xff\xf7\xec\xbf" ), mem_addr=0x1041F, arch=archinfo.ArchARMEL(), num_inst=6, bytes_offset=1, opt_level=i, ) assert irsb.jumpkind == "Ijk_Call" # mov lr, pc # b.w 10408 irsb = pyvex.IRSB( data=(b"\xfe\x46" b"\xe9\xe7"), mem_addr=0x10431, arch=archinfo.ArchARMEL(), num_inst=2, bytes_offset=1, opt_level=i, ) assert irsb.jumpkind == "Ijk_Call" # add r2, pc, #0 # add.w lr, r2, #4 # ldr.w pc, [pc, #52] irsb = pyvex.IRSB( data=(b"\x00\xa2" b"\x02\xf1\x06\x0e" b"\xdf\xf8\x34\xf0"), mem_addr=0x10435, arch=archinfo.ArchARMEL(), num_inst=3, bytes_offset=1, opt_level=i, ) assert irsb.jumpkind == "Ijk_Call" # ldr r0, [pc, #48] # mov r1, pc # add.w r2, r1, #4 # add.w r3, r2, #4 # add.w r4, r3, #4 # add.w lr, r4, #4 # mov pc, r0 irsb = pyvex.IRSB( data=( b"\x0c\x48" b"\x79\x46" b"\x01\xf1\x04\x02" b"\x02\xf1\x04\x03" b"\x03\xf1\x04\x04" b"\x04\xf1\x04\x0e" b"\x87\x46" ), mem_addr=0x1043F, arch=archinfo.ArchARMEL(), num_inst=7, bytes_offset=1, opt_level=i, ) assert irsb.jumpkind == "Ijk_Call" # eor.w r0, r0, r0 # mov lr, pc # b.n 10460 irsb = pyvex.IRSB( data=(b"\x80\xea\x00\x00" b"\x86\x46" b"\x01\xe0"), mem_addr=0x10455, arch=archinfo.ArchARMEL(), num_inst=3, bytes_offset=1, opt_level=i, ) assert irsb.jumpkind == "Ijk_Boring" # Thumb compiled with optimizations (gcc -O2) # mov.w r1, #6 # mov r0, pc # add.w lr, r0, r1 # b.w 104bc irsb = pyvex.IRSB( data=( b"\x4f\xf0\x06\x01" b"\x78\x46" b"\x00\xeb\x01\x0e" b"\x00\xf0\xc5\xb8" ), mem_addr=0x10325, arch=archinfo.ArchARMEL(), num_inst=4, bytes_offset=1, opt_level=i, ) assert irsb.jumpkind == "Ijk_Call" # ldr r0, [pc, #56] # mov r1, pc # add.w r2, r1, #4 # add.w r3, r2, #4 # add.w r4, r3, #4 # add.w lr, r4, #4 # mov pc, r0 irsb = pyvex.IRSB( data=( b"\x0e\x48" b"\x79\x46" b"\x01\xf1\x04\x02" b"\x02\xf1\x04\x03" b"\x03\xf1\x04\x04" b"\x04\xf1\x04\x0e" b"\x87\x46" ), mem_addr=0x10333, arch=archinfo.ArchARMEL(), num_inst=7, bytes_offset=1, opt_level=i, ) assert irsb.jumpkind == "Ijk_Call" # add r2, pc, #0 # add.w lr, r2, #6 # ldr.w pc, [pc, #28] irsb = pyvex.IRSB( data=(b"\x00\xa2" b"\x02\xf1\x06\x0e" b"\xdf\xf8\x1c\xf0"), mem_addr=0x10349, arch=archinfo.ArchARMEL(), num_inst=3, bytes_offset=1, opt_level=i, ) assert irsb.jumpkind == "Ijk_Call" # mov lr, pc # b.w 104bc irsb = pyvex.IRSB( data=(b"\xfe\x46" b"\xb2\xe0"), mem_addr=0x10353, arch=archinfo.ArchARMEL(), num_inst=2, bytes_offset=1, opt_level=i, ) assert irsb.jumpkind == "Ijk_Call" # eor.w r0, r0, r0 # mov lr, pc # b.n 10362 irsb = pyvex.IRSB( data=(b"\x80\xea\x00\x00" b"\x86\x46" b"\x01\xe0"), mem_addr=0x10357, arch=archinfo.ArchARMEL(), num_inst=3, bytes_offset=1, opt_level=i, ) assert irsb.jumpkind == "Ijk_Boring" # ARM compiled with optimizations (gcc -O2) # mov r1, #4 # mov r0, pc # add lr, r0, r1 # ldr pc, [pc, #56] irsb = pyvex.IRSB( data=( b"\x04\x10\xa0\xe3" b"\x0f\x00\xa0\xe1" b"\x01\xe0\x80\xe0" b"\x38\xf0\x9f\xe5" ), mem_addr=0x10298, arch=archinfo.ArchARMEL(), num_inst=4, opt_level=i, ) assert irsb.jumpkind == "Ijk_Call" # add r1, pc, #0 # add r2, r1, #4 # add r3, r2, #4 # add r4, r3, #4 # add lr, r4, #4 # b 10414 irsb = pyvex.IRSB( data=( b"\x00\x10\x8f\xe2" b"\x04\x20\x81\xe2" b"\x04\x30\x82\xe2" b"\x04\x40\x83\xe2" b"\x04\xe0\x84\xe2" b"\x54\x00\x00\xea" ), mem_addr=0x102A8, arch=archinfo.ArchARMEL(), num_inst=6, opt_level=i, ) assert irsb.jumpkind == "Ijk_Call" # mov lr, pc # b 10414 irsb = pyvex.IRSB( data=(b"\x0f\xe0\xa0\xe1" b"\x52\x00\x00\xea"), mem_addr=0x102C0, arch=archinfo.ArchARMEL(), num_inst=2, opt_level=i, ) assert irsb.jumpkind == "Ijk_Call" # eor r0, r0, r0 # mov lr, r0 # b 102d8 irsb = pyvex.IRSB( data=(b"\x00\x00\x20\xe0" b"\x00\xe0\xa0\xe1" b"\x00\x00\x00\xea"), mem_addr=0x102C8, arch=archinfo.ArchARMEL(), num_inst=3, opt_level=i, ) assert irsb.jumpkind == "Ijk_Boring" # ARM # push {fp} # add fp, sp, #0 # mov r1, #4 # mov r0, pc # add lr, r0, r1 # ldr pc, [pc, #68] irsb = pyvex.IRSB( data=( b"\x04\xb0\x2d\xe5" b"\x00\xb0\x8d\xe2" b"\x04\x10\xa0\xe3" b"\x0f\x00\xa0\xe1" b"\x01\xe0\x80\xe0" b"\x44\xf0\x9f\xe5" ), mem_addr=0x103E8, arch=archinfo.ArchARMEL(), num_inst=6, opt_level=i, ) assert irsb.jumpkind == "Ijk_Call" # add r1, pc, #0 # add r2, r1, #4 # add r3, r2, #4 # add r4, r3, #4 # add lr, r4, #4 # b 103c4 irsb = pyvex.IRSB( data=( b"\x00\x10\x8f\xe2" b"\x04\x20\x81\xe2" b"\x04\x30\x82\xe2" b"\x04\x40\x83\xe2" b"\x04\xe0\x84\xe2" b"\x54\xff\xff\xea" ), mem_addr=0x10400, arch=archinfo.ArchARMEL(), num_inst=6, opt_level=i, ) assert irsb.jumpkind == "Ijk_Call" # mov lr, pc # b 103c4 irsb = pyvex.IRSB( data=(b"\x0f\xe0\xa0\xe1" b"\xe8\xff\xff\xea"), mem_addr=0x10418, arch=archinfo.ArchARMEL(), num_inst=2, opt_level=i, ) assert irsb.jumpkind == "Ijk_Call" # eor r0, r0, r0 # mov lr, r0 # b 10430 irsb = pyvex.IRSB( data=(b"\x00\x00\x20\xe0" b"\x00\xe0\xa0\xe1" b"\x00\x00\x00\xea"), mem_addr=0x10420, arch=archinfo.ArchARMEL(), num_inst=3, opt_level=i, ) assert irsb.jumpkind == "Ijk_Boring" # From a "real thing" compiled with armc # ARM: # irsb = pyvex.IRSB( data=( b"H\x10\x9b\xe5" b"\x0b\x00\xa0\xe1" b"\x04 \x91\xe5" b"\x04\xe0\x8f\xe2" b"\x01\x10\x82\xe0" b"\x01\xf0\xa0\xe1" ), mem_addr=0x264B4C, arch=archinfo.ArchARMEL(), num_inst=6, opt_level=i, ) assert irsb.jumpkind == "Ijk_Call"
class BinjaBin(Backend): """ Get information from binaries using Binary Ninja. Basing this on idabin.py, but will try to be more complete. TODO: add more features as Binary Ninja's feature set improves """ is_default = True # Tell CLE to automatically consider using the BinjaBin backend BINJA_ARCH_MAP = { "aarch64": archinfo.ArchAArch64(endness='Iend_LE'), "armv7": archinfo.ArchARMEL(endness='Iend_LE'), "thumb2": archinfo.ArchARMEL(endness='Iend_LE'), "armv7eb": archinfo.ArchARMEL(endness='Iend_BE'), "thumb2eb": archinfo.ArchARMEL(endness='Iend_BE'), "mipsel32": archinfo.ArchMIPS32(endness='Iend_LE'), "mips32": archinfo.ArchMIPS32(endness='Iend_BE'), "ppc": archinfo.ArchPPC32(endness="Iend_BE"), "ppc_le": archinfo.ArchPPC32(endness="Iend_LE"), "x86": archinfo.ArchX86(), "x86_64": archinfo.ArchAMD64() } def __init__(self, binary, *args, **kwargs): super().__init__(binary, *args, **kwargs) if not bn: raise CLEError(BINJA_NOT_INSTALLED_STR) # get_view_of_file can take a bndb or binary - wait for autoanalysis to complete self.bv = bn.BinaryViewType.get_view_of_file(binary, False) l.info("Analyzing %s, this may take some time...", binary) self.bv.update_analysis_and_wait() l.info("Analysis complete") # Note may want to add option to kick off linear sweep try: self.set_arch(self.BINJA_ARCH_MAP[self.bv.arch.name]) except KeyError: l.error("Architecture %s is not supported.", self.bv.arch.name) for seg in self.bv.segments: l.info("Adding memory for segment at %x.", seg.start) br = bn.BinaryReader(self.bv) br.seek(seg.start) data = br.read(len(seg)) self.memory.add_backer(seg.start, data) self._find_got() self._symbol_cache = {} self._init_symbol_cache() # Note: this represents the plt stub. ImportAddressSymbol refers to .got entries # Since we're not trying to import and load dependencies directly, but want to run SimProcedures, # We should use the binaryninja.SymbolType.ImportedFunctionSymbol # Also this should be generalized to get data imports, too self.raw_imports = { i.name: i.address for i in self.bv.get_symbols_of_type( bn.SymbolType.ImportedFunctionSymbol) } self._process_imports() self.exports = {} self.linking = "static" if len(self.raw_imports) == 0 else "dynamic" # We'll look for this attribute to see if we need to do SimProcedures for any imports in this binary # This is an ugly hack, but will have to use this for now until Binary Ninja exposes dependencies self.guess_simprocs = True self.guess_simprocs_hint = "nix" if self.bv.get_section_by_name( ".plt") else "win" l.warning("This backend is based on idabin.py.\n\ You may encounter unexpected behavior if:\n\ \tyour target depends on library data symbol imports, or\n\ \tlibrary imports that don't have a guess-able SimProcedure\n\ Good luck!") def _process_imports(self): ''' Process self.raw_imports into list of Relocation objects ''' if not self.raw_imports: l.warning( "No imports found - if this is a dynamically-linked binary, something probably went wrong." ) for name, addr in self.raw_imports.items(): BinjaReloc(self, self._symbol_cache[name], addr) def _init_symbol_cache(self): # Note that we could also access name, short_name, or full_name attributes for sym in self.bv.get_symbols(): cle_sym = BinjaSymbol(self, sym) self._symbol_cache[sym.raw_name] = cle_sym self.symbols.add(cle_sym) def _find_got(self): """ Locate the section (e.g. .got) that should be updated when relocating functions (that's where we want to write absolute addresses). """ sec_name = self.arch.got_section_name self.got_begin = None self.got_end = None try: got_sec = self.bv.sections[self.arch.got_section_name] self.got_begin = got_sec.start self.got_end = got_sec.end except KeyError: l.warning("No got section mapping found!") # If we reach this point, we should have the addresses if self.got_begin is None or self.got_end is None: l.warning("No section %s, is this a static binary ? (or stripped)", sec_name) return False return True @staticmethod def is_compatible(stream): if not bn: return False magic = stream.read(100) stream.seek(0) # bndb files are SQlite 3 if magic.startswith(b"SQLite format 3") and stream.name.endswith( "bndb"): return True return False def in_which_segment(self, addr): """ Return the segment name at address `addr`. """ # WARNING: if there are overlapping sections, we choose the first name. # The only scenario I've seen here is a NOBITS section that "overlaps" with another one, but # I'm not sure if that's a heurstic that should be applied here. # https://stackoverflow.com/questions/25501044/gcc-ld-overlapping-sections-tbss-init-array-in-statically-linked-elf-bin#25771838 seg = self.bv.get_sections_at(addr)[0].name return "unknown" if len(seg) == 0 else seg def get_symbol_addr(self, sym): """ Get the address of the symbol `sym` from IDA. :returns: An address. """ # sym is assumed to be the raw_name of the symbol return self.bv.get_symbol_by_raw_name(sym) def function_name(self, addr): """ Return the function name at address `addr`. """ func = self.bv.get_function_at(addr) if not func: return "UNKNOWN" return func.name @property def min_addr(self): """ Get the min address of the binary. (note: this is probably not "right") """ return self.bv.start @property def max_addr(self): """ Get the max address of the binary. """ return self.bv.end @property def entry(self): if self._custom_entry_point is not None: return self._custom_entry_point + self.mapped_base return self.bv.entry_point + self.mapped_base def get_strings(self): """ Extract strings from binary (Binary Ninja). :returns: An array of strings. """ return self.bv.get_strings() def set_got_entry(self, name, newaddr): """ Resolve import `name` with address `newaddr`. That is, update the GOT entry for `name` with `newaddr`. """ if name not in self.imports: l.warning("%s not in imports", name) return addr = self.imports[name] self.memory.pack_word(addr, newaddr) def close(self): """ Release the BinaryView we created in __init__ :return: None """ self.bv.file.close()
def __init__(self, binary, **kwargs): super(ELF, self).__init__(binary, **kwargs) 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()
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])