动态程序分析的挑战与静态分析工具PointsTo的解决方案

本文探讨动态程序分析工具在检测内存漏洞时的局限性,并详细介绍Trail of Bits开发的静态分析工具PointsTo如何通过数据流跟踪和LLVM位码分析,全面检测数百万行代码中的use-after-free漏洞。

动态程序分析的问题 - Trail of Bits博客

动态分析的局限性

开发者可以使用AddressSanitizer和Valgrind等工具来检测运行时代码中的未初始化内存访问、内存泄漏或释放后使用(use-after-free)等问题。尽管这些优秀工具可用,内存漏洞仍然存在,仍然会被发布给用户,并在实际环境中被利用。

当今大多数漏洞查找工具都是动态的:它们在程序运行时识别漏洞。这很好,因为所有程序都有庞大的测试套件来覆盖每一行代码……对吗?错了。大型测试套件是例外而非规则。测试套件确实有助于发现和减少漏洞,但漏洞仍然会漏网。

也许解决方案是付费请专业人士审计代码。让更多眼睛检查代码是好事™,但根本问题依然存在。专家头脑中运行的分析仍然是“动态的”:通盘考虑每一条代码路径并不可行。

因此,动态分析可能会遗漏漏洞,因为它们无法检查所有可能的程序路径。那么,什么可以检查所有可能的程序路径呢?

在数百万行代码中查找释放后使用漏洞

我们使用静态分析来分析数百万行代码,而无需运行代码。这种称为数据流跟踪的分析技术使我们能够分析和总结关于所有可能程序路径的属性。这解决了前述因未执行某些程序路径而遗漏漏洞的问题。

一个能洞察一切的分析工具实际上是如何工作的?下面我们描述我们开发并定期使用的实际全程序静态分析工具PointsTo的1-2-3步骤。该工具在大型代码库中查找并报告潜在的释放后使用漏洞。

步骤1:转换为LLVM位码

PointsTo操作程序的LLVM位码表示。我们选择LLVM位码是因为它是执行程序分析的便捷中间表示。不出所料,我们分析流程的第一阶段是将程序的源代码转换为LLVM位码数据库。我们使用名为CompInfo的内部工具来生成这些数据库。一个类似的开源工具是whole-program-llvm。

步骤2:创建数据流图

PointsTo背后的关键思想是分析指向已分配对象的指针如何在程序中流动。我们关心的是指针的赋值和复制、指针解引用以及指针的释放。这些指针操作使用数据流图表示。

过程中最有趣的步骤是将分配和释放转换为特殊赋值的原因和方法。“原因”是这种转换让我们可以重新利用现有的程序分析来查找从FREE定义到指针解引用的路径。方法更为微妙:PointsTo如何知道应该将“new A”更改为ALLOC,将“delete a”更改为FREE?

想象一个假设的嵌入式系统,程序内存匮乏,因此自然选择是使用名为ration_memory的自定义内存分配器。我们创建了一种Python建模语言,向PointsTo提供关于高级函数行为的信息。我们的建模脚本告诉PointsTo“new A”返回一个新对象,因此我们可以用它来对ration_memory说同样的事情。

插曲:隐藏的数据流

从源代码到数据流图的转换看起来很简单,但那是因为我们开始的源代码很简单。它没有函数调用,更重要的是,它没有函数指针或方法调用!如果下面的callback是函数指针会发生什么?如果callback释放了x会发生什么?

1
2
3
int *x = malloc(4);
callback(x);
*x += 1;

这是PointsTo的秘方和同名来源:我们执行上下文和路径敏感的指针分析,告诉我们哪些函数指针指向哪些函数以及何时指向。总之,我们可以生成一个错误报告,跟踪x通过callback并再次返回。

步骤3:结局

是时候报告潜在错误供专家分析了。PointsTo搜索数据流图,查找从赋值到FREE再到解引用的流。这些流被转换为源代码行的程序切片,显示执行需要遵循的路径以产生释放后使用。以下是一个真实漏洞的程序切片示例:

(示例程序切片内容)

当向编译器人员描述这个系统时,通常的第一个问题是:但是误报呢?如果我们收到一个关于释放后使用的报告,但它不是呢?这就是编译器程序分析和漏洞分析的优先级分道扬镳的地方。

编译器分析中的误报可能会引入漏洞,因此编译器通常是保守的。也就是说,它们用误报换取漏报。它们可能会错过一些优化机会,因为它们无法证明某些事情,但至少程序会被正确编译咳嗽

对于漏洞分析,这是一个糟糕的交易。漏洞分析中的误报是不方便的,但当需要查看数百万行代码时,它们只是沧海一粟。然而,漏报是不可接受的。漏报是一个被遗漏并可能进入生产环境的漏洞。一个总能找到漏洞并有时警告你可疑但正确代码的工具是一项投资,可以在代码审计期间节省时间和金钱。

总结

分析程序中的漏洞是困难的。应该遵循行业最佳实践,如拥有广泛的测试套件。开发者应定期通过动态分析工具运行他们的程序,以摘取低垂的果实。但更重要的是,开发者应该理解测试套件和动态分析不是万能药。漏洞有一个讨厌的习惯,隐藏在很少执行的代码路径后面。这就是为什么需要查看所有路径。这就是我们制作PointsTo的原因。

PointsTo是最近Empire Hacking(纽约每两个月一次的聚会)的讨论话题。我在那里的演讲包括更多关于PointsTo设计和实现的信息,对于好奇的读者,幻灯片和视频如下所示。我们希望未来发布更多来自Empire Hacking的视频。

PointsTo最初是为Cyber Fast Track制作的,我们要感谢DARPA资助我们的工作。Trail of Bits的顾问使用PointsTo和其他内部工具进行应用程序安全审查。如果您有兴趣对您的代码进行详细审计,并得到PointsTo和我们的CRS等工具的支持,请联系我们。

如果您喜欢这篇文章,请分享: Twitter LinkedIn GitHub Mastodon Hacker News


页面内容 在数百万行代码中查找释放后使用漏洞 步骤1:转换为LLVM位码 步骤2:创建数据流图 步骤3:结局 总结 最近文章 使用Deptective调查您的依赖项 系好安全带,Buttercup,AIxCC的评分回合正在进行中! 使您的智能合约超越私钥风险 Go解析器中意想不到的安全陷阱 我们审查首批DKLs23库的收获 Silence Laboratories的23个库 © 2025 Trail of Bits. 使用Hugo和Mainroad主题生成。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计