about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorCamille Mougey <commial@gmail.com>2018-05-18 13:17:57 +0200
committerGitHub <noreply@github.com>2018-05-18 13:17:57 +0200
commitf45613e84c4de409342d1b971e7ce0234173ffc4 (patch)
tree244766e52d6fd83917de117ee3c14b830de8cb84
parentf6a9db54b4f385d680abfe91b33c7c5f577118cb (diff)
parent53273fa3b21e618cd9cc745624787450bc441476 (diff)
downloadmiasm-f45613e84c4de409342d1b971e7ce0234173ffc4.tar.gz
miasm-f45613e84c4de409342d1b971e7ce0234173ffc4.zip
Merge pull request #747 from serpilliere/asmblobk_bad_jit
Asmblobk bad jit
-rw-r--r--miasm2/core/asmblock.py39
-rw-r--r--miasm2/jitter/jitcore.py42
-rw-r--r--test/jitter/bad_block.py44
-rw-r--r--test/jitter/jmp_out_mem.py47
-rw-r--r--test/jitter/test_post_instr.py5
-rwxr-xr-xtest/test_all.py2
6 files changed, 148 insertions, 31 deletions
diff --git a/miasm2/core/asmblock.py b/miasm2/core/asmblock.py
index 8740aeb7..f763d85f 100644
--- a/miasm2/core/asmblock.py
+++ b/miasm2/core/asmblock.py
@@ -297,13 +297,23 @@ class AsmBlockBad(AsmBlock):
     """Stand for a *bad* ASM block (malformed, unreachable,
     not disassembled, ...)"""
 
-    ERROR_TYPES = {-1: "Unknown error",
-                   0: "Unable to disassemble",
-                   1: "Null starting block",
-                   2: "Address forbidden by dont_dis",
-                   }
 
-    def __init__(self, label=None, alignment=1, errno=-1, *args, **kwargs):
+    ERROR_UNKNOWN = -1
+    ERROR_CANNOT_DISASM = 0
+    ERROR_NULL_STARTING_BLOCK = 1
+    ERROR_FORBIDDEN = 2
+    ERROR_IO = 3
+
+
+    ERROR_TYPES = {
+        ERROR_UNKNOWN: "Unknown error",
+        ERROR_CANNOT_DISASM: "Unable to disassemble",
+        ERROR_NULL_STARTING_BLOCK: "Null starting block",
+        ERROR_FORBIDDEN: "Address forbidden by dont_dis",
+        ERROR_IO: "IOError",
+    }
+
+    def __init__(self, label=None, alignment=1, errno=ERROR_UNKNOWN, *args, **kwargs):
         """Instanciate an AsmBlock_bad.
         @label, @alignement: same as AsmBlock.__init__
         @errno: (optional) specify a error type associated with the block
@@ -311,6 +321,8 @@ class AsmBlockBad(AsmBlock):
         super(AsmBlockBad, self).__init__(label, alignment, *args, **kwargs)
         self._errno = errno
 
+    errno = property(lambda self: self._errno)
+
     def __str__(self):
         error_txt = self.ERROR_TYPES.get(self._errno, self._errno)
         return "\n".join([str(self.label),
@@ -1450,7 +1462,7 @@ class disasmEngine(object):
                 if not cur_block.lines:
                     job_done.add(offset)
                     # Block is empty -> bad block
-                    cur_block = AsmBlockBad(label, errno=2)
+                    cur_block = AsmBlockBad(label, errno=AsmBlockBad.ERROR_FORBIDDEN)
                 else:
                     # Block is not empty, stop the desassembly pass and add a
                     # constraint to the next block
@@ -1475,18 +1487,25 @@ class disasmEngine(object):
                 break
 
             off_i = offset
+            error = None
             try:
                 instr = self.arch.dis(self.bin_stream, self.attrib, offset)
-            except (Disasm_Exception, IOError), e:
+            except Disasm_Exception as e:
+                log_asmblock.warning(e)
+                instr = None
+                error = AsmBlockBad.ERROR_CANNOT_DISASM
+            except IOError as e:
                 log_asmblock.warning(e)
                 instr = None
+                error = AsmBlockBad.ERROR_IO
+
 
             if instr is None:
                 log_asmblock.warning("cannot disasm at %X", int(off_i))
                 if not cur_block.lines:
                     job_done.add(offset)
                     # Block is empty -> bad block
-                    cur_block = AsmBlockBad(label, errno=0)
+                    cur_block = AsmBlockBad(label, errno=error)
                 else:
                     # Block is not empty, stop the desassembly pass and add a
                     # constraint to the next block
@@ -1499,7 +1518,7 @@ class disasmEngine(object):
                 log_asmblock.warning("reach nul instr at %X", int(off_i))
                 if not cur_block.lines:
                     # Block is empty -> bad block
-                    cur_block = AsmBlockBad(label, errno=1)
+                    cur_block = AsmBlockBad(label, errno=AsmBlockBad.ERROR_NULL_STARTING_BLOCK)
                 else:
                     # Block is not empty, stop the desassembly pass and add a
                     # constraint to the next block
diff --git a/miasm2/jitter/jitcore.py b/miasm2/jitter/jitcore.py
index f2b1375d..4402ef49 100644
--- a/miasm2/jitter/jitcore.py
+++ b/miasm2/jitter/jitcore.py
@@ -17,7 +17,7 @@
 #
 from hashlib import md5
 
-from miasm2.core import asmblock
+from miasm2.core.asmblock import disasmEngine, AsmLabel, AsmBlockBad
 from miasm2.core.interval import interval
 from miasm2.core.utils import BoundedDict
 from miasm2.jitter.csts import *
@@ -57,13 +57,15 @@ class JitCore(object):
                         "max_exec_per_call": 0 # 0 means no limit
                         }
 
-        self.mdis = asmblock.disasmEngine(ir_arch.arch, ir_arch.attrib, bs,
-                                          lines_wd=self.options["jit_maxline"],
-                                          symbol_pool=ir_arch.symbol_pool,
-                                          follow_call=False,
-                                          dontdis_retcall=False,
-                                          split_dis=self.split_dis,
-                                          dis_block_callback=self.disasm_cb)
+        self.mdis = disasmEngine(
+            ir_arch.arch, ir_arch.attrib, bs,
+            lines_wd=self.options["jit_maxline"],
+            symbol_pool=ir_arch.symbol_pool,
+            follow_call=False,
+            dontdis_retcall=False,
+            split_dis=self.split_dis,
+            dis_block_callback=self.disasm_cb
+        )
 
 
     def set_options(self, **kwargs):
@@ -135,7 +137,7 @@ class JitCore(object):
         """
 
         # Get the block
-        if isinstance(addr, asmblock.AsmLabel):
+        if isinstance(addr, AsmLabel):
             addr = addr.offset
 
         # Prepare disassembler
@@ -143,13 +145,9 @@ class JitCore(object):
         self.mdis.dis_block_callback = self.disasm_cb
 
         # Disassemble it
-        try:
-            cur_block = self.mdis.dis_block(addr)
-        except IOError:
-            # vm_exception_flag is set
-            label = self.ir_arch.symbol_pool.getby_offset_create(addr)
-            cur_block = asmblock.AsmBlockBad(label)
-
+        cur_block = self.mdis.dis_block(addr)
+        if isinstance(cur_block, AsmBlockBad):
+            return cur_block
         # Logging
         if self.log_newbloc:
             print cur_block
@@ -165,6 +163,7 @@ class JitCore(object):
 
         # Update jitcode mem range
         self.add_bloc_to_mem_interval(vm, cur_block)
+        return cur_block
 
     def runbloc(self, cpu, lbl, breakpoints):
         """Run the block starting at lbl.
@@ -177,7 +176,16 @@ class JitCore(object):
 
         if not lbl in self.lbl2jitbloc:
             # Need to JiT the block
-            self.disbloc(lbl, cpu.vmmngr)
+            cur_block = self.disbloc(lbl, cpu.vmmngr)
+            if isinstance(cur_block, AsmBlockBad):
+                errno = cur_block.errno
+                if errno == AsmBlockBad.ERROR_IO:
+                    cpu.vmmngr.set_exception(EXCEPT_ACCESS_VIOL)
+                elif errno == AsmBlockBad.ERROR_CANNOT_DISASM:
+                    cpu.set_exception(EXCEPT_UNK_MNEMO)
+                else:
+                    raise RuntimeError("Unhandled disasm result %r" % errno)
+                return lbl
 
         # Run the block and update cpu/vmmngr state
         return self.exec_wrapper(lbl, cpu, self.lbl2jitbloc.data, breakpoints,
diff --git a/test/jitter/bad_block.py b/test/jitter/bad_block.py
new file mode 100644
index 00000000..04c1f475
--- /dev/null
+++ b/test/jitter/bad_block.py
@@ -0,0 +1,44 @@
+import sys
+from miasm2.jitter.csts import PAGE_READ, PAGE_WRITE, EXCEPT_UNK_MNEMO
+from miasm2.analysis.machine import Machine
+
+def code_sentinelle(jitter):
+    jitter.run = False
+    jitter.pc = 0
+    return True
+
+machine = Machine("x86_32")
+jitter = machine.jitter(sys.argv[1])
+
+jitter.init_stack()
+
+# nop
+# mov eax, 0x42
+# XX
+data = "90b842000000ffff90909090".decode('hex')
+
+# Will raise memory error at 0x40000006
+
+error_raised = False
+def raise_me(jitter):
+    global error_raised
+    error_raised = True
+    assert jitter.pc == 0x40000006
+    return False
+
+jitter.add_exception_handler(EXCEPT_UNK_MNEMO, raise_me)
+
+run_addr = 0x40000000
+
+jitter.vm.add_memory_page(run_addr, PAGE_READ | PAGE_WRITE, data)
+
+jitter.jit.log_regs = True
+jitter.jit.log_mn = True
+jitter.push_uint32_t(0x1337beef)
+
+jitter.add_breakpoint(0x1337beef, code_sentinelle)
+
+jitter.init_run(run_addr)
+jitter.continue_run()
+
+assert error_raised is True
diff --git a/test/jitter/jmp_out_mem.py b/test/jitter/jmp_out_mem.py
new file mode 100644
index 00000000..49da16ad
--- /dev/null
+++ b/test/jitter/jmp_out_mem.py
@@ -0,0 +1,47 @@
+import sys
+from miasm2.jitter.csts import PAGE_READ, PAGE_WRITE, EXCEPT_ACCESS_VIOL
+from miasm2.analysis.machine import Machine
+
+def code_sentinelle(jitter):
+    jitter.run = False
+    jitter.pc = 0
+    return True
+
+
+machine = Machine("x86_32")
+jitter = machine.jitter(sys.argv[1])
+
+jitter.init_stack()
+
+# nop
+# mov eax, 0x42
+# jmp 0x20
+
+data = "90b842000000eb20".decode('hex')
+
+# Will raise memory error at 0x40000028
+
+error_raised = False
+def raise_me(jitter):
+    global error_raised
+    error_raised = True
+    assert jitter.pc == 0x40000028
+    return False
+
+jitter.add_exception_handler(EXCEPT_ACCESS_VIOL, raise_me)
+
+
+run_addr = 0x40000000
+
+jitter.vm.add_memory_page(run_addr, PAGE_READ | PAGE_WRITE, data)
+
+jitter.jit.log_regs = True
+jitter.jit.log_mn = True
+jitter.push_uint32_t(0x1337beef)
+
+jitter.add_breakpoint(0x1337beef, code_sentinelle)
+
+jitter.init_run(run_addr)
+jitter.continue_run()
+
+assert error_raised is True
diff --git a/test/jitter/test_post_instr.py b/test/jitter/test_post_instr.py
index 3e68d58e..edf86645 100644
--- a/test/jitter/test_post_instr.py
+++ b/test/jitter/test_post_instr.py
@@ -1,6 +1,6 @@
+import sys
 from miasm2.analysis.machine import Machine
 from miasm2.jitter.csts import PAGE_READ, PAGE_WRITE, EXCEPT_BREAKPOINT_MEMORY, EXCEPT_ACCESS_VIOL
-import sys
 
 machine = Machine("x86_32")
 jitter = machine.jitter(sys.argv[1])
@@ -41,6 +41,3 @@ try:
     jitter.continue_run()
 except AssertionError:
     assert jitter.vm.get_exception() == EXCEPT_ACCESS_VIOL
-except RuntimeError:
-    assert sys.argv[1] == 'python'
-    assert jitter.vm.get_exception() == EXCEPT_ACCESS_VIOL
diff --git a/test/test_all.py b/test/test_all.py
index f9c90759..b1e36573 100755
--- a/test/test_all.py
+++ b/test/test_all.py
@@ -380,6 +380,8 @@ for script in ["jitload.py",
                "vm_mngr.py",
                "jit_options.py",
                "test_post_instr.py",
+               "bad_block.py",
+               "jmp_out_mem.py",
                ]:
     for engine in ArchUnitTest.jitter_engines:
         testset += RegressionTest([script, engine], base_dir="jitter",