Esempio n. 1
0
def popMultiple(args, constraint=None, assertion=None, clmax=None, optimizeLen=False):
    """
    args is a list of pairs (reg, value) 
        OR a list of triples (reg, value, comment)
    reg is a reg UID
    value is an int
    Creates a chain that pops values into regs
    """
    if( clmax is None ):
        clmax = POP_MULTIPLE_LMAX
    elif( clmax <= 0 ):
        return None
    
    if( constraint is None ):
        constr = Constraint()
    else:
        constr = constraint
    if( assertion is None ):
        a = Assertion()
    else:
        a = assertion
        
    perms = itertools.permutations(args)
    for perm in perms:
        clmax_tmp = clmax 
        res = ROPChain()
        constr_tmp = constr
        for arg in perm:
            if( len(arg) == 3 ):
                comment = arg[2]
            else:
                comment = None
            if( optimizeLen ):
                pop = search(QueryType.CSTtoREG, arg[0], arg[1], constr_tmp, a, n=1, clmax=clmax_tmp, CSTtoREG_comment=comment, optimizeLen=True)
            else:
                pop = search(QueryType.CSTtoREG, arg[0], arg[1], constr_tmp, a, n=1, clmax=clmax_tmp, CSTtoREG_comment=comment)
            if( not pop ):
                break
            else:
                clmax_tmp -= len(pop[0])
                # If Reached max length, exit  
                if( clmax_tmp < 0 ):
                    pop = None
                    break
                else:
                    res.addChain(pop[0])
                    constr_tmp = constr_tmp.add(RegsNotModified([arg[0]]))
        if( pop ):
            return res
    return None
Esempio n. 2
0
def build_mprotect64(addr, size, prot=7, constraint=None, assertion=None, clmax=SYSCALL_LMAX, optimizeLen=False):
    """
    Call mprotect from X86-64 arch
    Args must be on registers (rdi, rsi, rdx):
    Sizes are (unsigned long, size_t, unsigned long)
    rax must be 10 
    """
    # Check args
    if not isinstance(addr, int):
        error("Argument error. Expected integer, got " + str(type(addr)))
        return None
    elif not isinstance(size, int):
        error("Argument error. Expected integer, got " + str(type(size)))
        return None
    elif not isinstance(prot, int):
        error("Argument error. Expected integer, got " + str(type(prot)))
        return None
    
    if( constraint is None ):
        constraint = Constraint()
    if( assertion is None ):
        assertion = Assertion()
    
    # Check if we have the function !
    verbose("Trying to call mprotect() function directly")
    func_call = build_call('mprotect', [addr, size, prot], constraint, assertion, clmax=clmax, optimizeLen=optimizeLen)
    if( not isinstance(func_call, str) ):
        verbose("Success")
        return func_call
    else:
        if( not constraint.chainable.ret ):
            verbose("Coudn't call mprotect(), try direct syscall")
        else:
            verbose("Couldn't call mprotect() and return to ROPChain")
            return None
    
    # Otherwise do the syscall by 'hand' 
    # Set the registers
    args = [[Arch.n2r('rdi'),addr],[Arch.n2r('rsi'), size],[Arch.n2r('rdx'),prot], [Arch.n2r('rax'),10]]
    chain = popMultiple(args, constraint, assertion, clmax-1, optimizeLen)
    if( not chain ):
        verbose("Failed to set registers for the mprotect syscall")
        return None
    # Syscall 
    syscalls = search(QueryType.SYSCALL, None, None, constraint, assertion)
    if( not syscalls ):
        verbose("Failed to find a syscall gadget")
        return None
    else:
        chain.addChain(syscalls[0])
    verbose("Success")
    return chain
Esempio n. 3
0
def build_call(funcName, funcArgs, constraint, assertion):
    # Find the address of the fonction
    (funcName2, funcAddr) = getFunctionAddress(funcName)
    if (funcName2 is None):
        return "Couldn't find function '{}' in the binary".format(funcName)

    # Check if bad bytes in function address
    if (not constraint.badBytes.verifyAddress(funcAddr)):
        return "'{}' address ({}) contains bad bytes".format(
            funcName2,
            string_special('0x' + format(funcAddr, '0' +
                                         str(Arch.octets() * 2) + 'x')))

    # Find a gadget for the fake return address
    offset = len(
        funcArgs) * 8 - 8  # Because we do +8 at the beginning of the loop
    skip_args_chains = []
    i = 4
    while (i > 0 and (not skip_args_chains)):
        offset += 8
        skip_args_chains = search(QueryType.MEMtoREG, Arch.ipNum(), \
                    (Arch.spNum(),offset), constraint, assertion, n=1)
        i -= 1

    if (not skip_args_chains):
        return "Couldn't build ROP-Chain"
    skip_args_chain = skip_args_chains[0]

    # Build the ropchain with the arguments
    args_chain = ROPChain()
    arg_n = len(funcArgs)
    for arg in reversed(funcArgs):
        if (isinstance(arg, int)):
            args_chain.addPadding(arg,
                                  comment="Arg{}: {}".format(
                                      arg_n, string_ropg(hex(arg))))
            arg_n -= 1
        else:
            return "Type of argument '{}' not supported yet :'(".format(arg)

    # Build call chain (function address + fake return address)
    call_chain = ROPChain()
    call_chain.addPadding(funcAddr, comment=string_ropg(funcName2))
    skip_args_addr = int(
        validAddrStr(skip_args_chain.chain[0], constraint.getBadBytes(),
                     Arch.bits()), 16)
    call_chain.addPadding(skip_args_addr,
                          comment="Address of: " +
                          string_bold(str(skip_args_chain.chain[0])))

    return call_chain.addChain(args_chain)
Esempio n. 4
0
def build_call_linux86(funcName, funcArgs, constraint, assertion, clmax=None, optimizeLen=False):
    # Find the address of the fonction 
    (funcName2, funcAddr) = getFunctionAddress(funcName)
    if( funcName2 is None ):
        return "Couldn't find function '{}' in the binary".format(funcName)
    
    # Check if bad bytes in function address 
    if( not constraint.badBytes.verifyAddress(funcAddr) ):
        return "'{}' address ({}) contains bad bytes".format(funcName2, string_special('0x'+format(funcAddr, '0'+str(Arch.octets()*2)+'x')))
    
    # Check if lmax too small
    if( (1 + len(funcArgs) + (lambda x: 1 if len(x)>0 else 0)(funcArgs)) > clmax ):
        return "Not enough bytes to call function '{}'".format(funcName)
    
    # Find a gadget for the fake return address
    if( funcArgs ):
        offset = (len(funcArgs)-1)*Arch.octets() # Because we do +octets() at the beginning of the loop
        skip_args_chains = []
        i = 4 # Try 4 more maximum 
        while( i > 0 and (not skip_args_chains)):
            offset += Arch.octets() 
            skip_args_chains = search(QueryType.MEMtoREG, Arch.ipNum(), \
                        (Arch.spNum(),offset), constraint, assertion, n=1, optimizeLen=optimizeLen)
            i -= 1
            
        if( not skip_args_chains ):
            return "Couldn't build ROP-Chain"
        skip_args_chain = skip_args_chains[0]
    else:
        # No arguments 
        skip_args_chain = None
    
    # Build the ropchain with the arguments 
    args_chain = ROPChain()
    arg_n = len(funcArgs)
    for arg in reversed(funcArgs):
        if( isinstance(arg, int) ):
            args_chain.addPadding(arg, comment="Arg{}: {}".format(arg_n, string_ropg(hex(arg))))
            arg_n -= 1
        else:
            return "Type of argument '{}' not supported yet :'(".format(arg)
    
    # Build call chain (function address + fake return address)
    call_chain = ROPChain()
    call_chain.addPadding(funcAddr, comment=string_ropg(funcName2))
    if( funcArgs ):
        skip_args_addr = int( validAddrStr(skip_args_chain.chain[0], constraint.getBadBytes(), Arch.bits())  ,16)
        call_chain.addPadding(skip_args_addr, comment="Address of: "+string_bold(str(skip_args_chain.chain[0])))
    
    return call_chain.addChain(args_chain)
Esempio n. 5
0
def find(args):
    """
    args - List of user arguments as strings
    (the command should not be included in the list as args[0])
    """
    if (not args):
        print_help()
        return

    if (args[0] == OPTION_HELP or args[0] == OPTION_HELP_SHORT):
        print_help()
        return

    parsed_args = parse_args(args)
    if (not parsed_args[0]):
        error(parsed_args[1])
    else:
        qtype = parsed_args[1]
        arg1 = parsed_args[2]
        arg2 = parsed_args[3]
        constraint = parsed_args[4]
        nbResults = parsed_args[5]
        clmax = parsed_args[6]
        assertion = Assertion().add(\
            RegsValidPtrRead([(Arch.spNum(),-5000, 10000)])).add(\
            RegsValidPtrWrite([(Arch.spNum(), -5000, 0)]))
        # Search
        res = search(qtype,
                     arg1,
                     arg2,
                     constraint,
                     assertion,
                     n=nbResults,
                     clmax=clmax)
        if (res):
            print_chains(res, "Built matching ROPChain(s)",
                         constraint.getBadBytes())
        else:
            res = search_not_chainable(qtype,
                                       arg1,
                                       arg2,
                                       constraint,
                                       assertion,
                                       n=nbResults,
                                       clmax=clmax)
            print_chains(res, "Possibly matching gadget(s)",
                         constraint.getBadBytes())
Esempio n. 6
0
def find(args):
    """
    args - List of user arguments as strings
    (the command should not be included in the list as args[0])
    """
    if (not args):
        print_help()
        return

    if (args[0] == OPTION_HELP or args[0] == OPTION_HELP_SHORT):
        print_help()
        return

    parsed_args = parse_args(args)
    if (not parsed_args[0]):
        error(parsed_args[1])
    else:
        qtype = parsed_args[1]
        arg1 = parsed_args[2]
        arg2 = parsed_args[3]
        constraint = parsed_args[4]
        nbResults = parsed_args[5]
        clmax = parsed_args[6]
        optimizeLen = parsed_args[7]
        assertion = getBaseAssertion()
        # Search
        res = search(qtype,
                     arg1,
                     arg2,
                     constraint,
                     assertion,
                     n=nbResults,
                     clmax=clmax,
                     optimizeLen=optimizeLen)
        if (res):
            print_chains(res, "Built matching ROPChain(s)",
                         constraint.getBadBytes())
        else:
            res = search_not_chainable(qtype,
                                       arg1,
                                       arg2,
                                       constraint,
                                       assertion,
                                       n=nbResults,
                                       clmax=clmax)
            print_chains(res, "Possibly matching gadget(s)",
                         constraint.getBadBytes())
Esempio n. 7
0
def build_mprotect64(addr,
                     size,
                     prot=7,
                     constraint=None,
                     assertion=None,
                     clmax=None,
                     optimizeLen=False):
    """
    Call mprotect from X86-64 arch
    Args must be on registers (rdi, rsi, rdx):
    Sizes are (unsigned long, size_t, unsigned long)
    rax must be 10 
    """
    # Check args
    if not isinstance(addr, int):
        error("Argument error. Expected integer, got " + str(type(addr)))
        return None
    elif not isinstance(size, int):
        error("Argument error. Expected integer, got " + str(type(size)))
        return None
    elif not isinstance(prot, int):
        error("Argument error. Expected integer, got " + str(type(prot)))
        return None

    if (constraint is None):
        constraint = Constraint()
    if (assertion is None):
        assertion = Assertion()

    # Set the registers
    args = [[Arch.n2r('rdi'), addr], [Arch.n2r('rsi'), size],
            [Arch.n2r('rdx'), prot], [Arch.n2r('rax'), 10]]
    chain = popMultiple(args, constraint, assertion, clmax - 1, optimizeLen)
    if (not chain):
        verbose("Failed to set registers for the mprotect syscall")
        return None
    # Syscall
    syscalls = search(QueryType.SYSCALL, None, None, constraint, assertion)
    if (not syscalls):
        verbose("Failed to find a syscall gadget")
        return None
    else:
        chain.addChain(syscalls[0])
    verbose("Success")
    return chain
Esempio n. 8
0
def build_mprotect32(addr, size, prot=7, constraint=None, assertion = None, clmax=None, optimizeLen=False):
    """
    Call mprotect from X86 arch
    Args must be on the stack:
    int mprotect(void *addr, size_t len, int prot)
    args must be in registers (ebx, ecx, edx)
    eax must be 0x7d = 125
    """
    # Check args
    if not isinstance(addr, int):
        error("Argument error. Expected integer, got " + str(type(addr)))
        return None
    elif not isinstance(size, int):
        error("Argument error. Expected integer, got " + str(type(size)))
        return None
    elif not isinstance(prot, int):
        error("Argument error. Expected integer, got " + str(type(prot)))
        return None
        
    if( constraint is None ):
        constraint = Constraint()
    if( assertion is None ):
        assertion = Assertion()
    
    # Set the registers
    args = [[Arch.n2r('eax'),0x7d],[Arch.n2r('ebx'), addr],[Arch.n2r('ecx'),size], [Arch.n2r('edx'),prot]]
    chain = popMultiple(args, constraint, assertion, clmax-1, optimizeLen)
    if( not chain ):
        verbose("Failed to set registers for the mprotect syscall")
        return None
    # Int 0x80
    int80_gadgets = search(QueryType.INT80, None, None, constraint, assertion)
    if( not int80_gadgets ):
        verbose("Failed to find an 'int 80' gadget")
        return None
    else:
        chain.addChain(int80_gadgets[0])
    verbose("Success")
    return chain
Esempio n. 9
0
def build_dshell(shellcode, constraint, assertion, address, limit, lmax):
    """
    Returns a PwnChain() instance or None
    """
    # Build exploit
    #################

    res = PwnChain()

    #Find address for the payload
    if (not address):
        # Get the .bss address
        # TODO
        notify("Getting delivery address for shellcode")
        address = getSectionAddress('.bss')
        addr_str = ".bss"
        if (not address):
            verbose("Couldn't find .bss address")
            return []
    else:
        addr_str = hex(address)

    if (not limit):
        limit = address + Arch.minPageSize()

    # Deliver shellcode
    notify("Building chain to copy shellcode in memory")
    verbose("{}/{} bytes available".format(lmax * Arch.octets(),
                                           lmax * Arch.octets()))
    (shellcode_address, STRtoMEM_chain) = STRtoMEM(shellcode,
                                                   address,
                                                   constraint,
                                                   assertion,
                                                   limit=limit,
                                                   lmax=lmax,
                                                   addr_str=addr_str,
                                                   hex_info=True,
                                                   optimizeLen=True)
    address = shellcode_address
    addr_str = hex(address)
    if (not STRtoMEM_chain):
        verbose("Could not copy shellcode into memory")
        return None

    # Building mprotect
    notify("Building mprotect() chain")
    # Getting page to make executable
    # Arg of mprotect MUST be a valid multiple of page size
    over_page_size = address % Arch.minPageSize()
    page_address = address - over_page_size
    length = len(shellcode) + 1 + over_page_size
    flag = 7
    lmax2 = lmax - len(STRtoMEM_chain)
    verbose("{}/{} bytes available".format(lmax2 * Arch.octets(),
                                           lmax * Arch.octets()))
    if (lmax2 <= 0):
        return None
    if (Arch.currentArch == Arch.ArchX86):
        mprotect_chain = build_mprotect32(page_address,
                                          length,
                                          flag,
                                          constraint.add(Chainable(ret=True)),
                                          assertion,
                                          clmax=lmax2 - 2,
                                          optimizeLen=True)
    elif (Arch.currentArch == Arch.ArchX64):
        mprotect_chain = build_mprotect64(page_address,
                                          length,
                                          flag,
                                          constraint.add(Chainable(ret=True)),
                                          assertion,
                                          clmax=lmax2 - 2,
                                          optimizeLen=True)
    else:
        mprotect_chain = None
        verbose("mprotect call not supported for architecture {}".format(
            Arch.currentArch.name))
        return None
    if (not mprotect_chain):
        return None
    verbose("Done")

    # Jump to shellcode
    notify("Searching chain to jump to shellcode")
    verbose("{}/{} bytes available".format(
        (lmax2 - len(mprotect_chain)) * Arch.octets(), lmax * Arch.octets()))
    jmp_shellcode_chains = search(QueryType.CSTtoREG,
                                  Arch.ipNum(),
                                  address,
                                  constraint,
                                  assertion,
                                  clmax=lmax - len(STRtoMEM_chain) -
                                  len(mprotect_chain),
                                  optimizeLen=True)
    if (not jmp_shellcode_chains):
        verbose("Couldn't find a jump to the shellcode")
        return None
    verbose("Done")
    notify("Done")

    # Build PwnChain res and return
    res.add(mprotect_chain,
            "Call mprotect({},{},{})".format(hex(page_address), length, flag))
    res.add(STRtoMEM_chain, "Copy shellcode to {}".format(addr_str))
    res.add(jmp_shellcode_chains[0],
            "Jump to shellcode (address {})".format(addr_str))
    return res
Esempio n. 10
0
def store_constant_address(qtype,
                           cst_addr,
                           value,
                           constraint=None,
                           assertion=None,
                           clmax=None,
                           optimizeLen=False):
    """
    Does a XXXtoMEM kind of query BUT the memory address is 
    a simple constant ! 
    
    Expected qtypes are only XXXtoMEM
    cst_addr is the store address
    value is the value to store, a single cst or a couple (reg,cst)
    """
    if (clmax is None):
        clmax = STORE_CONSTANT_ADDRESS_LMAX
    elif (clmax <= 0):
        return None

    if (constraint is None):
        constr = Constraint()
    else:
        constr = constraint
    if (assertion is None):
        a = Assertion()
    else:
        a = assertion

    # Tranform the query type
    if (qtype == QueryType.CSTtoMEM):
        qtype2 = QueryType.CSTtoREG
    elif (qtype == QueryType.REGtoMEM):
        qtype2 = QueryType.REGtoREG
    elif (qtype == QueryType.MEMtoREG):
        qtype2 = QueryType.MEMtoREG
    else:
        raise Exception(
            "Query type {} should not appear in this function!".format(qtype))

    tried_values = []
    tried_cst_addr = []
    best = None  # If optimizeLen
    shortest = clmax  # Shortest ROPChain found if optimizeLen ;)

    for ((addr_reg, addr_cst), (reg,cst), gadget) in \
    sorted(DBAllPossibleWrites(constr.add(Chainable(ret=True)), a), \
    key=lambda x: 0 if (x[1] == value) else 1) :
        # DOn't use rip or rsp...
        if( reg == Arch.ipNum() or reg == Arch.spNum()\
            or addr_reg == Arch.ipNum() or addr_reg == Arch.spNum()):
            continue
        res = None
        # Check if directly the registers we want to write ;)
        value_is_reg = False
        value_to_reg = []
        addr_to_reg = []
        if ((reg, cst) == value):
            value_to_reg = [ROPChain()]
            value_is_reg = True

        # adapt value
        if (not isinstance(value, tuple)):
            adjusted_value = value - cst
        else:
            adjusted_value = (value[0], value[1] - cst)
        adjusted_cst_addr = cst_addr - addr_cst
        # Get spInc
        gadget_paddingLen = (gadget.spInc / Arch.octets()) - 1
        # Check if tried before
        if ((reg, cst) in tried_values):
            continue
        elif ((addr_reg, addr_cst) in tried_cst_addr):
            continue
        ### Try to do reg first then addr_reg
        # Try to put the value into reg
        clmax2 = shortest - gadget_paddingLen - 1
        if (not value_is_reg):
            value_to_reg = search(qtype2,
                                  reg,
                                  adjusted_value,
                                  constr,
                                  a,
                                  clmax=clmax2,
                                  n=1,
                                  optimizeLen=optimizeLen)
            if (not value_to_reg):
                tried_values.append((reg, cst))
                continue
            else:
                clmax2 = clmax2 - len(value_to_reg[0])
        # Try to put the cst_addr in addr_reg
        addr_to_reg = search(QueryType.CSTtoREG,
                             addr_reg,
                             adjusted_cst_addr,
                             constr.add(RegsNotModified([reg])),
                             a,
                             clmax=clmax2,
                             n=1,
                             optimizeLen=optimizeLen)
        if (addr_to_reg):
            # If we found a solution
            # Combine them and return
            # Padd the gadget
            res = value_to_reg[0].addChain(addr_to_reg[0]).addGadget(gadget)
            if (gadget.spInc > 0):
                padding_value = constr.getValidPadding(Arch.octets())
                res = res.addPadding(padding_value,
                                     n=(gadget.spInc / Arch.octets()) - 1)
            if (optimizeLen):
                if (best):
                    best = min(best, res)
                else:
                    best = res
                shortest = len(best)
            else:
                return res

        ### Try to do addr_reg first and then reg
        clmax2 = shortest - gadget_paddingLen - 1
        # Try to put the cst_addr in addr_reg
        addr_to_reg = search(QueryType.CSTtoREG,
                             addr_reg,
                             adjusted_cst_addr,
                             constr,
                             a,
                             clmax=clmax2,
                             n=1,
                             optimizeLen=optimizeLen)
        if (not addr_to_reg):
            tried_cst_addr.append((addr_reg, addr_cst))
            continue
        else:
            clmax2 = clmax2 - len(addr_to_reg[0])
        # Try to put the value into reg
        if (not value_is_reg):
            value_to_reg = search(qtype2,
                                  reg,
                                  adjusted_value,
                                  constr.add(RegsNotModified([addr_reg])),
                                  a,
                                  clmax=clmax2,
                                  n=1,
                                  optimizeLen=optimizeLen)
        if (value_to_reg):
            # If we found a solution
            # Combine them and return
            # Padd the gadget
            res = addr_to_reg[0].addChain(value_to_reg[0]).addGadget(gadget)
            if (gadget.spInc > 0):
                padding_value = constr.getValidPadding(Arch.octets())
                res = res.addPadding(padding_value,
                                     n=(gadget.spInc / Arch.octets()) - 1)
            if (optimizeLen):
                if (best):
                    best = min(best, res)
                else:
                    best = res
                shortest = len(best)
            else:
                return res

        # 5 = two pops for addr_reg and reg + 1 for the write gadget
        # So since 5 is the shortest possible with two pops we can return
        # We can have < 5 if reg is already equal to 'value' argument
        # But we try this case first (see sorted()) when getting possibleWrites ;)
        if (((not optimizeLen) or (not value_is_reg)) and (not best is None)
                and len(best) <= 5):
            return best
        elif (optimizeLen and (not best is None) and len(best) <= 3):
            return best
    return best
Esempio n. 11
0
def build_mprotect32(addr,
                     size,
                     prot=7,
                     constraint=None,
                     assertion=None,
                     clmax=SYSCALL_LMAX,
                     optimizeLen=False):
    """
    Call mprotect from X86 arch
    Args must be on the stack:
    int mprotect(void *addr, size_t len, int prot)
    args must be in registers (ebx, ecx, edx)
    eax must be 0x7d = 125
    """
    # Check args
    if not isinstance(addr, int):
        error("Argument error. Expected integer, got " + str(type(addr)))
        return None
    elif not isinstance(size, int):
        error("Argument error. Expected integer, got " + str(type(size)))
        return None
    elif not isinstance(prot, int):
        error("Argument error. Expected integer, got " + str(type(prot)))
        return None

    if (constraint is None):
        constraint = Constraint()
    if (assertion is None):
        assertion = Assertion()

    # Check if we have the function !
    verbose("Trying to call mprotect() function directly")
    func_call = build_call('mprotect', [addr, size, prot],
                           constraint,
                           assertion,
                           clmax=clmax,
                           optimizeLen=optimizeLen)
    if (not isinstance(func_call, str)):
        verbose("Success")
        return func_call
    else:
        if (not constraint.chainable.ret):
            verbose("Coudn't call mprotect(), try direct syscall")
        else:
            verbose("Couldn't call mprotect() and return to ROPChain")
            return None

    # Otherwise do syscall directly
    # Set the registers
    args = [[Arch.n2r('eax'), 0x7d], [Arch.n2r('ebx'), addr],
            [Arch.n2r('ecx'), size], [Arch.n2r('edx'), prot]]
    chain = popMultiple(args, constraint, assertion, clmax - 1, optimizeLen)
    if (not chain):
        verbose("Failed to set registers for the mprotect syscall")
        return None
    # Int 0x80
    int80_gadgets = search(QueryType.INT80, None, None, constraint, assertion)
    if (not int80_gadgets):
        verbose("Failed to find an 'int 80' gadget")
        return None
    else:
        chain.addChain(int80_gadgets[0])
    verbose("Success")
    return chain
Esempio n. 12
0
def build_syscall_Linux(syscall,
                        arg_list,
                        arch_bits,
                        constraint=None,
                        assertion=None,
                        clmax=SYSCALL_LMAX,
                        optimizeLen=False):
    """
    arch_bits = 32 or 64 :) 
    """
    # Check args
    if (syscall.nb_args() != len(arg_list)):
        error("Error. Expected {} arguments, got {}".format(
            len(syscall.arg_types), len(arg_list)))
        return None
    # Check args length
    for i in range(0, len(arg_list)):
        if (not verifyArgType(arg_list[i], syscall.arg_types[i])):
            error("Argument error for '{}': expected '{}', got '{}'".format(
                arg_list[i], syscall.arg_types[i], type(arg_list[i])))
            return None
    # Check constraint and assertion
    if (constraint is None):
        constraint = Constraint()
    if (assertion is None):
        assertion = getBaseAssertion()

    # Check if we have the function !
    verbose("Trying to call {}() function directly".format(syscall.def_name))
    func_call = build_call(syscall.function(),
                           arg_list,
                           constraint,
                           assertion,
                           clmax=clmax,
                           optimizeLen=optimizeLen)
    if (not isinstance(func_call, str)):
        verbose("Success")
        return func_call
    else:
        if (not constraint.chainable.ret):
            verbose("Coudn't call {}(), try direct syscall".format(
                syscall.def_name))
        else:
            verbose("Couldn't call {}() and return to ROPChain".format(
                syscall.def_name))
            return None

    # Otherwise do syscall directly
    # Set the registers
    args = [(Arch.n2r(x[0]), x[1])
            for x in zip(syscall.arg_regs, arg_list) + syscall.syscall_arg_regs
            ]
    chain = popMultiple(args,
                        constraint,
                        assertion,
                        clmax - 1,
                        optimizeLen=optimizeLen)
    if (not chain):
        verbose("Failed to set registers for the mprotect syscall")
        return None
    # Int 0x80
    if (arch_bits == 32):
        syscall_gadgets = search(QueryType.INT80, None, None, constraint,
                                 assertion)
    # syscall
    elif (arch_bits == 64):
        syscall_gadgets = search(QueryType.SYSCALL, None, None, constraint,
                                 assertion)
    if (not syscall_gadgets):
        verbose("Failed to find an 'int 0x80' OR 'syscall' gadget")
        return None
    else:
        chain.addChain(syscall_gadgets[0])
    verbose("Success")
    return chain
Esempio n. 13
0
def popMultiple(args,
                constraint=None,
                assertion=None,
                clmax=None,
                addr=None,
                limit=None,
                optimizeLen=False):
    """
    args is a list of pairs (reg, value) 
        OR a list of triples (reg, value, comment)
    reg is a reg UID
    value is an int OR a string
    addr and limit are used to put strings if args contains strings 
    Creates a chain that pops values into regs
    """
    if (clmax is None):
        clmax = POP_MULTIPLE_LMAX_PER_REG * len(args)
    elif (clmax <= 0):
        return None
    for arg in args:
        if (isinstance(arg, str)):
            clmax += STR_TO_MEM_LMAX

    if (constraint is None):
        constr = Constraint()
    else:
        constr = constraint
    if (assertion is None):
        a = Assertion()
    else:
        a = assertion

    # Get address
    #Find address for the payload
    if (not addr):
        # Get the .bss address
        addr = getSectionAddress('.bss')
        if (not addr):
            return None

    perms = itertools.permutations(args)
    for perm in perms:
        clmax_tmp = clmax
        res = ROPChain()
        constr_tmp = constr
        tmp_addr = addr
        chains = None
        for arg in perm:
            if (len(arg) == 3):
                comment = arg[2]
            else:
                comment = None
            if (isinstance(arg[1], int)):
                chains = search(QueryType.CSTtoREG,
                                arg[0],
                                arg[1],
                                constr_tmp,
                                a,
                                n=1,
                                clmax=clmax_tmp,
                                CSTtoREG_comment=comment,
                                optimizeLen=optimizeLen)
            elif (isinstance(arg[1], str)):
                (address, str_to_mem) = STRtoMEM(arg[1],
                                                 tmp_addr,
                                                 constr_tmp,
                                                 a,
                                                 limit=limit,
                                                 lmax=clmax_tmp,
                                                 addr_str=comment,
                                                 hex_info=True,
                                                 optimizeLen=optimizeLen)
                if (not str_to_mem):
                    break
                tmp_addr = address + len(arg)
                pop = search(QueryType.CSTtoREG,
                             arg[0],
                             address,
                             constr_tmp,
                             a,
                             n=1,
                             clmax=clmax_tmp - len(str_to_mem),
                             optimizeLen=optimizeLen)
                if (not pop):
                    break
                chains = [str_to_mem.addChain(pop[0])]
            else:
                raise Exception(
                    "UNknown argument type in popMultiple: '{}'".format(
                        type(arg)))

            if (not chains):
                break
            else:
                clmax_tmp -= len(chains[0])
                # If Reached max length, exit
                if (clmax_tmp < 0):
                    chains = None
                    break
                else:
                    res.addChain(chains[0])
                    constr_tmp = constr_tmp.add(RegsNotModified([arg[0]]))
        if (chains):
            return res
    return None