# Архитектура ## Слои ```text ┌──────────────────────────┐ CLI (noxis) │ clap → конфиг → отчёт │ └────────────┬─────────────┘ │ ┌─────────────────────┼─────────────────────┐ ▼ ▼ ▼ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │ noxis-jar │ │noxis-passes │ │noxis-verify │ │ ZIP, ресурсы│ │ трансформации│ │ red-паттерны │ └──────┬──────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ │ ┌──────┴───────┐ │ │ │ noxis-core │ │ │ │ конфиг, seed │ │ │ │ маппинги, Pass│ │ │ └──────┬───────┘ │ │ │ │ ▼ ▼ ▼ ┌────────────────────────────────────────────────────────┐ │ noxis-classfile (IR) │ │ Program → ClassFile → Code → Insn (метки, не смещения)│ │ model/ format/ insn error │ └────────────────────────────────────────────────────────┘ ▲ ┌──────┴──────┐ ┌───────────────┐ ┌──────────────────┐ │noxis- │ │noxis-runtime │ │noxis-structure- │ │analysis │ │ шифры, ABI │ │check (build-time)│ └─────────────┘ └───────────────┘ └──────────────────┘ ``` Зависимости направлены только вниз. Циклов нет: сборка конвейера живёт в `noxis-passes`, потому что `noxis-core` знает только контракт `Pass`. ## Крейты | крейт | ответственность | |---|---| | `noxis-classfile` | собственный IR классовых файлов, чтение/запись, `StackMapTable` | | `noxis-core` | конфигурация, детерминированный seed, маппинги, контекст и контракт `Pass` | | `noxis-analysis` | иерархия наследования, entrypoint'ы, рефлексия по имени, keep-правила | | `noxis-passes` | сами трансформации + сборка стандартного конвейера | | `noxis-runtime` | схемы шифрования строк и ABI класса-декодера | | `noxis-jar` | ZIP: чтение, перепаковка, вырезание подписей, патч ресурсов | | `noxis-verify` | red-паттерны, `java -Xverify:all`, метрики | | `noxis` | CLI | | `noxis-structure-check` | автогейт структурных правил (см. [`README.md`](README.md)) | ## Собственный IR Пассы не работают с API стороннего парсера - они работают с моделью: ```text Program все классы + ресурсы архива ├─ ClassFile версия, флаги, this/super, поля, методы, атрибуты │ ├─ Field │ └─ Method │ └─ Code max_stack/max_locals, insns, exception_table, frames └─ Resource путь + байты внутри архива ``` Ключевое решение - **`Insn::Mark(Label)` вместо байтовых смещений**: - любой пасс, меняющий порядок или длину инструкций, не пересчитывает jump-офсеты; - пересчёт делается ровно один раз - в writer'е; - в IR нет состояния, в котором «смещение уехало, а метка осталась». Атрибуты, которые мы не понимаем, хранятся как `Attribute::Raw { name, data }` и возвращаются на место без изменений - round-trip без потерь. ## Контракт пасса ```rust pub trait Pass: Send + Sync { fn id(&self) -> PassId; fn apply(&self, ctx: &mut Context, program: &mut Program) -> Result; } ``` - `Context` - всё состояние прогона: конфиг, мастер-сид, маппинги, заметки. Из него берётся RNG: `ctx.rng("rename/classes")` - доменное разделение, чтобы случайности разных пассов не были статистически коррелированы. - `PassReport` - что трансформировано, что сознательно пропущено и почему. - `Report` - собирает отчёты всех пассов + счётчики, сериализуется в JSON. Детерминированность - свойство, а не пожелание: одинаковый seed на одинаковой версии даёт байт-в-байт одинаковый выход. Это проверяется тестами. ## Конвейер Порядок пассов - не деталь: ```text Rename → Resources → Strings → Constants → Flow → Noise → DebugInfo ``` почему именно так: 1. **Rename первым** - все остальные техники порождают новые ссылки (`LDC`-шум, вызовы декодера, junk-классы), и они уже должны быть в обфусцированных именах. 2. **Resources сразу после Rename** - патч `fabric.mod.json`, `*.mixins.json`, refmap и access widener должен видеть *итоговые* имена классов. 3. **Strings и Constants** - работают по телам методов, ещё не искажённым control-flow'ем. 4. **Flow** - искажает CFG. Если поставить его раньше, Strings/Constants перестанут находить свои шаблоны в инструкциях. 5. **Noise** - junk-классы и аннотации добавляются в самом конце, когда целевой граф уже финален. 6. **DebugInfo последним** - strip/spoof отладочной информации после всех трансформаций, чтобы не породить свежие `LineNumberTable`. ## Статус | этап | что | |---|---| | **готово** | IR, модель, конфиг, seed/PRNG, маппинги, анализ, keep, гейт правил, `format::parse`/`write` поверх ристретто, вывод кадров `StackMapTable` | | **готово** | пассы rename/resources/strings/constants/noise/debug, генератор декодера, вывод мастер-секрета в рантайме | | **готово** | `noxis-verify` (red-паттерны, `java -Xverify:all`, метрики), CLI (`obfuscate`/`analyze`/`patterns`) | | **готово** | пасс `flow` (4 схемы + ротация + мешанина, приёмка настоящим `java`) | | **план** | фикстуры и regression-тесты | Детали выбора - [`stack.md`](stack.md), план - [`../todo.md`](../todo.md).