obfuskator/docs
loki5512344 139aea9a8f
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.
2026-10-09 13:47:27 +02:00
..
learnings frames,jar,passes: verifier-driven hardening from real jars 2026-10-09 13:47:27 +02:00
architecture.md frames,jar,passes: verifier-driven hardening from real jars 2026-10-09 13:47:27 +02:00
README.md frames,jar,passes: verifier-driven hardening from real jars 2026-10-09 13:47:27 +02:00
stack.md frames,jar,passes: verifier-driven hardening from real jars 2026-10-09 13:47:27 +02:00
techniques.md frames,jar,passes: verifier-driven hardening from real jars 2026-10-09 13:47:27 +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 с //!-документацией - это точка входа, читающаяся вместо пяти файлов.