def _decode_hardcode(self, value, info): ''' Returns a new Immediate, Register, or EffectiveAddress operand. ''' string_regs = { 'X':(IA32.REG_ESI_INDEX, IA32.REG_SI_INDEX), 'Y':(IA32.REG_EDI_INDEX, IA32.REG_DI_INDEX) } string_segs = { 'X':'ds', 'Y':'es'} addr_meth = info['addr_meth'] size = info['size'] info['hardcoded'] = True if addr_meth == 'II': # 'Immediate' value is implicit in opcode definition imm = ISA.ImmediateValue(1,value,value, info['signed']) op = Operand.Immediate(imm, info) elif addr_meth == 'F': reg = IA32.register_factory(IA32.REG_FLAGS_INDEX) op = Operand.Register(reg, info) elif addr_meth in string_regs: # String destination is hard-coded in opcode definition # Note that the intel instruction syntax specifies # this as a segment:register address pair -- either # DS:ESI or ES:EDI -- when really what it represents # is an effective address, e.g. [DS:ESI]. if self.state.addr_size == 2: reg_id = string_regs[addr_meth][1] else: reg_id = string_regs[addr_meth][0] info['string'] = True info['segment'] = string_segs[addr_meth] # NOTE: this operand applies to opcodes like MOVS. # Even though this is an explicit operand in the # opcode definition, it is not displayed during # disassembly ... so we make it implicit. info['implicit'] = True # base reg: reg = IA32.register_factory(reg_id) op = Operand.EffectiveAddress(None, reg, None, 1, info) else: # Register set is hard-coded in opcode definition reg_set = self._register_set(addr_meth, size) reg = IA32.register_factory(reg_set + value) op = Operand.Register(reg, info) return op
def decode(self, buf): if self.base == self.EBP_BASE and not self.disp_exists: # if ModR/M did not create a displacement # (! mod) get 4-byte unsigned disp self.disp = unpack_immediate(buf, 4, False) self.disp_size = 4 else: self.base_reg = \ IA32.register_factory(self.base + 1) self.scale_val = 1 << self.scale if self.index != self.NO_INDEX: self.index_reg = \ IA32.register_factory(self.index + 1)
def _decode_modrm_reg(self, info): ''' Returns a new Register operand object ''' addr_meth = info['addr_meth'] size = info['size'] reg_set = self._register_set(addr_meth, size) reg = IA32.register_factory(reg_set + self.state.modrm.reg) return Operand.Register(reg, info)
def _decode_16(self, buf): # format: base, index, seg rm_regs = ( ( IA32.REG_BX_INDEX, IA32.REG_SI_INDEX, None ), ( IA32.REG_BX_INDEX, IA32.REG_DI_INDEX, None ), ( IA32.REG_BP_INDEX, IA32.REG_SI_INDEX, "ss" ), ( IA32.REG_BP_INDEX, IA32.REG_DI_INDEX, "ss" ), ( IA32.REG_SI_INDEX, None, None ), ( IA32.REG_DI_INDEX, None, None ), ( IA32.REG_BX_INDEX, None, None ), ( IA32.REG_BP_INDEX, None, "ss" ) ) self.base = IA32.register_factory(rm_regs[self.rm][0]) idx = rm_regs[self.rm][1] if idx: self.index = IA32.register_factory(idx) if self.mod == ModRM.MOD.DISP8: # get 1-byte signed displacement self.disp = unpack_immediate(buf, 1, True) self.disp_size = 1 elif self.mod == ModRM.MOD.DISP16: # get 2-byte unsigned displacement self.disp = unpack_immediate(buf, 2, False) self.disp_size = 2 elif self.mod == ModRM.MOD.NO_DISP and \ self.rm == ModRM.RM16.BP: # special case: there is no [BP] case, instead it # decodes to disp16 with no register self.base = None # get 2-byte unsigned displacement self.disp = unpack_immediate(buf, 2, False) self.disp_size = 2 seg = rm_regs[self.rm][2] if seg: self.segment = seg
def _segment(self, seg=None): seg_regs = { 'es': IA32.REG_ES_INDEX, 'cs': IA32.REG_CS_INDEX, 'ss': IA32.REG_SS_INDEX, 'ds': IA32.REG_DS_INDEX, 'fs': IA32.REG_FS_INDEX, 'gs': IA32.REG_GS_INDEX } if not seg: seg = self.state.prefix_groups[2] if not seg or "taken" in seg: return None reg = seg_regs[seg] return IA32.register_factory(reg)
def _implicit_operands(self, index, insn ): # append to operands # TODO: Generate datatypes for implicit operands info = { 'segment':None, 'pointer':False, 'string':False, 'hardcoded':True, 'implicit':True, 'name':'', 'addr_meth':None, 'op_type':None, 'datatype':None, 'size':None } op_list = IA32.implicit_operands[index] for o in op_list: inf = info.copy() inf['access'] = o['access'] reg = IA32.register_factory(o['register']) op = Operand.Register(reg, inf) insn._operands.append(op) return
def _decode_base(self, buf): if self.rm == ModRM.RM.SIB: # RM = 100 self.sib = True sib = ModRM.SIB(buf.read(), self.mod) sib.decode(buf) self.base = sib.base_reg self.index = sib.index_reg self.scale = sib.scale_val self.disp = sib.disp self.disp_size = sib.disp_size if sib.segment: self.segment = sib.segment else: # RM encodes a general register self.base = IA32.register_factory(IA32.REG_DWORD_INDEX + self.rm )
def decode(self, buf, reg_set, addr_size): ''' Decode ModR/M byte, using mod and r/m fields. Reg/opcode extension field is handled elsewhere. Does not consume the ModR/M byte from buf, but DOES consume SIB and displacement bytes. ''' if self.mod == ModRM.MOD.REG_ONLY: # MOD = 11 self.register = IA32.register_factory(reg_set + self.rm) return if addr_size == 2: return self._decode_16(buf) if self.mod == ModRM.MOD.NO_DISP: # MOD = 00 if self.rm == ModRM.RM.NO_REG: # RM = 101 # read a unsigned dword from buffer self.disp = unpack_immediate(buf, 4, False) self.disp_size = 4 else: self._decode_base(buf) else: self._decode_base(buf) # NOTE: since mod > 0 in these cases, SIB.decode() # never creates a displacement. if self.mod == ModRM.MOD.DISP8: # get signed byted into displacement self.disp = unpack_immediate(buf, 1, True) self.disp_size = 1 else: # get unsigned dword into displacement self.disp = unpack_immediate(buf, 4, False) self.disp_size = 4