Giter Site home page Giter Site logo

evm_cfg_builder's Introduction

EVM CFG BUILDER

Build Status Slack Status PyPI version

evm-cfg-builder is used to extract a control flow graph (CFG) from EVM bytecode. It is used by Ethersplay, Manticore, and other tools from Trail of Bits. It is a reliable foundation to build program analysis tools for EVM.

We encourage contributions that address any known issues and will pay out bounties for accepted PRs. Join us on the Empire Hacking Slack to discuss using or extending evm-cfg-builder.

Features

  • Reliably recovers a Control Flow Graph (CFG) from EVM bytecode using a dedicated Value Set Analysis
  • Recovers functions names
  • Recovers attributes (e.g., payable, view, pure)
  • Outputs the CFG to a dot file
  • Library API

Usage

Command-line

To export basic dissassembly information, run:

evm-cfg-builder mycontract.evm 

To export the CFG of each function (dot format), run:

evm-cfg-builder mycontract.evm --export-dot my_dir 

dot files can be read using xdot.

Library

See examples/explore_cfg.py and examples/explore_functions.py for library examples.

How to install

Using Pip

pip install evm-cfg-builder

Using Git

git clone https://github.com/trailofbits/evm_cfg_builder
pip install .

Requirements

Getting Help

Feel free to stop by our Slack channel (#ethereum) for help using or extending evm-cfg-builder.

License

evm-cfg-builder is licensed and distributed under the AGPLv3. Contact us if you're looking for an exception to the terms.

evm_cfg_builder's People

Contributors

dguido avatar disconnect3d avatar elopez avatar montyly avatar pbwaffles avatar rajeevgopalakrishna avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

evm_cfg_builder's Issues

Replace calls to `print` with logging that can be enabled/disabled

I would prefer if the module itself did not have any calls to print in it. If having some output about analysis outside of __main__ blocks is necessary, it would be better to use some sort of logging that can be customized or completely ignored without having to try to do stdout redirection.

Investigate missing branches

From time to time the VSA is lost and is not able to retrieve the jump destination (error message Missing branches).

We need to investigate why it happens and how to fix it

Create Gidhra plugin

Task Description

We should have a Ghidra plugin for evm-cfg-builder.

Acceptance criteria

  • An evm file can be loaded in Ghidra
  • The CFG is shown
  • The function's name is shown (if recovered by evm-cfg-builder)

Required Skills

  • Reverse engineering experience
  • Ghidra or IDA experience
  • Experience with Python 3.6
  • Experience with Solidity smart contracts

Feel free to ask questions here, or join our slack (#ethereum)

Change knownHashes key from strings to integers

Using integers as dictionary keys is about twice as fast as using strings, and this would also remove the extra step of converting the Function.hash_id from an integer to a hex string prior to using it as a key in the knownHashes dict.

Only two functions detected in smart contract with ten functions

After creating a CFG on a simple smart contract with ten functions calling cfg.functions only yields two functions. After compiling TestContract.sol and creating the CFG from its TestContract.evm I see only two functions.

In python:

from evm_cfg_builder.cfg import CFG

runtime_bytecode = "0x608060405234801561001057600080fd5b506004361061012c5760003560e01c8063ac357632116100ad578063d7667f9911610071578063d7667f991461054b578063e2b9dcd514610591578063eed687c7146105d7578063f9392b591461061d578063fc78699e146106635761012c565b8063ac357632146103ed578063ad6fc25914610433578063ba5278d314610479578063bd76f3ba146104bf578063c63e6427146105055761012c565b80635a2cd2f3116100f45780635a2cd2f31461028f5780636623e5f4146102d557806372fdcfd31461031b57806384efc000146103615780638f10e3a0146103a75761012c565b8063066c36e2146101315780631a5e90f9146101775780632650b6c5146101bd57806354d315521461020357806356208a6d14610249575b600080fd5b61015d6004803603602081101561014757600080fd5b81019080803590602001909291905050506106a9565b604051808215151515815260200191505060405180910390f35b6101a36004803603602081101561018d57600080fd5b81019080803590602001909291905050506106c7565b604051808215151515815260200191505060405180910390f35b6101e9600480360360208110156101d357600080fd5b81019080803590602001909291905050506106e5565b604051808215151515815260200191505060405180910390f35b61022f6004803603602081101561021957600080fd5b8101908080359060200190929190505050610703565b604051808215151515815260200191505060405180910390f35b6102756004803603602081101561025f57600080fd5b8101908080359060200190929190505050610721565b604051808215151515815260200191505060405180910390f35b6102bb600480360360208110156102a557600080fd5b810190808035906020019092919050505061073f565b604051808215151515815260200191505060405180910390f35b610301600480360360208110156102eb57600080fd5b810190808035906020019092919050505061075d565b604051808215151515815260200191505060405180910390f35b6103476004803603602081101561033157600080fd5b810190808035906020019092919050505061077b565b604051808215151515815260200191505060405180910390f35b61038d6004803603602081101561037757600080fd5b8101908080359060200190929190505050610799565b604051808215151515815260200191505060405180910390f35b6103d3600480360360208110156103bd57600080fd5b81019080803590602001909291905050506107b7565b604051808215151515815260200191505060405180910390f35b6104196004803603602081101561040357600080fd5b81019080803590602001909291905050506107d5565b604051808215151515815260200191505060405180910390f35b61045f6004803603602081101561044957600080fd5b81019080803590602001909291905050506107f3565b604051808215151515815260200191505060405180910390f35b6104a56004803603602081101561048f57600080fd5b8101908080359060200190929190505050610811565b604051808215151515815260200191505060405180910390f35b6104eb600480360360208110156104d557600080fd5b810190808035906020019092919050505061082f565b604051808215151515815260200191505060405180910390f35b6105316004803603602081101561051b57600080fd5b810190808035906020019092919050505061084d565b604051808215151515815260200191505060405180910390f35b6105776004803603602081101561056157600080fd5b810190808035906020019092919050505061086b565b604051808215151515815260200191505060405180910390f35b6105bd600480360360208110156105a757600080fd5b8101908080359060200190929190505050610889565b604051808215151515815260200191505060405180910390f35b610603600480360360208110156105ed57600080fd5b81019080803590602001909291905050506108a7565b604051808215151515815260200191505060405180910390f35b6106496004803603602081101561063357600080fd5b81019080803590602001909291905050506108c5565b604051808215151515815260200191505060405180910390f35b61068f6004803603602081101561067957600080fd5b81019080803590602001909291905050506108e3565b604051808215151515815260200191505060405180910390f35b600060808214156106bd57600090506106c2565b600190505b919050565b600060808214156106db57600090506106e0565b600190505b919050565b600060808214156106f957600090506106fe565b600190505b919050565b60006080821415610717576000905061071c565b600190505b919050565b60006080821415610735576000905061073a565b600190505b919050565b600060808214156107535760009050610758565b600190505b919050565b600060808214156107715760009050610776565b600190505b919050565b6000608082141561078f5760009050610794565b600190505b919050565b600060808214156107ad57600090506107b2565b600190505b919050565b600060808214156107cb57600090506107d0565b600190505b919050565b600060808214156107e957600090506107ee565b600190505b919050565b60006080821415610807576000905061080c565b600190505b919050565b60006080821415610825576000905061082a565b600190505b919050565b600060808214156108435760009050610848565b600190505b919050565b600060808214156108615760009050610866565b600190505b919050565b6000608082141561087f5760009050610884565b600190505b919050565b6000608082141561089d57600090506108a2565b600190505b919050565b600060808214156108bb57600090506108c0565b600190505b919050565b600060808214156108d957600090506108de565b600190505b919050565b600060808214156108f757600090506108fc565b600190505b91905056fea265627a7a723158204e5e73fbefb184bdcc942d5864d57242af569a591514f4e670098b6c95737d4c64736f6c634300050c0032"

cfg = CFG(runtime_bytecode)
cfg.functions

> [<cfg Function@10>, <cfg Function@0>]

pip version outdated/broken

The version published on pip seems to be outdated (the version tag is identically though). When I install the current version published on pip I get the following message when trying to export the cfg as a dot file:

Traceback (most recent call last):
  File "/Users//.pyenv/versions/evm_toolkit/bin/evm-cfg-builder", line 11, i
n <module>
    sys.exit(main())
  File "/Users//.pyenv/versions/3.6.4/envs/evm_toolkit/lib/python3.6/site-pa
ckages/evm_cfg_builder/__main__.py", line 63, in main
    output_to_dot(args.dot_directory, args.filename, cfg)
  File "/Users//.pyenv/versions/3.6.4/envs/evm_toolkit/lib/python3.6/site-pa
ckages/evm_cfg_builder/__main__.py", line 21, in output_to_dot
    function.output_to_dot(filename)
  File "/Users//.pyenv/versions/3.6.4/envs/evm_toolkit/lib/python3.6/site-pa
ckages/evm_cfg_builder/cfg/function.py", line 146, in output_to_dot
    self.output_dispatcher_to_dot(base_filename)
  File "/Users//.pyenv/versions/3.6.4/envs/evm_toolkit/lib/python3.6/site-pa
ckages/evm_cfg_builder/cfg/function.py", line 181, in output_dispatcher_to_dot
    if self.key in basic_block.incoming_basic_blocks_as_dict:
AttributeError: 'BasicBlock' object has no attribute 'incoming_basic_blocks_as_dict'

Which was an error fixed in commit 0e1009f. However, the fix does not seem to be propagated to pip yet.

"KeyError: 0" error

When used with slyther and and a solidity version <0.5.x it gives the following error:

File "/home/ethsec/.local/lib/python3.6/site-packages/slither/main.py", line 741, in main_impl
) = process_all(filename, args, detector_classes, printer_classes)
File "/home/ethsec/.local/lib/python3.6/site-packages/slither/main.py", line 83, in process_all
) = process_single(compilation, args, detector_classes, printer_classes)
File "/home/ethsec/.local/lib/python3.6/site-packages/slither/main.py", line 68, in process_single
return _process(slither, detector_classes, printer_classes)
File "/home/ethsec/.local/lib/python3.6/site-packages/slither/main.py", line 115, in _process
printer_results = slither.run_printers()
File "/home/ethsec/.local/lib/python3.6/site-packages/slither/slither.py", line 195, in run_printers
return [p.output(self._crytic_compile.target).data for p in self._printers]
File "/home/ethsec/.local/lib/python3.6/site-packages/slither/slither.py", line 195, in
return [p.output(self._crytic_compile.target).data for p in self._printers]
File "/home/ethsec/.local/lib/python3.6/site-packages/slither/printers/summary/evm.py", line 79, in output
evm_info = _extract_evm_info(self.slither)
File "/home/ethsec/.local/lib/python3.6/site-packages/slither/printers/summary/evm.py", line 32, in _extract_evm_info
cfg = CFG(contract_bytecode_runtime)
File "/usr/local/lib/python3.6/dist-packages/evm_cfg_builder/cfg/init.py", line 96, in init
self.create_functions()
File "/usr/local/lib/python3.6/dist-packages/evm_cfg_builder/cfg/init.py", line 183, in create_functions
self.compute_functions(self._basic_blocks[0], True)
KeyError: 0
None

Traceback (most recent call last):
File "/home/ethsec/.local/lib/python3.6/site-packages/slither/main.py", line 741, in main_impl
) = process_all(filename, args, detector_classes, printer_classes)
File "/home/ethsec/.local/lib/python3.6/site-packages/slither/main.py", line 83, in process_all
) = process_single(compilation, args, detector_classes, printer_classes)
File "/home/ethsec/.local/lib/python3.6/site-packages/slither/main.py", line 68, in process_single
return _process(slither, detector_classes, printer_classes)
File "/home/ethsec/.local/lib/python3.6/site-packages/slither/main.py", line 115, in _process
printer_results = slither.run_printers()
File "/home/ethsec/.local/lib/python3.6/site-packages/slither/slither.py", line 195, in run_printers
return [p.output(self._crytic_compile.target).data for p in self._printers]
File "/home/ethsec/.local/lib/python3.6/site-packages/slither/slither.py", line 195, in
return [p.output(self._crytic_compile.target).data for p in self._printers]
File "/home/ethsec/.local/lib/python3.6/site-packages/slither/printers/summary/evm.py", line 79, in output
evm_info = _extract_evm_info(self.slither)
File "/home/ethsec/.local/lib/python3.6/site-packages/slither/printers/summary/evm.py", line 32, in _extract_evm_info
cfg = CFG(contract_bytecode_runtime)
File "/usr/local/lib/python3.6/dist-packages/evm_cfg_builder/cfg/init.py", line 96, in init
self.create_functions()
File "/usr/local/lib/python3.6/dist-packages/evm_cfg_builder/cfg/init.py", line 183, in create_functions
self.compute_functions(self._basic_blocks[0], True)
KeyError: 0

Refactor CFG.__init__

Make CFG's init method pure, so that it's only storing the bytecode. Additionally, create @classmethod factory methods to generate a new CFG object from hex or bytes.

ValueError: non-hexadecimal number found in fromhex() arg at position xxx

Not sure why I'm getting this error for both test cases provided (fomo3d.evm and recurse.evm):

bash-3.2$ evm-cfg-builder fomo3d.evm
evm-cfg-builder fomo3d.evm
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.6/bin/evm-cfg-builder", line 11, in <module>
    load_entry_point('evm-cfg-builder==0.2.0', 'console_scripts', 'evm-cfg-builder')()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/evm_cfg_builder-0.2.0-py3.6.egg/evm_cfg_\
builder/__main__.py", line 57, in main
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/evm_cfg_builder-0.2.0-py3.6.egg/evm_cfg_\
builder/cfg/__init__.py", line 55, in __init__
ValueError: non-hexadecimal number found in fromhex() arg at position 18642

bash-3.2$ evm-cfg-builder --version
evm-cfg-builder --version
0.2.0

Fix CFG API

We currently have a mix between the properties and the functions of the CFG.
What we should have:

  • cfg.instructions/cfg.basic_blocks/cfg.functions properties returning a list
  • cfg.get_instruction_at(addr)/cfg.get_basic_block_at(addr)/cfg.get_function_at(addr) functions returning the element
  • remove the .._from_addr properties

Investigate dispatcher strategies

We should document, implement and test the different dispatcher strategies used by solc, from 0.4 to the latest versions, including with or without optimization

#27 is an example of dispatcher strategy that was not correctly handled.

Error: Missing branches

Here is a simple contract:

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract Test{
	function p1() private returns(int) {
		return 3;
	}
	function p2() external returns(int) {
		return p1();
	}
}

solc --bin-runtime a.sol outputs 6080604052348015600f57600080fd5b506004361060285760003560e01c806381d01ed314602d575b600080fd5b60336047565b604051603e91906074565b60405180910390f35b6000604f6054565b905090565b60006003905090565b6000819050919050565b606e81605d565b82525050565b6000602082019050608760008301846067565b9291505056fea26469706673582212200a7cedf97c05163dd6a5a92d897b2d089f38434e1d25e6ef981ce390a3805ba064736f6c634300080a0033

Then I tried evm_cfg_builder a.evm, the output shows ERROR:evm-cfg-builder:Missing branches p2():0x5c.

Why is the error? Thanks.

Input: add if `0x` if missing

Currently, evm-cfg-builder does not read correctly a file with bytecode that does not start with 0x, we should improve this

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.