def __init__(self, addr_list, raw): """ addr_list = list of addresses of the gadget (if duplicate gadgets) raw = raw string of gadget asm """ # Check the type of the gadget # Check for 'int 0x80' gadgets if( raw == '\xcd\x80' and Arch.currentIsIntel()): self.type = GadgetType.INT80 self.asmStr = 'int 0x80' self.hexStr = '\\xcd\\x80' self.addrList = addr_list self.nbInstr = self.nbInstrREIL = 1 self.semantics = Semantics() return # Check for 'syscall' gadgets elif( raw == '\x0f\x05' and Arch.currentIsIntel()): self.type = GadgetType.SYSCALL self.asmStr = 'syscall' self.hexStr = '\\x0f\\x05' self.addrList = addr_list self.nbInstr = self.nbInstrREIL = 1 self.semantics = Semantics() return # Translate raw assembly into REIL # Then compute the Graph and its semantics try: (irsb, ins) = Arch.currentArch.asmToREIL(raw) except Arch.ArchException as e: raise GadgetException(str(e)) try: self.graph = REILtoGraph(irsb) self.semantics = self.graph.getSemantics() except GraphException as e: raise GadgetException("(In {}) - ".format('; '.join(str(i) for i in ins)) + str(e)) self.type = GadgetType.REGULAR # Possible addresses self.addrList = addr_list # String representations self.asmStr = '; '.join(str(i) for i in ins) self.hexStr = '\\x' + '\\x'.join("{:02x}".format(ord(c)) for c in raw) # Length of the gadget self.nbInstr = len(ins) self.nbInstrREIL = len(irsb) # List of modified registers # And of memory-read accesses self._modifiedRegs = [] self._memoryReads = [] for reg_num in list(set([reg.num for reg in self.semantics.registers.keys()])): # Check if there is an empty semantics if( not self.getSemantics(reg_num)): #self.semantics.registers.pop(reg) log("Gadget ({}) : empty semantics for {}"\ .format(self.asmStr, Arch.r2n(reg_num))) self._modifiedRegs.append(reg_num) continue # Get modified reg if ((SSAExpr(reg_num,0) != self.getSemantics(reg_num)[0].expr) ): self._modifiedRegs.append(reg_num) # Get memory reads for pair in self.getSemantics(reg_num): self._memoryReads += [m[0] for m in pair.expr.getMemAcc()] self._modifiedRegs = list(set(self._modifiedRegs)) # SP Increment if( self.type != GadgetType.REGULAR ): self.spInc = None else: sp_num = Arch.spNum() if( not sp_num in self.graph.lastMod ): self.spInc = 0 else: sp = SSAReg(sp_num, self.graph.lastMod[sp_num]) if( len(self.semantics.get(sp)) == 1 ): (isInc, inc) = self.semantics.get(sp)[0].expr.isRegIncrement(sp_num) if( isInc ): self.spInc = inc else: self.spInc = None else: self.spInc = None # Return type self.retType = RetType.UNKNOWN self.retValue = None if( self.type == GadgetType.REGULAR ): ip_num = Arch.n2r(Arch.currentArch.ip) ip = SSAReg(ip_num, self.graph.lastMod[ip_num]) sp_num = Arch.n2r(Arch.currentArch.sp) if( self.spInc != None ): for p in self.semantics.get(ip): if( p.cond.isTrue()): if( isinstance(p.expr, MEMExpr)): addr = p.expr.addr (isInc, inc) = addr.isRegIncrement(sp_num) # Normal ret if the final value of the IP is value that was in memory before the last modification of SP ( i.e final_IP = MEM[final_sp - size_of_a_register ) if( isInc and inc == (self.spInc - (Arch.currentArch.octets)) ): self.retType = RetType.RET self.retValue = p.expr elif( isinstance(p.expr, SSAExpr )): self.retValue = p.expr # Try to detect gadgets ending by 'call' if( ins[-1]._mnemonic[:4] == "call"): self.retType = RetType.CALL else: self.retType = RetType.JMP
def __init__(self, msg): self.msg = msg log(msg)
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)