|
|
@ -4,16 +4,15 @@ from z3 import ( |
|
|
|
BitVecRef, |
|
|
|
BitVecRef, |
|
|
|
BitVecNumRef, |
|
|
|
BitVecNumRef, |
|
|
|
BitVecSort, |
|
|
|
BitVecSort, |
|
|
|
Solver, |
|
|
|
|
|
|
|
ExprRef, |
|
|
|
ExprRef, |
|
|
|
Concat, |
|
|
|
Concat, |
|
|
|
sat, |
|
|
|
sat, |
|
|
|
simplify, |
|
|
|
simplify, |
|
|
|
Array, |
|
|
|
Array, |
|
|
|
ForAll, |
|
|
|
ForAll, |
|
|
|
Solver, |
|
|
|
|
|
|
|
UGT, |
|
|
|
|
|
|
|
Implies, |
|
|
|
Implies, |
|
|
|
|
|
|
|
UGE, |
|
|
|
|
|
|
|
UGT, |
|
|
|
) |
|
|
|
) |
|
|
|
from z3.z3types import Z3Exception |
|
|
|
from z3.z3types import Z3Exception |
|
|
|
from mythril.disassembler.disassembly import Disassembly |
|
|
|
from mythril.disassembler.disassembly import Disassembly |
|
|
@ -45,7 +44,7 @@ class Calldata: |
|
|
|
:param starting_calldata: byte array representing the concrete calldata of a transaction |
|
|
|
:param starting_calldata: byte array representing the concrete calldata of a transaction |
|
|
|
""" |
|
|
|
""" |
|
|
|
self.tx_id = tx_id |
|
|
|
self.tx_id = tx_id |
|
|
|
if starting_calldata: |
|
|
|
if not starting_calldata is None: |
|
|
|
self._calldata = [] |
|
|
|
self._calldata = [] |
|
|
|
self.calldatasize = BitVecVal(len(starting_calldata), 256) |
|
|
|
self.calldatasize = BitVecVal(len(starting_calldata), 256) |
|
|
|
self.concrete = True |
|
|
|
self.concrete = True |
|
|
@ -56,32 +55,21 @@ class Calldata: |
|
|
|
self.calldatasize = BitVec("{}_calldatasize".format(self.tx_id), 256) |
|
|
|
self.calldatasize = BitVec("{}_calldatasize".format(self.tx_id), 256) |
|
|
|
self.concrete = False |
|
|
|
self.concrete = False |
|
|
|
|
|
|
|
|
|
|
|
self.starting_calldata = starting_calldata or [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
|
|
def constraints(self): |
|
|
|
|
|
|
|
constraints = [] |
|
|
|
|
|
|
|
if self.concrete: |
|
|
|
if self.concrete: |
|
|
|
for calldata_byte in self.starting_calldata: |
|
|
|
for calldata_byte in starting_calldata: |
|
|
|
if type(calldata_byte) == int: |
|
|
|
if type(calldata_byte) == int: |
|
|
|
self._calldata.append(BitVecVal(calldata_byte, 8)) |
|
|
|
self._calldata.append(BitVecVal(calldata_byte, 8)) |
|
|
|
else: |
|
|
|
else: |
|
|
|
self._calldata.append(calldata_byte) |
|
|
|
self._calldata.append(calldata_byte) |
|
|
|
constraints.append(self.calldatasize == len(self.starting_calldata)) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
x = BitVec("x", 256) |
|
|
|
|
|
|
|
constraints.append( |
|
|
|
|
|
|
|
ForAll(x, Implies(self[x] != 0, UGT(self.calldatasize, x))) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
return constraints |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def concretized(self, model): |
|
|
|
def concretized(self, model): |
|
|
|
result = [] |
|
|
|
result = [] |
|
|
|
|
|
|
|
|
|
|
|
for i in range( |
|
|
|
for i in range( |
|
|
|
get_concrete_int(model.eval(self.calldatasize, model_completion=True)) |
|
|
|
get_concrete_int(model.eval(self.calldatasize, model_completion=True)) |
|
|
|
): |
|
|
|
): |
|
|
|
result.append(get_concrete_int(model.eval(self[i], model_completion=True))) |
|
|
|
result.append( |
|
|
|
|
|
|
|
get_concrete_int(model.eval(self._calldata[i], model_completion=True)) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
return result |
|
|
|
return result |
|
|
|
|
|
|
|
|
|
|
@ -103,15 +91,23 @@ class Calldata: |
|
|
|
except Z3Exception: |
|
|
|
except Z3Exception: |
|
|
|
raise IndexError("Invalid Calldata Slice") |
|
|
|
raise IndexError("Invalid Calldata Slice") |
|
|
|
|
|
|
|
|
|
|
|
return simplify(Concat(dataparts)) |
|
|
|
values, constraints = zip(*dataparts) |
|
|
|
|
|
|
|
result_constraints = [] |
|
|
|
|
|
|
|
for c in constraints: |
|
|
|
|
|
|
|
result_constraints.extend(c) |
|
|
|
|
|
|
|
return (simplify(Concat(values)), result_constraints) |
|
|
|
|
|
|
|
|
|
|
|
if self.concrete: |
|
|
|
if self.concrete: |
|
|
|
try: |
|
|
|
try: |
|
|
|
return self._calldata[get_concrete_int(item)] |
|
|
|
return (self._calldata[get_concrete_int(item)], ()) |
|
|
|
except IndexError: |
|
|
|
except IndexError: |
|
|
|
return BitVecVal(0, 8) |
|
|
|
return (BitVecVal(0, 8), ()) |
|
|
|
else: |
|
|
|
else: |
|
|
|
return self._calldata[item] |
|
|
|
constraints = [ |
|
|
|
|
|
|
|
Implies(self._calldata[item] != 0, UGT(self.calldatasize, item)) |
|
|
|
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return (self._calldata[item], constraints) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Storage: |
|
|
|
class Storage: |
|
|
|