engrbilal992/DeadDialect
GitHub: engrbilal992/DeadDialect
一个基于 RISC-V 的会话唯一指令集重映射系统,通过每次启动时随机化操作码、寄存器和系统调用号来彻底阻止恶意软件在重启后持久化执行。
Stars: 4 | Forks: 1
# DeadDialect
一个会话唯一的 RISC-V ISA 重映射系统。每次系统启动时,它都会生成全新的指令集加密置换。为某一个会话编译的二进制文件在下一次会话中会被加密拒绝。能在重启后存活的恶意软件无法执行——它说着一种已消亡的方言。
## 理念
标准 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
```
为引导 A 编译的二进制文件在引导 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 位的加密指纹,作为两条无害的 `addi x0,x0,N` NOP 嵌入在 `.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 个种子中未发现冲突。
## 仓库结构
```
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
# 构建已修补的 QEMU 8.2.0(首次运行约 10 分钟)
bash build.sh
# 安全演示
bash demo.sh
# 一个触发器同时旋转两个层
bash trigger/trigger_demo.sh
# 在已修补的 QEMU 下启动 Alpine Linux
cd alpine
bash setup_alpine.sh # first time only — downloads kernel + rootfs
bash boot_alpine.sh # boots to ~ # prompt in ~30 seconds
# Alpine ISA 演示
bash alpine_demo.sh
bash full_alpine_test.sh
```
## 演示结果
### 6 场景安全性证明
```
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 ✓
```
## 审计结果
| 里程碑 | 检查项 | 状态 |
|---|---|---|
| 触发重映射 | 37/37 | ✓ |
| Syscall 重映射 | 40/40 | ✓ |
| 寄存器重映射 | 43/43 | ✓ |
| 集成 | 51/51 | ✓ |
## 安全属性
### 它能阻止什么
- **恶意软件持久化**——来自前一个会话的任何二进制文件在下次引导时都会失效
- **预编译漏洞利用**——针对固定 ISA 的 shellcode 会立即失效
- **重放攻击**——来自某一个会话的二进制文件无法在另一个会话中执行
- **标准 QEMU 执行**——重映射的二进制文件需要打过补丁的执行器
### 为什么熵很重要
```
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
```
### POC 范围
- 需要 `-march=rv64g`(目前尚未处理 RVC 压缩指令)
- 测试程序仅支持静态二进制文件(通过 `isa_remap_ldso.h` 提供动态支持)
- 未涉及在单个会话内完成的攻击
## 各层工作原理
### 寄存器 (`register_mapping.h`)
32 个 RISC-V 寄存器中的 21 个被打乱。ABI 寄存器被冻结。QEMU hook 使用 `OPCODE_FIELDS` 表——仅重映射实际的寄存器字段,永远不触碰立即数(Curtis 的修复)。
| 冻结 | 可打乱 |
|---|---|
| x0 x1 x2 x10-x17 | x3-x9, x18-x31 (21 个寄存器) |
### Syscall(`syscall_mapping.h`)
436 个 Linux RISC-V 系统调用被置换。`do_syscall()` 中的一行代码。mtime 重载——无需重启 QEMU 即可更新密钥环。
### 操作码 (`isa_mapping.h`)
12 个主操作码被打乱。`translate.c` 中的解码 hook 在解码器之前恢复标准操作码。
### ld.so(`isa_remap_ldso.h`)
musl 动态链接器补丁——在加载时重映射每个已加载 ELF 的 `.text`。无法通过 `LD_PRELOAD` 绕过。需要重新构建 Alpine musl。
## 未来方向
- ARM 支持(相同概念,不同的固定 ISA 契约)
- 内核 `.text` 预引导重映射
- 硬件 FPGA 实现
- Hacker News / 学术出版物
## 作者与协作者
**Curtis Cole**
**Muhammad Bilal**
*"我知道我的想法是真实的,但我很确定大家都认为我疯了。"* — Curtis Cole
标签:0day挖掘, APT防御, ASLR, Cutter, ISA重映射, RISC-V, syscall随机化, TLS抓取, 内核安全, 动态二进制, 反恶意代码, 反持久化, 地址空间布局随机化, 子域名枚举, 安全工程, 寄存器混淆, 密码学, 手动系统调用, 指令集架构, 指令集混淆, 熵增, 系统启动, 系统安全, 编译器技术, 网络安全, 软件安全, 逆向工具, 逆向工程对抗, 防恶意软件, 随机化指令集, 隐私保护, 高级持续威胁防御