def _calc_displacement(self): """ Calculate the displacement offset of the operand's text. e.g: word ptr [rdi+rbx] :return int: calculated value """ size = 8 if idc.__EA64__ else 4 insn = idaapi.insn_t() idaapi.decode_insn(insn, self.ip) op = insn.ops[self.idx] offset = utils.signed(op.addr, utils.get_bits()) scale = utils.sib_scale(op) base_reg = utils.x86_base_reg(insn, op) indx_reg = utils.x86_index_reg(insn, op) base_val = self._cpu_context.registers[utils.reg2str(base_reg, size)] indx_val = self._cpu_context.registers[utils.reg2str( indx_reg, size)] if indx_reg != -1 else 0 result = base_val + indx_val * scale + offset logger.debug("calc_displacement :: Displacement {} -> {}".format( self.text, result)) # Before returning, record the frame_id and stack_offset for this address. # (This can become useful information for retrieving the original location of a variable) frame_id = idc.get_frame_id(self.ip) stack_var = ida_frame.get_stkvar(insn, op, offset) if stack_var: _, stack_offset = stack_var self._cpu_context.stack_variables[result] = (frame_id, stack_offset) return result
def base(self): """The value of the base register if operand is a displacement.""" if not self.has_phrase: return None base_reg = utils.reg2str(utils.x86_base_reg(self._insn, self._op)) value = self._cpu_context.registers[base_reg] return utils.signed(value, utils.get_bits())
def register_list(self) -> Optional[List[str]]: """ List of register names if operand is a register list. """ if not self.is_register_list: return None # Register numbers are stored in a bitmap in specval. reg_bitmap = self._op.specval return [utils.reg2str(i) for i in range(16) if reg_bitmap & (1 << i)]
def index(self): """The value of the index register if operand is a displacement.""" if not self.has_phrase: return None index_reg = utils.x86_index_reg(self._insn, self._op) if index_reg == -1: return 0 index_reg = utils.reg2str(index_reg) value = self._cpu_context.registers[index_reg] return utils.signed(value, utils.get_bits())
def base(self) -> Optional[int]: """ The value of the base register if operand is a displacement. e.g. [ebp+ecx*2+var_8] -> ebp """ if not self.has_phrase: return None base_reg = ida_intel.x86_base_reg(self._insn, self._op) value = self._cpu_context.registers[utils.reg2str(base_reg)] return utils.signed(value)
def index(self) -> Optional[int]: """ The value of the index register if operand is a displacement. e.g. [ebp+ecx*2+var_8] -> ecx """ if not self.has_phrase: return None index_reg = ida_intel.x86_index_reg(self._insn, self._op) if index_reg == -1: return 0 index_reg = utils.reg2str(index_reg) value = self._cpu_context.registers[index_reg] return utils.signed(value)
def shift_count(self) -> int: """The amount to shift (if a shifted register)""" if self.type == ida_ua.o_phrase: # For a phrase, shift is in op.value return self._op.value if self.type == ida_arm.o_shreg: # Shift can be an immediate or another register. # I believe we determine which one it is based on whether op.value is zero. count = self._op.value if not count: count = self._cpu_context.registers[utils.reg2str( ida_arm.secreg(self._op))] return count return 0 # not shifted
def offset(self) -> Optional[int]: """The offset value if the operand is a displacement/phrase.""" # [R1, R2] if self.type == ida_ua.o_phrase: second_reg = ida_arm.secreg(self._op) # pulling the R2 offset = self._cpu_context.registers[utils.reg2str(second_reg)] # We could also have a shift applied in the offset. # [R1, R2, LSL #3] offset = self._calc_shift(offset) return utils.signed(offset) # [R1, #1] elif self.type == ida_ua.o_displ: return utils.signed(self._op.addr) return None
def value(self): # Barrel shifter if self.type == ida_arm.o_shreg: value = self._cpu_context.registers[utils.reg2str(self._op.reg)] value = self._calc_shift(value) return value # Register list if self.type == ida_arm.o_reglist: return [ self._cpu_context.registers[reg] for reg in self.register_list ] value = super().value # If a memory reference, the final value may be signed. if self.is_memory_reference and self.is_signed: value = utils.signed(value) return value
def base(self, value: int): """Sets the value of the base register if operand is a displacement.""" if not self.has_phrase: return self._cpu_context.registers[utils.reg2str(self._op.reg)] = value
def base(self) -> Optional[int]: """The value of the base register if operand is a displacement.""" if not self.has_phrase: return None value = self._cpu_context.registers[utils.reg2str(self._op.reg)] return utils.signed(value)