about summary refs log tree commit diff stats
path: root/src/miasm/jitter/emulatedsymbexec.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/miasm/jitter/emulatedsymbexec.py')
-rw-r--r--src/miasm/jitter/emulatedsymbexec.py170
1 files changed, 170 insertions, 0 deletions
diff --git a/src/miasm/jitter/emulatedsymbexec.py b/src/miasm/jitter/emulatedsymbexec.py
new file mode 100644
index 00000000..1c3100ae
--- /dev/null
+++ b/src/miasm/jitter/emulatedsymbexec.py
@@ -0,0 +1,170 @@
+from miasm.core.utils import decode_hex, encode_hex
+import miasm.expression.expression as m2_expr
+from miasm.ir.symbexec import SymbolicExecutionEngine
+from miasm.arch.x86.arch import is_op_segm
+
+
+class EmulatedSymbExec(SymbolicExecutionEngine):
+    """Symbolic exec instance linked with a jitter"""
+
+    x86_cpuid = {
+        0: {
+            0: 0xa,
+            1: 0x756E6547,
+            2: 0x6C65746E,
+            3: 0x49656E69,
+        },
+        1: {
+            0: 0x00020652,
+            1: 0x00000800,
+            2: 0x00000209,
+            3: 0x078bf9ff
+        },
+        2: {
+            0: 0,
+            1: 0,
+            2: 0,
+            3: 0
+        },
+        4: {
+            0: 0,
+            1: 0,
+            2: 0,
+            3: 0
+        },
+        7: {
+            0: 0,
+            1: (1 << 0) | (1 << 3),
+            2: 0,
+            3: 0
+        },
+        0x80000000: {
+            0: 0x80000008,
+            1: 0,
+            2: 0,
+            3: 0
+        },
+        0x80000001: {
+            0: 0,
+            1: 0,
+            2: (1 << 0) | (1 << 8),
+            3: (1 << 11) | (1 << 29),
+        },
+    }
+
+    def __init__(self, cpu, vm, *args, **kwargs):
+        """Instantiate an EmulatedSymbExec, associated to CPU @cpu and bind
+        memory accesses.
+        @cpu: JitCpu instance
+        """
+        super(EmulatedSymbExec, self).__init__(*args, **kwargs)
+        self.cpu = cpu
+        self.vm = vm
+
+    def reset_regs(self):
+        """Set registers value to 0. Ignore register aliases"""
+        for reg in self.lifter.arch.regs.all_regs_ids_no_alias:
+            self.symbols.symbols_id[reg] = m2_expr.ExprInt(0, size=reg.size)
+
+    # Memory management
+    def mem_read(self, expr_mem):
+        """Memory read wrapper for symbolic execution
+        @expr_mem: ExprMem"""
+
+        addr = expr_mem.ptr
+        if not addr.is_int():
+            return super(EmulatedSymbExec, self).mem_read(expr_mem)
+        addr = int(addr)
+        size = expr_mem.size // 8
+        value = self.vm.get_mem(addr, size)
+        if self.vm.is_little_endian():
+            value = value[::-1]
+        self.vm.add_mem_read(addr, size)
+
+        return m2_expr.ExprInt(
+            int(encode_hex(value), 16),
+            expr_mem.size
+        )
+
+    def mem_write(self, dest, data):
+        """Memory read wrapper for symbolic execution
+        @dest: ExprMem instance
+        @data: Expr instance"""
+
+        # Get the content to write
+        data = self.expr_simp(data)
+        if not isinstance(data, m2_expr.ExprInt):
+            raise RuntimeError("A simplification is missing: %s" % data)
+        to_write = int(data)
+
+        # Format information
+        addr = int(dest.ptr)
+        size = data.size // 8
+        content = hex(to_write).replace("0x", "").replace("L", "")
+        content = "0" * (size * 2 - len(content)) + content
+        content = decode_hex(content)
+
+        if self.vm.is_little_endian():
+            content = content[::-1]
+
+        # Write in VmMngr context
+        self.vm.set_mem(addr, content)
+
+    # Interaction symbexec <-> jitter
+    def update_cpu_from_engine(self):
+        """Updates @cpu instance according to new CPU values"""
+
+        for symbol in self.symbols:
+            if isinstance(symbol, m2_expr.ExprId):
+                if hasattr(self.cpu, symbol.name):
+                    value = self.symbols.symbols_id[symbol]
+                    if not isinstance(value, m2_expr.ExprInt):
+                        raise ValueError("A simplification is missing: %s" % value)
+
+                    setattr(self.cpu, symbol.name, int(value))
+            else:
+                raise NotImplementedError("Type not handled: %s" % symbol)
+
+
+    def update_engine_from_cpu(self):
+        """Updates CPU values according to @cpu instance"""
+
+        for symbol in self.symbols:
+            if isinstance(symbol, m2_expr.ExprId):
+                if hasattr(self.cpu, symbol.name):
+                    value = m2_expr.ExprInt(getattr(self.cpu, symbol.name),
+                                            symbol.size)
+                    self.symbols.symbols_id[symbol] = value
+            else:
+                raise NotImplementedError("Type not handled: %s" % symbol)
+
+    # CPU specific simplifications
+    def _simp_handle_segm(self, e_s, expr):
+        """Handle 'segm' operation"""
+        if not is_op_segm(expr):
+            return expr
+        if not expr.args[0].is_int():
+            return expr
+        segm_nb = int(expr.args[0])
+        segmaddr = self.cpu.get_segm_base(segm_nb)
+        return e_s(m2_expr.ExprInt(segmaddr, expr.size) + expr.args[1])
+
+    def _simp_handle_x86_cpuid(self, e_s, expr):
+        """From miasm/jitter/op_semantics.h: x86_cpuid"""
+        if expr.op != "x86_cpuid":
+            return expr
+
+        if any(not arg.is_int() for arg in expr.args):
+            return expr
+        a, reg_num = (int(arg) for arg in expr.args)
+
+        # Not found error is keeped on purpose
+        return m2_expr.ExprInt(self.x86_cpuid[a][reg_num], expr.size)
+
+    def enable_emulated_simplifications(self):
+        """Enable simplifications needing a CPU instance on associated
+        ExpressionSimplifier
+        """
+        self.expr_simp.enable_passes({
+            m2_expr.ExprOp: [self._simp_handle_segm, self._simp_handle_x86_cpuid],
+        })