
Уникальная для каждого сеанса ISA RISC-V — каждая загрузка говорит на другом диалекте. Старые бинарники становятся недействительными. Вредоносное ПО не может сохраняться.
Каждая загрузка говорит на своем языке. Вчерашний бинарный код — это сегодняшний мертвый код.
Система уникального для сеанса переназначения набора команд RISC-V. Каждый раз при загрузке системы генерируется новая криптографическая перестановка набора инструкций. Бинарные файлы, скомпилированные для одного сеанса, криптографически отвергаются в следующем. Вредоносное ПО, пережившее перезагрузку, не может выполниться — оно говорит на мертвом диалекте.
Стандартные ISA — это фиксированные контракты. Каждая программа, каждая библиотека, каждая вредоносная программа согласны с тем, что означает 0x13, что делает системный вызов 64, какой регистр является указателем стека. DeadDialect разрывает этот контракт в каждом сеансе.
Boot A: addi = 0x13, write = syscall 64, t0 = x5
Boot B: addi = 0x33, write = syscall 178, t0 = x19
Boot C: addi = 0x67, write = syscall 291, t0 = x23
Бинарный файл, скомпилированный для Boot A, — бессмыслица на Boot B. Он либо выполняет неверные инструкции, вызывает неверные функции ядра, либо не проходит проверку криптографического отпечатка — срабатывает то, что произойдет раньше.
256-bit session seed (os.urandom)
│
├─── opcode permutation → /etc/isa/map 12! ≈ 2²⁹
├─── register permutation → /etc/isa/register_keyring 21! ≈ 2⁶⁵
└─── syscall permutation → /etc/isa/syscall_keyring 436! ≈ 2³⁰⁰⁰⁺
─────────────
Combined entropy: 2³⁰⁹⁴⁺
Три независимых слоя. Атакующий, взломавший один, все еще сталкивается с двумя другими.
┌──────────────────────────────────────────────────────────────┐
│ Binary (.text) │
│ rewritten at compile time by isa_integrate.py │
│ fingerprint NOPs embedded at .text+0 │
└─────────────────────────┬────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ Patched QEMU 8.2.0 │
│ │
│ translate.c ← register_mapping.h │
│ ├── verify 24-bit SHA-256 fingerprint │
│ │ mismatch → SIGILL before first instruction │
│ └── remap 21 shuffleable registers │
│ │
│ syscall.c ← syscall_mapping.h │
│ └── translate permuted syscall number → standard │
│ │
│ [Phase 1/2] ← isa_mapping.h │
│ └── remap 12 primary opcodes │
└──────────────────────────┬───────────────────────────────────┘
│
▼
Alpine Linux RISC-V (boots normally)
OS is unaware of the remapping
Каждый скомпилированный бинарный файл несет 24-битный криптографический отпечаток, встроенный в виде двух безвредных NOP addi x0,x0,N в начале .text. Это настоящие RISC-V NOP — они пишут в нулевой регистр и не оказывают архитектурного эффекта — но они кодируют доказательство сеанса.
QEMU sees fingerprint NOPs + matching keyring → RUN
QEMU sees fingerprint NOPs + wrong keyring → SIGILL
QEMU sees no fingerprint + active keyring → SIGILL ← standard binary blocked
QEMU sees fingerprint NOPs + empty keyring → SIGILL ← remapped binary blocked
Отпечаток получен из SHA-256(seed). Коллизий не обнаружено среди первых 100 000 проверенных seed.
DeadDialect/
├── opcode-remapping/ Phase 1 — 12 opcode shuffle
├── trigger-remapping/ Phase 2 — live trigger, no reboot needed
│ └── alpine/ Alpine Linux demo
├── syscall-remapping/ Phase 3 M1 — 436 syscall shuffle
├── register-remapping/ Phase 3 M2 — 21 register shuffle + fingerprint
└── integration/ Phase 3 M3 — all layers simultaneously
├── isa_integrate.py unified rewriter
├── register_mapping.h
├── syscall_mapping.h
├── isa_remap_ldso.h musl ld.so patch (dynamic binaries)
├── trigger/
│ └── trigger_demo.sh one trigger rotates both layers atomically
├── alpine/
│ ├── boot_alpine.sh boot Alpine under patched QEMU
│ ├── alpine_demo.sh full ISA demo inside Alpine
│ ├── full_alpine_test.sh
│ └── setup_alpine.sh fresh machine setup
├── build.sh downloads + patches QEMU 8.2.0
├── demo.sh
└── audit.sh 51/51 checks
Требования: Ubuntu 22.04, clang, lld, python3, wget, ninja-build, libglib2.0-dev, libpixman-1-dev, libslirp-dev
git clone https://github.com/engrbilal992/DeadDialect.git
cd DeadDialect/integration
# Build patched QEMU 8.2.0 (~10 min first run)
bash build.sh
# Security demo
bash demo.sh
# One trigger rotates both layers simultaneously
bash trigger/trigger_demo.sh
# Boot Alpine Linux under patched QEMU
cd alpine
bash setup_alpine.sh # first time only — downloads kernel + rootfs
bash boot_alpine.sh # boots to ~ # prompt in ~30 seconds
# Alpine ISA demos
bash alpine_demo.sh
bash full_alpine_test.sh
T1: Standard binary, empty keyrings → runs ✓
T2: Integrated binary, correct keyrings → runs ✓
T3: Standard binary, active keyrings → SIGILL ✗
T4: Integrated binary, empty keyrings → SIGILL ✗
T5: Wrong-seed binary → SIGILL ✗
T6: Correct seed binary → runs ✓
Session A binary runs SUCCESS ✓
Session A malware runs EXECUTED (expected — same session)
── trigger fires ──
Session B old binary BLOCKED ✓
Session B malware BLOCKED ✓
Session B new binary compiled for B SUCCESS ✓
100,000 seeds — zero collisions
Seed 999999999 → BLOCKED under different session ✓
Seed 2²⁵⁶-1 (max 256-bit) → BLOCKED under different session ✓
Keyring corrupted mid-run → BLOCKED on corrupted keyring ✓
| Milestone |
|---|
Guessing register permutation: 1 in 21! ≈ 1 in 51 quintillion
Guessing syscall permutation: 1 in 436! ≈ 1 in 10^(1000+)
Guessing both simultaneously: not a viable attack
-march=rv64g (сжатые инструкции RVC пока не поддерживаются)isa_remap_ldso.h)register_mapping.h)Перемешиваются 21 из 32 регистров RISC-V. Регистры ABI заморожены. Хук QEMU использует таблицу OPCODE_FIELDS — переназначаются только фактические поля регистров, непосредственные значения никогда не затрагиваются (исправление Кертиса).
| Замороженные | Перемешиваемые |
|---|---|
| x0 x1 x2 x10-x17 | x3-x9, x18-x31 (21 рег.) |
syscall_mapping.h)Переставлены 436 системных вызовов Linux RISC-V. Одна строка в do_syscall(). mtime-reload — обновление keyring без перезапуска QEMU.
isa_mapping.h)Перемешаны 12 первичных кодов операций. Хук декодирования в translate.c восстанавливает стандартный код операции перед декодером.
isa_remap_ldso.h)Патч динамического компоновщика musl — переназначает .text каждого загруженного ELF во время загрузки. Его нельзя обойти через LD_PRELOAD. Требуется пересборка musl для Alpine.
.text ядра до загрузкиКертис Коул
Мухаммад Билал
«Я знал, что моя идея реальна, но уверен, что все просто считали меня сумасшедшим». — Кертис Коул
| Checks |
|---|
| Status |
|---|
| Trigger remapping | 37/37 | ✓ |
| Syscall remapping | 40/40 | ✓ |
| Register remapping | 43/43 | ✓ |
| Integration | 51/51 | ✓ |