Wie kann man einen Smart Contract dekompilieren?

Auf der Blockchain kann ich den Code eines Vertrags überprüfen und die EVM-Opcodes sehen. Gibt es eine Möglichkeit, dies zu dekompilieren und wieder in (Solidity-) Quellcode zu konvertieren?

Wie können Sie die EVM-Opcodes sehen?

Antworten (7)

Eine Rückkompilierung in den ursprünglichen Quellcode ist unmöglich, da alle Variablennamen, Typnamen und sogar Funktionsnamen entfernt werden. Es könnte technisch möglich sein, zu einem Quellcode zu gelangen, der dem ursprünglichen Quellcode ähnelt, aber sehr kompliziert ist, insbesondere wenn der Optimierer während der Kompilierung verwendet wurde. Ich kenne keine Tools, die mehr tun, als Bytecode in Opcodes umzuwandeln.

Da Verträge auf ihren eigenen Code zugreifen und den Code somit zur Speicherung von Daten (ab-)verwenden können, ist nicht immer klar, ob ein Teil des Codes tatsächlich als Code oder nur als reine Daten verwendet wird und ob es sinnvoll ist, ihn zu dekompilieren . Es ist rechnerisch unentscheidbar, ob ein Teil des Codes erreichbar ist oder nicht.

Beachten Sie, dass es keinen dedizierten Bereich zum Speichern fester Daten zur Erstellungszeit (wie Nachschlagetabellen usw.) gibt. Abgesehen vom Vertragscode wäre es auch möglich, die Daten im Speicher zu speichern, aber das wäre viel teurer, daher ist das Einfügen solcher Daten in den Code eigentlich eine gängige Sache.

Wenn ich mir also zum Beispiel diesen Vertrag etherchain.org/account/… ansehe , der behauptet, hier ein 50/50-Coinflip zu sein ( medium.com/@kpcb_edge/… ): gibt es eine Möglichkeit sicherzustellen, dass er effektiv tut, was er sagt er tut ? Wie können Leute Geld an Verträge senden, wenn sie den Code nicht „lesen“ können?
@euri10-Ersteller können den Quellcode bereitstellen, und indem Sie ihn mit derselben Version des Compilers erstellen, können Sie überprüfen, ob er mit demselben Bytecode kompiliert wird. Einige Blockchain-Explorer, wie ether.camp, bieten diese Funktionalität integriert an.
Tolle Infos. Nur um die allgemeine Erreichbarkeit zu verdeutlichen ist unentscheidbar, aber viele, wenn nicht die praktischsten spezifischen Erreichbarkeitsprobleme sind entscheidbar. Beachten Sie, dass Linters auf ungenutzte Funktionen hinweisen.

Es gibt jetzt ein Projekt Porosity https://github.com/comaeio/porosity Es ist auch in die Quorum-Toolchain integriert https://www.coindesk.com/first-ethereum-decompiler-launches-jp-morgan-quorum-integration/

Ich habe dieses Tool ausprobiert. Es ist noch nicht stabil. github.com/comaeio/porosity/issues/30
JEB Decompiler liefert gute Ergebnisse, es ist ein Profi-Tool (nicht kostenlos), aber sie haben eine herunterladbare Demo hier pnfsoftware.com/blog/ethereum-smart-contract-decompiler
@MarcelFalliere Das ist ein interessantes Tool. Vielen Dank.

Es ist unmöglich, zum Solidity-Code zurückzukehren. Sie könnten den Bytecode einfach in Opcodes decodieren.

Schauen Sie sich dieses Beispiel an: https://etherscan.io/opcode-tool?a=0x9e1b57fc92eba6434251a8458811c32690f32c45

aber das Problem sollte nicht als erledigt angesehen werden, wenn Sie mit Opcodes fertig sind. Was der Autor des Beitrags wollte, ist der Quellcode.

Im Allgemeinen ist es, wie andere Benutzer anmerkten, in der Praxis nicht möglich, den ursprünglichen Quellcode zurückzuerhalten. Theoretisch sollten jedoch sowohl kompilierte als auch Quellanwendungen genau dieselbe Ausgabe erzeugen (dh dieselbe Semantik haben), sodass es möglich sein sollte, ein Programm in Quellcodedarstellung zu erhalten, das genau dasselbe tut wie der Bytecode. Es wurden andere Decompiler wie Porosity erwähnt. Es gibt auch Decompiler (zu einer Zwischendarstellung) namens Mythril, EthIR und Vandal. Als Benutzer im Jahr 2018 ist der vollständigste verfügbare Decompiler https://www.contract-library.com . Es ist kein eigenständiges Tool, kann aber die meisten Verträge dekompilieren, die sich derzeit im Ethereum-Mainnet und anderen Testnetzen befinden.

Und das ist der Vertrag, den Badr Bellaj vorgeschlagen hat: https://contract-library.com/contracts/Ethereum/0x9e1b57fc92eba6434251a8458811c32690f32c45

Wie Sie sehen können, werden sogar einige der Funktionsnamen automatisch abgeleitet, basierend auf dem Wissen, das beim Versuch, vergangene Verträge zu verstehen, erworben wurde. Insgesamt sind Decompiler für Ethereum derzeit nicht so konzipiert, dass ihre Ausgabe für den menschlichen Konsum optimiert ist, sie sind jedoch für den Konsum durch andere Maschinen (Algorithmen) optimiert, die Sicherheitslücken finden können.

Ich glaube nicht, dass Mythil eine Dekompilierung durchführt. Es kann Code zerlegen und ein baumähnliches Kontrollflussdiagramm anzeigen (es erkennt keine Schleifen in diesem Diagramm), aber ich denke, das ist weit entfernt von dem, was ein Decompiler tut.
Das ist richtig. Ich habe jedes Werkzeug eingeschlossen, das die Abstraktionsebene erhöht. In diesem Fall tun dies sowohl Mythril als auch Vandal in unterschiedlichem Maße, bieten jedoch keine Ansicht des Codes auf Quellebene.

Liste moderner Tools (2022 und darüber hinaus)

  1. Etherscans Bytecode-zu-Opcode-Disassembler .
  2. Der Online-Solidity-Decompiler von EtherVM .

Dies ist keine vollständige Antwort, sondern beschreibt einen Ansatz, für den man einen Decompiler für Solidity schreiben könnte, der möglicherweise besser ist als viele der vorhandenen Decompiler.

Es stützt sich auf Erfahrungen mit einem Python-Decompiler, den ich entwickelt und gewartet habe .

Chriseths ausgezeichnete akzeptierte Antwort beschreibt den allgemeinen Fall und geht davon aus, dass die Dekompilierung in allen Situationen über den gesamten Code hinweg funktionieren soll.

Aber oft ist dies möglicherweise nicht der Fall. Hier sind einige Szenarien, in denen Sie möglicherweise besser abschneiden können als im allgemeinen Fall:

  1. Angenommen, der Code, den ich dekompilieren möchte, ist eine Codevariante, für die ich den Quellcode zur Verfügung habe. (Dies wird auch in Neville Grechs Antwort erwähnt.) Vielleicht wurde der Bytecode/Ewasm aus einer älteren oder neueren Version der Quelle generiert, die ich habe. Hier kann ich darauf zurückgreifen, dass ich viele der Variablennamen und deren Typen bereits kenne, nur dass es im Code zu geringfügigen Abweichungen kommen kann. Selbst wenn eine Variable "err" im Quellcode, die ich habe, in "error" im verlorenen Quellcode geändert wird, der bei der Kompilierung verwendet wurde, ist es nicht so schlimm, den Variablennamen "err" zu verwenden, solange die Typen gleich sind. obwohl es "Fehler" war. Es ist wahrscheinlich ein hilfreicherer Name als ein willkürlich erfundener Name.

  2. Solc führt vor der yul-basierten Optimierung eine Stack-Optimierung und einige lokale Optimierungen durch, jedoch nicht die störenderen Arten der "globalen" Optimierung. Selbst mit Optimierung kann es möglich sein, Operationsfolgen nach Mustern abzugleichen, um größere Strukturen wie assertund zu erhalten require. In Python verwende ich einen J. Earley-Parser, der cool ist, weil er es ermöglicht, Grammatiken auf mehrdeutige Weise anzugeben. Das heißt, eine Folge von Opcodes könnte mit einer Grammatik übereinstimmen, mehreren unterschiedlichen Konstrukten auf hoher Ebene. Aber das ist in Ordnung, denn das ist in der Tat die Natur des Spiels. Bei der Dekompilierung sollten Sie nicht erwarten, etwas zu erhalten, das genau die Quelle ist (obwohl das passieren kann). Stattdessen sollten Sie etwas Gleichwertiges bekommen.

Wenn Sie zusätzlich die bei der Kompilierung verwendete Solc-Version und/oder die Optimierungsstufe kennen, kann dies weiter dazu beitragen, möglicherweise ausgegebene Muster einzugrenzen und somit die Grammatik zu verkürzen und weniger zweideutig zu machen. Wenn die Solc-Version vor 0.5 oder so liegt, wissen Sie, dass Yul-Optimierung keine Sache ist.

Ich bin mir sicher, dass es in Solc überall Boilerplate-Code gibt. Zum Beispiel bei Vertragsbeginn. Dieser Code kann abgeglichen werden. Es gibt Boilerplate-Code, den Solc verwendet, um zu sehen, ob der Index in einem dynamischen Array akzeptabel ist. Wenn dieses Codemuster eindeutig ist, können wir möglicherweise schlussfolgern, dass ein dynamisches Array verwendet wird. In ähnlicher Weise kann Code, der ein "neues" ausgibt, in die Mustererkennung fallen.

Hinweis: Warum schreibe ich, dass Sie auf Opcodes und nicht auf Anweisungen (dh Opcode- und Operandenpaar) übereinstimmen? Dies liegt daran, dass Sie beim Musterabgleich ein wenig abstrahieren möchten. die Verwendung des Opcodes für die Anweisung tut dies. In den Fällen, in denen Operandeninformationen enthalten sein sollten, ändert sich im Python-Decompiler der Opcode, um dieses zusätzliche Abstraktionselement widerzuspiegeln. Es gibt nichts, was vorschreibt, dass Sie vorhandene EVM-Opcodes abgleichen müssen. Sie können neue Opcodes erfinden, Opcodes einfügen, die die Grenze der Steuerstruktur angeben, oder einige Opcode-Namen ändern, um den Musterabgleich zu unterstützen.

  1. Manchmal sind Sie nicht daran interessiert, den gesamten Code zu dekompilieren, sondern nur einen Teil davon.

Ich habe den Solidity-Decompiler hier gefunden https://www.ethervm.io/decompile