Содержание статьи
- Контекст
- Инструменты
- Реверсим
- Получаем байт-код
- Дизассемблируем
- Находим диспетчер функций
- Превращаем селекторы обратно в названия функций
- Восстанавливаем логику
- Декомпилируем в псевдокод Solidity
- Читаем логику
- Разбор реального случая
- Truebit. Ущерб — 26,4 миллиона долларов, баг в расчете цены
- Взлом MEV-бота: 15 тысяч долларов украли из-за отсутствия аутентификации
Контракт развернули в сети Ethereum в 2021 году, и несколько лет он не привлекал внимания. При этом его так и не верифицировали на Etherscan: авторы не загрузили исходник на Solidity, поэтому посмотреть можно было только сырой байт‑код, который исполняет EVM. Если ты хотел понять, что делает этот контракт, путь был один — реверсить.
По оценкам аналитиков Chainalysis, за первые шесть месяцев 2026 года из неверифицированных смарт‑контрактов похитили как минимум 36,7 миллиона долларов. Если код не верифицирован, это еще не значит, что контракт вредоносный. Но без доступа к исходникам на языке высокого уровня проводить аудит и разбираться в бизнес‑логике гораздо сложнее.
В этой статье посмотрим, как выглядит байт‑код EVM, какими инструментами его анализировать и как применять этот навык при аудите смарт‑контрактов или расследовании инцидентов.
Контекст
Ethereum Virtual Machine (EVM) — стековая машина: в ней нет регистров. Смарт‑контракт на Solidity, Vyper или другом языке для EVM компилируется в последовательность опкодов — однобайтовых инструкций вроде PUSH1, SSTORE, JUMPI или CALL. Каждая инструкция расходует газ и выполняет определенную операцию: например, меняет стек, память или хранилище (storage).
Стоимость в газе может быть фиксированной или зависеть от параметров операции и состояния EVM. Набор инструкций включает около 140 опкодов. Они нужны для вычислений, сравнений, побитовых операций, хеширования, работы со стеком, памятью и хранилищем, а также взаимодействия с другими контрактами.
Есть два важных момента, которые отличают эту задачу от реверса обычного бинарника. Во‑первых, здесь нет ни имен функций, ни отладочных символов, ни самого понятия функции на уровне байт‑кода. Контракт — это кусок кода с таблицей переходов в самом начале.
Во‑вторых, все публично. После деплоя рантайм‑байт‑код контракта навсегда остается в открытом доступе: кто угодно может получить его с любой ноды или через блок‑эксплорер, даже если автор не публиковал исходники.
Верификация — загрузка исходного кода на высокоуровневом языке (например, Solidity) на Etherscan или аналогичный сервис и проверка его соответствия байт‑коду контракта — дело добровольное. На компиляцию и работоспособность контракта она не влияет.
Контракты остаются неверифицированными по разным причинам, и не все они связаны с противоправной деятельностью. Минимальные прокси и фабрики контрактов позволяют деплоить тысячи почти идентичных контрактов — верифицировать каждый экземпляр непрактично.
Старые контракты, задеплоенные годы назад и с тех пор заброшенные командой, часто не верифицированы просто потому, что во время их разработки и деплоя эта практика еще не устоялась. А некоторые контракты намеренно оставляют неверифицированными, чтобы затруднить анализ перед рагпулом или скрыть от пользователей бэкдор в коде.
Контракт Truebit как раз относится к категории заброшенных. На момент взлома ему было пять лет, на его счету лежали реальные деньги, но понять его бизнес‑логику без реверса было невозможно. При этом трогать то, что работает, казалось бессмысленным.
Именно поэтому реверс‑инжиниринг байт‑кода важен и для Red Team, и для Blue Team. Ресерчеры используют реверс для аудита неверифицированных контрактов, разбора эксплоитов и расследования инцидентов — ведь во время атак хакеры не публикуют исходный код на Solidity. Аудиторам реверс помогает проверять безопасность кода.
Инструменты
Для начала тебе понадобится немного — и все это бесплатно:
- Обозреватель блоков (Etherscan или аналог для твоей сети) — чтобы получить байт‑код задеплоенного контракта прямо на вкладке Contract.
- evm.codes — интерактивный справочник опкодов EVM и песочница для разбора байт‑кода прямо в браузере. Здесь ты можешь узнать, что делает каждый опкод, и вставить сырой байт‑код, чтобы сразу увидеть результат дизассемблирования.
- Декомпилятор. Heimdall-rs — бесплатный инструмент на Rust для анализа неверифицированных контрактов. Он дизассемблирует байт‑код, декодирует calldata без ABI, строит граф контракта и выдает декомпилированный код в стиле Solidity. Декомпилятор Dedaub — бесплатная альтернатива с веб‑интерфейсом. Он принимает адрес контракта или сырой байт‑код и возвращает читаемый код на нескольких уровнях абстракции.
- Опционально — Ghidra с расширением Mothra для EVM, если работаешь с крупными контрактами и тебе нужен полноценный графический дизассемблер с перекрестными ссылками. Работу с ним подробно разбирали на Devcon 2025.
Реверсим
Получаем байт-код
У каждого задеплоенного контракта есть два важных блока байт‑кода: код создания (creation code) и рантайм‑код. Первый выполняется один раз при деплое: формирует и возвращает рантайм‑код.
Продолжение доступно только участникам
Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».
Присоединяйся к сообществу «Xakep.ru»!
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
