def initEngine(): global INIT_LMAX, INIT_MAXDEPTH global global_impossible_REGtoREG global baseAssertion # Init global variables baseAssertion = Assertion().add(\ RegsValidPtrRead([(Arch.spNum(),-5000, 10000)]), copy=False).add(\ RegsValidPtrWrite([(Arch.spNum(), -5000, 0)]), copy=False) info(string_bold("Initializing Semantic Engine\n")) # Init helper for REGtoREG global_impossible_REGtoREG = SearchEnvironment(INIT_LMAX, Constraint(), baseAssertion, INIT_MAXDEPTH) init_impossible_REGtoREG(global_impossible_REGtoREG)
def dshell(args, constraint, assertion, lmax): address = None limit = None seenAddress = False seenRange = False # Parse options i = 0 while i < len(args): if (args[i][0] == '-'): if (args[i] in [OPTION_ADDRESS_SHORT, OPTION_ADDRESS]): if (seenAddress): error("Error. '" + args[i] + "' option should be used only once") return None elif (seenRange): error( "Error. You can't specify a delivery address and range at the same time" ) return None if (i + 1 >= len(args)): error("Error. Missing address after option '" + args[i] + "'") return seenAddress = True try: address = int(args[i + 1]) except: try: address = int(args[i + 1], 16) except: error("Error. '" + args[i + 1] + "' bytes is not valid") return None i = i + 2 seenAddress = True elif (args[i] in [OPTION_HELP, OPTION_HELP_SHORT]): print_help() return "help" elif (args[i] in [OPTION_RANGE, OPTION_RANGE_SHORT]): if (seenRange): error("Error. '" + args[i] + "' option should be used only once") return None elif (seenAddress): error( "Error. You can't specify a delivery address and range at the same time" ) return None if (i + 1 >= len(args)): error("Error. Missing address range after option '" + args[i] + "'") return seenRange = True values = args[i + 1].split(',') if (len(values) < 2): error("Error. Invalid address range") return elif (len(values) > 2): error("Error. Too many values after '{}' option".format( args[i])) return int_values = [] # Convert addresses into int for value in values: try: address = int(value) except: try: address = int(value, 16) except: error("Error. '" + value + "' isn't a valid address") return None if (address < 0): error("Error. Addresses can't be negative") return None int_values.append(address) # Check consistency if (int_values[0] > int_values[1]): error( "Error. Invalid address range: lower address should be inferior to upper address" ) return None # Ok (address, limit) = int_values i += 2 else: error("Error. Unknown option '{}'".format(args[i])) return None else: error("Error. Invalid option '{}'".format(args[i])) return None # Select shellcode to deliver (shellcode, shellcode_info) = select_shellcode(Arch.currentArch.name) if (not shellcode): return None else: shellcode = str(shellcode) # Build the exploit print("") info("Building exploit: deliver-shellcode strategy\n\n") res = build_dshell(shellcode, constraint, assertion, address, limit, lmax) return res
def load(args): global helpStr global loaded # Parse arguments and filename filename = None user_arch = None i = 0 seenArch = False if (not args): print(helpStr) return while i < len(args): if (args[i] in [OPTION_ARCH, OPTION_ARCH_SHORT]): if (seenArch): error("Option {} can be used only one time"\ .format(args[i])) return seenArch = True if (i + 1 == len(args)): error("Missing argument after {}.\n\tType 'load -h' for help"\ .format(args[i])) return elif (args[i + 1] == Arch.ArchX86.name): user_arch = Arch.ArchX86 elif (args[i + 1] == Arch.ArchX64.name): user_arch = Arch.ArchX64 else: error("Unknown architecture: {}".format(args[i + 1])) return i += 2 elif (args[i] in [OPTION_HELP, OPTION_HELP_SHORT]): print(helpStr) return else: filename = args[i] break if (not filename): error("Missing filename.\n\tType 'load help' for help") return # Test if the file exists if (not os.path.isfile(filename)): error("Error. Could not find file '{}'".format(filename)) return print('') info(string_bold("Extracting gadgets from file") + " '" + filename + "'\n") # Cleaning the data structures initDB() Arch.reinit() # Get architecture and OS info arch = getPlatformInfo(filename) if (arch == user_arch == None): error("Error. Could not determine architecture") return elif (arch and user_arch and (arch != user_arch)): error("Error. Conflicting architectures") print("\tUser supplied: " + user_arch.name) print("\tFound: " + arch.name) return elif (arch): Arch.currentArch = arch else: Arch.currentArch = user_arch # Init the binary scanner initScanner(filename) # Extract the gadget list gadgetList = getGadgets(filename) if (not gadgetList): return # Build the gadget database # (we mix the list so that charging bar # appears to grow steadily ) r = random() shuffle(gadgetList, lambda: r) build(gadgetList) # Init engine initEngine() loaded = True
def build(pair_list): """ Takes a list of pairs (addr, raw_asm) corresponding to gagets (their address and their intructions as a byte string) Fills the 'gadgets' and 'db' global structures ;) """ def sigint_handler(signal, frame): global sigint sigint = True def timeout_handler(signum, frame): global sigalarm sigalarm = True signal.alarm(0) raise TimeOutException('Timeout') global gadgets, db, sigint gadgets = [] raw_to_gadget = dict() sigint = False original_sigint_handler = signal.getsignal(signal.SIGINT) signal.signal(signal.SIGINT, sigint_handler) signal.signal(signal.SIGALRM, timeout_handler) info(string_bold("Creating gadget database\n")) startTime = datetime.now() success = i = 0 # Create the gadgets list for (addr, raw) in pair_list: charging_bar(len(pair_list) - 1, i, 30) if (sigint): break if (raw in raw_to_gadget): gadgets[raw_to_gadget[raw]].addrList.append(addr) success += 1 else: try: signal.alarm(1) gadget = Gadget([addr], raw) signal.alarm(0) success += 1 gadgets.append(gadget) raw_to_gadget[raw] = len(gadgets) - 1 except (GadgetException, TimeOutException) as e: signal.alarm(0) if (isinstance(e, GadgetException)): log("Gadget ({}) : ".format('\\x'+'\\x'\ .join("{:02x}".format(ord(c)) for c in raw)) + str(e)) i += 1 # Find syscalls # TODO # Getting time cTime = datetime.now() - startTime signal.signal(signal.SIGINT, original_sigint_handler) if (sigint): print("\n") fatal( "SIGINT ended the analysis prematurely, gadget database might be incomplete\n" ) sigint = False notify("Gadgets analyzed : " + str(len(pair_list))) notify("Successfully translated : " + str(success)) notify("Computation time : " + str(cTime)) # Create the database db = Database(gadgets)
def __init__(self, gadgets=[]): # List of gadgets self.gadgets = gadgets # Different query types self.types = dict() self.types[QueryType.CSTtoREG] = dict() self.types[QueryType.REGtoREG] = dict() self.types[QueryType.MEMtoREG] = dict() self.types[QueryType.CSTtoMEM] = MEMDict() self.types[QueryType.REGtoMEM] = MEMDict() self.types[QueryType.MEMtoMEM] = MEMDict() self.types[QueryType.SYSCALL] = [] self.types[QueryType.INT80] = [] # Initialize them for r in range(0, Arch.ssaRegCount): self.types[QueryType.CSTtoREG][r] = CSTList() self.types[QueryType.REGtoREG][r] = REGList() self.types[QueryType.MEMtoREG][r] = MEMList() if (gadgets): info(string_bold("Sorting gadgets semantics\n")) # Fill them for i in range(0, len(gadgets)): charging_bar(len(gadgets) - 1, i, 30) gadget = gadgets[i] # Check for special gadgets (int 0x80 and syscall if (gadget.type == GadgetType.INT80): self.types[QueryType.INT80].append(i) continue elif (gadget.type == GadgetType.SYSCALL): self.types[QueryType.SYSCALL].append(i) continue # For XXXtoREG for reg, pairs in gadget.semantics.registers.iteritems(): # Check if it is the final semantic for the register if (reg.ind < gadget.graph.lastMod[reg.num]): # If not, skip this SSA register continue for p in pairs: # For REGtoREG if (isinstance(p.expr, SSAExpr)): self.types[QueryType.REGtoREG][reg.num].add( p.expr.reg.num, 0, i, p.cond) elif (isinstance(p.expr, OpExpr)): (isInc, num, inc) = p.expr.isRegIncrement(-1) if (isInc): self.types[QueryType.REGtoREG][reg.num].add( num, inc, i, p.cond) # For CSTtoREG elif (isinstance(p.expr, ConstExpr)): self.types[QueryType.CSTtoREG][reg.num].add( p.expr.value, i, p.cond) # For MEMtoREG elif (isinstance(p.expr, MEMExpr)): if (isinstance(p.expr.addr, SSAExpr)): self.types[QueryType.MEMtoREG][reg.num].add( p.expr.addr.reg.num, 0, i, p.cond) elif (isinstance(p.expr.addr, OpExpr)): (isInc, num, inc) = p.expr.addr.isRegIncrement(-1) if (isInc): self.types[QueryType.MEMtoREG][reg.num].add( num, inc, i, p.cond) # For XXXtoMEM for addr, pairs in gadget.semantics.memory.iteritems(): addr_reg = None addr_cst = None # Check if the address is of type REG + CST if (isinstance(addr, SSAExpr)): addr_reg = addr.reg.num addr_cst = 0 elif (isinstance(addr, OpExpr)): (isInc, addr_reg, addr_cst) = addr.isRegIncrement(-1) if (not isInc): continue else: continue # Going through spairs for p in pairs: # Check for integrity of the database if (not isinstance(p.expr, Expr)): raise Exception( "Invalid dependency in fillGadgetLookUp(): " + str(p.expr)) # For REGtoMEM if (isinstance(p.expr, SSAExpr)): self.types[QueryType.REGtoMEM].addExpr(addr_reg, \ addr_cst, p.expr.reg.num, 0, i, p.cond) elif (isinstance(p.expr, OpExpr)): (isInc, num, inc) = p.expr.isRegIncrement(-1) if (isInc): self.types[QueryType.REGtoMEM].addExpr(addr_reg,\ addr_cst, num, inc, i, p.cond) # For CSTtoMEM elif (isinstance(p.expr, ConstExpr)): self.types[QueryType.CSTtoMEM].addCst(addr_reg, \ addr_cst, p.expr.value, i, p.cond) # For MEMtoMEM elif (isinstance(p.expr, MEMExpr)): if (isinstance(p.expr.addr, SSAExpr)): self.types[QueryType.MEMtoMEM].addExpr(addr_reg,\ addr_cst, p.expr.addr.reg.num, 0, i, p.cond) elif (isinstance(p.expr.addr, OpExpr)): (isInc, num, inc) = p.expr.addr.isRegIncrement(-1) if (isInc): self.types[QueryType.MEMtoMEM].addExpr(addr_reg,\ addr_cst, num, inc, i, p.cond)
def load(args): global helpStr global loaded # Parse arguments and filename filename = None user_arch = None i = 0 seenArch = False seenRopgadget = False ropgadget_options = '' if (not args): print(helpStr) return while i < len(args): if (args[i] in [OPTION_ARCH, OPTION_ARCH_SHORT]): if (seenArch): error("Option {} can be used only one time"\ .format(args[i])) return seenArch = True if (i + 1 == len(args)): error("Missing argument after {}.\n\tType 'load -h' for help"\ .format(args[i])) return elif (args[i + 1] == Arch.ArchX86.name): user_arch = Arch.ArchX86 elif (args[i + 1] == Arch.ArchX64.name): user_arch = Arch.ArchX64 else: error("Unknown architecture: {}".format(args[i + 1])) return i += 2 elif (args[i] in [OPTION_ROPGADGET_OPTIONS, OPTION_ROPGADGET_OPTIONS_SHORT]): if (seenRopgadget): error("Option {} can be used only one time"\ .format(args[i])) return seenRopgadget = True ropgadget_options = '' if (i + 1 == len(args)): error("Missing argument after {}.\n\tType 'load -h' for help"\ .format(args[i])) return j = i + 1 # Read the argments if (args[j][0] != "'"): error("ROPgadget options must be given between '' ") return if (args[j][-1] == "'" and len(args[j]) != 1): ropgadget_options += args[j][1:-1] else: ropgadget_options += args[j][1:] j += 1 closed_ok = False while (j < len(args)): if (args[j][0] != "'"): if (args[j][-1] == "'"): ropgadget_options += " " + args[j][0:-1] closed_ok = True break elif ("'" in args[j]): error( "ROPgadget options: You must leave a space after the closing '" ) return else: ropgadget_options += " " + args[j] else: if (len(args[j]) > 1): error( "ROPgadget options: You must leave a space after the closing \'" ) return else: closed_ok = True break j += 1 if (not closed_ok): error("ROPgadget options: missing closing \'") return i = j + 1 elif (args[i] in [OPTION_HELP, OPTION_HELP_SHORT]): print(helpStr) return else: filename = args[i] break if (not filename): error("Missing filename.\n\tType 'load help' for help") return # Test if the file exists if (not os.path.isfile(filename)): error("Error. Could not find file '{}'".format(filename)) return print('') info(string_bold("Extracting gadgets from file") + " '" + filename + "'\n") # Cleaning the data structures initDB() Arch.reinit() # Get architecture and OS info arch = getPlatformInfo(filename) if (arch == user_arch == None): error("Error. Could not determine architecture") return elif (arch and user_arch and (arch != user_arch)): error("Error. Conflicting architectures") print("\tUser supplied: " + user_arch.name) print("\tFound: " + arch.name) return elif (arch): Arch.setArch(arch) else: Arch.setArch(user_arch) # Init the binary scanner initScanner(filename) # Extract the gadget list gadgetList = getGadgets(filename, ropgadget_options) if (not gadgetList): return # Build the gadget database # (we mix the list so that charging bar # appears to grow steadily ) r = random() shuffle(gadgetList, lambda: r) build(gadgetList) # Init engine initEngine() loaded = True