EVM bytecode analyzer: disassemble, decode selectors, read storage
Disassemble Ethereum contract bytecode, resolve function selectors, decode ABI calldata, and read a storage slot the way Solidity packs it.
Open in ctfpalA blockchain challenge usually hands you an address and no source. What is on chain is the runtime bytecode, and everything you need is derivable from it - but only if you can read the two conventions the compiler follows.
The dispatcher tells you the ABI
Every Solidity contract begins with the same shape: load the first four bytes of calldata, and compare them against a list of constants. Those constants are function selectors - the first four bytes of keccak256("transfer(address,uint256)") - so the dispatcher is the ABI, listed in the order the compiler emitted it.
Selectors are looked up against a local table of common signatures. A selector that resolves tells you the name and the argument types; one that does not is either a custom function or a deliberately obscured one, and either way its position in the dispatcher tells you it exists.
Storage is packed, and the packing is the puzzle
- Value types are laid out in declaration order from slot 0, and several small ones share a slot: three
uint64s and aboolfit in one 32-byte word, right-aligned, in the order declared. Reading a slot as a single number when it holds four fields is the most common way to misread contract state. - A dynamic array at slot `p` stores its length in
pand its elements fromkeccak256(p)onwards. - A mapping at slot `p` stores the value for key
katkeccak256(k . p)- which is why "private" mapping values are readable by anyone who can compute a hash.
private in Solidity is a compile-time visibility rule and not a secret. Every slot is public on chain, and a challenge whose flag is in a private variable is asking whether you know that.
Reading calldata
Calldata is the selector followed by 32-byte-aligned arguments, with dynamic types stored as an offset to a length-prefixed region later in the buffer. Decoding it against a signature turns a wall of hex into the arguments somebody actually passed - which, for a transaction that drained a contract, is the whole answer.