def _decode_nomodrm(self, buf, info): ''' Returns a new Immediate, RelativeNear, RelativeFar, Offset, or SegmentOffset operand object. ''' addr_meth = info['addr_meth'] size = info['size'] addr_size = self.state.addr_size if addr_meth == 'A': # segment:offset (far calls). Either 16:16 or 16:32. seg = unpack_immediate(buf, 2, False) off = unpack_immediate(buf, addr_size, False) info['pointer'] = True op = Operand.SegmentOffset(seg, off, info) # mark this operand as variant self._mark_bytes(1, 2 + addr_size) elif addr_meth == 'I': sign = info['signed'] val = unpack_immediate(buf, size, sign) if (val.signed() > 4096 or val.signed < -4096): # use sensible defaults for signedness sign = False else: sign = True op = Operand.Immediate(val, info, sign) # if Optype is v, assume this is variant if info['op_type'] == 'v': self._mark_bytes(1, size) else: self._mark_bytes(0, size) elif addr_meth == 'J': val = unpack_immediate(buf, size, True) if size == addr_size: op = Operand.RelativeFar(val, self.state.insn, info) else: op = Operand.RelativeNear(val, self.state.insn, info) # mark this operand as invariant self._mark_bytes(0, size) elif addr_meth == 'O': val = unpack_immediate(buf, addr_size, False) info['segment'] = self._segment() info['pointer'] = True op = Operand.Offset(val, info) # mark this operand as variant self._mark_bytes(1, addr_size) return op
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 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(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