{"id":37138874,"url":"https://github.com/evilsocket/evmdis","last_synced_at":"2026-01-14T16:00:51.417Z","repository":{"id":57695275,"uuid":"489352815","full_name":"evilsocket/evmdis","owner":"evilsocket","description":"EVM disassembler","archived":false,"fork":true,"pushed_at":"2022-05-06T13:15:44.000Z","size":57,"stargazers_count":6,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-06-20T10:19:08.272Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"Arachnid/evmdis","license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/evilsocket.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-05-06T12:50:52.000Z","updated_at":"2024-06-20T10:19:08.272Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/evilsocket/evmdis","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/evilsocket/evmdis","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evilsocket%2Fevmdis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evilsocket%2Fevmdis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evilsocket%2Fevmdis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evilsocket%2Fevmdis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evilsocket","download_url":"https://codeload.github.com/evilsocket/evmdis/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evilsocket%2Fevmdis/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28425596,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T15:24:48.085Z","status":"ssl_error","status_checked_at":"2026-01-14T15:23:41.940Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-14T16:00:45.553Z","updated_at":"2026-01-14T16:00:51.356Z","avatar_url":"https://github.com/evilsocket.png","language":"Go","readme":"# evmdis\nevmdis is an EVM disassembler. It performs static analysis on the bytecode to provide a higher level of abstraction for the bytecode than raw EVM operations.\n\nFeatures include:\n - Separates bytecode into basic blocks.\n - Jump target analysis, assigning labels to jump targets and replacing addresses with label names.\n - Composes individual operations into compound expressions where possible.\n - Provides insight into the state of the stack at the start of each block.\n \n## Example\nThe following contract, compiled with `solc --optimize`:\n\n    contract Test {\n        function double(uint a) returns (uint) {\n            return multiply(a, 2);\n        }\n    \n        function triple(uint a) returns (uint) {\n            return multiply(a, 3);\n        }\n    \n        function multiply(uint a, uint b) internal returns (uint) {\n            return a * b;\n        }\n    }\n\nProduces the following disassembly:\n\n    # Stack: []\n    0x4 MSTORE(0x40, 0x60)\n    0xD PUSH(CALLDATALOAD(0x0) / 0x2 ** 0xE0)\n    0x13    DUP1\n    0x17    JUMPI(:label0, POP() == 0xEEE97206)\n\n    # Stack: [@0xD]\n    0x18    DUP1\n    0x21    JUMPI(:label2, 0xF40A049D == POP())\n\n    # Stack: [@0xD]\n    0x25    JUMP(0x2)\n\n    :label0\n    # Stack: [@0xD]\n    0x2A    JUMPI(0x2, CALLVALUE())\n\n    # Stack: [@0xD]\n    0x2B    PUSH(:label3)\n    0x2F    PUSH(CALLDATALOAD(0x4))\n    0x30    PUSH(0x0)\n    0x32    PUSH(:label4)\n    0x34    DUP3\n    0x35    PUSH(0x2)\n\n    :label1\n    # Stack: [[0x3 | 0x2] [@0x44 | @0x2F] [:label4 | :label4] [0x0 | 0x0] [@0x44 | @0x2F] [:label3 | :label3] @0xD]\n    0x38    PUSH(POP() * POP())\n    0x39    SWAP1\n    0x3A    JUMP(POP())\n\n    :label2\n    # Stack: [@0xD]\n    0x3F    JUMPI(0x2, CALLVALUE())\n\n    # Stack: [@0xD]\n    0x40    PUSH(:label3)\n    0x44    PUSH(CALLDATALOAD(0x4))\n    0x45    PUSH(0x0)\n    0x47    PUSH(:label4)\n    0x49    DUP3\n    0x4A    PUSH(0x3)\n    0x4E    JUMP(:label1)\n\n    :label3\n    # Stack: [@0x38 @0xD]\n    0x50    PUSH(0x40)\n    0x52    DUP1\n    0x53    PUSH(MLOAD(POP()))\n    0x54    SWAP2\n    0x55    DUP3\n    0x56    MSTORE(POP(), POP())\n    0x57    PUSH(MLOAD(POP()))\n    0x58    SWAP1\n    0x59    DUP2\n    0x5A    SWAP1\n    0x60    RETURN(POP(), 0x20 + POP() - POP())\n\n    :label4\n    # Stack: [@0x38 [0x0 | 0x0] [@0x44 | @0x2F] [:label3 | :label3] @0xD]\n    0x62    SWAP3\n    0x63    SWAP2\n    0x64    POP()\n    0x65    POP()\n    0x66    JUMP(POP())\n\n## How it works\n\nevmdis works on the principle of static analysis by abstract execution. Abstract execution is the process of simulating the execution of a program, substituting the 'concrete' values for abstract ones representing some useful property. Done properly, this is guaranteed to terminate (unlike regular execution).\n\nAbstract execution is implemented in abstract.go. Callers provide an `EvmState` object that represents the current state of execution for the analysis in question, with an `Advance` method that performs some execution before returning zero or more new states. `EvmState` implementations must be hashable, since they're used as keys in a Go map.\n\nAbstract execution starts with a single initial state. After calling Advance, each of the output states is compared to a map keeping track of all previously seen states. If the output state is not in the map, it is added to the map and to a stack of pending states. The procedure then pops a pending state off the stack and repeats until the stack of pending states is empty.\n\nFor example, evmdis performs reaching definition analysis. The goal of this is to generate, for each instruction that produces output, a list of all the places that the output is consumed. It does this by simulating execution of the code, replacing actual stack values with the address of the operation that generated them. Each time we encounter an instruction, we take the top elements of the current stack, and union each element with a set of previous definitions we've seen. The abstract execution semantics ensure that we continue executing for as long as we keep encountering new arrangements of the execution stack.\n\n## Analyses\n\nevmdis implements a number of different analyses, each building on the others. Only some of these require abstract execution.\n\nEach analysis annotates instructions or basic blocks (described below) with objects that provide additional data about the code.\n\n### Parsing and basic block creation\n\nFirst, the code is parsed and split up into basic blocks. A basic block is a series of sequential EVM operations that do not contain any control flow (jumps in or out). Each basic block may optionally start with a JUMPDEST, and may optionally end with a JUMP or JUMPI; these operations will never occur inside a block. The sequential nature of basic blocks makes them useful building blocks for analysis.\n\n### Reaching analysis\n\nNext, we perform reaching definition analysis on the code, as described above in \"How it works\". This produces a `ReachingDefinition` annotation on each reachable basic block and each reachable instruction. A `ReachingDefinition` is a list of sets of `InstructionPointer`s, pointing to the source of each definition that reaches the given argument.\n\n`ReachingDefinition` annotations on instructions have the same number of elements as the opcode has input arguments. `ReachingDefinition` annotations on basic blocks have elements for every stack slot that can be statically determined to be always present.\n\n### Reaches analysis\n\nReaches analysis is the inverse of reaching definition analysis; for each instruction it annotates all the locations that its output reaches. This step does not require symbolic execution; it simply iterates over the reaching definition analysis and inverts it. This produces a `ReachesDefinition` annotation on each instruction. A `ReachesDefinition` is a list of instruction pointers.\n\n### Jump target creation\n\nThis step finds all PUSH instructions whose output are consumed exclusively by JUMP or JUMPI instructions, and converts them to symbolic jump targets, inserting jump targets at the beginning of the appropriate basic blocks.\n\nRelevant PUSH instructions are annotated with an `Expression` that is an instance of `JumpLabel`, and relevant basic blocks are annotated with the same `JumpLabel`.\n\n### Expression construction\n\nExpression construction iterates over each basic block, identifying operations that are consumed only at a single location, constructing composite expressions for them. For instance, `PUSH1 3 PUSH1 1 PUSH1 2 ADD MUL` is rewritten to the expression `(1 + 2) * 3`. POP operations are elided when possible, and explicitly included as annotations where not. DUP and SWAP operations are eliminated where possible, and adjusted to show the correct number of stack slots when 'lifting' removes elements from the (virtual) stack.\n\nEach instruction that is not part of a subexpression is annotated with an `Expression` instance.\n\n## Building\nRetrieve the evmdis source. For example:\n\n    go get github.com/Arachnid/evmdis\n\nBuild and install evmdis to $GOPATH/bin:\n\n    go install github.com/Arachnid/evmdis/evmdis\n\nSanity check, assuming $GOPATH/bin is in your $PATH:\n\n    evmdis -h","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevilsocket%2Fevmdis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevilsocket%2Fevmdis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevilsocket%2Fevmdis/lists"}