Пример #1
0
    def call(self, resolvable, arguments=(), abi=None, **kwargs):
        """Add a call to the ROP chain

        Arguments:
            resolvable(str,int): Value which can be looked up via 'resolve',
                or is already an integer.
            arguments(list): List of arguments which can be passed to pack().
                Alternately, if a base address is set, arbitrarily nested
                structures of strings or integers can be provided.
        """
        if self.migrated:
            log.error('Cannot append to a migrated chain')

        # If we can find a function with that name, just call it
        if isinstance(resolvable, str):
            addr = self.resolve(resolvable)
        elif hasattr(resolvable, 'name') and hasattr(resolvable, 'address'):
            addr = resolvable.address
            resolvable = str(resolvable.name)
        else:
            addr = resolvable
            resolvable = ''

        if addr:
            self.raw(Call(resolvable, addr, arguments, abi))

        # Otherwise, if it is a syscall we might be able to call it
        elif not self._srop_call(resolvable, arguments):
            log.error('Could not resolve %r.' % resolvable)
Пример #2
0
    def _srop_call(self, resolvable, arguments):
        # Check that the call is a valid syscall
        resolvable    = 'SYS_' + resolvable.lower()
        syscall_number = getattr(constants, resolvable, None)
        if syscall_number is None:
            return False

        log.info_once("Using sigreturn for %r" % resolvable)

        # Find an int 0x80 or similar instruction we can use
        syscall_gadget       = None
        syscall_instructions = srop.syscall_instructions[context.arch]

        for instruction in syscall_instructions:
            syscall_gadget = self.find_gadget([instruction])
            if syscall_gadget:
                break
        else:
            log.error("Could not find any instructions in %r" % syscall_instructions)

        # Generate the SROP frame which would invoke the syscall
        with context.local(arch=self.elfs[0].arch):
            frame         = srop.SigreturnFrame()
            frame.pc      = syscall_gadget
            frame.syscall = syscall_number

            try:
                SYS_sigreturn  = constants.SYS_sigreturn
            except AttributeError:
                SYS_sigreturn  = constants.SYS_rt_sigreturn

            for register, value in zip(frame.arguments, arguments):
                if not isinstance(value, six.integer_types + (Unresolved,)):
                    frame[register] = AppendedArgument(value)
                else:
                    frame[register] = value

        # Set up a call frame which will set EAX and invoke the syscall
        call = Call('SYS_sigreturn',
                    syscall_gadget,
                    [SYS_sigreturn],
                    abi.ABI.sigreturn())

        self.raw(call)
        self.raw(frame)


        # We do not expect to ever recover after the syscall, as it would
        # require something like 'int 0x80; ret' which does not ever occur
        # in the wild.
        self.migrated = True

        return True
Пример #3
0
    def ret2dlresolve(self, dlresolve):
        elf = next(elf for elf in self.elfs if elf.get_section_by_name(".plt"))
        elf_base = elf.address if elf.pie else 0
        plt_init = elf.get_section_by_name(".plt").header.sh_addr + elf_base
        log.debug("PLT_INIT: %#x", plt_init)

        reloc_index = dlresolve.reloc_index
        real_args = dlresolve.real_args
        call = Call("[plt_init] " + dlresolve.symbol.decode(),
                    plt_init,
                    dlresolve.real_args,
                    before=[reloc_index])
        self.raw(call)
Пример #4
0
        def __call__(self,
                     id: Union[int, str],
                     args: list,
                     ret: bool = False) -> None:
            '''Making system calls without the massive overhead of SIGROP
            >>> context.arch = 'amd64'
            >>> r = ROP('./binary')
            >>> r.system_call(0x3b, ['/bin/sh', 0, 0])
            >>> print(r.dump())
            0x0000:         0x41e4af pop rax; ret
            0x0008:             0x3b
            0x0010:         0x44a309 pop rdx; pop rsi; ret
            0x0018:              0x0 [arg2] rdx = 0
            0x0020:              0x0 [arg1] rsi = 0
            0x0028:         0x401696 pop rdi; ret
            0x0030:             0x40 [arg0] rdi = AppendedArgument(['/bin/sh'], 0x0)
            0x0038:         0x4022b4 syscall
            0x0040:   b'/bin/sh\x00'

            Arguments:
                `id`: integer syscall number OR string identifier for the syscall
                    if int: integer is used directly as register value for syscall
                    if str: The syscall number will be resolved with `pwnlib.constants`.
                `args`: arguments to the syscall
                `ret`: Specifically use a 'syscall; ret' gadget for syscalls (instead of 'syscall')
                    `ret` WILL NOT WORK unless you have the dev verison of pwntools installed.
            
            Returns:
                Nothing. Will raise errors if things go wrong.
            '''
            # get the syscall gadget
            if ret:
                if parse_version(PWNLIB_VER) < parse_version('4.4.0dev0'):
                    raise NotImplementedError(
                        '"syscall; ret" gadgets are only available on the '
                        'latest version of pwntools.')
                # pwnlib.rop.srop.syscall_instructions == {'amd64': ['syscall'], 'arm': ['svc 0'], ...}
                syscall = self.rop.find_gadget(
                    [rop.srop.syscall_instructions[context.arch][0], 'ret'])
            else:  # Can lazily use ROP's __getattr__ here
                syscall = self.rop.syscall
            if syscall is None:
                raise AttributeError("ROP unable to find syscall gadget")

            # write the syscall
            id, label = self.label(id)
            self.rop.raw(
                Call(label, syscall.address, [id] + args, ABI.syscall()))