Clear Sky Science · ru
Стек‑ориентированная статическая сегментация и мутирование бинарников WebAssembly для генерации корректных суб‑бинарников
Почему важно разбивать код на более мелкие части
Современные веб‑приложения всё активнее используют WebAssembly — компактный машиноподобный язык, который позволяет программам на C, C++ или Rust работать с почти нативной скоростью в браузерах, облаках и даже в небольших встроенных устройствах. По мере того как всё больше систем запускают WebAssembly, нужны безопасные и тщательные способы тестирования этих сред выполнения на предмет ошибок и уязвимостей. Но реальные WebAssembly‑программы громоздки, сложны и тяжело собрать в достаточном разнообразии. В этой статье предлагается новый метод вырезания существующих WebAssembly‑программ на множество небольших, автономных мини‑программ с последующей осмысленной модификацией. В результате получается богатый набор корректных компактных тестов, которые могут значительно эффективнее нагружать движки WebAssembly по сравнению с существующими инструментами.

От одной большой программы к множеству маленьких
Авторы исходят из наблюдения, что простая генерация случайного WebAssembly‑кода почти никогда не работает: язык строго проверяется, особенно в части использования стека для временных значений. Вместо того чтобы писать код с нуля, они берут существующий «базовый» бинарник WebAssembly и применяют технику, называемую программной сегментацией (program slicing). Срез — это сокращённая версия программы, оставляющая только те фрагменты кода, которые влияют на выбранную точку интереса, например на конкретную инструкцию внутри функции. Прослеживая назад потоки данных, использование памяти и управление потоком, метод извлекает компактный фрагмент, который по‑прежнему «что‑то значит» в вычислительном смысле, а не является случайным шумом.
Сохранение невидимого стека в балансе
Программы WebAssembly опираются на строгую дисциплину стека: каждая инструкция снимает и помещает значения, а структурированные блоки и ветвления должны оставлять стек в точно ожидаемой форме по завершении. Наивное вырезание частей программы почти всегда нарушает эту дисциплину, делая результат некорректным. Ранние работы исправляли срезы, дополняя их фиксированными шаблонами фиктивных инструкций, что делало их исполняемыми, но ограничивало разнообразие. В этой статье предложён специальный алгоритм коррекции баланса стека. Он анализирует поток управления внутри каждого среза, находит места, где ветвления или окончания блоков нарушают ожидаемую форму стека, и вставляет подобранные последовательности инструкций, которые удаляют лишние значения и синтезируют новые правильных типов. Эти небольшие «гаджеты» восстанавливают корректность, позволяя при этом использовать гораздо более разнообразные последовательности инструкций, чем простое заполнение шаблонами.
Построение целых мини‑программ с контролируемой сложностью
Исправленный срез остаётся лишь телом функции, и эта функция может вызывать другие функции или зависеть от модульных компонентов, таких как глобальные переменные и линейная память. Поэтому авторы расширяют метод, чтобы собирать завершённые исполняемые мини‑модули. Начиная с случайно выбранной функции входа, они последовательно вырезают и корректируют любые вызываемые функции до заданной пользователем глубины вызовов, которая контролирует, сколько уровней вызовов сохраняется. За пределами этой глубины вызовы заменяются короткими заместителями, имитирующими правильное число аргументов и результатов без подтягивания дополнительного кода. Система также воссоздаёт окружающие секции модуля WebAssembly — типы, таблицы, память и т. п., — чтобы каждый сгенерированный бинарник был автономным и мог быть напрямую запущен стандартными инструментами и рантаймами.

Добавление разнообразия через аккуратное мутирование
Даже при сегментации многие сгенерированные бинарники всё ещё напоминают исходную программу. Чтобы расширить покрытие, авторы вводят фазу мутирования, которая работает в обратном направлении внутри каждой функции. Для инструкций, потребляющих входы, алгоритм случайно выбирает новый тип результата, находит заменяющие инструкции, производящие этот тип, а затем рекурсивно мутирует более ранние инструкции, обеспечивающие их входные данные, чтобы вся цепочка оставалась согласованной. Это сохраняет корректность стека при изменении структуры вычислений. По сравнению с набором реальных WebAssembly‑программ, мутированные бинарники содержат гораздо больше различных паттернов инструкций и активнее используют редко встречающиеся возможности, такие как векторные операции, что важно для всестороннего тестирования реализации движков WebAssembly.
Что показали эксперименты
Для проверки подхода авторы реализовали около 17 000 строк Python, покрывающих почти полный стандарт WebAssembly 2.0. Используя большой публичный набор из тысяч реальных бинарников, они показали, что их техника регулярно умеет сокращать программы до доли исходного количества инструкций — часто ниже 40% от крупнейших базовых размеров — сохраняя при этом корректность в более чем 99% случаев при включённом мутировании. Метод работает быстро, обычно значительно быстрее секунды на генерацию бинарника умеренного размера, и заметно увеличивает как разнообразие типов инструкций, так и число уникальных последовательностей инструкций. Практически это означает, что тестировщики и исследователи безопасности могут превратить скромный корпус WebAssembly‑программ в большой, разнообразный набор небольших корректных бинарников, идеальных для фаззинга, дифференциального тестирования и регрессионного тестирования рантаймов WebAssembly.
Как это помогает защищать WebAssembly
В простых словах, статья описывает умный «рафайнер кода» для WebAssembly: он разрубает большие программы на множество небольших осмысленных кусочков, автоматически ремонтирует их, чтобы они соблюдали строгие правила языка, а затем перестраивает их, чтобы исследовать редкоиспользуемые уголки набора инструкций. Поскольку эти мини‑программы остаются реалистичными, но компактными, их можно быстро и в больших количествах запускать, что повышает шансы обнаружить тонкие ошибки или уязвимости в ПО, выполняющем WebAssembly. По мере распространения WebAssembly из браузеров в облака и устройства, такой систематический подход к генерации корректных и разнообразных тестовых бинарников становится важным инструментом для поддержания устойчивости и безопасности этой экосистемы.
Цитирование: Choi, G., Jeon, S. Stack-based static WebAssembly binary slicing and mutation for generating valid sub-binaries. Sci Rep 16, 10910 (2026). https://doi.org/10.1038/s41598-026-45837-y
Ключевые слова: тестирование WebAssembly, программная сегментация, мутирование бинарников, безопасность ПО, проверка во время выполнения