docs: drop stale learnings notes (lessons/priorities/reference)
This commit is contained in:
parent
1ebbca10fa
commit
550f62e473
3 changed files with 0 additions and 416 deletions
|
|
@ -1,146 +0,0 @@
|
|||
# Уроки: что защита EvoVis сделала плохо
|
||||
|
||||
Источник: `info/evo-weaknesses.md` - полный разбор за один проход, без
|
||||
рантайм-хаков. Здесь - что из этого следует для **нашей** архитектуры.
|
||||
|
||||
Правило, которое стоит держать головой: **защита ломается не в рантайме,
|
||||
а на этапе, когда атакующий смотрит на статику.** Всё, что видно в `javap -p`
|
||||
или в содержимом jar, - это утечка.
|
||||
|
||||
## Сводная таблица: провал → наше решение
|
||||
|
||||
| № | провал EvoVis | наше решение | пасс | статус |
|
||||
|---|---|---|---|---|
|
||||
| 1 | ключ лежит рядом с шифротекстом | вывод мастер-секрета в декодере, ключ из `master‖salt` | Strings | **готово** |
|
||||
| 2 | переименованы типы, но не члены | rename полей/методов + семейства virtual | Rename | **готово** |
|
||||
| 3 | отладочная информация нетронута | strip + ложный `SourceFile`/номера строк | DebugInfo | **готово** (`SourceFile`; номера строк - план) |
|
||||
| 4 | шаблонный flattening | 4 схемы CFG + мешанина внутри метода | Flow | **готово** (4 схемы, приёмка `java`) |
|
||||
| 5 | opaque-предикаты = `A+B` | ротация тождеств + предикаты от состояния | Constants | **готово** (int/long) |
|
||||
| 6 | junk-классы вне графа reachability | `weave_reachable` - обязательная вплетённость | Noise | **готово** (без аннотаций) |
|
||||
| 7 | имена говорят «я защита» | все артефакты получают данные псевдонимы | Rename | **готово** |
|
||||
| 8 | вторичные компоненты без защиты | весь jar, а не только основной класс | Resources | **готово** |
|
||||
| 9 | шифр без MAC и без per-string salt | salt на строку, уникальный nonce, MAC | Strings | **готово** |
|
||||
|
||||
## 1. Ключ рядом с шифротекстом
|
||||
|
||||
`awc.d("<cipher>", <opaque-выражение>)` - ключ был **константным выражением
|
||||
в вызове**. Свёртка выражения - ~200 строк любого парсера. Итог: 8993 вызова
|
||||
расшифрованы детерминированно, **0 обращений к JVM**.
|
||||
|
||||
Хуже: один шифр на весь продукт (LCG с фиксированными `a/c`) - зная одну
|
||||
пару «шифротекст → текст», остальные раскрываются по обучению.
|
||||
|
||||
**Что делаем иначе.**
|
||||
|
||||
- Ключ строки = `F(master, salt)`, `master` **выводится** в рантайме и не
|
||||
является константой в `LDC`.
|
||||
- `salt` лежит рядом с шифротекстом, но сам по себе бесполезен без `master`.
|
||||
- **Ротация схем** (`xor-splitmix` / `xtea-ctr`): одна расшифровка не даёт
|
||||
ключа ко всему jar. Плюс per-string `nonce`, чтобы пары «текст→шифр»
|
||||
не повторялись и частотный анализ не работал.
|
||||
- MAC: подмена байта не «тихо» портит текст.
|
||||
|
||||
Остаточный риск честно признан: целевой анализ декодера раскрывает текст.
|
||||
Задача - поднять цену, а не сделать невозможным.
|
||||
|
||||
## 2. Члены не переименованы
|
||||
|
||||
`onDraw`, `getProjectiles`, `isAuthorized()` - открытые имена. Класс `wb`
|
||||
опознаётся за секунду по трём понятным методам.
|
||||
|
||||
**Что делаем иначе:** переименование полей и методов входит в базовый
|
||||
уровень, а не в «продвинутый». Уже готово, включая:
|
||||
|
||||
- **семейства virtual** - переименование на всю иерархию, чтобы не
|
||||
разъединить переопределения и не сломать `invokevirtual`;
|
||||
- **keep-список** - private/static/final можно сразу, `rename_public_members`
|
||||
по умолчанию выключен для библиотек, чтобы не сломать API;
|
||||
- **автодетект рефлексии по имени** - `Class.forName`, `getMethod`,
|
||||
`getField` с литералами попадают в keep автоматически.
|
||||
|
||||
## 3. Отладочная информация
|
||||
|
||||
`SourceFile` оригинальные у 160 классов, `LineNumberTable` - 10 218,
|
||||
`LocalVariableTable` - имена локальных переменных, `@rn(name, description)` -
|
||||
каталог всех модулей с описаниями.
|
||||
|
||||
**Что делаем иначе:** пасс `DebugInfo` - strip `SourceFile`,
|
||||
`LineNumberTable`, `LocalVariableTable`, `Signature`, `InnerClasses` +
|
||||
**ложная** отладочная информация (чужие имена и номера строк, чтобы
|
||||
деобфускатор выдавал правдоподобный, но чужой код).
|
||||
|
||||
Отсюда обязательное требование: **маппинги в отчёте** - иначе мы сами не
|
||||
читаем свои stack trace'и.
|
||||
|
||||
## 4. Шаблонный flattening
|
||||
|
||||
Один regex нашёл 3530 автоматов: `while(true) { switch(i + i2) }`, метки -
|
||||
константы, переходы - присваивания в одном basic block, тела блоков не
|
||||
тронуты.
|
||||
|
||||
**Что делаем иначе:** не одна схема, а **четыре** (`state-spread`,
|
||||
`computed-switch`, `butterfly`, `exception-goto`), с ротацией между методами
|
||||
и с перемешиванием внутри метода. Плюс `butterfly` и `exception-goto`
|
||||
ломают «все переходы - присваивания».
|
||||
|
||||
Это единственная техника с **высоким риском**: любая ошибка в CFG =
|
||||
`VerifyError`. Поэтому блокером Flow объявлен не «напишем потом», а
|
||||
`StackMapTable` - см. [`../stack.md`](../stack.md) §3. Без верификатора
|
||||
Flow не включается.
|
||||
|
||||
## 5. Opaque-предикаты
|
||||
|
||||
`(A^B)+((A&B)<<1)` - школьное тождество, узнаётся регуляркой и даёт
|
||||
бесплатный фолдинг остальных констант. Настоящих предикатов (зависящих
|
||||
от состояния и всегда истинных) нет.
|
||||
|
||||
**Что делаем иначе:** ротация семейств тождеств (арифметика, побитово,
|
||||
сдвиги, произведение соседних чисел, инвариант по модулю) + предикаты,
|
||||
завязанные на состояние, а не на пару констант.
|
||||
|
||||
## 6. Reachability убивает junk
|
||||
|
||||
42 файла, ни одного входящего ссылока, `dangling=0` → BFS от 4
|
||||
entrypoint'ов, которые открыто лежат в `fabric.mod.json`.
|
||||
|
||||
**Что делаем иначе:** `weave_reachable` - junk попадает в граф
|
||||
достижимости, создаёт ложные рёбра и участвует в вызовах. Это свойство
|
||||
пасса, а не настройка: без вплетённости junk не включается вовсе.
|
||||
|
||||
## 7. Самоописание защиты
|
||||
|
||||
`StringRuntime`, `KeyAssembler`, `AttestClient`, `RuntimeGuard`,
|
||||
`SealedBoot`, `NativeGuard` - названия указывают атакующему, куда смотреть.
|
||||
|
||||
**Что делаем иначе:** псевдонимы генерируются одним `NameGenerator` для
|
||||
всех сущностей - классы, пакеты, поля, методы, junk и даже имена атрибутов
|
||||
и схем выглядят как обычные данные. Отдельного «защитного» стиля не
|
||||
существует, поэтому отличить его от остального кода не по чему.
|
||||
|
||||
## 8. Вторичные компоненты
|
||||
|
||||
`evo-agent.jar` вообще без обфускации, .NET-лаунчер - статическая XOR-таблица.
|
||||
|
||||
**Что делаем иначе:** обфускация применяется ко **всему архиву**, включая
|
||||
ресурсы (`fabric.mod.json`, mixins, refmap, access widener) - см. пасс
|
||||
`Resources`. Отдельного «ядро защищено, остальное нет» не бывает.
|
||||
|
||||
## 9. Шифр без аутентификации
|
||||
|
||||
Нет MAC, нет per-string сида → повреждение не ловится, частотный анализ
|
||||
работает.
|
||||
|
||||
**Уже сделано:** `salt` на строку, уникальный `nonce`, FNV-1a MAC в
|
||||
`noxis-runtime::scheme`. `cipher:tag` лежат рядом - порча обнаруживается.
|
||||
|
||||
## Что подтвердилось и не нужно повторять в выводах
|
||||
|
||||
Разбор дал и **опровержения** - важно не строить защиту на мифах:
|
||||
|
||||
- «сдвиги в байткоде бывают отрицательными» - по 1277 классам **0** случаев
|
||||
(32 559 сдвигов, константные всегда `1`);
|
||||
- `awc.g(...)` (session-gate) в билде **не вызывался ни разу**.
|
||||
|
||||
Вывод: проверять гипотезу на статистике **до** того, как вкладываться
|
||||
в технику против неё. Отсюда требование к `noxis-verify` - не «красиво
|
||||
обфусцировано», а измеримые метрики ([`priorities.md`](priorities.md)).
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
# Что улучшим: стратегия и приоритеты
|
||||
|
||||
Материал собран из `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) - готов (09.10.2026): 4 схемы + ротация + мешанина, приёмка настоящим `java`
|
||||
✅ P3 метрики, красные паттерны, CLI
|
||||
```
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
# Референс: Fabric Mod Obfuscator (Java + ASM)
|
||||
|
||||
Разобранный образец лежит в `/tmp/opencode/obf_extract/OBF` (JAR из `OBF.rar`).
|
||||
Нужен не как «правильный ответ», а как **карта решений, которые уже были
|
||||
приняты и проверены на живых кейсах**.
|
||||
|
||||
## 1. Что это
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| язык | Java 21, Maven, сборка `mvnw package` |
|
||||
| движок | **ASM** (читает `.class`, строит маппинги, переписывает байткод) |
|
||||
| объём | 18 классов в `org.example`, 3224 строки |
|
||||
| цель | Fabric/Minecraft-моды |
|
||||
| интерфейс | CLI + Swing GUI (drag-and-drop) |
|
||||
|
||||
## 2. Карта модулей → наш план
|
||||
|
||||
| модуль | LOC | что делает | у нас |
|
||||
|---|---:|---|---|
|
||||
| `JarRemapper` | 409 | обход архива, remap всех ссылок | `noxis-jar` + `rename::rewrite` |
|
||||
| `InheritanceAnalyzer` | 373 | иерархия, безопасность переименования | `noxis-analysis::hierarchy` ✅ |
|
||||
| `ObfuscatorGui` | 276 | GUI | не нужно (CLI) |
|
||||
| `MappingGenerator` | 262 | маппинг → файл | `noxis-core::mapping` ✅ |
|
||||
| `JunkClassGenerator` | 251 | junk-классы | пасс `noise` |
|
||||
| `StringDecoderGenerator` | 205 | генерит класс-декодер | `noxis-runtime` + P2 генератор |
|
||||
| `ObfuscatorRunner` | 202 | конвейер, оркестрация | `noxis-passes::standard_pipeline` ✅ |
|
||||
| `NumberObfuscator` | 185 | константы / opaque | пасс `constants` |
|
||||
| `ControlFlowObfuscator` | 183 | flattening | пасс `flow` ✅ (4 схемы, свои кадры) |
|
||||
| `FabricKeepRuleScanner` | 147 | keep из конфига Fabric | `noxis-analysis::keep` ✅ |
|
||||
| `Main` | 134 | CLI-точки | `noxis` (clap) |
|
||||
| `StringEncryptor` | 132 | AES-128 строк + chunk'и | `noxis-runtime::scheme` ✅ |
|
||||
| `NameGenerator` | 131 | имена | `noxis-passes::namegen` ✅ |
|
||||
| `JunkAnnotationInjector` | 79 | junk-аннотации | пасс `noise` |
|
||||
| `PackageGenerator` | 78 | пакеты | `namegen::generate_packages` ✅ |
|
||||
| `AccessWidener` | 73 | патч access widener | `noxis-jar` + пасс `resources` |
|
||||
| `DebugInfoStripper` | 69 | strip отладки | пасс `debug` |
|
||||
| `StringFilter` | 35 | что считать строкой | функция внутри `strings` |
|
||||
|
||||
**Вывод:** структура совпадает с нашей почти один в один - это подтверждает
|
||||
раскладку крейтов. Ключевое отличие: у них всё живёт в одном jar'е и
|
||||
одном проекте; у нас конвейер отделён от I/O и от CLI.
|
||||
|
||||
## 3. Что берём
|
||||
|
||||
### 3.1 Порядок пассов
|
||||
|
||||
У них: remap → strings → numbers → flow → junk → debug. Тот же инвариант,
|
||||
что и у нас: **переименование раньше всех техник, порождающих новые ссылки**,
|
||||
а `debug` - последним.
|
||||
|
||||
### 3.2 Наследование как условие безопасности
|
||||
|
||||
`InheritanceAnalyzer` - самый большой после remap'ера модуль. Совпадает с
|
||||
нашим выводом: переименование virtual-методов **без** иерархии ломает
|
||||
`invokevirtual`. У нас это `hierarchy` + семейства в `rename`.
|
||||
|
||||
### 3.3 Keep-сканер
|
||||
|
||||
`FabricKeepRuleScanner` читает правило из конфигурации Fabric и не даёт
|
||||
сломать то, что JVM находит по имени. Мы делаем то же самое + расширяем
|
||||
рефлексией по строкам.
|
||||
|
||||
### 3.4 Подпись срезается
|
||||
|
||||
`*.SF/*.RSA/*.DSA/*.EC` удаляются при перепаковке - после записи подпись
|
||||
всё равно невалидна, а её наличие заставляет JVM падать. Это входит в
|
||||
`noxis-jar`.
|
||||
|
||||
### 3.5 Маппинг в файл + ложные ограничения
|
||||
|
||||
`--mappings` пишет соответствие «новое → старое» - без него автор сам не
|
||||
читает stack trace. Плюс честные off-ключи: `--no-strings`, `--no-flow`,
|
||||
`--no-junk`, `--keep-lines`, `--keep-source`, `--keep-vars`, `--no-widen`.
|
||||
|
||||
Мы берём то же: **каждый пасс выключаем по отдельности**, иначе диагностика
|
||||
проблемы «что сломало» превращается в угадывание.
|
||||
|
||||
### 3.6 Seed
|
||||
|
||||
`--seed` - детерминированный прогон. У нас это базовое свойство
|
||||
`noxis-core`, без отдельного флага.
|
||||
|
||||
## 4. Что не берём
|
||||
|
||||
### 4.1 Java + ASM
|
||||
|
||||
Главное отличие стека. Пара Java+ASM даёт родную JVM, готовые visitor'ы и
|
||||
`CheckClassAdapter` - но и:
|
||||
|
||||
- нужно раскатывать JDK для сборки и запуска тестов;
|
||||
- наш проект - Rust (`deny(unsafe_code)`, свои лимиты, свои гейты);
|
||||
- отсутствует возможность отдавать один бинарь.
|
||||
|
||||
Цена, которую мы платим: `StackMapTable` придётся считать самим (через
|
||||
inference-верификатор - [`../stack.md`](../stack.md) §3). Это осознанно.
|
||||
|
||||
### 4.2 Swing GUI
|
||||
|
||||
Лишняя точка входа: GUI дублирует CLI и удваивает площадь тестирования.
|
||||
У нас - только clap.
|
||||
|
||||
### 4.3 `StringDecoderGenerator` как «генератор текста»
|
||||
|
||||
Они генерируют Java-исходник декодера и компилируют. Для нас это означало бы
|
||||
зависимость от `javac` на этапе обфускации. Наш путь - генерировать
|
||||
**байткод напрямую** через наш IR (`noxis-runtime` держит схемы, генератор
|
||||
собирает `ClassFile`).
|
||||
|
||||
### 4.4 AES-128 + Base64 как единственная схема
|
||||
|
||||
Одна схема на весь архив = тот же провал, что у EvoVis §1/§9. У нас
|
||||
ротация схем, per-string salt, nonce и MAC.
|
||||
|
||||
### 4.5 `--flatten-flow` только «для простых методов»
|
||||
|
||||
Ограничение из их README: агрессивный switch-gate включается только на
|
||||
простых методах. Это признаёт, что **верификация у них эмпирическая**.
|
||||
Мы вместо этого делаем верификатор обязательным условием включения `flow`.
|
||||
|
||||
## 5. Что проверяем на их smoke-тестах
|
||||
|
||||
В `target/` референса лежат готовые проверочные кейсы - их стоит
|
||||
переиспользовать как наш regression-набор:
|
||||
|
||||
| кейс | что ломает |
|
||||
|---|---|
|
||||
| `smoke-safe` | базовый round-trip, `Sample`/`MyMixin` |
|
||||
| `smoke-inheritance` | `Base`/`Child`/`InheritedChild`/`ExternalChild` - семейства virtual и мосты |
|
||||
| `smoke-flow` | `LoadAll` - загрузка всех классов, ловит `VerifyError` |
|
||||
| `smoke-fields` | переименование полей и статических полей |
|
||||
| `smoke-aes` | шифрование строк, `RunStrings` сверяет расшифровку |
|
||||
| `Probe.java` | точечная проверка одной гипотезы |
|
||||
|
||||
Это ровно тот класс тестов, который нужен `noxis-verify`: **загрузить
|
||||
и выполнить**, а не «выглядит обфусцированным».
|
||||
|
||||
## 6. Итог
|
||||
|
||||
| берём | не берём |
|
||||
|---|---|
|
||||
| порядок пассов | стек Java + ASM |
|
||||
| иерархия как условие rename | Swing GUI |
|
||||
| keep-сканер | генератор Java-исходника |
|
||||
| срез подписей, патч ресурсов | единственная схема шифра |
|
||||
| маппинг в отчёт, честные off-ключи | эмпирическая верификация flow |
|
||||
| их smoke-кейсы как regression | - |
|
||||
|
||||
Полный перечень провалов защиты, которую они **не** закрывают, - в
|
||||
[`lessons.md`](lessons.md).
|
||||
Loading…
Add table
Add a link
Reference in a new issue