class CompareConstantRule4(JumpOptimizationRule): ORIGINAL_JUMP_OPCODES = [m_jl, m_jge] LEFT_PATTERN = AstNode( m_and, AstNode( m_or, AstNode(m_bnot, AstNode(m_sub, AstLeaf('x_0'), AstConstant('c_1'))), AstNode(m_xor, AstLeaf('x_0'), AstConstant('c_1'))), AstNode(m_or, AstLeaf("xdu_x_0"), AstConstant('bnot_c_1'))) RIGHT_PATTERN = AstConstant("0", 0) REPLACEMENT_OPCODE = m_jge REPLACEMENT_LEFT_PATTERN = AstLeaf("x_0") REPLACEMENT_RIGHT_PATTERN = AstLeaf("c_1") def check_candidate(self, opcode, left_candidate, right_candidate): print("dflighdrth") if not equal_mops_bypass_xdu(left_candidate["xdu_x_0"].mop, left_candidate["x_0"].mop): return False if not equal_bnot_mop(left_candidate["c_1"].mop, left_candidate["bnot_c_1"].mop): return False self.jump_replacement_block_serial = self.jump_original_block_serial return True
class CstSimplificationRule22(PatternMatchingRule): PATTERN = AstNode( m_or, AstNode(m_xor, AstNode(m_and, AstLeaf('x_0'), AstConstant('c_and')), AstConstant('c_xor_1')), AstNode(m_xor, AstNode(m_and, AstLeaf('bnot_x_0'), AstConstant('bnot_c_and')), AstConstant('c_xor_2'))) REPLACEMENT_PATTERN = AstNode(m_xor, AstLeaf("x_0"), AstConstant("c_xor_res")) def check_candidate(self, candidate): if not equal_bnot_mop(candidate["x_0"].mop, candidate["bnot_x_0"].mop): return False if not equal_bnot_cst(candidate["c_and"].mop, candidate["bnot_c_and"].mop): return False if candidate["c_xor_1"].mop.nnn.value & candidate[ "c_xor_2"].mop.nnn.value != 0: return False if candidate["c_xor_1"].mop.nnn.value & candidate[ "bnot_c_and"].mop.nnn.value != 0: return False candidate.add_constant_leaf( "c_xor_res", candidate["c_xor_1"].value ^ candidate["c_xor_2"].value ^ candidate["bnot_c_and"].value, candidate["c_xor_1"].size) return True
class ReplaceMovHigh(PatternMatchingRule): PATTERN = AstNode(m_mov, AstConstant('c_0')) REPLACEMENT_PATTERN = AstNode( m_or, AstConstant("new_c_0"), AstNode(m_and, AstLeaf("new_reg"), AstConstant("mask"))) def check_candidate(self, candidate): # IDA does not do constant propagation for pattern such as: # mov #0x65A4.2, r6.2 # mov #0x210F.2, r6^2.2 # jz r0.4, r6.4 # Thus, we try to detect mov to r6^2 and replace by (or #0x210F0000.4, r6.4 & 0x0000ffff.4, r6.4 # By doing that, IDA constant propagation will work again. if candidate.dst_mop.t != mop_r: return False dst_reg_name = format_mop_t(candidate.dst_mop) if dst_reg_name is None: return False if "^2" in dst_reg_name: if candidate["c_0"].mop.size != 2: return False candidate.add_constant_leaf("new_c_0", candidate["c_0"].value << 16, 4) candidate.add_constant_leaf("mask", 0xffff, 4) new_dst_reg = mop_t() new_dst_reg.make_reg(candidate.dst_mop.r - 2, 4) candidate.add_leaf("new_reg", new_dst_reg) candidate.dst_mop = new_dst_reg return True else: return False
class CstSimplificationRule1(PatternMatchingRule): PATTERN = AstNode( m_and, AstNode(m_bnot, AstLeaf("x_0")), AstNode(m_xor, AstNode(m_bnot, AstLeaf("x_0")), AstConstant("c_1"))) REPLACEMENT_PATTERN = AstNode( m_xor, AstNode(m_and, AstLeaf("x_0"), AstNode(m_bnot, AstConstant("c_1"))), AstNode(m_bnot, AstConstant("c_1")))
class Bnot_MbaRule_1(PatternMatchingRule): PATTERN = AstNode(m_sub, AstNode(m_sub, AstLeaf("x_0"), AstConstant("1", 1)), AstNode(m_mul, AstConstant("2", 2), AstLeaf("x_0"))) REPLACEMENT_PATTERN = AstNode(m_bnot, AstLeaf("x_0"))
class CstSimplificationRule5(PatternMatchingRule): PATTERN = AstNode(m_or, AstNode(m_and, AstLeaf("x_0"), AstConstant("c_1")), AstNode(m_and, AstLeaf("x_1"), AstConstant("c_2"))) REPLACEMENT_PATTERN = AstNode( m_xor, AstNode(m_and, AstNode(m_xor, AstLeaf("x_0"), AstLeaf("x_1")), AstConstant("c_1")), AstLeaf("x_1")) def check_candidate(self, candidate): return equal_bnot_cst(candidate["c_1"].mop, candidate["c_2"].mop)
class Xor1_MbaRule_1(PatternMatchingRule): PATTERN = AstNode( m_add, AstNode(m_bnot, AstLeaf('x_0')), AstNode(m_or, AstNode(m_mul, AstConstant('2', 2), AstLeaf('x_0')), AstConstant('2', 2))) REPLACEMENT_PATTERN = AstNode(m_xor, AstLeaf('x_0'), AstConstant("val_1")) def check_candidate(self, candidate): candidate.add_constant_leaf("val_1", 1, candidate.size) return True
class CstSimplificationRule15(PatternMatchingRule): PATTERN = AstNode(m_shr, AstNode(m_shr, AstLeaf("x_0"), AstConstant("c_1")), AstConstant("c_2")) REPLACEMENT_PATTERN = AstNode(m_shr, AstLeaf("x_0"), AstConstant("c_res")) def check_candidate(self, candidate): candidate.add_constant_leaf( "c_res", candidate["c_1"].value + candidate["c_2"].value, candidate["c_1"].size) return True
class CstSimplificationRule4(PatternMatchingRule): PATTERN = AstNode(m_sub, AstLeaf("x_0"), AstNode(m_sub, AstConstant("c_1"), AstLeaf("x_1"))) REPLACEMENT_PATTERN = AstNode( m_add, AstLeaf("x_0"), AstNode(m_add, AstLeaf("x_1"), AstConstant("c_res"))) def check_candidate(self, candidate): c_res = SUB_TABLE[candidate["c_1"].size] - candidate["c_1"].value candidate.add_constant_leaf("c_res", c_res, candidate["c_1"].size) return True
class And1_MbaRule_1(PatternMatchingRule): PATTERN = AstNode(m_and, AstNode(m_mul, AstLeaf("x_0"), AstLeaf("x_0")), AstConstant("3", 3)) REPLACEMENT_PATTERN = AstNode(m_and, AstLeaf("x_0"), AstConstant("val_1")) def check_candidate(self, candidate): candidate.add_constant_leaf("val_1", 1, candidate.size) return True
class JbRule1(JumpOptimizationRule): ORIGINAL_JUMP_OPCODES = [m_jb] PATTERN = AstNode(m_xdu, AstNode(m_and, AstLeaf("x_0"), AstConstant("1", 1))) RIGHT_PATTERN = AstConstant("2", 2) REPLACEMENT_OPCODE = m_goto def check_candidate(self, opcode, left_candidate, right_candidate): self.jump_replacement_block_serial = self.jump_original_block_serial return True
class Xor_HackersDelightRule_4(PatternMatchingRule): PATTERN = AstNode( m_sub, AstNode( m_sub, AstNode(m_sub, AstLeaf('x_0'), AstLeaf('x_1')), AstNode( m_mul, AstConstant('2', 2), AstNode(m_or, AstLeaf('x_0'), AstNode(m_bnot, AstLeaf('x_1'))))), AstConstant('2', 2)) REPLACEMENT_PATTERN = AstNode(m_xor, AstLeaf("x_0"), AstLeaf("x_1"))
class JaeRule1(JumpOptimizationRule): ORIGINAL_JUMP_OPCODES = [m_jae] PATTERN = AstNode(m_and, AstLeaf("x_0"), AstConstant("c_1")) RIGHT_PATTERN = AstConstant("c_2") REPLACEMENT_OPCODE = m_goto def check_candidate(self, opcode, left_candidate, right_candidate): if left_candidate["c_1"].value >= right_candidate["c_2"].value: return False self.jump_replacement_block_serial = self.direct_block_serial return True
class CstSimplificationRule8(PatternMatchingRule): PATTERN = AstNode(m_or, AstNode(m_and, AstLeaf("x_0"), AstConstant("c_1")), AstConstant("c_2")) REPLACEMENT_PATTERN = AstNode( m_or, AstNode(m_and, AstLeaf("x_0"), AstConstant("c_res")), AstConstant("c_2")) def check_candidate(self, candidate): c_res = candidate["c_1"].value & ~candidate["c_2"].value if c_res == candidate["c_1"].value: return False candidate.add_constant_leaf("c_res", c_res, candidate["c_1"].size) return True
class Sub1And1_MbaRule_1(PatternMatchingRule): PATTERN = AstNode( m_add, AstNode(m_or, AstNode(m_bnot, AstLeaf('x_0')), AstConstant("1", 1)), AstLeaf('x_0')) REPLACEMENT_PATTERN = AstNode( m_sub, AstNode(m_and, AstLeaf('x_0'), AstConstant("val_1_1")), AstConstant("val_1_2")) def check_candidate(self, candidate): candidate.add_constant_leaf("val_1_1", 1, candidate["x_0"].size) candidate.add_constant_leaf("val_1_2", 1, candidate["x_0"].size) return True
class Sub1_FactorRule_1(PatternMatchingRule): PATTERN = AstNode( m_sub, AstNode(m_sub, AstNode(m_neg, AstLeaf('x_0')), AstConstant('1', 1)), AstNode(m_mul, AstConstant('c_minus_2'), AstLeaf('x_0'))) REPLACEMENT_PATTERN = AstNode(m_sub, AstLeaf("x_0"), AstConstant("val_1")) def check_candidate(self, candidate): if candidate["c_minus_2"].value != SUB_TABLE[ candidate["c_minus_2"].size] - 2: return False candidate.add_constant_leaf("val_1", 1, candidate["x_0"].size) return True
class CompareConstantRule3(JumpOptimizationRule): ORIGINAL_JUMP_OPCODES = [m_jge] LEFT_PATTERN = AstNode(m_and, AstNode(m_sub, AstLeaf('x_0'), AstConstant('c_1')), AstNode(m_bnot, AstLeaf("x_0"))) RIGHT_PATTERN = AstConstant("0", 0) REPLACEMENT_OPCODE = m_jg REPLACEMENT_LEFT_PATTERN = AstLeaf("x_0") REPLACEMENT_RIGHT_PATTERN = AstLeaf("c_1") def check_candidate(self, opcode, left_candidate, right_candidate): self.jump_replacement_block_serial = self.jump_original_block_serial return True
class Add_SpecialConstantRule_1(PatternMatchingRule): PATTERN = AstNode(m_add, AstNode(m_xor, AstLeaf("x_0"), AstConstant("c_1")), AstNode(m_mul, AstConstant("2", 2), AstNode(m_and, AstLeaf("x_0"), AstConstant("c_2")))) REPLACEMENT_PATTERN = AstNode(m_add, AstLeaf("x_0"), AstConstant("c_1")) def check_candidate(self, candidate): return equal_ignore_msb_cst(candidate["c_1"].mop, candidate["c_2"].mop)
class CstSimplificationRule9(PatternMatchingRule): PATTERN = AstNode(m_and, AstNode(m_or, AstLeaf("x_0"), AstConstant("c_1")), AstConstant("c_2")) REPLACEMENT_PATTERN = AstNode( m_xor, AstNode(m_and, AstLeaf("x_0"), AstConstant("c_and")), AstConstant("c_xor")) def check_candidate(self, candidate): c_and = (AND_TABLE[candidate["c_1"].size] ^ candidate["c_1"].value) & candidate["c_2"].value c_xor = candidate["c_1"].value & candidate["c_2"].value candidate.add_constant_leaf("c_and", c_and, candidate["x_0"].size) candidate.add_constant_leaf("c_xor", c_xor, candidate["x_0"].size) return True
class CstSimplificationRule13(PatternMatchingRule): PATTERN = AstNode( m_xor, AstNode(m_and, AstConstant("cst_1"), AstNode(m_xor, AstLeaf("x_0"), AstLeaf("x_1"))), AstLeaf("x_1")) REPLACEMENT_PATTERN = AstNode( m_xor, AstNode(m_and, AstLeaf("x_0"), AstConstant("cst_1")), AstNode(m_and, AstLeaf("x_1"), AstConstant("not_cst_1"))) def check_candidate(self, candidate): candidate.add_constant_leaf("not_cst_1", ~candidate["cst_1"].value, candidate["cst_1"].size) return True
class Xor_Rule_4_WithXdu(PatternMatchingRule): PATTERN = AstNode( m_or, AstNode(m_and, AstLeaf("x_0"), AstConstant("bnot_c_1")), AstNode(m_and, AstNode(m_bnot, AstLeaf("x_0")), AstConstant("c_1"))) REPLACEMENT_PATTERN = AstNode(m_xor, AstLeaf("x_0"), AstLeaf("c_1")) def check_candidate(self, candidate): if candidate["x_0"].mop.t != mop_d: return False if candidate["x_0"].mop.d.opcode != m_xdu: return False return equal_bnot_cst(candidate["c_1"].mop, candidate["bnot_c_1"].mop, mop_size=candidate["x_0"].mop.d.l.size)
class JnzRule2(JumpOptimizationRule): ORIGINAL_JUMP_OPCODES = [m_jnz, m_jz] LEFT_PATTERN = AstNode(m_or, AstNode(m_bnot, AstLeaf("x_0")), AstConstant("1", 1)) RIGHT_PATTERN = AstConstant("0", 0) REPLACEMENT_OPCODE = m_goto def check_candidate(self, opcode, left_candidate, right_candidate): if opcode == m_jnz: self.jump_replacement_block_serial = self.jump_original_block_serial else: self.jump_replacement_block_serial = self.direct_block_serial return True
class XorAlmost_Rule_1(PatternMatchingRule): PATTERN = AstNode( m_sub, AstNode(m_add, AstLeaf("x_0"), AstLeaf("x_1")), AstNode( m_mul, AstConstant("2", 2), AstNode(m_or, AstLeaf("x_0"), AstNode(m_sub, AstLeaf("x_1"), AstConstant("1", 1))))) REPLACEMENT_PATTERN = AstNode( m_add, AstNode(m_xor, AstLeaf("x_0"), AstNode(m_neg, AstLeaf("x_1"))), AstLeaf("val_2")) def check_candidate(self, candidate): candidate.add_constant_leaf("val_2", 2, candidate.size) return True
class Sub1Add_HackersDelightRule_1(PatternMatchingRule): PATTERN = AstNode( m_add, AstNode(m_mul, AstConstant("2", 2), AstNode(m_or, AstLeaf("x_0"), AstLeaf("x_1"))), AstNode(m_xor, AstLeaf("x_0"), AstLeaf("bnot_x_1"))) REPLACEMENT_PATTERN = AstNode( m_sub, AstNode(m_add, AstLeaf("x_0"), AstLeaf("x_1")), AstConstant("val_1")) def check_candidate(self, candidate): if not equal_bnot_mop(candidate["x_1"].mop, candidate["bnot_x_1"].mop): return False candidate.add_constant_leaf("val_1", 1, candidate["x_1"].size) return True
class Or_MbaRule_2(PatternMatchingRule): PATTERN = AstNode( m_add, AstNode(m_add, AstNode(m_add, AstLeaf('x_0'), AstLeaf('x_1')), AstConstant('1', 1)), AstNode(m_bnot, AstNode(m_and, AstLeaf('x_1'), AstLeaf('x_0')))) REPLACEMENT_PATTERN = AstNode(m_or, AstLeaf("x_0"), AstLeaf("x_1"))
class SetGlobalVariablesToZero(EarlyRule): DESCRIPTION = "This rule can be used to patch memory read" PATTERN = AstNode(m_mov, AstLeaf("ro_dword")) REPLACEMENT_PATTERN = AstNode(m_mov, AstConstant("val_res")) def __init__(self): super().__init__() self.ro_dword_min_ea = None self.ro_dword_max_ea = None def configure(self, kwargs): super().configure(kwargs) self.ro_dword_min_ea = None self.ro_dword_max_ea = None if "ro_dword_min_ea" in kwargs.keys(): self.ro_dword_min_ea = int(kwargs["ro_dword_min_ea"], 16) if "ro_dword_max_ea" in kwargs.keys(): self.ro_dword_max_ea = int(kwargs["ro_dword_max_ea"], 16) def check_candidate(self, candidate): if (self.ro_dword_min_ea is None) or (self.ro_dword_max_ea is None): return False if candidate["ro_dword"].mop.t != mop_v: return False mem_read_address = candidate["ro_dword"].mop.g if not(self.ro_dword_min_ea <= mem_read_address <= self.ro_dword_max_ea): return False candidate.add_constant_leaf("val_res", 0, candidate["ro_dword"].mop.size) return True
class Mul_FactorRule_1(PatternMatchingRule): PATTERN = AstNode( m_add, AstConstant("2", 2), AstNode( m_mul, AstConstant("2", 2), AstNode(m_add, AstLeaf("x_1"), AstNode(m_or, AstLeaf("x_0"), AstLeaf("bnot_x_1"))))) REPLACEMENT_PATTERN = AstNode( m_mul, AstConstant("2", 2), AstNode(m_and, AstLeaf("x_0"), AstLeaf("x_1"))) def check_candidate(self, candidate): if not equal_bnot_mop(candidate["x_1"].mop, candidate["bnot_x_1"].mop): return False return True
class CstSimplificationRule3(PatternMatchingRule): PATTERN = AstNode( m_add, AstNode(m_sub, AstLeaf("x_0"), AstConstant("c_0")), AstNode(m_mul, AstConstant("c_1"), AstNode(m_sub, AstLeaf("x_0"), AstConstant("c_2")))) REPLACEMENT_PATTERN = AstNode( m_sub, AstNode(m_mul, AstConstant("c_coeff"), AstLeaf("x_0")), AstConstant("c_sub")) def check_candidate(self, candidate): c_coeff = candidate["c_1"].value + 1 c_sub = (candidate["c_1"].value * candidate["c_2"].value) + candidate["c_0"].value candidate.add_constant_leaf("c_coeff", c_coeff, candidate["c_1"].size) candidate.add_constant_leaf("c_sub", c_sub, candidate["c_2"].size) return True
class NegAdd_HackersDelightRule_1(PatternMatchingRule): PATTERN = AstNode( m_sub, AstNode(m_xor, AstLeaf("x_0"), AstLeaf("x_1")), AstNode(m_mul, AstConstant("2", 2), AstNode(m_or, AstLeaf("x_0"), AstLeaf("x_1")))) REPLACEMENT_PATTERN = AstNode( m_neg, AstNode(m_add, AstLeaf("x_0"), AstLeaf("x_1")))
class Sub_HackersDelightRule_2(PatternMatchingRule): PATTERN = AstNode( m_sub, AstNode(m_xor, AstLeaf("x_0"), AstLeaf("x_1")), AstNode( m_mul, AstConstant("2", 2), AstNode(m_and, AstNode(m_bnot, AstLeaf("x_0")), AstLeaf("x_1")))) REPLACEMENT_PATTERN = AstNode(m_sub, AstLeaf("x_0"), AstLeaf("x_1"))