def _rep_prefix_begin(self, tb, instruction): # Define counter register. if self._arch_info.address_size == 16: counter = ReilRegisterOperand("cx", 16) elif self._arch_info.address_size == 32: counter = ReilRegisterOperand("ecx", 32) elif self._arch_info.address_size == 64: counter = ReilRegisterOperand("rcx", 64) else: raise Exception("Invalid address size: %d", self._arch_info.address_size) # Create labels. loop_start_lbl = Label('loop_start') # Define immediate registers. end_addr = ReilImmediateOperand((instruction.address + instruction.size) << 8, self._arch_info.address_size + 8) # Define temporary registers. counter_zero = tb.temporal(1) tb.add(loop_start_lbl) tb.add(self._builder.gen_bisz(counter, counter_zero)) tb.add(self._builder.gen_jcc(counter_zero, end_addr)) return counter, loop_start_lbl
def _compute_register_list(self, operand): """Return operand register list. """ ret = [] for reg_range in operand.reg_list: if len(reg_range) == 1: ret.append( ReilRegisterOperand(reg_range[0].name, reg_range[0].size)) else: reg_num = int( reg_range[0].name[1:] ) # Assuming the register is named with one letter + number reg_end = int(reg_range[1].name[1:]) if reg_num > reg_end: raise NotImplementedError( "Instruction Not Implemented: Invalid register range.") while reg_num <= reg_end: ret.append( ReilRegisterOperand( reg_range[0].name[0] + str(reg_num), reg_range[0].size)) reg_num = reg_num + 1 return ret
def write(self, tb, x86_operand, value): if isinstance(x86_operand, X86RegisterOperand): reil_operand = ReilRegisterOperand(x86_operand.name, x86_operand.size) if self._arch_info.architecture_mode == ARCH_X86_MODE_64 and x86_operand.size == 32: if x86_operand.name in self._regs_mapper: base_reg, offset = self._regs_mapper[x86_operand.name] reil_operand_base = ReilRegisterOperand( base_reg, self._regs_size[base_reg]) reil_immediate = ReilImmediateOperand( 0x0, self._regs_size[base_reg]) tb.add( tb._builder.gen_str(reil_immediate, reil_operand_base)) tb.add(tb._builder.gen_str(value, reil_operand)) elif isinstance(x86_operand, X86MemoryOperand): addr = self.resolve_memory_access(tb, x86_operand) if value.size != x86_operand.size: tmp = tb.temporal(x86_operand.size) tb.add(tb._builder.gen_str(value, tmp)) tb.add(tb._builder.gen_stm(tmp, addr)) else: tb.add(tb._builder.gen_stm(value, addr)) else: raise Exception('Invalid operand type')
def _translate_ldrd(self, tb, instruction): if len(instruction.operands ) > 2: # Rd2 has been specified (UAL syntax) addr_reg = tb._compute_memory_address(instruction.operands[2]) else: addr_reg = tb._compute_memory_address(instruction.operands[1]) reil_operand = ReilRegisterOperand(instruction.operands[0].name, instruction.operands[0].size) tb.add(tb._builder.gen_ldm(addr_reg, reil_operand)) addr_reg = tb._add_to_reg(addr_reg, ReilImmediateOperand(4, reil_operand.size)) if len(instruction.operands ) > 2: # Rd2 has been specified (UAL syntax) reil_operand = ReilRegisterOperand(instruction.operands[1].name, instruction.operands[0].size) else: # TODO: Assuming the register is written in its number format # (no alias like lr or pc). reil_operand = ReilRegisterOperand( 'r' + str(int(reil_operand.name[1:]) + 1), reil_operand.size) tb.add(tb._builder.gen_ldm(addr_reg, reil_operand))
def test_arithmetic_store_add_2(self): # testing : dst_reg <- dst_reg + mem[src_reg + offset] binary = "\x22\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4, 0x22] binary += "\x03\x30\x80\xe0" # 0x00 : (4) add r3, r0, r3 binary += "\x22\x30\x84\xe5" # 0x00 : (4) str r3, [r4, 0x22] binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 2) self.assertEquals(g_classified[1].type, GadgetType.ArithmeticStore) self.assertEquals(g_classified[1].sources, [ ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32), ReilRegisterOperand("r0", 32) ]) self.assertEquals( g_classified[1].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32)]) self.assertEquals(g_classified[1].operation, "+") self.assertEquals(len(g_classified[1].modified_registers), 1) self.assertFalse( ReilRegisterOperand("r4", 32) in g_classified[1].modified_registers) self.assertTrue( ReilRegisterOperand("r3", 32) in g_classified[1].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[1]))
def _classify_arithmetic(self, regs_init, regs_fini, mem_fini, written_regs, read_regs): """Classify binary-operation gadgets. """ matches = [] # TODO: Review these restrictions. op_restrictions = { "+": lambda x, y: False, "-": lambda x, y: x == y, "|": lambda x, y: x == y, "&": lambda x, y: x == y, "^": lambda x, y: x == y, } # Check for "dst_reg <- src1_reg OP src2_reg" pattern. for op_name, op_fn in self._binary_ops.items(): for src_1_reg, src_1_val in regs_init.items(): # Make sure the *src* register was read. if src_1_reg not in read_regs: continue for src_2_reg, src_2_val in regs_init.items(): # Make sure the *src* register was read. if src_2_reg not in read_regs: continue for dst_reg, dst_val in regs_fini.items(): # Make sure the *dst* register was written. if dst_reg not in written_regs: continue # Check restrictions. if self._arch_regs_size[src_1_reg] != self._arch_regs_size[src_2_reg] or \ self._arch_regs_size[src_1_reg] != self._arch_regs_size[dst_reg]: continue # Avoid trivial operations. if op_restrictions[op_name](src_1_reg, src_2_reg): continue size = self._arch_regs_size[src_1_reg] if dst_val == op_fn(src_1_val, src_2_val) & (2**size - 1): src = sorted([src_1_reg, src_2_reg]) src_ir = [ ReilRegisterOperand(src[0], self._arch_regs_size[src[0]]), ReilRegisterOperand(src[1], self._arch_regs_size[src[1]]) ] dst_reg_ir = ReilRegisterOperand(dst_reg, self._arch_regs_size[dst_reg]) matches.append({ "src": src_ir, "dst": [dst_reg_ir], "op": op_name }) return matches
def _classify_load_memory(self, regs_init, regs_fini, mem_fini, written_regs, read_regs): """Classify load-memory gadgets. """ matches = [] regs_init_inv = self._invert_dictionary(regs_init) # Check for "dst_reg <- mem[src_reg + offset]" pattern. for dst_reg, dst_val in regs_fini.items(): # Make sure the *dst* register was written. if dst_reg not in written_regs: continue dst_size = self._arch_regs_size[dst_reg] # Look for memory addresses that contain *dst_val*. for src_addr in mem_fini.read_inverse(dst_val, dst_size // 8): # Look for registers whose values are used as memory # addresses. for src_reg, src_val in regs_init.items(): # Make sure the *src* register was read. if src_reg not in read_regs: continue # Check restrictions. if self._arch_regs_size[src_reg] != self._address_size: continue offset = (src_addr - src_val) & (2**self._address_size - 1) src_reg_ir = ReilRegisterOperand(src_reg, self._arch_regs_size[src_reg]) src_off_ir = ReilImmediateOperand(offset, self._arch_regs_size[src_reg]) dst_reg_ir = ReilRegisterOperand(dst_reg, self._arch_regs_size[dst_reg]) matches.append({ "src": [src_reg_ir, src_off_ir], "dst": [dst_reg_ir] }) # Check for "dst_reg <- mem[offset]" pattern. for dst_reg, dst_val in regs_fini.items(): # Make sure the *dst* register was written. if dst_reg not in written_regs: continue dst_size = self._arch_regs_size[dst_reg] for src_addr in mem_fini.read_inverse(dst_val, dst_size // 8): src_reg_ir = ReilEmptyOperand() src_off_ir = ReilImmediateOperand(src_addr, self._address_size) dst_reg_ir = ReilRegisterOperand(dst_reg, self._arch_regs_size[dst_reg]) matches.append({ "src": [src_reg_ir, src_off_ir], "dst": [dst_reg_ir] }) return matches
def _classify_store_memory(self, regs_init, regs_fini, mem_fini, written_regs, read_regs): """Classify store-memory gadgets. """ matches = [] regs_init_inv = self._invert_dictionary(regs_init) # Check for "mem[dst_reg + offset] <- src_reg" pattern. for src_reg, src_val in regs_init.items(): # Make sure the *src* register was read. if src_reg not in read_regs: continue src_size = self._arch_regs_size[src_reg] for addr in mem_fini.read_inverse(src_val, src_size // 8): for dst_reg, dst_val in regs_init.items(): # Make sure the *dst* register was written. if dst_reg not in read_regs: continue # Check restrictions. if self._arch_regs_size[dst_reg] != self._address_size: continue offset = (addr - dst_val) & (2**self._address_size - 1) src_reg_ir = ReilRegisterOperand(src_reg, self._arch_regs_size[src_reg]) dst_reg_ir = ReilRegisterOperand(dst_reg, self._arch_regs_size[dst_reg]) dst_off_ir = ReilImmediateOperand(offset, self._arch_regs_size[dst_reg]) matches.append({ "src": [src_reg_ir], "dst": [dst_reg_ir, dst_off_ir] }) # Check for "mem[offset] <- src_reg" pattern. for src_reg, src_val in regs_init.items(): # Make sure the *src* register was read. if src_reg not in read_regs: continue src_size = self._arch_regs_size[src_reg] for addr in mem_fini.read_inverse(src_val, src_size // 8): offset = addr & (2**self._address_size - 1) src_reg_ir = ReilRegisterOperand(src_reg, self._arch_regs_size[src_reg]) dst_reg_ir = ReilEmptyOperand() dst_off_ir = ReilImmediateOperand(offset, self._address_size) matches.append({ "src": [src_reg_ir], "dst": [dst_reg_ir, dst_off_ir] }) return matches
def _translate_cdqe(self, tb, instruction): # Flags Affected # None. oprnd1 = ReilRegisterOperand("eax", 32) oprnd2 = ReilRegisterOperand("rax", 64) tmp0 = tb.temporal(oprnd1.size) tb.add(self._builder.gen_sext(oprnd1, tmp0)) tb.add(self._builder.gen_sext(tmp0, oprnd2))
def _compute_shifted_register(self, sh_op): base = ReilRegisterOperand(sh_op.base_reg.name, sh_op.size) if sh_op.shift_amount: ret = self.temporal(sh_op.size) if isinstance(sh_op.shift_amount, ArmImmediateOperand): sh_am = ReilImmediateOperand(sh_op.shift_amount.immediate, sh_op.size) elif isinstance(sh_op.shift_amount, ArmRegisterOperand): sh_am = ReilRegisterOperand(sh_op.shift_amount.name, sh_op.shift_amount.size) else: raise NotImplementedError( "Instruction Not Implemented: Unknown shift amount type.") if sh_op.shift_type == 'lsl': if isinstance(sh_am, ReilImmediateOperand): self.add(self._builder.gen_bsh(base, sh_am, ret)) else: sh_am_greater_32_label = self.label( 'sh_am_greater_32_label') sh_am_end_label = self.label('sh_am_end_label') sh_am_7_0 = self._and_regs( sh_am, self.immediate(0xFF, sh_am.size)) self.add( self._builder.gen_jcc( self._greater_than_or_equal( sh_am_7_0, self.immediate(33, sh_am_7_0.size)), sh_am_greater_32_label)) # Shift < 32 => shifted_register = base lsl sh_am self.add(self._builder.gen_bsh(base, sh_am_7_0, ret)) self._jump_to(sh_am_end_label) # Shift >= 32 => shifted_register = 0 self.add(sh_am_greater_32_label) self.add( self._builder.gen_str(self.immediate(0x0, ret.size), ret)) self.add(sh_am_end_label) else: # TODO: Implement other shift types raise NotImplementedError( "Instruction Not Implemented: Shift type.") else: ret = base return ret
def _translate_movs_suffix(self, tb, instruction, suffix): # Flags Affected # None. # DEST <- SRC; # IF DF = 0 # THEN (E)DI <- (E)DI + sizeof(SRC); # ELSE (E)DI <- (E)DI - sizeof(SRC); # FI; # Define source and destination registers. if self._arch_mode == ARCH_X86_MODE_32: src = ReilRegisterOperand("esi", 32) dst = ReilRegisterOperand("edi", 32) elif self._arch_mode == ARCH_X86_MODE_64: src = ReilRegisterOperand("rsi", 64) dst = ReilRegisterOperand("rdi", 64) else: raise Exception("Invalid architecture mode: %d", self._arch_mode) # Define destination register. if suffix == 'b': data_size = 8 elif suffix == 'w': data_size = 16 elif suffix == 'd': data_size = 32 elif suffix == 'q': data_size = 64 else: raise Exception("Invalid instruction suffix: %s" % suffix) if instruction.prefix: counter, loop_start_lbl = _rep_prefix_begin(self, tb, instruction) # Define temporal registers. tmp0 = tb.temporal(data_size) # Instruction # -------------------------------------------------------------------- # # Move data. tb.add(self._builder.gen_ldm(src, tmp0)) tb.add(self._builder.gen_stm(tmp0, dst)) # Update destination pointer. _update_strings_src_and_dst(self, tb, src, dst, data_size) # -------------------------------------------------------------------- # if instruction.prefix: _rep_prefix_end(self, tb, instruction, counter, loop_start_lbl)
def _compute_memory_address(self, mem_operand): """Return operand memory access translation. """ base = ReilRegisterOperand(mem_operand.base_reg.name, mem_operand.size) if mem_operand.displacement: address = self.temporal(mem_operand.size) if isinstance(mem_operand.displacement, ArmRegisterOperand): disp = ReilRegisterOperand(mem_operand.displacement.name, mem_operand.size) elif isinstance(mem_operand.displacement, ArmImmediateOperand): disp = ReilImmediateOperand(mem_operand.displacement.immediate, mem_operand.size) elif isinstance(mem_operand.displacement, ArmShiftedRegisterOperand): disp = self._compute_shifted_register(mem_operand.displacement) else: raise Exception( "_compute_memory_address: displacement type unknown") if mem_operand.index_type == ARM_MEMORY_INDEX_PRE: if mem_operand.disp_minus: self.add(self._builder.gen_sub(base, disp, address)) else: self.add(self._builder.gen_add(base, disp, address)) self.add(self._builder.gen_str(address, base)) elif mem_operand.index_type == ARM_MEMORY_INDEX_OFFSET: if mem_operand.disp_minus: self.add(self._builder.gen_sub(base, disp, address)) else: self.add(self._builder.gen_add(base, disp, address)) elif mem_operand.index_type == ARM_MEMORY_INDEX_POST: self.add(self._builder.gen_str(base, address)) tmp = self.temporal(base.size) if mem_operand.disp_minus: self.add(self._builder.gen_sub(base, disp, tmp)) else: self.add(self._builder.gen_add(base, disp, tmp)) self.add(self._builder.gen_str(tmp, base)) else: raise Exception( "_compute_memory_address: indexing type unknown") else: address = base return address
def _translate_branch(self, tb, instruction, link): if instruction.condition_code == ARM_COND_CODE_AL: cond = tb.immediate(1, 1) else: eval_cc_fn = { ARM_COND_CODE_EQ: self._evaluate_eq, ARM_COND_CODE_NE: self._evaluate_ne, ARM_COND_CODE_CS: self._evaluate_cs, ARM_COND_CODE_HS: self._evaluate_cs, ARM_COND_CODE_CC: self._evaluate_cc, ARM_COND_CODE_LO: self._evaluate_cc, ARM_COND_CODE_MI: self._evaluate_mi, ARM_COND_CODE_PL: self._evaluate_pl, ARM_COND_CODE_VS: self._evaluate_vs, ARM_COND_CODE_VC: self._evaluate_vc, ARM_COND_CODE_HI: self._evaluate_hi, ARM_COND_CODE_LS: self._evaluate_ls, ARM_COND_CODE_GE: self._evaluate_ge, ARM_COND_CODE_LT: self._evaluate_lt, ARM_COND_CODE_GT: self._evaluate_gt, ARM_COND_CODE_LE: self._evaluate_le, } cond = eval_cc_fn[instruction.condition_code](tb) arm_operand = instruction.operands[0] if isinstance(arm_operand, ArmImmediateOperand): target = ReilImmediateOperand(arm_operand.immediate << 8, self._pc.size + 8) elif isinstance(arm_operand, ArmRegisterOperand): target = ReilRegisterOperand(arm_operand.name, arm_operand.size) target = tb._and_regs( target, ReilImmediateOperand(0xFFFFFFFE, target.size)) tmp0 = tb.temporal(target.size + 8) tmp1 = tb.temporal(target.size + 8) tb.add(self._builder.gen_str(target, tmp0)) tb.add( self._builder.gen_bsh(tmp0, ReilImmediateOperand(8, target.size + 8), tmp1)) target = tmp1 else: raise NotImplementedError( "Instruction Not Implemented: Unknown operand for branch operation." ) if link: tb.add( self._builder.gen_str( ReilImmediateOperand( instruction.address + instruction.size, self._pc.size), self._lr)) tb.add(self._builder.gen_jcc(cond, target)) return
def read(self, arm_operand): if isinstance(arm_operand, ArmImmediateOperand): reil_operand = ReilImmediateOperand(arm_operand.immediate, arm_operand.size) elif isinstance(arm_operand, ArmRegisterOperand): reil_operand = ReilRegisterOperand(arm_operand.name, arm_operand.size) elif isinstance(arm_operand, ArmShiftedRegisterOperand): reil_operand = self._compute_shifted_register(arm_operand) elif isinstance(arm_operand, ArmMemoryOperand): addr = self._compute_memory_address(arm_operand) reil_operand = self.temporal(arm_operand.size) self.add(self._builder.gen_ldm(addr, reil_operand)) elif isinstance(arm_operand, ArmRegisterListOperand): reil_operand = self._compute_register_list(arm_operand) else: raise NotImplementedError( "Instruction Not Implemented: Unknown operand for read operation." ) return reil_operand
def _create_typed_gadgets(self, gadget, classified_gadgets, modified_regs, gadget_type): typed_gadgets = [] # Remove register aliases mod_regs = [] for r in modified_regs: alias, _ = self._arch_info.alias_mapper.get(r, (None, None)) if not alias: mod_regs += [r] elif alias not in modified_regs: mod_regs += [r] modified_regs_ir = [ReilRegisterOperand(r, self._arch_regs_size[r]) for r in mod_regs] for candidate in classified_gadgets: typed_gadget = TypedGadget(gadget, gadget_type, gadget.instrs) if gadget_type in [GadgetType.Arithmetic, GadgetType.ArithmeticLoad, GadgetType.ArithmeticStore]: typed_gadget.operation = candidate["op"] if candidate.get("op", "") != "nop": typed_gadget.sources = candidate["src"] typed_gadget.destination = candidate["dst"] if gadget_type == GadgetType.StoreMemory: typed_gadget.modified_registers = [r for r in modified_regs_ir] else: typed_gadget.modified_registers = [r for r in modified_regs_ir if r not in typed_gadget.destination] typed_gadgets += [typed_gadget] return typed_gadgets
def _translate_cbnz(self, tb, instruction): oprnd0 = tb.read(instruction.operands[0]) arm_operand = instruction.operands[1] if isinstance(arm_operand, ArmImmediateOperand): target = ReilImmediateOperand(arm_operand.immediate << 8, self._pc.size + 8) elif isinstance(arm_operand, ArmRegisterOperand): target = ReilRegisterOperand(arm_operand.name, arm_operand.size) target = tb._and_regs( target, ReilImmediateOperand(0xFFFFFFFE, target.size)) tmp0 = tb.temporal(target.size + 8) tmp1 = tb.temporal(target.size + 8) tb.add(self._builder.gen_str(target, tmp0)) tb.add( self._builder.gen_bsh(tmp0, ReilImmediateOperand(8, target.size + 8), tmp1)) target = tmp1 else: raise Exception() neg_oprnd = tb._negate_reg(oprnd0) tb._jump_if_zero(neg_oprnd, target)
def _translate_sahf(self, tb, instruction): # Flags Affected # The SF, ZF, AF, PF, and CF flags are loaded with values from # the AH register. Bits 1, 3, and 5 of the EFLAGS register are # unaffected, with the values remaining 1, 0, and 0, # respectively. oprnd0 = ReilRegisterOperand("ah", 8) tmp0 = tb.temporal(oprnd0.size) tmp1 = tb.temporal(oprnd0.size) tmp2 = tb.temporal(oprnd0.size) tmp3 = tb.temporal(oprnd0.size) shl_two = tb.immediate(-2, 8) shl_one = tb.immediate(-1, 8) tb.add(self._builder.gen_str(oprnd0, self._flags["cf"])) tb.add(self._builder.gen_bsh(oprnd0, shl_two, tmp0)) tb.add(self._builder.gen_str(tmp0, self._flags["pf"])) tb.add(self._builder.gen_bsh(tmp0, shl_two, tmp1)) tb.add(self._builder.gen_str(tmp1, self._flags["af"])) tb.add(self._builder.gen_bsh(tmp1, shl_two, tmp2)) tb.add(self._builder.gen_str(tmp2, self._flags["zf"])) tb.add(self._builder.gen_bsh(tmp2, shl_one, tmp3)) tb.add(self._builder.gen_str(tmp3, self._flags["sf"]))
def _translate_branch(self, tb, instruction, link): arm_operand = instruction.operands[0] if isinstance(arm_operand, ArmImmediateOperand): target = ReilImmediateOperand(arm_operand.immediate << 8, self._pc.size + 8) elif isinstance(arm_operand, ArmRegisterOperand): target = ReilRegisterOperand(arm_operand.name, arm_operand.size) target = tb._and_regs( target, ReilImmediateOperand(0xFFFFFFFE, target.size)) tmp0 = tb.temporal(target.size + 8) tmp1 = tb.temporal(target.size + 8) tb.add(self._builder.gen_str(target, tmp0)) tb.add( self._builder.gen_bsh(tmp0, ReilImmediateOperand(8, target.size + 8), tmp1)) target = tmp1 else: raise NotImplementedError( "Instruction Not Implemented: Unknown operand for branch operation." ) if (link): tb.add( self._builder.gen_str( ReilImmediateOperand( instruction.address + instruction.size, self._pc.size), self._lr)) tb._jump_to(target)
def _translate_ldrh(self, tb, instruction): op0_reil = ReilRegisterOperand(instruction.operands[0].name, instruction.operands[0].size) addr_reg = self._reg_acc_translator.compute_memory_address(tb, instruction.operands[1]) byte_reg = tb.temporal(16) tb.add(tb._builder.gen_ldm(addr_reg, byte_reg)) tb.add(self._builder.gen_str(byte_reg, op0_reil))
def test_move_register_2(self): # testing : dst_reg <- src_reg binary = b"\x00\x00\x84\xe2" # 0x00 : (4) add r0, r4, #0 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.MoveRegister) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0]))
def test_store_memory_2(self): # testing : dst_reg <- m[src_reg + offset] binary = b"\x33\x30\x84\xe5" # 0x00 : (4) str r3, [r4 + 0x33] binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.StoreMemory) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r3", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x33, 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0]))
def __init__(self, architecture_mode=ARCH_ARM_MODE_THUMB, translation_mode=FULL_TRANSLATION): super(ArmTranslator, self).__init__() # Set *Architecture Mode*. The translation of each instruction # into the REIL language is based on this. self._arch_mode = architecture_mode # An instance of *ArchitectureInformation*. self._arch_info = ArmArchitectureInformation(architecture_mode) # Set *Translation Mode*. self._translation_mode = translation_mode # An instance of a *VariableNamer*. This is used so all the # temporary REIL registers are unique. self._ir_name_generator = VariableNamer("t", separator="") self._builder = ReilInstructionBuilder() self._flags = { "nf": ReilRegisterOperand("nf", 1), "zf": ReilRegisterOperand("zf", 1), "cf": ReilRegisterOperand("cf", 1), "vf": ReilRegisterOperand("vf", 1), } if self._arch_mode in [ARCH_ARM_MODE_ARM, ARCH_ARM_MODE_THUMB]: self._sp = ReilRegisterOperand("r13", 32) # TODO: Implement alias self._pc = ReilRegisterOperand("r15", 32) self._lr = ReilRegisterOperand("r14", 32) self._ws = ReilImmediateOperand(4, 32) # word size
def __init__(self, architecture_mode=ARCH_ARM_MODE_THUMB): super(ArmTranslator, self).__init__() # Set *Architecture Mode*. The translation of each instruction # into the REIL language is based on this. self._arch_mode = architecture_mode # An instance of *ArchitectureInformation*. self._arch_info = ArmArchitectureInformation(architecture_mode) self._builder = ReilBuilder() self._flags = { "nf": ReilRegisterOperand("nf", 1), "zf": ReilRegisterOperand("zf", 1), "cf": ReilRegisterOperand("cf", 1), "vf": ReilRegisterOperand("vf", 1), } if self._arch_mode in [ARCH_ARM_MODE_ARM, ARCH_ARM_MODE_THUMB]: self._sp = ReilRegisterOperand("r13", 32) # TODO: Implement alias self._pc = ReilRegisterOperand("r15", 32) self._lr = ReilRegisterOperand("r14", 32) self._ws = ReilImmediateOperand(4, 32) # word size
def _translate_strh(self, tb, instruction): reil_operand = ReilRegisterOperand(instruction.operands[0].name, instruction.operands[0].size) half_word_reg = tb.temporal(16) tb.add(self._builder.gen_str(reil_operand, half_word_reg)) # filter bits [15:0] part of result addr = self._reg_acc_translator.compute_memory_address(tb, instruction.operands[1]) tb.add(self._builder.gen_stm(half_word_reg, addr))
def test_load_constant_4(self): # testing : dst_reg <- constant binary = b"\x00\x20\x02\xe2" # 0x00 : (4) and r2, r2, #0 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.LoadConstant) self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(0, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0]))
def test_arithmetic_sub_1(self): # testing : dst_reg <- src1_reg + src2_reg binary = b"\x08\x00\x44\xe0" # 0x00 : (4) sub r0, r4, r8 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.Arithmetic) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilRegisterOperand("r8", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEqual(g_classified[0].operation, "-") self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0]))
def _translate_strb(self, tb, instruction): reil_operand = ReilRegisterOperand(instruction.operands[0].name, instruction.operands[0].size) byte_reg = tb.temporal(8) tb.add(self._builder.gen_str(reil_operand, byte_reg)) # filter bits [7:0] part of result addr = tb._compute_memory_address(instruction.operands[1]) tb.add(self._builder.gen_stm(byte_reg, addr))
def test_move_register_1(self): # testing : dst_reg <- src_reg binary = b"\x04\x00\xa0\xe1" # 0x00 : (4) mov r0, r4 binary += b"\x31\xff\x2f\xe1" # 0x04 : (4) blx r1 g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 2) self.assertEqual(g_classified[0].type, GadgetType.MoveRegister) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 1) self.assertTrue(ReilRegisterOperand("r14", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0]))
def __get_register(self, register): register = register.lower() if register not in self.__arch.registers_gp_all: raise TranslationError("Invalid register") if register not in self.__registers: self.__registers[register] = ReilRegisterOperand( register, self.__arch.registers_size[register]) return self.__registers[register]
def __get_flag(self, flag): flag = flag.lower() if flag not in self.__arch.registers_flags: raise TranslationError("Invalid flag") if flag not in self.__flags: self.__flags[flag] = ReilRegisterOperand( flag, self.__arch.registers_size[flag]) return self.__flags[flag]