Как можно декомпилировать смарт-контракт?

В блокчейне я могу проверить код контракта и увидеть коды операций EVM. Есть ли способ декомпилировать это и преобразовать обратно в исходный код (Solidity)?

как вы можете увидеть коды операций EVM?

Ответы (7)

Компиляция обратно в исходный исходный код невозможна, потому что все имена переменных, имена типов и даже имена функций удаляются. Технически возможно получить некоторый исходный код, похожий на исходный исходный код, но это очень сложно, особенно когда во время компиляции использовался оптимизатор. Я не знаю каких-либо инструментов, которые делают больше, чем преобразование байт-кода в коды операций.

Поскольку контракты могут обращаться к своему собственному коду и, таким образом, (аб)использовать код для хранения данных, не всегда ясно, используется ли какая-то часть кода на самом деле как код или только как простые данные, и имеет ли смысл пытаться ее декомпилировать. . С вычислительной точки зрения невозможно решить, достижим ли какой-то фрагмент кода или нет.

Обратите внимание, что нет специальной области для хранения фиксированных данных времени создания (таких как таблицы поиска и т. д.). Помимо кода контракта, можно было бы хранить данные и в хранилище, но это было бы намного дороже, поэтому размещение таких данных в коде — обычное дело.

поэтому, если я посмотрю, например, на этот контракт etherchain.org/account/… , который претендует на койнфлип 50/50 здесь ( medium.com/@kpcb_edge/… ): есть ли способ убедиться, что он эффективно выполняет то, что он говорит ? он делает ? как люди могут отправлять деньги на контракты, если они не могут «читать» код?
@euri10 Создатели могут предоставить исходный код, и, создав его с помощью той же версии компилятора, вы сможете убедиться, что он компилируется в тот же байт-код. Некоторые обозреватели блокчейнов, такие как ether.camp, предоставляют эту встроенную функциональность.
Отличная информация. Просто поясню, что общая достижимость неразрешима, но многие, если не самые практические, конкретные проблемы достижимости разрешимы. Учтите, что линтеры укажут на неиспользуемые функции.

Сейчас есть проект Porosity https://github.com/comaeio/porosity . Он также интегрирован в набор инструментов Quorum https://www.coindesk.com/first-ethereum-decompiler-launches-jp-morgan-quorum-integration/

Я пробовал это средство. Он пока не стабилен. github.com/comaeio/porosity/issues/30
JEB Decompiler дает хорошие результаты, это профессиональный инструмент (не бесплатный), но у них есть загружаемая демонстрация здесь pnfsoftware.com/blog/ethereum-smart-contract-decompiler
@MarcelFalliere Это интересный инструмент. Спасибо.

вернуться обратно к солидному коду невозможно. вы можете просто декодировать байт-код в коды операций.

посмотрите на этот пример: https://etherscan.io/opcode-tool?a=0x9e1b57fc92eba6434251a8458811c32690f32c45

но проблема не должна считаться выполненной, когда вы закончите с кодами операций. то, что хотел автор поста, это исходный код.

В целом, как отмечали другие пользователи, на практике невозможно вернуть исходный код. Теоретически, однако, как скомпилированные, так и исходные приложения должны производить одинаковый вывод (т. е. иметь одинаковую семантику), поэтому должна быть возможность получить программу в представлении исходного кода, которая делает то же самое, что и байт-код. Люди упоминали другие декомпиляторы, такие как Porosity. Также существуют декомпиляторы (до промежуточного представления) Mythril, EthIR и Vandal. Как пользователь в 2018 году, наиболее полный доступный декомпилятор — https://www.contract-library.com . Это не отдельный инструмент, но он может декомпилировать большинство контрактов, которые в настоящее время находятся в основной сети Ethereum и других тестовых сетях.

И это контракт, предложенный Бадром Белладжем: https://contract-library.com/contracts/Ethereum/0x9e1b57fc92eba6434251a8458811c32690f32c45

Как видите, даже некоторые имена функций выводятся автоматически на основе знаний, полученных при попытке понять прошлые контракты. В целом декомпиляторы для Ethereum в настоящее время не оптимизированы для использования людьми, однако они оптимизированы для использования другими машинами (алгоритмами), которые могут находить уязвимости в системе безопасности.

Я не думаю, что Mythil делает какую-либо декомпиляцию. Он может дизассемблировать код и показывать древовидный граф потока управления (он не обнаруживает циклов на этом графе), но я думаю, что это далеко не то, что делает декомпилятор.
Это правильно. Я включал любой инструмент, повышающий уровень абстракции. В данном случае и Mythril, и Vandal делают это в разной степени, но не представляют код на уровне исходного кода.

Список современных инструментов (2022 г. и далее)

  1. Байт- код Etherscan в дизассемблер кода операции .
  2. Онлайн-декомпилятор Solidity от EtherVM .

Это не полный ответ, но описывает подход, для которого можно написать декомпилятор для Solidity, который может быть лучше, чем многие из существующих декомпиляторов.

Он основан на опыте работы с декомпилятором Python, который я разработал и поддерживаю .

отличный принятый ответ chriseth описывает общий случай и предполагает, что вы хотите, чтобы декомпиляция работала во всех ситуациях по всему коду.

Но во многих случаях это может быть не так. Вот несколько сценариев, в которых вы можете добиться большего успеха, чем в общем случае:

  1. Предположим, что код, который я хочу декомпилировать, представляет собой вариант кода, исходный код которого у меня есть. (Это также упоминается в ответе Невилла Греча.) Возможно, байт-код/ewasm был сгенерирован из более старой или новой версии исходного кода, который у меня есть. Здесь я могу опираться на то, что многие имена переменных и их типы мне уже известны, просто в коде могут быть небольшие отличия. Даже если переменная «ошибка» в исходном коде, который у меня есть, изменена на «ошибка» в утерянном исходном коде, который использовался при компиляции, пока типы одинаковы, не так уж плохо использовать имя переменной «ошибка» хотя это была "ошибка". Скорее всего, оно даст более полезное имя, чем произвольно сфабрикованное имя.

  2. solc до оптимизации на основе yul выполняет оптимизацию стека и некоторую локальную оптимизацию, но не более разрушительные виды «глобальной» оптимизации. Даже с оптимизацией можно сопоставить последовательности операций с образцом для получения более крупных структур, таких как assertи require. В Python я использую синтаксический анализатор J. Earley, который классный, потому что он позволяет давать грамматику неоднозначным образом. То есть последовательность кодов операций может соответствовать грамматике, нескольким различным конструкциям высокого уровня. Но это нормально, потому что такова природа игры. При декомпиляции вы не должны ожидать получить что-то, что является точно исходным кодом (хотя это может случиться). Вместо этого вы должны получить что-то эквивалентное.

Кроме того, если вы знаете версию solc, которая использовалась при компиляции и/или уровне оптимизации, это может дополнительно помочь сузить шаблоны, которые могут быть созданы, и, следовательно, сократить грамматику и сделать ее менее двусмысленной. Если версия solc до 0.5 или около того, вы знаете, что оптимизация yul не имеет значения.

Я уверен, что в solc везде есть шаблонный код. Например, в начале контрактов. Этот код можно сопоставить. Существует шаблонный код, который solc использует для проверки приемлемости индекса в динамическом массиве. Если этот шаблон кода уникален, то мы можем сделать вывод, что используется динамический массив. Точно так же код, который выдает «новый», может попасть в распознавание сопоставления с образцом.

Примечание: почему я пишу, что вы сопоставляете коды операций, а не инструкции (т.е. пару кодов операций и операндов)? Это потому, что если вы выполняете сопоставление с образцом, вы хотите немного абстрагироваться; использование кода операции для инструкции делает это. В тех случаях, когда необходимо включить информацию об операнде, декомпилятор Python изменяет код операции, чтобы отразить эту дополнительную часть абстракции. Нет ничего, что предписывало бы вам сопоставлять существующие коды операций EVM. Вы можете создать новые коды операций, вставить коды операций, которые могут указывать на границу структуры управления, или изменить имена некоторых кодов операций, чтобы облегчить сопоставление с образцом.

  1. Иногда вам не интересно декомпилировать весь код, а только его часть.

Я нашел декомпилятор Solidity здесь https://www.ethervm.io/decompile