woodruffw/steg86
GitHub: woodruffw/steg86
steg86 利用 x86 指令编码的语义双重性,在不改变二进制文件体积和性能的前提下实现信息隐藏与提取。
Stars: 324 | Forks: 13
# steg86

[](https://github.com/woodruffw/steg86/actions/workflows/ci.yml)
*steg86* 是一款与格式无关的[隐写](https://en.wikipedia.org/wiki/Steganography)工具,适用于 x86 和 AMD64 二进制文件。你可以使用它在编译好的程序中隐藏信息,而不受可执行格式(PE、ELF、Mach-O、raw 等)的限制。它对所修改的文件没有任何性能*或*体积方面的影响(添加信息*不会*增加二进制文件的大小,也*不会*降低执行速度)。有关 *steg86* 工作原理的更多细节,请参阅[工作原理](#theory-of-operation)部分。
## 安装说明
可以通过 `cargo` 安装 `steg86`:
```
$ cargo install steg86
```
或者,你也可以在本仓库中使用 `cargo build` 进行构建:
```
$ cargo build
```
## 使用说明
运行 `steg86 --help` 查看完整的标志和子命令列表。
### 性能分析
要分析二进制文件的隐写适用性:
```
$ steg86 profile /bin/bash
Summary for /bin/bash:
175828 total instructions
27957 potential semantic pairs
19 potential commutative instructions
27944 bits of information capacity (3493 bytes, approx. 3KB)
```
### 嵌入
要向二进制文件中嵌入信息:
```
$ steg86 embed /bin/bash ./bash.steg <<< "here is my secret message"
```
默认情况下,`steg86 embed` 会将其输出写入 `$input.steg`。
例如,`/lib64/ld-linux-x86-64.so.2` 会变为 `/lib64/ld-linux-x86-64.so.2.steg`。
如果无法嵌入信息(例如信息太大),`steg86 embed` 将以非零状态退出。
### 提取
要从二进制文件中提取信息:
```
$ steg86 extract bash.steg > my_message
$ cat my_message
here is my secret message
```
如果无法提取信息(例如找不到信息),`steg86 extract` 将以非零状态退出。
## 工作原理
*steg86* 利用了 x86 编码的一个特性:ModR/M 字节的 R/M 字段:
```
7 6 5 4 3 2 1 0
-------------------------
| MOD | REG | R/M |
-------------------------
```
ModR/M 字节通常用于支持同一指令的寄存器到内存和内存到寄存器变体。例如,`MOV` 指令包含以下变体(以及许多其他变体):
| opcode | mnemonic |
----------|------------------
| `89 /r` | `MOV r/m32,r32` |
| `8B /r` | `MOV r32,r/m32` |
因为 ModR/M 字段既可以编码内存寻址操作,*也可以*编码纯粹的寄存器操作,所以同时支持寄存器到内存和内存到寄存器操作的 opcode *也*支持寄存器到寄存器操作的多种编码方式。
例如,`mov eax, ebx` 既可以编码为 `89 d8`,也可以编码为 `8b c3`,且*没有任何语义上的变化*。这就为每条具有重复语义的指令提供了一比特的信息。如果有足够多的、具有多种编码方式的寄存器到寄存器指令,我们就可以利用这些比特位隐藏完整的信息。
此外,由于这些语义相同的编码通常具有相同的大小,我们可以修改*现有的*二进制文件,而无需修复重定位或 RIP 相对寻址。
为了实现这些目标,*steg86* 进行了基础的[二进制转译](https://en.wikipedia.org/wiki/Binary_translation)。它使用 [iced-x86](https://github.com/0xd4d/iced) 进行编码和解码,并使用 [goblin](https://github.com/m4b/goblin) 处理二进制格式。
### 先前工作
*steg86* 的灵感来自 [@inventednight](https://github.com/inventednight),他将其描述为将类似想法(同样属于他们)适配到 RISC-V 二进制文件中的一种变体。
上述技术在[*Hydan: Hiding Information in Program Binaries*](http://web4.cs.columbia.edu/~angelos/Papers/hydan.pdf)(2004)一文中有详细讨论。
*steg86* 构成了对 Hydan 技术的独立发现,并且是完全独立编写的;论文中讨论的改进方案可能比 *steg86* 中实现的方案更优化,也可能并非如此。
### 未来改进
* *steg86* 目前将嵌入的信息限制为 16KB。这纯粹是人为的限制,可以通过一些微小的格式更改来解决。
* x86(以及 AMD64)都具有用于对齐的多字节 NOP。可以通过几种方式在这些指令中隐藏额外信息:
* `OF 1F /0` 多字节 NOP 最多可达 9 个字节,其中最多有 5 个字节是空闲的(SIB + 4 字节偏移量)。
* 还有更长的 NOP(11、15 字节),这些可能也是可用的。
* 超越寄存器到寄存器的双重编码,并像 Hydan 那样重写 `add`/`sub` 指令。
标签:Rust, x86架构, 二进制处理, 信息隐藏, 可视化界面, 网络流量审计, 通知系统, 隐写术