From 524c10a8c8537a72589aa33a7a5269b5f12684ea Mon Sep 17 00:00:00 2001 From: Dominik Muhs Date: Sun, 28 Oct 2018 14:21:46 +0100 Subject: [PATCH] Merge develop into dmuhs/type-hints --- .circleci/config.yml | 6 + README.md | 31 +- .../modules/dependence_on_predictable_vars.py | 9 +- mythril/analysis/modules/ether_send.py | 184 ++------ mythril/analysis/modules/exceptions.py | 3 +- mythril/analysis/modules/integer.py | 12 +- mythril/analysis/modules/multiple_sends.py | 7 +- mythril/analysis/modules/suicide.py | 5 +- .../modules/transaction_order_dependence.py | 6 +- mythril/analysis/solver.py | 6 +- mythril/analysis/symbolic.py | 7 +- mythril/analysis/traceexplore.py | 7 +- mythril/disassembler/disassembly.py | 107 +++-- mythril/ether/ethcontract.py | 2 +- mythril/ether/evm.py | 27 +- .../interface/leveldb/accountindexing.py | 17 +- mythril/ethereum/interface/leveldb/client.py | 61 +-- mythril/ethereum/interface/leveldb/state.py | 32 +- mythril/interfaces/cli.py | 38 +- mythril/laser/ethereum/call.py | 26 +- mythril/laser/ethereum/cfg.py | 2 + mythril/laser/ethereum/instructions.py | 109 +---- mythril/laser/ethereum/keccak.py | 1 + mythril/laser/ethereum/natives.py | 2 +- mythril/laser/ethereum/state.py | 104 ++++- mythril/laser/ethereum/strategy/__init__.py | 25 + mythril/laser/ethereum/strategy/basic.py | 96 ++-- mythril/laser/ethereum/svm.py | 10 +- mythril/laser/ethereum/taint_analysis.py | 1 + .../laser/ethereum/transaction/concolic.py | 6 +- .../laser/ethereum/transaction/symbolic.py | 4 +- .../transaction/transaction_models.py | 21 +- mythril/laser/ethereum/util.py | 13 +- mythril/mythril.py | 32 +- mythril/support/signatures.py | 8 +- requirements.txt | 1 + setup.py | 1 + static/mythril.png | Bin 22977 -> 0 bytes static/mythril_new.png | Bin 0 -> 19672 bytes tests/analysis/test_delegatecall.py | 2 +- tests/cmd_line_test.py | 5 +- tests/disassembler/__init__.py | 0 tests/disassembler/disassembly.py | 61 +++ tests/laser/evm_testsuite/evm_test.py | 9 +- tests/laser/state/calldata_test.py | 102 ++++ tests/laser/state/mstack_test.py | 2 +- tests/laser/transaction/symbolic_test.py | 2 +- tests/report_test.py | 6 +- tests/svm_test.py | 2 +- .../outputs_expected/calls.sol.o.graph.html | 10 +- .../outputs_expected/calls.sol.o.json | 2 +- .../outputs_expected/calls.sol.o.markdown | 2 +- .../outputs_expected/calls.sol.o.text | 2 +- .../environments.sol.o.graph.html | 10 +- .../ether_send.sol.o.graph.html | 10 +- .../outputs_expected/ether_send.sol.o.json | 2 +- .../ether_send.sol.o.markdown | 7 +- .../outputs_expected/ether_send.sol.o.text | 8 +- .../exceptions.sol.o.graph.html | 10 +- .../outputs_expected/exceptions.sol.o.json | 2 +- .../exceptions.sol.o.markdown | 8 +- .../outputs_expected/exceptions.sol.o.text | 8 +- .../kinds_of_calls.sol.o.graph.html | 10 +- .../metacoin.sol.o.graph.html | 10 +- .../multi_contracts.sol.o.graph.html | 10 +- .../multi_contracts.sol.o.json | 2 +- .../multi_contracts.sol.o.markdown | 3 +- .../multi_contracts.sol.o.text | 3 +- .../nonascii.sol.o.graph.html | 10 +- .../outputs_expected/origin.sol.o.graph.html | 10 +- .../outputs_expected/origin.sol.o.json | 2 +- .../outputs_current/calls.sol.o.easm | 400 ++++++++++++++++ .../outputs_current/calls.sol.o.graph.html | 62 +++ .../outputs_current/calls.sol.o.json | 1 + .../outputs_current/calls.sol.o.markdown | 111 +++++ .../outputs_current/calls.sol.o.text | 90 ++++ .../outputs_current/environments.sol.o.easm | 259 +++++++++++ .../environments.sol.o.graph.html | 62 +++ .../outputs_current/ether_send.sol.o.easm | 420 +++++++++++++++++ .../ether_send.sol.o.graph.html | 62 +++ .../outputs_current/ether_send.sol.o.json | 1 + .../outputs_current/ether_send.sol.o.markdown | 23 + .../outputs_current/ether_send.sol.o.text | 19 + .../outputs_current/exceptions.sol.o.easm | 392 ++++++++++++++++ .../exceptions.sol.o.graph.html | 62 +++ .../outputs_current/exceptions.sol.o.json | 1 + .../outputs_current/exceptions.sol.o.markdown | 45 ++ .../outputs_current/exceptions.sol.o.text | 36 ++ .../outputs_current/kinds_of_calls.sol.o.easm | 435 ++++++++++++++++++ .../kinds_of_calls.sol.o.graph.html | 62 +++ .../outputs_current/kinds_of_calls.sol.o.json | 1 + .../kinds_of_calls.sol.o.markdown | 45 ++ .../outputs_current/kinds_of_calls.sol.o.text | 36 ++ .../outputs_current/metacoin.sol.o.easm | 253 ++++++++++ .../outputs_current/metacoin.sol.o.graph.html | 62 +++ .../outputs_current/metacoin.sol.o.json | 1 + .../outputs_current/metacoin.sol.o.markdown | 3 + .../outputs_current/metacoin.sol.o.text | 1 + .../multi_contracts.sol.o.easm | 77 ++++ .../multi_contracts.sol.o.graph.html | 62 +++ .../multi_contracts.sol.o.json | 1 + .../multi_contracts.sol.o.markdown | 12 + .../multi_contracts.sol.o.text | 9 + .../outputs_current/nonascii.sol.o.easm | 167 +++++++ .../outputs_current/nonascii.sol.o.graph.html | 62 +++ .../outputs_current/nonascii.sol.o.json | 1 + .../outputs_current/nonascii.sol.o.markdown | 3 + .../outputs_current/nonascii.sol.o.text | 1 + .../outputs_current/origin.sol.o.easm | 168 +++++++ .../outputs_current/origin.sol.o.graph.html | 62 +++ .../outputs_current/origin.sol.o.json | 1 + .../outputs_current/origin.sol.o.markdown | 13 + .../outputs_current/origin.sol.o.text | 10 + .../outputs_current/overflow.sol.o.easm | 388 ++++++++++++++++ .../outputs_current/overflow.sol.o.graph.html | 62 +++ .../outputs_current/overflow.sol.o.json | 1 + .../outputs_current/overflow.sol.o.markdown | 34 ++ .../outputs_current/overflow.sol.o.text | 30 ++ .../outputs_current/returnvalue.sol.o.easm | 129 ++++++ .../returnvalue.sol.o.graph.html | 62 +++ .../outputs_current/returnvalue.sol.o.json | 1 + .../returnvalue.sol.o.markdown | 34 ++ .../outputs_current/returnvalue.sol.o.text | 27 ++ .../outputs_current/suicide.sol.o.easm | 58 +++ .../outputs_current/suicide.sol.o.graph.html | 62 +++ .../outputs_current/suicide.sol.o.json | 1 + .../outputs_current/suicide.sol.o.markdown | 12 + .../outputs_current/suicide.sol.o.text | 10 + .../outputs_current/underflow.sol.o.easm | 365 +++++++++++++++ .../underflow.sol.o.graph.html | 62 +++ .../outputs_current/underflow.sol.o.json | 1 + .../outputs_current/underflow.sol.o.markdown | 34 ++ .../outputs_current/underflow.sol.o.text | 30 ++ .../overflow.sol.o.graph.html | 10 +- .../outputs_expected/overflow.sol.o.json | 2 +- .../outputs_expected/overflow.sol.o.markdown | 9 +- .../outputs_expected/overflow.sol.o.text | 12 +- .../returnvalue.sol.o.graph.html | 10 +- .../outputs_expected/suicide.sol.o.graph.html | 10 +- .../outputs_expected/suicide.sol.o.json | 2 +- .../outputs_expected/suicide.sol.o.markdown | 2 +- .../outputs_expected/suicide.sol.o.text | 2 +- .../underflow.sol.o.graph.html | 10 +- .../outputs_expected/underflow.sol.o.json | 2 +- .../outputs_expected/underflow.sol.o.markdown | 9 +- .../outputs_expected/underflow.sol.o.text | 12 +- 146 files changed, 5851 insertions(+), 599 deletions(-) delete mode 100644 static/mythril.png create mode 100644 static/mythril_new.png create mode 100644 tests/disassembler/__init__.py create mode 100644 tests/disassembler/disassembly.py create mode 100644 tests/laser/state/calldata_test.py create mode 100644 tests/testdata/outputs_expected/outputs_current/calls.sol.o.easm create mode 100644 tests/testdata/outputs_expected/outputs_current/calls.sol.o.graph.html create mode 100644 tests/testdata/outputs_expected/outputs_current/calls.sol.o.json create mode 100644 tests/testdata/outputs_expected/outputs_current/calls.sol.o.markdown create mode 100644 tests/testdata/outputs_expected/outputs_current/calls.sol.o.text create mode 100644 tests/testdata/outputs_expected/outputs_current/environments.sol.o.easm create mode 100644 tests/testdata/outputs_expected/outputs_current/environments.sol.o.graph.html create mode 100644 tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.easm create mode 100644 tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.graph.html create mode 100644 tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.json create mode 100644 tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.markdown create mode 100644 tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.text create mode 100644 tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.easm create mode 100644 tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.graph.html create mode 100644 tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.json create mode 100644 tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.markdown create mode 100644 tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.text create mode 100644 tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.easm create mode 100644 tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.graph.html create mode 100644 tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.json create mode 100644 tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.markdown create mode 100644 tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.text create mode 100644 tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.easm create mode 100644 tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.graph.html create mode 100644 tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.json create mode 100644 tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.markdown create mode 100644 tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.text create mode 100644 tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.easm create mode 100644 tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.graph.html create mode 100644 tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.json create mode 100644 tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.markdown create mode 100644 tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.text create mode 100644 tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.easm create mode 100644 tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.graph.html create mode 100644 tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.json create mode 100644 tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.markdown create mode 100644 tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.text create mode 100644 tests/testdata/outputs_expected/outputs_current/origin.sol.o.easm create mode 100644 tests/testdata/outputs_expected/outputs_current/origin.sol.o.graph.html create mode 100644 tests/testdata/outputs_expected/outputs_current/origin.sol.o.json create mode 100644 tests/testdata/outputs_expected/outputs_current/origin.sol.o.markdown create mode 100644 tests/testdata/outputs_expected/outputs_current/origin.sol.o.text create mode 100644 tests/testdata/outputs_expected/outputs_current/overflow.sol.o.easm create mode 100644 tests/testdata/outputs_expected/outputs_current/overflow.sol.o.graph.html create mode 100644 tests/testdata/outputs_expected/outputs_current/overflow.sol.o.json create mode 100644 tests/testdata/outputs_expected/outputs_current/overflow.sol.o.markdown create mode 100644 tests/testdata/outputs_expected/outputs_current/overflow.sol.o.text create mode 100644 tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.easm create mode 100644 tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.graph.html create mode 100644 tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.json create mode 100644 tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.markdown create mode 100644 tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.text create mode 100644 tests/testdata/outputs_expected/outputs_current/suicide.sol.o.easm create mode 100644 tests/testdata/outputs_expected/outputs_current/suicide.sol.o.graph.html create mode 100644 tests/testdata/outputs_expected/outputs_current/suicide.sol.o.json create mode 100644 tests/testdata/outputs_expected/outputs_current/suicide.sol.o.markdown create mode 100644 tests/testdata/outputs_expected/outputs_current/suicide.sol.o.text create mode 100644 tests/testdata/outputs_expected/outputs_current/underflow.sol.o.easm create mode 100644 tests/testdata/outputs_expected/outputs_current/underflow.sol.o.graph.html create mode 100644 tests/testdata/outputs_expected/outputs_current/underflow.sol.o.json create mode 100644 tests/testdata/outputs_expected/outputs_current/underflow.sol.o.markdown create mode 100644 tests/testdata/outputs_expected/outputs_current/underflow.sol.o.text diff --git a/.circleci/config.yml b/.circleci/config.yml index 351fc89b..fc14bfc8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -33,6 +33,12 @@ jobs: - .tox/py* - /root/.cache/pip/wheels/ + - run: + name: Black style check + command: | + pip3 install --user black + python3 -m black --check /home/mythril/ + - run: background: true name: Launch of background geth instance diff --git a/README.md b/README.md index c5fbd20f..4b975def 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,21 @@ -# Mythril OSS [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Mythril%20-%20Security%20Analyzer%20for%20Ethereum%20Smart%20Contracts&url=https://www.github.com/ConsenSys/mythril) +# Mythril Classic + +

+ +

+ [![Discord](https://img.shields.io/discord/481002907366588416.svg)](https://discord.gg/E3YrVtG) [![PyPI](https://badge.fury.io/py/mythril.svg)](https://pypi.python.org/pypi/mythril) -![Master Build Status](https://img.shields.io/circleci/project/github/ConsenSys/mythril/master.svg) -[![Waffle.io - Columns and their card count](https://badge.waffle.io/ConsenSys/mythril.svg?columns=In%20Progress)](https://waffle.io/ConsenSys/mythril) +![Master Build Status](https://img.shields.io/circleci/project/github/ConsenSys/mythril-classic/master.svg) +[![Waffle.io - Columns and their card count](https://badge.waffle.io/ConsenSys/mythril-classic.svg?columns=In%20Progress)](https://waffle.io/ConsenSys/mythril-classic/) [![Sonarcloud - Maintainability](https://sonarcloud.io/api/project_badges/measure?project=mythril&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=mythril) [![PyPI Statistics](https://pypistats.com/badge/mythril.svg)](https://pypistats.com/package/mythril) -mythril -Mythril OSS is the classic security analysis tool for Ethereum smart contracts. It uses concolic analysis, taint analysis and control flow checking to detect a variety of security vulnerabilities. +Mythril Classic is an open-source security analysis tool for Ethereum smart contracts. It uses concolic analysis, taint analysis and control flow checking to detect a variety of security vulnerabilities. -Whether you want to contribute, need support, or want to learn what we have cooking for the future, our [Discord server](https://discord.gg/E3YrVtG) will serve your needs! +Whether you want to contribute, need support, or want to learn what we have cooking for the future, our [Discord server](https://discord.gg/E3YrVtG) will serve your needs. -Oh and by the way, we're building an easy-to-use SaaS solution and tools ecosystem for Ethereum developers called [Mythril Platform](https://mythril.ai). You should definitely check that out as well. +Oh and by the way, we're also building an easy-to-use security analysis platform (a.k.a. "the INFURA for smart contract security") that anybody can use to create purpose-built security tools. It's called [Mythril Platform](https://mythril.ai) and you should definitely [check it out](https://media.consensys.net/mythril-platform-api-is-upping-the-smart-contract-security-game-eee1d2642488). ## Installation and setup @@ -31,21 +35,10 @@ See the [Wiki](https://github.com/ConsenSys/mythril/wiki/Installation-and-Setup) ## Usage -Instructions for using the 'myth' tool are found on the [Wiki](https://github.com/ConsenSys/mythril/wiki). +Instructions for using Mythril Classic are found on the [Wiki](https://github.com/ConsenSys/mythril-classic/wiki). For support or general discussions please join the Mythril community on [Discord](https://discord.gg/E3YrVtG). ## Vulnerability Remediation Visit the [Smart Contract Vulnerability Classification Registry](https://smartcontractsecurity.github.io/SWC-registry/) to find detailed information and remediation guidance for the vulnerabilities reported. - -## Presentations, papers and articles - -- [Analyzing Ethereum Smart Contracts for Vulnerabilities](https://hackernoon.com/scanning-ethereum-smart-contracts-for-vulnerabilities-b5caefd995df) -- [What Caused the Parity SUICIDE Vulnerability & How to Detect Similar Bugs](https://hackernoon.com/what-caused-the-latest-100-million-ethereum-bug-and-a-detection-tool-for-similar-bugs-7b80f8ab7279) -- [Detecting Integer Overflows in Ethereum Smart Contracts](https://media.consensys.net/detecting-batchoverflow-and-similar-flaws-in-ethereum-smart-contracts-93cf5a5aaac8) -- [How Formal Verification Can Ensure Flawless Smart Contracts](https://media.consensys.net/how-formal-verification-can-ensure-flawless-smart-contracts-cbda8ad99bd1) -- [Smashing Smart Contracts for Fun and Real Profit](https://hackernoon.com/hitb2018ams-smashing-smart-contracts-for-fun-and-real-profit-720f5e3ac777) -- [HITBSecConf 2018 - Presentation video](https://www.youtube.com/watch?v=iqf6epACgds) -- [EDCon Toronto 2018 - Mythril: Find bugs and verify security properties in your contracts](https://www.youtube.com/watch?v=NJ9StJThxZY&feature=youtu.be&t=3h3m18s) - diff --git a/mythril/analysis/modules/dependence_on_predictable_vars.py b/mythril/analysis/modules/dependence_on_predictable_vars.py index f3fcf41a..12172982 100644 --- a/mythril/analysis/modules/dependence_on_predictable_vars.py +++ b/mythril/analysis/modules/dependence_on_predictable_vars.py @@ -156,12 +156,11 @@ def solve(call): try: model = solver.get_model(call.node.constraints) logging.debug("[DEPENDENCE_ON_PREDICTABLE_VARS] MODEL: " + str(model)) + pretty_model = solver.pretty_print_model(model) - for d in model.decls(): - logging.debug( - "[DEPENDENCE_ON_PREDICTABLE_VARS] main model: %s = 0x%x" - % (d.name(), model[d].as_long()) - ) + logging.debug( + "[DEPENDENCE_ON_PREDICTABLE_VARS] main model: \n%s" % pretty_model + ) return True except UnsatError: diff --git a/mythril/analysis/modules/ether_send.py b/mythril/analysis/modules/ether_send.py index fa967f2f..ae723333 100644 --- a/mythril/analysis/modules/ether_send.py +++ b/mythril/analysis/modules/ether_send.py @@ -1,10 +1,8 @@ -from z3 import * from mythril.analysis.ops import * from mythril.analysis import solver from mythril.analysis.report import Issue from mythril.analysis.swc_data import UNPROTECTED_ETHER_WITHDRAWAL from mythril.exceptions import UnsatError -import re import logging @@ -17,147 +15,63 @@ to that index). """ -def execute(statespace): +def execute(state_space): logging.debug("Executing module: ETHER_SEND") issues = [] - for call in statespace.calls: + for k in state_space.nodes: + node = state_space.nodes[k] - state = call.state - address = state.get_current_instruction()["address"] + for state in node.states: + issues += _analyze_state(state, node) - if "callvalue" in str(call.value): - logging.debug("[ETHER_SEND] Skipping refund function") - continue - - # We're only interested in calls that send Ether - - if call.value.type == VarType.CONCRETE and call.value.val == 0: - continue - - interesting = False - - description = "In the function `" + call.node.function_name + "` " - - if re.search(r"caller", str(call.to)): - description += "a non-zero amount of Ether is sent to msg.sender.\n" - interesting = True - - elif re.search(r"calldata", str(call.to)): - description += "a non-zero amount of Ether is sent to an address taken from function arguments.\n" - interesting = True - - else: - m = re.search(r"storage_([a-z0-9_&^]+)", str(call.to)) - - if m: - idx = m.group(1) - - description += ( - "a non-zero amount of Ether is sent to an address taken from storage slot " - + str(idx) - + ".\n" - ) - - func = statespace.find_storage_write( - state.environment.active_account.address, idx - ) - - if func: - description += ( - "There is a check on storage index " - + str(idx) - + ". This storage slot can be written to by calling the function `" - + func - + "`.\n" - ) - interesting = True - else: - logging.debug("[ETHER_SEND] No storage writes to index " + str(idx)) - - if interesting: - - node = call.node - - can_solve = True - constrained = False - - index = 0 - - while can_solve and index < len(node.constraints): - - constraint = node.constraints[index] - index += 1 - logging.debug("[ETHER_SEND] Constraint: " + str(constraint)) - - m = re.search(r"storage_([a-z0-9_&^]+)", str(constraint)) - - if m: - - constrained = True - idx = m.group(1) - - func = statespace.find_storage_write( - state.environment.active_account.address, idx - ) - - if func: - description += ( - "\nThere is a check on storage index " - + str(idx) - + ". This storage slot can be written to by calling the function `" - + func - + "`." - ) - else: - logging.debug( - "[ETHER_SEND] No storage writes to index " + str(idx) - ) - can_solve = False - break + return issues - # CALLER may also be constrained to hardcoded address. I.e. 'caller' and some integer - elif re.search(r"caller", str(constraint)) and re.search( - r"[0-9]{20}", str(constraint) - ): - constrained = True - can_solve = False - break - - if not constrained: - description += ( - "It seems that this function can be called without restrictions." - ) - - if can_solve: - - try: - model = solver.get_model(node.constraints) - - for d in model.decls(): - logging.debug( - "[ETHER_SEND] main model: %s = 0x%x" - % (d.name(), model[d].as_long()) - ) - - debug = "SOLVER OUTPUT:\n" + solver.pretty_print_model(model) - - issue = Issue( - contract=call.node.contract_name, - function=call.node.function_name, - address=address, - title="Ether send", - _type="Warning", - swc_id=UNPROTECTED_ETHER_WITHDRAWAL, - description=description, - debug=debug, - ) - issues.append(issue) - - except UnsatError: - logging.debug("[ETHER_SEND] no model found") +def _analyze_state(state, node): + issues = [] + instruction = state.get_current_instruction() + + if instruction["opcode"] != "CALL": + return [] + + call_value = state.mstate.stack[-3] + target = state.mstate.stack[-2] + + not_creator_constraints = [] + if len(state.world_state.transaction_sequence) > 1: + creator = state.world_state.transaction_sequence[0].caller + for transaction in state.world_state.transaction_sequence[1:]: + not_creator_constraints.append( + Not(Extract(159, 0, transaction.caller) == Extract(159, 0, creator)) + ) + not_creator_constraints.append( + Not(Extract(159, 0, transaction.caller) == 0) + ) + + try: + model = solver.get_model( + node.constraints + not_creator_constraints + [call_value > 0] + ) + + debug = "SOLVER OUTPUT:\n" + solver.pretty_print_model(model) + + issue = Issue( + contract=node.contract_name, + function=node.function_name, + address=instruction["address"], + swc_id=UNPROTECTED_ETHER_WITHDRAWAL, + title="Ether send", + _type="Warning", + description="It seems that an attacker is able to execute an call instruction," + " this can mean that the attacker is able to extract funds " + "out of the contract.".format(target), + debug=debug, + ) + issues.append(issue) + except UnsatError: + logging.debug("[UNCHECKED_SUICIDE] no model found") return issues diff --git a/mythril/analysis/modules/exceptions.py b/mythril/analysis/modules/exceptions.py index a9e63205..0768fac4 100644 --- a/mythril/analysis/modules/exceptions.py +++ b/mythril/analysis/modules/exceptions.py @@ -36,8 +36,7 @@ def execute(statespace): "out-of-bounds array access, or assert violations. " ) description += ( - "This is acceptable in most situations. " - "Note however that `assert()` should only be used to check invariants. " + "Note that explicit `assert()` should only be used to check invariants. " "Use `require()` for regular input checking. " ) diff --git a/mythril/analysis/modules/integer.py b/mythril/analysis/modules/integer.py index 091b8cfb..b5c952f8 100644 --- a/mythril/analysis/modules/integer.py +++ b/mythril/analysis/modules/integer.py @@ -98,12 +98,7 @@ def _check_integer_overflow(statespace, state, node): _type="Warning", ) - issue.description = ( - "A possible integer overflow exists in the function `{}`.\n" - "The addition or multiplication may result in a value higher than the maximum representable integer.".format( - node.function_name - ) - ) + issue.description = "The arithmetic operation can result in integer overflow.\n" issue.debug = solver.pretty_print_model(model) issues.append(issue) @@ -211,10 +206,7 @@ def _check_integer_underflow(statespace, state, node): ) issue.description = ( - "A possible integer underflow exists in the function `" - + node.function_name - + "`.\n" - "The subtraction may result in a value < 0." + "The subtraction can result in an integer underflow.\n" ) issue.debug = solver.pretty_print_model(model) diff --git a/mythril/analysis/modules/multiple_sends.py b/mythril/analysis/modules/multiple_sends.py index 459405dd..db7cca39 100644 --- a/mythril/analysis/modules/multiple_sends.py +++ b/mythril/analysis/modules/multiple_sends.py @@ -32,7 +32,8 @@ def execute(statespace): ) issue.description = ( - "Multiple sends exist in one transaction. Try to isolate each external call into its own transaction," + "Multiple sends are executed in a single transaction. " + "Try to isolate each external call into its own transaction," " as external calls can fail accidentally or deliberately.\nConsecutive calls: \n" ) @@ -47,9 +48,7 @@ def execute(statespace): def _explore_nodes(call, statespace): children = _child_nodes(statespace, call.node) - sending_children = list( - filter(lambda call: call.node in children, statespace.calls) - ) + sending_children = list(filter(lambda c: c.node in children, statespace.calls)) return sending_children diff --git a/mythril/analysis/modules/suicide.py b/mythril/analysis/modules/suicide.py index e2955486..2a191de2 100644 --- a/mythril/analysis/modules/suicide.py +++ b/mythril/analysis/modules/suicide.py @@ -39,9 +39,8 @@ def _analyze_state(state, node): to = state.mstate.stack[-1] logging.debug("[UNCHECKED_SUICIDE] suicide in function " + node.function_name) - description = ( - "The function `" + node.function_name + "` executes the SUICIDE instruction. " - ) + + description = "A reachable SUICIDE instruction was detected. " if "caller" in str(to): description += "The remaining Ether is sent to the caller's address.\n" diff --git a/mythril/analysis/modules/transaction_order_dependence.py b/mythril/analysis/modules/transaction_order_dependence.py index b8d34cd2..4528459c 100644 --- a/mythril/analysis/modules/transaction_order_dependence.py +++ b/mythril/analysis/modules/transaction_order_dependence.py @@ -42,10 +42,8 @@ def execute(statespace): ) issue.description = ( - "A possible transaction order dependence vulnerability exists in function {}. The value or " - "direction of the call statement is determined from a tainted storage location".format( - node.function_name - ) + "Possible transaction order dependence vulnerability: The value or " + "direction of the call statement is determined from a tainted storage location" ) issues.append(issue) diff --git a/mythril/analysis/solver.py b/mythril/analysis/solver.py index afa4ef5b..8e436b71 100644 --- a/mythril/analysis/solver.py +++ b/mythril/analysis/solver.py @@ -1,4 +1,4 @@ -from z3 import Solver, simplify, sat, unknown +from z3 import Solver, simplify, sat, unknown, FuncInterp from mythril.exceptions import UnsatError import logging @@ -22,6 +22,10 @@ def pretty_print_model(model): ret = "" for d in model.decls(): + if type(model[d]) == FuncInterp: + condition = model[d].as_list() + ret += "%s: %s\n" % (d.name(), condition) + continue try: condition = "0x%x" % model[d].as_long() diff --git a/mythril/analysis/symbolic.py b/mythril/analysis/symbolic.py index 871f0d61..539fbb24 100644 --- a/mythril/analysis/symbolic.py +++ b/mythril/analysis/symbolic.py @@ -7,6 +7,8 @@ from .ops import get_variable, SStore, Call, VarType from mythril.laser.ethereum.strategy.basic import ( DepthFirstSearchStrategy, BreadthFirstSearchStrategy, + ReturnRandomNaivelyStrategy, + ReturnWeightedRandomStrategy, ) @@ -28,11 +30,14 @@ class SymExecWrapper: max_transaction_count=3, ): - s_strategy = None if strategy == "dfs": s_strategy = DepthFirstSearchStrategy elif strategy == "bfs": s_strategy = BreadthFirstSearchStrategy + elif strategy == "naive-random": + s_strategy = ReturnRandomNaivelyStrategy + elif strategy == "weighted-random": + s_strategy = ReturnWeightedRandomStrategy else: raise ValueError("Invalid strategy argument supplied") diff --git a/mythril/analysis/traceexplore.py b/mythril/analysis/traceexplore.py index d3e87cab..6fd476aa 100644 --- a/mythril/analysis/traceexplore.py +++ b/mythril/analysis/traceexplore.py @@ -47,7 +47,6 @@ colors = [ def get_serializable_statespace(statespace): - nodes = [] edges = [] @@ -77,10 +76,10 @@ def get_serializable_statespace(statespace): color = color_map[node.get_cfg_dict()["contract_name"]] - def get_state_accounts(state): + def get_state_accounts(node_state): state_accounts = [] - for key in state.accounts: - account = state.accounts[key].as_dict + for key in node_state.accounts: + account = node_state.accounts[key].as_dict account.pop("code", None) account["balance"] = str(account["balance"]) diff --git a/mythril/disassembler/disassembly.py b/mythril/disassembler/disassembly.py index 6d3ef817..d86d32e5 100644 --- a/mythril/disassembler/disassembly.py +++ b/mythril/disassembler/disassembly.py @@ -4,16 +4,27 @@ import logging class Disassembly(object): - def __init__(self, code, enable_online_lookup=True): + """ + Disassembly class + + Stores bytecode, and its disassembly. + Additionally it will gather the following information on the existing functions in the disassembled code: + - function hashes + - function name to entry point mapping + - function entry point to function name mapping + """ + + def __init__(self, code: str, enable_online_lookup: bool = False): + self.bytecode = code self.instruction_list = asm.disassemble(util.safe_decode(code)) + self.func_hashes = [] - self.func_to_addr = {} - self.addr_to_func = {} - self.bytecode = code + self.function_name_to_address = {} + self.address_to_function_name = {} signatures = SignatureDb( enable_online_lookup=enable_online_lookup - ) # control if you want to have online sighash lookups + ) # control if you want to have online signature hash lookups try: signatures.open() # open from default locations except FileNotFoundError: @@ -21,46 +32,64 @@ class Disassembly(object): "Missing function signature file. Resolving of function names from signature file disabled." ) - # Parse jump table & resolve function names - # Need to take from PUSH1 to PUSH4 because solc seems to remove excess 0s at the beginning for optimizing - jmptable_indices = asm.find_opcode_sequence( + jump_table_indices = asm.find_opcode_sequence( [("PUSH1", "PUSH2", "PUSH3", "PUSH4"), ("EQ",)], self.instruction_list ) - for i in jmptable_indices: - func_hash = self.instruction_list[i]["argument"] - - # Append with missing 0s at the beginning - func_hash = "0x" + func_hash[2:].rjust(8, "0") - - self.func_hashes.append(func_hash) - try: - # tries local cache, file and optional online lookup - # may return more than one function signature. since we cannot probe for the correct one we'll use the first - func_names = signatures.get(func_hash) - if len(func_names) > 1: - # ambigious result - func_name = ( - "**ambiguous** %s" % func_names[0] - ) # return first hit but note that result was ambiguous - else: - # only one item - func_name = func_names[0] - except KeyError: - func_name = "_function_" + func_hash - - try: - offset = self.instruction_list[i + 2]["argument"] - jump_target = int(offset, 16) - - self.func_to_addr[func_name] = jump_target - self.addr_to_func[jump_target] = func_name - except: - continue + for index in jump_table_indices: + function_hash, jump_target, function_name = get_function_info( + index, self.instruction_list, signatures + ) + self.func_hashes.append(function_hash) + + if jump_target is not None and function_name is not None: + self.function_name_to_address[function_name] = jump_target + self.address_to_function_name[jump_target] = function_name signatures.write() # store resolved signatures (potentially resolved online) def get_easm(self): - # todo: tintinweb - print funcsig resolved data from self.addr_to_func? return asm.instruction_list_to_easm(self.instruction_list) + + +def get_function_info( + index: int, instruction_list: list, signature_database: SignatureDb +) -> (str, int, str): + """ + Finds the function information for a call table entry + Solidity uses the first 4 bytes of the calldata to indicate which function the message call should execute + The generated code that directs execution to the correct function looks like this: + - PUSH function_hash + - EQ + - PUSH entry_point + - JUMPI + + This function takes an index that points to the first instruction, and from that finds out the function hash, + function entry and the function name. + + :param index: Start of the entry pattern + :param instruction_list: Instruction list for the contract that is being analyzed + :param signature_database: Database used to map function hashes to their respective function names + :return: function hash, function entry point, function name + """ + + # Append with missing 0s at the beginning + function_hash = "0x" + instruction_list[index]["argument"][2:].rjust(8, "0") + + function_names = signature_database.get(function_hash) + if len(function_names) > 1: + # In this case there was an ambiguous result + function_name = "**ambiguous** {}".format(function_names[0]) + elif len(function_names) == 1: + function_name = function_names[0] + else: + function_name = "_function_" + function_hash + + try: + offset = instruction_list[index + 2]["argument"] + entry_point = int(offset, 16) + except (KeyError, IndexError): + return function_hash, None, None + + return function_hash, entry_point, function_name diff --git a/mythril/ether/ethcontract.py b/mythril/ether/ethcontract.py index b2a55106..8914c882 100644 --- a/mythril/ether/ethcontract.py +++ b/mythril/ether/ethcontract.py @@ -6,7 +6,7 @@ import re class ETHContract(persistent.Persistent): def __init__( - self, code, creation_code="", name="Unknown", enable_online_lookup=True + self, code, creation_code="", name="Unknown", enable_online_lookup=False ): # Workaround: We currently do not support compile-time linking. diff --git a/mythril/ether/evm.py b/mythril/ether/evm.py index 020dcd94..2dd84895 100644 --- a/mythril/ether/evm.py +++ b/mythril/ether/evm.py @@ -8,14 +8,12 @@ import re def trace(code, calldata=""): - log_handlers = [ "eth.vm.op", "eth.vm.op.stack", "eth.vm.op.memory", "eth.vm.op.storage", ] - output = StringIO() stream_handler = StreamHandler(output) @@ -25,58 +23,43 @@ def trace(code, calldata=""): log_vm_op.addHandler(stream_handler) addr = bytes.fromhex("0123456789ABCDEF0123456789ABCDEF01234567") - state = State() ext = messages.VMExt(state, transactions.Transaction(0, 0, 21000, addr, 0, addr)) - message = vm.Message(addr, addr, 0, 21000, calldata) - - res, gas, dat = vm.vm_execute(ext, message, util.safe_decode(code)) - + vm.vm_execute(ext, message, util.safe_decode(code)) stream_handler.flush() - ret = output.getvalue() - lines = ret.split("\n") - trace = [] - + state_trace = [] for line in lines: - m = re.search(r"pc=b\'(\d+)\'.*op=([A-Z0-9]+)", line) - if m: pc = m.group(1) op = m.group(2) - m = re.match(r".*stack=(\[.*?\])", line) if m: - stackitems = re.findall(r"b\'(\d+)\'", m.group(1)) - stack = "[" if len(stackitems): - for i in range(0, len(stackitems) - 1): stack += hex(int(stackitems[i])) + ", " - stack += hex(int(stackitems[-1])) stack += "]" - else: stack = "[]" if re.match(r"^PUSH.*", op): val = re.search(r"pushvalue=(\d+)", line).group(1) pushvalue = hex(int(val)) - trace.append( + state_trace.append( {"pc": pc, "op": op, "stack": stack, "pushvalue": pushvalue} ) else: - trace.append({"pc": pc, "op": op, "stack": stack}) + state_trace.append({"pc": pc, "op": op, "stack": stack}) - return trace + return state_trace diff --git a/mythril/ethereum/interface/leveldb/accountindexing.py b/mythril/ethereum/interface/leveldb/accountindexing.py index 21203740..6452a6b9 100644 --- a/mythril/ethereum/interface/leveldb/accountindexing.py +++ b/mythril/ethereum/interface/leveldb/accountindexing.py @@ -63,16 +63,15 @@ class AccountIndexer(object): def get_contract_by_hash(self, contract_hash): """ - get mapped address by its hash, if not found try indexing + get mapped contract_address by its hash, if not found try indexing """ - address = self.db.reader._get_address_by_hash(contract_hash) - if address is not None: - return address + contract_address = self.db.reader._get_address_by_hash(contract_hash) + if contract_address is not None: + return contract_address + else: raise AddressNotFoundError - return self.db.reader._get_address_by_hash(contract_hash) - def _process(self, startblock): """ Processesing method @@ -84,9 +83,9 @@ class AccountIndexer(object): addresses = [] for blockNum in range(startblock, startblock + BATCH_SIZE): - hash = self.db.reader._get_block_hash(blockNum) - if hash is not None: - receipts = self.db.reader._get_block_receipts(hash, blockNum) + block_hash = self.db.reader._get_block_hash(blockNum) + if block_hash is not None: + receipts = self.db.reader._get_block_receipts(block_hash, blockNum) for receipt in receipts: if receipt.contractAddress is not None and not all( diff --git a/mythril/ethereum/interface/leveldb/client.py b/mythril/ethereum/interface/leveldb/client.py index b3500baf..46e6bc77 100644 --- a/mythril/ethereum/interface/leveldb/client.py +++ b/mythril/ethereum/interface/leveldb/client.py @@ -84,55 +84,46 @@ class LevelDBReader(object): gets head block header """ if not self.head_block_header: - hash = self.db.get(head_header_key) - num = self._get_block_number(hash) - self.head_block_header = self._get_block_header(hash, num) + block_hash = self.db.get(head_header_key) + num = self._get_block_number(block_hash) + self.head_block_header = self._get_block_header(block_hash, num) # find header with valid state while ( not self.db.get(self.head_block_header.state_root) and self.head_block_header.prevhash is not None ): - hash = self.head_block_header.prevhash - num = self._get_block_number(hash) - self.head_block_header = self._get_block_header(hash, num) + block_hash = self.head_block_header.prevhash + num = self._get_block_number(block_hash) + self.head_block_header = self._get_block_header(block_hash, num) return self.head_block_header - def _get_block_number(self, hash): - """ - gets block number by hash - """ - number_key = block_hash_prefix + hash + def _get_block_number(self, block_hash): + """Get block number by its hash""" + number_key = block_hash_prefix + block_hash return self.db.get(number_key) - def _get_block_header(self, hash, num): - """ - get block header by block header hash & number - """ - header_key = header_prefix + num + hash + def _get_block_header(self, block_hash, num): + """Get block header by block header hash & number""" + header_key = header_prefix + num + block_hash + block_header_data = self.db.get(header_key) header = rlp.decode(block_header_data, sedes=BlockHeader) return header - def _get_address_by_hash(self, hash): - """ - get mapped address by its hash - """ - address_key = address_prefix + hash + def _get_address_by_hash(self, block_hash): + """Get mapped address by its hash""" + address_key = address_prefix + block_hash return self.db.get(address_key) def _get_last_indexed_number(self): - """ - latest indexed block number - """ + """Get latest indexed block number""" return self.db.get(address_mapping_head_key) - def _get_block_receipts(self, hash, num): - """ - get block transaction receipts by block header hash & number - """ + def _get_block_receipts(self, block_hash, num): + """Get block transaction receipts by block header hash & number""" number = _format_block_number(num) - receipts_key = block_receipts_prefix + number + hash + receipts_key = block_receipts_prefix + number + block_hash receipts_data = self.db.get(receipts_key) receipts = rlp.decode(receipts_data, sedes=CountableList(ReceiptForStorage)) return receipts @@ -224,12 +215,10 @@ class EthLevelDB(object): if not cnt % 1000: logging.info("Searched %d contracts" % cnt) - def contract_hash_to_address(self, hash): - """ - tries to find corresponding account address - """ + def contract_hash_to_address(self, contract_hash): + """Tries to find corresponding account address""" - address_hash = binascii.a2b_hex(utils.remove_0x_head(hash)) + address_hash = binascii.a2b_hex(utils.remove_0x_head(contract_hash)) indexer = AccountIndexer(self) return _encode_hex(indexer.get_contract_by_hash(address_hash)) @@ -238,9 +227,9 @@ class EthLevelDB(object): """ gets block header by block number """ - hash = self.reader._get_block_hash(number) + block_hash = self.reader._get_block_hash(number) block_number = _format_block_number(number) - return self.reader._get_block_header(hash, block_number) + return self.reader._get_block_header(block_hash, block_number) def eth_getBlockByNumber(self, number): """ diff --git a/mythril/ethereum/interface/leveldb/state.py b/mythril/ethereum/interface/leveldb/state.py index 678c36af..f756de24 100644 --- a/mythril/ethereum/interface/leveldb/state.py +++ b/mythril/ethereum/interface/leveldb/state.py @@ -58,9 +58,9 @@ class Account(rlp.Serializable): ("code_hash", hash32), ] - def __init__(self, nonce, balance, storage, code_hash, db, address): + def __init__(self, nonce, balance, storage, code_hash, db, addr): self.db = db - self.address = address + self.address = addr super(Account, self).__init__(nonce, balance, storage, code_hash) self.storage_cache = {} self.storage_trie = SecureTrie(Trie(self.db)) @@ -89,12 +89,12 @@ class Account(rlp.Serializable): return self.storage_cache[key] @classmethod - def blank_account(cls, db, address, initial_nonce=0): + def blank_account(cls, db, addr, initial_nonce=0): """ creates a blank account """ db.put(BLANK_HASH, b"") - o = cls(initial_nonce, 0, trie.BLANK_ROOT, BLANK_HASH, db, address) + o = cls(initial_nonce, 0, trie.BLANK_ROOT, BLANK_HASH, db, addr) o.existent_at_start = False return o @@ -117,22 +117,22 @@ class State: self.journal = [] self.cache = {} - def get_and_cache_account(self, address): - """ - gets and caches an account for an addres, creates blank if not found - """ - if address in self.cache: - return self.cache[address] - rlpdata = self.secure_trie.get(address) + def get_and_cache_account(self, addr): + """Gets and caches an account for an addres, creates blank if not found""" + + if addr in self.cache: + return self.cache[addr] + rlpdata = self.secure_trie.get(addr) if ( - rlpdata == trie.BLANK_NODE and len(address) == 32 + rlpdata == trie.BLANK_NODE and len(addr) == 32 ): # support for hashed addresses - rlpdata = self.trie.get(address) + rlpdata = self.trie.get(addr) + if rlpdata != trie.BLANK_NODE: - o = rlp.decode(rlpdata, Account, db=self.db, address=address) + o = rlp.decode(rlpdata, Account, db=self.db, address=addr) else: - o = Account.blank_account(self.db, address, 0) - self.cache[address] = o + o = Account.blank_account(self.db, addr, 0) + self.cache[addr] = o o._mutable = True o._cached_rlp = None return o diff --git a/mythril/interfaces/cli.py b/mythril/interfaces/cli.py index 08a8d4e7..443812bb 100644 --- a/mythril/interfaces/cli.py +++ b/mythril/interfaces/cli.py @@ -15,10 +15,11 @@ import argparse from mythril.exceptions import CriticalError, AddressNotFoundError from mythril.mythril import Mythril from mythril.version import VERSION +import mythril.support.signatures as sigs -def exit_with_error(format, message): - if format == "text" or format == "markdown": +def exit_with_error(format_, message): + if format_ == "text" or format_ == "markdown": print(message) else: result = {"success": False, "error": str(message), "issues": []} @@ -147,18 +148,19 @@ def main(): default=22, help="Maximum recursion depth for symbolic execution", ) + + options.add_argument( + "--strategy", + choices=["dfs", "bfs", "naive-random", "weighted-random"], + default="dfs", + help="Symbolic execution strategy", + ) options.add_argument( "--max-transaction-count", type=int, default=3, help="Maximum number of transactions issued by laser", ) - options.add_argument( - "--strategy", - choices=["dfs", "bfs"], - default="dfs", - help="Symbolic execution strategy", - ) options.add_argument( "--execution-timeout", type=int, @@ -179,6 +181,12 @@ def main(): "--enable-physics", action="store_true", help="enable graph physics simulation" ) options.add_argument("-v", type=int, help="log level (0-2)", metavar="LOG_LEVEL") + options.add_argument( + "-q", + "--query-signature", + action="store_true", + help="Lookup function signatures through www.4byte.directory", + ) rpc = parser.add_argument_group("RPC options") rpc.add_argument( @@ -231,6 +239,13 @@ def main(): args.outform, "Invalid -v value, you can find valid values in usage" ) + if args.query_signature: + if sigs.ethereum_input_decoder == None: + exit_with_error( + args.outform, + "The --query-signature function requires the python package ethereum-input-decoder", + ) + # -- commands -- if args.hash: print(Mythril.hash_for_function_signature(args.hash)) @@ -241,7 +256,12 @@ def main(): # infura = None, rpc = None, rpctls = None # solc_args = None, dynld = None, max_recursion_depth = 12): - mythril = Mythril(solv=args.solv, dynld=args.dynld, solc_args=args.solc_args) + mythril = Mythril( + solv=args.solv, + dynld=args.dynld, + solc_args=args.solc_args, + enable_online_lookup=args.query_signature, + ) if args.dynld and not (args.rpc or args.i): mythril.set_api_from_config_path() diff --git a/mythril/laser/ethereum/call.py b/mythril/laser/ethereum/call.py index 589d44a9..b96e5ac3 100644 --- a/mythril/laser/ethereum/call.py +++ b/mythril/laser/ethereum/call.py @@ -1,8 +1,8 @@ import logging from typing import Union -from z3 import simplify, BitVecRef, BitVecNumRef, BoolRef +from z3 import simplify, BitVecRef, BitVecNumRef, BoolRef, Extract import mythril.laser.ethereum.util as util -from mythril.laser.ethereum.state import Account, CalldataType, GlobalState +from mythril.laser.ethereum.state import Account, CalldataType, GlobalState, Calldata from mythril.support.loader import DynLoader import re @@ -125,7 +125,7 @@ def get_callee_account( try: code = dynamic_loader.dynld(environment.active_account.address, callee_address) - except Exception as e: + except Exception: logging.debug("Unable to execute dynamic loader.") raise ValueError() if code is None: @@ -156,21 +156,33 @@ def get_call_data( :return: Tuple containing: call_data array from memory or empty array if symbolic, type found """ state = global_state.mstate + transaction_id = "{}_internalcall".format(global_state.current_transaction.id) try: # TODO: This only allows for either fully concrete or fully symbolic calldata. # Improve management of memory and callata to support a mix between both types. - call_data = state.memory[ + calldata_from_mem = state.memory[ util.get_concrete_int(memory_start) : util.get_concrete_int( memory_start + memory_size ) ] - if len(call_data) < 32 and pad: - call_data += [0] * (32 - len(call_data)) + i = 0 + starting_calldata = [] + while i < len(calldata_from_mem): + elem = calldata_from_mem[i] + if isinstance(elem, int): + starting_calldata.append(elem) + i += 1 + else: # BitVec + for j in range(0, elem.size(), 8): + starting_calldata.append(Extract(j + 7, j, elem)) + i += 1 + + call_data = Calldata(transaction_id, starting_calldata) call_data_type = CalldataType.CONCRETE logging.debug("Calldata: " + str(call_data)) except TypeError: logging.info("Unsupported symbolic calldata offset") call_data_type = CalldataType.SYMBOLIC - call_data = [] + call_data = Calldata("{}_internalcall".format(transaction_id)) return call_data, call_data_type diff --git a/mythril/laser/ethereum/cfg.py b/mythril/laser/ethereum/cfg.py index 5ccf5287..93950104 100644 --- a/mythril/laser/ethereum/cfg.py +++ b/mythril/laser/ethereum/cfg.py @@ -38,9 +38,11 @@ class Node: code = "" for state in self.states: instruction = state.get_current_instruction() + code += str(instruction["address"]) + " " + instruction["opcode"] if instruction["opcode"].startswith("PUSH"): code += " " + instruction["argument"] + code += "\\n" return dict( diff --git a/mythril/laser/ethereum/instructions.py b/mythril/laser/ethereum/instructions.py index f0494ec1..41925c11 100644 --- a/mythril/laser/ethereum/instructions.py +++ b/mythril/laser/ethereum/instructions.py @@ -38,13 +38,14 @@ from mythril.laser.ethereum.evm_exceptions import ( InvalidInstruction, ) from mythril.laser.ethereum.keccak import KeccakFunctionManager -from mythril.laser.ethereum.state import GlobalState, CalldataType +from mythril.laser.ethereum.state import GlobalState, CalldataType, Calldata from mythril.laser.ethereum.transaction import ( MessageCallTransaction, TransactionStartSignal, ContractCreationTransaction, ) from mythril.support.loader import DynLoader +from mythril.analysis.solver import get_model TT256 = 2 ** 256 TT256M1 = 2 ** 256 - 1 @@ -162,7 +163,6 @@ class Instruction: op1 = If(op1, BitVecVal(1, 256), BitVecVal(0, 256)) if type(op2) == BoolRef: op2 = If(op2, BitVecVal(1, 256), BitVecVal(0, 256)) - stack.append(op1 & op2) return [global_state] @@ -314,8 +314,8 @@ class Instruction: @StateTransition() def exp_(self, global_state: GlobalState) -> List[GlobalState]: state = global_state.mstate - base, exponent = util.pop_bitvec(state), util.pop_bitvec(state) + if (type(base) != BitVecNumRef) or (type(exponent) != BitVecNumRef): state.stack.append( global_state.new_bitvec( @@ -423,89 +423,14 @@ class Instruction: environment = global_state.environment op0 = state.stack.pop() - try: - offset = util.get_concrete_int(simplify(op0)) - b = environment.calldata[offset] - except TypeError: - logging.debug("CALLDATALOAD: Unsupported symbolic index") - state.stack.append( - global_state.new_bitvec( - "calldata_" - + str(environment.active_account.contract_name) - + "[" - + str(simplify(op0)) - + "]", - 256, - ) - ) - return [global_state] - except IndexError: - logging.debug("Calldata not set, using symbolic variable instead") - state.stack.append( - global_state.new_bitvec( - "calldata_" - + str(environment.active_account.contract_name) - + "[" - + str(simplify(op0)) - + "]", - 256, - ) - ) - return [global_state] - - if type(b) == int: - - try: - val = b"".join( - [ - calldata.to_bytes(1, byteorder="big") - for calldata in environment.calldata[offset : offset + 32] - ] - ) - - logging.debug( - "Final value: " + str(int.from_bytes(val, byteorder="big")) - ) - state.stack.append(BitVecVal(int.from_bytes(val, byteorder="big"), 256)) - - except (TypeError, AttributeError): - state.stack.append( - global_state.new_bitvec( - "calldata_" - + str(environment.active_account.contract_name) - + "[" - + str(simplify(op0)) - + "]", - 256, - ) - ) - else: - # symbolic variable - state.stack.append( - global_state.new_bitvec( - "calldata_" - + str(environment.active_account.contract_name) - + "[" - + str(simplify(op0)) - + "]", - 256, - ) - ) - + state.stack.append(environment.calldata.get_word_at(op0)) return [global_state] @StateTransition() def calldatasize_(self, global_state: GlobalState) -> List[GlobalState]: state = global_state.mstate environment = global_state.environment - if environment.calldata_type == CalldataType.SYMBOLIC: - state.stack.append( - global_state.new_bitvec( - "calldatasize_" + environment.active_account.contract_name, 256 - ) - ) - else: - state.stack.append(BitVecVal(len(environment.calldata), 256)) + state.stack.append(environment.calldata.calldatasize) return [global_state] @StateTransition() @@ -536,7 +461,7 @@ class Instruction: size = simplify(op2) size_sym = True - if dstart_sym or size_sym: + if size_sym: state.mem_extend(mstart, 1) state.memory[mstart] = global_state.new_bitvec( "calldata_" @@ -574,11 +499,17 @@ class Instruction: return [global_state] try: - i_data = environment.calldata[dstart] + i_data = dstart + + new_memory = [] + for i in range(size): + new_memory.append(environment.calldata[i_data]) + i_data = ( + i_data + 1 if isinstance(i_data, int) else simplify(i_data + 1) + ) - for i in range(mstart, mstart + size): - state.memory[i] = environment.calldata[i_data] - i_data += 1 + for i in range(0, len(new_memory), 32): + state.memory[i + mstart] = simplify(Concat(new_memory[i : i + 32])) except IndexError: logging.debug("Exception copying calldata to memory") @@ -636,7 +567,6 @@ class Instruction: global keccak_function_manager state = global_state.mstate - environment = global_state.environment op0, op1 = state.stack.pop(), state.stack.pop() try: @@ -886,12 +816,9 @@ class Instruction: try: # Attempt to concretize value - _bytes = util.concrete_int_to_bytes(value) - state.memory[mstart : mstart + len(_bytes)] = _bytes - - except (AttributeError, TypeError): + except: try: state.memory[mstart] = value except TypeError: @@ -1161,7 +1088,7 @@ class Instruction: state = global_state.mstate dpth = int(self.op_code[3:]) state.stack.pop(), state.stack.pop() - [state.stack.pop() for x in range(dpth)] + [state.stack.pop() for _ in range(dpth)] # Not supported return [global_state] diff --git a/mythril/laser/ethereum/keccak.py b/mythril/laser/ethereum/keccak.py index d99c49aa..a69f782d 100644 --- a/mythril/laser/ethereum/keccak.py +++ b/mythril/laser/ethereum/keccak.py @@ -1,6 +1,7 @@ from z3 import ExprRef, BitVecRef + class KeccakFunctionManager: def __init__(self): self.keccak_expression_mapping = {} diff --git a/mythril/laser/ethereum/natives.py b/mythril/laser/ethereum/natives.py index 1e379fbe..b764aba1 100644 --- a/mythril/laser/ethereum/natives.py +++ b/mythril/laser/ethereum/natives.py @@ -87,4 +87,4 @@ def native_contracts(address: int, data: List): takes integer address 1, 2, 3, 4 """ functions = (ecrecover, sha256, ripemd160, identity) - return functions[address - 1](data) + return functions[address - 1](data.starting_calldata) diff --git a/mythril/laser/ethereum/state.py b/mythril/laser/ethereum/state.py index 6046b82d..43942c09 100644 --- a/mythril/laser/ethereum/state.py +++ b/mythril/laser/ethereum/state.py @@ -1,10 +1,29 @@ -from z3 import BitVec, BitVecVal, BitVecRef, BitVecNumRef, Solver, ExprRef, sat +from z3 import ( + BitVec, + BitVecVal, + BitVecRef, + BitVecNumRef, + BitVecSort, + Solver, + ExprRef, + Concat, + sat, + simplify, + Array, + ForAll, + Solver, + UGT, + Implies, +) +from z3.z3types import Z3Exception from mythril.disassembler.disassembly import Disassembly from mythril.laser.ethereum.cfg import Node from copy import copy, deepcopy from enum import Enum from random import randint from typing import KeysView, Dict, List, Union, Any +from mythril.laser.ethereum.util import get_concrete_int + from mythril.laser.ethereum.evm_exceptions import ( StackOverflowException, StackUnderflowException, @@ -16,6 +35,88 @@ class CalldataType(Enum): SYMBOLIC = 2 +class Calldata: + """ + Calldata class representing the calldata of a transaction + """ + + def __init__(self, tx_id, starting_calldata=None): + """ + Constructor for Calldata + :param tx_id: unique value representing the transaction the calldata is for + :param starting_calldata: byte array representing the concrete calldata of a transaction + """ + self.tx_id = tx_id + if starting_calldata: + self._calldata = [] + self.calldatasize = BitVecVal(len(starting_calldata), 256) + self.concrete = True + else: + self._calldata = Array( + "{}_calldata".format(self.tx_id), BitVecSort(256), BitVecSort(8) + ) + self.calldatasize = BitVec("{}_calldatasize".format(self.tx_id), 256) + self.concrete = False + + self.starting_calldata = starting_calldata or [] + + @property + def constraints(self): + constraints = [] + + if self.concrete: + for calldata_byte in self.starting_calldata: + if type(calldata_byte) == int: + self._calldata.append(BitVecVal(calldata_byte, 8)) + else: + 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): + result = [] + for i in range( + get_concrete_int(model.eval(self.calldatasize, model_completion=True)) + ): + result.append(get_concrete_int(model.eval(self[i], model_completion=True))) + + return result + + def get_word_at(self, index: int): + return self[index : index + 32] + + def __getitem__(self, item): + if isinstance(item, slice): + try: + current_index = ( + item.start + if isinstance(item.start, BitVecRef) + else BitVecVal(item.start, 256) + ) + dataparts = [] + while simplify(current_index != item.stop): + dataparts.append(self[current_index]) + current_index = simplify(current_index + 1) + except Z3Exception: + raise IndexError("Invalid Calldata Slice") + + return simplify(Concat(dataparts)) + + if self.concrete: + try: + return self._calldata[get_concrete_int(item)] + except IndexError: + return BitVecVal(0, 8) + else: + return self._calldata[item] + + class Storage: """ Storage class represents the storage of an Account @@ -339,7 +440,6 @@ class GlobalState: def new_bitvec(self, name: str, size=256) -> BitVec: transaction_id = self.current_transaction.id - node_id = self.node.uid return BitVec("{}_{}".format(transaction_id, name), size) diff --git a/mythril/laser/ethereum/strategy/__init__.py b/mythril/laser/ethereum/strategy/__init__.py index e69de29b..099aa4fb 100644 --- a/mythril/laser/ethereum/strategy/__init__.py +++ b/mythril/laser/ethereum/strategy/__init__.py @@ -0,0 +1,25 @@ +from abc import ABC, abstractmethod + + +class BasicSearchStrategy(ABC): + __slots__ = "work_list", "max_depth" + + def __init__(self, work_list, max_depth): + self.work_list = work_list + self.max_depth = max_depth + + def __iter__(self): + return self + + @abstractmethod + def get_strategic_global_state(self): + raise NotImplementedError("Must be implemented by a subclass") + + def __next__(self): + try: + global_state = self.get_strategic_global_state() + if global_state.mstate.depth >= self.max_depth: + return self.__next__() + return global_state + except IndexError: + raise StopIteration diff --git a/mythril/laser/ethereum/strategy/basic.py b/mythril/laser/ethereum/strategy/basic.py index b67f602f..232ac19b 100644 --- a/mythril/laser/ethereum/strategy/basic.py +++ b/mythril/laser/ethereum/strategy/basic.py @@ -3,55 +3,75 @@ This module implements basic symbolic execution search strategies """ from ..state import GlobalState from typing import List +from random import randrange +from . import BasicSearchStrategy +try: + from random import choices +except ImportError: -class DepthFirstSearchStrategy: + # This is for supporting python versions < 3.6 + from itertools import accumulate + from random import random + from bisect import bisect + + def choices(population, weights=None): + """ + Returns a random element out of the population based on weight. + If the relative weights or cumulative weights are not specified, + the selections are made with equal probability. + """ + if weights is None: + return [population[int(random() * len(population))]] + cum_weights = accumulate(weights) + return [ + population[ + bisect(cum_weights, random() * cum_weights[-1], 0, len(population) - 1) + ] + ] + + +class DepthFirstSearchStrategy(BasicSearchStrategy): """ Implements a depth first search strategy I.E. Follow one path to a leaf, and then continue to the next one """ - def __init__(self, work_list: List[GlobalState], max_depth: float): - self.work_list = work_list - self.max_depth = max_depth - - def __iter__(self): - return self + def get_strategic_global_state(self) -> GlobalState: + return self.work_list.pop() - def __next__(self) -> GlobalState: - """ Picks the next state to execute """ - try: - # This strategies assumes that new states are appended at the end of the work_list - # By taking the last element we effectively pick the "newest" states, which amounts to dfs - global_state = self.work_list.pop() - if global_state.mstate.depth >= self.max_depth: - return self.__next__() - return global_state - except IndexError: - raise StopIteration() - -class BreadthFirstSearchStrategy: +class BreadthFirstSearchStrategy(BasicSearchStrategy): """ Implements a breadth first search strategy I.E. Execute all states of a "level" before continuing """ - def __init__(self, work_list: List[GlobalState], max_depth: float): - self.work_list = work_list - self.max_depth = max_depth - - def __iter__(self) -> "BreadthFirstSearchStrategy": - return self - - def __next__(self) -> GlobalState: - """ Picks the next state to execute """ - try: - # This strategies assumes that new states are appended at the end of the work_list - # By taking the first element we effectively pick the "oldest" states, which amounts to bfs - global_state = self.work_list.pop(0) - if global_state.mstate.depth >= self.max_depth: - return self.__next__() - return global_state - except IndexError: - raise StopIteration() + def get_strategic_global_state(self) -> GlobalState: + return self.work_list.pop(0) + + +class ReturnRandomNaivelyStrategy(BasicSearchStrategy): + """ + chooses a random state from the worklist with equal likelihood + """ + + def get_strategic_global_state(self) -> GlobalState: + if len(self.work_list) > 0: + return self.work_list.pop(randrange(len(self.work_list))) + else: + raise IndexError + + +class ReturnWeightedRandomStrategy(BasicSearchStrategy): + """ + chooses a random state from the worklist with likelihood based on inverse proportion to depth + """ + + def get_strategic_global_state(self) -> GlobalState: + probability_distribution = [ + 1 / (global_state.mstate.depth + 1) for global_state in self.work_list + ] + return self.work_list.pop( + choices(range(len(self.work_list)), probability_distribution)[0] + ) diff --git a/mythril/laser/ethereum/svm.py b/mythril/laser/ethereum/svm.py index 818b8d3f..b5b6ccca 100644 --- a/mythril/laser/ethereum/svm.py +++ b/mythril/laser/ethereum/svm.py @@ -1,5 +1,6 @@ import logging from typing import List, Tuple, Union, Callable +from mythril.disassembler.disassembly import Disassembly from mythril.laser.ethereum.state import WorldState, GlobalState from mythril.laser.ethereum.transaction import ( TransactionStartSignal, @@ -105,7 +106,7 @@ class LaserEVM: if len(self.open_states) == 0: logging.warning( "No contract was created during the execution of contract creation " - "Increase the resources for creation execution (--max-depth or --create_timeout)" + "Increase the resources for creation execution (--max-depth or --create-timeout)" ) # Reset code coverage @@ -353,10 +354,11 @@ class LaserEVM: environment = state.environment disassembly = environment.code - if address in state.environment.code.addr_to_func: + if address in disassembly.address_to_function_name: # Enter a new function - - environment.active_function_name = disassembly.addr_to_func[address] + environment.active_function_name = disassembly.address_to_function_name[ + address + ] new_node.flags |= NodeFlags.FUNC_ENTRY logging.debug( diff --git a/mythril/laser/ethereum/taint_analysis.py b/mythril/laser/ethereum/taint_analysis.py index d014e78f..f0ff9ede 100644 --- a/mythril/laser/ethereum/taint_analysis.py +++ b/mythril/laser/ethereum/taint_analysis.py @@ -8,6 +8,7 @@ from mythril.laser.ethereum.state import GlobalState, Environment from mythril.analysis.symbolic import SymExecWrapper + class TaintRecord: """ TaintRecord contains tainting information for a specific (state, node) diff --git a/mythril/laser/ethereum/transaction/concolic.py b/mythril/laser/ethereum/transaction/concolic.py index 597de21d..db3f0116 100644 --- a/mythril/laser/ethereum/transaction/concolic.py +++ b/mythril/laser/ethereum/transaction/concolic.py @@ -10,6 +10,7 @@ from mythril.laser.ethereum.state import ( CalldataType, Account, WorldState, + Calldata, ) from mythril.disassembler.disassembly import Disassembly from mythril.laser.ethereum.cfg import Node, Edge, JumpType @@ -32,12 +33,13 @@ def execute_message_call( del laser_evm.open_states[:] for open_world_state in open_states: + next_transaction_id = get_next_transaction_id() transaction = MessageCallTransaction( - identifier=get_next_transaction_id(), + identifier=next_transaction_id, world_state=open_world_state, callee_account=open_world_state[callee_address], caller=caller_address, - call_data=data, + call_data=Calldata(next_transaction_id, data), gas_price=gas_price, call_value=value, origin=origin_address, diff --git a/mythril/laser/ethereum/transaction/symbolic.py b/mythril/laser/ethereum/transaction/symbolic.py index 540b2b6c..50337e73 100644 --- a/mythril/laser/ethereum/transaction/symbolic.py +++ b/mythril/laser/ethereum/transaction/symbolic.py @@ -3,7 +3,7 @@ from logging import debug from mythril.disassembler.disassembly import Disassembly from mythril.laser.ethereum.cfg import Node, Edge, JumpType -from mythril.laser.ethereum.state import CalldataType, Account +from mythril.laser.ethereum.state import CalldataType, Account, Calldata from mythril.laser.ethereum.transaction.transaction_models import ( MessageCallTransaction, ContractCreationTransaction, @@ -28,7 +28,7 @@ def execute_message_call(laser_evm, callee_address: str) -> None: callee_account=open_world_state[callee_address], caller=BitVec("caller{}".format(next_transaction_id), 256), identifier=next_transaction_id, - call_data=[], + call_data=Calldata(next_transaction_id), gas_price=BitVec("gas_price{}".format(next_transaction_id), 256), call_value=BitVec("call_value{}".format(next_transaction_id), 256), origin=BitVec("origin{}".format(next_transaction_id), 256), diff --git a/mythril/laser/ethereum/transaction/transaction_models.py b/mythril/laser/ethereum/transaction/transaction_models.py index 50a2e540..a4ff2e2a 100644 --- a/mythril/laser/ethereum/transaction/transaction_models.py +++ b/mythril/laser/ethereum/transaction/transaction_models.py @@ -1,7 +1,7 @@ import logging from typing import Union from mythril.disassembler.disassembly import Disassembly -from mythril.laser.ethereum.state import GlobalState, Environment, WorldState, Account +from mythril.laser.ethereum.state import GlobalState, Environment, WorldState, Account, Calldata from z3 import BitVec, BitVecNumRef import array @@ -42,7 +42,7 @@ class MessageCallTransaction: world_state: WorldState, callee_account: Account, caller: BitVecNumRef, - call_data=(), + call_data=None, identifier=None, gas_price=None, call_value=None, @@ -55,7 +55,11 @@ class MessageCallTransaction: self.world_state = world_state self.callee_account = callee_account self.caller = caller - self.call_data = call_data + self.call_data = ( + Calldata(self.id, call_data) + if not isinstance(call_data, Calldata) + else call_data + ) self.gas_price = ( BitVec("gasprice{}".format(identifier), 256) if gas_price is None @@ -92,6 +96,9 @@ class MessageCallTransaction: global_state = GlobalState(self.world_state, environment, None) global_state.environment.active_function_name = "fallback" + global_state.mstate.constraints.extend( + global_state.environment.calldata.constraints + ) return global_state @@ -110,7 +117,7 @@ class ContractCreationTransaction: identifier=None, callee_account=None, code=None, - call_data=(), + call_data=None, gas_price=None, call_value=None, origin=None, @@ -147,7 +154,11 @@ class ContractCreationTransaction: else call_data_type ) - self.call_data = call_data + self.call_data = ( + Calldata(self.id, call_data) + if not isinstance(call_data, Calldata) + else call_data + ) self.origin = origin self.code = code self.return_data = None diff --git a/mythril/laser/ethereum/util.py b/mythril/laser/ethereum/util.py index d27fa89f..966c9c0d 100644 --- a/mythril/laser/ethereum/util.py +++ b/mythril/laser/ethereum/util.py @@ -2,7 +2,6 @@ import re from z3 import * import logging from typing import Union, List, Dict -from mythril.laser.ethereum.state import MachineState import sha3 as _sha3 @@ -38,14 +37,14 @@ def get_instruction_index( return None -def get_trace_line(instr: Dict, state: MachineState) -> str: +def get_trace_line(instr: Dict, state: "MachineState") -> str: stack = str(state.stack[::-1]) # stack = re.sub("(\d+)", lambda m: hex(int(m.group(1))), stack) stack = re.sub("\n", "", stack) return str(instr["address"]) + " " + instr["opcode"] + "\tSTACK: " + stack -def pop_bitvec(state: MachineState) -> BitVecVal: +def pop_bitvec(state: "MachineState") -> BitVecVal: # pop one element from stack, converting boolean expressions and # concrete Python variables to BitVecVal @@ -85,18 +84,20 @@ def get_concrete_int(item: Union[int, BitVecNumRef, BoolRef]) -> int: def concrete_int_from_bytes(_bytes: bytes, start_index: int) -> int: + # logging.debug("-- concrete_int_from_bytes: " + str(_bytes[start_index:start_index+32])) b = _bytes[start_index : start_index + 32] val = int.from_bytes(b, byteorder="big") return val -def concrete_int_to_bytes(val: int) -> bytes: - if isinstance(val, int): +def concrete_int_to_bytes(val): + # logging.debug("concrete_int_to_bytes " + str(val)) + if type(val) == int: return val.to_bytes(32, byteorder="big") return (simplify(val).as_long()).to_bytes(32, byteorder="big") -def bytearray_to_int(arr: bytearray) -> int: +def bytearray_to_int(arr): o = 0 for a in arr: o = (o << 8) + a diff --git a/mythril/mythril.py b/mythril/mythril.py index d917d7f8..d5dbd76f 100644 --- a/mythril/mythril.py +++ b/mythril/mythril.py @@ -77,18 +77,23 @@ class Mythril(object): """ - def __init__(self, solv=None, solc_args=None, dynld=False): + def __init__( + self, solv=None, solc_args=None, dynld=False, enable_online_lookup=False + ): self.solv = solv self.solc_args = solc_args self.dynld = dynld + self.enable_online_lookup = enable_online_lookup self.mythril_dir = self._init_mythril_dir() - self.sigs = signatures.SignatureDb() + self.sigs = signatures.SignatureDb( + enable_online_lookup=self.enable_online_lookup + ) try: self.sigs.open() # tries mythril_dir/signatures.json by default (provide path= arg to make this configurable) - except FileNotFoundError as fnfe: + except FileNotFoundError: logging.info( "No signature database found. Creating database if sigs are loaded in: " + self.sigs.signatures_file @@ -291,8 +296,7 @@ class Mythril(object): self.set_api_rpc(dynamic_loading) def search_db(self, search): - def search_callback(contract, address, balance): - + def search_callback(_, address, balance): print("Address: " + address + ", balance: " + str(balance)) try: @@ -309,7 +313,11 @@ class Mythril(object): def load_from_bytecode(self, code): address = util.get_indexed_address(0) - self.contracts.append(ETHContract(code, name="MAIN")) + self.contracts.append( + ETHContract( + code, name="MAIN", enable_online_lookup=self.enable_online_lookup + ) + ) return address, self.contracts[-1] # return address and contract object def load_from_address(self, address): @@ -320,7 +328,7 @@ class Mythril(object): code = self.eth.eth_getCode(address) except FileNotFoundError as e: raise CriticalError("IPC error: " + str(e)) - except ConnectionError as e: + except ConnectionError: raise CriticalError( "Could not connect to RPC server. Make sure that your node is running and that RPC parameters are set correctly." ) @@ -332,7 +340,13 @@ class Mythril(object): "Received an empty response from eth_getCode. Check the contract address and verify that you are on the correct chain." ) else: - self.contracts.append(ETHContract(code, name=address)) + self.contracts.append( + ETHContract( + code, + name=address, + enable_online_lookup=self.enable_online_lookup, + ) + ) return address, self.contracts[-1] # return address and contract object def load_from_solidity(self, solidity_files): @@ -541,7 +555,7 @@ class Mythril(object): ) except FileNotFoundError as e: raise CriticalError("IPC error: " + str(e)) - except ConnectionError as e: + except ConnectionError: raise CriticalError( "Could not connect to RPC server. Make sure that your node is running and that RPC parameters are set correctly." ) diff --git a/mythril/support/signatures.py b/mythril/support/signatures.py index 4bc1880c..ba214db6 100644 --- a/mythril/support/signatures.py +++ b/mythril/support/signatures.py @@ -11,7 +11,6 @@ from subprocess import Popen, PIPE from mythril.exceptions import CompilerError -# todo: tintinweb - make this a normal requirement? (deps: eth-abi and requests, both already required by mythril) try: # load if available but do not fail import ethereum_input_decoder @@ -54,7 +53,7 @@ except ImportError: class SignatureDb(object): - def __init__(self, enable_online_lookup=True): + def __init__(self, enable_online_lookup=False): """ Constr :param enable_online_lookup: enable onlien signature hash lookup @@ -191,9 +190,12 @@ class SignatureDb(object): "online function signature lookup not available. will not try to lookup hash for the next 2 minutes. exception: %r" % fbdole ) + + if sighash not in self.signatures: + return [] if type(self.signatures[sighash]) != list: return [self.signatures[sighash]] - return self.signatures[sighash] # raise keyerror + return self.signatures[sighash] def __getitem__(self, item): """ diff --git a/requirements.txt b/requirements.txt index 30162f8d..b41daf56 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,7 @@ coverage eth_abi>=1.0.0 eth-account>=0.1.0a2 ethereum>=2.3.2 +ethereum-input-decoder>=0.2.2 eth-hash>=0.1.0 eth-keyfile>=0.5.1 eth-keys>=0.2.0b3 diff --git a/setup.py b/setup.py index fe9ad5f5..6aa0dfb7 100755 --- a/setup.py +++ b/setup.py @@ -96,6 +96,7 @@ setup( "mock", "configparser>=3.5.0", "persistent>=4.2.0", + "ethereum-input-decoder>=0.2.2", ], tests_require=["pytest>=3.6.0", "pytest_mock", "pytest-cov"], python_requires=">=3.5", diff --git a/static/mythril.png b/static/mythril.png deleted file mode 100644 index f59c807e51e0f98b342e542453308e3295979fec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22977 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

|IfSUVK3< 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 KoFRAj$^QXZh>4Q` literal 0 HcmV?d00001 diff --git a/tests/analysis/test_delegatecall.py b/tests/analysis/test_delegatecall.py index a363f0da..72519d57 100644 --- a/tests/analysis/test_delegatecall.py +++ b/tests/analysis/test_delegatecall.py @@ -199,7 +199,7 @@ def test_delegate_call(sym_mock, concrete_mock, curr_instruction): statespace.calls = [call] # act - issues = execute(statespace) + execute(statespace) # assert assert concrete_mock.call_count == 1 diff --git a/tests/cmd_line_test.py b/tests/cmd_line_test.py index 91c8714d..394c5d42 100644 --- a/tests/cmd_line_test.py +++ b/tests/cmd_line_test.py @@ -29,10 +29,7 @@ class TruffleTestCase(BaseTestCase): command = "cd {}; truffle compile; python3 {} --truffle".format( truffle_project_root, MYTH ) - self.assertIn( - "In the function `withdrawfunds()` a non-zero amount of Ether is sent to msg.sender.", - output_of(command), - ) + self.assertIn("=== Ether send ====", output_of(command)) class InfuraTestCase(BaseTestCase): diff --git a/tests/disassembler/__init__.py b/tests/disassembler/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/disassembler/disassembly.py b/tests/disassembler/disassembly.py new file mode 100644 index 00000000..49bca31d --- /dev/null +++ b/tests/disassembler/disassembly.py @@ -0,0 +1,61 @@ +from mythril.disassembler.disassembly import * + +instruction_list = [ + {"opcode": "PUSH4", "argument": "0x10203040"}, + {"opcode": "EQ"}, + {"opcode": "PUSH4", "argument": "0x40302010"}, + {"opcode": "JUMPI"}, +] + + +def test_get_function_info(mocker): + # Arrange + global instruction_list + + signature_database_mock = SignatureDb() + mocker.patch.object(signature_database_mock, "get") + signature_database_mock.get.return_value = ["function_name"] + + # Act + function_hash, entry_point, function_name = get_function_info( + 0, instruction_list, signature_database_mock + ) + + # Assert + assert function_hash == "0x10203040" + assert entry_point == 0x40302010 + assert function_name == "function_name" + + +def test_get_function_info_multiple_names(mocker): + # Arrange + global instruction_list + + signature_database_mock = SignatureDb() + mocker.patch.object(signature_database_mock, "get") + signature_database_mock.get.return_value = ["function_name", "another_name"] + + # Act + function_hash, entry_point, function_name = get_function_info( + 0, instruction_list, signature_database_mock + ) + + # Assert + assert function_name == "**ambiguous** function_name" + + +def test_get_function_info_no_names(mocker): + # Arrange + global instruction_list + + signature_database_mock = SignatureDb() + mocker.patch.object(signature_database_mock, "get") + signature_database_mock.get.return_value = [] + + # Act + function_hash, entry_point, function_name = get_function_info( + 0, instruction_list, signature_database_mock + ) + + # Assert + assert function_name == "_function_0x10203040" diff --git a/tests/laser/evm_testsuite/evm_test.py b/tests/laser/evm_testsuite/evm_test.py index 7e96a8c5..5bab5e45 100644 --- a/tests/laser/evm_testsuite/evm_test.py +++ b/tests/laser/evm_testsuite/evm_test.py @@ -3,8 +3,8 @@ from mythril.laser.ethereum.svm import LaserEVM from mythril.laser.ethereum.state import Account from mythril.disassembler.disassembly import Disassembly from mythril.laser.ethereum.transaction.concolic import execute_message_call +from mythril.analysis.solver import get_model from datetime import datetime -from mythril.laser.ethereum.util import get_concrete_int import binascii import json from pathlib import Path @@ -83,6 +83,7 @@ def test_vmtest( return world_state = laser_evm.open_states[0] + model = get_model(next(iter(laser_evm.nodes.values())).states[0].mstate.constraints) for address, details in post_condition.items(): account = world_state[address] @@ -92,5 +93,9 @@ def test_vmtest( for index, value in details["storage"].items(): expected = int(value, 16) - actual = get_concrete_int(account.storage[int(index, 16)]) + if type(account.storage[int(index, 16)]) != int: + actual = model.eval(account.storage[int(index, 16)]) + actual = 1 if actual == True else 0 if actual == False else actual + else: + actual = account.storage[int(index, 16)] assert actual == expected diff --git a/tests/laser/state/calldata_test.py b/tests/laser/state/calldata_test.py new file mode 100644 index 00000000..c2d76c81 --- /dev/null +++ b/tests/laser/state/calldata_test.py @@ -0,0 +1,102 @@ +import pytest +from mythril.laser.ethereum.state import Calldata +from z3 import Solver, simplify +from z3.z3types import Z3Exception + + +uninitialized_test_data = [ + ([]), # Empty concrete calldata + ([1, 4, 5, 3, 4, 72, 230, 53]), # Concrete calldata +] + + +@pytest.mark.parametrize("starting_calldata", uninitialized_test_data) +def test_concrete_calldata_uninitialized_index(starting_calldata): + # Arrange + calldata = Calldata(0, starting_calldata) + solver = Solver() + + # Act + value = calldata[100] + value2 = calldata.get_word_at(200) + + solver.add(calldata.constraints) + solver.check() + model = solver.model() + + value = model.eval(value) + value2 = model.eval(value2) + + # Assert + assert value == 0 + assert value2 == 0 + + +def test_concrete_calldata_calldatasize(): + # Arrange + calldata = Calldata(0, [1, 4, 7, 3, 7, 2, 9]) + solver = Solver() + + # Act + solver.add(calldata.constraints) + solver.check() + model = solver.model() + + result = model.eval(calldata.calldatasize) + + # Assert + assert result == 7 + + +def test_symbolic_calldata_constrain_index(): + # Arrange + calldata = Calldata(0) + solver = Solver() + + # Act + constraint = calldata[100] == 50 + + value = calldata[100] + + solver.add(calldata.constraints + [constraint]) + solver.check() + model = solver.model() + + value = model.eval(value) + calldatasize = model.eval(calldata.calldatasize) + + # Assert + assert value == 50 + assert simplify(calldatasize >= 100) + + +def test_concrete_calldata_constrain_index(): + # Arrange + calldata = Calldata(0, [1, 4, 7, 3, 7, 2, 9]) + solver = Solver() + + # Act + constraint = calldata[2] == 3 + + solver.add(calldata.constraints + [constraint]) + result = solver.check() + + # Assert + assert str(result) == "unsat" + + +def test_concrete_calldata_constrain_index(): + # Arrange + calldata = Calldata(0) + solver = Solver() + + # Act + constraints = [] + constraints.append(calldata[51] == 1) + constraints.append(calldata.calldatasize == 50) + + solver.add(calldata.constraints + constraints) + result = solver.check() + + # Assert + assert str(result) == "unsat" diff --git a/tests/laser/state/mstack_test.py b/tests/laser/state/mstack_test.py index 9724fd38..03787075 100644 --- a/tests/laser/state/mstack_test.py +++ b/tests/laser/state/mstack_test.py @@ -44,7 +44,7 @@ class MachineStackTest(BaseTestCase): mstack = MachineStack([0, 1]) with pytest.raises(NotImplementedError): - mstack = mstack + [2] + mstack + [2] @staticmethod def test_mstack_no_support_iadd(): diff --git a/tests/laser/transaction/symbolic_test.py b/tests/laser/transaction/symbolic_test.py index e14e5618..2ca12f63 100644 --- a/tests/laser/transaction/symbolic_test.py +++ b/tests/laser/transaction/symbolic_test.py @@ -59,7 +59,7 @@ def test_execute_contract_creation(mocked_setup: MagicMock): mocked_setup.side_effect = _is_contract_creation # Act - new_account = execute_contract_creation(laser_evm, "606000") + execute_contract_creation(laser_evm, "606000") # Assert # mocked_setup.assert_called() diff --git a/tests/report_test.py b/tests/report_test.py index 26aa5be6..8cee1d65 100644 --- a/tests/report_test.py +++ b/tests/report_test.py @@ -23,7 +23,7 @@ def _fix_debug_data(json_str): def _generate_report(input_file): - contract = ETHContract(input_file.read_text()) + contract = ETHContract(input_file.read_text(), enable_online_lookup=False) sym = SymExecWrapper( contract, address=(util.get_indexed_address(0)), @@ -43,7 +43,9 @@ def _generate_report(input_file): def reports(): """ Fixture that analyses all reports""" pool = Pool(cpu_count()) - input_files = sorted([f for f in TESTDATA_INPUTS.iterdir()]) + input_files = sorted( + [f for f in TESTDATA_INPUTS.iterdir() if f.name != "environments.sol.o"] + ) results = pool.map(_generate_report, input_files) return results diff --git a/tests/svm_test.py b/tests/svm_test.py index ba580440..acf3329e 100644 --- a/tests/svm_test.py +++ b/tests/svm_test.py @@ -69,7 +69,7 @@ class SVMTestCase(BaseTestCase): def test_laser_result(self): for input_file in TESTDATA_INPUTS_CONTRACTS.iterdir(): - if input_file.name == "weak_random.sol": + if input_file.name in ["weak_random.sol", "environments.sol"]: continue output_expected = TESTDATA_OUTPUTS_EXPECTED_LASER_RESULT / ( input_file.name + ".json" diff --git a/tests/testdata/outputs_expected/calls.sol.o.graph.html b/tests/testdata/outputs_expected/calls.sol.o.graph.html index 6af2b5fa..1e131531 100644 --- a/tests/testdata/outputs_expected/calls.sol.o.graph.html +++ b/tests/testdata/outputs_expected/calls.sol.o.graph.html @@ -8,6 +8,7 @@

Mythril / Ethereum LASER Symbolic VM

-


+

Mythril / Ethereum LASER Symbolic VM

-


+

Mythril / Ethereum LASER Symbolic VM

-


+

Mythril / Ethereum LASER Symbolic VM

-


+

Mythril / Ethereum LASER Symbolic VM

-


+

Mythril / Ethereum LASER Symbolic VM

-


+

Mythril / Ethereum LASER Symbolic VM

-


+

Mythril / Ethereum LASER Symbolic VM

-


+

Mythril / Ethereum LASER Symbolic VM

-


+
+ + + + + + + + +

Mythril / Ethereum LASER Symbolic VM

+
+ + + \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/calls.sol.o.json b/tests/testdata/outputs_expected/outputs_current/calls.sol.o.json new file mode 100644 index 00000000..d7b6f7e0 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/calls.sol.o.json @@ -0,0 +1 @@ +{"error": null, "issues": [{"address": 661, "contract": "Unknown", "debug": "", "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.", "function": "_function_0x5a6814ec", "swc_id": "107", "title": "Message call to external contract", "type": "Informational"}, {"address": 666, "contract": "Unknown", "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0x5a6814ec", "swc_id": "104", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 779, "contract": "Unknown", "debug": "", "description": "This contract executes a message call to an address found at storage slot 1. This storage slot can be written to by calling the function `_function_0x2776b163`. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.", "function": "_function_0xd24b08cc", "swc_id": "107", "title": "Message call to external contract", "type": "Warning"}, {"address": 779, "contract": "Unknown", "debug": "", "description": "Possible transaction order dependence vulnerability: The value or direction of the call statement is determined from a tainted storage location", "function": "_function_0xd24b08cc", "swc_id": "114", "title": "Transaction order dependence", "type": "Warning"}, {"address": 784, "contract": "Unknown", "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xd24b08cc", "swc_id": "104", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 858, "contract": "Unknown", "debug": "", "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.", "function": "_function_0xe11f493e", "swc_id": "107", "title": "Message call to external contract", "type": "Informational"}, {"address": 869, "contract": "Unknown", "debug": "", "description": "The contract account state is changed after an external call. Consider that the called contract could re-enter the function before this state change takes place. This can lead to business logic vulnerabilities.", "function": "_function_0xe11f493e", "swc_id": "107", "title": "State change after external call", "type": "Warning"}, {"address": 871, "contract": "Unknown", "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xe11f493e", "swc_id": "104", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 912, "contract": "Unknown", "debug": "", "description": "This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.", "function": "_function_0xe1d10f79", "swc_id": "107", "title": "Message call to external contract", "type": "Warning"}, {"address": 918, "contract": "Unknown", "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xe1d10f79", "swc_id": "104", "title": "Unchecked CALL return value", "type": "Informational"}], "success": true} \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/calls.sol.o.markdown b/tests/testdata/outputs_expected/outputs_current/calls.sol.o.markdown new file mode 100644 index 00000000..f19dbaef --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/calls.sol.o.markdown @@ -0,0 +1,111 @@ +# Analysis results for test-filename.sol + +## Message call to external contract +- SWC ID: 107 +- Type: Informational +- Contract: Unknown +- Function name: `_function_0x5a6814ec` +- PC address: 661 + +### Description + +This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code. + +## Unchecked CALL return value +- SWC ID: 104 +- Type: Informational +- Contract: Unknown +- Function name: `_function_0x5a6814ec` +- PC address: 666 + +### Description + +The return value of an external call is not checked. Note that execution continue even if the called contract throws. + +## Message call to external contract +- SWC ID: 107 +- Type: Warning +- Contract: Unknown +- Function name: `_function_0xd24b08cc` +- PC address: 779 + +### Description + +This contract executes a message call to an address found at storage slot 1. This storage slot can be written to by calling the function `_function_0x2776b163`. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state. + +## Transaction order dependence +- SWC ID: 114 +- Type: Warning +- Contract: Unknown +- Function name: `_function_0xd24b08cc` +- PC address: 779 + +### Description + +Possible transaction order dependence vulnerability: The value or direction of the call statement is determined from a tainted storage location + +## Unchecked CALL return value +- SWC ID: 104 +- Type: Informational +- Contract: Unknown +- Function name: `_function_0xd24b08cc` +- PC address: 784 + +### Description + +The return value of an external call is not checked. Note that execution continue even if the called contract throws. + +## Message call to external contract +- SWC ID: 107 +- Type: Informational +- Contract: Unknown +- Function name: `_function_0xe11f493e` +- PC address: 858 + +### Description + +This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code. + +## State change after external call +- SWC ID: 107 +- Type: Warning +- Contract: Unknown +- Function name: `_function_0xe11f493e` +- PC address: 869 + +### Description + +The contract account state is changed after an external call. Consider that the called contract could re-enter the function before this state change takes place. This can lead to business logic vulnerabilities. + +## Unchecked CALL return value +- SWC ID: 104 +- Type: Informational +- Contract: Unknown +- Function name: `_function_0xe11f493e` +- PC address: 871 + +### Description + +The return value of an external call is not checked. Note that execution continue even if the called contract throws. + +## Message call to external contract +- SWC ID: 107 +- Type: Warning +- Contract: Unknown +- Function name: `_function_0xe1d10f79` +- PC address: 912 + +### Description + +This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state. + +## Unchecked CALL return value +- SWC ID: 104 +- Type: Informational +- Contract: Unknown +- Function name: `_function_0xe1d10f79` +- PC address: 918 + +### Description + +The return value of an external call is not checked. Note that execution continue even if the called contract throws. diff --git a/tests/testdata/outputs_expected/outputs_current/calls.sol.o.text b/tests/testdata/outputs_expected/outputs_current/calls.sol.o.text new file mode 100644 index 00000000..c65b9fc7 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/calls.sol.o.text @@ -0,0 +1,90 @@ +==== Message call to external contract ==== +SWC ID: 107 +Type: Informational +Contract: Unknown +Function name: _function_0x5a6814ec +PC address: 661 +This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code. +-------------------- + +==== Unchecked CALL return value ==== +SWC ID: 104 +Type: Informational +Contract: Unknown +Function name: _function_0x5a6814ec +PC address: 666 +The return value of an external call is not checked. Note that execution continue even if the called contract throws. +-------------------- + +==== Message call to external contract ==== +SWC ID: 107 +Type: Warning +Contract: Unknown +Function name: _function_0xd24b08cc +PC address: 779 +This contract executes a message call to an address found at storage slot 1. This storage slot can be written to by calling the function `_function_0x2776b163`. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state. +-------------------- + +==== Transaction order dependence ==== +SWC ID: 114 +Type: Warning +Contract: Unknown +Function name: _function_0xd24b08cc +PC address: 779 +Possible transaction order dependence vulnerability: The value or direction of the call statement is determined from a tainted storage location +-------------------- + +==== Unchecked CALL return value ==== +SWC ID: 104 +Type: Informational +Contract: Unknown +Function name: _function_0xd24b08cc +PC address: 784 +The return value of an external call is not checked. Note that execution continue even if the called contract throws. +-------------------- + +==== Message call to external contract ==== +SWC ID: 107 +Type: Informational +Contract: Unknown +Function name: _function_0xe11f493e +PC address: 858 +This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code. +-------------------- + +==== State change after external call ==== +SWC ID: 107 +Type: Warning +Contract: Unknown +Function name: _function_0xe11f493e +PC address: 869 +The contract account state is changed after an external call. Consider that the called contract could re-enter the function before this state change takes place. This can lead to business logic vulnerabilities. +-------------------- + +==== Unchecked CALL return value ==== +SWC ID: 104 +Type: Informational +Contract: Unknown +Function name: _function_0xe11f493e +PC address: 871 +The return value of an external call is not checked. Note that execution continue even if the called contract throws. +-------------------- + +==== Message call to external contract ==== +SWC ID: 107 +Type: Warning +Contract: Unknown +Function name: _function_0xe1d10f79 +PC address: 912 +This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state. +-------------------- + +==== Unchecked CALL return value ==== +SWC ID: 104 +Type: Informational +Contract: Unknown +Function name: _function_0xe1d10f79 +PC address: 918 +The return value of an external call is not checked. Note that execution continue even if the called contract throws. +-------------------- + diff --git a/tests/testdata/outputs_expected/outputs_current/environments.sol.o.easm b/tests/testdata/outputs_expected/outputs_current/environments.sol.o.easm new file mode 100644 index 00000000..7a5b2043 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/environments.sol.o.easm @@ -0,0 +1,259 @@ +0 PUSH1 0x80 +2 PUSH1 0x40 +4 MSTORE +5 PUSH1 0x04 +7 CALLDATASIZE +8 LT +9 PUSH2 0x004c +12 JUMPI +13 PUSH1 0x00 +15 CALLDATALOAD +16 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 +46 SWAP1 +47 DIV +48 PUSH4 0xffffffff +53 AND +54 DUP1 +55 PUSH4 0x06661abd +60 EQ +61 PUSH2 0x0051 +64 JUMPI +65 DUP1 +66 PUSH4 0x83f12fec +71 EQ +72 PUSH2 0x007c +75 JUMPI +76 JUMPDEST +77 PUSH1 0x00 +79 DUP1 +80 REVERT +81 JUMPDEST +82 CALLVALUE +83 DUP1 +84 ISZERO +85 PUSH2 0x005d +88 JUMPI +89 PUSH1 0x00 +91 DUP1 +92 REVERT +93 JUMPDEST +94 POP +95 PUSH2 0x0066 +98 PUSH2 0x0104 +101 JUMP +102 JUMPDEST +103 PUSH1 0x40 +105 MLOAD +106 DUP1 +107 DUP3 +108 DUP2 +109 MSTORE +110 PUSH1 0x20 +112 ADD +113 SWAP2 +114 POP +115 POP +116 PUSH1 0x40 +118 MLOAD +119 DUP1 +120 SWAP2 +121 SUB +122 SWAP1 +123 RETURN +124 JUMPDEST +125 CALLVALUE +126 DUP1 +127 ISZERO +128 PUSH2 0x0088 +131 JUMPI +132 PUSH1 0x00 +134 DUP1 +135 REVERT +136 JUMPDEST +137 POP +138 PUSH2 0x00ea +141 PUSH1 0x04 +143 DUP1 +144 CALLDATASIZE +145 SUB +146 DUP2 +147 ADD +148 SWAP1 +149 DUP1 +150 DUP1 +151 CALLDATALOAD +152 SWAP1 +153 PUSH1 0x20 +155 ADD +156 SWAP1 +157 DUP3 +158 ADD +159 DUP1 +160 CALLDATALOAD +161 SWAP1 +162 PUSH1 0x20 +164 ADD +165 SWAP1 +166 DUP1 +167 DUP1 +168 PUSH1 0x20 +170 MUL +171 PUSH1 0x20 +173 ADD +174 PUSH1 0x40 +176 MLOAD +177 SWAP1 +178 DUP2 +179 ADD +180 PUSH1 0x40 +182 MSTORE +183 DUP1 +184 SWAP4 +185 SWAP3 +186 SWAP2 +187 SWAP1 +188 DUP2 +189 DUP2 +190 MSTORE +191 PUSH1 0x20 +193 ADD +194 DUP4 +195 DUP4 +196 PUSH1 0x20 +198 MUL +199 DUP1 +200 DUP3 +201 DUP5 +202 CALLDATACOPY +203 DUP3 +204 ADD +205 SWAP2 +206 POP +207 POP +208 POP +209 POP +210 POP +211 POP +212 SWAP2 +213 SWAP3 +214 SWAP2 +215 SWAP3 +216 SWAP1 +217 DUP1 +218 CALLDATALOAD +219 SWAP1 +220 PUSH1 0x20 +222 ADD +223 SWAP1 +224 SWAP3 +225 SWAP2 +226 SWAP1 +227 POP +228 POP +229 POP +230 PUSH2 0x010a +233 JUMP +234 JUMPDEST +235 PUSH1 0x40 +237 MLOAD +238 DUP1 +239 DUP3 +240 ISZERO +241 ISZERO +242 ISZERO +243 ISZERO +244 DUP2 +245 MSTORE +246 PUSH1 0x20 +248 ADD +249 SWAP2 +250 POP +251 POP +252 PUSH1 0x40 +254 MLOAD +255 DUP1 +256 SWAP2 +257 SUB +258 SWAP1 +259 RETURN +260 JUMPDEST +261 PUSH1 0x00 +263 SLOAD +264 DUP2 +265 JUMP +266 JUMPDEST +267 PUSH1 0x00 +269 DUP1 +270 PUSH1 0x00 +272 DUP5 +273 MLOAD +274 SWAP2 +275 POP +276 DUP4 +277 DUP3 +278 MUL +279 SWAP1 +280 POP +281 PUSH1 0x00 +283 DUP3 +284 GT +285 DUP1 +286 ISZERO +287 PUSH2 0x0129 +290 JUMPI +291 POP +292 PUSH1 0x14 +294 DUP3 +295 GT +296 ISZERO +297 JUMPDEST +298 ISZERO +299 ISZERO +300 PUSH2 0x0134 +303 JUMPI +304 PUSH1 0x00 +306 DUP1 +307 REVERT +308 JUMPDEST +309 DUP1 +310 PUSH1 0x01 +312 PUSH1 0x00 +314 CALLER +315 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +336 AND +337 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +358 AND +359 DUP2 +360 MSTORE +361 PUSH1 0x20 +363 ADD +364 SWAP1 +365 DUP2 +366 MSTORE +367 PUSH1 0x20 +369 ADD +370 PUSH1 0x00 +372 SHA3 +373 PUSH1 0x00 +375 DUP3 +376 DUP3 +377 SLOAD +378 SUB +379 SWAP3 +380 POP +381 POP +382 DUP2 +383 SWAP1 +384 SSTORE +385 POP +386 PUSH1 0x01 +388 SWAP3 +389 POP +390 POP +391 POP +392 SWAP3 +393 SWAP2 +394 POP +395 POP +396 JUMP +397 STOP diff --git a/tests/testdata/outputs_expected/outputs_current/environments.sol.o.graph.html b/tests/testdata/outputs_expected/outputs_current/environments.sol.o.graph.html new file mode 100644 index 00000000..bc273a9e --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/environments.sol.o.graph.html @@ -0,0 +1,62 @@ + + + + Call Graph + + + + + + + + + + +

Mythril / Ethereum LASER Symbolic VM

+
+ + + \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.easm b/tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.easm new file mode 100644 index 00000000..b0a5e256 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.easm @@ -0,0 +1,420 @@ +0 PUSH1 0x80 +2 PUSH1 0x40 +4 MSTORE +5 PUSH1 0x04 +7 CALLDATASIZE +8 LT +9 PUSH2 0x0078 +12 JUMPI +13 PUSH1 0x00 +15 CALLDATALOAD +16 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 +46 SWAP1 +47 DIV +48 PUSH4 0xffffffff +53 AND +54 DUP1 +55 PUSH4 0x12065fe0 +60 EQ +61 PUSH2 0x007d +64 JUMPI +65 DUP1 +66 PUSH4 0x27e235e3 +71 EQ +72 PUSH2 0x00a8 +75 JUMPI +76 DUP1 +77 PUSH4 0x56885cd8 +82 EQ +83 PUSH2 0x00ff +86 JUMPI +87 DUP1 +88 PUSH4 0x6c343ffe +93 EQ +94 PUSH2 0x0116 +97 JUMPI +98 DUP1 +99 PUSH4 0x8da5cb5b +104 EQ +105 PUSH2 0x012d +108 JUMPI +109 DUP1 +110 PUSH4 0xe8b5e51f +115 EQ +116 PUSH2 0x0184 +119 JUMPI +120 JUMPDEST +121 PUSH1 0x00 +123 DUP1 +124 REVERT +125 JUMPDEST +126 CALLVALUE +127 DUP1 +128 ISZERO +129 PUSH2 0x0089 +132 JUMPI +133 PUSH1 0x00 +135 DUP1 +136 REVERT +137 JUMPDEST +138 POP +139 PUSH2 0x0092 +142 PUSH2 0x018e +145 JUMP +146 JUMPDEST +147 PUSH1 0x40 +149 MLOAD +150 DUP1 +151 DUP3 +152 DUP2 +153 MSTORE +154 PUSH1 0x20 +156 ADD +157 SWAP2 +158 POP +159 POP +160 PUSH1 0x40 +162 MLOAD +163 DUP1 +164 SWAP2 +165 SUB +166 SWAP1 +167 RETURN +168 JUMPDEST +169 CALLVALUE +170 DUP1 +171 ISZERO +172 PUSH2 0x00b4 +175 JUMPI +176 PUSH1 0x00 +178 DUP1 +179 REVERT +180 JUMPDEST +181 POP +182 PUSH2 0x00e9 +185 PUSH1 0x04 +187 DUP1 +188 CALLDATASIZE +189 SUB +190 DUP2 +191 ADD +192 SWAP1 +193 DUP1 +194 DUP1 +195 CALLDATALOAD +196 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +217 AND +218 SWAP1 +219 PUSH1 0x20 +221 ADD +222 SWAP1 +223 SWAP3 +224 SWAP2 +225 SWAP1 +226 POP +227 POP +228 POP +229 PUSH2 0x01d4 +232 JUMP +233 JUMPDEST +234 PUSH1 0x40 +236 MLOAD +237 DUP1 +238 DUP3 +239 DUP2 +240 MSTORE +241 PUSH1 0x20 +243 ADD +244 SWAP2 +245 POP +246 POP +247 PUSH1 0x40 +249 MLOAD +250 DUP1 +251 SWAP2 +252 SUB +253 SWAP1 +254 RETURN +255 JUMPDEST +256 CALLVALUE +257 DUP1 +258 ISZERO +259 PUSH2 0x010b +262 JUMPI +263 PUSH1 0x00 +265 DUP1 +266 REVERT +267 JUMPDEST +268 POP +269 PUSH2 0x0114 +272 PUSH2 0x01ec +275 JUMP +276 JUMPDEST +277 STOP +278 JUMPDEST +279 CALLVALUE +280 DUP1 +281 ISZERO +282 PUSH2 0x0122 +285 JUMPI +286 PUSH1 0x00 +288 DUP1 +289 REVERT +290 JUMPDEST +291 POP +292 PUSH2 0x012b +295 PUSH2 0x022f +298 JUMP +299 JUMPDEST +300 STOP +301 JUMPDEST +302 CALLVALUE +303 DUP1 +304 ISZERO +305 PUSH2 0x0139 +308 JUMPI +309 PUSH1 0x00 +311 DUP1 +312 REVERT +313 JUMPDEST +314 POP +315 PUSH2 0x0142 +318 PUSH2 0x02eb +321 JUMP +322 JUMPDEST +323 PUSH1 0x40 +325 MLOAD +326 DUP1 +327 DUP3 +328 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +349 AND +350 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +371 AND +372 DUP2 +373 MSTORE +374 PUSH1 0x20 +376 ADD +377 SWAP2 +378 POP +379 POP +380 PUSH1 0x40 +382 MLOAD +383 DUP1 +384 SWAP2 +385 SUB +386 SWAP1 +387 RETURN +388 JUMPDEST +389 PUSH2 0x018c +392 PUSH2 0x0311 +395 JUMP +396 JUMPDEST +397 STOP +398 JUMPDEST +399 PUSH1 0x00 +401 DUP1 +402 PUSH1 0x00 +404 CALLER +405 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +426 AND +427 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +448 AND +449 DUP2 +450 MSTORE +451 PUSH1 0x20 +453 ADD +454 SWAP1 +455 DUP2 +456 MSTORE +457 PUSH1 0x20 +459 ADD +460 PUSH1 0x00 +462 SHA3 +463 SLOAD +464 SWAP1 +465 POP +466 SWAP1 +467 JUMP +468 JUMPDEST +469 PUSH1 0x00 +471 PUSH1 0x20 +473 MSTORE +474 DUP1 +475 PUSH1 0x00 +477 MSTORE +478 PUSH1 0x40 +480 PUSH1 0x00 +482 SHA3 +483 PUSH1 0x00 +485 SWAP2 +486 POP +487 SWAP1 +488 POP +489 SLOAD +490 DUP2 +491 JUMP +492 JUMPDEST +493 CALLER +494 PUSH1 0x01 +496 PUSH1 0x00 +498 PUSH2 0x0100 +501 EXP +502 DUP2 +503 SLOAD +504 DUP2 +505 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +526 MUL +527 NOT +528 AND +529 SWAP1 +530 DUP4 +531 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +552 AND +553 MUL +554 OR +555 SWAP1 +556 SSTORE +557 POP +558 JUMP +559 JUMPDEST +560 PUSH1 0x01 +562 PUSH1 0x00 +564 SWAP1 +565 SLOAD +566 SWAP1 +567 PUSH2 0x0100 +570 EXP +571 SWAP1 +572 DIV +573 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +594 AND +595 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +616 AND +617 CALLER +618 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +639 AND +640 EQ +641 ISZERO +642 ISZERO +643 PUSH2 0x028b +646 JUMPI +647 PUSH1 0x00 +649 DUP1 +650 REVERT +651 JUMPDEST +652 CALLER +653 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +674 AND +675 PUSH2 0x08fc +678 ADDRESS +679 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +700 AND +701 BALANCE +702 SWAP1 +703 DUP2 +704 ISZERO +705 MUL +706 SWAP1 +707 PUSH1 0x40 +709 MLOAD +710 PUSH1 0x00 +712 PUSH1 0x40 +714 MLOAD +715 DUP1 +716 DUP4 +717 SUB +718 DUP2 +719 DUP6 +720 DUP9 +721 DUP9 +722 CALL +723 SWAP4 +724 POP +725 POP +726 POP +727 POP +728 ISZERO +729 DUP1 +730 ISZERO +731 PUSH2 0x02e8 +734 JUMPI +735 RETURNDATASIZE +736 PUSH1 0x00 +738 DUP1 +739 RETURNDATACOPY +740 RETURNDATASIZE +741 PUSH1 0x00 +743 REVERT +744 JUMPDEST +745 POP +746 JUMP +747 JUMPDEST +748 PUSH1 0x01 +750 PUSH1 0x00 +752 SWAP1 +753 SLOAD +754 SWAP1 +755 PUSH2 0x0100 +758 EXP +759 SWAP1 +760 DIV +761 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +782 AND +783 DUP2 +784 JUMP +785 JUMPDEST +786 PUSH1 0x02 +788 SLOAD +789 CALLVALUE +790 GT +791 DUP1 +792 ISZERO +793 PUSH2 0x0323 +796 JUMPI +797 POP +798 PUSH1 0x03 +800 SLOAD +801 CALLVALUE +802 LT +803 JUMPDEST +804 ISZERO +805 ISZERO +806 PUSH2 0x032e +809 JUMPI +810 PUSH1 0x00 +812 DUP1 +813 REVERT +814 JUMPDEST +815 CALLVALUE +816 PUSH1 0x00 +818 DUP1 +819 CALLER +820 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +841 AND +842 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +863 AND +864 DUP2 +865 MSTORE +866 PUSH1 0x20 +868 ADD +869 SWAP1 +870 DUP2 +871 MSTORE +872 PUSH1 0x20 +874 ADD +875 PUSH1 0x00 +877 SHA3 +878 PUSH1 0x00 +880 DUP3 +881 DUP3 +882 SLOAD +883 ADD +884 SWAP3 +885 POP +886 POP +887 DUP2 +888 SWAP1 +889 SSTORE +890 POP +891 JUMP +892 STOP diff --git a/tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.graph.html b/tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.graph.html new file mode 100644 index 00000000..dbd5387a --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.graph.html @@ -0,0 +1,62 @@ + + + + Call Graph + + + + + + + + + + +

Mythril / Ethereum LASER Symbolic VM

+
+ + + \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.json b/tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.json new file mode 100644 index 00000000..da2d8d12 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.json @@ -0,0 +1 @@ +{"error": null, "issues": [{"address": 722, "contract": "Unknown", "debug": "", "description": "It seems that an attacker is able to execute an call instruction, this can mean that the attacker is able to extract funds out of the contract.", "function": "withdrawfunds()", "swc_id": "105", "title": "Ether send", "type": "Warning"}, {"address": 883, "contract": "Unknown", "debug": "", "description": "The arithmetic operation can result in integer overflow.\n", "function": "invest()", "swc_id": "101", "title": "Integer Overflow", "type": "Warning"}], "success": true} \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.markdown b/tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.markdown new file mode 100644 index 00000000..c4e23873 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.markdown @@ -0,0 +1,23 @@ +# Analysis results for test-filename.sol + +## Ether send +- SWC ID: 105 +- Type: Warning +- Contract: Unknown +- Function name: `withdrawfunds()` +- PC address: 722 + +### Description + +It seems that an attacker is able to execute an call instruction, this can mean that the attacker is able to extract funds out of the contract. + +## Integer Overflow +- SWC ID: 101 +- Type: Warning +- Contract: Unknown +- Function name: `invest()` +- PC address: 883 + +### Description + +The arithmetic operation can result in integer overflow. diff --git a/tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.text b/tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.text new file mode 100644 index 00000000..6be210d9 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.text @@ -0,0 +1,19 @@ +==== Ether send ==== +SWC ID: 105 +Type: Warning +Contract: Unknown +Function name: withdrawfunds() +PC address: 722 +It seems that an attacker is able to execute an call instruction, this can mean that the attacker is able to extract funds out of the contract. +-------------------- + +==== Integer Overflow ==== +SWC ID: 101 +Type: Warning +Contract: Unknown +Function name: invest() +PC address: 883 +The arithmetic operation can result in integer overflow. + +-------------------- + diff --git a/tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.easm b/tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.easm new file mode 100644 index 00000000..ef83a75c --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.easm @@ -0,0 +1,392 @@ +0 PUSH1 0x60 +2 PUSH1 0x40 +4 MSTORE +5 PUSH1 0x04 +7 CALLDATASIZE +8 LT +9 PUSH2 0x008e +12 JUMPI +13 PUSH1 0x00 +15 CALLDATALOAD +16 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 +46 SWAP1 +47 DIV +48 PUSH4 0xffffffff +53 AND +54 DUP1 +55 PUSH4 0x01d4277c +60 EQ +61 PUSH2 0x0093 +64 JUMPI +65 DUP1 +66 PUSH4 0x546455b5 +71 EQ +72 PUSH2 0x00b6 +75 JUMPI +76 DUP1 +77 PUSH4 0x78375f14 +82 EQ +83 PUSH2 0x00d9 +86 JUMPI +87 DUP1 +88 PUSH4 0x92dd38ea +93 EQ +94 PUSH2 0x00fc +97 JUMPI +98 DUP1 +99 PUSH4 0xa08299f1 +104 EQ +105 PUSH2 0x011f +108 JUMPI +109 DUP1 +110 PUSH4 0xb34c3610 +115 EQ +116 PUSH2 0x0142 +119 JUMPI +120 DUP1 +121 PUSH4 0xb630d706 +126 EQ +127 PUSH2 0x0157 +130 JUMPI +131 DUP1 +132 PUSH4 0xf44f13d8 +137 EQ +138 PUSH2 0x017a +141 JUMPI +142 JUMPDEST +143 PUSH1 0x00 +145 DUP1 +146 REVERT +147 JUMPDEST +148 CALLVALUE +149 ISZERO +150 PUSH2 0x009e +153 JUMPI +154 PUSH1 0x00 +156 DUP1 +157 REVERT +158 JUMPDEST +159 PUSH2 0x00b4 +162 PUSH1 0x04 +164 DUP1 +165 DUP1 +166 CALLDATALOAD +167 SWAP1 +168 PUSH1 0x20 +170 ADD +171 SWAP1 +172 SWAP2 +173 SWAP1 +174 POP +175 POP +176 PUSH2 0x018f +179 JUMP +180 JUMPDEST +181 STOP +182 JUMPDEST +183 CALLVALUE +184 ISZERO +185 PUSH2 0x00c1 +188 JUMPI +189 PUSH1 0x00 +191 DUP1 +192 REVERT +193 JUMPDEST +194 PUSH2 0x00d7 +197 PUSH1 0x04 +199 DUP1 +200 DUP1 +201 CALLDATALOAD +202 SWAP1 +203 PUSH1 0x20 +205 ADD +206 SWAP1 +207 SWAP2 +208 SWAP1 +209 POP +210 POP +211 PUSH2 0x01b2 +214 JUMP +215 JUMPDEST +216 STOP +217 JUMPDEST +218 CALLVALUE +219 ISZERO +220 PUSH2 0x00e4 +223 JUMPI +224 PUSH1 0x00 +226 DUP1 +227 REVERT +228 JUMPDEST +229 PUSH2 0x00fa +232 PUSH1 0x04 +234 DUP1 +235 DUP1 +236 CALLDATALOAD +237 SWAP1 +238 PUSH1 0x20 +240 ADD +241 SWAP1 +242 SWAP2 +243 SWAP1 +244 POP +245 POP +246 PUSH2 0x01c2 +249 JUMP +250 JUMPDEST +251 STOP +252 JUMPDEST +253 CALLVALUE +254 ISZERO +255 PUSH2 0x0107 +258 JUMPI +259 PUSH1 0x00 +261 DUP1 +262 REVERT +263 JUMPDEST +264 PUSH2 0x011d +267 PUSH1 0x04 +269 DUP1 +270 DUP1 +271 CALLDATALOAD +272 SWAP1 +273 PUSH1 0x20 +275 ADD +276 SWAP1 +277 SWAP2 +278 SWAP1 +279 POP +280 POP +281 PUSH2 0x01d5 +284 JUMP +285 JUMPDEST +286 STOP +287 JUMPDEST +288 CALLVALUE +289 ISZERO +290 PUSH2 0x012a +293 JUMPI +294 PUSH1 0x00 +296 DUP1 +297 REVERT +298 JUMPDEST +299 PUSH2 0x0140 +302 PUSH1 0x04 +304 DUP1 +305 DUP1 +306 CALLDATALOAD +307 SWAP1 +308 PUSH1 0x20 +310 ADD +311 SWAP1 +312 SWAP2 +313 SWAP1 +314 POP +315 POP +316 PUSH2 0x01ed +319 JUMP +320 JUMPDEST +321 STOP +322 JUMPDEST +323 CALLVALUE +324 ISZERO +325 PUSH2 0x014d +328 JUMPI +329 PUSH1 0x00 +331 DUP1 +332 REVERT +333 JUMPDEST +334 PUSH2 0x0155 +337 PUSH2 0x0202 +340 JUMP +341 JUMPDEST +342 STOP +343 JUMPDEST +344 CALLVALUE +345 ISZERO +346 PUSH2 0x0162 +349 JUMPI +350 PUSH1 0x00 +352 DUP1 +353 REVERT +354 JUMPDEST +355 PUSH2 0x0178 +358 PUSH1 0x04 +360 DUP1 +361 DUP1 +362 CALLDATALOAD +363 SWAP1 +364 PUSH1 0x20 +366 ADD +367 SWAP1 +368 SWAP2 +369 SWAP1 +370 POP +371 POP +372 PUSH2 0x0217 +375 JUMP +376 JUMPDEST +377 STOP +378 JUMPDEST +379 CALLVALUE +380 ISZERO +381 PUSH2 0x0185 +384 JUMPI +385 PUSH1 0x00 +387 DUP1 +388 REVERT +389 JUMPDEST +390 PUSH2 0x018d +393 PUSH2 0x0235 +396 JUMP +397 JUMPDEST +398 STOP +399 JUMPDEST +400 PUSH1 0x00 +402 PUSH1 0x08 +404 DUP3 +405 LT +406 ISZERO +407 PUSH2 0x01ae +410 JUMPI +411 PUSH1 0x00 +413 DUP3 +414 PUSH1 0x08 +416 DUP2 +417 LT +418 ISZERO +419 ISZERO +420 PUSH2 0x01a9 +423 JUMPI +424 ASSERT_FAIL +425 JUMPDEST +426 ADD +427 SLOAD +428 SWAP1 +429 POP +430 JUMPDEST +431 POP +432 POP +433 JUMP +434 JUMPDEST +435 PUSH1 0x17 +437 DUP2 +438 EQ +439 ISZERO +440 ISZERO +441 ISZERO +442 PUSH2 0x01bf +445 JUMPI +446 ASSERT_FAIL +447 JUMPDEST +448 POP +449 JUMP +450 JUMPDEST +451 PUSH1 0x17 +453 DUP2 +454 EQ +455 ISZERO +456 ISZERO +457 ISZERO +458 PUSH2 0x01d2 +461 JUMPI +462 PUSH1 0x00 +464 DUP1 +465 REVERT +466 JUMPDEST +467 POP +468 JUMP +469 JUMPDEST +470 PUSH1 0x00 +472 DUP1 +473 DUP3 +474 PUSH1 0x08 +476 DUP2 +477 LT +478 ISZERO +479 ISZERO +480 PUSH2 0x01e5 +483 JUMPI +484 ASSERT_FAIL +485 JUMPDEST +486 ADD +487 SLOAD +488 SWAP1 +489 POP +490 POP +491 POP +492 JUMP +493 JUMPDEST +494 PUSH1 0x00 +496 DUP2 +497 PUSH1 0x01 +499 DUP2 +500 ISZERO +501 ISZERO +502 PUSH2 0x01fb +505 JUMPI +506 ASSERT_FAIL +507 JUMPDEST +508 DIV +509 SWAP1 +510 POP +511 POP +512 POP +513 JUMP +514 JUMPDEST +515 PUSH1 0x00 +517 PUSH1 0x01 +519 SWAP1 +520 POP +521 PUSH1 0x00 +523 DUP2 +524 EQ +525 ISZERO +526 ISZERO +527 PUSH2 0x0214 +530 JUMPI +531 ASSERT_FAIL +532 JUMPDEST +533 POP +534 JUMP +535 JUMPDEST +536 PUSH1 0x00 +538 DUP1 +539 DUP3 +540 GT +541 ISZERO +542 PUSH2 0x0231 +545 JUMPI +546 DUP2 +547 PUSH1 0x01 +549 DUP2 +550 ISZERO +551 ISZERO +552 PUSH2 0x022d +555 JUMPI +556 ASSERT_FAIL +557 JUMPDEST +558 DIV +559 SWAP1 +560 POP +561 JUMPDEST +562 POP +563 POP +564 JUMP +565 JUMPDEST +566 PUSH1 0x00 +568 PUSH1 0x01 +570 SWAP1 +571 POP +572 PUSH1 0x00 +574 DUP2 +575 GT +576 ISZERO +577 ISZERO +578 PUSH2 0x0247 +581 JUMPI +582 ASSERT_FAIL +583 JUMPDEST +584 POP +585 JUMP +586 STOP diff --git a/tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.graph.html b/tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.graph.html new file mode 100644 index 00000000..c9f9356e --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.graph.html @@ -0,0 +1,62 @@ + + + + Call Graph + + + + + + + + + + +

Mythril / Ethereum LASER Symbolic VM

+
+ + + \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.json b/tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.json new file mode 100644 index 00000000..c8d722b5 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.json @@ -0,0 +1 @@ +{"error": null, "issues": [{"address": 446, "contract": "Unknown", "debug": "", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking. ", "function": "_function_0x546455b5", "swc_id": "110", "title": "Exception state", "type": "Informational"}, {"address": 484, "contract": "Unknown", "debug": "", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking. ", "function": "_function_0x92dd38ea", "swc_id": "110", "title": "Exception state", "type": "Informational"}, {"address": 506, "contract": "Unknown", "debug": "", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking. ", "function": "_function_0xa08299f1", "swc_id": "110", "title": "Exception state", "type": "Informational"}, {"address": 531, "contract": "Unknown", "debug": "", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking. ", "function": "_function_0xb34c3610", "swc_id": "110", "title": "Exception state", "type": "Informational"}], "success": true} \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.markdown b/tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.markdown new file mode 100644 index 00000000..2ed81d76 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.markdown @@ -0,0 +1,45 @@ +# Analysis results for test-filename.sol + +## Exception state +- SWC ID: 110 +- Type: Informational +- Contract: Unknown +- Function name: `_function_0x546455b5` +- PC address: 446 + +### Description + +A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking. + +## Exception state +- SWC ID: 110 +- Type: Informational +- Contract: Unknown +- Function name: `_function_0x92dd38ea` +- PC address: 484 + +### Description + +A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking. + +## Exception state +- SWC ID: 110 +- Type: Informational +- Contract: Unknown +- Function name: `_function_0xa08299f1` +- PC address: 506 + +### Description + +A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking. + +## Exception state +- SWC ID: 110 +- Type: Informational +- Contract: Unknown +- Function name: `_function_0xb34c3610` +- PC address: 531 + +### Description + +A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking. diff --git a/tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.text b/tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.text new file mode 100644 index 00000000..a9ac2d73 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.text @@ -0,0 +1,36 @@ +==== Exception state ==== +SWC ID: 110 +Type: Informational +Contract: Unknown +Function name: _function_0x546455b5 +PC address: 446 +A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking. +-------------------- + +==== Exception state ==== +SWC ID: 110 +Type: Informational +Contract: Unknown +Function name: _function_0x92dd38ea +PC address: 484 +A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking. +-------------------- + +==== Exception state ==== +SWC ID: 110 +Type: Informational +Contract: Unknown +Function name: _function_0xa08299f1 +PC address: 506 +A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking. +-------------------- + +==== Exception state ==== +SWC ID: 110 +Type: Informational +Contract: Unknown +Function name: _function_0xb34c3610 +PC address: 531 +A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking. +-------------------- + diff --git a/tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.easm b/tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.easm new file mode 100644 index 00000000..571b1c66 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.easm @@ -0,0 +1,435 @@ +0 PUSH1 0x60 +2 PUSH1 0x40 +4 MSTORE +5 PUSH1 0x04 +7 CALLDATASIZE +8 LT +9 PUSH2 0x006d +12 JUMPI +13 PUSH1 0x00 +15 CALLDATALOAD +16 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 +46 SWAP1 +47 DIV +48 PUSH4 0xffffffff +53 AND +54 DUP1 +55 PUSH4 0x141f32ff +60 EQ +61 PUSH2 0x0072 +64 JUMPI +65 DUP1 +66 PUSH4 0x2e52d606 +71 EQ +72 PUSH2 0x00b4 +75 JUMPI +76 DUP1 +77 PUSH4 0x67e404ce +82 EQ +83 PUSH2 0x00dd +86 JUMPI +87 DUP1 +88 PUSH4 0x9b58bc26 +93 EQ +94 PUSH2 0x0132 +97 JUMPI +98 DUP1 +99 PUSH4 0xeea4c864 +104 EQ +105 PUSH2 0x0174 +108 JUMPI +109 JUMPDEST +110 PUSH1 0x00 +112 DUP1 +113 REVERT +114 JUMPDEST +115 CALLVALUE +116 ISZERO +117 PUSH2 0x007d +120 JUMPI +121 PUSH1 0x00 +123 DUP1 +124 REVERT +125 JUMPDEST +126 PUSH2 0x00b2 +129 PUSH1 0x04 +131 DUP1 +132 DUP1 +133 CALLDATALOAD +134 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +155 AND +156 SWAP1 +157 PUSH1 0x20 +159 ADD +160 SWAP1 +161 SWAP2 +162 SWAP1 +163 DUP1 +164 CALLDATALOAD +165 SWAP1 +166 PUSH1 0x20 +168 ADD +169 SWAP1 +170 SWAP2 +171 SWAP1 +172 POP +173 POP +174 PUSH2 0x01b6 +177 JUMP +178 JUMPDEST +179 STOP +180 JUMPDEST +181 CALLVALUE +182 ISZERO +183 PUSH2 0x00bf +186 JUMPI +187 PUSH1 0x00 +189 DUP1 +190 REVERT +191 JUMPDEST +192 PUSH2 0x00c7 +195 PUSH2 0x0273 +198 JUMP +199 JUMPDEST +200 PUSH1 0x40 +202 MLOAD +203 DUP1 +204 DUP3 +205 DUP2 +206 MSTORE +207 PUSH1 0x20 +209 ADD +210 SWAP2 +211 POP +212 POP +213 PUSH1 0x40 +215 MLOAD +216 DUP1 +217 SWAP2 +218 SUB +219 SWAP1 +220 RETURN +221 JUMPDEST +222 CALLVALUE +223 ISZERO +224 PUSH2 0x00e8 +227 JUMPI +228 PUSH1 0x00 +230 DUP1 +231 REVERT +232 JUMPDEST +233 PUSH2 0x00f0 +236 PUSH2 0x0279 +239 JUMP +240 JUMPDEST +241 PUSH1 0x40 +243 MLOAD +244 DUP1 +245 DUP3 +246 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +267 AND +268 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +289 AND +290 DUP2 +291 MSTORE +292 PUSH1 0x20 +294 ADD +295 SWAP2 +296 POP +297 POP +298 PUSH1 0x40 +300 MLOAD +301 DUP1 +302 SWAP2 +303 SUB +304 SWAP1 +305 RETURN +306 JUMPDEST +307 CALLVALUE +308 ISZERO +309 PUSH2 0x013d +312 JUMPI +313 PUSH1 0x00 +315 DUP1 +316 REVERT +317 JUMPDEST +318 PUSH2 0x0172 +321 PUSH1 0x04 +323 DUP1 +324 DUP1 +325 CALLDATALOAD +326 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +347 AND +348 SWAP1 +349 PUSH1 0x20 +351 ADD +352 SWAP1 +353 SWAP2 +354 SWAP1 +355 DUP1 +356 CALLDATALOAD +357 SWAP1 +358 PUSH1 0x20 +360 ADD +361 SWAP1 +362 SWAP2 +363 SWAP1 +364 POP +365 POP +366 PUSH2 0x029f +369 JUMP +370 JUMPDEST +371 STOP +372 JUMPDEST +373 CALLVALUE +374 ISZERO +375 PUSH2 0x017f +378 JUMPI +379 PUSH1 0x00 +381 DUP1 +382 REVERT +383 JUMPDEST +384 PUSH2 0x01b4 +387 PUSH1 0x04 +389 DUP1 +390 DUP1 +391 CALLDATALOAD +392 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +413 AND +414 SWAP1 +415 PUSH1 0x20 +417 ADD +418 SWAP1 +419 SWAP2 +420 SWAP1 +421 DUP1 +422 CALLDATALOAD +423 SWAP1 +424 PUSH1 0x20 +426 ADD +427 SWAP1 +428 SWAP2 +429 SWAP1 +430 POP +431 POP +432 PUSH2 0x035a +435 JUMP +436 JUMPDEST +437 STOP +438 JUMPDEST +439 DUP2 +440 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +461 AND +462 PUSH1 0x40 +464 MLOAD +465 DUP1 +466 DUP1 +467 PUSH32 0x7365744e2875696e743235362900000000000000000000000000000000000000 +500 DUP2 +501 MSTORE +502 POP +503 PUSH1 0x0d +505 ADD +506 SWAP1 +507 POP +508 PUSH1 0x40 +510 MLOAD +511 DUP1 +512 SWAP2 +513 SUB +514 SWAP1 +515 SHA3 +516 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 +546 SWAP1 +547 DIV +548 DUP3 +549 PUSH1 0x40 +551 MLOAD +552 DUP3 +553 PUSH4 0xffffffff +558 AND +559 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 +589 MUL +590 DUP2 +591 MSTORE +592 PUSH1 0x04 +594 ADD +595 DUP1 +596 DUP3 +597 DUP2 +598 MSTORE +599 PUSH1 0x20 +601 ADD +602 SWAP2 +603 POP +604 POP +605 PUSH1 0x00 +607 PUSH1 0x40 +609 MLOAD +610 DUP1 +611 DUP4 +612 SUB +613 DUP2 +614 PUSH1 0x00 +616 DUP8 +617 GAS +618 CALLCODE +619 SWAP3 +620 POP +621 POP +622 POP +623 POP +624 POP +625 POP +626 JUMP +627 JUMPDEST +628 PUSH1 0x00 +630 SLOAD +631 DUP2 +632 JUMP +633 JUMPDEST +634 PUSH1 0x01 +636 PUSH1 0x00 +638 SWAP1 +639 SLOAD +640 SWAP1 +641 PUSH2 0x0100 +644 EXP +645 SWAP1 +646 DIV +647 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +668 AND +669 DUP2 +670 JUMP +671 JUMPDEST +672 DUP2 +673 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +694 AND +695 PUSH1 0x40 +697 MLOAD +698 DUP1 +699 DUP1 +700 PUSH32 0x7365744e2875696e743235362900000000000000000000000000000000000000 +733 DUP2 +734 MSTORE +735 POP +736 PUSH1 0x0d +738 ADD +739 SWAP1 +740 POP +741 PUSH1 0x40 +743 MLOAD +744 DUP1 +745 SWAP2 +746 SUB +747 SWAP1 +748 SHA3 +749 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 +779 SWAP1 +780 DIV +781 DUP3 +782 PUSH1 0x40 +784 MLOAD +785 DUP3 +786 PUSH4 0xffffffff +791 AND +792 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 +822 MUL +823 DUP2 +824 MSTORE +825 PUSH1 0x04 +827 ADD +828 DUP1 +829 DUP3 +830 DUP2 +831 MSTORE +832 PUSH1 0x20 +834 ADD +835 SWAP2 +836 POP +837 POP +838 PUSH1 0x00 +840 PUSH1 0x40 +842 MLOAD +843 DUP1 +844 DUP4 +845 SUB +846 DUP2 +847 DUP7 +848 GAS +849 DELEGATECALL +850 SWAP3 +851 POP +852 POP +853 POP +854 POP +855 POP +856 POP +857 JUMP +858 JUMPDEST +859 DUP2 +860 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +881 AND +882 PUSH1 0x40 +884 MLOAD +885 DUP1 +886 DUP1 +887 PUSH32 0x7365744e2875696e743235362900000000000000000000000000000000000000 +920 DUP2 +921 MSTORE +922 POP +923 PUSH1 0x0d +925 ADD +926 SWAP1 +927 POP +928 PUSH1 0x40 +930 MLOAD +931 DUP1 +932 SWAP2 +933 SUB +934 SWAP1 +935 SHA3 +936 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 +966 SWAP1 +967 DIV +968 DUP3 +969 PUSH1 0x40 +971 MLOAD +972 DUP3 +973 PUSH4 0xffffffff +978 AND +979 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 +1009 MUL +1010 DUP2 +1011 MSTORE +1012 PUSH1 0x04 +1014 ADD +1015 DUP1 +1016 DUP3 +1017 DUP2 +1018 MSTORE +1019 PUSH1 0x20 +1021 ADD +1022 SWAP2 +1023 POP +1024 POP +1025 PUSH1 0x00 +1027 PUSH1 0x40 +1029 MLOAD +1030 DUP1 +1031 DUP4 +1032 SUB +1033 DUP2 +1034 PUSH1 0x00 +1036 DUP8 +1037 GAS +1038 CALL +1039 SWAP3 +1040 POP +1041 POP +1042 POP +1043 POP +1044 POP +1045 POP +1046 JUMP +1047 STOP diff --git a/tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.graph.html b/tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.graph.html new file mode 100644 index 00000000..b7281833 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.graph.html @@ -0,0 +1,62 @@ + + + + Call Graph + + + + + + + + + + +

Mythril / Ethereum LASER Symbolic VM

+
+ + + \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.json b/tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.json new file mode 100644 index 00000000..4c42213f --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.json @@ -0,0 +1 @@ +{"error": null, "issues": [{"address": 626, "contract": "Unknown", "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0x141f32ff", "swc_id": "104", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 857, "contract": "Unknown", "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0x9b58bc26", "swc_id": "104", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 1038, "contract": "Unknown", "debug": "", "description": "This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.", "function": "_function_0xeea4c864", "swc_id": "107", "title": "Message call to external contract", "type": "Warning"}, {"address": 1046, "contract": "Unknown", "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xeea4c864", "swc_id": "104", "title": "Unchecked CALL return value", "type": "Informational"}], "success": true} \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.markdown b/tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.markdown new file mode 100644 index 00000000..7208086f --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.markdown @@ -0,0 +1,45 @@ +# Analysis results for test-filename.sol + +## Unchecked CALL return value +- SWC ID: 104 +- Type: Informational +- Contract: Unknown +- Function name: `_function_0x141f32ff` +- PC address: 626 + +### Description + +The return value of an external call is not checked. Note that execution continue even if the called contract throws. + +## Unchecked CALL return value +- SWC ID: 104 +- Type: Informational +- Contract: Unknown +- Function name: `_function_0x9b58bc26` +- PC address: 857 + +### Description + +The return value of an external call is not checked. Note that execution continue even if the called contract throws. + +## Message call to external contract +- SWC ID: 107 +- Type: Warning +- Contract: Unknown +- Function name: `_function_0xeea4c864` +- PC address: 1038 + +### Description + +This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state. + +## Unchecked CALL return value +- SWC ID: 104 +- Type: Informational +- Contract: Unknown +- Function name: `_function_0xeea4c864` +- PC address: 1046 + +### Description + +The return value of an external call is not checked. Note that execution continue even if the called contract throws. diff --git a/tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.text b/tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.text new file mode 100644 index 00000000..46f49440 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.text @@ -0,0 +1,36 @@ +==== Unchecked CALL return value ==== +SWC ID: 104 +Type: Informational +Contract: Unknown +Function name: _function_0x141f32ff +PC address: 626 +The return value of an external call is not checked. Note that execution continue even if the called contract throws. +-------------------- + +==== Unchecked CALL return value ==== +SWC ID: 104 +Type: Informational +Contract: Unknown +Function name: _function_0x9b58bc26 +PC address: 857 +The return value of an external call is not checked. Note that execution continue even if the called contract throws. +-------------------- + +==== Message call to external contract ==== +SWC ID: 107 +Type: Warning +Contract: Unknown +Function name: _function_0xeea4c864 +PC address: 1038 +This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state. +-------------------- + +==== Unchecked CALL return value ==== +SWC ID: 104 +Type: Informational +Contract: Unknown +Function name: _function_0xeea4c864 +PC address: 1046 +The return value of an external call is not checked. Note that execution continue even if the called contract throws. +-------------------- + diff --git a/tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.easm b/tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.easm new file mode 100644 index 00000000..fbb53181 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.easm @@ -0,0 +1,253 @@ +0 PUSH1 0x60 +2 PUSH1 0x40 +4 MSTORE +5 PUSH1 0x04 +7 CALLDATASIZE +8 LT +9 PUSH2 0x004c +12 JUMPI +13 PUSH1 0x00 +15 CALLDATALOAD +16 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 +46 SWAP1 +47 DIV +48 PUSH4 0xffffffff +53 AND +54 DUP1 +55 PUSH4 0x27e235e3 +60 EQ +61 PUSH2 0x0051 +64 JUMPI +65 DUP1 +66 PUSH4 0x412664ae +71 EQ +72 PUSH2 0x009e +75 JUMPI +76 JUMPDEST +77 PUSH1 0x00 +79 DUP1 +80 REVERT +81 JUMPDEST +82 CALLVALUE +83 ISZERO +84 PUSH2 0x005c +87 JUMPI +88 PUSH1 0x00 +90 DUP1 +91 REVERT +92 JUMPDEST +93 PUSH2 0x0088 +96 PUSH1 0x04 +98 DUP1 +99 DUP1 +100 CALLDATALOAD +101 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +122 AND +123 SWAP1 +124 PUSH1 0x20 +126 ADD +127 SWAP1 +128 SWAP2 +129 SWAP1 +130 POP +131 POP +132 PUSH2 0x00f8 +135 JUMP +136 JUMPDEST +137 PUSH1 0x40 +139 MLOAD +140 DUP1 +141 DUP3 +142 DUP2 +143 MSTORE +144 PUSH1 0x20 +146 ADD +147 SWAP2 +148 POP +149 POP +150 PUSH1 0x40 +152 MLOAD +153 DUP1 +154 SWAP2 +155 SUB +156 SWAP1 +157 RETURN +158 JUMPDEST +159 CALLVALUE +160 ISZERO +161 PUSH2 0x00a9 +164 JUMPI +165 PUSH1 0x00 +167 DUP1 +168 REVERT +169 JUMPDEST +170 PUSH2 0x00de +173 PUSH1 0x04 +175 DUP1 +176 DUP1 +177 CALLDATALOAD +178 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +199 AND +200 SWAP1 +201 PUSH1 0x20 +203 ADD +204 SWAP1 +205 SWAP2 +206 SWAP1 +207 DUP1 +208 CALLDATALOAD +209 SWAP1 +210 PUSH1 0x20 +212 ADD +213 SWAP1 +214 SWAP2 +215 SWAP1 +216 POP +217 POP +218 PUSH2 0x0110 +221 JUMP +222 JUMPDEST +223 PUSH1 0x40 +225 MLOAD +226 DUP1 +227 DUP3 +228 ISZERO +229 ISZERO +230 ISZERO +231 ISZERO +232 DUP2 +233 MSTORE +234 PUSH1 0x20 +236 ADD +237 SWAP2 +238 POP +239 POP +240 PUSH1 0x40 +242 MLOAD +243 DUP1 +244 SWAP2 +245 SUB +246 SWAP1 +247 RETURN +248 JUMPDEST +249 PUSH1 0x00 +251 PUSH1 0x20 +253 MSTORE +254 DUP1 +255 PUSH1 0x00 +257 MSTORE +258 PUSH1 0x40 +260 PUSH1 0x00 +262 SHA3 +263 PUSH1 0x00 +265 SWAP2 +266 POP +267 SWAP1 +268 POP +269 SLOAD +270 DUP2 +271 JUMP +272 JUMPDEST +273 PUSH1 0x00 +275 DUP2 +276 PUSH1 0x00 +278 DUP1 +279 CALLER +280 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +301 AND +302 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +323 AND +324 DUP2 +325 MSTORE +326 PUSH1 0x20 +328 ADD +329 SWAP1 +330 DUP2 +331 MSTORE +332 PUSH1 0x20 +334 ADD +335 PUSH1 0x00 +337 SHA3 +338 SLOAD +339 LT +340 ISZERO +341 PUSH2 0x0161 +344 JUMPI +345 PUSH1 0x00 +347 SWAP1 +348 POP +349 PUSH2 0x01fe +352 JUMP +353 JUMPDEST +354 DUP2 +355 PUSH1 0x00 +357 DUP1 +358 CALLER +359 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +380 AND +381 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +402 AND +403 DUP2 +404 MSTORE +405 PUSH1 0x20 +407 ADD +408 SWAP1 +409 DUP2 +410 MSTORE +411 PUSH1 0x20 +413 ADD +414 PUSH1 0x00 +416 SHA3 +417 PUSH1 0x00 +419 DUP3 +420 DUP3 +421 SLOAD +422 SUB +423 SWAP3 +424 POP +425 POP +426 DUP2 +427 SWAP1 +428 SSTORE +429 POP +430 DUP2 +431 PUSH1 0x00 +433 DUP1 +434 DUP6 +435 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +456 AND +457 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +478 AND +479 DUP2 +480 MSTORE +481 PUSH1 0x20 +483 ADD +484 SWAP1 +485 DUP2 +486 MSTORE +487 PUSH1 0x20 +489 ADD +490 PUSH1 0x00 +492 SHA3 +493 PUSH1 0x00 +495 DUP3 +496 DUP3 +497 SLOAD +498 ADD +499 SWAP3 +500 POP +501 POP +502 DUP2 +503 SWAP1 +504 SSTORE +505 POP +506 PUSH1 0x00 +508 SWAP1 +509 POP +510 JUMPDEST +511 SWAP3 +512 SWAP2 +513 POP +514 POP +515 JUMP +516 STOP diff --git a/tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.graph.html b/tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.graph.html new file mode 100644 index 00000000..87302af0 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.graph.html @@ -0,0 +1,62 @@ + + + + Call Graph + + + + + + + + + + +

Mythril / Ethereum LASER Symbolic VM

+
+ + + \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.json b/tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.json new file mode 100644 index 00000000..237b1c1e --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.json @@ -0,0 +1 @@ +{"error": null, "issues": [], "success": true} \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.markdown b/tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.markdown new file mode 100644 index 00000000..321484fd --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.markdown @@ -0,0 +1,3 @@ +# Analysis results for None + +The analysis was completed successfully. No issues were detected. diff --git a/tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.text b/tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.text new file mode 100644 index 00000000..729320d8 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.text @@ -0,0 +1 @@ +The analysis was completed successfully. No issues were detected. diff --git a/tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.easm b/tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.easm new file mode 100644 index 00000000..e83ace06 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.easm @@ -0,0 +1,77 @@ +0 PUSH1 0x60 +2 PUSH1 0x40 +4 MSTORE +5 PUSH1 0x04 +7 CALLDATASIZE +8 LT +9 PUSH1 0x3f +11 JUMPI +12 PUSH1 0x00 +14 CALLDATALOAD +15 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 +45 SWAP1 +46 DIV +47 PUSH4 0xffffffff +52 AND +53 DUP1 +54 PUSH4 0x8a4068dd +59 EQ +60 PUSH1 0x44 +62 JUMPI +63 JUMPDEST +64 PUSH1 0x00 +66 DUP1 +67 REVERT +68 JUMPDEST +69 CALLVALUE +70 ISZERO +71 PUSH1 0x4e +73 JUMPI +74 PUSH1 0x00 +76 DUP1 +77 REVERT +78 JUMPDEST +79 PUSH1 0x54 +81 PUSH1 0x56 +83 JUMP +84 JUMPDEST +85 STOP +86 JUMPDEST +87 CALLER +88 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +109 AND +110 PUSH2 0x08fc +113 PUSH8 0x1bc16d674ec80000 +122 SWAP1 +123 DUP2 +124 ISZERO +125 MUL +126 SWAP1 +127 PUSH1 0x40 +129 MLOAD +130 PUSH1 0x00 +132 PUSH1 0x40 +134 MLOAD +135 DUP1 +136 DUP4 +137 SUB +138 DUP2 +139 DUP6 +140 DUP9 +141 DUP9 +142 CALL +143 SWAP4 +144 POP +145 POP +146 POP +147 POP +148 ISZERO +149 ISZERO +150 PUSH1 0x9d +152 JUMPI +153 PUSH1 0x00 +155 DUP1 +156 REVERT +157 JUMPDEST +158 JUMP +159 STOP diff --git a/tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.graph.html b/tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.graph.html new file mode 100644 index 00000000..51431e2b --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.graph.html @@ -0,0 +1,62 @@ + + + + Call Graph + + + + + + + + + + +

Mythril / Ethereum LASER Symbolic VM

+
+ + + \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.json b/tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.json new file mode 100644 index 00000000..3a8a609a --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.json @@ -0,0 +1 @@ +{"error": null, "issues": [{"address": 142, "contract": "Unknown", "debug": "", "description": "It seems that an attacker is able to execute an call instruction, this can mean that the attacker is able to extract funds out of the contract.", "function": "_function_0x8a4068dd", "swc_id": "105", "title": "Ether send", "type": "Warning"}], "success": true} \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.markdown b/tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.markdown new file mode 100644 index 00000000..6cebd955 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.markdown @@ -0,0 +1,12 @@ +# Analysis results for test-filename.sol + +## Ether send +- SWC ID: 105 +- Type: Warning +- Contract: Unknown +- Function name: `_function_0x8a4068dd` +- PC address: 142 + +### Description + +It seems that an attacker is able to execute an call instruction, this can mean that the attacker is able to extract funds out of the contract. diff --git a/tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.text b/tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.text new file mode 100644 index 00000000..068f36d1 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.text @@ -0,0 +1,9 @@ +==== Ether send ==== +SWC ID: 105 +Type: Warning +Contract: Unknown +Function name: _function_0x8a4068dd +PC address: 142 +It seems that an attacker is able to execute an call instruction, this can mean that the attacker is able to extract funds out of the contract. +-------------------- + diff --git a/tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.easm b/tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.easm new file mode 100644 index 00000000..555d5ba3 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.easm @@ -0,0 +1,167 @@ +0 PUSH1 0x80 +2 PUSH1 0x40 +4 MSTORE +5 PUSH1 0x04 +7 CALLDATASIZE +8 LT +9 PUSH2 0x0041 +12 JUMPI +13 PUSH1 0x00 +15 CALLDATALOAD +16 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 +46 SWAP1 +47 DIV +48 PUSH4 0xffffffff +53 AND +54 DUP1 +55 PUSH4 0x24ff38a2 +60 EQ +61 PUSH2 0x0046 +64 JUMPI +65 JUMPDEST +66 PUSH1 0x00 +68 DUP1 +69 REVERT +70 JUMPDEST +71 CALLVALUE +72 DUP1 +73 ISZERO +74 PUSH2 0x0052 +77 JUMPI +78 PUSH1 0x00 +80 DUP1 +81 REVERT +82 JUMPDEST +83 POP +84 PUSH2 0x005b +87 PUSH2 0x00d6 +90 JUMP +91 JUMPDEST +92 PUSH1 0x40 +94 MLOAD +95 DUP1 +96 DUP1 +97 PUSH1 0x20 +99 ADD +100 DUP3 +101 DUP2 +102 SUB +103 DUP3 +104 MSTORE +105 DUP4 +106 DUP2 +107 DUP2 +108 MLOAD +109 DUP2 +110 MSTORE +111 PUSH1 0x20 +113 ADD +114 SWAP2 +115 POP +116 DUP1 +117 MLOAD +118 SWAP1 +119 PUSH1 0x20 +121 ADD +122 SWAP1 +123 DUP1 +124 DUP4 +125 DUP4 +126 PUSH1 0x00 +128 JUMPDEST +129 DUP4 +130 DUP2 +131 LT +132 ISZERO +133 PUSH2 0x009b +136 JUMPI +137 DUP1 +138 DUP3 +139 ADD +140 MLOAD +141 DUP2 +142 DUP5 +143 ADD +144 MSTORE +145 PUSH1 0x20 +147 DUP2 +148 ADD +149 SWAP1 +150 POP +151 PUSH2 0x0080 +154 JUMP +155 JUMPDEST +156 POP +157 POP +158 POP +159 POP +160 SWAP1 +161 POP +162 SWAP1 +163 DUP2 +164 ADD +165 SWAP1 +166 PUSH1 0x1f +168 AND +169 DUP1 +170 ISZERO +171 PUSH2 0x00c8 +174 JUMPI +175 DUP1 +176 DUP3 +177 SUB +178 DUP1 +179 MLOAD +180 PUSH1 0x01 +182 DUP4 +183 PUSH1 0x20 +185 SUB +186 PUSH2 0x0100 +189 EXP +190 SUB +191 NOT +192 AND +193 DUP2 +194 MSTORE +195 PUSH1 0x20 +197 ADD +198 SWAP2 +199 POP +200 JUMPDEST +201 POP +202 SWAP3 +203 POP +204 POP +205 POP +206 PUSH1 0x40 +208 MLOAD +209 DUP1 +210 SWAP2 +211 SUB +212 SWAP1 +213 RETURN +214 JUMPDEST +215 PUSH1 0x60 +217 PUSH1 0x40 +219 DUP1 +220 MLOAD +221 SWAP1 +222 DUP2 +223 ADD +224 PUSH1 0x40 +226 MSTORE +227 DUP1 +228 PUSH1 0x17 +230 DUP2 +231 MSTORE +232 PUSH1 0x20 +234 ADD +235 PUSH32 0xd0a5d18dd0bbd0bbd0bed18320d092d0bed180d0bbd0b4000000000000000000 +268 DUP2 +269 MSTORE +270 POP +271 SWAP1 +272 POP +273 SWAP1 +274 JUMP +275 STOP diff --git a/tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.graph.html b/tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.graph.html new file mode 100644 index 00000000..bfce08fb --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.graph.html @@ -0,0 +1,62 @@ + + + + Call Graph + + + + + + + + + + +

Mythril / Ethereum LASER Symbolic VM

+
+ + + \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.json b/tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.json new file mode 100644 index 00000000..237b1c1e --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.json @@ -0,0 +1 @@ +{"error": null, "issues": [], "success": true} \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.markdown b/tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.markdown new file mode 100644 index 00000000..321484fd --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.markdown @@ -0,0 +1,3 @@ +# Analysis results for None + +The analysis was completed successfully. No issues were detected. diff --git a/tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.text b/tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.text new file mode 100644 index 00000000..729320d8 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.text @@ -0,0 +1 @@ +The analysis was completed successfully. No issues were detected. diff --git a/tests/testdata/outputs_expected/outputs_current/origin.sol.o.easm b/tests/testdata/outputs_expected/outputs_current/origin.sol.o.easm new file mode 100644 index 00000000..e1bffe10 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/origin.sol.o.easm @@ -0,0 +1,168 @@ +0 PUSH1 0x60 +2 PUSH1 0x40 +4 MSTORE +5 PUSH1 0x04 +7 CALLDATASIZE +8 LT +9 PUSH2 0x004c +12 JUMPI +13 PUSH1 0x00 +15 CALLDATALOAD +16 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 +46 SWAP1 +47 DIV +48 PUSH4 0xffffffff +53 AND +54 DUP1 +55 PUSH4 0x8da5cb5b +60 EQ +61 PUSH2 0x0051 +64 JUMPI +65 DUP1 +66 PUSH4 0xf2fde38b +71 EQ +72 PUSH2 0x00a6 +75 JUMPI +76 JUMPDEST +77 PUSH1 0x00 +79 DUP1 +80 REVERT +81 JUMPDEST +82 CALLVALUE +83 ISZERO +84 PUSH2 0x005c +87 JUMPI +88 PUSH1 0x00 +90 DUP1 +91 REVERT +92 JUMPDEST +93 PUSH2 0x0064 +96 PUSH2 0x00df +99 JUMP +100 JUMPDEST +101 PUSH1 0x40 +103 MLOAD +104 DUP1 +105 DUP3 +106 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +127 AND +128 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +149 AND +150 DUP2 +151 MSTORE +152 PUSH1 0x20 +154 ADD +155 SWAP2 +156 POP +157 POP +158 PUSH1 0x40 +160 MLOAD +161 DUP1 +162 SWAP2 +163 SUB +164 SWAP1 +165 RETURN +166 JUMPDEST +167 CALLVALUE +168 ISZERO +169 PUSH2 0x00b1 +172 JUMPI +173 PUSH1 0x00 +175 DUP1 +176 REVERT +177 JUMPDEST +178 PUSH2 0x00dd +181 PUSH1 0x04 +183 DUP1 +184 DUP1 +185 CALLDATALOAD +186 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +207 AND +208 SWAP1 +209 PUSH1 0x20 +211 ADD +212 SWAP1 +213 SWAP2 +214 SWAP1 +215 POP +216 POP +217 PUSH2 0x0104 +220 JUMP +221 JUMPDEST +222 STOP +223 JUMPDEST +224 PUSH1 0x00 +226 DUP1 +227 SWAP1 +228 SLOAD +229 SWAP1 +230 PUSH2 0x0100 +233 EXP +234 SWAP1 +235 DIV +236 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +257 AND +258 DUP2 +259 JUMP +260 JUMPDEST +261 PUSH1 0x00 +263 DUP1 +264 SWAP1 +265 SLOAD +266 SWAP1 +267 PUSH2 0x0100 +270 EXP +271 SWAP1 +272 DIV +273 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +294 AND +295 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +316 AND +317 ORIGIN +318 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +339 AND +340 EQ +341 ISZERO +342 ISZERO +343 PUSH2 0x015f +346 JUMPI +347 PUSH1 0x00 +349 DUP1 +350 REVERT +351 JUMPDEST +352 PUSH1 0x00 +354 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +375 AND +376 DUP2 +377 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +398 AND +399 EQ +400 ISZERO +401 ISZERO +402 PUSH2 0x01d6 +405 JUMPI +406 DUP1 +407 PUSH1 0x00 +409 DUP1 +410 PUSH2 0x0100 +413 EXP +414 DUP2 +415 SLOAD +416 DUP2 +417 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +438 MUL +439 NOT +440 AND +441 SWAP1 +442 DUP4 +443 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +464 AND +465 MUL +466 OR +467 SWAP1 +468 SSTORE +469 POP +470 JUMPDEST +471 POP +472 JUMP +473 STOP diff --git a/tests/testdata/outputs_expected/outputs_current/origin.sol.o.graph.html b/tests/testdata/outputs_expected/outputs_current/origin.sol.o.graph.html new file mode 100644 index 00000000..88665173 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/origin.sol.o.graph.html @@ -0,0 +1,62 @@ + + + + Call Graph + + + + + + + + + + +

Mythril / Ethereum LASER Symbolic VM

+
+ + + \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/origin.sol.o.json b/tests/testdata/outputs_expected/outputs_current/origin.sol.o.json new file mode 100644 index 00000000..0e924831 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/origin.sol.o.json @@ -0,0 +1 @@ +{"error": null, "issues": [{"address": 317, "contract": "Unknown", "debug": "", "description": "The function `transferOwnership(address)` retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead.\nSee also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin", "function": "transferOwnership(address)", "swc_id": "115", "title": "Use of tx.origin", "type": "Warning"}], "success": true} \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/origin.sol.o.markdown b/tests/testdata/outputs_expected/outputs_current/origin.sol.o.markdown new file mode 100644 index 00000000..1e9d6d8b --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/origin.sol.o.markdown @@ -0,0 +1,13 @@ +# Analysis results for test-filename.sol + +## Use of tx.origin +- SWC ID: 115 +- Type: Warning +- Contract: Unknown +- Function name: `transferOwnership(address)` +- PC address: 317 + +### Description + +The function `transferOwnership(address)` retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead. +See also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin diff --git a/tests/testdata/outputs_expected/outputs_current/origin.sol.o.text b/tests/testdata/outputs_expected/outputs_current/origin.sol.o.text new file mode 100644 index 00000000..b71422be --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/origin.sol.o.text @@ -0,0 +1,10 @@ +==== Use of tx.origin ==== +SWC ID: 115 +Type: Warning +Contract: Unknown +Function name: transferOwnership(address) +PC address: 317 +The function `transferOwnership(address)` retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead. +See also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin +-------------------- + diff --git a/tests/testdata/outputs_expected/outputs_current/overflow.sol.o.easm b/tests/testdata/outputs_expected/outputs_current/overflow.sol.o.easm new file mode 100644 index 00000000..b0763999 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/overflow.sol.o.easm @@ -0,0 +1,388 @@ +0 PUSH1 0x60 +2 PUSH1 0x40 +4 MSTORE +5 PUSH1 0x04 +7 CALLDATASIZE +8 LT +9 PUSH2 0x0062 +12 JUMPI +13 PUSH1 0x00 +15 CALLDATALOAD +16 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 +46 SWAP1 +47 DIV +48 PUSH4 0xffffffff +53 AND +54 DUP1 +55 PUSH4 0x18160ddd +60 EQ +61 PUSH2 0x0067 +64 JUMPI +65 DUP1 +66 PUSH4 0x6241bfd1 +71 EQ +72 PUSH2 0x0090 +75 JUMPI +76 DUP1 +77 PUSH4 0x70a08231 +82 EQ +83 PUSH2 0x00b3 +86 JUMPI +87 DUP1 +88 PUSH4 0xa3210e87 +93 EQ +94 PUSH2 0x0100 +97 JUMPI +98 JUMPDEST +99 PUSH1 0x00 +101 DUP1 +102 REVERT +103 JUMPDEST +104 CALLVALUE +105 ISZERO +106 PUSH2 0x0072 +109 JUMPI +110 PUSH1 0x00 +112 DUP1 +113 REVERT +114 JUMPDEST +115 PUSH2 0x007a +118 PUSH2 0x015a +121 JUMP +122 JUMPDEST +123 PUSH1 0x40 +125 MLOAD +126 DUP1 +127 DUP3 +128 DUP2 +129 MSTORE +130 PUSH1 0x20 +132 ADD +133 SWAP2 +134 POP +135 POP +136 PUSH1 0x40 +138 MLOAD +139 DUP1 +140 SWAP2 +141 SUB +142 SWAP1 +143 RETURN +144 JUMPDEST +145 CALLVALUE +146 ISZERO +147 PUSH2 0x009b +150 JUMPI +151 PUSH1 0x00 +153 DUP1 +154 REVERT +155 JUMPDEST +156 PUSH2 0x00b1 +159 PUSH1 0x04 +161 DUP1 +162 DUP1 +163 CALLDATALOAD +164 SWAP1 +165 PUSH1 0x20 +167 ADD +168 SWAP1 +169 SWAP2 +170 SWAP1 +171 POP +172 POP +173 PUSH2 0x0160 +176 JUMP +177 JUMPDEST +178 STOP +179 JUMPDEST +180 CALLVALUE +181 ISZERO +182 PUSH2 0x00be +185 JUMPI +186 PUSH1 0x00 +188 DUP1 +189 REVERT +190 JUMPDEST +191 PUSH2 0x00ea +194 PUSH1 0x04 +196 DUP1 +197 DUP1 +198 CALLDATALOAD +199 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +220 AND +221 SWAP1 +222 PUSH1 0x20 +224 ADD +225 SWAP1 +226 SWAP2 +227 SWAP1 +228 POP +229 POP +230 PUSH2 0x01ab +233 JUMP +234 JUMPDEST +235 PUSH1 0x40 +237 MLOAD +238 DUP1 +239 DUP3 +240 DUP2 +241 MSTORE +242 PUSH1 0x20 +244 ADD +245 SWAP2 +246 POP +247 POP +248 PUSH1 0x40 +250 MLOAD +251 DUP1 +252 SWAP2 +253 SUB +254 SWAP1 +255 RETURN +256 JUMPDEST +257 CALLVALUE +258 ISZERO +259 PUSH2 0x010b +262 JUMPI +263 PUSH1 0x00 +265 DUP1 +266 REVERT +267 JUMPDEST +268 PUSH2 0x0140 +271 PUSH1 0x04 +273 DUP1 +274 DUP1 +275 CALLDATALOAD +276 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +297 AND +298 SWAP1 +299 PUSH1 0x20 +301 ADD +302 SWAP1 +303 SWAP2 +304 SWAP1 +305 DUP1 +306 CALLDATALOAD +307 SWAP1 +308 PUSH1 0x20 +310 ADD +311 SWAP1 +312 SWAP2 +313 SWAP1 +314 POP +315 POP +316 PUSH2 0x01f3 +319 JUMP +320 JUMPDEST +321 PUSH1 0x40 +323 MLOAD +324 DUP1 +325 DUP3 +326 ISZERO +327 ISZERO +328 ISZERO +329 ISZERO +330 DUP2 +331 MSTORE +332 PUSH1 0x20 +334 ADD +335 SWAP2 +336 POP +337 POP +338 PUSH1 0x40 +340 MLOAD +341 DUP1 +342 SWAP2 +343 SUB +344 SWAP1 +345 RETURN +346 JUMPDEST +347 PUSH1 0x01 +349 SLOAD +350 DUP2 +351 JUMP +352 JUMPDEST +353 DUP1 +354 PUSH1 0x01 +356 DUP2 +357 SWAP1 +358 SSTORE +359 PUSH1 0x00 +361 DUP1 +362 CALLER +363 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +384 AND +385 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +406 AND +407 DUP2 +408 MSTORE +409 PUSH1 0x20 +411 ADD +412 SWAP1 +413 DUP2 +414 MSTORE +415 PUSH1 0x20 +417 ADD +418 PUSH1 0x00 +420 SHA3 +421 DUP2 +422 SWAP1 +423 SSTORE +424 POP +425 POP +426 JUMP +427 JUMPDEST +428 PUSH1 0x00 +430 DUP1 +431 PUSH1 0x00 +433 DUP4 +434 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +455 AND +456 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +477 AND +478 DUP2 +479 MSTORE +480 PUSH1 0x20 +482 ADD +483 SWAP1 +484 DUP2 +485 MSTORE +486 PUSH1 0x20 +488 ADD +489 PUSH1 0x00 +491 SHA3 +492 SLOAD +493 SWAP1 +494 POP +495 SWAP2 +496 SWAP1 +497 POP +498 JUMP +499 JUMPDEST +500 PUSH1 0x00 +502 DUP1 +503 DUP3 +504 PUSH1 0x00 +506 DUP1 +507 CALLER +508 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +529 AND +530 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +551 AND +552 DUP2 +553 MSTORE +554 PUSH1 0x20 +556 ADD +557 SWAP1 +558 DUP2 +559 MSTORE +560 PUSH1 0x20 +562 ADD +563 PUSH1 0x00 +565 SHA3 +566 SLOAD +567 SUB +568 LT +569 ISZERO +570 ISZERO +571 ISZERO +572 PUSH2 0x0244 +575 JUMPI +576 PUSH1 0x00 +578 DUP1 +579 REVERT +580 JUMPDEST +581 DUP2 +582 PUSH1 0x00 +584 DUP1 +585 CALLER +586 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +607 AND +608 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +629 AND +630 DUP2 +631 MSTORE +632 PUSH1 0x20 +634 ADD +635 SWAP1 +636 DUP2 +637 MSTORE +638 PUSH1 0x20 +640 ADD +641 PUSH1 0x00 +643 SHA3 +644 PUSH1 0x00 +646 DUP3 +647 DUP3 +648 SLOAD +649 SUB +650 SWAP3 +651 POP +652 POP +653 DUP2 +654 SWAP1 +655 SSTORE +656 POP +657 DUP2 +658 PUSH1 0x00 +660 DUP1 +661 DUP6 +662 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +683 AND +684 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +705 AND +706 DUP2 +707 MSTORE +708 PUSH1 0x20 +710 ADD +711 SWAP1 +712 DUP2 +713 MSTORE +714 PUSH1 0x20 +716 ADD +717 PUSH1 0x00 +719 SHA3 +720 PUSH1 0x00 +722 DUP3 +723 DUP3 +724 SLOAD +725 ADD +726 SWAP3 +727 POP +728 POP +729 DUP2 +730 SWAP1 +731 SSTORE +732 POP +733 PUSH1 0x02 +735 PUSH1 0x00 +737 DUP1 +738 DUP6 +739 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +760 AND +761 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +782 AND +783 DUP2 +784 MSTORE +785 PUSH1 0x20 +787 ADD +788 SWAP1 +789 DUP2 +790 MSTORE +791 PUSH1 0x20 +793 ADD +794 PUSH1 0x00 +796 SHA3 +797 DUP2 +798 SWAP1 +799 SSTORE +800 POP +801 PUSH1 0x01 +803 SWAP1 +804 POP +805 SWAP3 +806 SWAP2 +807 POP +808 POP +809 JUMP +810 STOP diff --git a/tests/testdata/outputs_expected/outputs_current/overflow.sol.o.graph.html b/tests/testdata/outputs_expected/outputs_current/overflow.sol.o.graph.html new file mode 100644 index 00000000..188273ad --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/overflow.sol.o.graph.html @@ -0,0 +1,62 @@ + + + + Call Graph + + + + + + + + + + +

Mythril / Ethereum LASER Symbolic VM

+
+ + + \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/overflow.sol.o.json b/tests/testdata/outputs_expected/outputs_current/overflow.sol.o.json new file mode 100644 index 00000000..d651908c --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/overflow.sol.o.json @@ -0,0 +1 @@ +{"error": null, "issues": [{"address": 567, "contract": "Unknown", "debug": "", "description": "The subtraction can result in an integer underflow.\n", "function": "sendeth(address,uint256)", "swc_id": "101", "title": "Integer Underflow", "type": "Warning"}, {"address": 649, "contract": "Unknown", "debug": "", "description": "The subtraction can result in an integer underflow.\n", "function": "sendeth(address,uint256)", "swc_id": "101", "title": "Integer Underflow", "type": "Warning"}, {"address": 725, "contract": "Unknown", "debug": "", "description": "The arithmetic operation can result in integer overflow.\n", "function": "sendeth(address,uint256)", "swc_id": "101", "title": "Integer Overflow", "type": "Warning"}], "success": true} \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/overflow.sol.o.markdown b/tests/testdata/outputs_expected/outputs_current/overflow.sol.o.markdown new file mode 100644 index 00000000..f042f183 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/overflow.sol.o.markdown @@ -0,0 +1,34 @@ +# Analysis results for test-filename.sol + +## Integer Underflow +- SWC ID: 101 +- Type: Warning +- Contract: Unknown +- Function name: `sendeth(address,uint256)` +- PC address: 567 + +### Description + +The subtraction can result in an integer underflow. + +## Integer Underflow +- SWC ID: 101 +- Type: Warning +- Contract: Unknown +- Function name: `sendeth(address,uint256)` +- PC address: 649 + +### Description + +The subtraction can result in an integer underflow. + +## Integer Overflow +- SWC ID: 101 +- Type: Warning +- Contract: Unknown +- Function name: `sendeth(address,uint256)` +- PC address: 725 + +### Description + +The arithmetic operation can result in integer overflow. diff --git a/tests/testdata/outputs_expected/outputs_current/overflow.sol.o.text b/tests/testdata/outputs_expected/outputs_current/overflow.sol.o.text new file mode 100644 index 00000000..ad480ffd --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/overflow.sol.o.text @@ -0,0 +1,30 @@ +==== Integer Underflow ==== +SWC ID: 101 +Type: Warning +Contract: Unknown +Function name: sendeth(address,uint256) +PC address: 567 +The subtraction can result in an integer underflow. + +-------------------- + +==== Integer Underflow ==== +SWC ID: 101 +Type: Warning +Contract: Unknown +Function name: sendeth(address,uint256) +PC address: 649 +The subtraction can result in an integer underflow. + +-------------------- + +==== Integer Overflow ==== +SWC ID: 101 +Type: Warning +Contract: Unknown +Function name: sendeth(address,uint256) +PC address: 725 +The arithmetic operation can result in integer overflow. + +-------------------- + diff --git a/tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.easm b/tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.easm new file mode 100644 index 00000000..13a426cc --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.easm @@ -0,0 +1,129 @@ +0 PUSH1 0x60 +2 PUSH1 0x40 +4 MSTORE +5 PUSH1 0x04 +7 CALLDATASIZE +8 LT +9 PUSH2 0x004c +12 JUMPI +13 PUSH1 0x00 +15 CALLDATALOAD +16 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 +46 SWAP1 +47 DIV +48 PUSH4 0xffffffff +53 AND +54 DUP1 +55 PUSH4 0x633ab5e0 +60 EQ +61 PUSH2 0x0051 +64 JUMPI +65 DUP1 +66 PUSH4 0xe3bea282 +71 EQ +72 PUSH2 0x0066 +75 JUMPI +76 JUMPDEST +77 PUSH1 0x00 +79 DUP1 +80 REVERT +81 JUMPDEST +82 CALLVALUE +83 ISZERO +84 PUSH2 0x005c +87 JUMPI +88 PUSH1 0x00 +90 DUP1 +91 REVERT +92 JUMPDEST +93 PUSH2 0x0064 +96 PUSH2 0x007b +99 JUMP +100 JUMPDEST +101 STOP +102 JUMPDEST +103 CALLVALUE +104 ISZERO +105 PUSH2 0x0071 +108 JUMPI +109 PUSH1 0x00 +111 DUP1 +112 REVERT +113 JUMPDEST +114 PUSH2 0x0079 +117 PUSH2 0x00d4 +120 JUMP +121 JUMPDEST +122 STOP +123 JUMPDEST +124 PUSH1 0x00 +126 DUP1 +127 SWAP1 +128 SLOAD +129 SWAP1 +130 PUSH2 0x0100 +133 EXP +134 SWAP1 +135 DIV +136 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +157 AND +158 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +179 AND +180 PUSH1 0x40 +182 MLOAD +183 PUSH1 0x00 +185 PUSH1 0x40 +187 MLOAD +188 DUP1 +189 DUP4 +190 SUB +191 DUP2 +192 PUSH1 0x00 +194 DUP7 +195 GAS +196 CALL +197 SWAP2 +198 POP +199 POP +200 ISZERO +201 ISZERO +202 PUSH2 0x00d2 +205 JUMPI +206 PUSH1 0x00 +208 DUP1 +209 REVERT +210 JUMPDEST +211 JUMP +212 JUMPDEST +213 PUSH1 0x00 +215 DUP1 +216 SWAP1 +217 SLOAD +218 SWAP1 +219 PUSH2 0x0100 +222 EXP +223 SWAP1 +224 DIV +225 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +246 AND +247 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +268 AND +269 PUSH1 0x40 +271 MLOAD +272 PUSH1 0x00 +274 PUSH1 0x40 +276 MLOAD +277 DUP1 +278 DUP4 +279 SUB +280 DUP2 +281 PUSH1 0x00 +283 DUP7 +284 GAS +285 CALL +286 SWAP2 +287 POP +288 POP +289 POP +290 JUMP +291 STOP diff --git a/tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.graph.html b/tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.graph.html new file mode 100644 index 00000000..759f6b55 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.graph.html @@ -0,0 +1,62 @@ + + + + Call Graph + + + + + + + + + + +

Mythril / Ethereum LASER Symbolic VM

+
+ + + \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.json b/tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.json new file mode 100644 index 00000000..81ee3cb3 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.json @@ -0,0 +1 @@ +{"error": null, "issues": [{"address": 196, "contract": "Unknown", "debug": "", "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.", "function": "_function_0x633ab5e0", "swc_id": "107", "title": "Message call to external contract", "type": "Informational"}, {"address": 285, "contract": "Unknown", "debug": "", "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.", "function": "_function_0xe3bea282", "swc_id": "107", "title": "Message call to external contract", "type": "Informational"}, {"address": 290, "contract": "Unknown", "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xe3bea282", "swc_id": "104", "title": "Unchecked CALL return value", "type": "Informational"}], "success": true} \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.markdown b/tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.markdown new file mode 100644 index 00000000..f3a058bd --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.markdown @@ -0,0 +1,34 @@ +# Analysis results for test-filename.sol + +## Message call to external contract +- SWC ID: 107 +- Type: Informational +- Contract: Unknown +- Function name: `_function_0x633ab5e0` +- PC address: 196 + +### Description + +This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code. + +## Message call to external contract +- SWC ID: 107 +- Type: Informational +- Contract: Unknown +- Function name: `_function_0xe3bea282` +- PC address: 285 + +### Description + +This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code. + +## Unchecked CALL return value +- SWC ID: 104 +- Type: Informational +- Contract: Unknown +- Function name: `_function_0xe3bea282` +- PC address: 290 + +### Description + +The return value of an external call is not checked. Note that execution continue even if the called contract throws. diff --git a/tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.text b/tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.text new file mode 100644 index 00000000..2a8b1470 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.text @@ -0,0 +1,27 @@ +==== Message call to external contract ==== +SWC ID: 107 +Type: Informational +Contract: Unknown +Function name: _function_0x633ab5e0 +PC address: 196 +This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code. +-------------------- + +==== Message call to external contract ==== +SWC ID: 107 +Type: Informational +Contract: Unknown +Function name: _function_0xe3bea282 +PC address: 285 +This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code. +-------------------- + +==== Unchecked CALL return value ==== +SWC ID: 104 +Type: Informational +Contract: Unknown +Function name: _function_0xe3bea282 +PC address: 290 +The return value of an external call is not checked. Note that execution continue even if the called contract throws. +-------------------- + diff --git a/tests/testdata/outputs_expected/outputs_current/suicide.sol.o.easm b/tests/testdata/outputs_expected/outputs_current/suicide.sol.o.easm new file mode 100644 index 00000000..892e7787 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/suicide.sol.o.easm @@ -0,0 +1,58 @@ +0 PUSH1 0x60 +2 PUSH1 0x40 +4 MSTORE +5 PUSH1 0x04 +7 CALLDATASIZE +8 LT +9 PUSH1 0x3f +11 JUMPI +12 PUSH1 0x00 +14 CALLDATALOAD +15 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 +45 SWAP1 +46 DIV +47 PUSH4 0xffffffff +52 AND +53 DUP1 +54 PUSH4 0xcbf0b0c0 +59 EQ +60 PUSH1 0x44 +62 JUMPI +63 JUMPDEST +64 PUSH1 0x00 +66 DUP1 +67 REVERT +68 JUMPDEST +69 CALLVALUE +70 ISZERO +71 PUSH1 0x4e +73 JUMPI +74 PUSH1 0x00 +76 DUP1 +77 REVERT +78 JUMPDEST +79 PUSH1 0x78 +81 PUSH1 0x04 +83 DUP1 +84 DUP1 +85 CALLDATALOAD +86 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +107 AND +108 SWAP1 +109 PUSH1 0x20 +111 ADD +112 SWAP1 +113 SWAP2 +114 SWAP1 +115 POP +116 POP +117 PUSH1 0x7a +119 JUMP +120 JUMPDEST +121 STOP +122 JUMPDEST +123 DUP1 +124 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +145 AND +146 SUICIDE +147 STOP diff --git a/tests/testdata/outputs_expected/outputs_current/suicide.sol.o.graph.html b/tests/testdata/outputs_expected/outputs_current/suicide.sol.o.graph.html new file mode 100644 index 00000000..173d77ea --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/suicide.sol.o.graph.html @@ -0,0 +1,62 @@ + + + + Call Graph + + + + + + + + + + +

Mythril / Ethereum LASER Symbolic VM

+
+ + + \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/suicide.sol.o.json b/tests/testdata/outputs_expected/outputs_current/suicide.sol.o.json new file mode 100644 index 00000000..4b9b6b83 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/suicide.sol.o.json @@ -0,0 +1 @@ +{"error": null, "issues": [{"address": 146, "contract": "Unknown", "debug": "", "description": "A reachable SUICIDE instruction was detected. The remaining Ether is sent to an address provided as a function argument.\n", "function": "_function_0xcbf0b0c0", "swc_id": "106", "title": "Unchecked SUICIDE", "type": "Warning"}], "success": true} \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/suicide.sol.o.markdown b/tests/testdata/outputs_expected/outputs_current/suicide.sol.o.markdown new file mode 100644 index 00000000..6d24f84d --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/suicide.sol.o.markdown @@ -0,0 +1,12 @@ +# Analysis results for test-filename.sol + +## Unchecked SUICIDE +- SWC ID: 106 +- Type: Warning +- Contract: Unknown +- Function name: `_function_0xcbf0b0c0` +- PC address: 146 + +### Description + +A reachable SUICIDE instruction was detected. The remaining Ether is sent to an address provided as a function argument. diff --git a/tests/testdata/outputs_expected/outputs_current/suicide.sol.o.text b/tests/testdata/outputs_expected/outputs_current/suicide.sol.o.text new file mode 100644 index 00000000..138bf06b --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/suicide.sol.o.text @@ -0,0 +1,10 @@ +==== Unchecked SUICIDE ==== +SWC ID: 106 +Type: Warning +Contract: Unknown +Function name: _function_0xcbf0b0c0 +PC address: 146 +A reachable SUICIDE instruction was detected. The remaining Ether is sent to an address provided as a function argument. + +-------------------- + diff --git a/tests/testdata/outputs_expected/outputs_current/underflow.sol.o.easm b/tests/testdata/outputs_expected/outputs_current/underflow.sol.o.easm new file mode 100644 index 00000000..0ed8f651 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/underflow.sol.o.easm @@ -0,0 +1,365 @@ +0 PUSH1 0x60 +2 PUSH1 0x40 +4 MSTORE +5 PUSH1 0x04 +7 CALLDATASIZE +8 LT +9 PUSH2 0x0062 +12 JUMPI +13 PUSH1 0x00 +15 CALLDATALOAD +16 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 +46 SWAP1 +47 DIV +48 PUSH4 0xffffffff +53 AND +54 DUP1 +55 PUSH4 0x18160ddd +60 EQ +61 PUSH2 0x0067 +64 JUMPI +65 DUP1 +66 PUSH4 0x6241bfd1 +71 EQ +72 PUSH2 0x0090 +75 JUMPI +76 DUP1 +77 PUSH4 0x70a08231 +82 EQ +83 PUSH2 0x00b3 +86 JUMPI +87 DUP1 +88 PUSH4 0xa3210e87 +93 EQ +94 PUSH2 0x0100 +97 JUMPI +98 JUMPDEST +99 PUSH1 0x00 +101 DUP1 +102 REVERT +103 JUMPDEST +104 CALLVALUE +105 ISZERO +106 PUSH2 0x0072 +109 JUMPI +110 PUSH1 0x00 +112 DUP1 +113 REVERT +114 JUMPDEST +115 PUSH2 0x007a +118 PUSH2 0x015a +121 JUMP +122 JUMPDEST +123 PUSH1 0x40 +125 MLOAD +126 DUP1 +127 DUP3 +128 DUP2 +129 MSTORE +130 PUSH1 0x20 +132 ADD +133 SWAP2 +134 POP +135 POP +136 PUSH1 0x40 +138 MLOAD +139 DUP1 +140 SWAP2 +141 SUB +142 SWAP1 +143 RETURN +144 JUMPDEST +145 CALLVALUE +146 ISZERO +147 PUSH2 0x009b +150 JUMPI +151 PUSH1 0x00 +153 DUP1 +154 REVERT +155 JUMPDEST +156 PUSH2 0x00b1 +159 PUSH1 0x04 +161 DUP1 +162 DUP1 +163 CALLDATALOAD +164 SWAP1 +165 PUSH1 0x20 +167 ADD +168 SWAP1 +169 SWAP2 +170 SWAP1 +171 POP +172 POP +173 PUSH2 0x0160 +176 JUMP +177 JUMPDEST +178 STOP +179 JUMPDEST +180 CALLVALUE +181 ISZERO +182 PUSH2 0x00be +185 JUMPI +186 PUSH1 0x00 +188 DUP1 +189 REVERT +190 JUMPDEST +191 PUSH2 0x00ea +194 PUSH1 0x04 +196 DUP1 +197 DUP1 +198 CALLDATALOAD +199 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +220 AND +221 SWAP1 +222 PUSH1 0x20 +224 ADD +225 SWAP1 +226 SWAP2 +227 SWAP1 +228 POP +229 POP +230 PUSH2 0x01ab +233 JUMP +234 JUMPDEST +235 PUSH1 0x40 +237 MLOAD +238 DUP1 +239 DUP3 +240 DUP2 +241 MSTORE +242 PUSH1 0x20 +244 ADD +245 SWAP2 +246 POP +247 POP +248 PUSH1 0x40 +250 MLOAD +251 DUP1 +252 SWAP2 +253 SUB +254 SWAP1 +255 RETURN +256 JUMPDEST +257 CALLVALUE +258 ISZERO +259 PUSH2 0x010b +262 JUMPI +263 PUSH1 0x00 +265 DUP1 +266 REVERT +267 JUMPDEST +268 PUSH2 0x0140 +271 PUSH1 0x04 +273 DUP1 +274 DUP1 +275 CALLDATALOAD +276 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +297 AND +298 SWAP1 +299 PUSH1 0x20 +301 ADD +302 SWAP1 +303 SWAP2 +304 SWAP1 +305 DUP1 +306 CALLDATALOAD +307 SWAP1 +308 PUSH1 0x20 +310 ADD +311 SWAP1 +312 SWAP2 +313 SWAP1 +314 POP +315 POP +316 PUSH2 0x01f3 +319 JUMP +320 JUMPDEST +321 PUSH1 0x40 +323 MLOAD +324 DUP1 +325 DUP3 +326 ISZERO +327 ISZERO +328 ISZERO +329 ISZERO +330 DUP2 +331 MSTORE +332 PUSH1 0x20 +334 ADD +335 SWAP2 +336 POP +337 POP +338 PUSH1 0x40 +340 MLOAD +341 DUP1 +342 SWAP2 +343 SUB +344 SWAP1 +345 RETURN +346 JUMPDEST +347 PUSH1 0x01 +349 SLOAD +350 DUP2 +351 JUMP +352 JUMPDEST +353 DUP1 +354 PUSH1 0x01 +356 DUP2 +357 SWAP1 +358 SSTORE +359 PUSH1 0x00 +361 DUP1 +362 CALLER +363 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +384 AND +385 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +406 AND +407 DUP2 +408 MSTORE +409 PUSH1 0x20 +411 ADD +412 SWAP1 +413 DUP2 +414 MSTORE +415 PUSH1 0x20 +417 ADD +418 PUSH1 0x00 +420 SHA3 +421 DUP2 +422 SWAP1 +423 SSTORE +424 POP +425 POP +426 JUMP +427 JUMPDEST +428 PUSH1 0x00 +430 DUP1 +431 PUSH1 0x00 +433 DUP4 +434 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +455 AND +456 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +477 AND +478 DUP2 +479 MSTORE +480 PUSH1 0x20 +482 ADD +483 SWAP1 +484 DUP2 +485 MSTORE +486 PUSH1 0x20 +488 ADD +489 PUSH1 0x00 +491 SHA3 +492 SLOAD +493 SWAP1 +494 POP +495 SWAP2 +496 SWAP1 +497 POP +498 JUMP +499 JUMPDEST +500 PUSH1 0x00 +502 DUP1 +503 DUP3 +504 PUSH1 0x00 +506 DUP1 +507 CALLER +508 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +529 AND +530 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +551 AND +552 DUP2 +553 MSTORE +554 PUSH1 0x20 +556 ADD +557 SWAP1 +558 DUP2 +559 MSTORE +560 PUSH1 0x20 +562 ADD +563 PUSH1 0x00 +565 SHA3 +566 SLOAD +567 SUB +568 LT +569 ISZERO +570 ISZERO +571 ISZERO +572 PUSH2 0x0244 +575 JUMPI +576 PUSH1 0x00 +578 DUP1 +579 REVERT +580 JUMPDEST +581 DUP2 +582 PUSH1 0x00 +584 DUP1 +585 CALLER +586 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +607 AND +608 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +629 AND +630 DUP2 +631 MSTORE +632 PUSH1 0x20 +634 ADD +635 SWAP1 +636 DUP2 +637 MSTORE +638 PUSH1 0x20 +640 ADD +641 PUSH1 0x00 +643 SHA3 +644 PUSH1 0x00 +646 DUP3 +647 DUP3 +648 SLOAD +649 SUB +650 SWAP3 +651 POP +652 POP +653 DUP2 +654 SWAP1 +655 SSTORE +656 POP +657 DUP2 +658 PUSH1 0x00 +660 DUP1 +661 DUP6 +662 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +683 AND +684 PUSH20 0xffffffffffffffffffffffffffffffffffffffff +705 AND +706 DUP2 +707 MSTORE +708 PUSH1 0x20 +710 ADD +711 SWAP1 +712 DUP2 +713 MSTORE +714 PUSH1 0x20 +716 ADD +717 PUSH1 0x00 +719 SHA3 +720 PUSH1 0x00 +722 DUP3 +723 DUP3 +724 SLOAD +725 ADD +726 SWAP3 +727 POP +728 POP +729 DUP2 +730 SWAP1 +731 SSTORE +732 POP +733 PUSH1 0x01 +735 SWAP1 +736 POP +737 SWAP3 +738 SWAP2 +739 POP +740 POP +741 JUMP +742 STOP diff --git a/tests/testdata/outputs_expected/outputs_current/underflow.sol.o.graph.html b/tests/testdata/outputs_expected/outputs_current/underflow.sol.o.graph.html new file mode 100644 index 00000000..767cda13 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/underflow.sol.o.graph.html @@ -0,0 +1,62 @@ + + + + Call Graph + + + + + + + + + + +

Mythril / Ethereum LASER Symbolic VM

+
+ + + \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/underflow.sol.o.json b/tests/testdata/outputs_expected/outputs_current/underflow.sol.o.json new file mode 100644 index 00000000..d651908c --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/underflow.sol.o.json @@ -0,0 +1 @@ +{"error": null, "issues": [{"address": 567, "contract": "Unknown", "debug": "", "description": "The subtraction can result in an integer underflow.\n", "function": "sendeth(address,uint256)", "swc_id": "101", "title": "Integer Underflow", "type": "Warning"}, {"address": 649, "contract": "Unknown", "debug": "", "description": "The subtraction can result in an integer underflow.\n", "function": "sendeth(address,uint256)", "swc_id": "101", "title": "Integer Underflow", "type": "Warning"}, {"address": 725, "contract": "Unknown", "debug": "", "description": "The arithmetic operation can result in integer overflow.\n", "function": "sendeth(address,uint256)", "swc_id": "101", "title": "Integer Overflow", "type": "Warning"}], "success": true} \ No newline at end of file diff --git a/tests/testdata/outputs_expected/outputs_current/underflow.sol.o.markdown b/tests/testdata/outputs_expected/outputs_current/underflow.sol.o.markdown new file mode 100644 index 00000000..f042f183 --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/underflow.sol.o.markdown @@ -0,0 +1,34 @@ +# Analysis results for test-filename.sol + +## Integer Underflow +- SWC ID: 101 +- Type: Warning +- Contract: Unknown +- Function name: `sendeth(address,uint256)` +- PC address: 567 + +### Description + +The subtraction can result in an integer underflow. + +## Integer Underflow +- SWC ID: 101 +- Type: Warning +- Contract: Unknown +- Function name: `sendeth(address,uint256)` +- PC address: 649 + +### Description + +The subtraction can result in an integer underflow. + +## Integer Overflow +- SWC ID: 101 +- Type: Warning +- Contract: Unknown +- Function name: `sendeth(address,uint256)` +- PC address: 725 + +### Description + +The arithmetic operation can result in integer overflow. diff --git a/tests/testdata/outputs_expected/outputs_current/underflow.sol.o.text b/tests/testdata/outputs_expected/outputs_current/underflow.sol.o.text new file mode 100644 index 00000000..ad480ffd --- /dev/null +++ b/tests/testdata/outputs_expected/outputs_current/underflow.sol.o.text @@ -0,0 +1,30 @@ +==== Integer Underflow ==== +SWC ID: 101 +Type: Warning +Contract: Unknown +Function name: sendeth(address,uint256) +PC address: 567 +The subtraction can result in an integer underflow. + +-------------------- + +==== Integer Underflow ==== +SWC ID: 101 +Type: Warning +Contract: Unknown +Function name: sendeth(address,uint256) +PC address: 649 +The subtraction can result in an integer underflow. + +-------------------- + +==== Integer Overflow ==== +SWC ID: 101 +Type: Warning +Contract: Unknown +Function name: sendeth(address,uint256) +PC address: 725 +The arithmetic operation can result in integer overflow. + +-------------------- + diff --git a/tests/testdata/outputs_expected/overflow.sol.o.graph.html b/tests/testdata/outputs_expected/overflow.sol.o.graph.html index 5d117d28..188273ad 100644 --- a/tests/testdata/outputs_expected/overflow.sol.o.graph.html +++ b/tests/testdata/outputs_expected/overflow.sol.o.graph.html @@ -8,6 +8,7 @@

Mythril / Ethereum LASER Symbolic VM

-


+

Mythril / Ethereum LASER Symbolic VM

-


+

Mythril / Ethereum LASER Symbolic VM

-


+

Mythril / Ethereum LASER Symbolic VM

-


+