frames,jar,passes: verifier-driven hardening from real jars
Proven by paranoid runs over lorep (17 classes, fully green), LoVisual (4081 classes) and oc2r (1278 classes) with per-class java -Xverify:all, each fix first reproduced as a red test: - merge: Top absorbs instead of Top-wins (javac declares Top for slots unwritten on some inflow; precise types reject those edges). Regression: loop_head_keeps_top_for_loop_local. - emit: collapse [Long|Double, Top] pairs on operand stacks (javac writes one entry; the pair is rejected). Regression: wide_stack_join_emits_single_entries. - xfer ArrayLoad: push the wide pair, fixing lcmp underflow. Regression: array_load_wide_pushes_pair. - xfer <init>: convert only the receiver's own allocation site instead of every Uninitialized (nested construction clobbered the outer object). Regression: nested_construction_keeps_outer. - xfer ANewArray: array operands gain one dimension ([B] -> [[B) instead of an illegal L-wrap ([L[B;). Covered by the same test. - jar load: duplicate class names (multi-release module-info twins) keep the first occurrence instead of crashing save. Test: duplicate_class_names_keep_first. - strings/constants: skip methods past MAX_METHOD_INSNS (8000) so giants cannot overflow the 64KB writer ceiling. Tests: oversized_methods_are_skipped in both passes. - merge errors now name both types being merged. Also: em-dash removed repo-wide (724 spots, rule added to todo.md), allow-lints only in tests (scratch example deleted), code comments migrated to English in every file this change touches.
This commit is contained in:
parent
2172206e83
commit
139aea9a8f
96 changed files with 1053 additions and 831 deletions
|
|
@ -1,18 +1,18 @@
|
|||
# Что улучшим: стратегия и приоритеты
|
||||
|
||||
Материал собран из `info/evo-improvements.md` (план после разбора EvoVis) и
|
||||
`info/evo-weaknesses.md` (провалы). Здесь — что мы берём, в каком порядке
|
||||
`info/evo-weaknesses.md` (провалы). Здесь - что мы берём, в каком порядке
|
||||
и **что осознанно не делаем**.
|
||||
|
||||
## Стратегия в одном абзаце
|
||||
|
||||
Максимум защиты при минимуме риска сломать рантайм. Дешёвые техники,
|
||||
дающие 80% результата, включаются по умолчанию; дорогие и опасные —
|
||||
дающие 80% результата, включаются по умолчанию; дорогие и опасные -
|
||||
включаются **только** после того, как для них есть верификатор. Каждая
|
||||
техника имеет измеримый критерий «сработала/не сработала», иначе это
|
||||
не защита, а мнение.
|
||||
|
||||
## P0 — базовый уровень (дёшево, снимает главные утечки)
|
||||
## P0 - базовый уровень (дёшево, снимает главные утечки)
|
||||
|
||||
| пункт | что это | пасс | статус |
|
||||
|---|---|---|---|
|
||||
|
|
@ -20,63 +20,63 @@
|
|||
| A2 | вычистить `LineNumberTable`/`LocalVariableTable`/`SourceFile`/`InnerClasses`/`Signature`/`MethodParameters` | DebugInfo | ✅ готово |
|
||||
| A3 | никаких сигнатурных имён у защитного кода, защитный код смешан с обычным | Rename + Noise | ✅ готово |
|
||||
| A4 | обфусцировать **весь** архив, включая ресурсы, mixin-JSON, access widener, service loader'ы | Resources | ✅ готово |
|
||||
| — | маппинг в отчёт (иначе не читаем свои же stack trace) | Rename | ✅ готово |
|
||||
| - | маппинг в отчёт (иначе не читаем свои же stack trace) | Rename | ✅ готово |
|
||||
|
||||
Это самый дешёвый блок и одновременно **самый большой утечка** в разобранном
|
||||
образце: оригинальные `SourceFile` у 160 классов, имена полей и методов,
|
||||
каталог модулей в атрибутах.
|
||||
|
||||
## P1 — строки и константы
|
||||
## P1 - строки и константы
|
||||
|
||||
| пункт | что это | пасс | статус |
|
||||
|---|---|---|---|
|
||||
| B1 | ключ на строку + ротация 3–5 схем + MAC + уникальный nonce | Strings | ✅ готово |
|
||||
| B2 | **вывод** ключа в рантайме, а не константа в вызове | Strings + генератор декодера | ✅ готово |
|
||||
| B3 | константы — не тождества, а вычисления, разнесённые по блокам | Constants | ✅ готово (int/long) |
|
||||
| B3 | константы - не тождества, а вычисления, разнесённые по блокам | Constants | ✅ готово (int/long) |
|
||||
| B4 | **ложная** отладочная информация: чужие имена переменных и строк | DebugInfo | ✅ `SourceFile` |
|
||||
|
||||
B2 — главное отличие от разобранного образца: у него ключ был константным
|
||||
B2 - главное отличие от разобранного образца: у него ключ был константным
|
||||
выражением в вызове и расшифровывался статически, без JVM. Мастер-секрет
|
||||
теперь собирается в рантайме из двух частей (`k1 ^ k2`) декодером класса —
|
||||
теперь собирается в рантайме из двух частей (`k1 ^ k2`) декодером класса -
|
||||
см. [`../stack.md`](../stack.md) §4. B4 пока покрывает только `SourceFile`;
|
||||
ложные номера строк (`fake_line_numbers`) — см. [`../../todo.md`](../../todo.md) §3.6.
|
||||
ложные номера строк (`fake_line_numbers`) - см. [`../../todo.md`](../../todo.md) §3.6.
|
||||
|
||||
## P2 — контрольный поток
|
||||
## P2 - контрольный поток
|
||||
|
||||
| пункт | что это | статус |
|
||||
|---|---|---|
|
||||
| C1 | **несколько схем** флаттенинга вместо одной, с мешаниной внутри метода | план |
|
||||
| C2 | верификатор обязателен: ошибка CFG = `VerifyError` | ✅ готово (кадры + `java -Xverify:all`) |
|
||||
| C3 | реальный объём ≠ раздувание: бюджет на размер и время | ✅ размер; время — план |
|
||||
| C3 | реальный объём ≠ раздувание: бюджет на размер и время | ✅ размер; время - план |
|
||||
|
||||
Приоритет здесь строго подчинён: **C2 раньше C1**. Кадры `StackMapTable`
|
||||
и приёмка `java -Xverify:all` уже готовы (см. [`../stack.md`](../stack.md)
|
||||
§3) — единственное, чего не хватает, это сами схемы флаттенинга (C1).
|
||||
§3) - единственное, чего не хватает, это сами схемы флаттенинга (C1).
|
||||
|
||||
## P3 — измеримость (метрики, без которых ничего не доказано)
|
||||
## P3 - измеримость (метрики, без которых ничего не доказано)
|
||||
|
||||
Обязательный блок, иначе фраза «обфускация есть» ничего не означает.
|
||||
Крейт `noxis-verify` реализован — вот что из списка уже цифра, а что ещё мнение:
|
||||
Крейт `noxis-verify` реализован - вот что из списка уже цифра, а что ещё мнение:
|
||||
|
||||
1. **Утечки имён.** ✅ `collect_names`/`find_leaks` — сверка идентификаторов
|
||||
1. **Утечки имён.** ✅ `collect_names`/`find_leaks` - сверка идентификаторов
|
||||
с учётом keep-списка.
|
||||
2. **Читаемость декомпилята.** ⬜ Прогон JADX/CFR → доля распознанных
|
||||
структур — не начато.
|
||||
структур - не начато.
|
||||
3. **Противник.** ✅ `scan_secrets` + `RED_PATTERNS` держим в репозитории;
|
||||
⬜ полноценный скрипт-деобфускатор (свёртка констант) как тест — план.
|
||||
4. **Семантика.** ⬜ Эталонные программы до/после — не начато
|
||||
⬜ полноценный скрипт-деобфускатор (свёртка констант) как тест - план.
|
||||
4. **Семантика.** ⬜ Эталонные программы до/после - не начато
|
||||
(сейчас семантику подтверждает только `java -Xverify:all`).
|
||||
5. **Бюджеты.** ✅ размер (`inflation_ratio`/`check_inflation`);
|
||||
⬜ время исполнения — не начато.
|
||||
6. **Стабильность между сборками.** ✅ `mappings_changed` — маппинги
|
||||
⬜ время исполнения - не начато.
|
||||
6. **Стабильность между сборками.** ✅ `mappings_changed` - маппинги
|
||||
обязаны отличаться между прогонами с разным seed.
|
||||
|
||||
Итог: `noxis-verify` закрывает красные паттерны, утечки имён,
|
||||
`java -Xverify:all`, бюджет размера и стабильность маппингов. Остаются
|
||||
декомпилят-метрика, бюджет времени и эталонная семантика — три пункта,
|
||||
декомпилят-метрика, бюджет времени и эталонная семантика - три пункта,
|
||||
где «нам кажется защищённым» всё ещё мнение, а не цифра.
|
||||
|
||||
## P4 — долгий горизонт (пока не делаем)
|
||||
## P4 - долгий горизонт (пока не делаем)
|
||||
|
||||
| пункт | что это | почему не сразу |
|
||||
|---|---|---|
|
||||
|
|
@ -86,35 +86,35 @@ B2 — главное отличие от разобранного образц
|
|||
| D4 | честный anti-tamper, а не «зашейрь ключ» | целая инженерная задача, не пасс |
|
||||
| E | собственный нативный/Rust-цель вместо JVM | другой продукт, не наша цель |
|
||||
|
||||
D1 — явно ограничен: включать только для действительно ценных функций,
|
||||
остальное оправдания не имеет. E — отдельный продукт; если он когда-нибудь
|
||||
D1 - явно ограничен: включать только для действительно ценных функций,
|
||||
остальное оправдания не имеет. E - отдельный продукт; если он когда-нибудь
|
||||
понадобится, наш IR как раз делает его возможным (те же пассы, другой
|
||||
writer).
|
||||
|
||||
## Что мы добавили сверх исходного плана
|
||||
|
||||
1. **Структурный гейт при компиляции.** Лимиты «250 строк / 4 файла»
|
||||
гоняются в `build.rs` — см. [`../README.md`](../README.md). Без этого
|
||||
гоняются в `build.rs` - см. [`../README.md`](../README.md). Без этого
|
||||
план P0–P3 превращается в один гигантский файл через месяц.
|
||||
2. **Собственный IR с метками.** Исходный план предполагал работу поверх
|
||||
готового парсера. `Insn::Mark(Label)` убирает пересчёт смещений из
|
||||
всех пассов — это меняет цену каждой техники, меняющей CFG.
|
||||
всех пассов - это меняет цену каждой техники, меняющей CFG.
|
||||
3. **Детерминированный PRNG с доменным разделением.** Без этого
|
||||
пункт «стабильность между сборками» невозможно проверить тестом.
|
||||
4. **Keep как отдельный крейт (`noxis-analysis`), а не флаг CLI.**
|
||||
Рефлексия, JNI, сериализация и entrypoint'ы — это анализ иерархии,
|
||||
Рефлексия, JNI, сериализация и entrypoint'ы - это анализ иерархии,
|
||||
а не настройка, которую надо помнить руками.
|
||||
|
||||
## Порядок выполнения
|
||||
|
||||
Смотрите [`../../todo.md`](../../todo.md). P0–P3 и P3-измеримость уже
|
||||
готовы; единственный крупный пункт, который остался, — схемы `Flow` (C1),
|
||||
готовы; единственный крупный пункт, который остался, - схемы `Flow` (C1),
|
||||
потому что верификатор (C2) для них уже есть:
|
||||
|
||||
```text
|
||||
✅ P0 DebugInfo + Resources → главные утечки сняты
|
||||
✅ P1 Strings (B2) + Constants → ключ выводится, схемы ротируются
|
||||
✅ P1 backend (ristretto) + frames
|
||||
✅ P2 Flow (C1) — готов (09.10.2026): 4 схемы + ротация + мешанина, приёмка настоящим `java`
|
||||
✅ P2 Flow (C1) - готов (09.10.2026): 4 схемы + ротация + мешанина, приёмка настоящим `java`
|
||||
✅ P3 метрики, красные паттерны, CLI
|
||||
```
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue