def classify_JOP_gadget(self, gadget): """ Analyzes a gadget to determine which expressivity classes it satisfies :param Gadget gadget: gadget to analyze :return: None, but modifies Gadget expressivity collections """ last_instr = gadget.instructions[len(gadget.instructions) - 1] op1 = last_instr.op1 op1_family = Instruction.get_word_operand_register_family(op1) if self.practical_ROP[3] is False: if "[" in op1 and op1_family in [ 0, 5 ] and "+" not in op1 and "-" not in op1 and "*" not in op1: self.practical_ROP[3] = True if self.practical_ROP[5] is False: if op1_family in [ 0, 5 ] and "+" not in op1 and "-" not in op1 and "*" not in op1: self.practical_ROP[5] = True if self.practical_ROP[7] is False: if "[" in op1 and op1_family in [ 0, 4, 5 ] and "+" not in op1 and "-" not in op1 and "*" not in op1: self.practical_ROP[7] = True if self.practical_ASLR_ROP[0] is False: if "[" not in op1 and op1_family not in [None, 6, 7]: self.practical_ASLR_ROP[0] = True if self.practical_ASLR_ROP[1] is False: if "[" in op1 and op1_family not in [ None, 6, 7 ] and "+" not in op1 and "-" not in op1 and "*" not in op1: self.practical_ASLR_ROP[1] = True
def classify_gadget(self, gadget): """ Analyzes a gadget to determine which expressivity classes it satisfies :param Gadget gadget: gadget to analyze :return: None, but modifies Gadget expressivity collections """ first_instr = gadget.instructions[0] opcode = first_instr.opcode op1 = first_instr.op1 op2 = first_instr.op2 op1_family = Instruction.get_word_operand_register_family(op1) op2_family = Instruction.get_word_operand_register_family(op2) # For performance, iterate through the expressivity classes and perform analysis. Analysis rules should # set as many classes as possible. if self.practical_ROP[0] is False: if opcode == "dec" and op1_family in [0, 5] and "[" not in op1: self.practical_ROP[0] = True # Also satisfies: self.turing_complete_ROP[0] = True self.practical_ASLR_ROP[9] = True if self.practical_ROP[1] is False: if opcode == "inc" and op1_family in [0, 5] and "[" not in op1: self.practical_ROP[1] = True # Also satisfies: self.turing_complete_ROP[0] = True self.practical_ASLR_ROP[8] = True if self.practical_ROP[2] is False: if opcode == "pop" and op1_family in [0, 5] and "[" not in op1: self.practical_ROP[2] = True # Also satisfies: self.turing_complete_ROP[1] = True self.practical_ASLR_ROP[5] = True if self.practical_ROP[3] is False: if (opcode == "pop" and op1_family == 4 and "[" not in op1) or \ (opcode in ["xchg", "move"] and op1_family == 4 and op2_family in [0, 5] and "[" not in op1 and "[" not in op2) or \ (opcode == "lea" and op1_family == 4 and op2_family in [0, 5] and "+" not in op2 and "-" not in op2 and "*" not in op2) or \ (opcode == "xchg" and op1_family in [0, 5] and op2_family == 4 and "[" not in op1 and "[" not in op2): self.practical_ROP[3] = True if self.practical_ROP[4] is False: if opcode == "xchg" and ((op1_family == 0 and op2_family == 5) or (op2_family == 0 and op1_family == 5)) \ and "[" not in op1 and "[" not in op2: self.practical_ROP[4] = True if self.practical_ROP[5] is False: if opcode == "push" and op1_family in [0, 4, 5] and "[" not in op1: self.practical_ROP[5] = True if self.practical_ROP[6] is False: if opcode in ["clc", "sahf"] or \ (opcode in ["test", "add", "adc", "sub", "sbb", "and", "or", "xor", "cmp"] and op1_family in [0, 4, 5] and op2_family in [0, 4, 5] and "[" not in op1 and "[" not in op2): self.practical_ROP[6] = True # Also satisfies: self.turing_complete_ROP[7] = True self.practical_ASLR_ROP[4] = True if self.practical_ROP[7] is False: if (opcode.startswith("stos") or opcode in ["mov", "add", "or"]) and "[" in op1 and "+" not in op1 and \ "-" not in op1 and "*" not in op1 and op1_family in [0, 4, 5] and op2_family in [0, 4, 5] and \ op1_family != op2_family: self.practical_ROP[7] = True # Also satisfies: self.turing_complete_ROP[6] = True self.practical_ASLR_ROP[2] = True if self.practical_ROP[8] is False: if (opcode.startswith("lods") or opcode in ["mov", "add", "adc", "sub", "sbb", "and", "or", "xor"]) and \ "[" in op2 and "+" not in op2 and "-" not in op2 and "*" not in op2 and op1_family in [0, 4, 5] and \ op2_family in [0, 4, 5] and op1_family != op2_family: self.practical_ROP[8] = True # Also satisfies: self.turing_complete_ROP[5] = True self.practical_ASLR_ROP[1] = True # NOTE: Single rule for two classes if self.practical_ROP[9] is False or self.practical_ASLR_ROP[ 7] is False: if opcode == "leave": self.practical_ROP[9] = True self.practical_ASLR_ROP[7] = True if self.practical_ROP[10] is False: if (opcode == "pop" and op1_family == 6 and "[" not in op1) or \ (opcode == "xchg" and op1_family is not None and op2_family is not None and op1_family != op2_family and (op1_family == 6 or op2_family == 6) and "[" not in op1 and "[" not in op2) or \ (opcode in ["add", "adc", "sub", "sbb"] and "[" not in op1 and op1_family == 6 and op2_family not in [None, 6] and "+" not in op2 and "-" not in op2 and "*" not in op2): self.practical_ROP[10] = True if self.turing_complete_ROP[0] is False: if opcode in ["inc", "dec"] and op1_family not in [None, 7] and "+" not in op1 and "-" not in op1 and \ "*" not in op1: self.turing_complete_ROP[0] = True if self.turing_complete_ROP[1] is False: if opcode == "pop" and op1_family not in [None, 7 ] and "[" not in op1: self.turing_complete_ROP[1] = True if self.turing_complete_ROP[2] is False: if opcode in ["add", "adc", "sub", "sbb"] and op1_family not in [None, 7] and "+" not in op1 and \ "-" not in op1 and "*" not in op1 and op2_family not in [None, 7] and "+" not in op2 and \ "-" not in op2 and "*" not in op2 and op1_family != op2_family: self.turing_complete_ROP[2] = True if self.turing_complete_ROP[3] is False: if (opcode == "xor" and op1_family not in [None, 7] and "+" not in op1 and "-" not in op1 and "*" not in op1 and op2_family not in [None, 7] and "+" not in op2 and "-" not in op2 and "*" not in op2 and op1_family != op2_family) or \ (opcode in ["neg", "not"] and op1_family not in [None, 7] and "+" not in op1 and "-" not in op1 and "*" not in op1): self.turing_complete_ROP[3] = True if self.turing_complete_ROP[4] is False: if opcode in ["and", "or"] and op1_family not in [None, 7] and "+" not in op1 and \ "-" not in op1 and "*" not in op1 and op2_family not in [None, 7] and "+" not in op2 and \ "-" not in op2 and "*" not in op2 and op1_family != op2_family: self.turing_complete_ROP[4] = True if self.turing_complete_ROP[5] is False: if (opcode.startswith("lods") or opcode in ["mov", "add", "adc", "sub", "sbb", "and", "or", "xor"]) and \ "[" in op2 and "+" not in op2 and "-" not in op2 and "*" not in op2 and \ op1_family not in [None, 7] and op2_family not in [None, 7] and op1_family != op2_family: self.turing_complete_ROP[5] = True if self.turing_complete_ROP[6] is False: if (opcode.startswith("stos") or opcode in ["mov", "add", "or"]) and "[" in op1 and "+" not in op1 and \ "-" not in op1 and "*" not in op1 and op1_family not in [None, 7] and op2_family not in [None, 7] and \ op1_family != op2_family: self.turing_complete_ROP[6] = True if self.turing_complete_ROP[7] is False: if opcode in ["clc", "sahf"] or \ (opcode in ["test", "add", "adc", "sub", "sbb", "and", "or", "xor", "cmp"] and op1_family not in [None, 7] and op2_family not in [None, 7] and "+" not in op1 and "-" not in op1 and "*" not in op1 and "+" not in op2 and "-" not in op2 and "*" not in op2 and op1_family != op2_family): self.turing_complete_ROP[7] = True if self.turing_complete_ROP[8] is False: if opcode in ["add", "adc", "sub", "sbb"] and "[" not in op2 and op2_family == 7 and \ op1_family not in [None, 7] and "+" not in op1 and "-" not in op1 and "*" not in op1: self.turing_complete_ROP[8] = True if self.turing_complete_ROP[9] is False: if (opcode == "pop" and op1_family == 7 and "[" not in op1) or \ (opcode == "xchg" and op1_family is not None and op2_family is not None and op1_family != op2_family and (op1_family == 7 or op2_family == 7) and "[" not in op1 and "[" not in op2) or \ (opcode in ["add", "adc", "sub", "sbb"] and "[" not in op1 and op1_family == 7 and op2_family not in [None, 7] and "+" not in op2 and "-" not in op2 and "*" not in op2): self.turing_complete_ROP[9] = True if self.turing_complete_ROP[10] is False: if opcode in ["lahf", "pushf"] or \ (opcode in ["adc", "sbb"] and op1_family not in [None, 7] and op2_family not in [None, 7] and "+" not in op1 and "-" not in op1 and "*" not in op1 and "+" not in op2 and "-" not in op2 and "*" not in op2 and op1_family != op2_family): self.turing_complete_ROP[10] = True # Next 6 classes have common and very specific requirements, check once if opcode == "xchg" and "[" not in op1 and "[" not in op2 and op1_family != op2_family: if self.turing_complete_ROP[11] is False: if op1_family in [0, 1] and op2_family in [0, 1]: self.turing_complete_ROP[11] = True if self.turing_complete_ROP[12] is False: if op1_family in [0, 2] and op2_family in [0, 2]: self.turing_complete_ROP[12] = True if self.turing_complete_ROP[13] is False: if op1_family in [0, 3] and op2_family in [0, 3]: self.turing_complete_ROP[13] = True if self.turing_complete_ROP[14] is False: if op1_family in [0, 6] and op2_family in [0, 6]: self.turing_complete_ROP[14] = True if self.turing_complete_ROP[15] is False: if op1_family in [0, 4] and op2_family in [0, 4]: self.turing_complete_ROP[15] = True if self.turing_complete_ROP[16] is False: if op1_family in [0, 5] and op2_family in [0, 5]: self.turing_complete_ROP[16] = True if self.practical_ASLR_ROP[0] is False: if opcode == "push" and op1_family not in [None, 6, 7 ] and "[" not in op1: self.practical_ASLR_ROP[0] = True if self.practical_ASLR_ROP[1] is False: if (opcode.startswith("lods") or opcode in ["mov", "add", "adc", "sub", "sbb", "and", "or", "xor"]) and \ "[" in op2 and "+" not in op2 and "-" not in op2 and "*" not in op2 and \ op1_family not in [None, 7] and op2_family not in [None, 6, 7] and op1_family != op2_family: self.practical_ASLR_ROP[1] = True if self.practical_ASLR_ROP[2] is False: if (opcode.startswith("stos") or opcode == "mov") and "[" in op1 and "+" not in op1 and \ "-" not in op1 and "*" not in op1 and op1_family not in [None, 7] and op2_family not in [None, 7] and \ op1_family != op2_family: self.practical_ASLR_ROP[2] = True if self.practical_ASLR_ROP[3] is False: if opcode in ["mov", "add", "adc", "and", "or", "xor"] and "[" not in op1 and "[" not in op2 and \ op1_family not in [None, 7] and op2_family == 7: self.practical_ASLR_ROP[3] = True if self.practical_ASLR_ROP[4] is False: if opcode in ["clc", "sahf"] or \ (opcode in ["test", "add", "adc", "sub", "sbb", "and", "or", "xor", "cmp"] and op1_family not in [None, 7] and op2_family not in [None, 7] and "[" not in op1 and "[" not in op2): self.practical_ASLR_ROP[4] = True if self.practical_ASLR_ROP[5] is False: if opcode == "pop" and op1_family in [0, 4, 5] and "[" not in op1: self.practical_ASLR_ROP[5] = True if self.practical_ASLR_ROP[6] is False: if opcode == "pop" and op1_family in [1, 2, 3, 6 ] and "[" not in op1: self.practical_ASLR_ROP[6] = True # NOTE class 8 (index 7) is combined above if self.practical_ASLR_ROP[8] is False: if opcode == "inc" and op1_family not in [None, 7 ] and "[" not in op1: self.practical_ASLR_ROP[8] = True if self.practical_ASLR_ROP[9] is False: if opcode == "dec" and op1_family not in [None, 7 ] and "[" not in op1: self.practical_ASLR_ROP[9] = True if self.practical_ASLR_ROP[10] is False: if opcode in ["add", "adc", "sub", "sbb"] and op1_family not in [None, 7] and "[" not in op1 and \ op2_family not in [None, 7] and "[" not in op2 and op1_family != op2_family: self.practical_ASLR_ROP[10] = True # For the next 24 classes, some fairly common gadgets will satisfy many classes and significant # overlap in definitions exists. Check these without first seeing if the class is satisfied # POP AX if opcode == "pop" and "[" not in op1 and op1_family == 0: self.practical_ASLR_ROP[13] = True self.practical_ASLR_ROP[17] = True self.practical_ASLR_ROP[21] = True self.practical_ASLR_ROP[25] = True self.practical_ASLR_ROP[29] = True self.practical_ASLR_ROP[33] = True # XCHG AX with another GPR if opcode == "xchg" and "[" not in op1 and "[" not in op2: if op1_family == 0: if op2_family == 1: self.practical_ASLR_ROP[11] = True self.practical_ASLR_ROP[12] = True self.practical_ASLR_ROP[13] = True self.practical_ASLR_ROP[14] = True elif op2_family == 2: self.practical_ASLR_ROP[15] = True self.practical_ASLR_ROP[16] = True self.practical_ASLR_ROP[17] = True self.practical_ASLR_ROP[18] = True elif op2_family == 3: self.practical_ASLR_ROP[19] = True self.practical_ASLR_ROP[20] = True self.practical_ASLR_ROP[21] = True self.practical_ASLR_ROP[22] = True elif op2_family == 6: self.practical_ASLR_ROP[23] = True self.practical_ASLR_ROP[24] = True self.practical_ASLR_ROP[25] = True self.practical_ASLR_ROP[26] = True elif op2_family == 4: self.practical_ASLR_ROP[27] = True self.practical_ASLR_ROP[28] = True self.practical_ASLR_ROP[29] = True self.practical_ASLR_ROP[30] = True elif op2_family == 5: self.practical_ASLR_ROP[31] = True self.practical_ASLR_ROP[32] = True self.practical_ASLR_ROP[33] = True self.practical_ASLR_ROP[34] = True elif op2_family == 0: if op1_family == 1: self.practical_ASLR_ROP[11] = True self.practical_ASLR_ROP[12] = True self.practical_ASLR_ROP[13] = True self.practical_ASLR_ROP[14] = True elif op1_family == 2: self.practical_ASLR_ROP[15] = True self.practical_ASLR_ROP[16] = True self.practical_ASLR_ROP[17] = True self.practical_ASLR_ROP[18] = True elif op1_family == 3: self.practical_ASLR_ROP[19] = True self.practical_ASLR_ROP[20] = True self.practical_ASLR_ROP[21] = True self.practical_ASLR_ROP[22] = True elif op1_family == 6: self.practical_ASLR_ROP[23] = True self.practical_ASLR_ROP[24] = True self.practical_ASLR_ROP[25] = True self.practical_ASLR_ROP[26] = True elif op1_family == 4: self.practical_ASLR_ROP[27] = True self.practical_ASLR_ROP[28] = True self.practical_ASLR_ROP[29] = True self.practical_ASLR_ROP[30] = True elif op1_family == 5: self.practical_ASLR_ROP[31] = True self.practical_ASLR_ROP[32] = True self.practical_ASLR_ROP[33] = True self.practical_ASLR_ROP[34] = True # MOV between AX and another GPR if opcode == "mov" and "[" not in op1 and "[" not in op2: if op1_family == 0: if op2_family == 1: self.practical_ASLR_ROP[13] = True self.practical_ASLR_ROP[14] = True elif op2_family == 2: self.practical_ASLR_ROP[17] = True self.practical_ASLR_ROP[18] = True elif op2_family == 3: self.practical_ASLR_ROP[21] = True self.practical_ASLR_ROP[22] = True elif op2_family == 6: self.practical_ASLR_ROP[25] = True self.practical_ASLR_ROP[26] = True elif op2_family == 4: self.practical_ASLR_ROP[29] = True self.practical_ASLR_ROP[30] = True elif op2_family == 5: self.practical_ASLR_ROP[33] = True self.practical_ASLR_ROP[34] = True elif op2_family == 0: if op1_family == 1: self.practical_ASLR_ROP[11] = True self.practical_ASLR_ROP[12] = True elif op1_family == 2: self.practical_ASLR_ROP[15] = True self.practical_ASLR_ROP[16] = True elif op1_family == 3: self.practical_ASLR_ROP[19] = True self.practical_ASLR_ROP[20] = True elif op1_family == 6: self.practical_ASLR_ROP[23] = True self.practical_ASLR_ROP[24] = True elif op1_family == 4: self.practical_ASLR_ROP[27] = True self.practical_ASLR_ROP[28] = True elif op1_family == 5: self.practical_ASLR_ROP[31] = True self.practical_ASLR_ROP[32] = True # ["add", "adc", "sub", "sbb", "and", "or", "xor"] between AX and another GPR if opcode in ["add", "adc", "sub", "sbb", "and", "or", "xor" ] and "[" not in op1 and "[" not in op2: if op1_family == 0: if op2_family == 1: self.practical_ASLR_ROP[14] = True elif op2_family == 2: self.practical_ASLR_ROP[18] = True elif op2_family == 3: self.practical_ASLR_ROP[22] = True elif op2_family == 6: self.practical_ASLR_ROP[26] = True elif op2_family == 4: self.practical_ASLR_ROP[30] = True elif op2_family == 5: self.practical_ASLR_ROP[34] = True elif op2_family == 0: if op1_family == 1: self.practical_ASLR_ROP[12] = True elif op1_family == 2: self.practical_ASLR_ROP[16] = True elif op1_family == 3: self.practical_ASLR_ROP[20] = True elif op1_family == 6: self.practical_ASLR_ROP[24] = True elif op1_family == 4: self.practical_ASLR_ROP[28] = True elif op1_family == 5: self.practical_ASLR_ROP[32] = True # Resume checks for individual classes 11, 15, 19, 23, 27, and 31. Others entirely checked entirely above if self.practical_ASLR_ROP[11] is False: if opcode == "pop" and "[" not in op1 and op1_family == 1: self.practical_ASLR_ROP[11] = True if self.practical_ASLR_ROP[15] is False: if opcode == "pop" and "[" not in op1 and op1_family == 2: self.practical_ASLR_ROP[15] = True if self.practical_ASLR_ROP[19] is False: if opcode == "pop" and "[" not in op1 and op1_family == 3: self.practical_ASLR_ROP[19] = True if self.practical_ASLR_ROP[23] is False: if opcode == "pop" and "[" not in op1 and op1_family == 6: self.practical_ASLR_ROP[23] = True if self.practical_ASLR_ROP[27] is False: if opcode == "pop" and "[" not in op1 and op1_family == 4: self.practical_ASLR_ROP[27] = True if self.practical_ASLR_ROP[31] is False: if opcode == "pop" and "[" not in op1 and op1_family == 5: self.practical_ASLR_ROP[31] = True