diff options
| -rw-r--r-- | example/disasm/full.py | 11 | ||||
| -rw-r--r-- | miasm2/analysis/depgraph.py | 48 | ||||
| -rw-r--r-- | miasm2/jitter/llvmconvert.py | 20 | ||||
| -rw-r--r-- | miasm2/jitter/vm_mngr.c | 5 | ||||
| -rw-r--r-- | miasm2/jitter/vm_mngr.h | 3 | ||||
| -rwxr-xr-x | test/analysis/dg_test_11_expected.json | 1 | ||||
| -rw-r--r-- | test/analysis/dg_test_11_implicit_expected.json | 1 | ||||
| -rw-r--r-- | test/samples/x86_32/dg_test_11.S | 10 | ||||
| -rwxr-xr-x | test/test_all.py | 1 |
9 files changed, 68 insertions, 32 deletions
diff --git a/example/disasm/full.py b/example/disasm/full.py index 7ff60d3b..f15b59eb 100644 --- a/example/disasm/full.py +++ b/example/disasm/full.py @@ -50,6 +50,8 @@ parser.add_argument('-a', "--try-disasm-all", action="store_true", help="Try to disassemble the whole binary") parser.add_argument('-i', "--image", action="store_true", help="Display image representation of disasm") +parser.add_argument('-c', "--rawbinary", default=False, action="store_true", + help="Don't interpret input as ELF/PE/...") args = parser.parse_args() @@ -57,8 +59,13 @@ if args.verbose: log_asmbloc.setLevel(logging.DEBUG) log.info('Load binary') -with open(args.filename) as fdesc: - cont = Container.from_stream(fdesc, addr=args.shiftoffset) +if args.rawbinary: + shift = args.shiftoffset if args.shiftoffset is not None else 0 + cont = Container.fallback_container(open(args.filename).read(), + None, addr=shift) +else: + with open(args.filename) as fdesc: + cont = Container.from_stream(fdesc, addr=args.shiftoffset) default_addr = cont.entry_point bs = cont.bin_stream diff --git a/miasm2/analysis/depgraph.py b/miasm2/analysis/depgraph.py index 9fc28fb8..281251c2 100644 --- a/miasm2/analysis/depgraph.py +++ b/miasm2/analysis/depgraph.py @@ -53,8 +53,8 @@ class DependencyNode(object): def __cmp__(self, node): """Compares @self with @node.""" if not isinstance(node, self.__class__): - raise ValueError("Compare error between %s, %s" % (self.__class__, - node.__class__)) + return cmp(self.__class__, node.__class__) + return cmp((self.label, self.element, self.line_nb), (node.label, node.element, node.line_nb)) @@ -90,9 +90,8 @@ class DependencyState(object): Store intermediate depnodes states during dependencygraph analysis """ - def __init__(self, label, inputs, pending, line_nb=None): + def __init__(self, label, pending, line_nb=None): self.label = label - self.inputs = inputs self.history = [label] self.pending = {k: set(v) for k, v in pending.iteritems()} self.line_nb = line_nb @@ -110,7 +109,7 @@ class DependencyState(object): """Return a copy of itself, with itself in history @label: asm_label instance for the new DependencyState's label """ - new_state = self.__class__(label, self.inputs, self.pending) + new_state = self.__class__(label, self.pending) new_state.links = set(self.links) new_state.history = self.history + [label] return new_state @@ -195,12 +194,13 @@ class DependencyResult(DependencyState): """Container and methods for DependencyGraph results""" - def __init__(self, state, ira): + def __init__(self, ira, initial_state, state, inputs): + self.initial_state = initial_state self.label = state.label - self.inputs = state.inputs self.history = state.history self.pending = state.pending self.line_nb = state.line_nb + self.inputs = inputs self.links = state.links self._ira = ira @@ -247,7 +247,7 @@ class DependencyResult(DependencyState): self._has_loop = self.graph.has_loop() return self._has_loop - def irblock_slice(self, irb): + def irblock_slice(self, irb, max_line=None): """Slice of the dependency nodes on the irblock @irb @irb: irbloc instance """ @@ -261,6 +261,8 @@ class DependencyResult(DependencyState): set()).add(depnode.element) for line_nb, elements in sorted(line2elements.iteritems()): + if max_line is not None and line_nb >= max_line: + break assignblk = AssignBlock() for element in elements: if element in irb.irs[line_nb]: @@ -285,8 +287,14 @@ class DependencyResult(DependencyState): assignblks = [] # Build a single affectation block according to history - for label in self.relevant_labels[::-1]: - assignblks += self.irblock_slice(self._ira.blocs[label]).irs + last_index = len(self.relevant_labels) + for index, label in enumerate(reversed(self.relevant_labels), 1): + if index == last_index and label == self.initial_state.label: + line_nb = self.initial_state.line_nb + else: + line_nb = None + assignblks += self.irblock_slice(self._ira.blocs[label], + line_nb).irs # Eval the block temp_label = asm_label("Temp") @@ -352,15 +360,19 @@ class DependencyResultImplicit(DependencyResult): translator = Translator.to_language("z3") size = self._ira.IRDst.size - for hist_nb, label in enumerate(history): - irb = self.irblock_slice(self._ira.blocs[label]) + for hist_nb, label in enumerate(history, 1): + if hist_nb == history_size and label == self.initial_state.label: + line_nb = self.initial_state.line_nb + else: + line_nb = None + irb = self.irblock_slice(self._ira.blocs[label], line_nb) # Emul the block and get back destination dst = symb_exec.emulbloc(irb, step=step) # Add constraint - if hist_nb + 1 < history_size: - next_label = history[hist_nb + 1] + if hist_nb < history_size: + next_label = history[hist_nb] expected = symb_exec.eval_expr(m2_expr.ExprId(next_label, size)) solver.add( @@ -585,9 +597,9 @@ class DependencyGraph(object): Return an iterator on DiGraph(DependencyNode) """ # Init the algorithm - pending = {element: set() for element in elements} - state = DependencyState(label, elements, pending, line_nb) - todo = set([state]) + inputs = {element: set() for element in elements} + initial_state = DependencyState(label, inputs, line_nb) + todo = set([initial_state]) done = set() dpResultcls = DependencyResultImplicit if self._implicit else DependencyResult @@ -601,7 +613,7 @@ class DependencyGraph(object): if (not state.pending or state.label in heads or not self._ira.graph.predecessors(state.label)): - yield dpResultcls(state, self._ira) + yield dpResultcls(self._ira, initial_state, state, elements) if not state.pending: continue diff --git a/miasm2/jitter/llvmconvert.py b/miasm2/jitter/llvmconvert.py index 051dbb96..bc04689c 100644 --- a/miasm2/jitter/llvmconvert.py +++ b/miasm2/jitter/llvmconvert.py @@ -197,10 +197,11 @@ class LLVMContext_JIT(LLVMContext): def add_op(self): "Add operations functions" - p8 = llvm_ir.PointerType(LLVMType.IntType(8)) + i8 = LLVMType.IntType(8) + p8 = llvm_ir.PointerType(i8) itype = LLVMType.IntType(64) - self.add_fc({"parity": {"ret": LLVMType.IntType(1), - "args": [itype]}}) + self.add_fc({"llvm.ctpop.i8": {"ret": i8, + "args": [i8]}}) self.add_fc({"rot_left": {"ret": itype, "args": [itype, itype, @@ -381,8 +382,7 @@ class LLVMFunction(): # Operation translation ## Basics - op_translate = {'parity': 'parity', - 'cpuid': 'cpuid', + op_translate = {'cpuid': 'cpuid', } ## Add the size as first argument op_translate_with_size = {'<<<': 'rot_left', @@ -711,6 +711,16 @@ class LLVMFunction(): self.update_cache(expr, ret) return ret + if op == "parity": + assert len(expr.args) == 1 + arg = self.add_ir(expr.args[0]) + truncated = builder.trunc(arg, LLVMType.IntType(8)) + bitcount = builder.call(self.mod.get_global("llvm.ctpop.i8"), + [truncated]) + ret = builder.not_(builder.trunc(bitcount, LLVMType.IntType(1))) + self.update_cache(expr, ret) + return ret + if op == "segm": fc_ptr = self.mod.get_global("segm2addr") diff --git a/miasm2/jitter/vm_mngr.c b/miasm2/jitter/vm_mngr.c index 42f91f72..c48ba334 100644 --- a/miasm2/jitter/vm_mngr.c +++ b/miasm2/jitter/vm_mngr.c @@ -76,11 +76,6 @@ const uint8_t parity_table[256] = { 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, }; -uint8_t parity(uint64_t a) { - return parity_table[(a) & 0xFF]; -} - - // #define DEBUG_MIASM_AUTOMOD_CODE void memory_access_list_init(struct memory_access_list * access) diff --git a/miasm2/jitter/vm_mngr.h b/miasm2/jitter/vm_mngr.h index 88ecf34d..912b105e 100644 --- a/miasm2/jitter/vm_mngr.h +++ b/miasm2/jitter/vm_mngr.h @@ -193,8 +193,7 @@ int vm_write_mem(vm_mngr_t* vm_mngr, uint64_t addr, char *buffer, uint64_t size) #define CC_P 1 extern const uint8_t parity_table[256]; - -uint8_t parity(uint64_t a); +#define parity(a) parity_table[(a) & 0xFF] unsigned int my_imul08(unsigned int a, unsigned int b); diff --git a/test/analysis/dg_test_11_expected.json b/test/analysis/dg_test_11_expected.json new file mode 100755 index 00000000..ced55daf --- /dev/null +++ b/test/analysis/dg_test_11_expected.json @@ -0,0 +1 @@ +[{"has_loop": false, "EBX": "0x1"}, {"has_loop": false, "EBX": "0x3"}, {"has_loop": true, "EBX": "0x5"}] diff --git a/test/analysis/dg_test_11_implicit_expected.json b/test/analysis/dg_test_11_implicit_expected.json new file mode 100644 index 00000000..bd0fbf29 --- /dev/null +++ b/test/analysis/dg_test_11_implicit_expected.json @@ -0,0 +1 @@ +[{"has_loop": false, "EBX": "0x1", "satisfiability": true, "constraints": {}}, {"has_loop": false, "EBX": "0x3", "satisfiability": true, "constraints": {}}, {"has_loop": true, "EBX": "0x5", "satisfiability": true, "constraints": {}}] diff --git a/test/samples/x86_32/dg_test_11.S b/test/samples/x86_32/dg_test_11.S new file mode 100644 index 00000000..ac0edc56 --- /dev/null +++ b/test/samples/x86_32/dg_test_11.S @@ -0,0 +1,10 @@ +main: + MOV EBX, 0x1 + JMP lbl1 +lbl1: + ADD EBX, 0x2 + CMP EBX, 0x0 + JNZ lbl1 +end: + MOV EAX, EBX + RET diff --git a/test/test_all.py b/test/test_all.py index 59624832..c710a8ab 100755 --- a/test/test_all.py +++ b/test/test_all.py @@ -315,6 +315,7 @@ test_args = [(0x401000, 0x40100d, ["EAX"]), (0x401000, 0x401012, ["ECX"]), (0x401000, 0x40101f, ["EAX", "EBX"]), (0x401000, 0x401025, ["EAX", "EBX"]), + (0x401000, 0x401007, ["EBX"]), ] for i, test_args in enumerate(test_args): test_dg = SemanticTestAsm("x86_32", "PE", ["dg_test_%.2d" % i]) |