# Что улучшим: стратегия и приоритеты Материал собран из `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 | ✅ готово (int/long) | | B4 | **ложная** отладочная информация: чужие имена переменных и строк | DebugInfo | ✅ `SourceFile` | B2 — главное отличие от разобранного образца: у него ключ был константным выражением в вызове и расшифровывался статически, без JVM. Мастер-секрет теперь собирается в рантайме из двух частей (`k1 ^ k2`) декодером класса — см. [`../stack.md`](../stack.md) §4. B4 пока покрывает только `SourceFile`; ложные номера строк (`fake_line_numbers`) — см. [`../../todo.md`](../../todo.md) §3.6. ## P2 — контрольный поток | пункт | что это | статус | |---|---|---| | C1 | **несколько схем** флаттенинга вместо одной, с мешаниной внутри метода | план | | C2 | верификатор обязателен: ошибка CFG = `VerifyError` | ✅ готово (кадры + `java -Xverify:all`) | | C3 | реальный объём ≠ раздувание: бюджет на размер и время | ✅ размер; время — план | Приоритет здесь строго подчинён: **C2 раньше C1**. Кадры `StackMapTable` и приёмка `java -Xverify:all` уже готовы (см. [`../stack.md`](../stack.md) §3) — единственное, чего не хватает, это сами схемы флаттенинга (C1). ## P3 — измеримость (метрики, без которых ничего не доказано) Обязательный блок, иначе фраза «обфускация есть» ничего не означает. Крейт `noxis-verify` реализован — вот что из списка уже цифра, а что ещё мнение: 1. **Утечки имён.** ✅ `collect_names`/`find_leaks` — сверка идентификаторов с учётом keep-списка. 2. **Читаемость декомпилята.** ⬜ Прогон JADX/CFR → доля распознанных структур — не начато. 3. **Противник.** ✅ `scan_secrets` + `RED_PATTERNS` держим в репозитории; ⬜ полноценный скрипт-деобфускатор (свёртка констант) как тест — план. 4. **Семантика.** ⬜ Эталонные программы до/после — не начато (сейчас семантику подтверждает только `java -Xverify:all`). 5. **Бюджеты.** ✅ размер (`inflation_ratio`/`check_inflation`); ⬜ время исполнения — не начато. 6. **Стабильность между сборками.** ✅ `mappings_changed` — маппинги обязаны отличаться между прогонами с разным seed. Итог: `noxis-verify` закрывает красные паттерны, утечки имён, `java -Xverify:all`, бюджет размера и стабильность маппингов. Остаются декомпилят-метрика, бюджет времени и эталонная семантика — три пункта, где «нам кажется защищённым» всё ещё мнение, а не цифра. ## P4 — долгий горизонт (пока не делаем) | пункт | что это | почему не сразу | |---|---|---| | D1 | маленький VM/interpreter для ценных кусков | цена окупается только на ключевом коде | | D2 | split-function / раскрываемое по шагам тело | режет обычный профилировщик, сложная отладка | | D3 | мягкий анти-анализ в рантайме | требует своего нативного компонента | | D4 | честный anti-tamper, а не «зашейрь ключ» | целая инженерная задача, не пасс | | E | собственный нативный/Rust-цель вместо JVM | другой продукт, не наша цель | D1 — явно ограничен: включать только для действительно ценных функций, остальное оправдания не имеет. E — отдельный продукт; если он когда-нибудь понадобится, наш IR как раз делает его возможным (те же пассы, другой writer). ## Что мы добавили сверх исходного плана 1. **Структурный гейт при компиляции.** Лимиты «250 строк / 4 файла» гоняются в `build.rs` — см. [`../README.md`](../README.md). Без этого план P0–P3 превращается в один гигантский файл через месяц. 2. **Собственный IR с метками.** Исходный план предполагал работу поверх готового парсера. `Insn::Mark(Label)` убирает пересчёт смещений из всех пассов — это меняет цену каждой техники, меняющей CFG. 3. **Детерминированный PRNG с доменным разделением.** Без этого пункт «стабильность между сборками» невозможно проверить тестом. 4. **Keep как отдельный крейт (`noxis-analysis`), а не флаг CLI.** Рефлексия, JNI, сериализация и entrypoint'ы — это анализ иерархии, а не настройка, которую надо помнить руками. ## Порядок выполнения Смотрите [`../../todo.md`](../../todo.md). P0–P3 и P3-измеримость уже готовы; единственный крупный пункт, который остался, — схемы `Flow` (C1), потому что верификатор (C2) для них уже есть: ```text ✅ P0 DebugInfo + Resources → главные утечки сняты ✅ P1 Strings (B2) + Constants → ключ выводится, схемы ротируются ✅ P1 backend (ristretto) + frames ⬜ P2 Flow (C1) — единственное, что ждёт реализации; верификатор готов ✅ P3 метрики, красные паттерны, CLI ```