
Una ISA RISC-V única por sesión — cada arranque habla un dialecto diferente. Los binarios antiguos se vuelven inválidos. El malware no puede persistir.
Cada arranque habla un idioma diferente. El binario de ayer es el código muerto de hoy.
Un sistema de reasignación de ISA RISC-V único por sesión. Cada vez que el sistema arranca, genera una permutación criptográfica fresca del conjunto de instrucciones. Los binarios compilados para una sesión son rechazados criptográficamente en la siguiente. El malware que sobrevive a un reinicio no puede ejecutarse: habla un dialecto muerto.
Las ISA estándar son contratos fijos. Cada programa, cada biblioteca, cada pieza de malware acuerda qué significa 0x13, qué hace la llamada al sistema 64, qué registro es el puntero de pila. DeadDialect rompe ese contrato cada sesión.
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 binario compilado para el Arranque A no tiene sentido en el Arranque B. O ejecuta las instrucciones incorrectas, llama a las funciones incorrectas del kernel, o falla la verificación de la huella criptográfica — lo que ocurra primero.
Semilla de sesión de 256 bits (os.urandom)
│
├─── permutación de opcodes → /etc/isa/map 12! ≈ 2²⁹
├─── permutación de registros → /etc/isa/register_keyring 21! ≈ 2⁶⁵
└─── permutación de syscalls → /etc/isa/syscall_keyring 436! ≈ 2³⁰⁰⁰⁺
─────────────
Entropía combinada: 2³⁰⁹⁴⁺
Tres capas independientes. Un atacante que rompe una aún se enfrenta a las otras dos.
┌──────────────────────────────────────────────────────────────┐
│ Binario (.text) │
│ reescrito en tiempo de compilación por isa_integrate.py│
│ NOPs de huella incrustados en .text+0 │
└─────────────────────────┬────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ QEMU 8.2.0 parcheado │
│ │
│ translate.c ← register_mapping.h │
│ ├── verificar huella SHA-256 de 24 bits │
│ │ desajuste → SIGILL antes de la primera instrucción │
│ └── reasignar 21 registros mezclables │
│ │
│ syscall.c ← syscall_mapping.h │
│ └── traducir número de syscall permutado → estándar │
│ │
│ [Fase 1/2] ← isa_mapping.h │
│ └── reasignar 12 opcodes primarios │
└──────────────────────────┬───────────────────────────────────┘
│
▼
Alpine Linux RISC-V (arranca normalmente)
El SO no está al tanto de la reasignación
Cada binario compilado lleva una huella criptográfica de 24 bits incrustada como dos NOPs addi x0,x0,N inofensivos al inicio de .text. Estos son NOPs RISC-V verdaderos — escriben en el registro cero y no tienen efecto arquitectónico — pero codifican la prueba de sesión.
QEMU ve NOPs de huella + llavero coincidente → EJECUTAR
QEMU ve NOPs de huella + llavero incorrecto → SIGILL
QEMU no ve huella + llavero activo → SIGILL ← binario estándar bloqueado
QEMU ve NOPs de huella + llavero vacío → SIGILL ← binario reasignado bloqueado
La huella se deriva de SHA-256(semilla). No se encontraron colisiones en las primeras 100,000 semillas probadas.
DeadDialect/
├── opcode-remapping/ Fase 1 — mezcla de 12 opcodes
├── trigger-remapping/ Fase 2 — disparo en vivo, sin necesidad de reinicio
│ └── alpine/ Demo de Alpine Linux
├── syscall-remapping/ Fase 3 M1 — mezcla de 436 syscalls
├── register-remapping/ Fase 3 M2 — mezcla de 21 registros + huella
└── integration/ Fase 3 M3 — todas las capas simultáneamente
├── isa_integrate.py reescritor unificado
├── register_mapping.h
├── syscall_mapping.h
├── isa_remap_ldso.h parche de musl ld.so (binarios dinámicos)
├── trigger/
│ └── trigger_demo.sh un disparo rota ambas capas atómicamente
├── alpine/
│ ├── boot_alpine.sh arrancar Alpine bajo QEMU parcheado
│ ├── alpine_demo.sh demo de ISA completa dentro de Alpine
│ ├── full_alpine_test.sh
│ └── setup_alpine.sh configuración de máquina fresca
├── build.sh descarga + parchea QEMU 8.2.0
├── demo.sh
└── audit.sh 51/51 verificaciones
Requisitos: 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: Binario estándar, llaveros vacíos → ejecuta ✓
T2: Binario integrado, llaveros correctos → ejecuta ✓
T3: Binario estándar, llaveros activos → SIGILL ✗
T4: Binario integrado, llaveros vacíos → SIGILL ✗
T5: Binario con semilla incorrecta → SIGILL ✗
T6: Binario con semilla correcta → ejecuta ✓
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 ✓
| Hito | Verificaciones | Estado |
|---|---|---|
| Trigger remapping | 37/37 | ✓ |
| Syscall remapping | 40/40 | ✓ |
| Register remapping | 43/43 | ✓ |
| Integration | 51/51 | ✓ |
Adivinar la permutación de registros: 1 entre 21! ≈ 1 entre 51 quintillones
Adivinar la permutación de syscalls: 1 entre 436! ≈ 1 entre 10^(1000+)
Adivinar ambas simultáneamente: no es un ataque viable
-march=rv64g (las instrucciones comprimidas RVC aún no se manejan)isa_remap_ldso.h)register_mapping.h)21 de los 32 registros RISC-V mezclados. Los registros ABI están congelados. El gancho de QEMU usa la tabla OPCODE_FIELDS — solo se reasignan los campos de registro reales, los inmediatos nunca se tocan (corrección de Curtis).
| Congelados | Mezclables |
|---|---|
| x0 x1 x2 x10-x17 | x3-x9, x18-x31 (21 regs) |
syscall_mapping.h)436 syscalls de Linux RISC-V permutadas. Una línea en do_syscall(). Recarga en mtime — el llavero se actualiza sin reiniciar QEMU.
isa_mapping.h)12 opcodes primarios mezclados. El gancho de decodificación en translate.c restaura el opcode estándar antes del decodificador.
isa_remap_ldso.h)Parche del enlazador dinámico musl — reasigna .text de cada ELF cargado en tiempo de carga. No se puede evitar mediante LD_PRELOAD. Requiere reconstrucción de musl de Alpine.
.text del kernel antes del arranqueCurtis Cole
Muhammad Bilal
"Sabía que mi idea era real, pero estoy bastante seguro de que todos pensaban que estaba loco." — Curtis Cole