|
|
@ -1,8 +1,8 @@ |
|
|
|
from typing import Union, overload, List, Set, cast, Any, Optional, Callable |
|
|
|
from typing import Union, overload, List, Set, cast, Any, Callable |
|
|
|
import z3 |
|
|
|
import z3 |
|
|
|
|
|
|
|
|
|
|
|
from mythril.laser.smt.bool import Bool, And, Or |
|
|
|
from mythril.laser.smt.bool import Bool, Or |
|
|
|
from mythril.laser.smt.bitvec import BitVec |
|
|
|
from mythril.laser.smt.bitvec import BitVec, BitVecExtract |
|
|
|
from mythril.laser.smt.bitvecfunc import BitVecFunc |
|
|
|
from mythril.laser.smt.bitvecfunc import BitVecFunc |
|
|
|
from mythril.laser.smt.bitvecfunc import BitVecFuncExtract |
|
|
|
from mythril.laser.smt.bitvecfunc import BitVecFuncExtract |
|
|
|
from mythril.laser.smt.bitvecfunc import _arithmetic_helper as _func_arithmetic_helper |
|
|
|
from mythril.laser.smt.bitvecfunc import _arithmetic_helper as _func_arithmetic_helper |
|
|
@ -109,6 +109,10 @@ def ULE(a: BitVec, b: BitVec) -> Bool: |
|
|
|
return Or(ULT(a, b), a == b) |
|
|
|
return Or(ULT(a, b), a == b) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def check_extracted_var(bv: BitVec): |
|
|
|
|
|
|
|
return isinstance(bv, BitVecFuncExtract) or isinstance(bv, BitVecExtract) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@overload |
|
|
|
@overload |
|
|
|
def Concat(*args: List[BitVec]) -> BitVec: |
|
|
|
def Concat(*args: List[BitVec]) -> BitVec: |
|
|
|
... |
|
|
|
... |
|
|
@ -131,65 +135,43 @@ def Concat(*args: Union[BitVec, List[BitVec]]) -> BitVec: |
|
|
|
else: |
|
|
|
else: |
|
|
|
bvs = cast(List[BitVec], args) |
|
|
|
bvs = cast(List[BitVec], args) |
|
|
|
|
|
|
|
|
|
|
|
concat_list = bvs |
|
|
|
|
|
|
|
nraw = z3.Concat([a.raw for a in bvs]) |
|
|
|
nraw = z3.Concat([a.raw for a in bvs]) |
|
|
|
annotations = set() # type: Annotations |
|
|
|
annotations = set() # type: Annotations |
|
|
|
|
|
|
|
|
|
|
|
nested_functions = [] # type: List[BitVecFunc] |
|
|
|
nested_functions = [] # type: List[BitVecFunc] |
|
|
|
bfne_cnt = 0 |
|
|
|
|
|
|
|
parent = None |
|
|
|
|
|
|
|
for bv in bvs: |
|
|
|
for bv in bvs: |
|
|
|
annotations = annotations.union(bv.annotations) |
|
|
|
annotations = annotations.union(bv.annotations) |
|
|
|
if isinstance(bv, BitVecFunc): |
|
|
|
if isinstance(bv, BitVecFunc): |
|
|
|
nested_functions += bv.nested_functions |
|
|
|
nested_functions += bv.nested_functions |
|
|
|
nested_functions += [bv] |
|
|
|
nested_functions += [bv] |
|
|
|
if isinstance(bv, BitVecFuncExtract): |
|
|
|
new_bvs = [] |
|
|
|
if parent is None: |
|
|
|
prev_bv = bvs[0] |
|
|
|
parent = bv.parent |
|
|
|
# casting everywhere in if's looks quite messy, so I am type ignoring |
|
|
|
if hash(parent.raw) != hash(bv.parent.raw): |
|
|
|
for bv in bvs[1:]: |
|
|
|
continue |
|
|
|
if ( |
|
|
|
bfne_cnt += 1 |
|
|
|
not check_extracted_var(bv) |
|
|
|
|
|
|
|
or bv.high + 1 != prev_bv.low # type: ignore |
|
|
|
if bfne_cnt == len(bvs): |
|
|
|
or bv.parent != prev_bv.parent # type: ignore |
|
|
|
# check for continuity |
|
|
|
): |
|
|
|
fail = True |
|
|
|
if check_extracted_var(prev_bv) and hash(prev_bv) == hash( |
|
|
|
if bvs[-1].low == 0: |
|
|
|
prev_bv.parent |
|
|
|
fail = False |
|
|
|
): # type: ignore |
|
|
|
for index, bv in enumerate(bvs): |
|
|
|
new_bvs.append(prev_bv.parent) # type: ignore |
|
|
|
if index == 0: |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
if bv.high + 1 != bvs[index - 1].low: |
|
|
|
|
|
|
|
fail = True |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if fail is False: |
|
|
|
|
|
|
|
if bvs[0].high == bvs[0].parent.size() - 1: |
|
|
|
|
|
|
|
return bvs[0].parent |
|
|
|
|
|
|
|
else: |
|
|
|
else: |
|
|
|
return BitVecFuncExtract( |
|
|
|
new_bvs.append(prev_bv) |
|
|
|
raw=nraw, |
|
|
|
prev_bv = bv |
|
|
|
func_name=bvs[0].func_name, |
|
|
|
continue |
|
|
|
input_=bvs[0].input_, |
|
|
|
prev_bv = Concat(prev_bv, bv) |
|
|
|
nested_functions=nested_functions, |
|
|
|
new_bvs.append(prev_bv) |
|
|
|
concat_args=concat_list, |
|
|
|
|
|
|
|
low=bvs[-1].low, |
|
|
|
|
|
|
|
high=bvs[0].high, |
|
|
|
|
|
|
|
parent=bvs[0].parent, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if nested_functions: |
|
|
|
if nested_functions: |
|
|
|
for bv in bvs: |
|
|
|
|
|
|
|
bv.simplify() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return BitVecFunc( |
|
|
|
return BitVecFunc( |
|
|
|
raw=nraw, |
|
|
|
raw=nraw, |
|
|
|
func_name="Hybrid", |
|
|
|
func_name="Hybrid", |
|
|
|
input_=BitVec(z3.BitVec("", 256), annotations=annotations), |
|
|
|
input_=BitVec(z3.BitVec("", 256), annotations=annotations), |
|
|
|
nested_functions=nested_functions, |
|
|
|
nested_functions=nested_functions, |
|
|
|
concat_args=concat_list, |
|
|
|
concat_args=new_bvs, |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
return BitVec(raw=nraw, annotations=annotations, concat_args=new_bvs) |
|
|
|
return BitVec(nraw, annotations) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def Extract(high: int, low: int, bv: BitVec) -> BitVec: |
|
|
|
def Extract(high: int, low: int, bv: BitVec) -> BitVec: |
|
|
@ -202,7 +184,6 @@ def Extract(high: int, low: int, bv: BitVec) -> BitVec: |
|
|
|
""" |
|
|
|
""" |
|
|
|
|
|
|
|
|
|
|
|
raw = z3.Extract(high, low, bv.raw) |
|
|
|
raw = z3.Extract(high, low, bv.raw) |
|
|
|
if isinstance(bv, BitVecFunc): |
|
|
|
|
|
|
|
count = 0 |
|
|
|
count = 0 |
|
|
|
val = None |
|
|
|
val = None |
|
|
|
for small_bv in bv.concat_args[::-1]: |
|
|
|
for small_bv in bv.concat_args[::-1]: |
|
|
@ -211,9 +192,7 @@ def Extract(high: int, low: int, bv: BitVec) -> BitVec: |
|
|
|
val = small_bv |
|
|
|
val = small_bv |
|
|
|
else: |
|
|
|
else: |
|
|
|
val = Extract( |
|
|
|
val = Extract( |
|
|
|
small_bv.size() - 1, |
|
|
|
small_bv.size() - 1, small_bv.size() - (high - low + 1), small_bv |
|
|
|
small_bv.size() - (high - low + 1), |
|
|
|
|
|
|
|
small_bv, |
|
|
|
|
|
|
|
) |
|
|
|
) |
|
|
|
elif high < count: |
|
|
|
elif high < count: |
|
|
|
break |
|
|
|
break |
|
|
@ -231,14 +210,14 @@ def Extract(high: int, low: int, bv: BitVec) -> BitVec: |
|
|
|
) |
|
|
|
) |
|
|
|
count += small_bv.size() |
|
|
|
count += small_bv.size() |
|
|
|
if val is not None: |
|
|
|
if val is not None: |
|
|
|
if isinstance(val, BitVecFuncExtract) and z3.simplify( |
|
|
|
|
|
|
|
val.raw == val.parent.raw |
|
|
|
|
|
|
|
): |
|
|
|
|
|
|
|
val = val.parent |
|
|
|
|
|
|
|
val.simplify() |
|
|
|
val.simplify() |
|
|
|
|
|
|
|
bv.simplify() |
|
|
|
|
|
|
|
if check_extracted_var(val) and hash(val.raw) == hash(val.parent.raw): |
|
|
|
|
|
|
|
val = val.parent |
|
|
|
return val |
|
|
|
return val |
|
|
|
input_string = "" |
|
|
|
input_string = "" |
|
|
|
# Is there a better value to set func_name and input to in this case? |
|
|
|
bv.simplify() |
|
|
|
|
|
|
|
if isinstance(bv, BitVecFunc): |
|
|
|
return BitVecFuncExtract( |
|
|
|
return BitVecFuncExtract( |
|
|
|
raw=raw, |
|
|
|
raw=raw, |
|
|
|
func_name="Hybrid", |
|
|
|
func_name="Hybrid", |
|
|
@ -248,8 +227,8 @@ def Extract(high: int, low: int, bv: BitVec) -> BitVec: |
|
|
|
high=high, |
|
|
|
high=high, |
|
|
|
parent=bv, |
|
|
|
parent=bv, |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
else: |
|
|
|
return BitVec(raw, annotations=bv.annotations) |
|
|
|
return BitVecExtract(raw=raw, low=low, high=high, parent=bv) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def URem(a: BitVec, b: BitVec) -> BitVec: |
|
|
|
def URem(a: BitVec, b: BitVec) -> BitVec: |
|
|
|