mirror of https://github.com/ConsenSys/mythril
[WIP] Handle exponents (#1497)
* Handle exponents * Bruteforce enumerate constraints * Fix evm tests * Fix imports * Fix z3 version to avoid exception * Fix z3 version to avoid exception * Fix z3 version * Fix z3 version * Hunt the issue * Hunt the issue * Hunt the issue * Hunt the issue * Hunt the issue * Fix issue * Fix issue * Add tests * Black * Fix issue * Fix issue with disassembler test * Fix issue with disassembler testpull/1498/head
parent
d8d469398b
commit
c72d212c7e
@ -0,0 +1,2 @@ |
||||
from .exponent_function_manager import exponent_function_manager |
||||
from .keccak_function_manager import keccak_function_manager |
@ -0,0 +1,74 @@ |
||||
import logging |
||||
from typing import Dict, List, Optional, Tuple |
||||
|
||||
from ethereum import utils |
||||
|
||||
from mythril.laser.smt import ( |
||||
And, |
||||
BitVec, |
||||
Bool, |
||||
Function, |
||||
URem, |
||||
symbol_factory, |
||||
) |
||||
|
||||
log = logging.getLogger(__name__) |
||||
|
||||
|
||||
class ExponentFunctionManager: |
||||
""" |
||||
Uses an uninterpreted function for exponentiation with the following properties: |
||||
1) power(a, b) > 0 |
||||
2) if a = 256 => forall i if b = i then power(a, b) = (256 ^ i) % (2^256) |
||||
|
||||
Only these two properties are added as to handle indexing of boolean arrays. |
||||
Caution should be exercised when increasing the conditions since it severely affects |
||||
the solving time. |
||||
""" |
||||
|
||||
def __init__(self): |
||||
power = Function("Power", [256, 256], 256) |
||||
NUMBER_256 = symbol_factory.BitVecVal(256, 256) |
||||
self.concrete_constraints = And( |
||||
*[ |
||||
power(NUMBER_256, symbol_factory.BitVecVal(i, 256)) |
||||
== symbol_factory.BitVecVal(256 ** i, 256) |
||||
for i in range(0, 32) |
||||
] |
||||
) |
||||
self.concrete_constraints_sent = False |
||||
|
||||
def create_condition(self, base: BitVec, exponent: BitVec) -> Tuple[BitVec, Bool]: |
||||
""" |
||||
Creates a condition for exponentiation |
||||
:param base: The base of exponentiation |
||||
:param exponent: The exponent of the exponentiation |
||||
:return: Tuple of condition and the exponentiation result |
||||
""" |
||||
power = Function("Power", [256, 256], 256) |
||||
exponentiation = power(base, exponent) |
||||
|
||||
if exponent.symbolic is False and base.symbolic is False: |
||||
const_exponentiation = symbol_factory.BitVecVal( |
||||
pow(base.value, exponent.value, 2 ** 256), |
||||
256, |
||||
annotations=base.annotations.union(exponent.annotations), |
||||
) |
||||
constraint = const_exponentiation == exponentiation |
||||
return const_exponentiation, constraint |
||||
|
||||
constraint = exponentiation > 0 |
||||
if self.concrete_constraints_sent is False: |
||||
constraint = And(constraint, self.concrete_constraints) |
||||
self.concrete_constraints_sent = True |
||||
if base.value == 256: |
||||
constraint = And( |
||||
constraint, |
||||
power(base, URem(exponent, symbol_factory.BitVecVal(32, 256))) |
||||
== power(base, exponent), |
||||
) |
||||
|
||||
return exponentiation, constraint |
||||
|
||||
|
||||
exponent_function_manager = ExponentFunctionManager() |
@ -0,0 +1,33 @@ |
||||
import pytest |
||||
import json |
||||
import sys |
||||
|
||||
from subprocess import check_output |
||||
from tests import PROJECT_DIR, TESTDATA |
||||
|
||||
MYTH = str(PROJECT_DIR / "myth") |
||||
test_data = ( |
||||
( |
||||
"flag_array.sol.o", |
||||
{ |
||||
"TX_COUNT": 1, |
||||
"TX_OUTPUT": 1, |
||||
"MODULE": "EtherThief", |
||||
"ISSUE_COUNT": 1, |
||||
"ISSUE_NUMBER": 0, |
||||
}, |
||||
"0xab12585800000000000000000000000000000000000000000000000000000000000004d2", |
||||
), |
||||
) |
||||
|
||||
|
||||
@pytest.mark.parametrize("file_name, tx_data, calldata", test_data) |
||||
def test_analysis(file_name, tx_data, calldata): |
||||
bytecode_file = str(TESTDATA / "inputs" / file_name) |
||||
command = f"""python3 {MYTH} analyze -f {bytecode_file} -t {tx_data["TX_COUNT"]} -o jsonv2 -m {tx_data["MODULE"]} --solver-timeout 60000""" |
||||
output = json.loads(check_output(command, shell=True).decode("UTF-8")) |
||||
|
||||
assert len(output[0]["issues"]) == tx_data["ISSUE_COUNT"] |
||||
test_case = output[0]["issues"][tx_data["ISSUE_NUMBER"]]["extra"]["testCases"][0] |
||||
print(test_case["steps"]) |
||||
assert test_case["steps"][tx_data["TX_OUTPUT"]]["input"] == calldata |
@ -0,0 +1,17 @@ |
||||
pragma solidity ^0.8.0; |
||||
|
||||
contract BasicLiquidation { |
||||
bool[4096] _flags; |
||||
constructor() payable |
||||
{ |
||||
require(msg.value == 0.1 ether); |
||||
_flags[1234] = true; |
||||
} |
||||
function extractMoney(uint256 idx) public payable |
||||
{ |
||||
require(idx >= 0); |
||||
require(idx < 4096); |
||||
require(_flags[idx]); |
||||
payable(msg.sender).transfer(address(this).balance); |
||||
} |
||||
} |
@ -0,0 +1 @@ |
||||
608060405267016345785d8a0000341461001857600080fd5b600160006104d2611000811061003157610030610055565b5b602091828204019190066101000a81548160ff021916908315150217905550610084565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6101a6806100936000396000f3fe60806040526004361061001e5760003560e01c8063ab12585814610023575b600080fd5b61003d600480360381019061003891906100ee565b61003f565b005b600081101561004d57600080fd5b611000811061005b57600080fd5b60008161100081106100705761006f610125565b5b602091828204019190069054906101000a900460ff1661008f57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f193505050501580156100d5573d6000803e3d6000fd5b5050565b6000813590506100e881610159565b92915050565b60006020828403121561010457610103610154565b5b6000610112848285016100d9565b91505092915050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b6101628161011b565b811461016d57600080fd5b5056fea264697066735822122038d1a63a64c5408c7008a0f3746ab94e43a04b5bc74f52e4869d3f15cf5b2b9e64736f6c63430008060033 |
Loading…
Reference in new issue