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 _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 _translate_cmovcc(self, tb, instruction, condition_code): # Move if condition (condition_code) is met. # Flags Affected # None. oprnd0 = self._reg_acc_translator.read(tb, instruction.operands[0]) oprnd1 = self._reg_acc_translator.read(tb, instruction.operands[1]) # NOTE: CMOV pseudocode (not its description) specifies that in 32-bit # registers, even if the condition is not met, the upper 32 bits of the # destination are set to zero (DEST[63:32] <- 0). So oprnd0 (dst) is # assigned to itself, in 32 bits that doesn't change anything, in 64 it # sets the upper 32 bits to zero. Then, if the condition is met, the mov # is performed and the previous assignment has no effect (oprnd0 <- # oprnd0.) tmp = tb.temporal(oprnd0.size) tb.add(self._builder.gen_str(oprnd0, tmp)) self._reg_acc_translator.write(tb, instruction.operands[0], tmp) cond_not_met = ReilLabel('cond_not_met') neg_cond = negate_reg( tb, X86ConditionCodeHelper.evaluate_cc(self._flags, tb, condition_code)) tb.add(self._builder.gen_jcc(neg_cond, cond_not_met)) self._reg_acc_translator.write(tb, instruction.operands[0], oprnd1) tb.add(cond_not_met) tb.add(self._builder.gen_nop())
def _translate_psrldq(self, tb, instruction): # Flags Affected # None. # Operation # PSRLDQ(128-bit Legacy SSE version) # TEMP <- COUNT # IF (TEMP > 15) THEN TEMP <- 16; FI # DEST <- DEST >> (TEMP * 8) # DEST[MAX_VL-1:128] (Unmodified) # NOTE Only supports xmm registers. oprnd0 = self._reg_acc_translator.read(tb, instruction.operands[0]) oprnd1 = self._reg_acc_translator.read(tb, instruction.operands[1]) count = tb.temporal(oprnd0.size) count_tmp = tb.temporal(oprnd1.size) count_tmp_2 = tb.temporal(oprnd1.size) tmp0 = tb.temporal(oprnd1.size) cmp_result = tb.temporal(1) dst = tb.temporal(oprnd0.size) imm0 = tb.immediate(~0x7fff, oprnd1.size) # Create labels. count_ok_lbl = ReilLabel('count_ok_lbl') # Check if count <= 16 tb.add(self._builder.gen_str(oprnd1, count_tmp)) tb.add(self._builder.gen_and(count_tmp, imm0, tmp0)) tb.add(self._builder.gen_bisz(tmp0, cmp_result)) tb.add(self._builder.gen_jcc(cmp_result, count_ok_lbl)) # Set count to 16. tb.add(self._builder.gen_str(imm0, count_tmp)) # Count ok. tb.add(count_ok_lbl) # Extend count to the size of oprnd0 and multiply by 8. tb.add( self._builder.gen_mul(count_tmp, tb.immediate(8, oprnd1.size), count_tmp_2)) # Negate tb.add( self._builder.gen_sub(tb.immediate(0, oprnd1.size), count_tmp_2, count)) # Do the shift. tb.add(self._builder.gen_bsh(oprnd0, count, dst)) # Save the result. self._reg_acc_translator.write(tb, instruction.operands[0], dst)
def _update_strings_src_and_dst(self, tb, src, dst, size): # Create labels. forward_lbl = ReilLabel('forward') backward_lbl = ReilLabel('backward') continue_lbl = ReilLabel('continue') # Define immediate registers. imm_one = tb.immediate(1, 1) # Define temporary registers. df_zero = tb.temporal(1) imm_tmp = tb.immediate(size // 8, src.size) src_tmp = tb.temporal(src.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) # src tb.add(self._builder.gen_sub(src, imm_tmp, src_tmp)) tb.add(self._builder.gen_str(src_tmp, src)) # dst 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, continue_lbl)) # Update forwards. tb.add(forward_lbl) # src tb.add(self._builder.gen_add(src, imm_tmp, src_tmp)) tb.add(self._builder.gen_str(src_tmp, src)) # dst tb.add(self._builder.gen_add(dst, imm_tmp, dst_tmp)) tb.add(self._builder.gen_str(dst_tmp, dst)) # Continuation label. tb.add(continue_lbl)
def _rep_prefix_begin(self, tb, instruction): # Define counter register. counter_x86 = __get_counter_register(self._arch_info.address_size) counter = self._reg_acc_translator.read(tb, counter_x86) # Create labels. loop_start_lbl = ReilLabel('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 _translate_setcc(self, tb, instruction, condition_code): # Set if condition (condition_code) is met. # Flags Affected # None. self._reg_acc_translator.write(tb, instruction.operands[0], tb.immediate(0, 1)) cond_not_met = ReilLabel('cond_not_met') neg_cond = negate_reg( tb, X86ConditionCodeHelper.evaluate_cc(self._flags, tb, condition_code)) tb.add(self._builder.gen_jcc(neg_cond, cond_not_met)) self._reg_acc_translator.write( tb, instruction.operands[0], tb.immediate(1, instruction.operands[0].size)) tb.add(cond_not_met) tb.add(self._builder.gen_nop())
def label(self, name): return ReilLabel(name)
def _translate_shrd(self, tb, instruction): # Flags Affected # If the count is 1 or greater, the CF flag is filled with the last # bit shifted out of the destination operand and the SF, ZF, and PF # flags are set according to the value of the result. For a 1-bit # shift, the OF flag is set if a sign change occurred; otherwise, it # is cleared. For shifts greater than 1 bit, the OF flag is undefined. # If a shift occurs, the AF flag is undefined. If the count operand is # 0, the flags are not affected. If the count is greater than the # operand size, the flags are undefined. # Operation # IF (In 64-Bit Mode and REX.W = 1) # THEN COUNT <- COUNT MOD 64; # ELSE COUNT <- COUNT MOD 32; # FI # SIZE <- OperandSize; # IF COUNT = 0 # THEN # No operation; # ELSE # IF COUNT > SIZE # THEN (* Bad parameters *) # DEST is undefined; # CF, OF, SF, ZF, AF, PF are undefined; # ELSE (* Perform the shift *) # CF <- BIT[DEST, COUNT - 1]; (* Last bit shifted out on exit *) # FOR i <- 0 TO SIZE - 1 - COUNT # DO # BIT[DEST, i] <- BIT[DEST, i + COUNT]; # OD; # FOR i <- SIZE - COUNT TO SIZE - 1 # DO # BIT[DEST,i] <- BIT[SRC, i + COUNT - SIZE]; # OD; # FI; # FI; oprnd0 = self._reg_acc_translator.read(tb, instruction.operands[0]) oprnd1 = self._reg_acc_translator.read(tb, instruction.operands[1]) oprnd2 = self._reg_acc_translator.read(tb, instruction.operands[2]) if self._arch_info.architecture_mode == ARCH_X86_MODE_32: mod_const = tb.immediate(32, oprnd2.size) elif self._arch_info.architecture_mode == ARCH_X86_MODE_64: mod_const = tb.immediate(64, oprnd2.size) else: raise Exception('Invalid architecture mode.') size = tb.immediate(self._arch_info.operand_size, oprnd2.size) end_addr = ReilImmediateOperand((instruction.address + instruction.size) << 8, self._arch_info.address_size + 8) count = tb.temporal(oprnd2.size) count_zero = tb.temporal(1) count_ext = tb.temporal(oprnd2.size * 2) size_ext = tb.temporal(oprnd2.size * 2) count_check = tb.temporal(oprnd2.size * 2) count_check_sign = tb.temporal(1) dst = tb.temporal(oprnd0.size) bad_parameters_lbl = ReilLabel('bad_parameters_lbl') shift_lbl = ReilLabel('shift_lbl') tb.add(self._builder.gen_mod(oprnd2, mod_const, count)) tb.add(self._builder.gen_bisz(count, count_zero)) tb.add(self._builder.gen_jcc(count_zero, end_addr)) tb.add(self._builder.gen_str(count, count_ext)) tb.add(self._builder.gen_str(size, size_ext)) tb.add(self._builder.gen_sub(size_ext, count_ext, count_check)) # count_check = size_ext - count_ext # count_check_sign == 1 => count > size tb.add(self._builder.gen_bsh(count_check, tb.immediate(-count.size, count_check.size), count_check_sign)) tb.add(self._builder.gen_jcc(count_check_sign, bad_parameters_lbl)) tb.add(self._builder.gen_jcc(tb.immediate(1, 1), shift_lbl)) tb.add(bad_parameters_lbl) # dst <- undefined tb.add(self._builder.gen_str(oprnd0, dst)) # Set flags: CF, OF, SF, ZF, AF, PF are undefined; self._flag_translator.undefine_flag(tb, self._flags.cf) self._flag_translator.undefine_flag(tb, self._flags.of) self._flag_translator.undefine_flag(tb, self._flags.sf) self._flag_translator.undefine_flag(tb, self._flags.zf) self._flag_translator.undefine_flag(tb, self._flags.af) self._flag_translator.undefine_flag(tb, self._flags.pf) tb.add(self._builder.gen_jcc(tb.immediate(1, 1), end_addr)) tb.add(shift_lbl) # (* Perform the shift *) # CF <- BIT[DEST, COUNT - 1]; (* Last bit shifted out on exit *) # FOR i <- 0 TO SIZE - 1 - COUNT # DO # BIT[DEST, i] <- BIT[DEST, i + COUNT]; # OD; # FOR i <- SIZE - COUNT TO SIZE - 1 # DO # BIT[DEST,i] <- BIT[SRC, i + COUNT - SIZE]; # OD; zero = tb.immediate(0, count.size) one = tb.immediate(1, count.size) bit_offset = tb.temporal(oprnd0.size) bit_offset_tmp = tb.temporal(oprnd0.size) tmp0 = tb.temporal(1) lower = tb.temporal(oprnd0.size * 2) upper = tb.temporal(oprnd0.size * 2) dst_tmp0 = tb.temporal(oprnd0.size * 2) dst_tmp1 = tb.temporal(oprnd0.size * 2) dst_count = tb.temporal(oprnd0.size * 2) dst_count0 = tb.temporal(oprnd0.size * 2) # Compute bit offset. tb.add(self._builder.gen_sub(count, one, bit_offset_tmp)) tb.add(self._builder.gen_sub(zero, bit_offset_tmp, bit_offset)) # negate # Extract bit. tb.add(self._builder.gen_bsh(oprnd0, bit_offset, tmp0)) # Set CF. tb.add(self._builder.gen_and(tmp0, tb.immediate(1, 1), self._flags.cf)) tb.add(self._builder.gen_str(oprnd0, lower)) tb.add(self._builder.gen_bsh(oprnd1, tb.immediate(oprnd1.size, oprnd1.size), upper)) tb.add(self._builder.gen_or(upper, lower, dst_tmp0)) tb.add(self._builder.gen_str(count, dst_count0)) tb.add(self._builder.gen_sub(tb.immediate(0, dst_count0.size), dst_count0, dst_count)) tb.add(self._builder.gen_bsh(dst_tmp0, dst_count, dst_tmp1)) tb.add(self._builder.gen_str(dst_tmp1, dst)) # Flags : SF, ZF, PF self._flag_translator.update_sf(tb, oprnd0, dst) self._flag_translator.update_zf(tb, oprnd0, dst) self._flag_translator.update_pf(tb, dst) self._reg_acc_translator.write(tb, instruction.operands[0], dst)
def _translate_bsf(self, tb, instruction): # Flags Affected # The ZF flag is set to 1 if all the source operand is 0; # otherwise, the ZF flag is cleared. The CF, OF, SF, AF, and PF, # flags are undefined. # Operation # IF SRC = 0 # THEN # ZF <- 1; # DEST is undefined; # ELSE # ZF <- 0; # temp <- 0; # WHILE Bit(SRC, temp) = 0 # DO # temp <- temp + 1; # OD; # DEST <- temp; # FI; oprnd0 = self._reg_acc_translator.read(tb, instruction.operands[0]) oprnd1 = self._reg_acc_translator.read(tb, instruction.operands[1]) zf = self._flags.zf tmp = tb.temporal(oprnd1.size) tmp1 = tb.temporal(oprnd1.size) bit_curr = tb.temporal(1) dst = tb.temporal(oprnd0.size) src_is_zero = tb.temporal(1) bit_zero = tb.temporal(1) src_is_zero_lbl = ReilLabel('src_is_zero_lbl') loop_lbl = ReilLabel('loop_lbl') end_lbl = ReilLabel('end_lbl') tb.add(self._builder.gen_bisz(oprnd1, src_is_zero)) tb.add(self._builder.gen_jcc(src_is_zero, src_is_zero_lbl)) # if src != 0 ... tb.add(self._builder.gen_str(tb.immediate(0, 1), zf)) tb.add(self._builder.gen_str(tb.immediate(1, tmp.size), tmp)) tb.add(self._builder.gen_str(tb.immediate(-1, tmp1.size), tmp1)) # while bit(src, tmp) == 0 ... tb.add(loop_lbl) tb.add(self._builder.gen_sub(tmp, tb.immediate(1, tmp.size), tmp)) tb.add(self._builder.gen_add(tmp1, tb.immediate(1, tmp.size), tmp1)) tb.add(self._builder.gen_bsh(oprnd1, tmp, bit_curr)) tb.add(self._builder.gen_bisz(bit_curr, bit_zero)) tb.add(self._builder.gen_jcc(bit_zero, loop_lbl)) # Save result. tb.add(self._builder.gen_str(tmp1, dst)) # jump to the end. tb.add(self._builder.gen_jcc(tb.immediate(1, 1), end_lbl)) # If src == 0 ... tb.add(src_is_zero_lbl) tb.add(self._builder.gen_str(tb.immediate(1, 1), zf)) # Undefine dst (set the same value). tb.add(self._builder.gen_str(oprnd0, dst)) tb.add(end_lbl) # Set flags. # Flags : CF, OF, SF, AF, and PF self._flag_translator.undefine_flag(tb, self._flags.cf) self._flag_translator.undefine_flag(tb, self._flags.of) self._flag_translator.undefine_flag(tb, self._flags.sf) self._flag_translator.undefine_flag(tb, self._flags.af) self._flag_translator.undefine_flag(tb, self._flags.pf) self._reg_acc_translator.write(tb, instruction.operands[0], dst)