EVM Bytecode Decompiler: Read Unverified Smart Contracts
The contracts you most need to read are exactly the ones nobody published source for. Scam tokens, freshly deployed attacker contracts, and obfuscated drainers almost never verify their code on a block explorer — which is why an EVM bytecode decompiler belongs in every investigator's toolkit. It takes the raw hex sitting at a contract address and reconstructs Solidity-like pseudo-source a human can actually read, no original code required.
This guide covers the whole territory behind that term: what a bytecode decompiler actually does, the difference between decoding, disassembling, and decompiling, how decompilation works under the hood, how the Lantern engine inside Noxos Intelligence compares with open-source decompilers like heimdall-rs, Panoramix, ethervm.io, and Dedaub — and what to hunt for once you can finally read the code.
What Is an EVM Bytecode Decompiler?
An EVM bytecode decompiler is a tool that takes the compiled code deployed at a contract address — a hex string of opcodes the Ethereum Virtual Machine executes — and works backwards to a readable approximation of the source. Because most EVM contracts are written in Solidity, you will also see the tool called a Solidity bytecode decompiler — same thing, and the output is Solidity-shaped either way. When a developer verifies a contract, a block explorer shows you their original Solidity. When they don't, the bytecode is all that exists on-chain, and a decompiler is the only way to find out what the contract can do.
In investigation work, the unverified case is not the exception; it is the norm. Attackers have no incentive to publish their source. The drainer deployed an hour before a theft, the honeypot token with a hidden blacklist, the middle contract in a laundering chain — every one of them is a wall of hex until you decompile it.
Noxos built its Lantern engine for exactly this case. Lantern accepts raw EVM bytecode, with or without the 0x prefix, up to roughly 200KB, and returns two things: reconstructed pseudo-source that mirrors the structure of the original code, and a plain-English explanation of what the contract is doing — recovered control flow, inferred storage layout, and the intent behind each function. You do not trace opcodes by hand to learn that a function gates an action behind an owner check or moves funds to a fixed address; the report tells you.
Decode, Disassemble, or Decompile Bytecode: What's the Difference?
People who search for how to decode bytecode usually mean one of three different operations. Knowing which one you actually need saves real time, so here is the ladder from shallow to deep.
Decoding: hex to meaning, shallowly
Decoding is translation without interpretation. The classic example is calldata: the first four bytes of a transaction's input are the function selector — the truncated keccak-256 hash of the function's signature. Match those bytes against a public signature database and 0xa9059cbb becomes transfer(address,uint256), with the arguments decoded from the bytes that follow. Decoding also covers splitting constructor code from runtime code and reading the metadata blob the Solidity compiler appends to every contract. Decoding tells you what was called; it says nothing about what the code does with the call.
Disassembly: hex to opcodes
A disassembler converts the hex into the EVM's instruction listing: PUSH1 0x80, MSTORE, CALLDATALOAD, JUMPI, and so on. The mapping is one-to-one and lossless, which makes disassembly the ground truth for any dispute about behavior. It is also unreadable at scale — a contract near the 24KB size limit disassembles into thousands of instructions, and stack machines scatter a single logical statement across dozens of them.
Decompilation: from opcodes to logic
A decompiler goes the rest of the way. It reconstructs functions, branches, loops, and storage variables from the instruction stream and emits pseudo-source that reads like Solidity. Compilation is lossy in reverse — names and comments are gone forever — so the output is an inference, not a recovery. But it is the only representation where a human can answer the questions that matter: what can this contract do, who is allowed to call the sensitive parts, and where does value end up?
How Does an EVM Decompiler Actually Work?
Every serious EVM decompiler — open-source or commercial — runs some version of the same pipeline. Understanding it tells you exactly how far to trust the output.
1. Recover the function dispatcher
Almost every compiled contract begins the same way: load the 4-byte selector from calldata, compare it against a list of hard-coded constants, and jump to the matching function body. A decompiler enumerates those comparisons to recover the contract's full public interface, then checks each selector against public signature databases. Selectors with known preimages come back with real names like withdraw(); the rest stay as raw hex — which is itself a signal, because custom, never-before-seen selectors are common in attack tooling.
2. Rebuild the control-flow graph
EVM jumps take their destination from the stack, not from the instruction itself, so a decompiler must simulate execution to resolve where every JUMP and JUMPI can land. From the resolved jump targets it partitions the code into basic blocks and stitches them into a control-flow graph — the skeleton of every if, for, and require in the output.
3. Turn stack operations into expressions
The EVM is a stack machine: a single comparison might involve a dozen pushes, dups, and swaps. Symbolic analysis tracks those values and collapses them back into nested expressions, so a smear of stack shuffling becomes require(msg.sender == owner) — the line an investigator actually needs to see.
4. Infer the storage layout
Reads and writes go through SLOAD and SSTORE against numbered slots. Fixed slots map to scalar state variables; slots derived through keccak hashing reveal mappings and arrays, such as a balances mapping keyed by address. Recognizing the patterns — an address in a low slot that gates privileged calls is almost always the owner — is how a decompiler labels state meaningfully.
5. Emit pseudo-source
Finally the tool renders the graph and expressions as Solidity-like code. This is why the honest term is pseudo-source: the logic and layout are reconstructed from evidence, while variable names and comments are inferred or synthetic, because the compiler discarded the originals. No bytecode decompiler can hand you back the Solidity file the developer wrote — only what the machine was told to do.
How to Decompile Bytecode: Step by Step
To decompile bytecode you need two things: the bytecode itself and a decompiler. Here is the full path from contract address to readable logic.
- Pull the bytecode. Ask any node for the code at the address with a standard
eth_getCodeJSON-RPC call:
Alternatively, most public block explorers display the deployed bytecode on the contract tab, ready to copy.curl -s -X POST https://YOUR_RPC_ENDPOINT \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"eth_getCode", "params":["0xCONTRACT_ADDRESS","latest"]}' - Check you are not holding a proxy shell. If the result is suspiciously short — an EIP-1167 minimal proxy is around 45 bytes — you are looking at a forwarder, and the logic lives at the implementation address embedded in it or stored in the proxy's implementation slot. Pull the code at that address instead.
- Feed it to the decompiler. In Lantern, paste the hex with or without the
0xprefix; anything up to roughly 200KB is accepted. - Read intent first, lines second. Start with the plain-English explanation to get the shape of the contract, then drop into the pseudo-source for the functions that touch value or access control.
- Check the
fromCacheflag. Lantern hashes every submission with SHA-256 and checks a shared global cache, because identical contracts are redeployed constantly across the ecosystem. A hit returns instantly, the flag tells you the result was previously computed, and every run lands in your persistent personal history so last week's analysis is one click away.
Worked Example: From Hex Blob to Honeypot Logic
A composite drawn from patterns that recur across real cases — details simplified, no real project depicted. A victim asks about a token that pumped for two days and then became unsellable. The contract is unverified: the explorer shows nothing but bytecode.
Decompiled, the dispatcher lists the standard ERC-20 surface — transfer, approve, balanceOf — plus two selectors with no known signature. The pseudo-source for transfer contains the tell: before moving tokens, it checks a mapping keyed by the sender, and reverts unless the sender is flagged in it or is the owner. One of the unknown selectors resolves to an owner-only function that writes that mapping. Translation: everyone can buy, and only addresses the deployer blesses can sell. The plain-English report says exactly that, in one paragraph, without anyone reading a single opcode.
From there the investigation is standard: run a scam-address check on the deployer and its funding wallets, and trace where the ETH raised from victims went. The decompilation is what turned "the chart looks weird" into documented mechanism.
Bytecode Decompilers Compared: Lantern vs Open-Source Tools
The open-source decompiler ecosystem is genuinely good, and for some jobs it is the right answer. Here is the honest landscape as of mid-2026.
| Tool | Type | Output | Best for |
|---|---|---|---|
| heimdall-rs | Open-source Rust CLI | Solidity-like pseudo-source, disassembly, CFGs | Engineers comfortable assembling their own workflow |
| Panoramix | Open-source Python decompiler | Python-flavored pseudocode | Quick reads; it long powered explorer "decompile" buttons |
| ethervm.io | Free in-browser tool | Disassembly plus lower-level decompilation | Instant first look at a contract, zero setup |
| Dedaub | Security firm with a free online decompiler | High-fidelity, research-grade pseudo-source | Deep static analysis by security professionals |
| Lantern (Noxos) | Decompiler inside an investigation platform | Pseudo-source plus a plain-English behavior report | Investigators who need answers and a case trail |
If all you want is a fast disassembly, ethervm.io in a browser tab is hard to beat. If you live in a terminal, heimdall-rs is the bytecode decompiler Solidity engineers tend to reach for first — fast and actively developed. Dedaub's decompiler produces some of the cleanest output in the field for gnarly, optimized bytecode.
Lantern's difference is who it is built for. Open-source decompilers hand pseudo-source to someone who already reads Solidity; Lantern also explains the contract in plain English, so a case officer or a victim can follow the finding. Results are cached globally by content hash and kept in your history, and the decompilation sits in the same workspace as cross-chain fund tracing, address labels, and the transaction simulator — so "what does this contract do" and "where did the money go" are answered in one place, on one case record.
Red Flags to Hunt For in Decompiled Contracts
Once the pseudo-source is in front of you, these are the patterns worth an immediate closer look:
- Hidden mint paths. Any function that increases a balance or total supply outside the constructor — especially owner-gated — can dilute holders at will.
- Transfer gates and blacklists. Conditions inside
transferthat consult a writable mapping are the honeypot signature: buys succeed, sells revert. - Adjustable fee switches. An owner-settable fee with no upper bound is a rug lever — set it to 100% and every sell routes to the deployer.
- Sweep functions. Owner-only functions that transfer the contract's whole token or ETH balance to an arbitrary address.
- Approval harvesting. Code that spends third-party allowances via
transferFromagainst addresses it never received deposits from — then go check your own approvals. - Escape hatches.
selfdestruct,delegatecallto a caller-supplied address, or upgrade hooks that can swap the logic out from under every assumption above.
What a Decompiler Cannot Do
Decompilation is powerful but not magic, and treating its output as gospel will burn you.
- It cannot return the original Solidity. Names, comments, and file structure are gone at compile time. Pseudo-source captures behavior and structure; it is not a line-for-line replica, and no tool that claims otherwise is telling the truth.
- It reads the shell, not the proxy target. If the bytecode belongs to a proxy, the logic that matters lives at the implementation address. Decompile that — and remember an upgradeable proxy can change its behavior after your analysis.
- Optimizers distort structure. Aggressive optimization and via-IR compilation inline, deduplicate, and reorder code, so one original function may appear as several fragments or vice versa.
- It is evidence-supporting, not evidence-final. Confirm what you read by watching real behavior: simulate the transaction before anyone signs, and let on-chain results arbitrate. For matters heading to court, the decompilation is one exhibit inside a properly documented investigation report, not the whole case.
Where Decompilation Fits a Full Investigation
Lantern is the unverified-contract counterpart to verified-source analysis. Start with the smart contract scanner; when it reports no verified source, hand the bytecode to Lantern. In an active incident, decompiling the attacker's contract is one of the first moves — it reveals the exploit mechanism while the anatomy of the exploit is still unfolding and the funds are still traceable.
And if the contract you are staring at has already taken your funds, you do not have to run the case alone: hire a specialist and Noxos investigators will decompile the contract, trace the proceeds, and hand you a court-ready report. Outcomes are never guaranteed — but an unread contract guarantees nothing at all.
FAQ: Decompiling EVM Bytecode
Can EVM bytecode be decompiled back to Solidity?
Not exactly. Compilation discards variable names, comments, and most structure, so no decompiler can recover the original Solidity file. What a good EVM decompiler produces is Solidity-like pseudo-source: correct control flow, recovered function selectors, and inferred storage layout. That is enough to understand what a contract does and who controls it, but treat it as a reconstruction of behavior, not a copy of the original code.
How do I get a contract's bytecode?
Call eth_getCode over JSON-RPC against any node — pass the contract address and "latest" as the block tag, and the node returns the deployed runtime bytecode as a hex string. Alternatively, most public block explorers show the deployed bytecode on the contract tab, where you can copy it directly. Either form pastes straight into a decompiler, with or without the 0x prefix.
What is the difference between decoding and decompiling bytecode?
Decoding is shallow translation: turning hex into opcodes, or matching a transaction's 4-byte function selector against a signature database to name the function being called. Decompiling goes much further — it reconstructs control flow, functions, and storage layout to produce readable pseudo-source. Decode when you need to identify what was called; decompile when you need to understand what the contract actually does.
Is there a free EVM bytecode decompiler?
Yes. heimdall-rs is an open-source Rust toolkit run from the command line, Panoramix is an open-source Python decompiler, ethervm.io offers instant in-browser disassembly and decompilation, and Dedaub provides a free online decompiler aimed at security researchers. Noxos Intelligence's Lantern engine adds a plain-English explanation of the contract's behavior on top of the pseudo-source, built for investigators rather than compiler engineers.
Can I trust decompiled smart contract code?
Trust it to describe behavior, not to be the original source. Decompiled pseudo-source reliably captures control flow, access checks, and where value moves, but variable names are inferred and compiler optimizations can distort structure. For high-stakes decisions, confirm what you read by simulating a transaction against the contract and watching the actual balance changes — on-chain behavior is the final arbiter.
Why are unverified smart contracts a red flag?
Legitimate projects verify their source because transparency costs them nothing and builds trust. Attackers do the opposite: verification would hand analysts their exploit or scam logic, so drainers, honeypots, and laundering contracts stay unverified deliberately. Unverified is not proof of malice — plenty of lazy but honest deploys exist — but combined with fresh deployment and anonymous funding, it earns a decompilation before you interact.
Read the Code Nobody Published
An unverified contract is not a dead end — it is one decompilation away from readable. Paste the bytecode into Lantern and get pseudo-source, storage layout, and a plain-English verdict in the same workspace you trace funds in. See it on the interactive demo, and let the deployer's own opcodes tell you what they chose not to.