crytic / rattle Goto Github PK
View Code? Open in Web Editor NEWevm binary static analysis
Home Page: https://www.trailofbits.com/presentations/rattle/
evm binary static analysis
Home Page: https://www.trailofbits.com/presentations/rattle/
I am wondering what differences between slither & rattle, from a development and functional point of view?
Thanks a lot!
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)
We need to identify and extract inline function calls for proper recovery.
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.
➜ 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
.
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.
Symbolic variables should keep track of who defined them and where they're used.
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);
}
}
Add support for grabbing a constructor off the blockchain and its current storage state
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.
Reimplement the method extraction from the c++ rattle
Rattle and ethersplay both fail to recover the control flow graph of the fomo3d contract. Analysis never finishes.
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;;;;;;;"
}
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
Identify which security checkers apply from slither and port them to rattle
Rattle should output a precooked file for graph disassembly
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
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
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.
The API should support storage location recovery at specific blocks and annotate the disassembly.
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.
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
Collect a bunch of solidity contracts, make a recovery test harness, and use them as recovery tests.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.