Проблема самоизменяющегося кода¶
Самоизменяющийся код — это программа или её фрагмент, который в процессе своего выполнения модифицирует собственные инструкции. В отличие от обычных программ, где код статичен, а изменяются только данные, самоизменяющийся код активно перезаписывает машинные команды или байт-код в памяти. Данная техника существует с первых дней вычислительной техники и применяется в таких областях, как сжатие исполняемых файлов, защита от взлома, создание полиморфных вирусов и в некоторых нишевых методологиях программирования.
¶История
Истоки самоизменяющегося кода лежат в архитектуре ранних компьютеров, где память для данных и инструкций была общей (гарвардская архитектура с общей шиной). В 1940–1950-х годах программисты использовали модификацию кода для экономии памяти и ускорения вычислений. Например, в компьютере EDSAC (1949) программы могли изменять собственные адреса, что позволяло организовывать циклы без дополнительных регистров индексации.
С развитием конвейерной обработки и кэш-памяти в 1970–1980-х годах самоизменение стало проблемой: процессоры, предсказывающие ветвления и кэширующие инструкции, могли выполнять устаревшие версии команд. Это привело к тому, что в большинстве современных процессоров (x86, ARM) самоизменяющийся код требует обязательной синхронизации кэша инструкций (например, инструкция cpuid или вызов системных функций типа __clear_cache в Linux).
¶Технические аспекты
¶Механизмы реализации
Самоизменяющийся код создаётся несколькими способами:
- Прямая запись в область кода: программа получает указатель на собственный сегмент инструкций и записывает туда новые байты (через операции с памятью).
- Генерация кода на лету (JIT-компиляция): программа создаёт машинный код в буфере данных, а затем передаёт управление на этот буфер. Этот метод не является самоизменением в строгом смысле (исходный код не меняется), но часто рассматривается вместе с ним.
- Перехват и патчинг: загрузка внешней библиотеки, которая подменяет адреса функций в таблице импорта или непосредственно в теле вызывающей функции.
¶Ограничения современных систем
Современные операционные системы и аппаратура накладывают серьёзные ограничения:
- W^X (Write XOR Execute): политика безопасности, при которой страница памяти не может быть одновременно записываемой и исполняемой. Реализована в Windows (DEP), Linux (NX-бит) и macOS. Для самоизменения требуется переключение атрибутов страниц через системные вызовы (
mprotect,VirtualProtect), что замедляет работу и повышает риск обнаружения. - Контроль целостности: антивирусы и системы защиты (например, PatchGuard в Windows) отслеживают попытки модификации системного кода.
- Кэш инструкций: на архитектурах со слабой моделью памяти (ARM) требуется явная инструкция
ISB(Instruction Synchronization Barrier) для сброса конвейера.
¶Применение
¶Сжатие и упаковка исполняемых файлов
Упаковщики (packers) и протекторы (protectors), такие как UPX, ASPack, Themida, используют самоизменяющийся код для распаковки собственного тела в памяти. Программа начинается с небольшого распаковщика, который восстанавливает оригинальный код и затем передаёт ему управление. Это позволяет уменьшить размер файла на диске и затруднить статический анализ.
¶Защита от отладки и реверс-инжиниринга
Полиморфные генераторы (например, в вирусах типа Storm Worm) создают каждый раз новый вариант кода, который функционально идентичен, но отличается по байтовой последовательности. Самоизменение используется для запутывания логики: команды расшифровываются только в момент выполнения, а после работы снова шифруются. Это затрудняет сигнатурный поиск и статический анализ.
¶JIT-компиляция и виртуальные машины
Высокопроизводительные интерпретаторы (Java HotSpot, V8 JavaScript, .NET JIT) генерируют машинный код на лету. Хотя формально это не самоизменение исходного кода, принцип модификации исполняемых инструкций в памяти идентичен. JIT-компиляция позволяет оптимизировать код под конкретный процессор и профиль выполнения.
¶Обфускация и метапрограммирование
В языках низкого уровня (C, ассемблер) самоизменение иногда применяется для реализации полиморфных алгоритмов, например, для быстрого переключения между несколькими версиями функции без ветвлений. В некоторых исследовательских проектах (например, в области искусственного интеллекта) самоизменяющиеся программы рассматриваются как модель эволюционных вычислений.
¶Критика и риски
Самоизменяющийся код критикуется за:
- Нечитаемость: программы становятся сложными для сопровождения и отладки. Отладчики не могут корректно отображать изменяющиеся инструкции.
- Небезопасность: техника часто используется вредоносным ПО для обхода антивирусов. Это привело к тому, что легитимные самоизменяющиеся программы (например, упаковщики) автоматически помечаются антивирусами как подозрительные.
- Низкая производительность: на современных процессорах переключение атрибутов страниц и сброс кэша инструкций требуют значительных накладных расходов. В некоторых случаях самоизменение выполняется в 10–100 раз медленнее эквивалентного статического кода.
¶Самоизменяющийся код в России
В российской практике техника используется преимущественно в двух контекстах. Первый — защита программного обеспечения от несанкционированного копирования: российские разработчики (например, StarForce, Protect Software) применяют самоизменяющиеся модули для привязки к оборудованию. Второй — судебная компьютерная экспертиза: при анализе вредоносных программ, созданных с использованием полиморфных генераторов, эксперты сталкиваются с необходимостью динамической трассировки, так как статический анализ невозможен. Российское законодательство (ст. 273 УК РФ) квалифицирует создание самоизменяющегося вредоносного кода как неправомерный доступ к компьютерной информации, что делает данную технику предметом правового регулирования.
¶См. также
- Полиморфный код
- JIT-компиляция
- Обфускация (программирование)
- Упаковщик исполняемых файлов
¶Источники
- А. В. Столяров, «Введение в архитектуру ЭВМ», МГУ, 2015.
- Д. Кнут, «Искусство программирования», т. 1, раздел о саммодифицирующихся программах.
- Intel 64 and IA-32 Architectures Software Developer’s Manual, Vol. 3A, раздел о self-modifying code.
- Документация Microsoft по DEP и защите памяти Windows.
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →

