Классификация контрактов является краеугольным камнем бирж, кошельков, браузеров блокчейнов, платформ анализа данных и т. д.
Написано: Fourteen Jun
В области смарт-контрактов «Ethereum Virtual Machine EVM» и ее алгоритмы и структуры данных являются первыми принципами.
Эта статья начинается с того, почему контракты должны быть классифицированы, и комбинирует, с какими злонамеренными атаками может столкнуться каждый сценарий, и, наконец, дает набор относительно безопасных алгоритмов анализа классификации контрактов.
Хотя техническое содержание относительно велико, его также можно использовать в качестве материала для чтения для различных дискуссий, давая представление о темном лесу игр между децентрализованными системами.
**1. Почему контракты следует классифицировать? **
Поскольку это так важно, можно сказать, что это краеугольный камень Dapps, таких как биржи, кошельки, браузеры блокчейна и платформы анализа данных!
Причина, по которой транзакция является переводом ERC20, заключается в том, что его поведение соответствует стандарту ERC20, по крайней мере:
Статус транзакции — успех
Адрес «Кому» — это контракт, соответствующий стандарту ERC20.
Вызывается функция Transfer, которая характеризуется тем, что первые 4 цифры транзакции CallData равны 0xa9059cbb
После выполнения на адрес To отправляется событие Transfer
Если классификация неверна, поведение транзакции будет неверно оценено
Основываясь на поведении транзакции, можно ли точно классифицировать адрес Кому, это приведет к совершенно другим выводам в оценке его CallData. Для Dapp передача информации в цепочке и за ее пределами сильно зависит от мониторинга событий транзакций, и одному и тому же коду события можно доверять только в том случае, если он отправляется в контракте, который соответствует стандартам.
Если классификация неверна, транзакция по ошибке попадет в черную дыру
Если пользователь переводит Токен в определенный контракт, если в контракте нет предустановленного функционального метода для передачи Токенов, средства будут заблокированы так же, как при сжигании, и их нельзя будет контролировать.
И теперь, когда большое количество проектов начали добавлять встроенную поддержку кошелька, неизбежно управление кошельками для пользователей.Необходимо классифицировать последние развернутые контракты из цепочки в реальном времени в любое время, могут ли они соответствовать стандарты активов.
Параграф 1 для расширенного чтения: [Толкование контракта] CryptoPunk — это самый ранний в мире децентрализованный торговый рынок NFT.
**2. Каковы риски классификации? **
Сеть — это место, где нет ни идентичности, ни верховенства права.Вы не можете остановить обычную транзакцию, даже если она злонамеренная.
Он может быть волком, притворяющимся бабушкой, совершая большинство действий, которые вы ожидаете от бабушки, но с целью проникнуть в дом и ограбить.
заявляют о стандарте, но на самом деле могут не соответствовать
Распространенным методом классификации является прямое использование стандарта EIP-165 для определения того, поддерживает ли адрес ERC20 и т. д. Конечно, это эффективный метод, но в конце концов договор контролируется другой стороной, поэтому заявление может быть подделано ведь.
Стандартный запрос 165 — это просто метод предотвращения перевода средств в черные дыры с наименьшей стоимостью в ограниченных кодах операций в цепочке.
Вот почему, когда мы анализировали NFT ранее, мы специально упомянули, что в стандарте будет метод SafeTransferFrom, где Safe относится к использованию стандарта 165 для определения того, что другая сторона имеет возможность передавать NFT.
Параграф 2.2 для расширенного чтения: [Интерпретация исходного кода] Что такое NFT, который вы купили?
Только начиная с байт-кода контракта, выполняя статический анализ на уровне исходного кода и исходя из ожидаемого поведения контракта, он может быть более точным.
3. Разработка схемы классификации контрактов
Далее мы систематически проанализируем общий план, отметив, что нашей целью являются два основных показателя «точность» и «эффективность».
Вы должны знать, что даже если направление правильное, путь до другой стороны океана не ясен.Первой остановкой для анализа байт-кода является получение кода.
**3.1 Как получить код? **
С точки зрения цепочки есть метод getCode, RPC, который может получить байткод с адреса, указанного в цепочке, и прочитать его очень быстро, так как codeHash помещается в структуру аккаунта EVM. .. в самом верху.
Но этот метод равносилен получению одного только определенного адреса.Хотите еще больше повысить точность и эффективность?
Если это транзакция развертывания контракта, как получить развернутый код сразу после его выполнения или даже когда он все еще находится в пуле памяти?
Если транзакция находится в режиме фабрики контрактов, есть ли исходный код в Calldata транзакции?
В конце концов, мой способ состоит в том, чтобы классифицировать в решетоподобном режиме.
Для транзакций, не развернутых по контракту, напрямую используйте getCode для получения задействованных адресов для классификации.
Для последних транзакций мемпула отфильтруйте транзакции, адрес которых пуст, а CallData — это исходный код с помощью конструктора.
Для транзакции режима фабрики контрактов, поскольку контракт, развернутый контрактом, может быть повторно использован для вызова других контрактов для выполнения развертывания, он будет рекурсивно анализировать подтранзакции транзакции и записывать каждый вызов, тип которого CREATE. или СОЗДАТЬ2 .
Когда я сделал демонстрационную реализацию, я обнаружил, что, к счастью, версия rpc сейчас относительно высока, потому что самая сложная часть всего процесса — это как рекурсивно найти вызов указанного типа при выполнении 3. Метод нижнего уровня — восстанавливать контекст через опкод.Я опешил!
К счастью, в текущей версии geth есть метод debug_traceTransaction, который может помочь отсортировать контекстную информацию каждого вызова в коде операции кода операции и отсортировать основные поля.
В итоге можно получить исходные байт-коды различных режимов развертывания (прямое развертывание, одиночное развертывание в фабричном режиме, пакетное развертывание в фабричном режиме).
**3.2 Как классифицировать по коду? **
Самый простой, но небезопасный способ — напрямую сопоставить код со строкой.На примере ERC20 стандарту соответствует функция
После имени функции это сигнатура функции. Как упоминалось в предыдущем анализе, транзакция зависит от сопоставления первых 4 цифр callData, чтобы найти целевую функцию. Дальнейшее чтение:
Следовательно, подписи этих 6 функций должны храниться в байт-коде контракта.
Конечно, этот способ очень быстрый и можно найти все 6, но небезопасный фактор в том, что если я воспользуюсь контрактом солидности и спроектирую переменную со значением хранилища 0x18160ddd, то он подумает, что у меня есть эта функция.
3.3, Повышение точности 1- декомпиляция
Еще один точный метод — декомпилировать Opcode! Декомпиляция — это процесс преобразования полученных байт-кодов в коды операций, а более продвинутая декомпиляция — преобразование их в псевдокоды, что более удобно для чтения человеком.На этот раз нам это не нужно.Метод декомпиляции указан в приложении на конец статьи.
Мы можем явно найти функцию, сигнатура функции будет выполняться опкодом PUSH4, поэтому дальнейший метод — извлечь содержимое после PUSH4 из полного текста и сопоставить его со стандартом функции.
Я также провел простой эксперимент с производительностью, и я должен сказать, что язык Go очень эффективен, и для декомпиляции 1 Вт требуется всего 220 мс.
Далее будет несколько сложно.
3.4. Повышение точности 2 – поиск блоков кода
Приведенный выше уровень точности был улучшен, но этого недостаточно, потому что это полнотекстовый поиск PUSH4, потому что мы все еще можем создать переменную типа byte4, которая также вызовет команду PUSH4.
Когда заморачивался, думал о реализации каких-то опенсорсных проектов.ETL это инструмент чтения данных по цепочке для анализа.Он будет анализировать передачу ERC20 и 721 в отдельные таблицы,поэтому должен иметь возможность классифицировать контракты.
После анализа можно обнаружить, что он основан на классификации кодовых блоков и обрабатывает только первые основные_блоки [0] Инструкция push4 в
** Возникает вопрос, как точно оценить кодовый блок **
Концепция блока кода исходит из двух последовательных опкодов REVERT + JUMPDEST, и здесь необходимы два последовательных опкода, потому что в интервале опкода всего селектора функций, если функций слишком много, появится логика перелистывания страниц Затем также появится команда JUMPDEST.
3.5. Повышение точности 3-найти селектор функций
Функция селектора функций состоит в том, чтобы прочитать первые 4 байта Calldata транзакции и сопоставить их с сигнатурой контрактной функции, заданной в коде, и помочь инструкции перейти к ячейке памяти, указанной методом функции.
Давайте попробуем минимальное фиктивное выполнение
Эта часть является селектором *store(uint 256) и *retrieve() двух функций, а подпись может быть рассчитана как 2e64cec1, 6057361d.
После декомпиляции вы получите следующую строку кода операции, которая, можно сказать, разделена на две части.
первая часть:
В компиляторе только часть контракта, посвященная селектору функций, получит содержимое callData, что означает получение сигнатуры вызова функции ее CallData, как показано на рисунке ниже.
Мы можем увидеть эффект, моделируя изменение пула памяти EVM.
Вторая часть:
Процесс оценки того, соответствует ли он значению селектора
Передать 4-байтовую сигнатуру функции (0x2e64cec1) функции retrieve() в стек,
Код операции EQ извлекает 2 переменные из области стека, а именно 0x2e64cec1 и 0x6057361d, и проверяет, равны ли они
PUSH2 передает в стек 2 байта данных (0x003b здесь, 59 в десятичной системе) В области стека находится программный счетчик, который указывает позицию следующей команды выполнения в байт-коде. Здесь мы устанавливаем 59, потому что именно здесь начинается байт-код retrieve().
JUMPI расшифровывается как "Перейти к, если...", он извлекает 2 значения из стека в качестве входных данных, и если условие истинно, счетчик программ будет обновлен до 59.
Вот как EVM определяет расположение байт-кода функции, которую необходимо выполнить, на основе вызова функции в контракте.
На самом деле это просто набор операторов «если» для каждой функции в контракте и того, куда они переходят.
4. Резюме схемы
В общем кратко так
Каждый адрес контракта может получить развернутый байт-код через rpcgetcode или debug_traceTransaction, используя виртуальную машину и библиотеку ASM в GO, и получить опкод после декомпиляции.
В принципе работы EVM контракт будет иметь следующие характеристики
Используйте два последовательных кода операции REVERT+JUMPDEST в качестве различения блоков кода.
Контракт должен иметь функцию селектора функций, и эта функция также должна быть в первом кодовом блоке.
В селекторе функций все методы функций используют PUSH4 в качестве кода операции,
В коде операции, включенном в селектор, будут непрерывные PUSH1 00;CALLDATALOAD;PUSH1 e0;SHR;DUP1, основной функцией является загрузка данных callDate и выполнение операций смещения, а другой синтаксис не будет генерироваться
Соответствующая сигнатура функции определена в eip, и есть обязательные и необязательные четкие инструкции
4.1, доказательство уникальности
На данный момент мы можем сказать, что мы в основном достигли высокоэффективного и высокоточного метода анализа контрактов.Конечно, поскольку мы так долго были строгими, мы могли бы быть более строгими.В приведенной выше схеме мы использовал REVER+JUMPDEST, чтобы блоки кода различались, и комбинировал неизбежную загрузку и смещение CallDate, чтобы сделать уникальное суждение.Существует ли, что я могу использовать контракт Solidity для реализации аналогичной последовательности кода операции?
Я провел контрольный эксперимент.Хотя есть методы получения CallData типа msg.sig с уровня грамматики солидности, методы реализации опкода после компиляции разные.
5. Резюме
После столь красноречивого анализа прошло 3 дня.
Хотя это очень дотошно, хотя это может быть каплей в море для контрактов, которые используют byte4, чтобы злонамеренно запутать, соответствуют ли они стандартам в повседневной жизни.
Так что на самом деле окупаемость этих трехдневных инвестиций в анализ очень низкая. Но в бесконечной реке времени вещи с малейшей вероятностью рано или поздно произойдут.
Только с принципом недоверия мы можем идти дальше в мире web3.
Сегодня друг задал мне очень наводящую на размышления тему: каков конечный результат того, чтобы быть отраслевым KOL? Какова ваша бизнес-модель?
Хотя я знаю, что поток технических статей всегда мрачный, но поток не является целью, я надеюсь, что он всегда будет исходным видением:
💡 С точки зрения технологий узнайте о ключевых изменениях в промышленном развитии, поделитесь прошлым опытом и будущими возможностями промышленного развития, а также окажите дифференцированную помощь строителям в новую эпоху.
Приложение
Если вам нужны образцы кодов операций и декомпилированные образцы кодов Go, вы можете получить их, ответив на «Классификация контрактов» в фоновом режиме официального аккаунта.
Зависимая библиотека:
Принципиальный анализ:
Ссылка на исходный код проекта с открытым исходным кодом:
Посмотреть Оригинал
Содержание носит исключительно справочный характер и не является предложением или офертой. Консультации по инвестициям, налогообложению или юридическим вопросам не предоставляются. Более подробную информацию о рисках см. в разделе «Дисклеймер».
Углубленный EVM: риск тривиальной классификации контрактов
Написано: Fourteen Jun
В области смарт-контрактов «Ethereum Virtual Machine EVM» и ее алгоритмы и структуры данных являются первыми принципами.
Эта статья начинается с того, почему контракты должны быть классифицированы, и комбинирует, с какими злонамеренными атаками может столкнуться каждый сценарий, и, наконец, дает набор относительно безопасных алгоритмов анализа классификации контрактов.
Хотя техническое содержание относительно велико, его также можно использовать в качестве материала для чтения для различных дискуссий, давая представление о темном лесу игр между децентрализованными системами.
**1. Почему контракты следует классифицировать? **
Поскольку это так важно, можно сказать, что это краеугольный камень Dapps, таких как биржи, кошельки, браузеры блокчейна и платформы анализа данных!
Причина, по которой транзакция является переводом ERC20, заключается в том, что его поведение соответствует стандарту ERC20, по крайней мере:
Если классификация неверна, поведение транзакции будет неверно оценено
Основываясь на поведении транзакции, можно ли точно классифицировать адрес Кому, это приведет к совершенно другим выводам в оценке его CallData. Для Dapp передача информации в цепочке и за ее пределами сильно зависит от мониторинга событий транзакций, и одному и тому же коду события можно доверять только в том случае, если он отправляется в контракте, который соответствует стандартам.
Если классификация неверна, транзакция по ошибке попадет в черную дыру
Если пользователь переводит Токен в определенный контракт, если в контракте нет предустановленного функционального метода для передачи Токенов, средства будут заблокированы так же, как при сжигании, и их нельзя будет контролировать.
И теперь, когда большое количество проектов начали добавлять встроенную поддержку кошелька, неизбежно управление кошельками для пользователей.Необходимо классифицировать последние развернутые контракты из цепочки в реальном времени в любое время, могут ли они соответствовать стандарты активов.
Параграф 1 для расширенного чтения: [Толкование контракта] CryptoPunk — это самый ранний в мире децентрализованный торговый рынок NFT.
**2. Каковы риски классификации? **
Сеть — это место, где нет ни идентичности, ни верховенства права.Вы не можете остановить обычную транзакцию, даже если она злонамеренная.
Он может быть волком, притворяющимся бабушкой, совершая большинство действий, которые вы ожидаете от бабушки, но с целью проникнуть в дом и ограбить.
заявляют о стандарте, но на самом деле могут не соответствовать
Распространенным методом классификации является прямое использование стандарта EIP-165 для определения того, поддерживает ли адрес ERC20 и т. д. Конечно, это эффективный метод, но в конце концов договор контролируется другой стороной, поэтому заявление может быть подделано ведь.
Стандартный запрос 165 — это просто метод предотвращения перевода средств в черные дыры с наименьшей стоимостью в ограниченных кодах операций в цепочке.
Вот почему, когда мы анализировали NFT ранее, мы специально упомянули, что в стандарте будет метод SafeTransferFrom, где Safe относится к использованию стандарта 165 для определения того, что другая сторона имеет возможность передавать NFT.
Параграф 2.2 для расширенного чтения: [Интерпретация исходного кода] Что такое NFT, который вы купили?
Только начиная с байт-кода контракта, выполняя статический анализ на уровне исходного кода и исходя из ожидаемого поведения контракта, он может быть более точным.
3. Разработка схемы классификации контрактов
Далее мы систематически проанализируем общий план, отметив, что нашей целью являются два основных показателя «точность» и «эффективность».
Вы должны знать, что даже если направление правильное, путь до другой стороны океана не ясен.Первой остановкой для анализа байт-кода является получение кода.
**3.1 Как получить код? **
С точки зрения цепочки есть метод getCode, RPC, который может получить байткод с адреса, указанного в цепочке, и прочитать его очень быстро, так как codeHash помещается в структуру аккаунта EVM. .. в самом верху.
Но этот метод равносилен получению одного только определенного адреса.Хотите еще больше повысить точность и эффективность?
Если это транзакция развертывания контракта, как получить развернутый код сразу после его выполнения или даже когда он все еще находится в пуле памяти?
Если транзакция находится в режиме фабрики контрактов, есть ли исходный код в Calldata транзакции?
В конце концов, мой способ состоит в том, чтобы классифицировать в решетоподобном режиме.
Когда я сделал демонстрационную реализацию, я обнаружил, что, к счастью, версия rpc сейчас относительно высока, потому что самая сложная часть всего процесса — это как рекурсивно найти вызов указанного типа при выполнении 3. Метод нижнего уровня — восстанавливать контекст через опкод.Я опешил!
К счастью, в текущей версии geth есть метод debug_traceTransaction, который может помочь отсортировать контекстную информацию каждого вызова в коде операции кода операции и отсортировать основные поля.
В итоге можно получить исходные байт-коды различных режимов развертывания (прямое развертывание, одиночное развертывание в фабричном режиме, пакетное развертывание в фабричном режиме).
**3.2 Как классифицировать по коду? **
Самый простой, но небезопасный способ — напрямую сопоставить код со строкой.На примере ERC20 стандарту соответствует функция
После имени функции это сигнатура функции. Как упоминалось в предыдущем анализе, транзакция зависит от сопоставления первых 4 цифр callData, чтобы найти целевую функцию. Дальнейшее чтение:
Следовательно, подписи этих 6 функций должны храниться в байт-коде контракта.
Конечно, этот способ очень быстрый и можно найти все 6, но небезопасный фактор в том, что если я воспользуюсь контрактом солидности и спроектирую переменную со значением хранилища 0x18160ddd, то он подумает, что у меня есть эта функция.
3.3, Повышение точности 1- декомпиляция
Еще один точный метод — декомпилировать Opcode! Декомпиляция — это процесс преобразования полученных байт-кодов в коды операций, а более продвинутая декомпиляция — преобразование их в псевдокоды, что более удобно для чтения человеком.На этот раз нам это не нужно.Метод декомпиляции указан в приложении на конец статьи.
Solidity (язык высокого уровня) -> bytecode (байтовый код) -> opcode (код операции)
Мы можем явно найти функцию, сигнатура функции будет выполняться опкодом PUSH4, поэтому дальнейший метод — извлечь содержимое после PUSH4 из полного текста и сопоставить его со стандартом функции.
Я также провел простой эксперимент с производительностью, и я должен сказать, что язык Go очень эффективен, и для декомпиляции 1 Вт требуется всего 220 мс.
Далее будет несколько сложно.
3.4. Повышение точности 2 – поиск блоков кода
Приведенный выше уровень точности был улучшен, но этого недостаточно, потому что это полнотекстовый поиск PUSH4, потому что мы все еще можем создать переменную типа byte4, которая также вызовет команду PUSH4.
Когда заморачивался, думал о реализации каких-то опенсорсных проектов.ETL это инструмент чтения данных по цепочке для анализа.Он будет анализировать передачу ERC20 и 721 в отдельные таблицы,поэтому должен иметь возможность классифицировать контракты.
После анализа можно обнаружить, что он основан на классификации кодовых блоков и обрабатывает только первые основные_блоки [0] Инструкция push4 в
** Возникает вопрос, как точно оценить кодовый блок **
Концепция блока кода исходит из двух последовательных опкодов REVERT + JUMPDEST, и здесь необходимы два последовательных опкода, потому что в интервале опкода всего селектора функций, если функций слишком много, появится логика перелистывания страниц Затем также появится команда JUMPDEST.
3.5. Повышение точности 3-найти селектор функций
Функция селектора функций состоит в том, чтобы прочитать первые 4 байта Calldata транзакции и сопоставить их с сигнатурой контрактной функции, заданной в коде, и помочь инструкции перейти к ячейке памяти, указанной методом функции.
Давайте попробуем минимальное фиктивное выполнение
Эта часть является селектором *store(uint 256) и *retrieve() двух функций, а подпись может быть рассчитана как 2e64cec1, 6057361d.
60003560e01c80632e64cec11461003b5780636057361d1461005957
После декомпиляции вы получите следующую строку кода операции, которая, можно сказать, разделена на две части.
первая часть:
В компиляторе только часть контракта, посвященная селектору функций, получит содержимое callData, что означает получение сигнатуры вызова функции ее CallData, как показано на рисунке ниже.
Мы можем увидеть эффект, моделируя изменение пула памяти EVM.
Вторая часть:
Процесс оценки того, соответствует ли он значению селектора
Вот как EVM определяет расположение байт-кода функции, которую необходимо выполнить, на основе вызова функции в контракте.
На самом деле это просто набор операторов «если» для каждой функции в контракте и того, куда они переходят.
4. Резюме схемы
В общем кратко так
4.1, доказательство уникальности
На данный момент мы можем сказать, что мы в основном достигли высокоэффективного и высокоточного метода анализа контрактов.Конечно, поскольку мы так долго были строгими, мы могли бы быть более строгими.В приведенной выше схеме мы использовал REVER+JUMPDEST, чтобы блоки кода различались, и комбинировал неизбежную загрузку и смещение CallDate, чтобы сделать уникальное суждение.Существует ли, что я могу использовать контракт Solidity для реализации аналогичной последовательности кода операции?
Я провел контрольный эксперимент.Хотя есть методы получения CallData типа msg.sig с уровня грамматики солидности, методы реализации опкода после компиляции разные.
5. Резюме
После столь красноречивого анализа прошло 3 дня.
Хотя это очень дотошно, хотя это может быть каплей в море для контрактов, которые используют byte4, чтобы злонамеренно запутать, соответствуют ли они стандартам в повседневной жизни.
Так что на самом деле окупаемость этих трехдневных инвестиций в анализ очень низкая. Но в бесконечной реке времени вещи с малейшей вероятностью рано или поздно произойдут.
Только с принципом недоверия мы можем идти дальше в мире web3.
Сегодня друг задал мне очень наводящую на размышления тему: каков конечный результат того, чтобы быть отраслевым KOL? Какова ваша бизнес-модель?
Хотя я знаю, что поток технических статей всегда мрачный, но поток не является целью, я надеюсь, что он всегда будет исходным видением:
💡 С точки зрения технологий узнайте о ключевых изменениях в промышленном развитии, поделитесь прошлым опытом и будущими возможностями промышленного развития, а также окажите дифференцированную помощь строителям в новую эпоху.