Source code for envi.archs.i386.emu

"""
Home for the i386 emulation code.
"""
import struct

import envi
import envi.bits as e_bits
import envi.memory as e_mem

from envi.archs.i386.regs import *
from envi.archs.i386.disasm import *
from envi.archs.i386 import i386Module

[docs]def shiftMask(val, size): if size == 1: return (val & 0x1f) % 9 elif size == 2: return (val & 0x1f) % 17 elif size == 4: return val & 0x1f elif size == 8: return val & 0x3f else: raise Exception("shiftMask is broke in envi/intel.py") # The indexes for the list of segments in the emulator
SEG_CS = 0 SEG_DS = 1 SEG_ES = 2 SEG_FS = 3 SEG_GS = 4 SEG_SS = 5 # The general purpose register indexes # (for use in _emu_setGpReg / _emu_getGpReg) # NOTE: These *must* stay in sync with i386regs first row. GPR_A = 0 GPR_C = 1 GPR_D = 2 GPR_B = 3 GPR_SP = 4 GPR_BP = 5 GPR_SI = 6 GPR_DI = 7
[docs]class IntelCall(envi.CallingConvention):
[docs] def getCallArgs(self, emu, count): """ Standard intel stack arg parsing """ esp = emu.getRegister(REG_ESP) esp += 4 # For the saved eip return struct.unpack("<%dI" % count, emu.readMemory(esp, 4*count))
[docs] def setReturnValue(self, emu, value, argc): """ A return routine which cleans up it's stack args. """ esp = emu.getRegister(REG_ESP) eip = emu.readMemoryFormat(esp, '<I')[0] esp += 4 # For the saved eip esp += (4 * argc) # Cleanup saved args emu.setRegister(REG_ESP, esp) emu.setRegister(REG_EAX, value) emu.setProgramCounter(eip)
[docs]class StdCall(IntelCall): pass
[docs]class Cdecl(IntelCall):
[docs] def setReturnValue(self, emu, value, argc): """ A base non-cleanup stackarg return """ esp = emu.getRegister(REG_ESP) eip = struct.unpack("<I", emu.readMemory(esp, 4))[0] esp += 4 # For the saved eip emu.setRegister(REG_EAX, value) emu.setStackCounter(esp) emu.setProgramCounter(eip)
[docs]class ThisCall(StdCall):
[docs] def getCallArgs(self, emu, count): ret = [emu.getRegister(REG_ECX),] count -= 1 esp = emu.getRegister(REG_ESP) esp += 4 # For the saved eip if count: ret.extend(struct.unpack("<%dI" % count, emu.readMemory(esp, 4*count))) return ret
[docs] def setReturnValue(self, emu, value, argc): argc -= 1 # One for the ECX... return StdCall.setReturnValue(self, emu, value, argc)
[docs]class FastCall(envi.CallingConvention): def __init__(self, reglist): self.reglist = reglist
[docs] def getCallArgs(self, emu, count): ret = [] for i in xrange(count): if len(self.reglist) <= i: break regid = self.reglist[i] ret.append(emu.getRegister(regid)) count -= 1 if count > 0: esp = emu.getRegister(REG_ESP) esp += 4 # For the saved eip ret.extend(struct.unpack("<%dI" % count, emu.readMemory(esp, 4*count))) return ret
[docs] def setReturnValue(self, emu, value, argc): esp = emu.getRegister(REG_ESP) eip = emu.readMemoryFormat(esp, '<I')[0] esp += 4 if argc > len(self.reglist): cbytes = (argc - len(self.reglist)) * 4 esp += cbytes emu.setRegister(REG_EAX, value) emu.setStackCounter(esp) emu.setProgramCounter(eip)
[docs]class MsFastCall(FastCall): def __init__(self): FastCall.__init__(self, (REG_ECX, REG_EDX))
[docs]class BFastCall(FastCall): def __init__(self): FastCall.__init__(self, (REG_EAX, REG_EDX, REG_ECX))
stdcall = StdCall() thiscall = ThisCall() cdecl = Cdecl() msfastcall = MsFastCall() bfastcall = BFastCall()
[docs]class IntelEmulator(i386RegisterContext, envi.Emulator): def __init__(self): # Set ourself up as an arch module *and* register context #i386Module.__init__(self) archmod = i386Module() envi.Emulator.__init__(self, archmod=archmod) for i in xrange(6): self.setSegmentInfo(i, 0, 0xffffffff) i386RegisterContext.__init__(self) # Add our known calling conventions self.addCallingConvention('stdcall', stdcall) self.addCallingConvention('thiscall', thiscall) self.addCallingConvention('cdecl', cdecl) self.addCallingConvention('msfastcall', msfastcall) self.addCallingConvention('bfastcall', bfastcall)
[docs] def getSegmentIndex(self, op): # FIXME this needs to account for push/pop/etc if op.prefixes == 0: return SEG_DS if op.prefixes & PREFIX_ES: return SEG_ES elif op.prefixes & PREFIX_CS: return SEG_CS elif op.prefixes & PREFIX_SS: return SEG_SS elif op.prefixes & PREFIX_DS: return SEG_DS elif op.prefixes & PREFIX_FS: return SEG_FS elif op.prefixes & PREFIX_GS: return SEG_GS return SEG_DS
[docs] def setFlag(self, which, state): flags = self.getRegister(REG_EFLAGS) if state: flags |= which else: flags &= ~which self.setRegister(REG_EFLAGS, flags)
[docs] def getFlag(self, which): flags = self.getRegister(REG_EFLAGS) return bool(flags & which)
[docs] def readMemValue(self, addr, size): bytes = self.readMemory(addr, size) if bytes == None: return None #FIXME change this (and all uses of it) to passing in format... if len(bytes) != size: raise Exception("Read Gave Wrong Length At 0x%.8x (va: 0x%.8x wanted %d got %d)" % (self.getProgramCounter(),addr, size, len(bytes))) if size == 1: return struct.unpack("B", bytes)[0] elif size == 2: return struct.unpack("<H", bytes)[0] elif size == 4: return struct.unpack("<I", bytes)[0] elif size == 8: return struct.unpack("<Q", bytes)[0]
[docs] def writeMemValue(self, addr, value, size): #FIXME change this (and all uses of it) to passing in format... if size == 1: bytes = struct.pack("B",value & 0xff) elif size == 2: bytes = struct.pack("<H",value & 0xffff) elif size == 4: bytes = struct.pack("<I", value & 0xffffffff) elif size == 8: bytes = struct.pack("<Q", value & 0xffffffffffffffff) self.writeMemory(addr, bytes)
[docs] def readMemSignedValue(self, addr, size): bytes = self.readMemory(addr, size) if bytes == None: return None if size == 1: return struct.unpack("b", bytes)[0] elif size == 2: return struct.unpack("<h", bytes)[0] elif size == 4: return struct.unpack("<l", bytes)[0]
[docs] def executeOpcode(self, op): # NOTE: If an opcode method returns # other than None, that is the new eip meth = self.op_methods.get(op.mnem, None) if meth == None: raise envi.UnsupportedInstruction(self, op) if op.prefixes & PREFIX_REP: x = self.doRepPrefix(meth, op) else: x = meth(op) if x == None: pc = self.getProgramCounter() x = pc+op.size self.setProgramCounter(x) ###### Conditional Callbacks ##### # NOTE: for ease of validation, these are in the same order as the Jcc # page in the intel manual. However, duplicate conditions (be/na) are # reduced to their earliest (in the manual) form.
[docs] def cond_a(self): return self.getFlag(EFLAGS_CF) == 0 and self.getFlag(EFLAGS_ZF) == 0
[docs] def cond_ae(self): return self.getFlag(EFLAGS_CF) == 0
[docs] def cond_b(self): return self.getFlag(EFLAGS_CF) == 1
[docs] def cond_be(self): return self.getFlag(EFLAGS_CF) == 1 or self.getFlag(EFLAGS_ZF) == 1
[docs] def cond_c(self): return self.getFlag(EFLAGS_CF) == 1
[docs] def cond_ecxz(self): return self.getRegister(REG_ECX) == 0
[docs] def cond_e(self): return self.getFlag(EFLAGS_ZF) == 1
[docs] def cond_g(self): return self.getFlag(EFLAGS_ZF) == 0 and (self.getFlag(EFLAGS_SF) == self.getFlag(EFLAGS_OF))
[docs] def cond_ge(self): return self.getFlag(EFLAGS_SF) == self.getFlag(EFLAGS_OF)
[docs] def cond_l(self): return self.getFlag(EFLAGS_SF) != self.getFlag(EFLAGS_OF)
[docs] def cond_le(self): return (self.getFlag(EFLAGS_SF) != self.getFlag(EFLAGS_OF) or (self.getFlag(EFLAGS_ZF) == 1)) # Some duplicates
cond_na = cond_be cond_nae = cond_b cond_nb = cond_ae cond_nbe = cond_a cond_nc = cond_ae
[docs] def cond_ne(self): return self.getFlag(EFLAGS_ZF) == 0 # A few more
cond_ng = cond_le cond_nge = cond_l cond_nl = cond_ge cond_nle = cond_g
[docs] def cond_no(self): return self.getFlag(EFLAGS_OF) == 0
[docs] def cond_np(self): return self.getFlag(EFLAGS_PF) == 0
[docs] def cond_ns(self): return self.getFlag(EFLAGS_SF) == 0
cond_nz = cond_ne
[docs] def cond_o(self): return self.getFlag(EFLAGS_OF) == 1
[docs] def cond_p(self): return self.getFlag(EFLAGS_PF) == 1
cond_pe = cond_p cond_po = cond_np
[docs] def cond_s(self): return self.getFlag(EFLAGS_SF) == 1
cond_z = cond_e # FROM OTHER INSTRUCTIONS cond_nc = cond_ae cond_nl = cond_ge ###### End Conditional Callbacks #####
[docs] def doPush(self, val): esp = self.getRegister(REG_ESP) esp -= 4 self.writeMemValue(esp, val, 4) self.setRegister(REG_ESP, esp)
[docs] def doPop(self): esp = self.getRegister(REG_ESP) val = self.readMemValue(esp, 4) self.setRegister(REG_ESP, esp+4) return val
[docs] def integerSubtraction(self, op): """ Do the core of integer subtraction but only *return* the resulting value rather than assigning it. (allows cmp and sub to use the same code) """ # Src op gets sign extended to dst dst = self.getOperValue(op, 0) src = self.getOperValue(op, 1) # So we can either do a BUNCH of crazyness with xor and shifting to # get the necissary flags here, *or* we can just do both a signed and # unsigned sub and use the results. dsize = op.opers[0].tsize ssize = op.opers[1].tsize # Sign extend immediates where the sizes don't match if dsize != ssize: src = e_bits.sign_extend(src, ssize, dsize) ssize = dsize return self.intSubBase(src, dst, ssize, dsize)
[docs] def intSubBase(self, src, dst, ssize, dsize): usrc = e_bits.unsigned(src, ssize) udst = e_bits.unsigned(dst, dsize) ssrc = e_bits.signed(src, ssize) sdst = e_bits.signed(dst, dsize) ures = udst - usrc sres = sdst - ssrc #print "dsize/ssize: %d %d" % (dsize, ssize) #print "unsigned: %d %d %d" % (usrc, udst, ures) #print "signed: %d %d %d" % (ssrc, sdst, sres) self.setFlag(EFLAGS_OF, e_bits.is_signed_overflow(sres, dsize)) self.setFlag(EFLAGS_AF, e_bits.is_aux_carry(usrc, udst)) self.setFlag(EFLAGS_CF, e_bits.is_unsigned_carry(ures, dsize)) self.setFlag(EFLAGS_SF, e_bits.is_signed(ures, dsize)) self.setFlag(EFLAGS_ZF, not sres) self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(ures)) return ures
[docs] def logicalAnd(self, op): dst = self.getOperValue(op, 0) src = self.getOperValue(op, 1) dsize = op.opers[0].tsize ssize = op.opers[1].tsize # sign-extend an immediate if needed if dsize != ssize: src = e_bits.sign_extend(src, ssize, dsize) ssize = dsize # Make sure everybody's on the same bit page. dst = e_bits.unsigned(dst, dsize) src = e_bits.unsigned(src, ssize) res = src & dst self.setFlag(EFLAGS_AF, 0) # AF is undefined, but it seems like it is zeroed self.setFlag(EFLAGS_OF, 0) self.setFlag(EFLAGS_CF, 0) self.setFlag(EFLAGS_SF, e_bits.is_signed(res, dsize)) self.setFlag(EFLAGS_ZF, not res) self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(res)) return res
[docs] def doRepPrefix(self, meth, op): #FIXME check for opcode family valid to rep ret = None ecx = self.getRegister(REG_ECX) while ecx != 0: ret = meth(op) ecx -= 1 self.setRegister(REG_ECX, 0) return ret
[docs] def doRepzPrefix(self, meth, op): pass # Beginning of Instruction methods
[docs] def i_adc(self, op): dst = self.getOperValue(op, 0) src = self.getOperValue(op, 1) cf = 0 if self.getFlag(EFLAGS_CF): cf = 1 dstsize = op.opers[0].tsize srcsize = op.opers[1].tsize if (isinstance(op.opers[1], i386ImmOper) and srcsize < dstsize): src = e_bits.sign_extend(src, srcsize, dstsize) srcsize = dstsize #FIXME perhaps unify the add/adc flags/arith code res = dst + src + cf tsize = op.opers[0].tsize self.setFlag(EFLAGS_CF, e_bits.is_unsigned_carry(res, tsize)) self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(res)) self.setFlag(EFLAGS_AF, e_bits.is_aux_carry(src, dst)) self.setFlag(EFLAGS_ZF, not res) self.setFlag(EFLAGS_SF, e_bits.is_signed(res, tsize)) self.setFlag(EFLAGS_OF, e_bits.is_signed_overflow(res, tsize)) self.setOperValue(op, 0, res)
[docs] def i_add(self, op): dst = self.getOperValue(op, 0) src = self.getOperValue(op, 1) dsize = op.opers[0].tsize ssize = op.opers[1].tsize if dsize > ssize: src = e_bits.sign_extend(src, ssize, dsize) ssize = dsize udst = e_bits.unsigned(dst, dsize) usrc = e_bits.unsigned(src, ssize) sdst = e_bits.signed(dst, dsize) ssrc = e_bits.signed(src, ssize) ures = udst + usrc sres = sdst + ssrc self.setFlag(EFLAGS_CF, e_bits.is_unsigned_carry(ures, dsize)) self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(ures)) self.setFlag(EFLAGS_AF, e_bits.is_aux_carry(src, dst)) self.setFlag(EFLAGS_ZF, not ures) self.setFlag(EFLAGS_SF, e_bits.is_signed(ures, dsize)) self.setFlag(EFLAGS_OF, e_bits.is_signed_overflow(sres, dsize)) self.setOperValue(op, 0, ures)
[docs] def i_and(self, op): #FIXME 24 and 25 opcodes should *not* get sign-extended. res = self.logicalAnd(op) self.setOperValue(op, 0, res)
[docs] def i_arpl(self, op): v1 = self.getOperValue(op, 0) v2 = self.getOperValue(op, 1) # Mask off the rpl r1 = v1 & 3 r2 = v2 & 3 if r1 < r2: # If dest rpl < src rpl self.setFlag(EFLAGS_ZF, True) # Bump 2 bits off the bottom and add r2 self.setOperValue(op, 0, ((v1 >> 2) << 2) | r2) else: self.setFlag(EFLAGS_ZF, False)
[docs] def i_bswap(self, op): val = self.getOperValue(op, 0) tsize = op.opers[0].tsize self.setOperValue(op, 0, e_bits.byteswap(val, tsize))
[docs] def i_bsr(self, op): val = self.getOperValue(op, 0) if val == 0: # If the src is 0, set ZF and get out self.setFlag(EFLAGS_ZF, True) return self.setFlag(EFLAGS_ZF, False) tsize = op.opers[0].tsize rmax = (tsize*8) - 1 while rmax >= 0: if val & (1<<rmax): self.setOperValue(op, 1, rmax) return rmax -= 1
[docs] def doBitTest(self, op): val = self.getOperValue(op, 0) shift = self.getOperValue(op, 1) mask = 1 << shift self.setFlag(EFLAGS_CF, val & mask) # Return the source and mask for btc/btr return val,mask
[docs] def i_bt(self, op): self.doBitTest(op)
[docs] def i_btc(self, op): # bit test and toggle bit in source val, mask = self.doBitTest(op) self.setOperValue(op, 0, val ^ mask)
[docs] def i_btr(self, op): # bit test (and clear in the source) val, mask = self.doBitTest(op) mask = e_bits.unsigned(~val, op.opers[0].tsize) self.setOperValue(op, 0, val & mask)
[docs] def i_bts(self, op): # bit test (and set in the source) val, mask = self.doBitTest(op) self.setOperValue(op, 0, val | mask)
[docs] def i_call(self, op): eip = self.getProgramCounter() saved = eip + op.size self.doPush(saved) return self.getOperValue(op, 0)
[docs] def i_clc(self, op): self.setFlag(EFLAGS_CF, False)
[docs] def i_cld(self, op): self.setFlag(EFLAGS_DF, False)
[docs] def i_cli(self, op): self.setFlag(EFLAGS_IF, False) # We include all the possible CMOVcc names just in case somebody # gets hinkey with the disassembler.
[docs] def i_cmova(self, op): if self.cond_a(): return self.i_mov(op)
[docs] def i_cmovae(self, op): if self.cond_ae(): return self.i_mov(op)
[docs] def i_cmovb(self, op): if self.cond_b(): return self.i_mov(op)
[docs] def i_cmovbe(self, op): if self.cond_be(): return self.i_mov(op)
[docs] def i_cmovc(self, op): if self.cond_c(): return self.i_mov(op)
[docs] def i_cmovecxz(self, op): if self.cond_ecxz(): return self.i_mov(op)
[docs] def i_cmove(self, op): if self.cond_e(): return self.i_mov(op)
[docs] def i_cmovg(self, op): if self.cond_g(): return self.i_mov(op)
[docs] def i_cmovge(self, op): if self.cond_ge(): return self.i_mov(op)
[docs] def i_cmovl(self, op): if self.cond_l(): return self.i_mov(op)
[docs] def i_cmovle(self, op): if self.cond_le(): return self.i_mov(op)
i_cmovna = i_cmovbe i_cmovnae = i_cmovb i_cmovnb = i_cmovae i_cmovnbe = i_cmova i_cmovnc = i_cmovae
[docs] def i_cmovne(self, op): if self.cond_ne(): return self.i_mov(op)
i_cmovng = i_cmovle i_cmovnge = i_cmovl i_cmovnl = i_cmovge i_cmovnle = i_cmovg
[docs] def i_cmovno(self, op): if self.cond_no(): return self.i_mov(op)
[docs] def i_cmovnp(self, op): if self.cond_np(): return self.i_mov(op)
[docs] def i_cmovns(self, op): if self.cond_ns(): return self.i_mov(op)
i_cmovnz = i_cmovne
[docs] def i_cmovo(self, op): if self.cond_o(): return self.i_mov(op)
[docs] def i_cmovp(self, op): if self.cond_p(): return self.i_mov(op)
i_cmovpe = i_cmovp i_cmovpo = i_cmovnp
[docs] def i_cmovs(self, op): if self.cond_s(): return self.i_mov(op)
i_cmovz = i_cmove
[docs] def i_cmp(self, op): self.integerSubtraction(op)
[docs] def doCmps(self, width): esi = self.getRegister(REG_ESI) edi = self.getRegister(REG_EDI) # FIXME che sval = self.readMemValue(esi, width) dval = self.readMemValue(edi, width) self.intSubBase(sval, dval, width, width) if self.getFlag(EFLAGS_ZF): if self.getFlag(EFLAGS_DF): # decrement esi -= width edi -= width else: esi += width edi += width self.setRegister(REG_ESI, esi) self.setRegister(REG_EDI, edi)
[docs] def i_cmpsb(self, op): self.doCmps(1)
[docs] def i_cmpsd(self, op): """ Compare the dword pointed at by ds:esi to ds:edi. (if equal, update esi/edi by one acording to DF) """ width = 4 if op.prefixes & PREFIX_OP_SIZE: width = 2 self.doCmps(width)
[docs] def i_cmpxchg(self, op): tsize = op.opers[0].tsize if tsize == 4: areg = REG_EAX elif tsize == 1: areg = REG_AL else: areg = REG_AX aval = self.getRegister(areg) tval = self.getOperValue(op, 0) vval = self.getOperValue(op, 1) #FIXME eflags... is this supposed to be a real cmp? if aval == tval: self.setFlag(EFLAGS_ZF, True) self.setOperValue(op, 0, vval) else: self.setFlag(EFLAGS_ZF, False) self.setRegister(areg, tval)
[docs] def twoRegCompound(self, topreg, botreg, size): """ Build a compound value where the value of the top reg is shifted and or'd with the value of the bot reg ( assuming they are size bytes in length). The return is size * 2 wide (and unsigned). """ top = e_bits.unsigned(self.getRegister(topreg), size) bot = e_bits.unsigned(self.getRegister(botreg), size) return ((top << (size *8)) | bot)
[docs] def regsFromCompound(self, val, size): top = e_bits.unsigned(val >> (size * 8), size) bot = e_bits.unsigned(val, size) return (top, bot)
[docs] def i_cmpxch8b(self, op): size = 4 dsize = 8 if op.prefixes & PREFIX_OP_SIZE: size = 2 dsize = 4 bignum = self.twoRegCompound(REG_EDX, REG_EAX, size) testnum = self.getOperValue(op, 0) if bignum == testnum: self.setFlag(EFLAGS_ZF, 1) resval = self.twoRegCompound(REG_ECX, REG_EBX, size) self.setOperValue(op, 0, resval) else: self.setFlag(EFLAGS_ZF, 0) edx,eax = self.regsFromCompound(testnum, dsize) self.setRegister(REG_EDX, edx) self.setRegister(REG_EAX, eax)
[docs] def i_cdq(self, op): return self.i_cwd(op)
[docs] def i_cpuid(self, op): eax = self.getRegister(REG_EAX) print "FIXME: cpuid() returns NONSENSE (eax:0x%.8x)" % eax self.setRegister(REG_EAX, 0) self.setRegister(REG_EBX, 0) self.setRegister(REG_ECX, 0) self.setRegister(REG_EDX, 0)
[docs] def i_cwd(self, op): #FIXME handle 16 bit variant eax = self.getRegister(REG_EAX) if e_bits.is_signed(eax, 4): self.setRegister(REG_EDX, 0xffffffff) else: self.setRegister(REG_EDX, 0)
[docs] def i_dec(self, op): val = self.getOperValue(op, 0) if val == None: self.undefFlags() return val -= 1 self.setOperValue(op, 0, val) #FIXME change over to integer subtraction self.setFlag(EFLAGS_OF, 0) #FIXME OF self.setFlag(EFLAGS_SF, e_bits.is_signed(val, op.opers[0].tsize)) self.setFlag(EFLAGS_ZF, not val) self.setFlag(EFLAGS_AF, 0) #FIXME AF... self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(val))
[docs] def i_div(self, op): #FIXME this is probably broke oper = op.opers[0] val = self.getOperValue(op, 1) if val == 0: raise envi.DivideByZero(self) if oper.tsize == 1: ax = self.getRegister(REG_AX) quot = ax / val rem = ax % val if quot > 255: #FIXME stuff print "FIXME: division exception" self.setRegister(REG_EAX, (quot << 8) + rem) elif oper.tsize == 4: #FIXME 16 bit over-ride eax = self.getRegister(REG_EAX) edx = self.getRegister(REG_EDX) tot = (edx << 32) + eax quot = tot / val rem = tot % val if quot > 0xffffffff: print "FIXME: division exception" self.setRegister(REG_EAX, quot) self.setRegister(REG_EDX, rem) else: raise envi.UnsupportedInstruction(self, op)
[docs] def i_enter(self, op): locsize = self.getOperValue(op, 0) depth = self.getOperValue(op, 1) if depth != 0: raise envi.UnsupportedInstruction(self, op) esp = self.getRegister(REG_ESP) ebp = self.getRegister(REG_EBP) esp -= 4 # Room for the base pointer self.writeMemValue(esp, ebp, 4) self.setRegister(REG_EBP, esp) esp -= locsize self.setRegister(REG_ESP, esp) # FIXME a whole bunch of float instructions whose # processing is essentially ignored:
[docs] def i_fldz(self, op): pass
[docs] def i_fild(self, op): pass
[docs] def i_fstp(self, op): pass
[docs] def i_idiv(self, op): #FIXME this needs emulation testing! tsize = op.opers[0].tsize if tsize == 1: ax = self.getRegister(REG_AX) ax = e_bits.signed(ax, 2) d = self.getOperValue(op, 0) d = e_bits.signed(d, 1) if d == 0: raise envi.DivideByZero(self) q = ax / d r = ax % d res = ((r & 0xff) << 8) | (q & 0xff) self.setRegister(REG_AX, res) elif tsize == 2: val = self.twoRegCompound(REG_DX, REG_AX, 2) val = e_bits.signed(val, 4) d = self.getOperValue(op, 0) d = e_bits.signed(d, 2) if d == 0: raise envi.DivideByZero(self) q = val / d r = val % d self.setRegister(REG_AX, q) self.setRegister(REG_DX, r) elif tsize == 4: val = self.twoRegCompound(REG_EDX, REG_EAX, 4) val = e_bits.signed(val, 8) d = self.getOperValue(op, 0) d = e_bits.signed(d, 4) if d == 0: raise envi.DivideByZero(self) q = val / d r = val % d self.setRegister(REG_EAX, q) self.setRegister(REG_EDX, r) else: raise envi.UnsupportedInstruction(self, op)
[docs] def i_imul(self, op): #FIXME eflags # FIXME imul bugs ocount = len(op.opers) if ocount == 2: dst = self.getOperValue(op, 0) src = self.getOperValue(op, 1) dsize = op.opers[0].tsize ssize = op.opers[1].tsize # FIXME all these are taken care of in disasm now... if dsize > ssize: src = e_bits.sign_extend(src, ssize, dsize) ssize = dsize res = dst * src sof = e_bits.is_unsigned_carry(res, dsize) self.setFlag(EFLAGS_CF, sof) self.setFlag(EFLAGS_OF, sof) self.setOperValue(op, 0, res) elif ocount == 3: dst = self.getOperValue(op, 0) src1 = self.getOperValue(op, 1) src2 = self.getOperValue(op, 2) dsize = op.opers[0].tsize ssize1 = op.opers[1].tsize ssize2 = op.opers[2].tsize if dsize > ssize2: # Only the last operand may be shorter imm src2 = e_bits.sign_extend(src2, ssize2, dsize) ssize2 = dsize res = src1 * src2 sof = e_bits.is_unsigned_carry(res, dsize) self.setFlag(EFLAGS_CF, sof) self.setFlag(EFLAGS_OF, sof) self.setOperValue(op, 0, res) else: raise envi.UnsupportedInstruction(self, op)
[docs] def i_in(self, op): raise envi.UnsupportedInstruction(self, op)
[docs] def i_inc(self, op): size = op.opers[0].tsize val = self.getOperValue(op, 0) sval = e_bits.signed(val, size) sval += 1 self.setOperValue(op, 0, sval) # Another arithmetic op where doing signed and unsigned is easier ;) self.setFlag(EFLAGS_OF, e_bits.is_signed_overflow(sval, size)) self.setFlag(EFLAGS_SF, e_bits.is_signed(sval, size)) self.setFlag(EFLAGS_ZF, not sval) self.setFlag(EFLAGS_AF, (sval & 0xf == 0)) self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(sval))
[docs] def i_int(self, op): raise envi.UnsupportedInstruction(self, op)
[docs] def i_int3(self, op): raise envi.BreakpointHit(self)
[docs] def i_lea(self, op): base = self.getOperAddr(op, 1) self.setOperValue(op, 0, base)
[docs] def decCounter(self): """ A helper to decrement and return the counter """ ecx = self.getRegister(REG_ECX) ecx -= 1 self.setRegister(REG_ECX, ecx) return ecx
[docs] def i_lodsb(self, op): esi = self.getRegister(REG_ESI) newal = self.readMemoryFormat(esi, "<B")[0] self.setRegister(REG_AL, newal) if not self.getFlag(EFLAGS_DF): esi += 1 else: esi -= 1 self.setRegister(REG_ESI, esi)
[docs] def i_lodsd(self, op): esi = self.getRegister(REG_ESI) neweax = self.readMemoryFormat(esi, "<L")[0] #FIXME figgure out ADDR_SIZE vs OP_SIZE and which is which self.setRegister(REG_EAX, neweax) if not self.getFlag(EFLAGS_DF): esi += 4 else: esi -= 4 self.setRegister(REG_ESI, esi)
[docs] def i_loop(self, op): if self.decCounter() != 0: return self.getOperValue(op, 0)
[docs] def i_loopz(self, op): if self.decCounter() != 0 and self.cond_e(): return self.getOperValue(op, 0)
[docs] def i_loopnz(self, op): if self.decCounter() != 0 and self.cond_ne(): return self.getOperValue(op, 0)
i_loope = i_loopz i_loopne = i_loopnz
[docs] def i_leave(self, op): ebp = self.getRegister(REG_EBP) self.setRegister(REG_ESP, ebp) self.setRegister(REG_EBP, self.doPop())
[docs] def i_mov(self, op): val = self.getOperValue(op, 1) self.setOperValue(op, 0, val)
[docs] def i_movq(self, op): val = self.getOperValue(op, 1) self.setOperValue(op, 0, val)
[docs] def i_movsb(self, op): esi = self.getRegister(REG_ESI) edi = self.getRegister(REG_EDI) bytes = self.readMemory(esi, 1) self.writeMemory(edi, bytes) if self.getFlag(EFLAGS_DF): self.setRegister(REG_ESI, esi-1) self.setRegister(REG_EDI, edi-1) else: self.setRegister(REG_ESI, esi+1) self.setRegister(REG_EDI, edi+1)
[docs] def i_movsd(self, op): esi = self.getRegister(REG_ESI) edi = self.getRegister(REG_EDI) bytes = self.readMemory(esi, 4) self.writeMemory(edi, bytes) if self.getFlag(EFLAGS_DF): self.setRegister(REG_ESI, esi-4) self.setRegister(REG_EDI, edi-4) else: self.setRegister(REG_ESI, esi+4) self.setRegister(REG_EDI, edi+4)
[docs] def i_movsx(self, op): osize = op.opers[1].tsize nsize = op.opers[0].tsize val = self.getOperValue(op, 1) val = e_bits.sign_extend(val, osize, nsize) self.setOperValue(op, 0, val)
[docs] def i_movzx(self, op): val = self.getOperValue(op, 1) self.setOperValue(op, 0, val)
[docs] def i_mul(self, op): #FIXME make sure these work right tsize = op.opers[0].tsize val = self.getOperValue(op, 0) # Return al/ax/eax as needed... a = self._emu_getGpReg(GPR_A, tsize) res = a * val if tsize == 1: self.setRegister(REG_AX, res) elif tsize == 2: d,a = self.regsFromCompound(res, tsize) self._emu_setGpReg(GPR_A, a, tsize) self._emu_setGpReg(GPR_D, d, tsize) # If the high order stuff was used, set CF/OF if res >> (tsize * 8): self.setFlag(EFLAGS_CF, True) self.setFlag(EFLAGS_OF, True) else: self.setFlag(EFLAGS_CF, False) self.setFlag(EFLAGS_OF, False)
def _emu_setGpReg(self, reg, val, tsize): """ Automagically map all general purpose register accesses to their tsize equiv. Helps clean up a lot of code (and makes a nice place for AMD64 to hook ;) ) """ if tsize == 1: reg += 0x00080000 elif tsize == 2: reg += 0x00100000 self.setRegister(reg, value) def _emu_getGpReg(self, reg, tsize): """ Automagically map all general purpose register accesses to their tsize equiv. Helps clean up a lot of code (and makes a nice place for AMD64 to hook ;) ) """ if tsize == 1: reg += 0x00080000 elif tsize == 2: reg += 0x00100000 return self.getRegister(reg)
[docs] def i_neg(self, op): tsize = op.opers[0].tsize val = self.getOperValue(op, 0) res = 0 - val self.setOperValue(op, 0, res) self.setFlag(EFLAGS_CF, val != 0) self.setFlag(EFLAGS_ZF, not res) self.setFlag(EFLAGS_SF, e_bits.is_signed(res, tsize)) #FIXME how does neg cause/not cause a carry? self.setFlag(EFLAGS_AF, 0) # FIXME EFLAGS_AF
[docs] def i_nop(self, op): pass
[docs] def i_not(self, op): val = self.getOperValue(op, 0) val ^= e_bits.u_maxes[op.opers[0].tsize] self.setOperValue(op, 0, val)
[docs] def i_or(self, op): dst = self.getOperValue(op, 0) dsize = op.opers[0].tsize src = self.getOperValue(op, 1) ssize = op.opers[1].tsize if dsize != ssize: src = e_bits.sign_extend(src, ssize, dsize) ssize = dsize res = dst | src self.setOperValue(op, 0, res) self.setFlag(EFLAGS_OF, 0) self.setFlag(EFLAGS_CF, 0) self.setFlag(EFLAGS_SF, e_bits.is_signed(res, dsize)) self.setFlag(EFLAGS_ZF, not res) self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(res))
[docs] def i_pop(self, op): val = self.doPop() self.setOperValue(op, 0, val)
[docs] def i_popad(self, op): #FIXME 16 bit? self.setRegister(REG_EDI, self.doPop()) self.setRegister(REG_ESI, self.doPop()) self.setRegister(REG_EBP, self.doPop()) self.doPop() # skip one self.setRegister(REG_EBX, self.doPop()) self.setRegister(REG_EDX, self.doPop()) self.setRegister(REG_ECX, self.doPop()) self.setRegister(REG_EAX, self.doPop())
[docs] def i_popfd(self, op): eflags = self.doPop() self.setRegister(REG_EFLAGS, eflags)
[docs] def i_push(self, op): val = self.getOperValue(op, 0) if isinstance(op.opers[0], i386ImmOper): val = e_bits.sign_extend(val, op.opers[0].tsize, 4) #FIXME 64bit self.doPush(val)
[docs] def i_pushad(self, op): tmp = self.getRegister(REG_ESP) self.doPush(self.getRegister(REG_EAX)) self.doPush(self.getRegister(REG_ECX)) self.doPush(self.getRegister(REG_EDX)) self.doPush(self.getRegister(REG_EBX)) self.doPush(tmp) self.doPush(self.getRegister(REG_EBP)) self.doPush(self.getRegister(REG_ESI)) self.doPush(self.getRegister(REG_EDI))
[docs] def i_pushfd(self, op): eflags = self.getRegister(REG_EFLAGS) self.doPush(eflags)
[docs] def i_jmp(self, op): return self.getOperValue(op, 0) # We include all the possible Jcc names just in case somebody # gets hinkey with the disassembler.
[docs] def i_ja(self, op): if self.cond_a(): return self.getOperValue(op, 0)
[docs] def i_jae(self, op): if self.cond_ae(): return self.getOperValue(op, 0)
[docs] def i_jb(self, op): if self.cond_b(): return self.getOperValue(op, 0)
[docs] def i_jbe(self, op): if self.cond_be(): return self.getOperValue(op, 0)
[docs] def i_jc(self, op): if self.cond_c(): return self.getOperValue(op, 0)
[docs] def i_jecxz(self, op): if self.cond_ecxz(): return self.getOperValue(op, 0)
[docs] def i_je(self, op): if self.cond_e(): return self.getOperValue(op, 0)
[docs] def i_jg(self, op): if self.cond_g(): return self.getOperValue(op, 0)
[docs] def i_jge(self, op): if self.cond_ge(): return self.getOperValue(op, 0)
[docs] def i_jl(self, op): if self.cond_l(): return self.getOperValue(op, 0)
[docs] def i_jle(self, op): if self.cond_le(): return self.getOperValue(op, 0)
i_jna = i_jbe i_jnae = i_jb i_jnb = i_jae i_jnbe = i_ja i_jnc = i_jae
[docs] def i_jne(self, op): if self.cond_ne(): return self.getOperValue(op, 0)
i_jng = i_jle i_jnge = i_jl i_jnl = i_jge i_jnle = i_jg
[docs] def i_jno(self, op): if self.cond_no(): return self.getOperValue(op, 0)
[docs] def i_jnp(self, op): if self.cond_np(): return self.getOperValue(op, 0)
[docs] def i_jns(self, op): if self.cond_ns(): return self.getOperValue(op, 0)
i_jnz = i_jne
[docs] def i_jo(self, op): if self.cond_o(): return self.getOperValue(op, 0)
[docs] def i_jp(self, op): if self.cond_p(): return self.getOperValue(op, 0)
i_jpe = i_jp i_jpo = i_jnp
[docs] def i_js(self, op): if self.cond_s(): return self.getOperValue(op, 0)
i_jz = i_je
[docs] def i_rcl(self, op): dsize = op.opers[0].tsize dst = self.getOperValue(op, 0) src = self.getOperValue(op, 1) src = src & 0x1f # Put that carry bit up there. if self.getFlag(EFLAGS_CF): dst = dst | (1 << (8 * dsize)) # Add one to account for carry x = ((8*dsize) - src) + 1 #FIXME is this the one that can end up negative? res = (dst << src) | (dst >> x) cf = (res >> (8*dsize)) & 1 res = e_bits.unsigned(res, dsize) self.setFlag(EFLAGS_CF, cf) if src == 1: m1 = e_bits.msb(res, dsize) m2 = e_bits.msb(res << 1, dsize) self.setFlag(EFLAGS_OF, m1 ^ m2) self.setOperValue(op, 0, res)
[docs] def i_rcr(self, op): dsize = op.opers[0].tsize dst = self.getOperValue(op, 0) src = self.getOperValue(op, 1) src = src & 0x1f # Put that carry bit up there. if self.getFlag(EFLAGS_CF): dst = dst | (1 << (8 * dsize)) # Add one to account for carry x = ((8*dsize) - src) + 1 res = (dst >> src) | (dst << x) cf = (res >> (8*dsize)) & 1 res = e_bits.unsigned(res, dsize) self.setFlag(EFLAGS_CF, cf) if src == 1: m1 = e_bits.msb(res, dsize) m2 = e_bits.msb(res << 1, dsize) self.setFlag(EFLAGS_OF, m1 ^ m2) self.setOperValue(op, 0, res)
[docs] def i_rdtsc(self, op): """ Read the clock cycle counter into edx:eax """ self.setRegister(REG_EDX, 0) self.setRegister(REG_EAX, 0x414141)
[docs] def i_rol(self, op): dstSize = op.opers[0].tsize count = self.getOperValue(op, 1) tempCount = shiftMask(count, dstSize) if tempCount > 0: # Yeah, i know...weird. See the intel manual while tempCount: val = self.getOperValue(op, 0) tempCf = e_bits.msb(val, dstSize) self.setOperValue(op, 0, (val * 2) + tempCf) tempCount -= 1 val = self.getOperValue(op, 0) self.setFlag(EFLAGS_CF, e_bits.lsb(val)) if count == 1: val = self.getOperValue(op, 0) cf = self.getFlag(EFLAGS_CF) self.setFlag(EFLAGS_OF, e_bits.msb(val, dstSize) ^ cf) else: self.setFlag(EFLAGS_OF, False)
[docs] def i_ror(self, op): dstSize = op.opers[0].tsize count = self.getOperValue(op, 1) tempCount = shiftMask(count, dstSize) if tempCount > 0: # Yeah, i know...weird. See the intel manual while tempCount: val = self.getOperValue(op, 0) tempCf = e_bits.lsb(val) self.setOperValue(op, 0, (val / 2) + (tempCf * (2 ** dstSize))) tempCount -= 1 val = self.getOperValue(op, 0) self.setFlag(EFLAGS_CF, e_bits.msb(val, dstSize)) if count == 1: val = self.getOperValue(op, 0) cf = self.getFlag(EFLAGS_CF) # FIXME: This may be broke...the manual is kinda flaky here self.setFlag(EFLAGS_OF, e_bits.msb(val, dstSize) ^ (e_bits.msb(val, dstSize) - 1)) else: self.setFlag(EFLAGS_OF, False)
[docs] def i_ret(self, op): ret = self.doPop() if len(op.opers): esp = self.getRegister(REG_ESP) ival = self.getOperValue(op, 0) self.setRegister(REG_ESP, esp+ival) return ret
[docs] def i_sal(self, op): dsize = op.opers[0].tsize dst = self.getOperValue(op, 0) src = self.getOperValue(op, 1) src = src & 0x1f # According to intel manual, if src == 0 eflags are not changed if src == 0: return res = dst << src cf = (res >> 8*dsize) & 1 res = e_bits.unsigned(res, dsize) self.setFlag(EFLAGS_CF, cf) self.setFlag(EFLAGS_SF, e_bits.is_signed(res, dsize)) self.setFlag(EFLAGS_ZF, not res) self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(res)) if src == 1: self.setFlag(EFLAGS_OF, not e_bits.msb(res, dsize) == cf) else: self.setFlag(EFLAGS_OF, 0) # Undefined, but zero'd on core2 duo self.setOperValue(op, 0, res)
[docs] def i_sar(self, op): dsize = op.opers[0].tsize dst = self.getOperValue(op, 0) src = self.getOperValue(op, 1) src = src & 0x1f # According to intel manual, if src == 0 eflags are not changed if src == 0: return signed = e_bits.msb(dst, dsize) res = dst >> src cf = (dst >> (src-1)) & 1 # If it was signed, we need to fill in all those bits we # shifted off with ones. if signed: x = (8*dsize) - src umax = e_bits.u_maxes[dsize] res |= (umax >> x) << x res = e_bits.unsigned(res, dsize) self.setFlag(EFLAGS_CF, cf) self.setFlag(EFLAGS_SF, e_bits.is_signed(res, dsize)) self.setFlag(EFLAGS_ZF, not res) self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(res)) if src == 1: self.setFlag(EFLAGS_OF, False) else: self.setFlag(EFLAGS_OF, 0) # Undefined, but zero'd on core2 duo self.setOperValue(op, 0, res)
[docs] def i_shl(self, op): return self.i_sal(op)
[docs] def i_shr(self, op): dsize = op.opers[0].tsize dst = self.getOperValue(op, 0) src = self.getOperValue(op, 1) src = src & 0x1f # According to intel manual, if src == 0 eflags are not changed if src == 0: return res = dst >> src cf = (dst >> (src-1)) & 1 res = e_bits.unsigned(res, dsize) self.setFlag(EFLAGS_CF, cf) self.setFlag(EFLAGS_SF, e_bits.is_signed(res, dsize)) self.setFlag(EFLAGS_ZF, not res) self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(res)) if src == 1: self.setFlag(EFLAGS_OF, False) else: self.setFlag(EFLAGS_OF, 0) # Undefined, but zero'd on core2 duo self.setOperValue(op, 0, res)
[docs] def i_shrd(self, op): dsize = op.opers[0].tsize bsize = dsize * 8 dst = self.getOperValue(op, 0) src = self.getOperValue(op, 1) cnt = self.getOperValue(op, 2) cnt &= 0x1f # Reg gets masked down if cnt == 0: return if cnt > bsize: # result is "undfined" return res = dst >> cnt res |= src << (bsize - cnt) # We now have the bits masked into res, but it has become # wider than the original operand. # Ret is masked down to size ret = e_bits.unsigned(res, dsize) if cnt == 1: # Set OF on sign change dsign = e_bits.is_signed(dst, dsize) rsign = e_bits.is_signed(ret, dsize) self.setFlag(EFLAGS_OF, dsign != rsign) # set carry to last shifted bit self.setFlag(EFLAGS_CF, (res << bsize) & 1) self.setFlag(EFLAGS_SF, e_bits.is_signed(ret, dsize)) self.setFlag(EFLAGS_ZF, not ret) self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(ret)) self.setOperValue(op, 0, ret)
[docs] def i_shld(self, op): dsize = op.opers[0].tsize bsize = dsize * 8 dst = self.getOperValue(op, 0) src = self.getOperValue(op, 1) cnt = self.getOperValue(op, 2) cnt &= 0x1f # Reg gets masked down if cnt == 0: return if cnt > bsize: return res = dst << cnt res |= src >> (bsize - cnt) ret = e_bits.unsigned(res, dsize) if cnt == 1: # Set OF on sign change dsign = e_bits.is_signed(dst, dsize) rsign = e_bits.is_signed(ret, dsize) self.setFlag(EFLAGS_OF, dsign != rsign) # set carry to last shifted bit self.setFlag(EFLAGS_CF, (dst << (cnt-1)) & 1) self.setFlag(EFLAGS_SF, e_bits.is_signed(ret, dsize)) self.setFlag(EFLAGS_ZF, not ret) self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(ret)) self.setOperValue(op, 0, ret)
[docs] def i_scasb(self, op): al = self.getRegister(REG_AL) edi = self.getRegister(REG_EDI) base,size = self._emu_segments[SEG_ES] memval = ord(self.readMemory(base+edi, 1)) self.intSubBase(al, memval, 1, 1) if self.getFlag(EFLAGS_DF): edi -= 1 else: edi += 1 self.setRegister(REG_EDI, edi)
[docs] def i_scasd(self, op): #FIXME probably need to handle oper prefix by hand here... eax = self.getRegister(REG_EAX) edi = self.getRegister(REG_EDI) base,size = self._emu_segments[SEG_ES] memval = struct.unpack("<L",self.readMemory(base+edi, 4))[0] self.intSubBase(eax, memval, 4, 4) if self.getFlag(EFLAGS_DF): edi -= 4 else: edi += 4 self.setRegister(REG_EDI, edi)
[docs] def i_stosb(self, op): al = self.getRegister(REG_AL) edi = self.getRegister(REG_EDI) base,size = self._emu_segments[SEG_ES] self.writeMemory(base+edi, chr(al)) if self.getFlag(EFLAGS_DF): edi -= 1 else: edi += 1 self.setRegister(REG_EDI, edi)
def i_stosd(self, op): eax = self.getRegister(REG_EAX) edi = self.getRegister(REG_EDI) base,size = self._emu_segments[SEG_ES] self.writeMemory(base+edi, struct.pack("<L", eax)) if self.getFlag(EFLAGS_DF): edi -= 4 else: edi += 4 self.setRegister(REG_EDI, edi) # We include all the possible SETcc names just in case somebody # gets hinkey with the disassembler.
[docs] def i_seta(self, op): self.setOperValue(op, 0, int(self.cond_a()))
[docs] def i_setae(self, op): self.setOperValue(op, 0, int(self.cond_ae()))
[docs] def i_setb(self, op): self.setOperValue(op, 0, int(self.cond_b()))
[docs] def i_setbe(self, op): self.setOperValue(op, 0, int(self.cond_be()))
[docs] def i_setc(self, op): self.setOperValue(op, 0, int(self.cond_c()))
[docs] def i_setecxz(self, op): self.setOperValue(op, 0, int(self.cond_ecxz()))
[docs] def i_sete(self, op): self.setOperValue(op, 0, int(self.cond_e()))
[docs] def i_setg(self, op): self.setOperValue(op, 0, int(self.cond_g()))
[docs] def i_setge(self, op): self.setOperValue(op, 0, int(self.cond_ge()))
[docs] def i_setl(self, op): self.setOperValue(op, 0, int(self.cond_l()))
[docs] def i_setle(self, op): self.setOperValue(op, 0, int(self.cond_le()))
i_setna = i_setbe i_setnae = i_setb i_setnb = i_setae i_setnbe = i_seta i_setnc = i_setae
[docs] def i_setne(self, op): self.setOperValue(op, 0, int(self.cond_ne()))
i_setng = i_setle i_setnge = i_setl i_setnl = i_setge i_setnle = i_setg
[docs] def i_setno(self, op): self.setOperValue(op, 0, int(self.cond_no()))
[docs] def i_setnp(self, op): self.setOperValue(op, 0, int(self.cond_np()))
[docs] def i_setns(self, op): self.setOperValue(op, 0, int(self.cond_ns()))
i_setnz = i_setne
[docs] def i_seto(self, op): self.setOperValue(op, 0, int(self.cond_o()))
[docs] def i_setp(self, op): self.setOperValue(op, 0, int(self.cond_p()))
i_setpe = i_setp i_setpo = i_setnp
[docs] def i_sets(self, op): self.setOperValue(op, 0, int(self.cond_s()))
i_setz = i_sete
[docs] def i_sbb(self, op): dst = self.getOperValue(op, 0) src = self.getOperValue(op, 1) # Much like "integer subtraction" but we need # too add in the carry flag if src == None or dst == None: self.undefFlags() return None dsize = op.opers[0].tsize ssize = op.opers[1].tsize # Sign extend immediates where the sizes don't match if dsize != ssize: src = e_bits.sign_extend(src, ssize, dsize) ssize = dsize src += self.getFlag(EFLAGS_CF) res = self.intSubBase(src, dst, ssize, dsize) self.setOperValue(op, 0, res) # FIXME scas stuff goes here # FIXME conditional byte set goes here
[docs] def i_stc(self, op): self.setFlag(EFLAGS_CF, True)
[docs] def i_std(self, op): self.setFlag(EFLAGS_DF, True)
[docs] def i_sti(self, op): self.setFlag(EFLAGS_IF, True) # FIXME stos variants go here
[docs] def i_stosd(self, op): eax = self.getRegister(REG_EAX) edi = self.getRegister(REG_EDI) # FIXME shouldn't have to do this directly # FIXME this needs a 32/16 bit mode check base,size = self._emu_segments[SEG_ES] self.writeMemValue(base+edi, eax, 4) # FIXME edi inc must be by oper len self.setRegister(REG_EDI, edi+4)
[docs] def i_sub(self, op): x = self.integerSubtraction(op) if x != None: self.setOperValue(op, 0, x)
[docs] def i_test(self, op): self.logicalAnd(op)
[docs] def i_wait(self, op): print "i_wait() is a stub..."
[docs] def i_xadd(self, op): val1 = self.getOperValue(op, 0) val2 = self.getOperValue(op, 1) temp = val1 + val2 self.setOperValue(op, 1, val1) self.setOperValue(op, 0, temp)
[docs] def i_xchg(self, op): temp = self.getOperValue(op, 0) self.setOperValue(op, 0, self.getOperValue(op, 1)) self.setOperValue(op, 1, temp)
[docs] def i_xor(self, op): dsize = op.opers[0].tsize ssize = op.opers[1].tsize dst = self.getOperValue(op, 0) src = self.getOperValue(op, 1) ret = src ^ dst self.setOperValue(op, 0, ret) self.setFlag(EFLAGS_CF, 0) self.setFlag(EFLAGS_OF, 0) self.setFlag(EFLAGS_SF, e_bits.is_signed(ret, dsize)) self.setFlag(EFLAGS_ZF, not ret) self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(ret)) self.setFlag(EFLAGS_AF, False) # Undefined but actually cleared on amd64 X2
[docs] def i_pxor(self, op): return self.i_xor(op)