Exemple #1
0
def build_call_linux64(funcName, funcArgs, constraint, assertion, clmax=None, optimizeLen=False):
    # Arguments registers 
    # (Args should go in these registers for x64)
    argsRegsNames = ['rdi','rsi','rdx','rcx', 'r8', 'r9']
    argsRegs = [Arch.n2r(name) for name in argsRegsNames]
    # 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 how many arguments 
    if( len(funcArgs) > 6 ):
        return "Doesn't support function call with more than 6 arguments with Linux X64 calling convention :("
        
    # Find a gadget for the fake return address
    if( funcArgs ):
        # Build the ropchain with the arguments
        args_chain = popMultiple(map(lambda x,y:(x,)+y,  argsRegs[:len(funcArgs)], funcArgs), constraint, assertion, clmax=clmax, optimizeLen=optimizeLen)
        if( not args_chain):
            return "Couldn't load arguments in registers"
    else:
        # No arguments 
        args_chain = ROPChain()
    
    # Build call chain (function address + fake return address)
    return args_chain.addPadding(funcAddr, comment=string_ropg(funcName2))
Exemple #2
0
def popMultiple(args,
                constraint=None,
                assertion=None,
                clmax=None,
                optimizeLen=False):
    """
    args is a list of pairs (reg, value)
    reg is a reg UID
    value is an int
    Creates a chain that pops values into regs
    """
    if (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 (optimizeLen):
                pop = search_optimize_len(QueryType.CSTtoREG,
                                          arg[0],
                                          arg[1],
                                          constr_tmp,
                                          a,
                                          n=1,
                                          clmax=clmax_tmp)
            else:
                pop = search(QueryType.CSTtoREG,
                             arg[0],
                             arg[1],
                             constr_tmp,
                             a,
                             n=1,
                             clmax=clmax_tmp)
            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
Exemple #3
0
def CSTtoMEM_write(arg1, cst, constraint, assertion, n=1, clmax=LMAX):
    """
    reg <- cst 
    mem(arg2) <- reg
    """
    if (clmax <= 0):
        return []

    res = []
    addr_reg = arg1[0]
    addr_cst = arg1[1]
    # 1. First strategy (direct)
    # reg <- cst
    # mem(arg1) <- reg
    for reg in range(0, Arch.ssaRegCount):
        if (reg == Arch.ipNum() or reg == Arch.spNum() or reg == addr_reg):
            continue
        # Find reg <- cst
        # maxdepth 3 or it's too slow
        cst_to_reg_chains = search(QueryType.CSTtoREG,
                                   reg,
                                   cst,
                                   constraint.add(RegsNotModified([addr_reg])),
                                   assertion,
                                   n,
                                   clmax - 1,
                                   maxdepth=3)
        if (not cst_to_reg_chains):
            continue
        # Search for mem(arg1) <- reg
        # We get all reg2,cst2 s.t mem(arg1) <- reg2+cst2
        possible_mem_writes = DBPossibleMemWrites(addr_reg,
                                                  addr_cst,
                                                  constraint,
                                                  assertion,
                                                  n=1)
        # 1.A. Ideally we look for reg2=reg and cst2=0 (direct_writes)
        possible_mem_writes_reg = possible_mem_writes.get(reg)
        if (possible_mem_writes_reg):
            direct_writes = possible_mem_writes[reg].get(0, [])
        else:
            direct_writes = []
        padding = constraint.getValidPadding(Arch.octets())
        for write_gadget in direct_writes:
            for cst_to_reg_chain in cst_to_reg_chains:
                # Pad the gadgets
                write_chain = ROPChain([write_gadget])
                for i in range(0, write_gadget.spInc - Arch.octets(),
                               Arch.octets()):
                    write_chain.addPadding(padding)
                full_chain = cst_to_reg_chain.addChain(write_chain, new=True)
                if (len(full_chain) <= clmax):
                    res.append(full_chain)
                if (len(res) >= n):
                    return res
        # 1.B.
    return res
Exemple #4
0
def STRtoMEM_write(string,
                   addr,
                   constraint,
                   assertion,
                   limit=None,
                   lmax=STR_TO_MEM_LMAX,
                   addr_str=None,
                   hex_info=False):
    """
    WRITE STRATEGY
    Copy the string using mem(XXX) <- YYY gadgets 
    """
    if (not addr_str):
        addr_str = hex(addr)

    # We decompose the string in substrings to be copied
    substrings_addr = find_best_valid_writes(addr, string, constraint, limit)
    if (substrings_addr is None):
        return (None, None)

    # Build chain
    res = ROPChain()
    offset = 0
    for (substring_addr, substring_val) in substrings_addr:
        substring_info = "(" + string_bold("Substring in int") + hex(
            substring_val) + ")"
        write_chain = store_constant_address(QueryType.CSTtoMEM,
                                             substring_addr,
                                             substring_val,
                                             constraint,
                                             assertion,
                                             clmax=lmax - len(res),
                                             optimizeLen=True)
        if (write_chain):
            res.addChain(write_chain)
        else:
            verbose("Coudln't find suitable memory write ropchain")
            return (None, None)
    return (substrings_addr[0][0], res)
Exemple #5
0
def _CSTtoREG_pop(reg,
                  cst,
                  constraint,
                  assertion,
                  n=1,
                  clmax=LMAX,
                  comment=None):
    """
    Returns a payload that puts cst into register reg by poping it from the stack
    """
    # Test clmax
    if (clmax <= 0):
        return []
    # Test n
    if (n < 1):
        return []
    # Check if the cst is incompatible with the constraint
    if (not constraint.badBytes.verifyAddress(cst)):
        return []

    if (not comment):
        comment = "Constant: " + string_bold("0x{:x}".format(cst))

    # Direct pop from the stack
    res = []
    if (reg == Arch.ipNum()):
        constraint2 = constraint.remove([CstrTypeID.CHAINABLE])
    else:
        constraint2 = constraint.add(Chainable(ret=True))
    possible = DBPossiblePopOffsets(reg, constraint2, assertion)
    for offset in sorted(filter(lambda x: x >= 0, possible.keys())):
        # If offsets are too big to fit in the lmax just break
        if (offset > clmax * Arch.octets()):
            break
        # Get possible gadgets
        possible_gadgets = [g for g in possible[offset]\
            if g.spInc >= Arch.octets() \
            and g.spInc - Arch.octets() > offset \
            and (g.spInc/Arch.octets()-1) <= clmax] # Test if padding is too much for clmax
        # Pad the gadgets
        padding = constraint.getValidPadding(Arch.octets())
        for gadget in possible_gadgets:
            chain = ROPChain([gadget])
            for i in range(0, gadget.spInc - Arch.octets(), Arch.octets()):
                if (i == offset):
                    chain.addPadding(cst, comment)
                else:
                    chain.addPadding(padding)
            if (len(chain) <= clmax):
                res.append(chain)
            if (len(res) >= n):
                return res
    return res
Exemple #6
0
def _REGtoREG_increment(arg1,
                        arg2,
                        constraint,
                        assertion,
                        record,
                        n=1,
                        clmax=LMAX):
    """
    Perform REG1 <- REG2+CST with REG1<-REG2; REG1 += CST
    """
    # Test clmax
    if (clmax <= 0):
        return []

    # Find possible increments gadgets for arg1
    possible_inc = DBPossibleInc(arg1, constraint, assertion)
    print("possible inc " + str(possible_inc))
    # Combine increments to get the constant
    combination = combine_increments(possible_inc.keys(), arg2[1])
    print("combination : " + str(combination))
    if (not combination):
        return []
    nb = reduce(lambda x, y: x * y,
                [len(possible_inc[inc]) for inc in combination])
    # Translate increments into gadgets
    inc_gadgets = [possible_inc[inc] for inc in combination]
    print("inc_gadgets " + str(inc_gadgets))

    # And Create full ropchains
    res = inc_gadgets[0]
    for gadgets in inc_gadgets[1:]:
        res = product(res, gadgets)
    print("res : " + str(res))
    res = [ROPChain(c) for c in res]
    print("res : " + str(res))
    if (arg1 != arg2[0]):
        # Get gadgets REG1 <- REG2
        arg2_to_arg1 = search(QueryType.REGtoREG, arg1, (arg2[0],0), \
                    constraint, assertion, record, n/nb + 1)
        res = [
            chain.addChain(c, new=True) for chain in arg2_to_arg1 for c in res
        ]
    return res
Exemple #7
0
def _basic(qtype, arg1, arg2, env, n=1, enablePreConds=False):
    """
    Search for gadgets basic method ( without chaining ) 
    Direct Database check  
    """
    if (env.getLmax() <= 0):
        return FailRecord(lmax=True)

    if (env.getNoPadding()):
        maxSpInc = None
    else:
        maxSpInc = env.getLmax() * Arch.octets()

    # Check for special gadgets
    if (qtype == QueryType.INT80 or qtype == QueryType.SYSCALL):
        gadgets = DBSearch(qtype,
                           arg1,
                           arg2,
                           env.getConstraint(),
                           env.getAssertion(),
                           n=n,
                           maxSpInc=maxSpInc)
        res = [ROPChain().addGadget(g) for g in gadgets]
        return res

    # Check if the type is IP <- ...
    # In this case we remove the CHAINABLE constraint which makes no sense
    if (arg1 == Arch.ipNum()):
        constraint2 = env.getConstraint().remove([CstrTypeID.CHAINABLE])
    else:
        constraint2 = env.getConstraint()

    # Check to add assertions when looking for Memory gadgets
    if (qtype == QueryType.CSTtoMEM or qtype == QueryType.REGtoMEM):
        assertion2 = env.getAssertion().add(
            RegsNoOverlap([(arg1[0], Arch.spNum())]))
    else:
        assertion2 = env.getAssertion()

    # Regular gadgets
    # maxSpInc -> +1 because we don't count the ret but -1 because the gadget takes one place
    gadgets = DBSearch(qtype,
                       arg1,
                       arg2,
                       constraint2,
                       assertion2,
                       n,
                       enablePreConds=enablePreConds,
                       maxSpInc=maxSpInc)
    if (enablePreConds):
        return [(ROPChain().addGadget(g[0]), g[1]) for g in gadgets]
    elif (env.getNoPadding()):
        return [ROPChain().addGadget(g) for g in gadgets]
    else:
        res = []
        padding = constraint2.getValidPadding(Arch.octets())
        for g in gadgets:
            chain = ROPChain().addGadget(g)
            # Padding the chain if possible
            if (g.spInc > 0):
                for i in range(0, g.spInc / Arch.octets() - 1):
                    chain.addPadding(padding)
            # Adding to the result
            res.append(chain)
    if (len(res) == 0):
        return FailRecord()
    else:
        return res
Exemple #8
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
Exemple #9
0
def _basic(qtype,
           arg1,
           arg2,
           constraint,
           assertion,
           n=1,
           clmax=LMAX,
           noPadding=False):
    """
    Search for gadgets basic method ( without chaining ) 
    Direct Database check  
    """
    # Test clmax
    if (clmax <= 0):
        return []

    if (not noPadding):
        maxSpInc = clmax * Arch.octets()
    else:
        maxSpInc = None

    # Check for special gadgets
    if (qtype == QueryType.INT80 or qtype == QueryType.SYSCALL):
        gadgets = DBSearch(qtype,
                           arg1,
                           arg2,
                           constraint,
                           assertion,
                           n=1,
                           maxSpInc=maxSpInc)
        res = [ROPChain().addGadget(g) for g in gadgets]
        return res

    # Check if the type is IP <- ...
    # In this case we remove the CHAINABLE constraint which makes no sense
    if (arg1 == Arch.ipNum()):
        constraint2 = constraint.remove([CstrTypeID.CHAINABLE])
    else:
        constraint2 = constraint

    # Check to add assertions when looking for Memory gadgets
    if (qtype == QueryType.CSTtoMEM or qtype == QueryType.REGtoMEM):
        assertion2 = assertion.add(RegsNoOverlap([(arg1[0], Arch.spNum())]))
    else:
        assertion2 = assertion

    # Regular gadgets
    # maxSpInc -> +1 because we don't count the ret but -1 because the gadget takes one place
    gadgets = DBSearch(qtype,
                       arg1,
                       arg2,
                       constraint2,
                       assertion2,
                       n,
                       maxSpInc=maxSpInc)
    if (noPadding):
        return [ROPChain().addGadget(g) for g in gadgets]
    else:
        res = []
        padding = constraint2.getValidPadding(Arch.currentArch.octets)
        for g in gadgets:
            chain = ROPChain().addGadget(g)
            # Padding the chain if possible
            if (g.spInc > 0):
                for i in range(0, g.spInc / Arch.octets() - 1):
                    chain.addPadding(padding)
            # Adding to the result
            res.append(chain)
    return res
Exemple #10
0
def STRtoMEM_memcpy(string,
                    addr,
                    constraint,
                    assertion,
                    limit=None,
                    lmax=STR_TO_MEM_LMAX,
                    addr_str=None,
                    hex_info=False):
    """
    MEMCPY STRATEGY
    Copy the string using memcpy function 
    """
    if (not addr_str):
        addr_str = hex(addr)

    # Getting strcpy function
    (func_name, func_addr) = getFunctionAddress('memcpy')
    if (not func_addr):
        verbose('Could not find memcpy function')
        return (None, None)
    elif (not constraint.badBytes.verifyAddress(func_addr)):
        verbose("memcpy address ({}) contains bad bytes".format(
            hex(func_addr)))
        return (None, None)

    # We decompose the string in substrings to be copied
    substrings_addr = findBytes(string, badBytes=constraint.getBadBytes())
    if (not substrings_addr):
        return (None, None)

    # Find delivery address
    substr_lengthes = [len(substr[1]) for substr in substrings_addr]
    if (not limit is None):
        custom_stack = find_closest_base_fake_stack_address(
            addr, limit, substr_lengthes, constraint)
        if (custom_stack is None):
            verbose("Couldn't write string in memory because of bad bytes")
            return (None, None)
    else:
        custom_stack = find_closest_base_fake_stack_address(
            addr, addr + sum(substr_lengthes), substr_lengthes, constraint)
        if (custom_stack is None):
            verbose("Couldn't write string in memory because of bad bytes")
            return (None, None)
    if (custom_stack != addr):
        addr_str = hex(custom_stack)

    # Build chain
    res = ROPChain()
    offset = 0
    saved_custom_stack = custom_stack
    for (substring_addr, substring_str) in substrings_addr:
        if (hex_info):
            substring_info = "'" + '\\x' + '\\x'.join(
                ["%02x" % ord(c) for c in substring_str]) + "'"
        else:
            substring_info = "'" + substring_str + "'"
        comment3 = "Arg3: " + string_ropg(str(len(substring_str)))
        comment2 = "Arg2: " + string_ropg(substring_info)
        comment1 = "Arg1: " + string_ropg("{} + {}".format(addr_str, offset))

        func_call = build_call(func_name, [custom_stack, substring_addr, len(substring_str)],\
                    constraint, assertion, [comment1, comment2, comment3], optimizeLen=True)

        if (isinstance(func_call, str)):
            verbose("memcpy: " + func_call)
            return (None, None)

        res.addChain(func_call)
        if (len(res) > lmax):
            return (None, None)

        # Adjust
        custom_stack = custom_stack + len(substring_str)
        offset = offset + len(substring_str)

    return (saved_custom_stack, res)
Exemple #11
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)
Exemple #12
0
def STRtoMEM_strcpy(string,
                    addr,
                    constraint,
                    assertion,
                    limit=None,
                    lmax=STR_TO_MEM_LMAX,
                    addr_str=None,
                    hex_info=False):
    """
    STRCPY STRATEGY
    Copy the string using strcpy function 
    """
    if (not addr_str):
        addr_str = hex(addr)

    # Getting strcpy function
    (func_name, func_addr) = getFunctionAddress('strcpy')
    if (not func_addr):
        verbose('Could not find strcpy function')
        return (None, None)
    elif (not constraint.badBytes.verifyAddress(func_addr)):
        verbose("strcpy address ({}) contains bad bytes".format(
            hex(func_addr)))
        return (None, None)

    # We decompose the string in substrings to be copied
    substrings_addr = findBytes(string,
                                badBytes=constraint.getBadBytes(),
                                add_null=True)
    if (not substrings_addr):
        return (None, None)

    # Find delivery address
    substr_lengthes = [len(substr[1]) - 1
                       for substr in substrings_addr]  # -1 becasue strcpy
    substr_lengthes[-1] += 1
    if (not limit is None):
        custom_stack = find_closest_base_fake_stack_address(
            addr, limit, substr_lengthes, constraint)
        if (custom_stack is None):
            verbose("Couldn't write string in memory because of bad bytes")
            return (None, None)
    else:
        custom_stack = find_closest_base_fake_stack_address(
            addr, addr + sum(substr_lengthes), substr_lengthes, constraint)
        if (custom_stack is None):
            verbose("Couldn't write string in memory because of bad bytes")
            return (None, None)
    if (custom_stack != addr):
        addr_str = hex(custom_stack)

    # Build chain
    res = ROPChain()
    offset = 0
    saved_custom_stack = custom_stack
    for (substring_addr, substring_str) in substrings_addr:
        if (hex_info):
            substring_info = '\\x' + '\\x'.join(
                ["%02x" % ord(c) for c in substring_str])
        else:
            substring_info = substring_str
        commentStack = "Arg2: " + string_ropg("{} + {}".format(
            addr_str, offset))
        commentSubStr = "Arg1: " + string_ropg(substring_info)
        func_call = build_call(func_name, [substring_addr, custom_stack],
                               constraint,
                               assertion, [commentSubStr, commentStack],
                               optimizeLen=True)
        if (isinstance(func_call, str)):
            verbose("strcpy: " + func_call)
            return (None, None)
        else:
            res.addChain(func_call)
            if (len(res) > lmax):
                return (None, None)
        # Adjust
        # -1 Because strcpy has a null byte :/
        # Except when we INTEND to write a null byte
        if (substring_str == '\x00'):
            dec = 0
        else:
            dec = 1
        custom_stack = custom_stack + len(substring_str) - dec
        offset = offset + len(substring_str) - dec

    return (saved_custom_stack, res)
Exemple #13
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)
Exemple #14
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
Exemple #15
0
def _CSTtoREG_pop(reg, cst, env, n=1):
    """
    Returns a payload that puts cst into register reg by poping it from the stack
    """
    ID = StrategyType.CSTtoREG_POP

    ## Test for special cases
    # Test lmax
    if (env.getLmax() <= 0):
        return FailRecord(lmax=True)
    # Limit number of calls to ...
    elif (env.nbCalls(ID) >= 99):
        return FailRecord()
    # Check if the cst is in badBytes
    elif (not env.getConstraint().badBytes.verifyAddress(cst)):
        return FailRecord()

    # Set env
    env.addCall(ID)
    # Get comment
    if (env.hasComment(ID)):
        envHadComment = True
        comment = env.popComment(ID)
    else:
        envHadComment = False
        comment = "Constant: " + string_bold("0x{:x}".format(cst))

    ########################
    # Direct pop from the stack
    res = []
    res_fail = FailRecord()
    # Adapt constraint if ip <- cst
    if (reg != Arch.ipNum()):
        constraint2 = env.getConstraint().add(Chainable(ret=True))
    else:
        constraint2 = env.getConstraint()

    possible = DBPossiblePopOffsets(reg, constraint2, env.getAssertion())
    for offset in sorted(filter(lambda x: x >= 0, possible.keys())):
        # If offsets are too big to fit in the lmax just break
        if (offset > env.getLmax() * Arch.octets()):
            break
        # Get possible gadgets
        possible_gadgets = [g for g in possible[offset]\
            if g.spInc >= Arch.octets() \
            and g.spInc - Arch.octets() > offset \
            and (g.spInc/Arch.octets()-1) <= env.getLmax()] # Test if padding is too much for clmax
        # Pad the gadgets
        padding = env.getConstraint().getValidPadding(Arch.octets())
        for gadget in possible_gadgets:
            chain = ROPChain([gadget])
            for i in range(0, gadget.spInc - Arch.octets(), Arch.octets()):
                if (i == offset):
                    chain.addPadding(cst, comment)
                else:
                    chain.addPadding(padding)
            if (len(chain) <= env.getLmax()):
                res.append(chain)
            if (len(res) >= n):
                break
        if (len(res) >= n):
            break
    #########################

    # Restore env
    env.removeCall(ID)
    if (envHadComment):
        env.pushComment(ID, comment)

    return res if res else res_fail
Exemple #16
0
def _CSTtoMEM_write(arg1, cst, env, n=1):
    """
    reg <- cst 
    mem(arg2) <- reg
    """
    ID = StrategyType.CSTtoMEM_WRITE

    ## Test for special cases
    # Test lmax
    if (env.getLmax() <= 0):
        return FailRecord(lmax=True)
    # Limit number of calls to ...
    elif (env.nbCalls(ID) >= 99):
        return FailRecord()

    # Set env
    env.addCall(ID)
    ######################################
    res = []
    res_fail
    addr_reg = arg1[0]
    addr_cst = arg1[1]
    # 1. First strategy (direct)
    # reg <- cst
    # mem(arg1) <- reg
    for reg in Arch.registers():
        if (reg == Arch.ipNum() or reg == Arch.spNum() or reg == addr_reg):
            continue
        # Find reg <- cst
        constraint = env.getConstraint()
        env.setConstraint(constraint.add(RegsNotModified([addr_reg])))
        env.subLmax(1)
        cst_to_reg_chains = _search(QueryType.CSTtoREG, reg, cst, env, n)
        env.addLmax(1)
        env.setConstraint(constraint)
        if (not cst_to_reg_chains):
            res_fail.merge(cst_to_reg_chains)
            continue
        # Search for mem(arg1) <- reg
        # We get all reg2,cst2 s.t mem(arg1) <- reg2+cst2
        possible_mem_writes = DBPossibleMemWrites(addr_reg,
                                                  addr_cst,
                                                  env.getConstraint(),
                                                  env.getAssertion(),
                                                  n=1)
        # 1.A. Ideally we look for reg2=reg and cst2=0 (direct_writes)
        possible_mem_writes_reg = possible_mem_writes.get(reg)
        if (possible_mem_writes_reg):
            direct_writes = possible_mem_writes[reg].get(0, [])
        else:
            direct_writes = []
        padding = constraint.getValidPadding(Arch.octets())
        for write_gadget in direct_writes:
            for cst_to_reg_chain in cst_to_reg_chains:
                # Pad the gadgets
                write_chain = ROPChain([write_gadget])
                for i in range(0, write_gadget.spInc - Arch.octets(),
                               Arch.octets()):
                    write_chain.addPadding(padding)
                full_chain = cst_to_reg_chain.addChain(write_chain, new=True)
                if (len(full_chain) <= env.getLmax()):
                    res.append(full_chain)
                if (len(res) >= n):
                    break
            if (len(res) >= n):
                break
        if (len(res) >= n):
            break
        # 1.B. Otherwise we try to adjust the cst2
        # To be implemented

    # 2d Strategy: indirect
    # reg <- arg2 - cst
    # mem(arg1) <- reg + cst

    # TO IMPLEMENT IN ANOTHER FUNCTION !

    ###################
    # Restore env
    env.removeCall(ID)
    return res if res else res_fail
Exemple #17
0
def STRtoMEM_memcpy(string,
                    addr,
                    constraint,
                    assertion,
                    lmax=STR_TO_MEM_LMAX,
                    addr_str=None,
                    hex_info=False):
    """
    MEMCPY STRATEGY
    Copy the string using memcpy function 
    """
    if (not addr_str):
        addr_str = "0x" + format(addr, '0' + str(Arch.octets() * 2) + 'x')

    # Getting strcpy function
    (func_name, func_addr) = getFunctionAddress('memcpy')
    if (not func_addr):
        verbose('Could not find memcpy function')
        return None
    elif (not constraint.badBytes.verifyAddress(func_addr)):
        verbose("memcpy address ({}) contains bad bytes".format(
            hex(func_addr)))
        return None

    # We decompose the string in substrings to be copied
    substrings_addr = findBytes(string, badBytes=constraint.getBadBytes())
    if (not substrings_addr):
        return None
    elif (len(substrings_addr) * 5 > lmax):
        verbose(
            "Memcpy: ROP-Chain too long (length: {}, available bytes: {}) ".
            format(
                len(substrings_addr) * 5 * Arch.octets(),
                lmax * Arch.octets()))
        return None

    # Get a pop-pop-pop-ret gadget
    pppr_chains = _basic(QueryType.MEMtoREG,
                         Arch.ipNum(), [Arch.spNum(), 3 * Arch.octets()],
                         constraint.add(
                             StackPointerIncrement(4 * Arch.octets())),
                         assertion,
                         clmax=1,
                         noPadding=True)
    if (not pppr_chains):
        verbose("Memcpy: Could not find suitable pop-pop-pop-ret gadget")
        return None
    pppr_gadget = pppr_chains[0].chain[0]  # Get the first gadget

    # Build chain
    res = ROPChain()
    offset = 0
    custom_stack = addr
    for (substring_addr, substring_str) in substrings_addr:
        if (hex_info):
            substring_info = "'" + '\\x' + '\\x'.join(
                ["%02x" % ord(c) for c in substring_str]) + "'"
        else:
            substring_info = "'" + substring_str + "'"

        res.addPadding(func_addr, comment=string_ropg(func_name))
        res.addGadget(pppr_gadget)
        res.addPadding(len(substring_str),
                       comment="Arg3: " + string_ropg(str(len(substring_str))))
        res.addPadding(substring_addr,
                       comment="Arg2: " + string_ropg(substring_info))
        res.addPadding(custom_stack,
                       comment="Arg1: " +
                       string_ropg("{} + {}".format(addr_str, offset)))

        # Adjust
        custom_stack = custom_stack + len(substring_str)
        offset = offset + len(substring_str)

    return res