rea-reverse

EVM bytecode disassembler: opcodes, selectors and metadata

Paste EVM bytecode to get an address-annotated opcode listing, with the Solidity CBOR metadata trailer decoded separately and the dispatcher function selectors listed. No ABI, RPC or upload needed.

Your bytecode never leaves your browser. The disassembler is a few kilobytes of JavaScript running in a Web Worker on this page. Nothing is uploaded. How to verify this yourself

Whitespace and a leading 0x are ignored. Up to 256 KiB of bytecode.

Hex text or raw bytecode bytes.

Two things to keep in mind

  • This is a linear sweep, not a control-flow analysis: it disassembles bytes in order and does not follow jumps or mark basic blocks. Only the trailing compiler metadata is separated from the code.
  • Selector detection matches the common PUSH4 … EQ dispatcher pattern; binary-search dispatchers, proxies and hand-written assembly may report fewer selectors, or none.

A deployed EVM contract is a string of bytes. Each byte is an opcode, and a handful of opcodes (PUSH1 through PUSH32) carry their operand inline in the bytes that follow. Disassembling the bytecode means walking it one instruction at a time and printing the mnemonic and operand for each, annotated with the byte offset where it lives. That offset listing is what jump targets, debuggers and the dispatcher all refer to.

This tool does that inside your browser. You paste runtime or creation bytecode as hex, or load a file, and the page prints the opcode listing, decodes the compiler metadata trailer separately, and lists the function selectors it finds in the dispatcher. The bytecode never leaves your machine.

What it does

Input. Paste hexadecimal bytecode into the text area. A 0x prefix is optional and whitespace is ignored, so you can paste a copied block as is. You can also load a file containing hex text or the raw bytes. Limit: up to 256 KiB of bytecode (well above the 24 KiB on-chain deployed-code limit, with room for creation code).

Opcode listing. Every instruction is shown as offset: MNEMONIC operand, with the offset as a hexadecimal byte address. PUSH1..PUSH32 show the pushed value; PUSH0 and all other opcodes show just the mnemonic. A byte that is not a defined opcode is shown as 0xXX and marked invalid rather than guessed at. The listing covers opcodes through the Cancun upgrade, including PUSH0, TLOAD/TSTORE, MCOPY, BLOBHASH and BLOBBASEFEE.

Metadata trailer. The Solidity compiler appends a CBOR-encoded metadata block to the end of the runtime code, followed by two bytes giving its length. The tool reads that length, decodes the CBOR map in front of it, and shows it as a separate section rather than disassembling it as code. It decodes the solc version (three bytes, shown as major.minor.patch) and the ipfs, bzzr0 or bzzr1 hash when present. The bytes covered by the trailer are excluded from the opcode listing.

Function selectors. Solidity and Vyper dispatchers compare the first four bytes of the call data against each function’s selector with a PUSH4 … EQ sequence. The tool collects those PUSH4 operands and lists them as 4-byte selectors. To turn selectors into argument types, state mutability and a storage layout, use the dedicated EVM function selector extractor.

You can export the whole result as JSON.

How it works

The disassembler is a small, dependency-free pass written for this page and run in a Web Worker so the page stays responsive. It walks the bytes from offset zero: for each opcode it looks up the mnemonic, and for a PUSH it consumes the next N bytes as the operand and advances past them, which is what keeps the offsets correct (a PUSH operand is data, not the next instruction). The metadata decoder reads the last two bytes as a length, parses the CBOR map immediately before it, and only treats it as metadata if the map parses cleanly and consumes exactly those bytes; otherwise everything is disassembled as code.

How your bytecode stays private

Your bytecode is not uploaded. That follows from how the page is built:

  • The disassembly runs in a Web Worker on your device. There is no WebAssembly and no external library to download; the whole analysis is a few kilobytes of JavaScript served from this site.
  • The worker runs under a Content Security Policy with connect-src 'none': it cannot make any network request at all. The browser blocks it.
  • The only analytics event is disasm_run. It carries success or an error code, whether a metadata trailer was found, and coarse buckets for the instruction count, selector count, input size and duration. It never contains bytecode, selectors or any other content. The full list of events is on the privacy page.
  • The tool page shows no ads.

How to verify this yourself

  1. Open your browser’s developer tools and switch to the Network tab before pasting anything. Run the disassembler and inspect every request. None of them contains your bytecode.
  2. Or load the page, then go offline (turn off Wi-Fi, or tick Offline in the Network tab) and run it. It still works, because nothing needs to leave your machine.

Limitations

  • The listing is a linear sweep, not a control-flow analysis. It disassembles bytes in order. It does not follow jumps, mark basic blocks or tell data apart from code beyond the metadata trailer. A PUSH operand that happens to contain opcode-like bytes is correctly shown as the operand, but constant data embedded elsewhere is still decoded as instructions.
  • Selector detection is a heuristic. It matches the common PUSH4 … EQ dispatcher shape. Binary-search dispatchers, proxies and hand-written assembly may report fewer selectors, or none. Treat the list as a starting point and confirm with the selector extractor.
  • Names are not recovered. A selector is a hash prefix and cannot be reversed. This tool shows the 4-byte value, not a function name.
  • EOF is not special-cased. Bytecode in the EVM Object Format (starting with 0xEF00) is disassembled byte by byte like legacy code; its section structure is not parsed.

FAQ

What is the difference between this and the selector extractor?

This tool shows you the raw opcode listing and decodes the metadata trailer. The EVM function selector extractor runs EVMole to infer argument types, state mutability and a storage layout for each selector. Use the disassembler to read the code, the extractor to recover the interface.

Can I paste creation (init) code?

Yes. The listing will show the constructor, the CODECOPY that lays out the runtime code and a RETURN. The metadata trailer is attached to the runtime code, so for creation code it may be decoded only if the runtime section’s trailer happens to sit at the very end.

Why is a byte shown as 0xXX?

Because that byte is not a defined opcode. On chain it would halt execution as an invalid instruction. It often marks the boundary between code and data, or a newer opcode this table does not know.

Where do I get the bytecode?

From your own build (solc --bin-runtime, or the deployedBytecode/bytecode fields in Hardhat or Foundry artifacts), or from a node with eth_getCode for an address you are allowed to examine. The tool makes no RPC or explorer requests of its own.

Compliance

Use this tool on contracts you wrote, contracts you are authorized to review, or public contracts whose bytecode is published on chain. Recovering a disassembly does not grant any right to the code.