diff options
| author | Camille Mougey <commial@gmail.com> | 2016-09-01 11:09:21 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-09-01 11:09:21 +0200 |
| commit | 9f135c02e9bce299a700fa0191388542d141ea22 (patch) | |
| tree | d8ad86407e24ae9435ca4ca344ae7ec61e8568d2 | |
| parent | fb7501f4bb0bc77a0262ad4894732e4de6ccb2b2 (diff) | |
| parent | 2858e916f35f0469baeea23632ddd8befdd7ca5d (diff) | |
| download | miasm-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.py | 56 | ||||
| -rw-r--r-- | example/samples/x86_32_seh.S | 76 | ||||
| -rw-r--r-- | miasm2/jitter/JitCore.c | 12 | ||||
| -rw-r--r-- | miasm2/jitter/JitCore.h | 5 | ||||
| -rw-r--r-- | miasm2/jitter/arch/JitCore_aarch64.c | 2 | ||||
| -rw-r--r-- | miasm2/jitter/arch/JitCore_arm.c | 2 | ||||
| -rw-r--r-- | miasm2/jitter/arch/JitCore_mips32.c | 2 | ||||
| -rw-r--r-- | miasm2/jitter/arch/JitCore_msp430.c | 2 | ||||
| -rw-r--r-- | miasm2/jitter/arch/JitCore_x86.c | 10 | ||||
| -rw-r--r-- | miasm2/jitter/codegen.py | 4 | ||||
| -rw-r--r-- | miasm2/jitter/emulatedsymbexec.py | 5 | ||||
| -rw-r--r-- | miasm2/jitter/jitcore.py | 21 | ||||
| -rw-r--r-- | miasm2/jitter/jitcore_python.py | 21 | ||||
| -rw-r--r-- | miasm2/jitter/jitload.py | 7 | ||||
| -rw-r--r-- | miasm2/jitter/vm_mngr.c | 220 | ||||
| -rw-r--r-- | miasm2/jitter/vm_mngr.h | 29 | ||||
| -rw-r--r-- | miasm2/jitter/vm_mngr_py.c | 94 | ||||
| -rw-r--r-- | test/test_all.py | 18 |
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"]) |