diff --git a/README.rst b/README.rst index f9318af..006d520 100644 --- a/README.rst +++ b/README.rst @@ -57,7 +57,7 @@ User documentation and API can be found at Todo ==== -Some components of Amoco are still in the +Some components of amoco are still in the process of being pushed to the release branch or further developed. More precisely: @@ -65,7 +65,6 @@ More precisely: - arm SIMD, VFP, NEON, TrustZone, Jazelle instruction sets are not implemented, - some solver-based disassembling strategies are not merged yet. - idb import/export features are not implemented. -- 6502 and PPC archs are planned. Contributions to fulfill uncomplete/unimplemented parts are welcome. @@ -88,6 +87,19 @@ Please see `LICENSE`_. Changelog ========= +- `v2.9.10`_ + + * x86: add support for real mode execution + * x86: add full support for segmentation/paging + * add baremetal-x86 system for bios firmware analysis + * merge new arch.io module to define IOs' stubs + * merge cas.blobs module + * add fast versions of rep stos/lods/scas/movs + * add tracepoint method in emul class + * add support for PE resources + * improve amoco app load/emul commands + * add set,display,nexti,until in emul ui. + - `v2.9.9`_ * add ppc32 (e200) architecture @@ -397,6 +409,7 @@ Changelog .. _sqlalchemy: http://www.sqlalchemy.org .. _QDarkStyleSheet: https://github.com/ColinDuquesnoy/QDarkStyleSheet .. _LICENSE: https://github.com/bdcht/amoco/blob/release/LICENSE +.. _v2.9.10: https://github.com/bdcht/amoco/releases/tag/v2.9.10 .. _v2.9.9: https://github.com/bdcht/amoco/releases/tag/v2.9.9 .. _v2.9.8: https://github.com/bdcht/amoco/releases/tag/v2.9.8 .. _v2.9.7: https://github.com/bdcht/amoco/releases/tag/v2.9.7 diff --git a/amoco/arch/arm/cpu_armv7.py b/amoco/arch/arm/cpu_armv7.py index 64ee7bd..f928d33 100644 --- a/amoco/arch/arm/cpu_armv7.py +++ b/amoco/arch/arm/cpu_armv7.py @@ -29,7 +29,7 @@ disassemble = disassembler([spec_armv7, spec_thumb], instruction_armv7, mode, endian) -def PC(): +def PC(state=None): return pc_ diff --git a/amoco/arch/arm/cpu_armv8.py b/amoco/arch/arm/cpu_armv8.py index 57d6cb5..3ba6429 100644 --- a/amoco/arch/arm/cpu_armv8.py +++ b/amoco/arch/arm/cpu_armv8.py @@ -25,7 +25,7 @@ disassemble = disassembler([spec_armv8], endian=endian, iclass=instruction_armv8) -def PC(): +def PC(state=None): return pc diff --git a/amoco/arch/avr/cpu.py b/amoco/arch/avr/cpu.py index 03c7782..55ed75d 100644 --- a/amoco/arch/avr/cpu.py +++ b/amoco/arch/avr/cpu.py @@ -21,7 +21,7 @@ disassemble = disassembler([spec], iclass=instruction_avr) -def PC(): +def PC(state=None): return pc diff --git a/amoco/arch/avr/env.py b/amoco/arch/avr/env.py index 625f231..46ef45a 100644 --- a/amoco/arch/avr/env.py +++ b/amoco/arch/avr/env.py @@ -81,30 +81,30 @@ EEPM1 = slc(EECR,5, 1, "EEPM1") # 10=WriteOnly 11:Reserved vectors = [ - ext("RESET",8), - ext("INT0",8), - ext("INT1",8), - ext("PCINT0",8), - ext("PCINT1",8), - ext("PCINT2",8), - ext("WDT",8), - ext("TIMER2_COMPA",8), - ext("TIMER2_COMPB",8), - ext("TIMER2_OVF",8), - ext("TIMER1_CAPT",8), - ext("TIMER1_COMPA",8), - ext("TIMER1_COMPB",8), - ext("TIMER1_OVF",8), - ext("TIMER0_COMPA",8), - ext("TIMER0_COMPB",8), - ext("TIMER0_OVF",8), - ext("SPI_STC",8), - ext("USART_RX",8), - ext("USART_UDRE",8), - ext("USART_TX",8), - ext("ADC",8), - ext("EE_READY",8), - ext("ANALOG_COMP",8), - ext("TWI",8), - ext("SPM_READY",8), + ext("RESET",size=8), + ext("INT0",size=8), + ext("INT1",size=8), + ext("PCINT0",size=8), + ext("PCINT1",size=8), + ext("PCINT2",size=8), + ext("WDT",size=8), + ext("TIMER2_COMPA",size=8), + ext("TIMER2_COMPB",size=8), + ext("TIMER2_OVF",size=8), + ext("TIMER1_CAPT",size=8), + ext("TIMER1_COMPA",size=8), + ext("TIMER1_COMPB",size=8), + ext("TIMER1_OVF",size=8), + ext("TIMER0_COMPA",size=8), + ext("TIMER0_COMPB",size=8), + ext("TIMER0_OVF",size=8), + ext("SPI_STC",size=8), + ext("USART_RX",size=8), + ext("USART_UDRE",size=8), + ext("USART_TX",size=8), + ext("ADC",size=8), + ext("EE_READY",size=8), + ext("ANALOG_COMP",size=8), + ext("TWI",size=8), + ext("SPM_READY",size=8), ] diff --git a/amoco/arch/dwarf/cpu.py b/amoco/arch/dwarf/cpu.py index 19251bb..4d79e09 100644 --- a/amoco/arch/dwarf/cpu.py +++ b/amoco/arch/dwarf/cpu.py @@ -21,7 +21,7 @@ disassemble.maxlen = 21 -def PC(): +def PC(state=None): return op_ptr diff --git a/amoco/arch/eBPF/cpu.py b/amoco/arch/eBPF/cpu.py index 903ee2b..f5681bb 100644 --- a/amoco/arch/eBPF/cpu.py +++ b/amoco/arch/eBPF/cpu.py @@ -21,7 +21,7 @@ disassemble = disassembler([spec], iclass=instruction_eBPF) -def PC(): +def PC(state=None): return pc diff --git a/amoco/arch/eBPF/cpu_bpf.py b/amoco/arch/eBPF/cpu_bpf.py index 58602af..5a864bf 100644 --- a/amoco/arch/eBPF/cpu_bpf.py +++ b/amoco/arch/eBPF/cpu_bpf.py @@ -22,7 +22,7 @@ disassemble = disassembler([spec_bpf], iclass=instruction_BPF) -def PC(): +def PC(state=None): return pc diff --git a/amoco/arch/io.py b/amoco/arch/io.py new file mode 100644 index 0000000..ba26cc0 --- /dev/null +++ b/amoco/arch/io.py @@ -0,0 +1,42 @@ +from amoco.cas.expressions import top +from types import MethodType +from amoco.logger import Log + +logger = Log(__name__) +logger.debug("loading module") + +class DefineIO: + + def __init__(self,port,name=None): + self.io = IO(port,name) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + IO.ports[self.io.port] = self.io + + def In(self, func): + self.io.In = MethodType(func,self.io) + return func + + def Out(self, func): + self.io.Out = MethodType(func,self.io) + return func + +class IO: + ports = {} + @classmethod + def get_port(cls,port): + return cls.ports.get(port,cls(port)) + + def __init__(self,port,name=None): + self.port = port + self.name = name or "IO#0x%x"%port + def In(self,env,dl): + logger.warning("undefined %s IN"%str(self)) + return top(dl*8) + def Out(self,env,src): + logger.warning("undefined %s OUT (%s)"%(str(self),src)) + def __str__(self): + return self.name diff --git a/amoco/arch/mips/cpu_r3000.py b/amoco/arch/mips/cpu_r3000.py index c6e5c14..ccd998e 100644 --- a/amoco/arch/mips/cpu_r3000.py +++ b/amoco/arch/mips/cpu_r3000.py @@ -24,7 +24,7 @@ disassemble = disassembler([spec], iclass=instruction_r3000,endian=endian) -def PC(): +def PC(state=None): return pc def get_data_endian(): diff --git a/amoco/arch/mips/cpu_r3000LE.py b/amoco/arch/mips/cpu_r3000LE.py index b1473fa..f2afba6 100644 --- a/amoco/arch/mips/cpu_r3000LE.py +++ b/amoco/arch/mips/cpu_r3000LE.py @@ -22,7 +22,7 @@ disassemble = disassembler([spec], iclass=instruction_r3000) -def PC(): +def PC(state=None): return pc diff --git a/amoco/arch/msp430/cpu.py b/amoco/arch/msp430/cpu.py index dfbd692..85d131a 100644 --- a/amoco/arch/msp430/cpu.py +++ b/amoco/arch/msp430/cpu.py @@ -23,7 +23,7 @@ disassemble.maxlen = 6 -def PC(): +def PC(state=None): return pc diff --git a/amoco/arch/pic/cpu_pic18f46k22.py b/amoco/arch/pic/cpu_pic18f46k22.py index 7e0b83d..223cf48 100644 --- a/amoco/arch/pic/cpu_pic18f46k22.py +++ b/amoco/arch/pic/cpu_pic18f46k22.py @@ -21,7 +21,7 @@ disassemble = disassembler([spec_pic18], iclass=instruction_f46k22) -def PC(): +def PC(state=None): return pc diff --git a/amoco/arch/ppc32/cpu.py b/amoco/arch/ppc32/cpu.py index ca977d9..cac4eaf 100644 --- a/amoco/arch/ppc32/cpu.py +++ b/amoco/arch/ppc32/cpu.py @@ -23,7 +23,7 @@ disassemble = disassembler([spec], iclass=instruction_ppc32,endian=endian) -def PC(): +def PC(state=None): return pc def get_data_endian(): diff --git a/amoco/arch/ppc32/cpu_e200.py b/amoco/arch/ppc32/cpu_e200.py index 75b9a97..95f1159 100644 --- a/amoco/arch/ppc32/cpu_e200.py +++ b/amoco/arch/ppc32/cpu_e200.py @@ -23,7 +23,7 @@ disassemble = disassembler([spec_vle], iclass=instruction_e200,endian=endian) -def PC(): +def PC(state=None): return pc def get_data_endian(): diff --git a/amoco/arch/ppc32/e200/spec_e200.py b/amoco/arch/ppc32/e200/spec_e200.py index 837adca..150c69c 100644 --- a/amoco/arch/ppc32/e200/spec_e200.py +++ b/amoco/arch/ppc32/e200/spec_e200.py @@ -8,5 +8,5 @@ # import generic PowerPC ISA (book E): -from amoco.arch.ppc32.spec import * +from amoco.arch.ppc32.spec_booke import * diff --git a/amoco/arch/riscv/cpu_rv32i.py b/amoco/arch/riscv/cpu_rv32i.py index ab2587d..b325cd3 100644 --- a/amoco/arch/riscv/cpu_rv32i.py +++ b/amoco/arch/riscv/cpu_rv32i.py @@ -22,7 +22,7 @@ disassemble = disassembler([spec_rv32i], iclass=instruction_riscv) -def PC(): +def PC(state=None): return pc diff --git a/amoco/arch/riscv/cpu_rv64i.py b/amoco/arch/riscv/cpu_rv64i.py index 45d2e51..2ac9a01 100644 --- a/amoco/arch/riscv/cpu_rv64i.py +++ b/amoco/arch/riscv/cpu_rv64i.py @@ -22,7 +22,7 @@ disassemble = disassembler([spec_rv64i], iclass=instruction_riscv64) -def PC(): +def PC(state=None): return pc diff --git a/amoco/arch/sparc/cpu_v8.py b/amoco/arch/sparc/cpu_v8.py index 1716153..a8a5dc7 100644 --- a/amoco/arch/sparc/cpu_v8.py +++ b/amoco/arch/sparc/cpu_v8.py @@ -22,7 +22,7 @@ disassemble = disassembler([spec_v8], endian=lambda: -1, iclass=instruction_sparc) -def PC(): +def PC(state=None): return pc diff --git a/amoco/arch/superh/cpu_sh2.py b/amoco/arch/superh/cpu_sh2.py index 8198c35..2c240fc 100644 --- a/amoco/arch/superh/cpu_sh2.py +++ b/amoco/arch/superh/cpu_sh2.py @@ -21,7 +21,7 @@ disassemble = disassembler([spec_sh2], endian=lambda: -1, iclass=instruction_sh2) -def PC(): +def PC(state=None): return pc diff --git a/amoco/arch/superh/cpu_sh4.py b/amoco/arch/superh/cpu_sh4.py index db24c0e..dac7719 100644 --- a/amoco/arch/superh/cpu_sh4.py +++ b/amoco/arch/superh/cpu_sh4.py @@ -22,5 +22,5 @@ disassemble = disassembler([spec_sh4], endian=lambda: -1, iclass=instruction_sh4) -def PC(): +def PC(state=None): return pc diff --git a/amoco/arch/tricore/cpu.py b/amoco/arch/tricore/cpu.py index 5da1cc5..a8aa631 100644 --- a/amoco/arch/tricore/cpu.py +++ b/amoco/arch/tricore/cpu.py @@ -21,7 +21,7 @@ disassemble = disassembler([spec], iclass=instruction_tricore) -def PC(): +def PC(state=None): return pc diff --git a/amoco/arch/v850/asm.py b/amoco/arch/v850/asm.py index 56a04e5..2d5e449 100644 --- a/amoco/arch/v850/asm.py +++ b/amoco/arch/v850/asm.py @@ -477,6 +477,7 @@ def i_HSW(i, fmap): @_pc def i_SHR(i, fmap): shift, src = i.operands[0:2] + dst = None if len(i.operands) == 3: dst = i.operands[2] if shift._is_reg: @@ -490,12 +491,14 @@ def i_SHR(i, fmap): fmap[Z] = r == 0 fmap[S] = r.bit(r.size - 1) fmap[OV] = bit0 - fmap[dst] = x + if dst is not None: + fmap[dst] = x @_pc def i_SHL(i, fmap): shift, src = i.operands[0:2] + dst = None if len(i.operands) == 3: dst = i.operands[2] if shift._is_reg: @@ -509,7 +512,8 @@ def i_SHL(i, fmap): fmap[Z] = r == 0 fmap[S] = r.bit(r.size - 1) fmap[OV] = bit0 - fmap[dst] = x + if dst is not None: + fmap[dst] = x # conditionals : diff --git a/amoco/arch/v850/cpu_v850e2s.py b/amoco/arch/v850/cpu_v850e2s.py index 7e36fca..5c2a7e2 100644 --- a/amoco/arch/v850/cpu_v850e2s.py +++ b/amoco/arch/v850/cpu_v850e2s.py @@ -21,7 +21,7 @@ disassemble = disassembler([spec], iclass=instruction_v850) -def PC(): +def PC(state=None): return pc diff --git a/amoco/arch/w65c02/cpu.py b/amoco/arch/w65c02/cpu.py index 6a407d3..f28da8e 100644 --- a/amoco/arch/w65c02/cpu.py +++ b/amoco/arch/w65c02/cpu.py @@ -21,7 +21,7 @@ disassemble = disassembler([spec], iclass=instruction_w65c02) -def PC(): +def PC(state=None): return pc diff --git a/amoco/arch/wasm/cpu.py b/amoco/arch/wasm/cpu.py index bc6fea3..1b1049f 100644 --- a/amoco/arch/wasm/cpu.py +++ b/amoco/arch/wasm/cpu.py @@ -27,7 +27,7 @@ disassemble.maxlen = 16 -def PC(): +def PC(state=None): return op_ptr diff --git a/amoco/arch/x64/cpu_x64.py b/amoco/arch/x64/cpu_x64.py index d38849a..7222cbb 100644 --- a/amoco/arch/x64/cpu_x64.py +++ b/amoco/arch/x64/cpu_x64.py @@ -19,8 +19,8 @@ disassemble.maxlen = 15 -def PC(): - return rip +def PC(state=None): + return rip if state is None else state(ptr(rip,seg=cs)) def get_data_endian(): diff --git a/amoco/arch/x64/spec_ia32e.py b/amoco/arch/x64/spec_ia32e.py index 480e94f..2248741 100644 --- a/amoco/arch/x64/spec_ia32e.py +++ b/amoco/arch/x64/spec_ia32e.py @@ -990,8 +990,8 @@ def ia32_xfence(obj, Mod, RM, data): obj.operands = [] -@ispec_ia32("*>[ {0f}{20} /r ]", mnemonic="MOV", _inv=False) -@ispec_ia32("*>[ {0f}{22} /r ]", mnemonic="MOV", _inv=True) +@ispec_ia32("*>[ {0f}{20} /r ]", mnemonic="MOV", _inv=True) +@ispec_ia32("*>[ {0f}{22} /r ]", mnemonic="MOV", _inv=False) def ia32_mov_cr(obj, Mod, REG, RM, data, _inv): if REG not in (0, 2, 3, 4): raise InstructionError(obj) @@ -1001,9 +1001,11 @@ def ia32_mov_cr(obj, Mod, REG, RM, data, _inv): obj.type = type_system -@ispec_ia32("*>[ {0f}{21} /r ]", mnemonic="MOV", _inv=False) -@ispec_ia32("*>[ {0f}{23} /r ]", mnemonic="MOV", _inv=True) +@ispec_ia32("*>[ {0f}{21} /r ]", mnemonic="MOV", _inv=True) +@ispec_ia32("*>[ {0f}{23} /r ]", mnemonic="MOV", _inv=False) def ia32_mov_dr(obj, Mod, REG, RM, data, _inv): + if REG not in (0, 1, 2, 3, 6, 7): + raise InstructionError(obj) op1 = env.dr(REG) op2 = getregR(obj, RM, 64) obj.operands = [op1, op2] if not _inv else [op2, op1] diff --git a/amoco/arch/x86/asm.py b/amoco/arch/x86/asm.py index bc7d367..393206a 100644 --- a/amoco/arch/x86/asm.py +++ b/amoco/arch/x86/asm.py @@ -5,6 +5,8 @@ # published under GPLv2 license from .env import * +from .structs import * +from amoco.arch.x86 import hw from amoco.cas.utils import * from amoco.logger import Log @@ -15,12 +17,13 @@ # utils : def push(fmap, x): fmap[esp] = fmap(esp - x.length) - fmap[mem(esp, x.size)] = x + fmap[mem(esp, x.size, seg=ss)] = x -def pop(fmap, l): - v = fmap(mem(esp, l.size)) - fmap[esp] = fmap(esp + l.length) +def pop(fmap, l, sz=0): + v = fmap(mem(esp, l.size, seg=ss)) + nb = (sz//8) or l.length + fmap[esp] = fmap(esp + nb) fmap[l] = v @@ -48,7 +51,6 @@ def halfborrow(x, y, c=None): s, carry, o = SubWithBorrow(x[0:4], y[0:4], c) return carry - # ------------------------------------------------------------------------------ def i_AAA(i, fmap): fmap[eip] = fmap[eip] + i.length @@ -127,7 +129,7 @@ def i_AAM(i, fmap): def i_XLATB(i, fmap): fmap[eip] = fmap[eip] + i.length _table = bx if i.misc["opdsz"] == 16 else ebx - fmap[al] = fmap(mem(_table + al.zeroextend(_table.size), 8)) + fmap[al] = fmap(mem(_table + al.zeroextend(_table.size), 8,seg=ds)) # ------------------------------------------------------------------------------ @@ -152,6 +154,23 @@ def i_WAIT(i, fmap): def i_MWAIT(i, fmap): fmap[eip] = fmap[eip] + i.length +def i_ENTER(i, fmap): + fmap[eip] = fmap[eip] + i.length + AllocSize = i.operands[0].v # required size in bytes (imm16) + NestingLevel = i.operands[1].v % 32 + opdsz = i.misc["opdsz"] or internals['mode'] + _bp = ebp if opdsz==32 else bp + _sp = esp if opdsz==32 else sp + push(fmap,fmap(_bp)) + frame = fmap(_sp) + if NestingLevel>1: + for _ in range(NestingLevel): + fmap[_bp] = fmap(_bp)-_bp.length + push(fmap,fmap(_bp)) + if NestingLevel>0: + push(fmap,frame) + fmap[_bp] = frame + fmap[esp] = fmap(esp-AllocSize) # LEAVE instruction is a shortcut for 'mov esp,ebp ; pop ebp ;' def i_LEAVE(i, fmap): @@ -161,7 +180,14 @@ def i_LEAVE(i, fmap): def i_RET(i, fmap): - pop(fmap, eip) + opdsz = i.misc["opdsz"] or internals['mode'] + _ip = eip if opdsz==32 else ip + if len(i.operands)>0: + src = i.operands[0].v + pop(fmap, _ip) + fmap[esp] = fmap(esp) + src + else: + pop(fmap, _ip) def i_HLT(i, fmap): @@ -169,18 +195,24 @@ def i_HLT(i, fmap): # ------------------------------------------------------------------------------ + def _ins_(i, fmap, l): - counter = cx if i.misc["adrsz"] else ecx - loc = mem(edi, l * 8) - src = ext("IN", size=l * 8).call(fmap, port=fmap(dx)) + adrsz = i.misc["adrsz"] or internals['mode'] + counter = ecx if adrsz==32 else cx + dst_r = edi if adrsz==32 else di + dst = fmap(ptr(dst_r,seg=es)) + direction = fmap(df) + cnt = 1 if i.misc["rep"]: - fmap[loc] = tst(fmap(counter) == 0, fmap(loc), src) - fmap[counter] = fmap(counter) - 1 - fmap[eip] = tst(fmap(counter) == 0, fmap[eip] + i.length, fmap[eip]) - else: - fmap[loc] = src - fmap[eip] = fmap[eip] + i.length - fmap[edi] = tst(fmap(df), fmap(edi) - l, fmap(edi) + l) + cnt = fmap(counter) + if cnt==0: + return + fmap[counter] = cst(0,counter.size) + src = hw.IO.get_port(fmap(dx)).In(env=fmap,dl=l) + fmap[dst] = src + off = cnt*l + fmap[dst_r] = tst(fmap(df), fmap(dst_r) - off, fmap(dst_r) + off) + fmap[eip] = fmap[eip] + i.length def i_INSB(i, fmap): @@ -196,15 +228,28 @@ def i_INSD(i, fmap): # ------------------------------------------------------------------------------ +from amoco.cas.blobs import blob_ptr, blob_comp + def _outs_(i, fmap, l): - counter = cx if i.misc["adrsz"] else ecx - ext("OUT").call(fmap, src=fmap(mem(esi, l * 8))) + adrsz = i.misc["adrsz"] or internals['mode'] + counter = ecx if adrsz==32 else cx + src_r = esi if adrsz==32 else si + src_seg = i.misc["segreg"] + if src_seg is None: + src_seg = ds + cnt = 1 if i.misc["rep"]: - fmap[counter] = fmap(counter) - 1 - fmap[eip] = tst(fmap(counter) == 0, fmap[eip] + i.length, fmap[eip]) - else: - fmap[eip] = fmap[eip] + i.length - fmap[edi] = tst(fmap(df), fmap(edi) - l, fmap(edi) + l) + cnt = fmap(counter) + if cnt==0: + return + fmap[counter] = cst(0,counter.size) + src = ptr(src_r,seg=src_seg) + direction = fmap(df) + data = blob_ptr(dl=l,a=src).as_array(N=cnt,d=direction) + off = cnt*l + hw.IO.get_port(fmap(dx)).Out(env=fmap,src=fmap(data)) + fmap[src_r] = tst(fmap(df), fmap(src_r) - off, fmap(src_r) + off) + fmap[eip] = fmap[eip] + i.length def i_OUTSB(i, fmap): @@ -221,8 +266,8 @@ def i_OUTSD(i, fmap): # ------------------------------------------------------------------------------ def i_INT3(i, fmap): - fmap[eip] = ext("INT3", size=32) - + fmap[eip] = fmap[eip] + i.length + do_interrupt_call(i,fmap,cst(3,8)) def i_CLC(i, fmap): fmap[eip] = fmap[eip] + i.length @@ -325,27 +370,34 @@ def i_SAHF(i, fmap): # ------------------------------------------------------------------------------ def _cmps_(i, fmap, l): counter = cx if i.misc["adrsz"] else ecx - dst = fmap(mem(edi, l * 8)) - src = fmap(mem(esi, l * 8)) + dst = fmap(mem(edi, l * 8,seg=es)) + src_seg = i.misc["segreg"] + if src_seg is None: + src_seg = ds + src = fmap(mem(esi, l * 8,seg=src_seg)) x, carry, overflow = SubWithBorrow(dst, src) - if i.misc["rep"]: + if i.misc["rep"] or i.misc["repne"]: + zv = bit0 if i.misc["rep"] else bit1 cnt = fmap(counter) - fmap[af] = tst(cnt == 0, fmap(af), halfborrow(dst, src)) - fmap[pf] = tst(cnt == 0, fmap(pf), parity8(x[0:8])) - fmap[zf] = tst(cnt == 0, fmap(zf), x == 0) - fmap[sf] = tst(cnt == 0, fmap(sf), x < 0) - fmap[cf] = tst(cnt == 0, fmap(cf), carry) - fmap[of] = tst(cnt == 0, fmap(of), overflow) - fmap[eip] = tst(cnt == 0, fmap[eip] + i.length, fmap[eip]) - fmap[counter] = tst(cnt == 0, cnt, cnt - 1) + cond = (cnt==0)|(fmap(zf)==zv) + if cond==bit1: + fmap[eip] = fmap[eip] + i.length + return + elif cond==bit0: + fmap[counter] = cnt - 1 + else: + fmap[counter] = cst(0,counter.size) + fmap[edi] = top(32) + fmap[esi] = top(32) + return else: - fmap[af] = halfborrow(dst, src) - fmap[pf] = parity8(x[0:8]) - fmap[zf] = x == 0 - fmap[sf] = x < 0 - fmap[cf] = carry - fmap[of] = overflow fmap[eip] = fmap[eip] + i.length + fmap[af] = halfborrow(dst, src) + fmap[pf] = parity8(x[0:8]) + fmap[zf] = x == 0 + fmap[sf] = x < 0 + fmap[cf] = carry + fmap[of] = overflow fmap[edi] = tst(fmap(df), fmap(edi) - l, fmap(edi) + l) fmap[esi] = tst(fmap(df), fmap(esi) - l, fmap(esi) + l) @@ -367,29 +419,34 @@ def i_CMPSD(i, fmap): # ------------------------------------------------------------------------------ def _scas_(i, fmap, l): - counter = cx if i.misc["adrsz"] else ecx + adrsz = i.misc["adrsz"] or internals['mode'] + counter = ecx if adrsz==32 else cx + dst_r = edi if adrsz==32 else di a = fmap({1: al, 2: ax, 4: eax}[l]) - src = fmap(mem(edi, l * 8)) + src = fmap(mem(edi, l * 8,seg=es)) x, carry, overflow = SubWithBorrow(a, src) - if i.misc["rep"]: + if i.misc["rep"] or i.misc["repne"]: + zv = bit0 if i.misc["rep"] else bit1 cnt = fmap(counter) - fmap[af] = tst(cnt == 0, fmap(af), halfborrow(a, src)) - fmap[pf] = tst(cnt == 0, fmap(pf), parity8(x[0:8])) - fmap[zf] = tst(cnt == 0, fmap(zf), x == 0) - fmap[sf] = tst(cnt == 0, fmap(sf), x < 0) - fmap[cf] = tst(cnt == 0, fmap(cf), carry) - fmap[of] = tst(cnt == 0, fmap(of), overflow) - fmap[eip] = tst(cnt == 0, fmap[eip] + i.length, fmap[eip]) - fmap[counter] = tst(cnt == 0, cnt, cnt - 1) + cond = (cnt==0)|(fmap(zf)==zv) + if cond==bit1: + fmap[eip] = fmap[eip] + i.length + return + elif cond==bit0: + fmap[counter] = cnt - 1 + else: + fmap[counter] = cst(0,counter.size) + fmap[dst_r] = top(dst_r.size) + return else: - fmap[af] = halfborrow(a, src) - fmap[pf] = parity8(x[0:8]) - fmap[zf] = x == 0 - fmap[sf] = x < 0 - fmap[cf] = carry - fmap[of] = overflow fmap[eip] = fmap[eip] + i.length - fmap[edi] = tst(fmap(df), fmap(edi) - l, fmap(edi) + l) + fmap[af] = halfborrow(a, src) + fmap[pf] = parity8(x[0:8]) + fmap[zf] = x == 0 + fmap[sf] = x < 0 + fmap[cf] = carry + fmap[of] = overflow + fmap[dst_r] = tst(fmap(df), fmap(dst_r) - l, fmap(dst_r) + l) def i_SCASB(i, fmap): @@ -405,19 +462,26 @@ def i_SCASD(i, fmap): # ------------------------------------------------------------------------------ + def _lods_(i, fmap, l): - counter = cx if i.misc["adrsz"] else ecx - loc = {1: al, 2: ax, 4: eax}[l] - src = fmap(mem(esi, l * 8)) + adrsz = i.misc["adrsz"] or internals['mode'] + counter = ecx if adrsz==32 else cx + src_r = esi if adrsz==32 else si + dst = {1: al, 2: ax, 4: eax}[l] + src_seg = i.misc["segreg"] + if src_seg is None: + src_seg = ds + src = ptr(esi, seg=src_seg) + direction = fmap(df) + cnt = 1 if i.misc["rep"]: cnt = fmap(counter) - fmap[loc] = tst(cnt == 0, fmap(loc), src) - fmap[eip] = tst(cnt == 0, fmap[eip] + i.length, fmap[eip]) - fmap[counter] = tst(cnt == 0, cnt, cnt - 1) - else: - fmap[loc] = src - fmap[eip] = fmap[eip] + i.length - fmap[esi] = tst(fmap(df), fmap(esi) - l, fmap(esi) + l) + fmap[counter] = cst(0,counter.size) + data = fmap(blob_ptr(dt=l,a=src).as_array(cnt,direction)) + fmap[dst] = data[-1] + off = cnt*l + fmap[src_r] = tst(direction, fmap(src_r) - off, fmap(src_r) + off) + fmap[eip] = fmap[eip] + i.length def i_LODSB(i, fmap): @@ -433,19 +497,25 @@ def i_LODSD(i, fmap): # ------------------------------------------------------------------------------ + def _stos_(i, fmap, l): - counter = cx if i.misc["adrsz"] else ecx + adrsz = i.misc["adrsz"] or internals['mode'] + counter = ecx if adrsz==32 else cx + dst_r = edi if adrsz==32 else di src = fmap({1: al, 2: ax, 4: eax}[l]) - loc = mem(edi, l * 8) + dst = fmap(ptr(edi,seg=es)) + direction = fmap(df) + cnt = 1 + fmap[eip] = fmap[eip] + i.length if i.misc["rep"]: cnt = fmap(counter) - fmap[loc] = tst(cnt == 0, fmap(loc), src) - fmap[eip] = tst(cnt == 0, fmap[eip] + i.length, fmap[eip]) - fmap[counter] = tst(cnt == 0, cnt, cnt - 1) - else: - fmap[loc] = src - fmap[eip] = fmap[eip] + i.length - fmap[edi] = tst(fmap(df), fmap(edi) - l, fmap(edi) + l) + if cnt==0: + return + fmap[counter] = cst(0,counter.size) + src = blob_comp(dt=l,el=src).as_array(cnt,direction) + fmap[dst] = src + off = cnt*l + fmap[dst_r] = tst(direction, fmap(dst_r) - off, fmap(dst_r) + off) def i_STOSB(i, fmap): @@ -461,20 +531,32 @@ def i_STOSD(i, fmap): # ------------------------------------------------------------------------------ -def _movs_(i, fmap, l): - counter = cx if i.misc["adrsz"] else ecx - loc = mem(edi, l * 8) - src = fmap(mem(esi, l * 8)) - if i.misc["rep"]: + +def _movs_(i,fmap,l): + adrsz = i.misc["adrsz"] or internals['mode'] + counter = ecx if adrsz==32 else cx + dst_r = edi if adrsz==32 else di + src_r = esi if adrsz==32 else si + dst = fmap(ptr(dst_r, seg=es)) + src_seg = i.misc["segreg"] + if src_seg is None: + src_seg = ds + src = ptr(src_r, seg=src_seg) + direction = fmap(df) + cnt = 1 + fmap[eip] = fmap[eip] + i.length + if i.misc['rep']: cnt = fmap(counter) - fmap[loc] = tst(cnt == 0, fmap(loc), src) - fmap[eip] = tst(cnt == 0, fmap[eip] + i.length, fmap[eip]) - fmap[counter] = tst(cnt == 0, cnt, cnt - 1) - else: - fmap[loc] = src - fmap[eip] = fmap[eip] + i.length - fmap[esi] = tst(fmap(df), fmap(esi) - l, fmap(esi) + l) - fmap[edi] = tst(fmap(df), fmap(edi) - l, fmap(edi) + l) + if cnt==0: + return + fmap[counter] = cst(0,counter.size) + src = blob_ptr(dt=l,a=src) + fmap[dst] = fmap(src.as_array(N=cnt,d=direction)) + off = cnt*l + src_v = fmap(src_r) + dst_v = fmap(dst_r) + fmap[src_r] = tst(direction, src_v - off, src_v + off) + fmap[dst_r] = tst(direction, dst_v - off, dst_v + off) def i_MOVSB(i, fmap): @@ -497,21 +579,22 @@ def i_IN(i, fmap): fmap[eip] = fmap[eip] + i.length op1 = i.operands[0] op2 = fmap(i.operands[1]) - fmap[op1] = ext("IN", size=op1.size).call(fmap, port=op2) + data = hw.IO.get_port(op2).In(env=fmap,dl=op1.length) + fmap[op1] = data def i_OUT(i, fmap): fmap[eip] = fmap[eip] + i.length op1 = fmap(i.operands[0]) op2 = fmap(i.operands[1]) - ext("OUT").call(fmap, port=op1, src=op2) + hw.IO.get_port(op1).Out(env=fmap,src=op2) # op1_src retreives fmap[op1] (op1 value): def i_PUSH(i, fmap): fmap[eip] = fmap[eip] + i.length op1 = fmap(i.operands[0]) - opdsz = 16 if i.misc["opdsz"] else 32 + opdsz = i.misc["opdsz"] or internals["mode"] if op1.size == 8: op1 = op1.signextend(opdsz) # push imm8 elif op1.size == 16: @@ -523,21 +606,30 @@ def i_PUSH(i, fmap): def i_POP(i, fmap): fmap[eip] = fmap[eip] + i.length op1 = i.operands[0] - pop(fmap, op1) + opdsz = i.misc["opdsz"] or internals["mode"] + pop(fmap, op1, sz=opdsz) def i_CALL(i, fmap): - pc = fmap[eip] + i.length - fmap[eip] = pc + opdsz = i.misc["opdsz"] or internals["mode"] + _ip = eip if opdsz==32 else ip + pc = fmap(_ip) + i.length + fmap[_ip] = pc push(fmap, pc) op1 = fmap(i.operands[0]) op1 = op1.signextend(pc.size) target = pc + op1 if not i.misc["absolute"] else op1 - fmap[eip] = target + fmap[_ip] = target def i_CALLF(i, fmap): - logger.verbose("%s semantic is not defined" % i.mnemonic) + opdsz = i.misc["opdsz"] or internals["mode"] + _ip = eip if opdsz==32 else ip + pc = fmap(_ip) + i.length + fmap[_ip] = pc + push(fmap, fmap(cs).zeroextend(opdsz)) + push(fmap, pc) + do_far_jump(i,fmap,reason="CALLF") def i_JMP(i, fmap): @@ -546,15 +638,239 @@ def i_JMP(i, fmap): op1 = fmap(i.operands[0]) op1 = op1.signextend(pc.size) target = pc + op1 if not i.misc["absolute"] else op1 + if internals["mode"]==16 and not i.misc["opdsz"]: + target = target&0xffff fmap[eip] = target def i_JMPF(i, fmap): - logger.verbose("%s semantic is not defined" % i.mnemonic) + pc = fmap[eip] + i.length + fmap[eip] = pc + do_far_jump(i,fmap) +def do_far_jump(i, fmap, reason="JMPF"): + op1 = i.operands[0] + if internals['mode']==16: + if op1._is_ptr: + selector = op1.seg + offset = op1.base + elif op1._is_mem: + desc = fmap(op1) + sz = 32 if i.misc["opdsz"] else 16 + offset = desc[0:sz] + selector = desc[sz:desc.size] + else: + sz = 16 if i.misc["opdsz"] else 32 + if op1._is_ptr: + selector = op1.seg + offset = op1.base + elif op1._is_mem: + fa = fmap(op1) + selector = fa[sz:fa.size] + offset = fa[0:sz] + if fmap(PE)==bit0: + # still in (un)real mode: + fmap[cs] = selector + fmap[eip] = offset.zeroextend(32) + return + # read cs descriptor from GDT or LDT + _e = read_descriptor(fmap,selector) + if _e is None: + logger.error(reason) + fmap[eip] = top(32) + return + # and update mode, hidden parts (MSRs) and eip: + if _e.s == DESC_SEGMENT: + fmap[cs] = selector + load_segment(fmap,cs,_e) + target = offset.zeroextend(32) + fmap[eip] = target + return + else: + if _e.type==GATE_TASK: + tss_sel = cst(_e.base0,16) + _e = read_descriptor(fmap,tss_sel) + selector = tss_sel + if _e.type==DESC_TSS32_OK and fmap(PE)==bit1: + switch_tss32(fmap,_e, selector, reason) + return + if _e.type==GATE_CALL32: + _g = gate_call_t(_e.pack()) + fmap[cs] = cst(_g.selector,16) + _e = read_descriptor(fmap,fmap(cs)) + if _e.type==DESC_SEGMENT: + load_segment(fmap,cs,_e) + fmap[eip] = _g.offset() + return + logger.warning("%s to unsupported descriptor",reason) + +def read_descriptor(fmap,selector): + if isinstance(selector,int): + selector = cst(selector,16) + _ti = selector[2:3] + offset = selector[3:16].zeroextend(32)*8 + if _ti==bit0: + Tmx = GDTR[0:16] + Tbl = GDTR[16:48] + elif _ti==bit1: + Tmx = seglimit(LDTR) + Tbl = segbase(LDTR) + adr = Tbl+offset + desc = fmap(mem(adr,64)) + if desc._is_cst: + _e = gdt_entry_t(desc.to_bytes()) + return _e + logger.verbose("impossible to access descriptor "%desc) + return None + +def write_descriptor(fmap,selector,new_desc): + if isinstance(selector,int): + selector = cst(selector,16) + if isinstance(new_desc,bytes): + new_desc = gdt_entry_t(new_desc) + _ti = selector[2:3] + offset = selector[3:16].zeroextend(32)*8 + if _ti==bit0: + Tmx = GDTR[0:16] + Tbl = GDTR[16:48] + elif _ti==bit1: + Tmx = seglimit(LDTR) + Tbl = segbase(LDTR) + adr = fmap(Tbl)+offset + fmap._Mem_write(ptr(adr),new_desc.pack()) + +def load_segment(fmap,seg,desc): + rpl = fmap(seg)[0:2] + if desc is not None: + dpl = desc.dpl + if rpl._is_cst and dpl<=(rpl.v): + fmap[segbase(seg)] = cst(desc.base(),32) + if seg==cs: + internals['mode'] = 32 if desc.d else 16 + internals['ring'] = dpl + else: + logger.error("load_segment privilege error") + fmap[segbase(seg)] = top(32) + else: + logger.warning("load_segment into %s: invalid descriptor"%seg) + +def switch_tss32(fmap,e,selector,reason): + # qemu reads the new tss before saving the current one... + # (see tcg/seg_helper.c:switch_tss_ra). + # not sure why its done this way, may be saving the current + # could erase the new one ?? anyway lets do it the same way. + new_tss = read_tss32(fmap,e) + save_tss32(fmap,reason) + if reason in ('JMPF', 'CALLF'): + # set BUSY flag in descriptor: + e._v.type |= 2 + write_descriptor(fmap,selector,e) + if reason == 'CALLF': + # new task is "nested" so it needs to remember link to current: + adr = cst(e.base(),32) + fmap[mem(adr,32,disp=new_tss.offset_of("link"))] = fmap(TR) + # now change state to new TR & TSS: + fmap[TR] = selector + load_segment(fmap,TR,e) + load_tss32(fmap,new_tss,reason) + +def read_tss32(fmap,e): + adr = cst(e.base(),32) + sz = tss32_entry_t.size() + if sz>e.limit()+1: + logger.error("tss segment too short @ %s"%adr) + tss_ = fmap(mem(adr,sz*8)) + if tss_._is_cst: + return tss32_entry_t(tss_.to_bytes()) + return tss_ + +def save_tss32(fmap,reason): + old_tss = tss32_entry_t() + cur_tr = read_descriptor(fmap,fmap(TR)) + if reason in ('JMPF', 'IRET'): + # clear BUSY flag for current tss descriptor: + cur_tr._v.type &= ~2 + write_descriptor(fmap,fmap(TR),cur_tr) + old_eflags = fmap(eflags) + if reason == 'IRET': + # clear nested flag since the interrupt task is now terminated + NT_MASK = 0x00004000 + old_eflags &= (~NT_MASK) + fmap[mem(segbase(TR),32,disp=old_tss.offset_of("EIP"))] = fmap(eip) + fmap[mem(segbase(TR),32,disp=old_tss.offset_of("EFLAGS"))] = old_eflags + fmap[mem(segbase(TR),32,disp=old_tss.offset_of("EAX"))] = fmap(eax) + fmap[mem(segbase(TR),32,disp=old_tss.offset_of("ECX"))] = fmap(ecx) + fmap[mem(segbase(TR),32,disp=old_tss.offset_of("EDX"))] = fmap(edx) + fmap[mem(segbase(TR),32,disp=old_tss.offset_of("EBX"))] = fmap(ebx) + fmap[mem(segbase(TR),32,disp=old_tss.offset_of("ESP"))] = fmap(esp) + fmap[mem(segbase(TR),32,disp=old_tss.offset_of("EBP"))] = fmap(ebp) + fmap[mem(segbase(TR),32,disp=old_tss.offset_of("ESI"))] = fmap(esi) + fmap[mem(segbase(TR),32,disp=old_tss.offset_of("EDI"))] = fmap(edi) + fmap[mem(segbase(TR),16,disp=old_tss.offset_of("ES"))] = fmap(es) + fmap[mem(segbase(TR),16,disp=old_tss.offset_of("CS"))] = fmap(cs) + fmap[mem(segbase(TR),16,disp=old_tss.offset_of("SS"))] = fmap(ss) + fmap[mem(segbase(TR),16,disp=old_tss.offset_of("DS"))] = fmap(ds) + fmap[mem(segbase(TR),16,disp=old_tss.offset_of("FS"))] = fmap(fs) + fmap[mem(segbase(TR),16,disp=old_tss.offset_of("GS"))] = fmap(gs) + #if reason == 'CALLF': + # fmap[mem(segbase(TR),16,disp=old_tss.offset_of("link"))] = fmap(TR) + +def load_tss32(fmap,tss_,reason): + fmap[TS] = bit1 + try: + if isinstance(tss_,tss32_entry_t): + fmap[cr3] = cst(tss_.CR3,32) + fmap[eip] = cst(tss_.EIP,32) + fmap[eax] = cst(tss_.EAX,32) + fmap[ecx] = cst(tss_.ECX,32) + fmap[edx] = cst(tss_.EDX,32) + fmap[ebx] = cst(tss_.EBX,32) + fmap[esp] = cst(tss_.ESP,32) + fmap[ebp] = cst(tss_.EBP,32) + fmap[esi] = cst(tss_.ESI,32) + fmap[edi] = cst(tss_.EDI,32) + # update segment regs: + fmap[es] = cst(tss_.ES,16) + fmap[cs] = cst(tss_.CS,16) + fmap[ss] = cst(tss_.SS,16) + fmap[ds] = cst(tss_.DS,16) + fmap[fs] = cst(tss_.FS,16) + fmap[gs] = cst(tss_.GS,16) + fmap[eflags] = cst(tss_.EFLAGS,32) + if reason == 'CALLF': + fmap[Nt] = bit1 + # update LDTR: + if (ldt_s:=tss_.LDTR&(~7)): + fmap[LDTR] = cst(tss_.LDTR,16) + # read LDT descriptor in the GDT and update hidden parts: + e = read_descriptor(fmap,ldt_s) + if e is not None and e.type==DESC_LDT: + fmap[seglimit(LDTR)] = cst(e.limit(),16) + fmap[segbase(LDTR)] = cst(e.base(),32) + for seg in (es,cs,ss,ds,fs,gs): + desc = read_descriptor(fmap,fmap(seg)) + load_segment(fmap,seg,desc) + elif isinstance(tss_,mem): + logger.verbose("can't find TSS segment") + raise NotImplemented + except: + fmap[eip] = top(32) + logger.verbose("error in TSS switch:\n") + logger.verbose("%s"%tss_) def i_RETF(i, fmap): - logger.verbose("%s semantic is not defined" % i.mnemonic) + opdsz = i.misc["opdsz"] or internals['mode'] + _ip = eip if opdsz==32 else ip + if len(i.operands)>0: + src = i.operands[0].v + pop(fmap, _ip) + pop(fmap, cs, sz=opdsz) + fmap[esp] = fmap(esp) + src + else: + pop(fmap, _ip) + pop(fmap, cs, sz=opdsz) + desc = read_descriptor(fmap,fmap(cs)) + load_segment(fmap,cs,desc) # ------------------------------------------------------------------------------ @@ -594,9 +910,14 @@ def i_LSL(i, fmap): def i_LTR(i, fmap): - logger.verbose("%s semantic is not defined" % i.mnemonic) fmap[eip] = fmap[eip] + i.length - + selector = fmap(i.operands[0]) + fmap[TR] = selector + _e = read_descriptor(fmap,selector) + load_segment(fmap,TR,_e) + if _e is None: + logger.verbose("error in task register descriptor") + # now load the information associated to this selector in the GDT ####################### @@ -629,17 +950,87 @@ def i_JCXZ(i, fmap): fmap[eip] = target -def i_RETN(i, fmap): - src = i.operands[0].v - pop(fmap, eip) - fmap[esp] = fmap(esp) + src - - def i_INT(i, fmap): fmap[eip] = fmap[eip] + i.length - op1 = fmap(i.operands[0]) - push(fmap, fmap[eip]) - fmap[eip] = ext("INT", port=op1, size=32) + op1 = i.operands[0] + do_interrupt_call(i,fmap,op1) + +def do_interrupt_call(i,fmap,op1): + if isinstance(op1,int): + op1 = cst(op1,8) + op1.sf=False + vector = op1.v + Tmx = fmap(IDTR[0:16]) + Tbl = fmap(IDTR[16:48]) + if internals['mode']==16: + offset = vector<<2 + adr = Tbl+offset + push(fmap,fmap(eflags[0:16])) + fmap[If] = bit0 + fmap[tf] = bit0 + push(fmap,fmap(cs)) + push(fmap,fmap(ip)) + desc = fmap(mem(adr,32)) + fmap[cs] = desc[16:32] + fmap[eip] = desc[0:16].zeroextend(32) + return + # 32-bit protected-mode: + offset = vector<<3 + adr = Tbl+offset + desc = fmap(mem(adr,64)) + if desc._is_cst: + _e = idt_entry_t(desc.to_bytes()) + else: + logger.error("INT %d"%vector) + fmap[eip] = top(32) + return + if _e.type == GATE_TASK: + tss_sel = cst(_e.selector,16) + # read TSS in GDT: + _e = read_descriptor(fmap,tss_sel) + if _e.type==DESC_TSS32_OK and fmap(PE)==bit1: + #switch task with nesting (aka like a far call): + #(nesting means that the TSS.link is updated with previous TR) + switch_tss32(fmap,_e,tss_sel,'CALLF') + return + logger.error("interrupt task gate error (not a TSS?)") + elif _e.type in (GATE_INTERRUPT32, GATE_TRAP32): + #trap or interrupt 32-bit gates: + if _e.type == GATE_INTERRUPT32: + fmap[If] = bit0 + fmap[tf] = bit0 + fmap[Nt] = bit0 + selector = cst(_e.selector,16) + desc = read_descriptor(fmap,selector) + if desc is not None and desc.s == DESC_SEGMENT: + if desc.dpl < internals['ring']: + # inter-privilege-level-interrupt: + logger.warning("inter-privilege-level-interrupt is not implemented yet...") + else: + # intra-privilege-level-interrupt: + push(fmap,fmap(eflags)) + push(fmap,fmap(cs).zeroextend(32)) + push(fmap,fmap(eip)) + fmap[cs] = selector + load_segment(fmap,cs,desc) + fmap[eip] = desc.offset() + return + logger.error("INT %d runtime error",vector) + +def i_IRET(i, fmap): + if internals['mode']==16 or not (fmap(Nt)==bit1): + i_RETF(i, fmap) + pop(fmap,eip) + pop(fmap,cs,sz=32) + pop(fmap,eflags) + + +def i_IRETD(i, fmap): + if internals['mode']==16 or not (fmap(Nt)==bit1): + i_RETF(i, fmap) + pop(fmap,eip) + pop(fmap,cs,sz=32) + pop(fmap,eflags) def i_INC(i, fmap): @@ -704,6 +1095,9 @@ def i_MOV(i, fmap): op2 = fmap(i.operands[1]) fmap[eip] = fmap[eip] + i.length fmap[op1] = op2 + if fmap(PE)==bit1 and (op1 in (cs,ds,es,ss,fs,gs)): + desc = read_descriptor(fmap,fmap(op1)) + load_segment(fmap,op1,desc) def i_MOVBE(i, fmap): @@ -890,7 +1284,9 @@ def i_LEA(i, fmap): fmap[eip] = fmap[eip] + i.length op1 = i.operands[0] op2 = i.operands[1] - adr = op2.addr(fmap) + # "effective" address is agnostic of segmentation/pagination + # so we don't want to compute op2.addr(fmap) + adr = fmap(op2.a.base+op2.a.disp) if op1.size > adr.size: adr = adr.zeroextend(op1.size) elif op1.size < adr.size: @@ -1164,6 +1560,18 @@ def i_DIV(i, fmap): fmap[d] = r_[0 : d.size] fmap[m] = q_[0 : m.size] +def i_IDIV(i, fmap): + fmap[eip] = fmap[eip] + i.length + src = i.operands[0] + m, d = {8: (al, ah), 16: (ax, dx), 32: (eax, edx)}[src.size] + md_ = composer([m, d]) + md_.sf = True + s_ = src.signextend(md_.size) + q_ = fmap(md_ / s_) + r_ = fmap(md_ % s_) + fmap[d] = r_[0 : d.size] + fmap[m] = q_[0 : m.size] + def i_RDRAND(i, fmap): fmap[eip] = fmap[eip] + i.length @@ -1183,17 +1591,17 @@ def i_MOVNTI(i, fmap): def i_CRC32(i, fmap): logger.verbose("%s semantic is not defined" % i.mnemonic) fmap[eip] = fmap[eip] + i.length + dst = i.operands[0] + fmap[dst] = top(dst.size) def i_RDTSC(i, fmap): - logger.verbose("%s semantic is not defined" % i.mnemonic) fmap[eip] = fmap[eip] + i.length fmap[edx] = top(32) fmap[eax] = top(32) def i_RDTSCP(i, fmap): - logger.verbose("%s semantic is not defined" % i.mnemonic) fmap[eip] = fmap[eip] + i.length fmap[edx] = top(32) fmap[eax] = top(32) @@ -1201,15 +1609,37 @@ def i_RDTSCP(i, fmap): def i_CLTS(i, fmap): - logger.verbose("%s semantic is not defined" % i.mnemonic) fmap[eip] = fmap[eip] + i.length - # #UD #BR exceptions not implemented + fmap[TS] = bit0 def i_CPUID(i, fmap): - logger.verbose("%s semantic is not defined" % i.mnemonic) fmap[eip] = fmap[eip] + i.length - # #UD #BR exceptions not implemented + #EAX 0 returns maximum input eax value and vendor id: + v = fmap(eax) + if v._is_cst: + if v==0: + fmap[eax] = cst(0x02,32) + fmap[ebx] = cst(struct.unpack('