
Un ISA RISC-V unique par session — chaque démarrage parle un dialecte différent. Les anciens binaires deviennent invalides. Les malwares ne peuvent pas persister.
Chaque démarrage parle une langue différente. Le binaire d'hier est le code mort d'aujourd'hui.
Un système de remappage ISA RISC-V unique par session. Chaque fois que le système démarre, il génère une nouvelle permutation cryptographique du jeu d'instructions. Les binaires compilés pour une session sont cryptographiquement rejetés lors de la suivante. Un logiciel malveillant qui survit à un redémarrage ne peut pas s'exécuter — il parle un dialecte mort.
Les ISA standards sont des contrats fixes. Chaque programme, chaque bibliothèque, chaque logiciel malveillant s'accorde sur ce que signifie 0x13, ce que fait l'appel système 64, quel registre est le pointeur de pile. DeadDialect brise ce contrat à chaque session.
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
Un binaire compilé pour Boot A n'a pas de sens sur Boot B. Il exécute soit les mauvaises instructions, appelle les mauvaises fonctions du noyau, ou échoue à la vérification de l'empreinte cryptographique — selon ce qui arrive en premier.
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³⁰⁹⁴⁺
Trois couches indépendantes. Un attaquant qui en brise une fait toujours face aux deux autres.
┌──────────────────────────────────────────────────────────────┐
│ 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
Chaque binaire compilé porte une empreinte cryptographique de 24 bits intégrée sous la forme de deux NOP addi x0,x0,N inoffensifs au début de .text. Ce sont de véritables NOP RISC-V — ils écrivent dans le registre zéro et n'ont aucun effet architectural — mais ils encodent la preuve de session.
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
L'empreinte est dérivée de SHA-256(seed). Aucune collision trouvée dans les 100 000 premières graines testées.
DeadDialect/
├── opcode-remapping/ Phase 1 — Mélange de 12 opcodes
├── trigger-remapping/ Phase 2 — Déclencheur en direct, pas de redémarrage nécessaire
│ └── alpine/ Démo Alpine Linux
├── syscall-remapping/ Phase 3 M1 — Mélange de 436 appels système
├── register-remapping/ Phase 3 M2 — Mélange de 21 registres + empreinte
└── integration/ Phase 3 M3 — Toutes les couches simultanément
├── isa_integrate.py Réécrivain unifié
├── register_mapping.h
├── syscall_mapping.h
├── isa_remap_ldso.h Correctif ld.so musl (binaires dynamiques)
├── trigger/
│ └── trigger_demo.sh Un déclencheur fait pivoter les deux couches atomiquement
├── alpine/
│ ├── boot_alpine.sh Démarre Alpine sous QEMU patché
│ ├── alpine_demo.sh Démo ISA complète dans Alpine
│ ├── full_alpine_test.sh
│ └── setup_alpine.sh Configuration machine vierge
├── build.sh Télécharge + patche QEMU 8.2.0
├── demo.sh
└── audit.sh 51/51 vérifications
Prérequis : 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 requis (instructions compressées RVC pas encore prises en charge)isa_remap_ldso.h)register_mapping.h)21 des 32 registres RISC-V mélangés. Registres ABI gelés. Le hook QEMU utilise la table OPCODE_FIELDS — seuls les champs de registre réels sont remappés, les immédiats ne sont jamais touchés (correctif de Curtis).
| Frozen | Shuffleable |
|---|---|
| x0 x1 x2 x10-x17 | x3-x9, x18-x31 (21 regs) |
syscall_mapping.h)436 appels système Linux RISC-V permutés. Une ligne dans do_syscall(). mtime-reload — mises à jour du keyring sans redémarrage de QEMU.
isa_mapping.h)12 opcodes principaux mélangés. Le hook de décodage dans translate.c restaure l'opcode standard avant le décodeur.
isa_remap_ldso.h)Correctif du linker dynamique musl — remappe le .text de chaque ELF chargé au moment du chargement. Ne peut pas être contourné via LD_PRELOAD. Nécessite une reconstruction de musl Alpine.
.text du noyau avant démarrageCurtis Cole
Muhammad Bilal
"Je savais que mon idée était réelle mais je suis à peu près sûr que tout le monde pensait que j'étais fou." — Curtis Cole
| Checks |
|---|
| Status |
|---|
| Trigger remapping | 37/37 | ✓ |
| Syscall remapping | 40/40 | ✓ |
| Register remapping | 43/43 | ✓ |
| Integration | 51/51 | ✓ |