obfuskator/docs
loki5512344 2172206e83
passes: implement control-flow pass (4 schemes + rotation)
FlowPass rebuilds one method per scheme picked from FlowConfig:
state-spread (dense tableswitch dispatcher), computed-switch
(sparse lookupswitch over a counter local), butterfly (branch
inversion), exception-goto (dispatcher under try with a dead
catch-all), plus opaque goto-splices inside every method and
StackMapTable recomputation afterwards. Now in standard_pipeline
(between constants and noise); --no-flow is an honest off-flag.

Acceptance is real JVM, not shapes: per-scheme verify, rotation
spread, calc-prints-45 execution, paranoid smoke on lorep-1.1.0
(131 methods rebuilt, no new failures over standard).

Two verifier rules learned the hard way are now construction
invariants: no inserted mark shares a bytecode offset with a
foreign one (nop pads), and no frameless gap follows a terminal
(dead blocks are opaque-entered and throw).

Also fixes a latent frame-emitter bug the pass exposed: wide
stack values were written as slot pairs ([Double, Top]) while
javac writes one entry ([Double]); HotSpot rejects the pair.
Stacks now collapse like locals (emit::stack_vars), with a
regression test in classfile/tests/frames.rs.
2026-10-09 11:11:55 +02:00
..
learnings passes: implement control-flow pass (4 schemes + rotation) 2026-10-09 11:11:55 +02:00
architecture.md passes: implement control-flow pass (4 schemes + rotation) 2026-10-09 11:11:55 +02:00
README.md structure-check: gate counts code lines, docs and comments in English 2026-10-09 10:31:02 +02:00
stack.md Initial commit: noxis JVM bytecode obfuscator 2026-10-08 22:01:03 +02:00
techniques.md passes: implement control-flow pass (4 schemes + rotation) 2026-10-09 11:11:55 +02:00

Документация noxis

Обфускатор JVM/Java-байткода на Rust. Этот файл — индекс.

Что где

файл что внутри
architecture.md слои, крейты, собственный IR, конвейер пассов, структурные правила
techniques.md как работает каждая техника + плюсы/минусы/цена
stack.md почему свой IR, какой backend, StackMapTable, PRNG, генерация рантайма
learnings/lessons.md уроки из разбора EvoVis: что защита сделала плохо и чего мы не делаем
learnings/reference.md разбор референсного обфускатора (Java/ASM) — что берём, что нет
learnings/priorities.md что улучшим: стратегия и приоритеты
learnings/ai-resistance.md новые техники обфускации и устойчивость к LLM-анализу

План выполнения — ../todo.md. Исходный материал разбора — ../info/.

Структурные правила проекта

Правила — только про Rust-код: crates/*/src, crates/*/tests, crates/*/benches. Документация (docs/**, корневые .md) и info/ вне гейта: писать подробно там, где это документация, а не ограничивать объём искусственно. Не учитываются также Cargo.lock, .gitignore, корень крейта (в нём всегда лежат Cargo.toml + build.rs).

  1. Не больше 250 строк кода в одном .rs файле. Пустые строки и полно-строчные комментарии (//, ///, //!) не считаются — измеряется объём кода, а не документации.
  2. Не больше 4 .rs-файлов в одной директории. Подпапки не ограничены: src/ может содержать lib.rs и три модуля-директории, каждая из которых в свою очередь содержит не больше четырёх файлов.

tests/ и benches/ не исключены намеренно — иначе правило «250 строк» обходится выносом кода в тесты.

Правило 2 — это не косметика: файл из тысячи строк означает, что в нём смешаны разные причины к изменению (нарушение KISS/DRY/SOLID), а команда из восьми файлов в одной папке — что модуль перестал быть модулем.

Как проверяется

Правила гоняются при компиляции. Каждый крейт имеет build.rs:

fn main() {
    noxis_structure_check::check();
}

noxis-structure-check обходит деревья src/, tests/ и benches/ этого крейта и падает со стопкой ошибок, если лимит нарушен. Поэтому cargo build не соберёт нарушение — специально запускать проверку не нужно. Деревья регистрируются через cargo:rerun-if-changed, чтобы гейт не срабатывал на правки вне проверяемых путей.

Остальное, что не привязано к компиляции, собирается одним скриптом:

./scripts/check.sh   # structure → fmt → clippy -D warnings → test

Что делать при нарушении

  • файл разрослся → разрезать по одной ответственности на файл: mod.rs = публичный контракт модуля, соседние файлы — внутренности;
  • папка переполнилась → завести подпапку и вынести подфункцию целиком, а не «чтобы влезло».

Каждый модуль получает mod.rs с //!-документацией — это точка входа, читающаяся вместо пяти файлов.