Workspace of 9 crates (noxis, noxis-core, noxis-classfile, noxis-analysis, noxis-passes, noxis-runtime, noxis-jar, noxis-verify, noxis-structure-check). AGPL-3.0-only license, Rust 2024 edition, unsafe_code denied.
9 KiB
Что улучшим: стратегия и приоритеты
Материал собран из info/evo-improvements.md (план после разбора EvoVis) и
info/evo-weaknesses.md (провалы). Здесь — что мы берём, в каком порядке
и что осознанно не делаем.
Стратегия в одном абзаце
Максимум защиты при минимуме риска сломать рантайм. Дешёвые техники, дающие 80% результата, включаются по умолчанию; дорогие и опасные — включаются только после того, как для них есть верификатор. Каждая техника имеет измеримый критерий «сработала/не сработала», иначе это не защита, а мнение.
P0 — базовый уровень (дёшево, снимает главные утечки)
| пункт | что это | пасс | статус |
|---|---|---|---|
| A1 | переименование всех символов: классы, поля, методы, локальные переменные, параметры, record-компоненты, enum-константы, SourceFile |
Rename | ✅ готово |
| A2 | вычистить LineNumberTable/LocalVariableTable/SourceFile/InnerClasses/Signature/MethodParameters |
DebugInfo | план |
| A3 | никаких сигнатурных имён у защитного кода, защитный код смешан с обычным | Rename + Noise | ✅ / план |
| A4 | обфусцировать весь архив, включая ресурсы, mixin-JSON, access widener, service loader'ы | Resources | план |
| — | маппинг в отчёт (иначе не читаем свои же stack trace) | Rename | ✅ готово |
Это самый дешёвый блок и одновременно самый большой утечка в разобранном
образце: оригинальные SourceFile у 160 классов, имена полей и методов,
каталог модулей в атрибутах.
P1 — строки и константы
| пункт | что это | пасс | статус |
|---|---|---|---|
| B1 | ключ на строку + ротация 3–5 схем + MAC + уникальный nonce | Strings | ✅ схемы готовы |
| B2 | вывод ключа в рантайме, а не константа в вызове | Strings + генератор декодера | ⛔ блокер |
| B3 | константы — не тождества, а вычисления, разнесённые по блокам | Constants | план |
| B4 | ложная отладочная информация: чужие имена переменных и строк | DebugInfo | план |
B2 — главное отличие от разобранного образца: у него ключ был константным выражением в вызове и расшифровывался статически, без JVM. Мастер-секрет должен собираться в рантайме из нескольких мест. Это требует сначала собрать класс-декодер (P2) — потому и блокер, а не «сделаем потом».
P2 — контрольный поток
| пункт | что это | статус |
|---|---|---|
| C1 | несколько схем флаттенинга вместо одной, с мешаниной внутри метода | план |
| C2 | верификатор обязателен: ошибка CFG = VerifyError |
план |
| C3 | реальный объём ≠ раздувание: бюджет на размер и время | план |
Приоритет здесь строго подчинён: C2 раньше C1. Включать Flow без
проверки кадров StackMapTable — это гарантированный битый jar.
Подробности: ../stack.md §3.
P3 — измеримость (метрики, без которых ничего не доказано)
Обязательный блок, иначе фраза «обфускация есть» ничего не означает:
- Утечки имён. Список эталонных осмысленных идентификаторов;
если хоть один остался в
strings/константах — тест падает. - Читаемость декомпилята. Прогон JADX/CFR → доля распознанных структур (try/catch, switch, циклы), доля классов с восстановленными именами.
- Противник. Минимальный скрипт-деобфускатор (свёртка констант, regex-паттерны). Если он снимает больше порога — техника провалена. Красный список паттернов держим в репозитории.
- Семантика. Эталонные программы до и после — 100% совпадение.
- Бюджеты. Размер ≤ N%, время исполнения ≤ M%, отдельно — бюджет раскрытия строк (кэш, чтобы не платить на каждый вызов).
- Стабильность между сборками. Имена и схемы меняются от билда к билду: у разобранного образца шифр был один на все версии — готовое окно для обучения по частотам.
Это блок noxis-verify: красные паттерны + java -Xverify:all +
метрики. Единственное место, где «нам кажется защищённым» заменяется
цифрой.
P4 — долгий горизонт (пока не делаем)
| пункт | что это | почему не сразу |
|---|---|---|
| D1 | маленький VM/interpreter для ценных кусков | цена окупается только на ключевом коде |
| D2 | split-function / раскрываемое по шагам тело | режет обычный профилировщик, сложная отладка |
| D3 | мягкий анти-анализ в рантайме | требует своего нативного компонента |
| D4 | честный anti-tamper, а не «зашейрь ключ» | целая инженерная задача, не пасс |
| E | собственный нативный/Rust-цель вместо JVM | другой продукт, не наша цель |
D1 — явно ограничен: включать только для действительно ценных функций, остальное оправдания не имеет. E — отдельный продукт; если он когда-нибудь понадобится, наш IR как раз делает его возможным (те же пассы, другой writer).
Что мы добавили сверх исходного плана
- Структурный гейт при компиляции. Лимиты «250 строк / 4 файла»
гоняются в
build.rs— см.../README.md. Без этого план P0–P3 превращается в один гигантский файл через месяц. - Собственный IR с метками. Исходный план предполагал работу поверх
готового парсера.
Insn::Mark(Label)убирает пересчёт смещений из всех пассов — это меняет цену каждой техники, меняющей CFG. - Детерминированный PRNG с доменным разделением. Без этого пункт «стабильность между сборками» невозможно проверить тестом.
- Keep как отдельный крейт (
noxis-analysis), а не флаг CLI. Рефлексия, JNI, сериализация и entrypoint'ы — это анализ иерархии, а не настройка, которую надо помнить руками.
Порядок выполнения
Смотрите ../../todo.md. Кратко:
P0 DebugInfo + Resources → снимает главные утечки, почти бесплатно
P1 Strings (B2) + Constants → ключ выводится, схемы ротируются
P1 backend (ristretto) + frames
P2 Flow (C1) после верификатора
P3 метрики (F) и красные паттерны