Coder Social home page Coder Social logo

rattle's People

Contributors

carstennz avatar dependabot[bot] avatar dguido avatar jesserc avatar montyly avatar nveloso avatar withzombies avatar woodruffw 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rattle's Issues

Optimize operations

There are many constant operations that we don't optimize.

Pretty much every address load has 2-5 operations that can be optimized:

<SSA::Block offset:0x84>
   %20 = SLOAD(#1)
   %21 = CALLER()
   %22 = EXP(#2, #a0)
   %23 = SUB(%22, #1)
   %24 = AND(%23, %21)

Error conditions that jump to invalid offsets

We don't handle error conditions that jump to invalid targets.

python3 rattle.py --input inputs/sycep/SYCEarlyPurchase.binaryninja.bytecode

sycep jumps to offset 0x1 in block 0xc94.

Fails to work for the 0x v2 `Exchange` contract

➜  rattle git:(master) ✗ python3 rattle-cli.py --input ../code.bytecode -O
Traceback (most recent call last):
  File "rattle-cli.py", line 203, in <module>
    main()
  File "rattle-cli.py", line 48, in main
    ssa = rattle.Recover(args.input.read(), edges=edges, optimize=args.optimize)
  File "/Users/___/Projects/Ethereum/rattle/rattle/recover.py", line 712, in __init__
    self.internal = InternalRecover(filedata, edges, optimize)
  File "/Users/___/Projects/Ethereum/rattle/rattle/recover.py", line 41, in __init__
    self.recover(dispatch)
  File "/Users/___/Projects/Ethereum/rattle/rattle/recover.py", line 75, in recover
    self.identify_blocks(function)
  File "/Users/___/Projects/Ethereum/rattle/rattle/recover.py", line 185, in identify_blocks
    block.set_fallthrough_target(terminator.offset + terminator.insn.size)
  File "/Users/___/Projects/Ethereum/rattle/rattle/ssa.py", line 478, in set_fallthrough_target
    target_block : SSABasicBlock = self.function.blockmap[other]
KeyError: 22707

code.bytecode created with cat code.bin | xxd -r -ps > code.bytecode whereas code.bin is https://gist.github.com/reverendus/9151b4d7b154b63fd55ae663fa6465a4. I'm on the recent master i.e. 2ec580f6963ee876b90326576bc328cca0d03c79.

Basic CFG Recovery misses some blocks

SSA lifting identifies them, but basic recovery misses them.

python3 rattle.py --input inputs/inline_calls/C.bin.bytecode

Misses a block starting at 0x2e.

Use-def graphs

Symbolic variables should keep track of who defined them and where they're used.

Delegatecalls causes ValueError

If a contract has a delegatecall, we get this exception:

Traceback (most recent call last):
  File "rattle-cli.py", line 191, in <module>
    main()
  File "rattle-cli.py", line 87, in main
    can_send, functions_that_can_send = ssa.can_send_ether()
  File "/home/itszn/tools/rattle/rattle/recover.py", line 724, in can_send_ether
    frv, _ = function.can_send_ether()
  File "/home/itszn/tools/rattle/rattle/ssa.py", line 692, in can_send_ether
    gas, to, value, in_offset, in_size, out_offset, out_size = insn.arguments
ValueError: not enough values to unpack (expected 7, got 6)

Here is an example contract:

pragma solidity ^0.4.24;
contract Test {
    function test(address target, bytes data) public {
        target.delegatecall(data);
    }
}

Failure to identify internal call results in wrong CFG

Git a3fa9c7

Function luckyNumberOfAddress of the Lottery example.

The body of luckyNumberOfAddress is factorized by the compiler into an internal helper function that is used by luckyNumberOfAddress and participate.

Rattle fails to identify the helper function and consequently pulls part of the participate body (after the call) into the luckyNumberOfAddress body.

2022-05-02 08_36_38-luckyNumberOfAddress(address)

CFG recovery non-termination

Rattle and ethersplay both fail to recover the control flow graph of the fomo3d contract. Analysis never finishes.

AttributeError: 'NoneType' object has no attribute 'offset'

sloth:rattle pag$ python3 rattle-cli.py --input map.bin  -O
INVALID JUMPDEST: <SSABasicBlock offset:0x3f num_insns:1 in: [] insns:[
	<0x3f: INVALID()>
] fallthrough:None jumps:None>
INVALID JUMPDEST: <SSABasicBlock offset:0x44 num_insns:1 in: [] insns:[
	<0x44: INVALID()>
] fallthrough:None jumps:None>
INVALID JUMPDEST: <SSABasicBlock offset:0x4f num_insns:1 in: [] insns:[
	<0x4f: INVALID()>
] fallthrough:None jumps:None>
INVALID JUMPDEST: <SSABasicBlock offset:0x8e num_insns:1 in: [] insns:[
	<0x8e: INVALID()>
] fallthrough:None jumps:None>
Traceback (most recent call last):
  File "rattle-cli.py", line 191, in <module>
    main()
  File "rattle-cli.py", line 50, in main
    print(ssa)
  File "/Users/pag/Code/rattle/rattle/recover.py", line 689, in __str__
    rv += str(function) + "\n\n"
  File "/Users/pag/Code/rattle/rattle/ssa.py", line 522, in __repr__
    blocks = '\n'.join([f'{x}' for x in self.blocks])
  File "/Users/pag/Code/rattle/rattle/ssa.py", line 522, in <listcomp>
    blocks = '\n'.join([f'{x}' for x in self.blocks])
  File "/Users/pag/Code/rattle/rattle/ssa.py", line 424, in __repr__
    jump_targets = [f"{x.offset:#x}" for x in self.jump_edges]
  File "/Users/pag/Code/rattle/rattle/ssa.py", line 424, in <listcomp>
    jump_targets = [f"{x.offset:#x}" for x in self.jump_edges]
AttributeError: 'NoneType' object has no attribute 'offset'

From this contract:

pragma solidity ^0.4.0;
contract Foo {

    mapping(address => uint) addr_to_uint;
    uint[] array_of_uints;

    function Set(address from, uint to) public {
        addr_to_uint[from] = to;
    }
}

With bytecode:

{
    "linkReferences": {},
    "object": "608060405234801561001057600080fd5b50610101806100206000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063fd28ec3e146044575b600080fd5b348015604f57600080fd5b50608c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050608e565b005b806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050505600a165627a7a7230582066505353c876f1bedecc87837015db37436ab0482aa0819d53f28c363da469800029",
    "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x101 DUP1 PUSH2 0x20 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH1 0x3F JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0xFD28EC3E EQ PUSH1 0x44 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x4F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x8C PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH1 0x8E JUMP JUMPDEST STOP JUMPDEST DUP1 PUSH1 0x0 DUP1 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 DUP2 SWAP1 SSTORE POP POP POP JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 PUSH7 0x505353C876F1BE 0xde 0xcc DUP8 DUP4 PUSH17 0x15DB37436AB0482AA0819D53F28C363DA4 PUSH10 0x80002900000000000000 ",
    "sourceMap": "24:176:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;24:176:0;;;;;;;"
}

Can't run example of project

I ran this command to test this tool at beginning
python3 rattle-cli.py --input inputs/kingofether/KingOfTheEtherThrone.bin -0

But got following error:

File "rattle-cli.py", line 46
    logger.info(f"Rattle running on input: {args.input.name}")
                                                            ^
SyntaxError: invalid syntax

FileNotFoundError: [Errno 2] No such file or directory: 'dot': 'dot'

I tried to get rattle running and got FileNotFoundError: [Errno 2] No such file or directory: 'dot': 'dot'

Traceback (most recent call last):
  File "rattle-cli.py", line 203, in <module>
    main()
  File "rattle-cli.py", line 189, in main
    subprocess.call(['dot', '-Tpng', f'-o{out_file}', t.name])
  File "~/.pyenv/versions/3.7.0/lib/python3.7/subprocess.py", line 304, in call
    with Popen(*popenargs, **kwargs) as p:
  File "~/.pyenv/versions/3.7.0/lib/python3.7/subprocess.py", line 756, in __init__
    restore_signals, start_new_session)
  File "~/.pyenv/versions/3.7.0/lib/python3.7/subprocess.py", line 1499, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'dot': 'dot'

I also tried to fix dot path but can find it no where

Rattle never finishes for some contracts

I tried analyzing the wallet contract from RealWorldCTF, but rattle never output anything or finished running. It appears to be stuck in some kind of infinite loop.

I ran the contract with python3.6 rattle-cli.py --input ./inputs/multisig.bin

Here is the contract with only the seemingly important parts left that cause the hang (removing either public function causes the hang to go away):

pragma solidity ^0.4.24;
contract MultiSigWallet {
    struct Transaction{
        address target; // 3
        uint amount; // 4
        bool isDelegate; // 5
        bytes data; // 6
    }
    Transaction[] transactions;
    mapping(address => bool) isOwner;
    mapping(address => bool) isTrusted;
    Transaction tx;

    constructor() public{
        isOwner[msg.sender] = true;
    }

    // ...

    function deleteTransaction(uint id) public{
        for (uint i = id; i < transactions.length-1; i++){
            transactions[i] = transactions[i+1];
        }
        popTransaction();
    }

    // ...

    // there's no pop impl in solidity, sad :(
    function popTransaction() internal {
        require(transactions.length >= 0);
        transactions.length --;
    }

    function submitTransaction(address target, uint amount, bool isDelegate, bytes data) public returns(uint){
        tx = Transaction(target, amount, isDelegate, data);
        if (isOwner[msg.sender]) {
            transactions.push(tx);
        }
        return transactions.length-1;
    }

    // ...
}

Here is the runtime bin:

YIBgQFJgBDYQYQBLV2AANXwBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJAEY/////8WgGLp
wAYUYQBQV4BjxqxT/RRhAH1XW2AAgP1bNIAVYQBcV2AAgP1bUGEAe2AEgDYDgQGQgIA1kGAgAZCS
kZBQUFBhATBWWwBbNIAVYQCJV2AAgP1bUGEBGmAEgDYDgQGQgIA1c///////////////////////
////FpBgIAGQkpGQgDWQYCABkJKRkIA1FRWQYCABkJKRkIA1kGAgAZCCAYA1kGAgAZCAgGAfAWAg
gJEEAmAgAWBAUZCBAWBAUoCTkpGQgYFSYCABg4OAgoQ3ggGRUFBQUFBQkZKRkpBQUFBhAmVWW2BA
UYCCgVJgIAGRUFBgQFGAkQOQ81tgAIGQUFtgAWAAgFSQUAOBEBVhAllXYABgAYIBgVSBEBUVYQFY
V/5bkGAAUmAgYAAgkGAEAgFgAIKBVIEQFRVhAXVX/luQYABSYCBgACCQYAQCAWAAggFgAJBUkGEB
AAqQBHP//////////////////////////xaBYAABYABhAQAKgVSBc///////////////////////
////AhkWkINz//////////////////////////8WAheQVVBgAYIBVIFgAQFVYAKCAWAAkFSQYQEA
CpAEYP8WgWACAWAAYQEACoFUgWD/AhkWkIMVFQIXkFVQYAOCAYFgAwGQgFRgAYFgARYVYQEAAgMW
YAKQBGECSJKRkGEEvlZbUJBQUICAYAEBkVBQYQE2VlthAmFhBJJWW1BQVltgAGCAYEBRkIEBYEBS
gIZz//////////////////////////8WgVJgIAGFgVJgIAGEFRWBUmAgAYOBUlBgA2AAggFRgWAA
AWAAYQEACoFUgXP//////////////////////////wIZFpCDc///////////////////////////
FgIXkFVQYCCCAVGBYAEBVWBAggFRgWACAWAAYQEACoFUgWD/AhkWkIMVFQIXkFVQYGCCAVGBYAMB
kIBRkGAgAZBhAzCSkZBhBUVWW1CQUFBgAWAAM3P//////////////////////////xZz////////
//////////////////8WgVJgIAGQgVJgIAFgACBgAJBUkGEBAAqQBGD/FhVhBH9XYABgA5CAYAGB
VAGAglWAkVBQkGABggOQYABSYCBgACCQYAQCAWAAkJGSkJGQkVBgAIIBYACQVJBhAQAKkARz////
//////////////////////8WgWAAAWAAYQEACoFUgXP//////////////////////////wIZFpCD
c///////////////////////////FgIXkFVQYAGCAVSBYAEBVWACggFgAJBUkGEBAAqQBGD/FoFg
AgFgAGEBAAqBVIFg/wIZFpCDFRUCF5BVUGADggGBYAMBkIBUYAGBYAEWFWEBAAIDFmACkARhBHqS
kZBhBL5WW1BQUFBbYAFgAIBUkFADkFCUk1BQUFBWW2AAgIBUkFAQFRUVYQSmV2AAgP1bYACAVICR
kGABkANhBLuRkGEFxVZbUFZbgoBUYAGBYAEWFWEBAAIDFmACkASQYABSYCBgACCQYB8BYCCQBIEB
koJgHxBhBPdXgFSFVWEFNFZbgoABYAEBhVWCFWEFNFdgAFJgIGAAIJFgHwFgIJAEggFbgoERFWEF
M1eCVIJVkWABAZGQYAEBkGEFGFZbW1CQUGEFQZGQYQX3VltQkFZbgoBUYAGBYAEWFWEBAAIDFmAC
kASQYABSYCBgACCQYB8BYCCQBIEBkoJgHxBhBYZXgFFg/xkWg4ABF4VVYQW0VluCgAFgAQGFVYIV
YQW0V5GCAVuCgREVYQWzV4JRglWRYCABkZBgAQGQYQWYVltbUJBQYQXBkZBhBfdWW1CQVluBVIGD
VYGBERVhBfJXYAQCgWAEAoNgAFJgIGAAIJGCAZEBYQXxkZBhBhxWW1tQUFBWW2EGGZGQW4CCERVh
BhVXYACBYACQVVBgAQFhBf1WW1CQVluQVlthBouRkFuAghEVYQaHV2AAgIIBYABhAQAKgVSQc///
////////////////////////AhkWkFVgAYIBYACQVWACggFgAGEBAAqBVJBg/wIZFpBVYAOCAWAA
YQZ+kZBhBo5WW1BgBAFhBiJWW1CQVluQVltQgFRgAYFgARYVYQEAAgMWYAKQBGAAglWAYB8QYQa0
V1BhBtNWW2AfAWAgkASQYABSYCBgACCQgQGQYQbSkZBhBfdWW1tQVgChZWJ6enIwWCAbe61E3sWJ
0c6/B9JA0mzBEzjnj+NdskoxZ3jjn6YVtwAp

Installation steps are unclear

The installation steps say To install the python dependencies, run these commands:, but the commands need to be run on a git clone of the rattle repository, and not on a random path. We should add a bit of text to make that clear.

Storage location recovery

The API should support storage location recovery at specific blocks and annotate the disassembly.

Optimize PHI nodes

We don't optimize PHI nodes.

A funny example:

python3 rattle.py --input inputs/0x1b0db6198bab2e573c62f209d32f99ad4c483dee.evm.bytecode

Outputs these blocks:

<SSA::Block offset:0x1ad>
   %126 = PHI(%89, %65)
   %129 = PHI(#61, #61)
   %72 = ISZERO(%126)
   JUMPI(#200, %72)

<SSA::Block offset:0x200>
   %128 = PHI(#61, %129, #61, #61, #61)
   JUMP(%128)

%128 should not be a PHI node at all, it should be #61.

No such file or directory: 'open'

I tried to get rattle running (Linux 4.17.12-arch1-1-ARCH x86_64 GNU/Linux) and got FileNotFoundError: [Errno 2] No such file or directory: 'open': 'open'. Which open is used for rattle?

Also, as a side note: I had to fix the dot path from /usr/local/bin/dot to /usr/bin/dot, as this is where my dot is.
Thanks

Recovery unit tests

Collect a bunch of solidity contracts, make a recovery test harness, and use them as recovery tests.

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.