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)
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"
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.
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,
31 @name: name of memory Arrays generated. They will be named
32 name+str(address size) (for example mem32, mem16...).
34 if endianness
not in [
'<',
'>']:
35 raise ValueError(
"Endianness should be '>' (big) or '<' (little)")
41 """Returns a z3 Array used internally to represent memory for addresses
43 @size: integer, size in bit of addresses in the memory to get.
44 Return a z3 Array: BitVecSort(size) -> BitVecSort(8).
50 self.
mems[size] = z3.Array(self.
name + str(size),
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.
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.
73 if original_size % 8 != 0:
75 size = ((original_size / 8) + 1) * 8
78 for i
in xrange(1, size/8):
79 res = z3.Concat(self[addr+i], res)
81 for i
in xrange(1, size/8):
82 res = z3.Concat(res, self[addr+i])
83 if size == original_size:
87 return z3.Extract(original_size-1, 0, res)
90 """True if this memory is little endian."""
94 """True if this memory is big endian."""
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.
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.
111 trivial_ops = [
"+",
"-",
"/",
"%",
"&",
"^",
"|",
"*",
"<<"]
114 """Instance a Z3 translator
115 @endianness: (optional) memory endianness
117 super(TranslatorZ3, self).
__init__(**kwargs)
121 return z3.BitVecVal(expr.arg.arg, expr.size)
124 if isinstance(expr.name, asm_label)
and expr.name.offset
is not None:
125 return z3.BitVecVal(expr.name.offset, expr.size)
127 return z3.BitVec(str(expr), expr.size)
131 return self._mem.get(addr, expr.size)
135 res = z3.Extract(expr.stop-1, expr.start, res)
140 args = sorted(expr.args, key=operator.itemgetter(2))
141 for subexpr, start, stop
in args:
143 e = z3.Extract(stop-start-1, 0, sube)
145 res = z3.Concat(e, res)
154 return z3.If(cond != 0, src1, src2)
163 res = eval(
"res %s arg" % expr.op)
164 elif expr.op ==
">>":
165 res = z3.LShR(res, arg)
166 elif expr.op ==
"a>>":
168 elif expr.op ==
"a<<":
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":
176 elif expr.op ==
"udiv":
177 res = z3.UDiv(res, arg)
178 elif expr.op ==
"imod":
180 elif expr.op ==
"umod":
181 res = z3.URem(res, arg)
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)
188 res = res ^ z3.Extract(i, i, arg)
192 raise NotImplementedError(
"Unsupported OP yet: %s" % expr.op)
203 Translator.register(TranslatorZ3)