about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--example/disasm/full.py11
-rw-r--r--miasm2/analysis/depgraph.py48
-rw-r--r--miasm2/jitter/llvmconvert.py20
-rw-r--r--miasm2/jitter/vm_mngr.c5
-rw-r--r--miasm2/jitter/vm_mngr.h3
-rwxr-xr-xtest/analysis/dg_test_11_expected.json1
-rw-r--r--test/analysis/dg_test_11_implicit_expected.json1
-rw-r--r--test/samples/x86_32/dg_test_11.S10
-rwxr-xr-xtest/test_all.py1
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])