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_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 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 _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 _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_address(self, tb, oprnd): addr_oprnd_size = oprnd.size + 8 if isinstance(oprnd, ReilRegisterOperand): oprnd_tmp = tb.temporal(addr_oprnd_size) addr_oprnd = tb.temporal(addr_oprnd_size) imm = ReilImmediateOperand(8, addr_oprnd_size) tb.add(self._builder.gen_str(oprnd, oprnd_tmp)) tb.add(self._builder.gen_bsh(oprnd_tmp, imm, addr_oprnd)) elif isinstance(oprnd, ReilImmediateOperand): addr_oprnd = ReilImmediateOperand(oprnd.immediate << 8, addr_oprnd_size) return addr_oprnd
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 __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 _evaluate_condition_code(self, tb, instruction): if instruction.condition_code == ARM_COND_CODE_AL: return 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, } neg_cond = tb._negate_reg(eval_cc_fn[instruction.condition_code](tb)) end_addr = ReilImmediateOperand( (instruction.address + instruction.size) << 8, self._arch_info.address_size + 8) tb.add(self._builder.gen_jcc(neg_cond, end_addr)) return
def _update_strings_dst(self, tb, dst, size, instruction): # Create labels. forward_lbl = ReilLabel('forward') backward_lbl = ReilLabel('backward') end_addr = ReilImmediateOperand((instruction.address + instruction.size) << 8, self._arch_info.address_size + 8) # Define immediate registers. imm_one = tb.immediate(1, 1) # Define temporary registers. df_zero = tb.temporal(1) imm_tmp = tb.immediate(size // 8, dst.size) dst_tmp = tb.temporal(dst.size) # Update destination pointer. tb.add(self._builder.gen_bisz(self._flags.df, df_zero)) tb.add(self._builder.gen_jcc(df_zero, forward_lbl)) # Update backwards. tb.add(backward_lbl) tb.add(self._builder.gen_sub(dst, imm_tmp, dst_tmp)) tb.add(self._builder.gen_str(dst_tmp, dst)) # Jump to next instruction. tb.add(self._builder.gen_jcc(imm_one, end_addr)) # Update forwards. tb.add(forward_lbl) tb.add(self._builder.gen_add(dst, imm_tmp, dst_tmp)) tb.add(self._builder.gen_str(dst_tmp, dst))
def _rep_prefix_end(self, tb, instruction, counter, loop_start_lbl): # Define immediate registers imm_one = tb.immediate(1, 1) counter_imm_one = tb.immediate(1, counter.size) end_addr = ReilImmediateOperand((instruction.address + instruction.size) << 8, self._arch_info.address_size + 8) # Define temporary registers. counter_tmp = tb.temporal(counter.size) counter_zero = tb.temporal(1) zf_zero = tb.temporal(1) # Termination Condition 1: RCX or (E)CX = 0. tb.add(self._builder.gen_sub(counter, counter_imm_one, counter_tmp)) tb.add(self._builder.gen_str(counter_tmp, counter)) tb.add(self._builder.gen_bisz(counter, counter_zero)) tb.add(self._builder.gen_jcc(counter_zero, end_addr)) prefix = instruction.prefix if prefix in ['rep']: # Termination Condition 2: None. pass elif prefix in ['repz', 'repe']: # Termination Condition 2: ZF = 0. tb.add(self._builder.gen_xor(self._flags.zf, imm_one, zf_zero)) tb.add(self._builder.gen_jcc(zf_zero, end_addr)) elif prefix in ['repnz', 'repne']: # Termination Condition 2: ZF = 1. tb.add(self._builder.gen_str(self._flags.zf, zf_zero)) tb.add(self._builder.gen_jcc(zf_zero, end_addr)) else: raise Exception('Invalid prefix: %s' % prefix) tb.add(self._builder.gen_jcc(imm_one, loop_start_lbl))
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 __resolve_loops(self, address, instrs): # Collect labels. idx_by_labels = {} instrs_no_labels = [] curr = 0 for i in instrs: if isinstance(i, ReilLabel): idx_by_labels[i.name] = curr else: instrs_no_labels.append(i) curr += 1 instrs[:] = instrs_no_labels # Resolve instruction addresses and JCC targets. for index, instr in enumerate(instrs): instr.address = to_reil_address(address, index) if instr.mnemonic == ReilMnemonic.JCC: target = instr.operands[2] if isinstance(target, ReilLabel): addr = to_reil_address(address, idx_by_labels[target.name]) size = self._arch_info.address_size + 8 instr.operands[2] = ReilImmediateOperand(addr, size) return instrs
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 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 _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 __init__(self, architecture_mode): super(X86Translator, 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 = X86ArchitectureInformation(architecture_mode) self._builder = ReilBuilder() self._registers = RegisterTranslator(self._arch_info) self._reg_acc_translator = X86OperandAccessTranslator(self._arch_info) self._flags = FlagTranslator(self._arch_info) self._flag_translator = X86FlagTranslator(self._flags) # Special registers. if self._arch_mode == ARCH_X86_MODE_32: self._sp = self._registers.esp self._bp = self._registers.ebp self._ip = self._registers.eip if self._arch_mode == ARCH_X86_MODE_64: self._sp = self._registers.rsp self._bp = self._registers.rbp self._ip = self._registers.rip # Word size. self._ws = ReilImmediateOperand(self._arch_info.address_size // 8, self._arch_info.address_size)
def _translate_ldm_stm(self, tb, instruction, load=True): # LDM and STM have exactly the same logic except one loads and the # other stores It is assumed that the disassembler (for example # Capstone) writes the register list in increasing order base = tb.read(instruction.operands[0]) reg_list = tb.read(instruction.operands[1]) if instruction.ldm_stm_addr_mode is None: instruction.ldm_stm_addr_mode = ARM_LDM_STM_IA # default mode for load and store if load: load_store_fn = self._load_value # Convert stack addressing modes to non-stack addressing modes if instruction.ldm_stm_addr_mode in ldm_stack_am_to_non_stack_am: instruction.ldm_stm_addr_mode = ldm_stack_am_to_non_stack_am[ instruction.ldm_stm_addr_mode] else: # Store load_store_fn = self._store_value if instruction.ldm_stm_addr_mode in stm_stack_am_to_non_stack_am: instruction.ldm_stm_addr_mode = stm_stack_am_to_non_stack_am[ instruction.ldm_stm_addr_mode] pointer = tb.temporal(base.size) tb.add(self._builder.gen_str(base, pointer)) reg_list_size_bytes = ReilImmediateOperand( self._ws.immediate * len(reg_list), base.size) if instruction.ldm_stm_addr_mode == ARM_LDM_STM_IA: for reg in reg_list: load_store_fn(tb, pointer, reg) pointer = tb._add_to_reg(pointer, self._ws) elif instruction.ldm_stm_addr_mode == ARM_LDM_STM_IB: for reg in reg_list: pointer = tb._add_to_reg(pointer, self._ws) load_store_fn(tb, pointer, reg) elif instruction.ldm_stm_addr_mode == ARM_LDM_STM_DA: reg_list.reverse( ) # Assuming the registry list was in increasing registry number for reg in reg_list: load_store_fn(tb, pointer, reg) pointer = tb._sub_to_reg(pointer, self._ws) elif instruction.ldm_stm_addr_mode == ARM_LDM_STM_DB: reg_list.reverse() for reg in reg_list: pointer = tb._sub_to_reg(pointer, self._ws) load_store_fn(tb, pointer, reg) else: raise Exception("Unknown addressing mode.") # Write-back if instruction.operands[0].wb: if instruction.ldm_stm_addr_mode == ARM_LDM_STM_IA or instruction.ldm_stm_addr_mode == ARM_LDM_STM_IB: tmp = tb._add_to_reg(base, reg_list_size_bytes) elif instruction.ldm_stm_addr_mode == ARM_LDM_STM_DA or instruction.ldm_stm_addr_mode == ARM_LDM_STM_DB: tmp = tb._sub_to_reg(base, reg_list_size_bytes) tb.add(self._builder.gen_str(tmp, base))
def _translate_cmpxchg(self, tb, instruction): # Flags Affected # The ZF flag is set if the values in the destination operand # and register AL, AX, or EAX are equal; otherwise it is # cleared. The CF, PF, AF, SF, and OF flags are set according # to the results of the comparison operation. # Accumulator = AL, AX, EAX, or RAX depending on whether a byte, # word, doubleword, or quadword comparison is being performed # IF accumulator = DEST # THEN # ZF <- 1; # DEST <- SRC; # ELSE # ZF <- 0; # accumulator <- DEST; # FI; oprnd0 = self._reg_acc_translator.read(tb, instruction.operands[0]) oprnd1 = self._reg_acc_translator.read(tb, instruction.operands[1]) accum_x86 = __get_cmpxchg_implicit_operand(oprnd0.size) accum = self._reg_acc_translator.read(tb, accum_x86) # Define immediate registers end_addr = ReilImmediateOperand( (instruction.address + instruction.size) << 8, self._arch_info.address_size + 8) tmp0 = tb.temporal(oprnd0.size * 2) one = tb.immediate(1, 1) change_dst_lbl = ReilLabel('change_dst') change_accum_lbl = ReilLabel('change_accum') # Compare. tb.add(self._builder.gen_sub(accum, oprnd0, tmp0)) # Update flags : CF, OF, SF, ZF, AF, PF self._flag_translator.update_cf(tb, accum, tmp0) self._flag_translator.update_of(tb, accum, oprnd0, tmp0, subtraction=True) self._flag_translator.update_sf(tb, accum, tmp0) self._flag_translator.update_zf(tb, accum, tmp0) self._flag_translator.update_af(tb, accum, oprnd0, subtraction=True) self._flag_translator.update_pf(tb, tmp0) # Exchange tb.add(self._builder.gen_jcc(tmp0, change_accum_lbl)) tb.add(change_dst_lbl) self._reg_acc_translator.write(tb, instruction.operands[0], oprnd1) tb.add(self._builder.gen_jcc(one, end_addr)) tb.add(change_accum_lbl) # tb.add(self._builder.gen_str(oprnd0, accum)) self._reg_acc_translator.write(tb, accum_x86, oprnd0)
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_movw(self, tb, instruction): reil_operand = ReilRegisterOperand(instruction.operands[0].name, instruction.operands[0].size) word_mask = ReilImmediateOperand(0x0000FFFF, reil_operand.size) and_temp = tb.temporal(reil_operand.size) oprnd1 = tb.read(instruction.operands[1]) tb.write(instruction.operands[0], oprnd1) tb.add(self._builder.gen_and(reil_operand, word_mask, and_temp)) # filter bits [7:0] part of result tb.add(self._builder.gen_str(and_temp, reil_operand))
def __init__(self, architecture_mode): super(X86Translator, 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 = X86ArchitectureInformation(architecture_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 = ReilBuilder() self._flags = { "af": ReilRegisterOperand("af", 1), "cf": ReilRegisterOperand("cf", 1), "df": ReilRegisterOperand("df", 1), "of": ReilRegisterOperand("of", 1), "pf": ReilRegisterOperand("pf", 1), "sf": ReilRegisterOperand("sf", 1), "zf": ReilRegisterOperand("zf", 1), } if self._arch_mode == ARCH_X86_MODE_32: self._sp = ReilRegisterOperand("esp", 32) self._bp = ReilRegisterOperand("ebp", 32) self._ip = ReilRegisterOperand("eip", 32) self._ws = ReilImmediateOperand(4, 32) # word size elif self._arch_mode == ARCH_X86_MODE_64: self._sp = ReilRegisterOperand("rsp", 64) self._bp = ReilRegisterOperand("rbp", 64) self._ip = ReilRegisterOperand("rip", 64) self._ws = ReilImmediateOperand(8, 64) # word size
def _translate_branch(self, tb, instruction, link): oprnd_cc = ArmConditionCodeHelper.evaluate_cond_code( self._flags, tb, instruction.condition_code) 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 = and_regs(tb, 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(oprnd_cc, target))
def read(self, tb, x86_operand): if isinstance(x86_operand, X86ImmediateOperand): reil_operand = ReilImmediateOperand(x86_operand.immediate, x86_operand.size) elif isinstance(x86_operand, X86RegisterOperand): reil_operand = ReilRegisterOperand(x86_operand.name, x86_operand.size) elif isinstance(x86_operand, X86MemoryOperand): reil_operand = tb.temporal(x86_operand.size) addr = self.resolve_memory_access(tb, x86_operand) tb.add(tb._builder.gen_ldm(addr, reil_operand)) else: raise Exception('Invalid operand type') return reil_operand
def parse_operand(string, location, tokens): """Parse instruction operand. """ sizes = { "dqword": 128, "pointer": 72, "qword": 64, "pointer": 40, "dword": 32, "word": 16, "byte": 8, "bit": 1, } if "immediate" in tokens: imm_str = "".join(tokens["immediate"]) base = 16 if imm_str.startswith("0x") or imm_str.startswith("-0x") else 10 imm = int(imm_str, base) oprnd = ReilImmediateOperand(imm) if "register" in tokens: if tokens["register"] in ["e", "empty"]: oprnd = ReilEmptyOperand() oprnd.size = 0 else: name = tokens["register"] oprnd = ReilRegisterOperand(name) if "size" in tokens: oprnd.size = int(sizes[tokens["size"]]) return [oprnd]
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 test_load_memory_2(self): # testing : dst_reg <- m[src_reg + offset] binary = b"\x33\x30\x94\xe5" # 0x00 : (4) ldr 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.LoadMemory) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x33, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r3", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0]))
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 _translate_call(self, tb, instruction): # Flags Affected # All flags are affected if a task switch occurs; no flags are # affected if a task switch does not occur. oprnd0 = self._reg_acc_translator.read(tb, instruction.operands[0]) addr_oprnd = _translate_address(self, tb, oprnd0) imm1 = tb.immediate(1, 1) tmp0 = tb.temporal(self._sp.size) ret_addr = ReilImmediateOperand((instruction.address + instruction.size), self._arch_info.address_size) tb.add(self._builder.gen_sub(self._sp, self._ws, tmp0)) tb.add(self._builder.gen_str(tmp0, self._sp)) tb.add(self._builder.gen_stm(ret_addr, self._sp)) tb.add(self._builder.gen_jcc(imm1, addr_oprnd))
def _resolve_loops(self, instrs): idx_by_labels = {} # Collect labels. # curr = 0 # for index, instr in enumerate(instrs): # if isinstance(instr, Label): # idx_by_labels[instr.name] = curr # # del instrs[index] # else: # curr += 1 # TODO: Hack to avoid deleting while iterating instrs_no_labels = [] curr = 0 for i in instrs: if isinstance(i, Label): idx_by_labels[i.name] = curr else: instrs_no_labels.append(i) curr += 1 instrs[:] = instrs_no_labels # Resolve instruction addresses and JCC targets. for index, instr in enumerate(instrs): assert isinstance(instr, ReilInstruction) instr.address |= index if instr.mnemonic == ReilMnemonic.JCC: target = instr.operands[2] if isinstance(target, Label): idx = idx_by_labels[target.name] address = (instr.address & ~0xff) | idx instr.operands[2] = ReilImmediateOperand( address, self._arch_info.address_size + 8) return instrs