diff options
| author | Camille Mougey <commial@gmail.com> | 2018-05-18 13:17:57 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-05-18 13:17:57 +0200 |
| commit | f45613e84c4de409342d1b971e7ce0234173ffc4 (patch) | |
| tree | 244766e52d6fd83917de117ee3c14b830de8cb84 | |
| parent | f6a9db54b4f385d680abfe91b33c7c5f577118cb (diff) | |
| parent | 53273fa3b21e618cd9cc745624787450bc441476 (diff) | |
| download | miasm-f45613e84c4de409342d1b971e7ce0234173ffc4.tar.gz miasm-f45613e84c4de409342d1b971e7ce0234173ffc4.zip | |
Merge pull request #747 from serpilliere/asmblobk_bad_jit
Asmblobk bad jit
| -rw-r--r-- | miasm2/core/asmblock.py | 39 | ||||
| -rw-r--r-- | miasm2/jitter/jitcore.py | 42 | ||||
| -rw-r--r-- | test/jitter/bad_block.py | 44 | ||||
| -rw-r--r-- | test/jitter/jmp_out_mem.py | 47 | ||||
| -rw-r--r-- | test/jitter/test_post_instr.py | 5 | ||||
| -rwxr-xr-x | test/test_all.py | 2 |
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", |