文章总结: Entropia是一个用Rust编写的实验性编译器,可将.etpy语言编译为Windowsx64位置无关shellcode和CobaltStrikeBOF。项目约15800行代码,具备OPSEC混淆功能,审查发现其x64指令编码器质量高、错误诊断体系完善,但存在全仓库零单元测试、str.format缓冲区溢出等6个实质性bug。总体评价为工程素养出色但未达到1.0版本应有的工程纪律,建议优先补充测试和修复关键漏洞。 综合评分: 75 文章分类: 安全工具,红队,安全开发,二进制安全
工具 | Entropia —— Rust Shellcode/BOF 编译器
原创
GLM-5.2 GLM-5.2
赛博生存指南
2026年6月29日 08:58 浙江
在小说阅读器读本章
去阅读
把
.etpy源码一行命令编译成 Windows x64 shellcode 或 Cobalt Strike BOF,OPSEC 混淆全做成编译参数——这个叫 Entropia 的项目,代码到底写得怎么样?本文对它的 ~15800 行 Rust 做了一次完整审查。
仓库地址:https://github.com/entropykit/entropia
这是什么项目
Entropia 是一个实验性(pre-1.0)编译器,用 Rust 写成,把自创的 .etpy 语言编译成两种产物:
- • Windows x86-64 位置无关 shellcode(
.bin) - • Cobalt Strike Beacon Object File / COFF(
.x64.o)
定位是红队 / 安全研究的 dual-use 工具(README 有明确的授权与责任使用声明,类比 nanodump、mimikatz 这类公开工具)。它最大的卖点是把传统”C 编译器 + 链接器 + sRDI/Donut 位置无关变换 + 手工 OPSEC”的多工具链,压成单个编译器,OPSEC 技术栈(指令多态、加密字符串、直接/间接系统调用、栈欺骗、sleep mask……)全部以 --opsec=... 编译参数的形式提供。
先看规模:
| 范围 | 行数 |
| — | — |
| 核心编译器 src/*.rs(17 个模块) | ~11,000 |
| 工具链 tools/*(BOF 加载器、本地运行器、DAP 调试器、Win32 头生成器) | ~4,800 |
| 合计 | ~15,800 行 Rust |
编译管线很清晰:
lexer → parser → AST 变换 → typecheck → dce → codegen → 输出
↑
OPSEC 多态后处理
下面进入正题:代码质量到底如何。
总体评价:7 / 10
一句话结论:
工程素养出色的实验性编译器。手写 x64 编码器和 COFF/Beacon 语义还原度令人印象深刻,错误诊断带稳定错误码,核心编译在简单程序下是正确的;但全仓库零单元测试、几处实质性 bug、以及一个有意保持宽松的类型系统,是它的主要短板。
它的问题不是”写得很烂”,而是”还没到 1.0 该有的工程纪律”。
四个子领域的打分:
| 模块 | 评分 | 一句话 |
| — | — | — |
| 前端 lexer / parser | 7.5 | 优先级阶梯扎实、诊断好;零测试、转义静默降级 |
| 语义分析 | 6.5 | DCE/GC/PEB-walk 设计正确;类型检查实质宽松(部分有意)+ 一处真实空分支 |
| 后端 codegen / encoder / poly | 7.0 | encoder 编码质量高、reloc-aware;poly 指令边界隐患、str.format 溢出、COFF aux |
| 工具链 | 8.0 | 分层清晰、Beacon/VEH 还原度高;coff.rs 缺边界检查、dap.rs 过大 |
先说亮点:这些地方写得确实好
1. x64 指令编码器质量很高
encoder.rs(1277 行)是整个项目正确性的命脉,它做对了几件手写编码器最容易翻车的事:
- • rbp/r13 作基址寄存器时,
mod=00会被误解成 disp32,代码强制改成mod=01 + disp8=0; - • rsp/r12(低 3 位是
100)在所有寻址模式下都正确补了 SIB 字节0x24; - • spl/bpl/sil/dil 这类 8 位寄存器正确识别”即使没有扩展寄存器也需要 REX 前缀”,避免了把
mov al,[mem]误编码成ah的经典 bug; - • 立即数 size-aware:能塞进 imm8 就用
83形式,否则才用81,省字节。
更难得的是:整个后端没有 unsafe、没有 transmute,是纯 safe Rust。
2. 错误诊断有产品意识
类型检查器用了一套稳定的错误码体系 T001–T023,错误信息带行列定位,还常带可操作的修复建议(比如 “Add an explicit cast (u32)arg“)。display_type 会把内部哨兵 ? 转成对用户友好的 <unknown>,不泄露实现细节——这是一个有人在认真做”开发者体验”的信号。
3. DCE / GC / PEB-walk 运行时设计正确
这几个最容易出隐蔽 bug 的地方,作者都做对了:
- • **DCE(死代码消除)**正确保留了带
[Hook]/[Stage]/[Override]属性的间接调用函数——这些函数没有被显式call,但运行时会被入口 prologue 或钩子间接调起,漏保留就是”链接期丢函数”。作者没漏。 - • 保守式 GC 的根扫描设计合理:入口处捕获
STACK_TOP、收集时保存全部 Win64 非易失寄存器、用”本趟新增标记数为 0 才停”的不动点算法处理多代引用链。 - • PEB-walk 严格按 PE 导出目录的
Names → Ordinals → Functions三级跳转解析 API,还专门处理了 ntdll 对栈对齐敏感(movaps)的坑。
4. OPSEC 多态变换是真的”重定位感知”
polymorphism.rs 在每个指令等价替换点都检查 overlaps_reloc 和 label_inside,避免改坏重定位字段。README 宣传的 “reloc-aware” 是有代码支撑的,不是营销话术。
5. 工具链分层复用做得干净
bof-loader 作为纯库被 CLI 运行器和 DAP 调试器共同依赖;Beacon API 的字节序 / 长度前缀与 Cobalt Strike 的 bof_pack 严格对称;DAP 的 readMemory 用 VirtualQuery 守卫避免野指针打爆调试器进程,反汇编视图还会叠加断点处的原始字节让你看到真实指令而非 0xCC——细节到位。
再说问题:按真实严重性分级
🔴 应该修的实质性 bug
1. 类型检查的一处”空操作”分支(typecheck.rs)
一个声明返回 int 但写了 ret;(不带返回值)的函数,会被静默放行。对应的 match 分支是空的,而隔壁 void 函数返回值却会报 T023 错误——这种不对称强烈暗示是写漏了一行 errs.push(...)。
2. str.format 的栈缓冲区溢出(codegen.rs)
字符串格式化用的是微软已废弃的 wsprintfA,搭配一个固定 256 字节、无边界检查的缓冲区。用户可控的格式串展开超长时,会越界写 .bss 段相邻 slot。一个安全工具里不该有的内存安全漏洞。
3. BOF 的 COFF 符号格式不规范(coff.rs)
输出的函数符号标了 IMAGE_SYM_DTYPE_FUNCTION(type=0x20)但 NumberOfAuxSymbols=0,不符合 COFF 规范的严格读法(正常要么 type=0x00,要么配 .bf/.ef 辅助记录)。宽松的 BOF loader 能吃,但严格的自研 loader 可能拒绝加载或偏移错位——这直接威胁”BOF 能被加载”这个核心卖点。
4. BOF 加载器解析外部 COFF 缺边界检查(tools/bof-loader/src/coff.rs)
解析 .obj 文件时,节表 / 符号表的访问没有边界校验直接切片 + .unwrap()。一个字段值被伪造的畸形 .obj,会让加载器在启动阶段直接 panic,而不是给出可读的错误信息。作为一个”解析外部输入”的入口,这里应当全部改成带校验的 ? 返回。
5. BeaconFormatFree 的 Vec 重建契约脆弱(tools/bof-loader/src/beacon.rs)
用 Vec::from_raw_parts(ptr, 0, cap) 重建并 drop 一个 Vec 来释放内存,依赖”len 永远传 0″这个隐式假设——一旦有人在 append 路径改用 Vec::push 或记录真实 len,就会以错误的 len/cap 释放导致未定义行为。用 dealloc + Layout 更稳。
6. 字符串转义静默降级(lexer.rs)
未知的转义符(比如 \x、或者 Windows 路径 "C:\bad" 里漏写的反斜杠)会被静默降级成字面字符,没有任何警告。在 BOF 场景里这是高频且极隐蔽的错误来源。
🟡 设计弱点 / 隐患
指令多态的扫描没有”指令边界”概念(polymorphism.rs)
这是审查里最技术性的一处隐患。多态变换是线性扫描字节流、按 i += consumed 前进的,没有维护”指令起始偏移”集合。这意味着当某条指令的立即数或位移字节,恰好拼出 REX.W + 0x85/0x09/0x21 + 合法 ModRM 的样子时,扫描器会误以为这是一条 test/or/and 指令并改写它——把指令内部字节改坏了。重定位检查防不住这种(位移字段不在 reloc 表里)。
需要说明:它不是”随便一个程序就会崩”,触发需要特定的字节模式(立即数里恰好出现特定字节序列)。但它是一个真实的正确性隐患,且一旦触发极难调试。修法是让 codegen 在 emit 时记录每条指令的边界,多态扫描只在边界处尝试匹配。
try/catch 不支持嵌套
try/catch 的异常处理用了一组全局 BSS slot(__handler_pc/rsp/rbp),意味着嵌套 try 的内层会覆盖外层的 handler,内层退出后外层 raise 就丢了。这是 VEH-based 异常机制的固有局限,应当在文档里明示。
codegen 的栈对齐”侥幸正确”且无防护
Windows x64 ABI 要求调用瞬间栈 16 字节对齐。审查逐点复核后发现,目前多数调用点其实是对的——但全是靠”恰好此刻 rsp 对齐”侥幸成立,没有任何 assert 守护。任何对函数 prologue 的改动,都可能悄悄引入一个 8 字节错位、然后在某个深层调用处崩成无法追踪的 AV。建议加编译期栈深度跟踪或运行时断言。
C 头解析器与 README 承诺不符
cimport.rs 的顶层解析器拒绝函数声明、#include、#pragma、enum、非整数 #define——遇到就直接报错终止。但 README 的示例写着 use_c "winuser.h",暗示能直接喂 SDK 头。真实 SDK 头第一行就是 #include,会直接解析失败。实际上它只能消化由配套工具 entc-win32gen 从 win32metadata 生成的”净化版”头。这是文档与实现的落差,对用户是真实陷阱。
🟢 可维护性 / 小问题
- • 类型系统刻意宽松:Cast 是”逃生舱”(任何
(T)expr直接通过类型检查)、整数与指针双向自由互通。代码注释明确写着”by design,未来会收紧”。对写底层 shellcode 这种场景是合理的取舍——这不是 bug,是已知限制——但意味着类型检查对指针密集的代码基本不起作用,文档应该说清楚。 - • 巨型文件:
codegen.rs3450 行(一个 struct 22 个字段)、dap.rs1985 行(还内嵌了一个手写的表达式求值器),都到了该拆分的体量。 - • 零散的
.unwrap()/unreachable!()散落各处;内联汇编立即数的 hex/dec 转换里有一处”注释和实现恰好相反”的小矛盾。
最大的系统性短板:全仓库零单元测试
四个子审查一致确认:
src/*.rs和tools/*/src/*.rs里没有任何#[test],仓库也没有tests/目录。 README 自己也写着 “Tests: To be implemented”。仅有entc-debug/scripts/下 3 个 Python 冒烟测试。
对一个把源码编译成机器码的编译器来说,这是最要命的:
- • 运算符优先级表、x64 指令编码、类型兼容规则、COFF 二进制格式、多态等价变换——全部没有回归网;
- • 任何重构都只能靠人肉跑 examples 验证,风险极高;
- • 而像类型兼容
compat、类型推断infer_type、C 头解析parse_header、COFF 解析ParsedCoff这些,全是纯函数,加测试的成本极低、收益却最高。
这是 ROI(投入产出比)最高的改进方向,没有之一。
如果要改进,优先级建议
- 1. 补单元测试(最高 ROI)——先覆盖 lexer 词法、parser 优先级阶梯、typecheck 的兼容性判断、C 头解析、COFF 解析(喂一个小
.objfixture)。 - 2. 修掉上面 6 个 🔴 实质 bug——尤其
str.format缓冲区溢出、类型检查空分支、BOF 加载器的 COFF 边界检查。 - 3. 给多态变换加指令边界跟踪,给 codegen 加栈对齐 assert——消除两类最隐蔽的崩溃源。
- 4. 拆分
codegen.rs/dap.rs两个巨型文件。 - 5. 对齐 C 头解析器与文档——要么容错跳过函数声明 /
#include,要么 README 明示只支持净化头。
写在最后
审完整体感受是:这代码不是 AI 粗制滥造的产物,也不是新手练手作。 指令编码器、错误码体系、保守式 GC、PEB-walk 运行时——这些地方都见得到真实的工程功底和踩坑经验(注释里能看到”作者实际遇到过这个 AV 并修复了”的痕迹)。
它的核心编译能力在简单程序下是正确的,OPSEC 栈的设计也是认真的。
它的问题,本质上是一个实验性项目还没补上 1.0 该有的工程纪律:
- • 没有测试网,所以每次改动都在裸奔;
- • 几处边界 bug 没补(尤其那个
str.format溢出,在安全工具里特别讽刺); - • 类型系统还停在”渐进收紧”的早期阶段;
- • 文档在某些地方(C 头支持)领先于实现。
以 experimental(实验性)的标准衡量,它是合格偏上的;但如果想正式宣称 “Stable”,至少需要:补测试 + 修掉 🔴 列表 + 加固多态与栈对齐。
对于正在学编译器、学 Rust、或对红队工具链内部实现好奇的读者,这是一个相当值得读的代码库——编码器和运行时部分尤其有学习价值。
本次为只读审查,未修改任何源码。评估基于当前 main 分支快照,项目仍在活跃开发中,部分问题可能在后续提交中已修复。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:赛博生存指南 GLM-5.2 GLM-5.2《工具 | Entropia —— Rust Shellcode/BOF 编译器》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论