Miasm2
 All Classes Namespaces Files Functions Variables Typedefs Properties Macros
z3_ir.py
Go to the documentation of this file.
1 import logging
2 import operator
3 
4 import z3
5 
6 from miasm2.core.asmbloc import asm_label
7 from miasm2.ir.translators.translator import Translator
8 
9 log = logging.getLogger("translator_z3")
10 console_handler = logging.StreamHandler()
11 console_handler.setFormatter(logging.Formatter("%(levelname)-5s: %(message)s"))
12 log.addHandler(console_handler)
13 log.setLevel(logging.WARNING)
14 
15 class Z3Mem(object):
16  """Memory abstration for TranslatorZ3. Memory elements are only accessed,
17  never written. To give a concrete value for a given memory cell in a solver,
18  add "mem32.get(address, size) == <value>" constraints to your equation.
19  The endianness of memory accesses is handled accordingly to the "endianness"
20  attribute.
21 
22  Note: Will have one memory space for each addressing size used.
23  For example, if memory is accessed via 32 bits values and 16 bits values,
24  these access will not occur in the same address space.
25  """
26 
27  def __init__(self, endianness="<", name="mem"):
28  """Initializes a Z3Mem object with a given @name and @endianness.
29  @endianness: Endianness of memory representation. '<' for little endian,
30  '>' for big endian.
31  @name: name of memory Arrays generated. They will be named
32  name+str(address size) (for example mem32, mem16...).
33  """
34  if endianness not in ['<', '>']:
35  raise ValueError("Endianness should be '>' (big) or '<' (little)")
36  self.endianness = endianness
37  self.mems = {} # Address size -> memory z3.Array
38  self.name = name
39 
40  def get_mem_array(self, size):
41  """Returns a z3 Array used internally to represent memory for addresses
42  of size @size.
43  @size: integer, size in bit of addresses in the memory to get.
44  Return a z3 Array: BitVecSort(size) -> BitVecSort(8).
45  """
46  try:
47  mem = self.mems[size]
48  except KeyError:
49  # Lazy instanciation
50  self.mems[size] = z3.Array(self.name + str(size),
51  z3.BitVecSort(size),
52  z3.BitVecSort(8))
53  mem = self.mems[size]
54  return mem
55 
56  def __getitem__(self, addr):
57  """One byte memory access. Different address sizes with the same value
58  will result in different memory accesses.
59  @addr: a z3 BitVec, the address to read.
60  Return a z3 BitVec of size 8 bits representing a memory access.
61  """
62  size = addr.size()
63  mem = self.get_mem_array(size)
64  return mem[addr]
65 
66  def get(self, addr, size):
67  """ Memory access at address @addr of size @size.
68  @addr: a z3 BitVec, the address to read.
69  @size: int, size of the read in bits.
70  Return a z3 BitVec of size @size representing a memory access.
71  """
72  original_size = size
73  if original_size % 8 != 0:
74  # Size not aligned on 8bits -> read more than size and extract after
75  size = ((original_size / 8) + 1) * 8
76  res = self[addr]
77  if self.is_little_endian():
78  for i in xrange(1, size/8):
79  res = z3.Concat(self[addr+i], res)
80  else:
81  for i in xrange(1, size/8):
82  res = z3.Concat(res, self[addr+i])
83  if size == original_size:
84  return res
85  else:
86  # Size not aligned, extract right sized result
87  return z3.Extract(original_size-1, 0, res)
88 
89  def is_little_endian(self):
90  """True if this memory is little endian."""
91  return self.endianness == "<"
92 
93  def is_big_endian(self):
94  """True if this memory is big endian."""
95  return not self.is_little_endian()
96 
97 
99  """Translate a Miasm expression to an equivalent z3 python binding
100  expression. Memory is abstracted via z3.Array (see Z3Mem).
101  The result of from_expr will be a z3 Expr.
102 
103  If you want to interract with the memory abstraction after the translation,
104  you can instanciate your own Z3Mem, that will be equivalent to the one
105  used by TranslatorZ3.
106  """
107 
108  # Implemented language
109  __LANG__ = "z3"
110  # Operations translation
111  trivial_ops = ["+", "-", "/", "%", "&", "^", "|", "*", "<<"]
112 
113  def __init__(self, endianness="<", **kwargs):
114  """Instance a Z3 translator
115  @endianness: (optional) memory endianness
116  """
117  super(TranslatorZ3, self).__init__(**kwargs)
118  self._mem = Z3Mem(endianness)
119 
120  def from_ExprInt(self, expr):
121  return z3.BitVecVal(expr.arg.arg, expr.size)
122 
123  def from_ExprId(self, expr):
124  if isinstance(expr.name, asm_label) and expr.name.offset is not None:
125  return z3.BitVecVal(expr.name.offset, expr.size)
126  else:
127  return z3.BitVec(str(expr), expr.size)
128 
129  def from_ExprMem(self, expr):
130  addr = self.from_expr(expr.arg)
131  return self._mem.get(addr, expr.size)
132 
133  def from_ExprSlice(self, expr):
134  res = self.from_expr(expr.arg)
135  res = z3.Extract(expr.stop-1, expr.start, res)
136  return res
137 
138  def from_ExprCompose(self, expr):
139  res = None
140  args = sorted(expr.args, key=operator.itemgetter(2)) # sort by start off
141  for subexpr, start, stop in args:
142  sube = self.from_expr(subexpr)
143  e = z3.Extract(stop-start-1, 0, sube)
144  if res:
145  res = z3.Concat(e, res)
146  else:
147  res = e
148  return res
149 
150  def from_ExprCond(self, expr):
151  cond = self.from_expr(expr.cond)
152  src1 = self.from_expr(expr.src1)
153  src2 = self.from_expr(expr.src2)
154  return z3.If(cond != 0, src1, src2)
155 
156  def from_ExprOp(self, expr):
157  args = map(self.from_expr, expr.args)
158  res = args[0]
159 
160  if len(args) > 1:
161  for arg in args[1:]:
162  if expr.op in self.trivial_ops:
163  res = eval("res %s arg" % expr.op)
164  elif expr.op == ">>":
165  res = z3.LShR(res, arg)
166  elif expr.op == "a>>":
167  res = res >> arg
168  elif expr.op == "a<<":
169  res = res << arg
170  elif expr.op == "<<<":
171  res = z3.RotateLeft(res, arg)
172  elif expr.op == ">>>":
173  res = z3.RotateRight(res, arg)
174  elif expr.op == "idiv":
175  res = res / arg
176  elif expr.op == "udiv":
177  res = z3.UDiv(res, arg)
178  elif expr.op == "imod":
179  res = res % arg
180  elif expr.op == "umod":
181  res = z3.URem(res, arg)
182  else:
183  raise NotImplementedError("Unsupported OP yet: %s" % expr.op)
184  elif expr.op == 'parity':
185  arg = z3.Extract(7, 0, res)
186  res = z3.BitVecVal(1, 1)
187  for i in xrange(8):
188  res = res ^ z3.Extract(i, i, arg)
189  elif expr.op == '-':
190  res = -res
191  else:
192  raise NotImplementedError("Unsupported OP yet: %s" % expr.op)
193 
194  return res
195 
196  def from_ExprAff(self, expr):
197  src = self.from_expr(expr.src)
198  dst = self.from_expr(expr.dst)
199  return (src == dst)
200 
201 
202 # Register the class
203 Translator.register(TranslatorZ3)