about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorCamille Mougey <commial@gmail.com>2016-09-01 11:09:21 +0200
committerGitHub <noreply@github.com>2016-09-01 11:09:21 +0200
commit9f135c02e9bce299a700fa0191388542d141ea22 (patch)
treed8ad86407e24ae9435ca4ca344ae7ec61e8568d2
parentfb7501f4bb0bc77a0262ad4894732e4de6ccb2b2 (diff)
parent2858e916f35f0469baeea23632ddd8befdd7ca5d (diff)
downloadmiasm-9f135c02e9bce299a700fa0191388542d141ea22.tar.gz
miasm-9f135c02e9bce299a700fa0191388542d141ea22.zip
Merge pull request #411 from serpilliere/fix_memory_breakpoint
Fix memory breakpoint
-rw-r--r--example/jitter/test_x86_32_seh.py56
-rw-r--r--example/samples/x86_32_seh.S76
-rw-r--r--miasm2/jitter/JitCore.c12
-rw-r--r--miasm2/jitter/JitCore.h5
-rw-r--r--miasm2/jitter/arch/JitCore_aarch64.c2
-rw-r--r--miasm2/jitter/arch/JitCore_arm.c2
-rw-r--r--miasm2/jitter/arch/JitCore_mips32.c2
-rw-r--r--miasm2/jitter/arch/JitCore_msp430.c2
-rw-r--r--miasm2/jitter/arch/JitCore_x86.c10
-rw-r--r--miasm2/jitter/codegen.py4
-rw-r--r--miasm2/jitter/emulatedsymbexec.py5
-rw-r--r--miasm2/jitter/jitcore.py21
-rw-r--r--miasm2/jitter/jitcore_python.py21
-rw-r--r--miasm2/jitter/jitload.py7
-rw-r--r--miasm2/jitter/vm_mngr.c220
-rw-r--r--miasm2/jitter/vm_mngr.h29
-rw-r--r--miasm2/jitter/vm_mngr_py.c94
-rw-r--r--test/test_all.py18
18 files changed, 450 insertions, 136 deletions
diff --git a/example/jitter/test_x86_32_seh.py b/example/jitter/test_x86_32_seh.py
new file mode 100644
index 00000000..5277807d
--- /dev/null
+++ b/example/jitter/test_x86_32_seh.py
@@ -0,0 +1,56 @@
+import os
+from pdb import pm
+from miasm2.analysis.sandbox import Sandbox_Win_x86_32
+from miasm2.os_dep import win_api_x86_32_seh
+from miasm2.jitter.csts import *
+
+def deal_exception_access_violation(jitter):
+    jitter.pc = win_api_x86_32_seh.fake_seh_handler(jitter, win_api_x86_32_seh.EXCEPTION_ACCESS_VIOLATION)
+    return True
+
+def deal_exception_breakpoint(jitter):
+    jitter.pc = win_api_x86_32_seh.fake_seh_handler(jitter, win_api_x86_32_seh.EXCEPTION_BREAKPOINT)
+    return True
+
+def deal_exception_div(jitter):
+    jitter.pc = win_api_x86_32_seh.fake_seh_handler(jitter, win_api_x86_32_seh.EXCEPTION_INT_DIVIDE_BY_ZERO)
+    return True
+
+def deal_exception_privileged_instruction(jitter):
+    jitter.pc = win_api_x86_32_seh.fake_seh_handler(jitter, win_api_x86_32_seh.EXCEPTION_PRIV_INSTRUCTION)
+    return True
+
+def deal_exception_illegal_instruction(jitter):
+    jitter.pc = win_api_x86_32_seh.fake_seh_handler(jitter, win_api_x86_32_seh.EXCEPTION_ILLEGAL_INSTRUCTION)
+    return True
+
+
+def return_from_seh(jitter):
+    win_api_x86_32_seh.return_from_seh(jitter)
+    return True
+
+# Insert here user defined methods
+
+# Parse arguments
+parser = Sandbox_Win_x86_32.parser(description="PE sandboxer")
+parser.add_argument("filename", help="PE Filename")
+options = parser.parse_args()
+options.usesegm = True
+options.use_seh = True
+
+# Create sandbox
+sb = Sandbox_Win_x86_32(options.filename, options, globals())
+
+# Install Windows SEH callbacks
+sb.jitter.add_exception_handler(EXCEPT_ACCESS_VIOL, deal_exception_access_violation)
+sb.jitter.add_exception_handler(EXCEPT_SOFT_BP, deal_exception_breakpoint)
+sb.jitter.add_exception_handler(EXCEPT_DIV_BY_ZERO, deal_exception_div)
+sb.jitter.add_exception_handler(1<<17, deal_exception_privileged_instruction)
+sb.jitter.add_exception_handler(EXCEPT_UNK_MNEMO, deal_exception_illegal_instruction)
+
+sb.jitter.add_breakpoint(win_api_x86_32_seh.return_from_exception, return_from_seh)
+
+# Run
+sb.run()
+
+assert(sb.jitter.run is False)
diff --git a/example/samples/x86_32_seh.S b/example/samples/x86_32_seh.S
new file mode 100644
index 00000000..7bb2c3cd
--- /dev/null
+++ b/example/samples/x86_32_seh.S
@@ -0,0 +1,76 @@
+
+main:
+	PUSH       error
+	PUSH       DWORD PTR FS:[0x0]
+	MOV        DWORD PTR FS:[0x0], ESP
+	XOR        EAX, EAX
+
+;; Access violation
+lbl_err_0:
+	MOV        DWORD PTR [EAX], 0x0
+lbl_err_end0:
+	NOP
+
+
+;; Breakpoint
+lbl_err_1:
+	INT        0x3
+lbl_err_end1:
+	NOP
+
+;; Divide by 0
+	XOR        EAX, EAX
+lbl_err_2:
+	DIV        EAX
+lbl_err_end2:
+	NOP
+
+;; Privileged instruction
+lbl_err_3:
+	STI
+lbl_err_end3:
+	NOP
+
+;; Unknown instruction (Bad LEA encoding)
+lbl_err_4:
+	.byte 0x8D, 0xC0
+lbl_err_end4:
+	NOP
+
+	POP        DWORD PTR FS:[0x0]
+	ADD        ESP, 4
+	RET
+
+error:
+	MOV        ECX, DWORD PTR [ESP+0xC]
+	MOV        EAX, DWORD PTR [ECX+0xB8]
+	MOV        EBX, DWORD PTR [err_num]
+	CMP        EAX, DWORD PTR [labels_err + 4*EBX]
+	JZ         error_address_ok
+	INT        0x3
+error_address_ok:
+	INC        DWORD PTR [err_num]
+	MOV        EAX, DWORD PTR [labels_err_end + 4*EBX]
+	MOV        DWORD PTR [ECX+0xB8], EAX
+	XOR        EAX, EAX
+	RET
+
+
+
+err_num:
+.dword 0
+
+labels_err:
+.dword lbl_err_0
+.dword lbl_err_end1
+.dword lbl_err_2
+.dword lbl_err_3
+.dword lbl_err_4
+
+
+labels_err_end:
+.dword lbl_err_end0
+.dword lbl_err_end1
+.dword lbl_err_end2
+.dword lbl_err_end3
+.dword lbl_err_end4
diff --git a/miasm2/jitter/JitCore.c b/miasm2/jitter/JitCore.c
index a6d29a72..84f835f1 100644
--- a/miasm2/jitter/JitCore.c
+++ b/miasm2/jitter/JitCore.c
@@ -26,7 +26,7 @@ PyObject * JitCpu_get_vmmngr(JitCpu *self, void *closure)
 {
 	if (self->pyvm) {
 		Py_INCREF(self->pyvm);
-		return self->pyvm;
+		return (PyObject*)self->pyvm;
 	}
 	Py_INCREF(Py_None);
 	return Py_None;
@@ -34,7 +34,7 @@ PyObject * JitCpu_get_vmmngr(JitCpu *self, void *closure)
 
 PyObject * JitCpu_set_vmmngr(JitCpu *self, PyObject *value, void *closure)
 {
-	self->pyvm = value;
+	self->pyvm = (VmMngr*)value;
 	return 0;
 }
 
@@ -56,22 +56,22 @@ PyObject * JitCpu_set_jitter(JitCpu *self, PyObject *value, void *closure)
 
 uint8_t __attribute__((weak)) MEM_LOOKUP_08(JitCpu* jitcpu, uint64_t addr)
 {
-	return vm_MEM_LOOKUP_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr);
+	return vm_MEM_LOOKUP_08(&(jitcpu->pyvm->vm_mngr), addr);
 }
 
 uint16_t __attribute__((weak)) MEM_LOOKUP_16(JitCpu* jitcpu, uint64_t addr)
 {
-	return vm_MEM_LOOKUP_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr);
+	return vm_MEM_LOOKUP_16(&(jitcpu->pyvm->vm_mngr), addr);
 }
 
 uint32_t __attribute__((weak)) MEM_LOOKUP_32(JitCpu* jitcpu, uint64_t addr)
 {
-	return vm_MEM_LOOKUP_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr);
+	return vm_MEM_LOOKUP_32(&(jitcpu->pyvm->vm_mngr), addr);
 }
 
 uint64_t __attribute__((weak)) MEM_LOOKUP_64(JitCpu* jitcpu, uint64_t addr)
 {
-	return vm_MEM_LOOKUP_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr);
+	return vm_MEM_LOOKUP_64(&(jitcpu->pyvm->vm_mngr), addr);
 }
 
 void __attribute__((weak)) MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src)
diff --git a/miasm2/jitter/JitCore.h b/miasm2/jitter/JitCore.h
index 6add6f37..24feb9c0 100644
--- a/miasm2/jitter/JitCore.h
+++ b/miasm2/jitter/JitCore.h
@@ -92,7 +92,7 @@ typedef struct {
 
 typedef struct {
 	PyObject_HEAD
-	PyObject *pyvm;
+	VmMngr *pyvm;
 	PyObject *jitter;
 	void* cpu;
 } JitCpu;
@@ -129,8 +129,7 @@ PyObject* vm_get_mem(JitCpu *self, PyObject* args);
 
 
 
-
-#define VM_exception_flag (((VmMngr*)jitcpu->pyvm)->vm_mngr.exception_flags)
+#define VM_exception_flag (jitcpu->pyvm->vm_mngr.exception_flags)
 #define CPU_exception_flag (((vm_cpu_t*)jitcpu->cpu)->exception_flags)
 #define CPU_exception_flag_at_instr ((CPU_exception_flag) && ((CPU_exception_flag) > EXCEPT_NUM_UPDT_EIP))
 #define JIT_RET_EXCEPTION 1
diff --git a/miasm2/jitter/arch/JitCore_aarch64.c b/miasm2/jitter/arch/JitCore_aarch64.c
index 46b5b25c..15a3c27c 100644
--- a/miasm2/jitter/arch/JitCore_aarch64.c
+++ b/miasm2/jitter/arch/JitCore_aarch64.c
@@ -1,11 +1,11 @@
 #include <Python.h>
-#include "../JitCore.h"
 #include "structmember.h"
 #include <stdint.h>
 #include <inttypes.h>
 #include "../queue.h"
 #include "../vm_mngr.h"
 #include "../vm_mngr_py.h"
+#include "../JitCore.h"
 #include "JitCore_aarch64.h"
 
 
diff --git a/miasm2/jitter/arch/JitCore_arm.c b/miasm2/jitter/arch/JitCore_arm.c
index b3a93aca..90e72ea4 100644
--- a/miasm2/jitter/arch/JitCore_arm.c
+++ b/miasm2/jitter/arch/JitCore_arm.c
@@ -1,11 +1,11 @@
 #include <Python.h>
-#include "../JitCore.h"
 #include "structmember.h"
 #include <stdint.h>
 #include <inttypes.h>
 #include "../queue.h"
 #include "../vm_mngr.h"
 #include "../vm_mngr_py.h"
+#include "../JitCore.h"
 #include "JitCore_arm.h"
 
 
diff --git a/miasm2/jitter/arch/JitCore_mips32.c b/miasm2/jitter/arch/JitCore_mips32.c
index 86624b76..fc5589ff 100644
--- a/miasm2/jitter/arch/JitCore_mips32.c
+++ b/miasm2/jitter/arch/JitCore_mips32.c
@@ -1,11 +1,11 @@
 #include <Python.h>
-#include "../JitCore.h"
 #include "structmember.h"
 #include <stdint.h>
 #include <inttypes.h>
 #include "../queue.h"
 #include "../vm_mngr.h"
 #include "../vm_mngr_py.h"
+#include "../JitCore.h"
 #include "JitCore_mips32.h"
 
 
diff --git a/miasm2/jitter/arch/JitCore_msp430.c b/miasm2/jitter/arch/JitCore_msp430.c
index c6f6aa92..977b0777 100644
--- a/miasm2/jitter/arch/JitCore_msp430.c
+++ b/miasm2/jitter/arch/JitCore_msp430.c
@@ -1,11 +1,11 @@
 #include <Python.h>
-#include "../JitCore.h"
 #include "structmember.h"
 #include <stdint.h>
 #include <inttypes.h>
 #include "../queue.h"
 #include "../vm_mngr.h"
 #include "../vm_mngr_py.h"
+#include "../JitCore.h"
 #include "JitCore_msp430.h"
 
 
diff --git a/miasm2/jitter/arch/JitCore_x86.c b/miasm2/jitter/arch/JitCore_x86.c
index 6a503d83..0b788071 100644
--- a/miasm2/jitter/arch/JitCore_x86.c
+++ b/miasm2/jitter/arch/JitCore_x86.c
@@ -1,11 +1,11 @@
 #include <Python.h>
-#include "../JitCore.h"
 #include "structmember.h"
 #include <stdint.h>
 #include <inttypes.h>
 #include "../queue.h"
 #include "../vm_mngr.h"
 #include "../vm_mngr_py.h"
+#include "../JitCore.h"
 #include "JitCore_x86.h"
 
 
@@ -322,13 +322,6 @@ IMOD(16)
 IMOD(32)
 IMOD(64)
 
-void check_automod(JitCpu* jitcpu, uint64_t addr, uint64_t size)
-{
-	if (!(((VmMngr*)jitcpu->pyvm)->vm_mngr.exception_flags & EXCEPT_CODE_AUTOMOD))
-		return;
-	code_bloc_add_write(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, size/8);
-}
-
 void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src)
 {
 	vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
@@ -376,7 +369,6 @@ PyObject* vm_set_mem(JitCpu *self, PyObject* args)
        ret = vm_write_mem(&(((VmMngr*)self->pyvm)->vm_mngr), addr, buffer, size);
        if (ret < 0)
 	       RAISE(PyExc_TypeError,"arg must be str");
-       check_automod(self, addr, size*8);
 
        Py_INCREF(Py_None);
        return Py_None;
diff --git a/miasm2/jitter/codegen.py b/miasm2/jitter/codegen.py
index 068839e7..7630a2ef 100644
--- a/miasm2/jitter/codegen.py
+++ b/miasm2/jitter/codegen.py
@@ -89,6 +89,8 @@ class CGen(object):
     """
 
     CODE_VM_EXCEPTION_POST_INSTR = r"""
+    check_memory_breakpoint(&(jitcpu->pyvm->vm_mngr));
+    check_invalid_code_blocs(&(jitcpu->pyvm->vm_mngr));
     if (VM_exception_flag) {
         %s = %s;
         BlockDst->address = DST_value;
@@ -332,7 +334,7 @@ class CGen(object):
             out += (self.CODE_CPU_EXCEPTION_POST_INSTR % (self.C_PC, dst)).split('\n')
 
         if attrib.mem_read | attrib.mem_write:
-            out.append("reset_code_bloc_write(&((VmMngr*)jitcpu->pyvm)->vm_mngr);")
+            out.append("reset_memory_access(&(jitcpu->pyvm->vm_mngr));")
 
         return out
 
diff --git a/miasm2/jitter/emulatedsymbexec.py b/miasm2/jitter/emulatedsymbexec.py
index f7c48227..d72de771 100644
--- a/miasm2/jitter/emulatedsymbexec.py
+++ b/miasm2/jitter/emulatedsymbexec.py
@@ -5,13 +5,14 @@ from miasm2.ir.symbexec import symbexec
 class EmulatedSymbExec(symbexec):
     """Symbolic exec instance linked with a jitter"""
 
-    def __init__(self, cpu, *args, **kwargs):
+    def __init__(self, cpu, vm, *args, **kwargs):
         """Instanciate 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
         self.func_read = self._func_read
         self.func_write = self._func_write
 
@@ -28,6 +29,7 @@ class EmulatedSymbExec(symbexec):
         addr = expr_mem.arg.arg.arg
         size = expr_mem.size / 8
         value = self.cpu.get_mem(addr, size)
+        self.vm.add_mem_read(addr, size)
 
         return m2_expr.ExprInt(int(value[::-1].encode("hex"), 16),
                                expr_mem.size)
@@ -53,6 +55,7 @@ class EmulatedSymbExec(symbexec):
 
         # Write in VmMngr context
         self.cpu.set_mem(addr, content)
+        self.vm.add_mem_write(addr, len(content))
 
     # Interaction symbexec <-> jitter
     def update_cpu_from_engine(self):
diff --git a/miasm2/jitter/jitcore.py b/miasm2/jitter/jitcore.py
index e81acc4e..04bd707a 100644
--- a/miasm2/jitter/jitcore.py
+++ b/miasm2/jitter/jitcore.py
@@ -51,8 +51,6 @@ class JitCore(object):
         self.blocs_mem_interval = interval()
         self.disasm_cb = None
         self.split_dis = set()
-        self.addr_mod = interval()
-
         self.options = {"jit_maxline": 50  # Maximum number of line jitted
                         }
 
@@ -261,12 +259,21 @@ class JitCore(object):
 
         return modified_blocs
 
-    def updt_automod_code(self, vm):
-        """Remove code jitted in range self.addr_mod
+    def updt_automod_code_range(self, vm, mem_range):
+        """Remove jitted code in range @mem_range
         @vm: VmMngr instance
+        @mem_range: list of start/stop addresses
         """
-        for addr_start, addr_stop in vm.get_code_bloc_write():
+        for addr_start, addr_stop in mem_range:
             self.del_bloc_in_range(addr_start, addr_stop)
         self.__updt_jitcode_mem_range(vm)
-        self.addr_mod = interval()
-        vm.reset_code_bloc_write()
+        vm.reset_memory_access()
+
+    def updt_automod_code(self, vm):
+        """Remove jitted code updated by memory write
+        @vm: VmMngr instance
+        """
+        mem_range = []
+        for addr_start, addr_stop in vm.get_memory_write():
+            mem_range.append((addr_start, addr_stop))
+        self.updt_automod_code_range(vm, mem_range)
diff --git a/miasm2/jitter/jitcore_python.py b/miasm2/jitter/jitcore_python.py
index e1e62816..ae72b307 100644
--- a/miasm2/jitter/jitcore_python.py
+++ b/miasm2/jitter/jitcore_python.py
@@ -17,10 +17,14 @@ class JitCore_Python(jitcore.JitCore):
         super(JitCore_Python, self).__init__(ir_arch, bs)
         self.ir_arch = ir_arch
 
-        # CPU (None for now) will be set by the "jitted" Python function
-        self.symbexec = EmulatedSymbExec(None, self.ir_arch, {})
+        # CPU & VM (None for now) will be set by the "jitted" Python function
+        self.symbexec = EmulatedSymbExec(None, None, self.ir_arch, {})
         self.symbexec.enable_emulated_simplifications()
 
+    def set_cpu_vm(self, cpu, vm):
+        self.symbexec.cpu = cpu
+        self.symbexec.vm = vm
+
     def load(self):
         "Preload symbols according to current architecture"
         self.symbexec.reset_regs()
@@ -45,7 +49,6 @@ class JitCore_Python(jitcore.JitCore):
 
             # Get exec engine
             exec_engine = self.symbexec
-            exec_engine.cpu = cpu
 
             # For each irbloc inside irblocs
             while True:
@@ -66,12 +69,19 @@ class JitCore_Python(jitcore.JitCore):
 
                     # For each new instruction (in assembly)
                     if line.offset not in offsets_jitted:
+                        # Test exceptions
+                        vmmngr.check_invalid_code_blocs()
+                        vmmngr.check_memory_breakpoint()
+                        if vmmngr.get_exception():
+                            exec_engine.update_cpu_from_engine()
+                            return line.offset
+
                         offsets_jitted.add(line.offset)
 
                         # Log registers values
                         if self.log_regs:
                             exec_engine.update_cpu_from_engine()
-                            cpu.dump_gpregs()
+                            exec_engine.cpu.dump_gpregs()
 
                         # Log instruction
                         if self.log_mn:
@@ -90,6 +100,9 @@ class JitCore_Python(jitcore.JitCore):
                         exec_engine.update_cpu_from_engine()
                         return line.offset
 
+                vmmngr.check_invalid_code_blocs()
+                vmmngr.check_memory_breakpoint()
+
                 # Get next bloc address
                 ad = expr_simp(exec_engine.eval_expr(self.ir_arch.IRDst))
 
diff --git a/miasm2/jitter/jitload.py b/miasm2/jitter/jitload.py
index 8943e2c7..d8393230 100644
--- a/miasm2/jitter/jitload.py
+++ b/miasm2/jitter/jitload.py
@@ -198,7 +198,7 @@ class jitter:
         self.ir_arch = ir_arch
         self.bs = bin_stream_vm(self.vm)
 
-        self.symbexec = EmulatedSymbExec(self.cpu, self.ir_arch, {})
+        self.symbexec = EmulatedSymbExec(self.cpu, self.vm, self.ir_arch, {})
         self.symbexec.reset_regs()
 
         try:
@@ -218,6 +218,8 @@ class jitter:
         self.jit = JitCore(self.ir_arch, self.bs)
         if jit_type in ['tcc', 'gcc']:
             self.jit.init_codegen(self.C_Gen(self.ir_arch))
+        elif jit_type == "python":
+            self.jit.set_cpu_vm(self.cpu, self.vm)
 
         self.cpu.init_regs()
         self.vm.init_memory_page_pool()
@@ -265,8 +267,7 @@ class jitter:
         self.breakpoints_handler.add_callback(addr, callback)
         self.jit.add_disassembly_splits(addr)
         # De-jit previously jitted blocks
-        self.jit.addr_mod = interval([(addr, addr)])
-        self.jit.updt_automod_code(self.vm)
+        self.jit.updt_automod_code_range(self.vm, [(addr, addr)])
 
     def set_breakpoint(self, addr, *args):
         """Set callbacks associated with addr.
diff --git a/miasm2/jitter/vm_mngr.c b/miasm2/jitter/vm_mngr.c
index 2b0ae1fd..df8326d9 100644
--- a/miasm2/jitter/vm_mngr.c
+++ b/miasm2/jitter/vm_mngr.c
@@ -76,7 +76,38 @@ const uint8_t parity_table[256] = {
     0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
 };
 
-//#define DEBUG_MIASM_AUTOMOD_CODE
+// #define DEBUG_MIASM_AUTOMOD_CODE
+
+void memory_access_list_init(struct memory_access_list * access)
+{
+	access->array = NULL;
+	access->allocated = 0;
+	access->num = 0;
+}
+
+void memory_access_list_reset(struct memory_access_list * access)
+{
+	if (access->array) {
+		free(access->array);
+		access->array = NULL;
+	}
+	access->allocated = 0;
+	access->num = 0;
+}
+
+void memory_access_list_add(struct memory_access_list * access, uint64_t start, uint64_t stop)
+{
+	if (access->num >= access->allocated) {
+		if (access->allocated == 0)
+			access->allocated = 1;
+		else
+			access->allocated *= 2;
+		access->array = realloc(access->array, access->allocated * sizeof(struct memory_access));
+	}
+	access->array[access->num].start = start;
+	access->array[access->num].stop = stop;
+	access->num += 1;
+}
 
 
 
@@ -393,67 +424,56 @@ void dump_code_bloc(vm_mngr_t* vm_mngr)
 
 }
 
-void code_bloc_add_write(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t size)
+void add_range_to_list(struct memory_access_list * access, uint64_t addr1, uint64_t addr2)
 {
-	PyObject* range;
-	PyObject* element;
-	int list_size;
-	uint64_t addr_start, addr_stop;
-
-	list_size = PyList_Size(vm_mngr->code_bloc_memory_w);
-
-	if (list_size > 0) {
-		/* check match on upper bound */
-		 element = PyList_GetItem(vm_mngr->code_bloc_memory_w, list_size - 1);
-
-		 addr_start = (uint64_t)PyLong_AsUnsignedLongLong(PyTuple_GetItem(element, 0));
-		 addr_stop = (uint64_t)PyLong_AsUnsignedLongLong(PyTuple_GetItem(element, 1));
-
-		 if (addr_stop == addr) {
-			 range = PyTuple_New(2);
-			 PyTuple_SetItem(range, 0, PyLong_FromUnsignedLongLong((uint64_t)addr_start));
-			 PyTuple_SetItem(range, 1, PyLong_FromUnsignedLongLong((uint64_t)addr+size));
-			 PyList_SetItem(vm_mngr->code_bloc_memory_w, list_size - 1, range);
+	if (access->num > 0) {
+		/* Check match on upper bound */
+		 if (access->array[access->num-1].stop == addr1) {
+			 access->array[access->num-1].stop = addr2;
 			 return;
-
 		 }
 
-		/* check match on lower bound */
-		 element = PyList_GetItem(vm_mngr->code_bloc_memory_w, 0);
-		 addr_start = (uint64_t)PyLong_AsUnsignedLongLong(PyTuple_GetItem(element, 0));
-
-		 if (addr_start == addr + size) {
-			 range = PyTuple_New(2);
-			 PyTuple_SetItem(range, 0, PyLong_FromUnsignedLongLong((uint64_t)addr));
-			 PyTuple_SetItem(range, 1, PyLong_FromUnsignedLongLong((uint64_t)addr_start));
-			 PyList_SetItem(vm_mngr->code_bloc_memory_w, 0, range);
+		/* Check match on lower bound */
+		 if (access->array[0].start == addr2) {
+			 access->array[0].start = addr1;
 			 return;
 		 }
-
 	}
-	range = PyTuple_New(2);
-	PyTuple_SetItem(range, 0, PyLong_FromUnsignedLongLong((uint64_t)addr));
-	PyTuple_SetItem(range, 1, PyLong_FromUnsignedLongLong((uint64_t)addr+size));
 
-	PyList_Append(vm_mngr->code_bloc_memory_w, range);
+	/* No merge, add to the list */
+	memory_access_list_add(access, addr1, addr2);
 }
 
-void check_write_code_bloc(vm_mngr_t* vm_mngr, uint64_t my_size, uint64_t addr)
+
+void add_mem_read(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t size)
 {
-	struct code_bloc_node * cbp;
+	add_range_to_list(&(vm_mngr->memory_r), addr, addr + size);
+}
 
-	if (vm_mngr->exception_flags & EXCEPT_CODE_AUTOMOD)
-		return;
+void add_mem_write(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t size)
+{
+	add_range_to_list(&(vm_mngr->memory_w), addr, addr + size);
+}
+
+void check_invalid_code_blocs(vm_mngr_t* vm_mngr)
+{
+	int i;
+	struct code_bloc_node * cbp;
+	for (i=0;i<vm_mngr->memory_w.num; i++) {
+		if (vm_mngr->exception_flags & EXCEPT_CODE_AUTOMOD)
+			break;
+		if (vm_mngr->memory_w.array[i].stop <= vm_mngr->code_bloc_pool_ad_min ||
+		    vm_mngr->memory_w.array[i].start >=vm_mngr->code_bloc_pool_ad_max)
+			continue;
 
-	if (!(addr + my_size/8 <= vm_mngr->code_bloc_pool_ad_min ||
-	      addr >=vm_mngr->code_bloc_pool_ad_max)){
 		LIST_FOREACH(cbp, &vm_mngr->code_bloc_pool, next){
-			if ((cbp->ad_start < addr + my_size/8) &&
-			    (addr < cbp->ad_stop)){
+			if ((cbp->ad_start < vm_mngr->memory_w.array[i].stop) &&
+			    (vm_mngr->memory_w.array[i].start < cbp->ad_stop)){
 #ifdef DEBUG_MIASM_AUTOMOD_CODE
 				fprintf(stderr, "**********************************\n");
 				fprintf(stderr, "self modifying code %"PRIX64" %"PRIX64"\n",
-				       addr, my_size);
+					vm_mngr->memory_w.array[i].start,
+					vm_mngr->memory_w.array[i].stop);
 				fprintf(stderr, "**********************************\n");
 #endif
 				vm_mngr->exception_flags |= EXCEPT_CODE_AUTOMOD;
@@ -463,27 +483,62 @@ void check_write_code_bloc(vm_mngr_t* vm_mngr, uint64_t my_size, uint64_t addr)
 	}
 }
 
-void reset_code_bloc_write(vm_mngr_t* vm_mngr)
+
+void check_memory_breakpoint(vm_mngr_t* vm_mngr)
 {
 	int i;
-	int list_size;
-	PyObject* element;
+	struct memory_breakpoint_info * memory_bp;
+
+	/* Check memory breakpoints */
+	LIST_FOREACH(memory_bp, &vm_mngr->memory_breakpoint_pool, next) {
+		if (vm_mngr->exception_flags & EXCEPT_BREAKPOINT_INTERN)
+			break;
+		if (memory_bp->access & BREAKPOINT_READ) {
+			for (i=0;i<vm_mngr->memory_r.num; i++) {
+				if ((memory_bp->ad < vm_mngr->memory_r.array[i].stop) &&
+				    (vm_mngr->memory_r.array[i].start < memory_bp->ad + memory_bp->size)) {
+					vm_mngr->exception_flags |= EXCEPT_BREAKPOINT_INTERN;
+					break;
+				}
+			}
+		}
+		if (memory_bp->access & BREAKPOINT_WRITE) {
+			for (i=0;i<vm_mngr->memory_w.num; i++) {
+				if ((memory_bp->ad < vm_mngr->memory_w.array[i].stop) &&
+				    (vm_mngr->memory_w.array[i].start < memory_bp->ad + memory_bp->size)) {
+					vm_mngr->exception_flags |= EXCEPT_BREAKPOINT_INTERN;
+					break;
+				}
+			}
+		}
+	}
+}
 
-	list_size = PyList_Size(vm_mngr->code_bloc_memory_w);
 
-	for (i=0;i<list_size; i++) {
-		element = PyList_GetItem(vm_mngr->code_bloc_memory_w, i);
-		Py_DECREF(element);
+PyObject* get_memory_pylist(vm_mngr_t* vm_mngr, struct memory_access_list* memory_list)
+{
+	int i;
+	PyObject *pylist;
+	PyObject *range;
+	pylist = PyList_New(memory_list->num);
+	for (i=0;i<memory_list->num;i++) {
+		range = PyTuple_New(2);
+		PyTuple_SetItem(range, 0, PyLong_FromUnsignedLongLong((uint64_t)memory_list->array[i].start));
+		PyTuple_SetItem(range, 1, PyLong_FromUnsignedLongLong((uint64_t)memory_list->array[i].stop));
+		PyList_SetItem(pylist, i, range);
 	}
+	return pylist;
 
-	Py_DECREF(vm_mngr->code_bloc_memory_w);
-	vm_mngr->code_bloc_memory_w = PyList_New(0);
+}
 
+PyObject* get_memory_read(vm_mngr_t* vm_mngr)
+{
+	return get_memory_pylist(vm_mngr, &vm_mngr->memory_r);
 }
 
-PyObject* get_code_bloc_write(vm_mngr_t* vm_mngr)
+PyObject* get_memory_write(vm_mngr_t* vm_mngr)
 {
-	return vm_mngr->code_bloc_memory_w;
+	return get_memory_pylist(vm_mngr, &vm_mngr->memory_w);
 }
 
 PyObject* addr2BlocObj(vm_mngr_t* vm_mngr, uint64_t addr)
@@ -505,53 +560,53 @@ PyObject* addr2BlocObj(vm_mngr_t* vm_mngr, uint64_t addr)
 
 void vm_MEM_WRITE_08(vm_mngr_t* vm_mngr, uint64_t addr, unsigned char src)
 {
-	check_write_code_bloc(vm_mngr, 8, addr);
-	code_bloc_add_write(vm_mngr, addr, 1);
+	add_mem_write(vm_mngr, addr, 1);
 	memory_page_write(vm_mngr, 8, addr, src);
 }
 
 void vm_MEM_WRITE_16(vm_mngr_t* vm_mngr, uint64_t addr, unsigned short src)
 {
-	check_write_code_bloc(vm_mngr, 16, addr);
-	code_bloc_add_write(vm_mngr, addr, 2);
+	add_mem_write(vm_mngr, addr, 2);
 	memory_page_write(vm_mngr, 16, addr, src);
 }
 void vm_MEM_WRITE_32(vm_mngr_t* vm_mngr, uint64_t addr, unsigned int src)
 {
-	check_write_code_bloc(vm_mngr, 32, addr);
-	code_bloc_add_write(vm_mngr, addr, 4);
+	add_mem_write(vm_mngr, addr, 4);
 	memory_page_write(vm_mngr, 32, addr, src);
 }
 void vm_MEM_WRITE_64(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t src)
 {
-	check_write_code_bloc(vm_mngr, 64, addr);
-	code_bloc_add_write(vm_mngr, addr, 8);
+	add_mem_write(vm_mngr, addr, 8);
 	memory_page_write(vm_mngr, 64, addr, src);
 }
 
 unsigned char vm_MEM_LOOKUP_08(vm_mngr_t* vm_mngr, uint64_t addr)
 {
-    unsigned char ret;
-    ret = memory_page_read(vm_mngr, 8, addr);
-    return ret;
+	unsigned char ret;
+	add_mem_read(vm_mngr, addr, 1);
+	ret = memory_page_read(vm_mngr, 8, addr);
+	return ret;
 }
 unsigned short vm_MEM_LOOKUP_16(vm_mngr_t* vm_mngr, uint64_t addr)
 {
-    unsigned short ret;
-    ret = memory_page_read(vm_mngr, 16, addr);
-    return ret;
+	unsigned short ret;
+	add_mem_read(vm_mngr, addr, 2);
+	ret = memory_page_read(vm_mngr, 16, addr);
+	return ret;
 }
 unsigned int vm_MEM_LOOKUP_32(vm_mngr_t* vm_mngr, uint64_t addr)
 {
-    unsigned int ret;
-    ret = memory_page_read(vm_mngr, 32, addr);
-    return ret;
+	unsigned int ret;
+	add_mem_read(vm_mngr, addr, 4);
+	ret = memory_page_read(vm_mngr, 32, addr);
+	return ret;
 }
 uint64_t vm_MEM_LOOKUP_64(vm_mngr_t* vm_mngr, uint64_t addr)
 {
-    uint64_t ret;
-    ret = memory_page_read(vm_mngr, 64, addr);
-    return ret;
+	uint64_t ret;
+	add_mem_read(vm_mngr, addr, 8);
+	ret = memory_page_read(vm_mngr, 64, addr);
+	return ret;
 }
 
 
@@ -592,8 +647,6 @@ int vm_write_mem(vm_mngr_t* vm_mngr, uint64_t addr, char *buffer, uint64_t size)
        uint64_t len;
        struct memory_page_node * mpn;
 
-       check_write_code_bloc(vm_mngr, size * 8, addr);
-
        /* write is multiple page wide */
        while (size){
 	      mpn = get_memory_page_from_address(vm_mngr, addr, 1);
@@ -1465,7 +1518,9 @@ void init_code_bloc_pool(vm_mngr_t* vm_mngr)
 	vm_mngr->code_bloc_pool_ad_min = 0xffffffff;
 	vm_mngr->code_bloc_pool_ad_max = 0;
 
-	vm_mngr->code_bloc_memory_w = PyList_New(0);
+	memory_access_list_init(&(vm_mngr->memory_r));
+	memory_access_list_init(&(vm_mngr->memory_w));
+
 
 }
 
@@ -1504,6 +1559,11 @@ void reset_code_bloc_pool(vm_mngr_t* vm_mngr)
 	vm_mngr->code_bloc_pool_ad_max = 0;
 }
 
+void reset_memory_access(vm_mngr_t* vm_mngr)
+{
+	memory_access_list_reset(&(vm_mngr->memory_r));
+	memory_access_list_reset(&(vm_mngr->memory_w));
+}
 
 void reset_memory_breakpoint(vm_mngr_t* vm_mngr)
 {
@@ -1517,6 +1577,8 @@ void reset_memory_breakpoint(vm_mngr_t* vm_mngr)
 
 }
 
+
+
 /* We don't use dichotomy here for the insertion */
 int is_mpn_in_tab(vm_mngr_t* vm_mngr, struct memory_page_node* mpn_a)
 {
diff --git a/miasm2/jitter/vm_mngr.h b/miasm2/jitter/vm_mngr.h
index 67f0bac2..13ec065a 100644
--- a/miasm2/jitter/vm_mngr.h
+++ b/miasm2/jitter/vm_mngr.h
@@ -73,7 +73,16 @@ struct memory_page_node {
 	char* name;
 };
 
+struct memory_access {
+	uint64_t start;
+	uint64_t stop;
+};
 
+struct memory_access_list {
+	struct memory_access *array;
+	uint64_t allocated;
+	uint64_t num;
+};
 
 typedef struct {
 	int sex;
@@ -92,9 +101,11 @@ typedef struct {
 	PyObject *addr2obj;
 
 
+	struct memory_access_list memory_r;
+	struct memory_access_list memory_w;
 
-	PyObject* code_bloc_memory_w;
 
+	int write_num;
 
 }vm_mngr_t;
 
@@ -266,6 +277,11 @@ unsigned int rcr_rez_op(unsigned int size, unsigned int a, unsigned int b, unsig
 	    }
 
 
+void memory_access_list_init(struct memory_access_list * access);
+void memory_access_list_reset(struct memory_access_list * access);
+void memory_access_list_add(struct memory_access_list * access, uint64_t start, uint64_t stop);
+
+
 void hexdump(char* m, unsigned int l);
 
 struct code_bloc_node * create_code_bloc_node(uint64_t ad_start, uint64_t ad_stop);
@@ -287,10 +303,13 @@ void remove_memory_breakpoint(vm_mngr_t* vm_mngr, uint64_t ad, unsigned int acce
 
 void add_memory_page(vm_mngr_t* vm_mngr, struct memory_page_node* mpn);
 
-void check_write_code_bloc(vm_mngr_t* vm_mngr, uint64_t my_size, uint64_t addr);
-void code_bloc_add_write(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t size);
-void reset_code_bloc_write(vm_mngr_t* vm_mngr);
-PyObject* get_code_bloc_write(vm_mngr_t* vm_mngr);
+void add_mem_read(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t size);
+void add_mem_write(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t size);
+void check_invalid_code_blocs(vm_mngr_t* vm_mngr);
+void check_memory_breakpoint(vm_mngr_t* vm_mngr);
+void reset_memory_access(vm_mngr_t* vm_mngr);
+PyObject* get_memory_read(vm_mngr_t* vm_mngr);
+PyObject* get_memory_write(vm_mngr_t* vm_mngr);
 
 
 char* dump(vm_mngr_t* vm_mngr);
diff --git a/miasm2/jitter/vm_mngr_py.c b/miasm2/jitter/vm_mngr_py.c
index 9e370465..5aece270 100644
--- a/miasm2/jitter/vm_mngr_py.c
+++ b/miasm2/jitter/vm_mngr_py.c
@@ -186,7 +186,8 @@ PyObject* vm_set_mem(VmMngr* self, PyObject* args)
        if (ret < 0)
 	      RAISE(PyExc_TypeError, "Error in set_mem");
 
-       check_write_code_bloc(&self->vm_mngr, size*8, addr);
+       add_mem_write(&self->vm_mngr, addr, size);
+       check_invalid_code_blocs(&self->vm_mngr);
 
        Py_INCREF(Py_None);
        return Py_None;
@@ -320,6 +321,63 @@ PyObject* vm_reset_memory_breakpoint(VmMngr* self, PyObject* args)
 
 }
 
+PyObject* vm_reset_memory_access(VmMngr* self, PyObject* args)
+{
+    reset_memory_access(&self->vm_mngr);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+PyObject* py_add_mem_read(VmMngr* self, PyObject* args)
+{
+	PyObject *py_addr;
+	PyObject *py_size;
+	uint64_t addr;
+	uint64_t size;
+
+	if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_size))
+		return NULL;
+
+	PyGetInt(py_addr, addr);
+	PyGetInt(py_size, size);
+	add_mem_read(&self->vm_mngr, addr, size);
+	Py_INCREF(Py_None);
+	return Py_None;
+
+}
+
+PyObject* py_add_mem_write(VmMngr* self, PyObject* args)
+{
+	PyObject *py_addr;
+	PyObject *py_size;
+	uint64_t addr;
+	uint64_t size;
+
+	if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_size))
+		return NULL;
+
+	PyGetInt(py_addr, addr);
+	PyGetInt(py_size, size);
+	add_mem_write(&self->vm_mngr, addr, size);
+	Py_INCREF(Py_None);
+	return Py_None;
+
+}
+
+PyObject* vm_check_invalid_code_blocs(VmMngr* self, PyObject* args)
+{
+    check_invalid_code_blocs(&self->vm_mngr);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+PyObject* vm_check_memory_breakpoint(VmMngr* self, PyObject* args)
+{
+    check_memory_breakpoint(&self->vm_mngr);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
 PyObject *vm_dump(PyObject* self)
 {
 	char* buf_final;
@@ -460,26 +518,24 @@ PyObject* vm_is_mapped(VmMngr* self, PyObject* args)
 	return PyLong_FromUnsignedLongLong((uint64_t)ret);
 }
 
-PyObject* vm_reset_code_bloc_write(VmMngr* self, PyObject* args)
+PyObject* vm_get_memory_read(VmMngr* self, PyObject* args)
 {
-	reset_code_bloc_write(&self->vm_mngr);
-	Py_INCREF(Py_None);
-	return Py_None;
+	PyObject* result;
+	result = get_memory_read(&self->vm_mngr);
+	Py_INCREF(result);
+	return result;
 }
 
-PyObject* vm_get_code_bloc_write(VmMngr* self, PyObject* args)
+PyObject* vm_get_memory_write(VmMngr* self, PyObject* args)
 {
 	PyObject* result;
-
-	result = get_code_bloc_write(&self->vm_mngr);
+	result = get_memory_write(&self->vm_mngr);
 	Py_INCREF(result);
-
 	return result;
 }
 
 
 
-
 static PyObject *
 vm_set_big_endian(VmMngr *self, PyObject *value, void *closure)
 {
@@ -548,8 +604,6 @@ static PyMethodDef VmMngr_methods[] = {
 	 "X"},
 	{"is_mapped", (PyCFunction)vm_is_mapped, METH_VARARGS,
 	 "X"},
-	{"reset_code_bloc_write", (PyCFunction)vm_reset_code_bloc_write, METH_VARARGS,
-	 "X"},
 	{"add_code_bloc",(PyCFunction)vm_add_code_bloc, METH_VARARGS,
 	 "X"},
 	{"get_mem", (PyCFunction)vm_get_mem, METH_VARARGS,
@@ -572,8 +626,6 @@ static PyMethodDef VmMngr_methods[] = {
 	 "X"},
 	{"reset_code_bloc_pool", (PyCFunction)vm_reset_code_bloc_pool, METH_VARARGS,
 	 "X"},
-	{"get_code_bloc_write", (PyCFunction)vm_get_code_bloc_write, METH_VARARGS,
-	 "X"},
 	{"set_alarm", (PyCFunction)set_alarm, METH_VARARGS,
 	 "X"},
 	{"get_exception",(PyCFunction)vm_get_exception, METH_VARARGS,
@@ -584,6 +636,20 @@ static PyMethodDef VmMngr_methods[] = {
 	 "X"},
 	{"set_little_endian",(PyCFunction)vm_set_little_endian, METH_VARARGS,
 	 "X"},
+	{"get_memory_read",(PyCFunction)vm_get_memory_read, METH_VARARGS,
+	 "X"},
+	{"get_memory_write",(PyCFunction)vm_get_memory_write, METH_VARARGS,
+	 "X"},
+	{"reset_memory_access",(PyCFunction)vm_reset_memory_access, METH_VARARGS,
+	 "X"},
+	{"add_mem_read",(PyCFunction)py_add_mem_read, METH_VARARGS,
+	 "X"},
+	{"add_mem_write",(PyCFunction)py_add_mem_write, METH_VARARGS,
+	 "X"},
+	{"check_invalid_code_blocs",(PyCFunction)vm_check_invalid_code_blocs, METH_VARARGS,
+	 "X"},
+	{"check_memory_breakpoint",(PyCFunction)vm_check_memory_breakpoint, METH_VARARGS,
+	 "X"},
 
 	{NULL}  /* Sentinel */
 };
diff --git a/test/test_all.py b/test/test_all.py
index a487900f..c9401552 100644
--- a/test/test_all.py
+++ b/test/test_all.py
@@ -398,6 +398,8 @@ test_mips32l = ExampleShellcode(["mips32l", "mips32.S", "mips32_sc_l.bin"])
 test_x86_64 = ExampleShellcode(["x86_64", "x86_64.S", "demo_x86_64.bin",
                                 "--PE"])
 test_x86_32_if_reg = ExampleShellcode(['x86_32', 'x86_32_if_reg.S', "x86_32_if_reg.bin"])
+test_x86_32_seh = ExampleShellcode(["x86_32", "x86_32_seh.S", "x86_32_seh.bin",
+                                    "--PE"])
 
 testset += test_armb
 testset += test_arml
@@ -412,6 +414,7 @@ testset += test_mips32b
 testset += test_mips32l
 testset += test_x86_64
 testset += test_x86_32_if_reg
+testset += test_x86_32_seh
 
 class ExampleDisassembler(Example):
     """Disassembler examples specificities:
@@ -553,6 +556,14 @@ class ExampleJitter(Example):
     jitter_engines = ["tcc", "llvm", "python", "gcc"]
 
 
+class ExampleJitterNoPython(ExampleJitter):
+    """Jitter examples specificities:
+    - script path begins with "jitter/"
+    Run jitting script without python support
+    """
+    jitter_engines = ["tcc", "llvm", "gcc"]
+
+
 for jitter in ExampleJitter.jitter_engines:
     # Take 5 min on a Core i5
     tags = {"python": [TAGS["long"]],
@@ -587,6 +598,13 @@ for script, dep in [(["x86_32.py", Example.get_sample("x86_32_sc.bin")], []),
         testset += ExampleJitter(script + ["--jitter", jitter], depends=dep,
                                  tags=tags)
 
+
+for jitter in ExampleJitterNoPython.jitter_engines:
+    tags = [TAGS[jitter]] if jitter in TAGS else []
+    testset += ExampleJitterNoPython(["test_x86_32_seh.py", Example.get_sample("x86_32_seh.bin")] + ["--jitter", jitter],
+                                     depends=[test_x86_32_seh],
+                                     tags=tags)
+
 testset += ExampleJitter(["example_types.py"])