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
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)
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)
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)
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)
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
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)