diff --git a/mythril/interfaces/cli.py b/mythril/interfaces/cli.py index 1501120f..cdc6044d 100644 --- a/mythril/interfaces/cli.py +++ b/mythril/interfaces/cli.py @@ -769,15 +769,6 @@ def parse_args_and_execute(parser: ArgumentParser, args: Namespace) -> None: solc_settings_json=solc_json, enable_online_lookup=query_signature, ) - if args.command == "truffle": - try: - disassembler.analyze_truffle_project(args) - except FileNotFoundError: - print( - "Build directory not found. Make sure that you start the analysis from the project root, " - "and that 'truffle compile' has executed successfully." - ) - sys.exit() address = load_code(disassembler, args) execute_command( diff --git a/mythril/interfaces/old_cli.py b/mythril/interfaces/old_cli.py index 27bde387..5db0aff2 100644 --- a/mythril/interfaces/old_cli.py +++ b/mythril/interfaces/old_cli.py @@ -528,14 +528,6 @@ def parse_args(parser: argparse.ArgumentParser, args: argparse.Namespace) -> Non solc_settings_json=args.solc_json, enable_online_lookup=args.query_signature, ) - if args.truffle: - try: - disassembler.analyze_truffle_project(args) - except FileNotFoundError: - print( - "Build directory not found. Make sure that you start the analysis from the project root, and that 'truffle compile' has executed successfully." - ) - sys.exit() address = get_code(disassembler, args) execute_command( diff --git a/mythril/mythril/mythril_disassembler.py b/mythril/mythril/mythril_disassembler.py index e7ef1e3b..ad6b04b7 100644 --- a/mythril/mythril/mythril_disassembler.py +++ b/mythril/mythril/mythril_disassembler.py @@ -10,7 +10,6 @@ from mythril.ethereum import util from mythril.ethereum.interface.rpc.client import EthJsonRpc from mythril.exceptions import CriticalError, CompilerError, NoContractFoundError from mythril.support import signatures -from mythril.support.truffle import analyze_truffle_project from mythril.ethereum.evmcontract import EVMContract from mythril.ethereum.interface.rpc.exceptions import ConnectionError from mythril.solidity.soliditycontract import SolidityContract, get_contracts_from_file @@ -225,16 +224,6 @@ class MythrilDisassembler: return address, contracts - def analyze_truffle_project(self, *args, **kwargs) -> None: - """ - :param args: - :param kwargs: - :return: - """ - analyze_truffle_project( - self.sigs, *args, **kwargs - ) # just passthru by passing signatures for now - @staticmethod def hash_for_function_signature(func: str) -> str: """ diff --git a/mythril/support/truffle.py b/mythril/support/truffle.py deleted file mode 100644 index b42b1e10..00000000 --- a/mythril/support/truffle.py +++ /dev/null @@ -1,205 +0,0 @@ -"""This module contains functionality used to easily analyse Truffle -projects.""" -import json -import logging -import os -import re -import sys -import warnings -from pathlib import PurePath - -from ethereum.utils import sha3 - -from mythril.analysis.report import Report -from mythril.analysis.security import fire_lasers -from mythril.analysis.symbolic import SymExecWrapper -from mythril.ethereum import util -from mythril.ethereum.evmcontract import EVMContract -from mythril.laser.ethereum.util import get_instruction_index -from mythril.solidity.soliditycontract import SourceMapping - -log = logging.getLogger(__name__) - - -def format_Warning(message, category, filename, lineno, line=""): - return "{}: {}\n\n".format(str(filename), str(message)) - - -warnings.formatwarning = format_Warning - - -def analyze_truffle_project(sigs, args): - """ - - :param sigs: - :param args: - """ - warnings.warn( - "The option --truffle is being deprecated, Please use the truffle-security plugin, https://github.com/ConsenSys/truffle-security", - FutureWarning, - ) - - project_root = os.getcwd() - - build_dir = os.path.join(project_root, "build", "contracts") - - files = os.listdir(build_dir) - - for filename in files: - - if re.match(r".*\.json$", filename) and filename != "Migrations.json": - - with open(os.path.join(build_dir, filename)) as cf: - contractdata = json.load(cf) - - try: - name = contractdata["contractName"] - bytecode = contractdata["deployedBytecode"] - filename = PurePath(contractdata["sourcePath"]).name - except KeyError: - print( - "Unable to parse contract data. Please use Truffle 4 to compile your project." - ) - sys.exit() - if len(bytecode) < 4: - continue - get_sigs_from_truffle(sigs, contractdata) - - ethcontract = EVMContract(bytecode, name=name) - - address = util.get_indexed_address(0) - sym = SymExecWrapper( - ethcontract, - address, - args.strategy, - max_depth=args.max_depth, - create_timeout=args.create_timeout, - execution_timeout=args.execution_timeout, - transaction_count=args.transaction_count, - modules=args.modules or [], - compulsory_statespace=False, - ) - issues = fire_lasers(sym) - - if not len(issues): - if args.outform == "text" or args.outform == "markdown": - print("# Analysis result for " + name + "\n\nNo issues found.") - else: - result = { - "contract": name, - "result": {"success": True, "error": None, "issues": []}, - } - print(json.dumps(result)) - else: - - report = Report() - # augment with source code - - deployed_disassembly = ethcontract.disassembly - constructor_disassembly = ethcontract.creation_disassembly - - source = contractdata["source"] - - deployed_source_map = contractdata["deployedSourceMap"].split(";") - source_map = contractdata["sourceMap"].split(";") - - deployed_mappings = get_mappings(source, deployed_source_map) - constructor_mappings = get_mappings(source, source_map) - - for issue in issues: - if issue.function == "constructor": - mappings = constructor_mappings - disassembly = constructor_disassembly - else: - mappings = deployed_mappings - disassembly = deployed_disassembly - - index = get_instruction_index( - disassembly.instruction_list, issue.address - ) - - if index: - try: - offset = mappings[index].offset - length = mappings[index].length - - issue.filename = filename - issue.code = source.encode("utf-8")[ - offset : offset + length - ].decode("utf-8") - issue.lineno = mappings[index].lineno - except IndexError: - log.debug("No code mapping at index %d", index) - - report.append_issue(issue) - - if args.outform == "json": - - result = { - "contract": name, - "result": { - "success": True, - "error": None, - "issues": list(map(lambda x: x.as_dict, issues)), - }, - } - print(json.dumps(result)) - - else: - if args.outform == "text": - print( - "# Analysis result for " + name + ":\n\n" + report.as_text() - ) - elif args.outform == "markdown": - print(report.as_markdown()) - - -def get_sigs_from_truffle(sigs, contract_data): - """ - - :param sigs: - :param contract_data: - """ - abis = contract_data["abi"] - for abi in abis: - if abi["type"] != "function": - continue - function_name = abi["name"] - list_of_args = ",".join([input["type"] for input in abi["inputs"]]) - signature = function_name + "(" + list_of_args + ")" - sigs.add("0x" + sha3(signature)[:4].hex(), signature) - - -def get_mappings(source, deployed_source_map): - """ - - :param source: - :param deployed_source_map: - :return: - """ - mappings = [] - prev_item = "" - for item in deployed_source_map: - if item == "": - item = prev_item - - mapping = item.split(":") - - if len(mapping) > 0 and len(mapping[0]) > 0: - offset = int(mapping[0]) - - if len(mapping) > 1 and len(mapping[1]) > 0: - length = int(mapping[1]) - - if len(mapping) > 2 and len(mapping[2]) > 0: - idx = int(mapping[2]) - - if idx == -1: - lineno = None - else: - lineno = source.encode("utf-8")[0:offset].count("\n".encode("utf-8")) + 1 - prev_item = item - - mappings.append(SourceMapping(idx, offset, length, lineno, item)) - - return mappings diff --git a/tests/cmd_line_test.py b/tests/cmd_line_test.py index 258a6882..8d67ca5f 100644 --- a/tests/cmd_line_test.py +++ b/tests/cmd_line_test.py @@ -70,15 +70,6 @@ class CommandLineToolTestCase(BaseTestCase): self.assertIn("0x1a270efc", output_of(command)) -class TruffleTestCase(BaseTestCase): - def test_analysis_truffle_project(self): - truffle_project_root = str(TESTS_DIR / "truffle_project") - command = "cd {}; truffle compile; python3 {} truffle -t 2".format( - truffle_project_root, MYTH - ) - self.assertIn("=== Unprotected Ether Withdrawal ====", output_of(command)) - - class InfuraTestCase(BaseTestCase): def test_infura_mainnet(self): command = "python3 {} disassemble --rpc infura-mainnet -a 0x2a0c0dbecc7e4d658f48e01e3fa353f44050c208".format( diff --git a/tests/truffle_project/README.md b/tests/truffle_project/README.md deleted file mode 100644 index 6629e939..00000000 --- a/tests/truffle_project/README.md +++ /dev/null @@ -1,30 +0,0 @@ -Truffle Hello World Demo -======================== - -``` -npm install -g truffle ethereumjs-testrpc -``` - -This repo is created by following commands: - -``` -truffle init -truffle compile -``` - -In order to run `truffle migrate`, we need to setup `truffle.js` first: - -``` -networks: { - development: { - host: "localhost", - port: 8545, - network_id: "*" // Match any network id - } -} -``` - -Resources ---------- - -- diff --git a/tests/truffle_project/contracts/Migrations.sol b/tests/truffle_project/contracts/Migrations.sol deleted file mode 100644 index f170cb4f..00000000 --- a/tests/truffle_project/contracts/Migrations.sol +++ /dev/null @@ -1,23 +0,0 @@ -pragma solidity ^0.4.17; - -contract Migrations { - address public owner; - uint public last_completed_migration; - - modifier restricted() { - if (msg.sender == owner) _; - } - - function Migrations() public { - owner = msg.sender; - } - - function setCompleted(uint completed) public restricted { - last_completed_migration = completed; - } - - function upgrade(address new_address) public restricted { - Migrations upgraded = Migrations(new_address); - upgraded.setCompleted(last_completed_migration); - } -} diff --git a/tests/truffle_project/contracts/ether_send.sol b/tests/truffle_project/contracts/ether_send.sol deleted file mode 100644 index c8e5bc46..00000000 --- a/tests/truffle_project/contracts/ether_send.sol +++ /dev/null @@ -1,34 +0,0 @@ -contract Crowdfunding { - - mapping(address => uint) public balances; - address public owner; - uint256 INVEST_MIN = 1 ether; - uint256 INVEST_MAX = 10 ether; - - modifier onlyOwner() { - require(msg.sender == owner); - _; - } - - function crowdfunding() { - owner = msg.sender; - } - - function withdrawfunds() onlyOwner { - msg.sender.transfer(this.balance); - } - - function invest() public payable { - require(msg.value > INVEST_MIN && msg.value < INVEST_MAX); - - balances[msg.sender] += msg.value; - } - - function getBalance() public constant returns (uint) { - return balances[msg.sender]; - } - - function() public payable { - invest(); - } -} \ No newline at end of file diff --git a/tests/truffle_project/migrations/1_initial_migration.js b/tests/truffle_project/migrations/1_initial_migration.js deleted file mode 100644 index 4d5f3f9b..00000000 --- a/tests/truffle_project/migrations/1_initial_migration.js +++ /dev/null @@ -1,5 +0,0 @@ -var Migrations = artifacts.require("./Migrations.sol"); - -module.exports = function(deployer) { - deployer.deploy(Migrations); -}; diff --git a/tests/truffle_project/truffle-config.js b/tests/truffle_project/truffle-config.js deleted file mode 100644 index a6330d6d..00000000 --- a/tests/truffle_project/truffle-config.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - // See - // to customize your Truffle configuration! -}; diff --git a/tests/truffle_project/truffle.js b/tests/truffle_project/truffle.js deleted file mode 100644 index 1a56d124..00000000 --- a/tests/truffle_project/truffle.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = { - // See - // to customize your Truffle configuration! - networks: { - development: { - host: "localhost", - port: 8545, - network_id: "*" // Match any network id - } - } -};