mirror of https://github.com/ConsenSys/mythril
Add array based implementation of calldata (#778)
* mythril/laser/ethereum/state: add array based implementation * Create symbolic calldata * remove debug statement * Return the concrete calldata, and adapt natives to new calldata pattern * remove debugging statement from test * Move simplifies and remove clean * move simplify to expected place * remove unused test: svm_test.pypull/792/head
parent
5dd544d301
commit
e661eac348
@ -1,122 +0,0 @@ |
||||
import json |
||||
from mythril.analysis.security import get_detection_module_hooks |
||||
from mythril.analysis.symbolic import SymExecWrapper |
||||
from mythril.analysis.callgraph import generate_graph |
||||
from mythril.ethereum.evmcontract import EVMContract |
||||
from mythril.solidity.soliditycontract import SolidityContract |
||||
from mythril.mythril import Mythril |
||||
|
||||
|
||||
from mythril.laser.ethereum.state.account import Account |
||||
from mythril.laser.ethereum.state.machine_state import MachineState |
||||
from mythril.laser.ethereum.state.global_state import GlobalState |
||||
from mythril.laser.ethereum import svm |
||||
from tests import ( |
||||
BaseTestCase, |
||||
TESTDATA_INPUTS_CONTRACTS, |
||||
TESTDATA_OUTPUTS_EXPECTED_LASER_RESULT, |
||||
TESTDATA_OUTPUTS_CURRENT_LASER_RESULT, |
||||
) |
||||
|
||||
|
||||
class LaserEncoder(json.JSONEncoder): |
||||
def default(self, o): |
||||
if getattr(o, "__module__", None) == "z3.z3": |
||||
return str(o) |
||||
return str(o) |
||||
|
||||
|
||||
def _all_info(laser): |
||||
accounts = {} |
||||
for address, _account in laser.world_state.accounts.items(): |
||||
account = _account.as_dict |
||||
account["code"] = account["code"].instruction_list |
||||
account["balance"] = str(account["balance"]) |
||||
accounts[address] = account |
||||
|
||||
nodes = {} |
||||
for uid, node in laser.nodes.items(): |
||||
states = [] |
||||
for state in node.states: |
||||
if isinstance(state, MachineState): |
||||
states.append(state.as_dict) |
||||
elif isinstance(state, GlobalState): |
||||
environment = state.environment.as_dict |
||||
environment["active_account"] = environment["active_account"].address |
||||
states.append( |
||||
{ |
||||
"accounts": state.accounts.keys(), |
||||
"environment": environment, |
||||
"mstate": state.mstate.as_dict, |
||||
} |
||||
) |
||||
|
||||
nodes[uid] = { |
||||
"uid": node.uid, |
||||
"contract_name": node.contract_name, |
||||
"start_addr": node.start_addr, |
||||
"states": states, |
||||
"constraints": node.constraints, |
||||
"function_name": node.function_name, |
||||
"flags": str(node.flags), |
||||
} |
||||
|
||||
edges = [edge.as_dict for edge in laser.edges] |
||||
|
||||
return { |
||||
"accounts": accounts, |
||||
"nodes": nodes, |
||||
"edges": edges, |
||||
"total_states": laser.total_states, |
||||
"max_depth": laser.max_depth, |
||||
} |
||||
|
||||
|
||||
class SVMTestCase(BaseTestCase): |
||||
def setUp(self): |
||||
super(SVMTestCase, self).setUp() |
||||
svm.gbl_next_uid = 0 |
||||
|
||||
def test_laser_result(self): |
||||
for input_file in TESTDATA_INPUTS_CONTRACTS.iterdir(): |
||||
if input_file.name in ["weak_random.sol", "environments.sol"]: |
||||
continue |
||||
output_expected = TESTDATA_OUTPUTS_EXPECTED_LASER_RESULT / ( |
||||
input_file.name + ".json" |
||||
) |
||||
output_current = TESTDATA_OUTPUTS_CURRENT_LASER_RESULT / ( |
||||
input_file.name + ".json" |
||||
) |
||||
|
||||
disassembly = SolidityContract( |
||||
str(input_file), solc_binary=Mythril._init_solc_binary("0.5.0") |
||||
).disassembly |
||||
account = Account("0x0000000000000000000000000000000000000000", disassembly) |
||||
accounts = {account.address: account} |
||||
|
||||
laser = svm.LaserEVM(accounts, max_depth=22, transaction_count=1) |
||||
laser.register_hooks( |
||||
hook_type="post", hook_dict=get_detection_module_hooks() |
||||
) |
||||
laser.sym_exec(account.address) |
||||
laser_info = _all_info(laser) |
||||
|
||||
output_current.write_text( |
||||
json.dumps(laser_info, cls=LaserEncoder, indent=4) |
||||
) |
||||
|
||||
if not (output_expected.read_text() == output_expected.read_text()): |
||||
self.found_changed_files(input_file, output_expected, output_current) |
||||
|
||||
self.assert_and_show_changed_files() |
||||
|
||||
def runTest(self): |
||||
|
||||
code = "0x60606040525b603c5b60006010603e565b9050593681016040523660008237602060003683856040603f5a0204f41560545760206000f35bfe5b50565b005b73c3b2ae46792547a96b9f84405e36d0e07edcd05c5b905600a165627a7a7230582062a884f947232ada573f95940cce9c8bfb7e4e14e21df5af4e884941afb55e590029" |
||||
|
||||
contract = EVMContract(code) |
||||
sym = SymExecWrapper(contract, "0xd0a6E6C543bC68Db5db3A191B171A77407Ff7ccf") |
||||
|
||||
html = generate_graph(sym) |
||||
|
||||
self.assertTrue("0 PUSH1 0x60\\n2 PUSH1 0x40\\n4 MSTORE\\n5 JUMPDEST" in html) |
File diff suppressed because it is too large
Load Diff
@ -1,472 +0,0 @@ |
||||
{ |
||||
"accounts": { |
||||
"0x0000000000000000000000000000000000000000": { |
||||
"storage": "<mythril.laser.ethereum.state.Storage object at 0x7f18fbbcab70>", |
||||
"nonce": 0, |
||||
"balance": "balance", |
||||
"code": [ |
||||
{ |
||||
"address": 0, |
||||
"argument": "0x80", |
||||
"opcode": "PUSH1" |
||||
}, |
||||
{ |
||||
"address": 2, |
||||
"argument": "0x40", |
||||
"opcode": "PUSH1" |
||||
}, |
||||
{ |
||||
"address": 4, |
||||
"opcode": "MSTORE" |
||||
}, |
||||
{ |
||||
"address": 5, |
||||
"argument": "0x00", |
||||
"opcode": "PUSH1" |
||||
}, |
||||
{ |
||||
"address": 7, |
||||
"opcode": "DUP1" |
||||
}, |
||||
{ |
||||
"address": 8, |
||||
"opcode": "REVERT" |
||||
}, |
||||
{ |
||||
"address": 9, |
||||
"opcode": "STOP" |
||||
} |
||||
] |
||||
} |
||||
}, |
||||
"total_states": 5, |
||||
"nodes": { |
||||
"933": { |
||||
"contract_name": "unknown", |
||||
"flags": "NodeFlags()", |
||||
"constraints": [], |
||||
"function_name": "unknown", |
||||
"start_addr": 0, |
||||
"uid": 933, |
||||
"states": [ |
||||
{ |
||||
"accounts": "dict_keys(['0x0000000000000000000000000000000000000000'])", |
||||
"mstate": { |
||||
"gas": 10000000, |
||||
"memory": [], |
||||
"pc": 0, |
||||
"memsize": 0, |
||||
"stack": [] |
||||
}, |
||||
"environment": { |
||||
"sender": "caller", |
||||
"callvalue": "call_value", |
||||
"origin": "origin", |
||||
"active_account": "0x0000000000000000000000000000000000000000", |
||||
"gasprice": "gas_price", |
||||
"calldata": [], |
||||
"calldata_type": "CalldataType.SYMBOLIC" |
||||
} |
||||
}, |
||||
{ |
||||
"accounts": "dict_keys(['0x0000000000000000000000000000000000000000'])", |
||||
"mstate": { |
||||
"gas": 10000000, |
||||
"memory": [], |
||||
"pc": 1, |
||||
"memsize": 0, |
||||
"stack": [ |
||||
"128" |
||||
] |
||||
}, |
||||
"environment": { |
||||
"sender": "caller", |
||||
"callvalue": "call_value", |
||||
"origin": "origin", |
||||
"active_account": "0x0000000000000000000000000000000000000000", |
||||
"gasprice": "gas_price", |
||||
"calldata": [], |
||||
"calldata_type": "CalldataType.SYMBOLIC" |
||||
} |
||||
}, |
||||
{ |
||||
"accounts": "dict_keys(['0x0000000000000000000000000000000000000000'])", |
||||
"mstate": { |
||||
"gas": 10000000, |
||||
"memory": [], |
||||
"pc": 2, |
||||
"memsize": 0, |
||||
"stack": [ |
||||
"128", |
||||
"64" |
||||
] |
||||
}, |
||||
"environment": { |
||||
"sender": "caller", |
||||
"callvalue": "call_value", |
||||
"origin": "origin", |
||||
"active_account": "0x0000000000000000000000000000000000000000", |
||||
"gasprice": "gas_price", |
||||
"calldata": [], |
||||
"calldata_type": "CalldataType.SYMBOLIC" |
||||
} |
||||
}, |
||||
{ |
||||
"accounts": "dict_keys(['0x0000000000000000000000000000000000000000'])", |
||||
"mstate": { |
||||
"gas": 10000000, |
||||
"memory": [ |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
128 |
||||
], |
||||
"pc": 3, |
||||
"memsize": 96, |
||||
"stack": [] |
||||
}, |
||||
"environment": { |
||||
"sender": "caller", |
||||
"callvalue": "call_value", |
||||
"origin": "origin", |
||||
"active_account": "0x0000000000000000000000000000000000000000", |
||||
"gasprice": "gas_price", |
||||
"calldata": [], |
||||
"calldata_type": "CalldataType.SYMBOLIC" |
||||
} |
||||
}, |
||||
{ |
||||
"accounts": "dict_keys(['0x0000000000000000000000000000000000000000'])", |
||||
"mstate": { |
||||
"gas": 10000000, |
||||
"memory": [ |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
128 |
||||
], |
||||
"pc": 4, |
||||
"memsize": 96, |
||||
"stack": [ |
||||
"0" |
||||
] |
||||
}, |
||||
"environment": { |
||||
"sender": "caller", |
||||
"callvalue": "call_value", |
||||
"origin": "origin", |
||||
"active_account": "0x0000000000000000000000000000000000000000", |
||||
"gasprice": "gas_price", |
||||
"calldata": [], |
||||
"calldata_type": "CalldataType.SYMBOLIC" |
||||
} |
||||
}, |
||||
{ |
||||
"accounts": "dict_keys(['0x0000000000000000000000000000000000000000'])", |
||||
"mstate": { |
||||
"gas": 10000000, |
||||
"memory": [ |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
128 |
||||
], |
||||
"pc": 5, |
||||
"memsize": 96, |
||||
"stack": [ |
||||
"0", |
||||
"0" |
||||
] |
||||
}, |
||||
"environment": { |
||||
"sender": "caller", |
||||
"callvalue": "call_value", |
||||
"origin": "origin", |
||||
"active_account": "0x0000000000000000000000000000000000000000", |
||||
"gasprice": "gas_price", |
||||
"calldata": [], |
||||
"calldata_type": "CalldataType.SYMBOLIC" |
||||
} |
||||
} |
||||
] |
||||
} |
||||
}, |
||||
"max_depth": 22, |
||||
"edges": [] |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue