Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
clr — 生命周期及其他细化类型的检查器 | Kitploit
工具/GitHubGitHub/ityonemo/clr
静态分析漏洞分析代码分析模糊测试二进制分析学习与教育
GitHubityonemo/clr

clr

生命周期及其他细化类型的检查器

查看仓库
277219天前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CLR

Checker of

Lifetimes and other

Refinement types

for Zig

视频:https://www.youtube.com/watch?v=mf0WzTOe-40
赞助:https://buymeacoffee.com/dnautics

在 HN 上讨论:https://news.ycombinator.com/item?id=42923829

在 lobste.rs 上讨论:https://lobste.rs/s/9sitsj/clr_checker_for_lifetimes_other

现场演示视频:https://www.youtube.com/watch?v=ZY_Z-aGbYm8

概述

该项目为 Zig 编译器创建了一个 Zig 转译器,它将 AIR(抽象中间表示)转换为在编译时执行静态分析的 Zig 源代码。生成的分析器可以捕获内存安全问题,例如:未赋值即使用、释放后使用、栈指针逃逸,以及 Zig 特有的未定义行为(如非空断言、联合体(tagged union)违规或 fieldParentPtr 误用)。

目标是通过对 AIR 的静态分析,将 Rust 级别的内存安全保证带到 Zig,而不改变语言本身。

CLR 依赖于一个分支版本的 Zig 编译器(作为子模块包含在 zig/ 中),该版本增加了对外部插件路由 AIR 的支持。当使用 -ofmt=air -fair-out=<plugin.so> 调用时,编译器会加载指定的共享库,并将生成的 AIR 传递给它进行处理。

面向安全的架构

CLR 旨在推动程序采用显式且局部可验证的生命周期模式,而不仅仅是识别每一个技术上有效的 Zig 程序。当两种表示方式都可行时,CLR 更倾向于使资源状态在类型和控制流结构中可见的那种。

例如,避免有条件地关闭一个非可选的(non-optional)文件描述符:

root@kitploit:~
const file = try std.fs.cwd().openFile(path, .{});
if (should_close) {
    file.close(); // 差的做法:文件在此分支后处于模糊的打开状态。
}

推荐使用可选类型表示条件所有权:

root@kitploit:~
var file: ?std.fs.File = null;
if (should_open) {
    file = try std.fs.cwd().openFile(path, .{});
}

if (file) |open_file| {
    open_file.close();
}

有条件地关闭一个非可选的描述符会使其生命周期在分支后变得模糊。CLR 的预期策略是拒绝这种模式,而不是永久携带一个“可能已关闭”的状态。

同样的原则适用于已分配的指针。不要通过派生指针进行释放:

root@kitploit:~
const allocation = try allocator.alloc(u8, size);
const payload = allocation[header_size..];
allocator.free(payload); // 差的做法:payload 不是分配基地址。

保留分配基地址指针用于释放,仅使用派生指针进行访问:

root@kitploit:~
const allocation = try allocator.alloc(u8, size);
defer allocator.free(allocation);

const payload = allocation[header_size..];
use(payload);

释放字段指针、子切片或通过算术运算产生的指针,除非存在文档化的内部规则重新建立分配基地址的来源,否则将被拒绝。

这些策略默认是严格的,因为它们能产生资源生命周期更简单、更易审查的代码。未来的不安全注释机制将允许选定的 GID(全局标识符)或操作选择退出个别分析。这将支持那些有意接受较弱检查以换取性能的代码,同时不削弱程序其余部分的默认模型。

状态

这是对最初基于 Elixir 的概念验证项目在 Zig 中的积极重写。当前的 Zig 实现作为编译器插件加载,并直接分析 AIR。

目前已实现:

  • 未定义值跟踪(未赋值即使用,结构体的字段级跟踪)
  • 内存安全分析(释放后使用、双重释放、内存泄漏、分配器不匹配、栈逃逸)
  • 完整的 std.mem.Allocator 接口覆盖:
    • create/destroy - 单项分配
    • alloc/free - 切片分配(包括 alignedAlloc、allocSentinel 等)
    • realloc/remap - 切片重新分配,带旧切片已释放跟踪
    • dupe/dupeZ - 切片复制
    • 分配器不匹配检测(使用错误的分配器释放,create/destroy 与 alloc/free 混用)
    • 复杂分配器类型(GPA、ArenaAllocator、FixedBufferAllocator)
  • ArenaAllocator 生命周期跟踪:
    • init/deinit/allocator - 完整的 Arena 生命周期

计划中(详见 LIMITATIONS.md):

  • async/await
  • 别名安全(检测冲突的可变引用)
  • 针对合并或间接指针来源的多源指针精化
  • 超出当前已覆盖的 fd 传播模式的描述符别名分析
  • 更完整的过程间/全局突变摘要
  • 对齐转换降低识别
  • 互斥锁安全(lock/unlock 配对,死锁检测)
  • 自定义强制能力(用户定义的精化规则)

先决条件

  • Zig 0.15.2(支持 LLVM 的系统安装)
  • Linux(目前仅限 Linux,因为直接使用系统调用)
  • BATS(用于集成测试):sudo apt install bats

构建

供应商提供的 Zig 编译器和 libclr 插件必须以匹配的优化级别构建。优化级别不匹配会导致段错误。

root@kitploit:~
# 构建自定义 Zig 编译器,使用 ReleaseFast(仅在第一次或子模块更改后执行)
cd zig && zig build --zig-lib-dir lib -Doptimize=ReleaseFast && cd ..

# 构建匹配优化的 CLR 插件
zig build -Doptimize=ReleaseFast

对于开发/调试,可以将两者都设置为 ReleaseSafe 或 Debug:

root@kitploit:~
# ReleaseSafe(带有安全检查,稍慢)
cd zig && zig build --zig-lib-dir lib -Doptimize=ReleaseSafe && cd ..
zig build -Doptimize=ReleaseSafe

# Debug(完整的调试信息,最慢)
cd zig && zig build --zig-lib-dir lib && cd ..
zig build

用法

root@kitploit:~
# 使用 AIR 后端编译一个 Zig 文件
zig/zig-out/bin/zig build-exe -fair-out=zig-out/lib/libclr.so -ofmt=air -femit-bin=output.air.zig your_file.zig

# 运行生成的分析器
zig run --dep clr -Mroot=output.air.zig -Mclr=lib/lib.zig

输出发送到 stderr。

测试

root@kitploit:~
# 单元测试(代码生成/DLL)
zig build test

# 单元测试(运行时库)
zig test lib/lib.zig

# 一个聚焦的集成测试文件
bats test/integration/fd.bats

# 集成测试(需要 BATS)
# 默认为 ReleaseFast;可覆盖为 OPTIMIZE=ReleaseSafe 或 OPTIMIZE=Debug
./run_integration.sh

# 手动测试单个文件
./run_one.sh test/cases/undefined/use_before_assign.zig

注意: 集成测试会使用指定的优化级别(默认:ReleaseFast)重新构建 libclr。确保您供应商提供的 Zig 编译器是以匹配的优化级别构建的。

项目结构

root@kitploit:~
clr/
├── src/                     # DLL/插件代码(生成 .air.zig)
│   ├── clr.zig              # CLR 插件主入口点
│   ├── codegen.zig          # 从 AIR 指令生成 .air.zig 源代码
│   └── allocator.zig        # DLL 安全的分配器包装
├── lib/                     # 运行时分析库
│   ├── lib.zig              # 库入口点
│   ├── tag.zig              # AnyTag 联合体, Type, tag 处理器, splat 分派
│   ├── Inst.zig             # 指令结果和过程间分析
│   ├── Refinements.zig      # 精化类型(指针、结构体、可选等)
│   ├── Analyte.zig          # 分析状态容器
│   ├── Context.zig          # 执行上下文(元数据,错误报告)
│   └── analysis/            # 分析模块
│       ├── undefined_safety.zig  # 未赋值即使用跟踪
│       ├── memory_safety.zig     # 分配/释放跟踪
│       ├── null_safety.zig       # 可选解包检查
│       ├── variant_safety.zig    # 联合体字段访问
│       └── fd_safety.zig         # 文件描述符跟踪
├── test/
│   ├── integration/         # BATS 集成测试
│   │   ├── test_helper.bash
│   │   └── *.bats
│   └── cases/               # 测试输入文件 (.zig)
├── zig/                     # Zig 编译器子模块(已插桩的分支)
├── build.zig                # 构建配置
└── build.zig.zon            # 包依赖

总体思路

图表

Zig 是一种著名的“不安全”语言。内存管理是手动的,这导致了实现错误的可能性。尽管 Zig 通过消除安全检查代码中的越界数组访问和空指针解引用,相比 C 减少了安全问题,但它仍然不如 Rust 安全,因为 Rust 通过静态分析消除了释放后使用、双重释放和数据竞争。

受 Rust 的 MIRI 项目启发,CLR 对 Zig 的 AIR 中间表示执行静态分析,以实现比 Zig 开箱即用更高的安全性。与 MIRI 在沙箱伪运行时中解释 Rust 的 MIR 不同,CLR 将 AIR 转译为静态运行分析的 Zig 源代码。请注意,CLR 的 AIR 输出的 Zig 代码原则上可以在编译时运行,但通过 Zig 中间层,我们产生了一个易于理解和调试的逻辑流程。有抱负的人可能会使用这种通用方法输出不同的目标,例如证明助理语言,或者重构它使其完全在 Zig 编译器中运行!

关键洞察:如果即使是最注重安全的 Rust 项目也需要 MIRI,那么为什么不选择一种更简单的语言,并执行 MIRI 风格的分析来获得借用检查和其他精化类型分析呢?这个项目表明,这样的未来对于 Zig 是真实可能的。

Zig 编译管线为:

  1. Zig 代码 / AST
  2. Zig ZIR(无类型,每个文件的中间表示)
  3. Zig AIR(带类型,每个函数的 IR,为多态函数具体化)
  4. 编译器目标

AIR 是进行分析的理想层次,因为它是带类型的,可以被解释为广义编程指令的“最小可行”列表,并允许用精化元数据扩展类型。

关于 Zig 的 AIR 如何工作的深入分析,请参见 Mitchell Hashimoto 的博客文章:https://mitchellh.com/zig/sema

许可证

MIT 许可证 - 详情请参见 LICENSE。

下载工具
  • Arena 分配在 deinit 时被释放(无虚假泄漏警告)
  • 检测 deinit 后使用、双重 deinit、deinit 后分配
  • 跨分配器不匹配(arena 与 page_allocator)
  • 派生指针跟踪(不能释放字段指针、子切片 - 仅可释放根分配)
  • 指针算术安全(阻止对单项指针进行 ptr_add/ptr_sub)
  • 空安全(未检查的可选类型解包检测)
  • 变体安全(访问非活跃联合体字段,分支后的模糊变体)
  • FieldParentPtr 安全(检测从字段指针恢复包含对象的无效操作)
  • 过程间分析(通过指针参数跟踪跨函数调用的值)
  • 函数指针跟踪(间接调用分派到可能的目标)
  • 结构体和联合体字段跟踪(指针字段,嵌套类型)
  • 切片跟踪(alloc/free 与区域,子切片派生)
  • 错误联合支持(try 表达式,包裹/解包裹载荷)
  • Switch 语句支持(n 路合并与变体跟踪)
  • 带标签的 switch/Duff's 设备支持
  • 错误消息的源位置和变量名跟踪
  • 分支/控制流与状态合并
  • 循环分析(for、while、for-else、while-else 与定点迭代)
  • 全局变量跟踪(未定义、变体和内存安全)
  • 递归数据类型(链表、树、递归联合体)
  • 针对常见模式的标准库边界约简,例如 std.process.args、std.mem.asBytes、std.HashMap 以及分配器/文件 API
  • 特权的 std.HashMap 精化,包含规范的元数据/键/值存储恒等性,横跨 put、get、getPtr 和值迭代
  • 文件描述符安全:
    • posix.open/close/dup/dup2/socket/accept/epoll_create/pipe 跟踪
    • 关闭后使用检测(对已关闭的 fd 进行 read/write/dup)
    • 双重关闭检测
    • 函数退出和模块终结时的 Fd 泄漏检测
    • 降级本地句柄跟踪,使得保持活跃的别名抑制过早的泄漏报告
    • 对覆盖的描述符模式的返回和聚合传播
    • 未定义 fd 参数检测(对未定义的 fd 执行 close/read/write)