woodruffw/steg86

GitHub: woodruffw/steg86

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

Stars: 324 | Forks: 13

# steg86 ![license](https://raster.shields.io/badge/license-MIT%20with%20restrictions-green.png) [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg)](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架构, 二进制处理, 信息隐藏, 可视化界面, 网络流量审计, 通知系统, 隐写术