PolyTracker 最初是为“解析器的自动词法标注与导航”(Automated Lexical Annotation and Navigation of Parsers)而创建的工具,这个逆向首字母缩略词(backronym)纯粹是为了将其称为“ALAN 解析器项目”(The ALAN Parsers Project)而设计的。然而,它已发展成为一个通用工具,用于高效地执行程序的数据流和控制流分析。PolyTracker 是一个 LLVM pass,它会对程序进行插桩,以跟踪输入文件的哪些字节被哪些函数处理。它输出一个包含数据流信息的数据库,以及一个运行时跟踪。PolyTracker 还提供了一个 Python 库,用于与其输出进行交互并对其进行分析,以及一个交互式 Python REPL。
PolyTracker 可以与 PolyFile 结合使用,以自动确定解析器中函数的语义用途。它还有一个实验性功能,能够生成表示解析器所接受语言的上下文无关文法。
与 Taintgrind 等动态插桩替代方案不同,PolyTracker 对几乎所有输入产生的性能开销都微乎其微,并且能够同时跟踪输入的每一个字节。PolyTracker 最初是 LLVM DataFlowSanitizer 的一个分支,并从 Angora Fuzzer 中汲取了大量灵感。然而,与 Angora 系统不同,PolyTracker 能够跟踪污点的完整来源(provenance)。2021 年 2 月,LLVM DataFlowSanitizer 添加了一项名为 origin tracking(原点跟踪)的新功能来跟踪污点来源。但是,它一次最多只能跟踪 16 个污点,而 PolyTracker 可以跟踪多达 231-1 个。
本 README 是安装 PolyTracker 以及编译/插桩二进制文件的通用使用指南。如需通过其 Python API 以编程方式与 PolyTracker 交互或对其进行扩展,以及处理插桩代码产生的运行时跟踪,请。
PolyTracker 通过一个名为 polytracker 的 Python 脚本来控制。你可以通过运行以下命令来安装它:
pip3 install polytracker
PolyTracker 需要非常特定的系统环境才能运行,因此几乎所有用户都可能需要在容器化环境中运行它。幸运的是,polytracker 让这变得很简单。你只需要安装 docker,然后运行:
polytracker docker pull
以及
polytracker docker run
后一个命令会将当前工作目录挂载到 PolyTracker Docker 容器中,并允许你构建和运行插桩后的程序。
polytracker 控制脚本——你既可以在主机系统上运行,也可以在 Docker 容器内运行——提供了多种命令,既可以用于对程序进行插桩,也可以用于分析生成的产物。例如,你可以探索执行过程中的数据流,重建插桩程序的控制流图,甚至可以提取与程序所接受输入匹配的上下文无关文法。你可以通过运行以下命令来探索这些命令:
polytracker --help
如果在没有命令行参数的情况下运行,polytracker 脚本还是一个 REPL:
$ polytracker
PolyTracker (4.0.0)
https://github.com/trailofbits/polytracker
Type "help" or "commands"
>>> commands
PolyTracker 还附带一个 build 命令。该命令允许用户在任何 Blight 插桩环境中运行构建命令。这将生成一个 blight_journal.jsonl 文件,记录构建期间运行的所有命令。如果你有一个 C/C++ 目标,可以通过调用 polytracker build 并传入构建命令来对其进行插桩:
polytracker build gcc -g -o my_binary my_source.c
要对构建目标进行插桩,请使用 instrument-targets 命令。默认情况下,该命令将使用当前工作目录中的 blight_journal.jsonl 来构建构建目标的插桩版本。插桩后的构建目标将使用与原始构建目标相同的标志进行构建。
polytracker instrument-targets my_binary
build 还支持使用 autotools 或 CMake 等构建系统的更复杂的程序:
polytracker build cmake .. -DCMAKE_BUILD_TYPE=Release
polytracker build ninja
# or
polytracker build ./configure
polytracker build make
然后对构建的任何目标运行 instrument-targets:
polytracker instrument-targets a.bin b.so
然后,a.instrumented.bin 和 b.instrumented.so 即为插桩后的版本。有关实际程序如何被插桩的示例,请参阅 examples 目录中的 Dockerfile。
插桩后的软件会将其输出写入 POLYDB 指定的路径;如果省略,则为 polytracker.tdag。这是一个二进制文件,可以通过运行以下命令来操作它:
from polytracker import PolyTrackerTrace, taint_dag
trace = PolyTrackerTrace.load("polytracker.tdag")
tdfile = trace.tdfile
first_node = list(tdfile.nodes)[0]
print(f"First node affects control flow: {first_node.affects_control_flow}")
# Operate on all Range nodes
for index, node in enumerate(tdfile.nodes):
if isinstance(node, taint_dag.TDRangeNode):
print(f"Node {index}: first {node.first}, last {node.last}")
# Access taint forest
tdforest = trace.taint_forest
n1 = tdforest.get_node(1)
print(
f"Forest node {n1.label}. Parent labels: {n1.parent_labels}, "
f"source: {n1.source.path if n1.source is not None else None}, "
f"affects control flow: {n1.affected_control_flow}"
)
你也可以直接从 REPL 运行插桩后的二进制文件:
$ polytracker
PolyTracker (4.0.0)
https://github.com/trailofbits/polytracker
Type "help" or "commands"
>>> trace = run_trace("path_to_binary", "path_to_input_file")
如有必要,这将自动在 Docker 容器中运行插桩后的二进制文件。
⚠️ 如果在 Docker 或虚拟机中运行 PolyTracker:在虚拟化环境中运行时, 如果输入文件或(尤其是)输出数据库位于从主机操作系统映射或挂载的目录中, PolyTracker 可能会非常慢。在 macOS 主机上的 Docker 中运行 PolyTracker 时 尤其如此。解决方法是将数据库写入容器/虚拟机内部的路径, 然后在最后将其复制到主机系统。
Python API 文档可在此处获取。
在运行时,PolyTracker 插桩会查找通过环境变量指定的一系列配置参数。这使得无需重新编译二进制文件即可修改插桩参数。
PolyTracker 接受以环境变量形式提供的配置参数,以避免重新编译目标程序。PolyTracker 当前支持的环境变量集如下:
POLYDB: A path to which to save the output database (default is polytracker.tdag)
WLLVM_ARTIFACT_STORE: Provides a path to an existing directory to store artifact/manifest for all build targets
POLYTRACKER_TAINT_ARGV: Set to '1' to use argv as a taint source.
POLYTRACKER_STDIN_SOURCE: Set to '1' to use stdin as a taint source.
POLYTRACKER_STDOUT_SINK: Set to '1' to use stdout as a taint sink.
POLYTRACKER_STDERR_SINK: Set to '1' to use stderr as a taint sink.
PolyTracker 将按以下顺序设置其配置参数:
DFSan 使用 ABI 列表来确定应自动插桩哪些函数、应忽略哪些函数,以及存在哪些自定义函数包装器。更多信息请参阅 dfsan 文档。
尝试构建大型软件项目可能非常耗时,尤其是较旧/不受支持的项目。尝试修改构建系统以使其支持像 dfsan/我们的插桩这样的更改则更加耗时。
polytracker/scripts 中有一个脚本,你可以对任何 ELF 库运行它,它将输出一个要忽略的函数列表。当我们不想跟踪通过特定库(如 libpng)或程序的其他子组件的信息时,我们会使用它。Dockerfile-listgen.demo 用于构建常见的开源库,以便我们可以创建这些列表。
该脚本是 DataFlowSanitizer 所附脚本的略微调整版本,其重点是忽略系统库。原始脚本可以在 dfsan_rt 中找到。
检出此 Git 仓库。从根目录开始,可以构建基础的 PolyTracker Docker 镜像:
pip3 install -e ".[dev]" && polytracker docker rebuild
或者直接从 DockerHub 拉取最新的预构建版本:
docker pull trailofbits/polytracker:latest
要演示 PolyTracker 在 MuPDF 解析器上的运行,请运行以下命令:
docker build -t trailofbits/polytracker-demo-mupdf -f examples/pdf/Dockerfile-mupdf.demo .
mutool_track 将在 /polytracker/the_klondike/mupdf/build/debug 中构建。运行 mutool_track 将输出 polytracker.tdag,其中包含污点分析提供的信息。
要演示 PolyTracker 在 Poppler utils 0.84.0 版本上的运行,请运行以下命令:
docker build -t trailofbits/polytracker-demo-poppler -f examples/pdf/Dockerfile-poppler.demo .
所有 poppler utils 将位于 /polytracker/the_klondike/poppler-0.84.0/build/utils。
cd /polytracker/the_klondike/poppler-0.84.0/build/utils
./pdfinfo_track some_pdf.pdf
假设你想更深入地扩展 PolyTracker 代码库或分析 TDAG 跟踪,但又不想通过安装高度定制的 LLVM 版本来搞乱本地环境。
如果你在 Ubuntu 上工作,并且从相对干净的 22.04 或 24.04 基础系统开始,链接的 Gist 详细介绍了获取可用的 PolyTracker 基础容器直通版本的步骤。基础容器提供了一个包含所有依赖项的开发环境,你可以直接在其中工作,也可以进行扩展(正如我们在示例 Dockerfile 中所做的那样)。
Python 和 C++ 单元测试都应在 PolyTracker Docker 容器内运行。
unittests/ 中的 Catch2 单元测试位于容器内的 /polytracker-build/unittests/src/taintdag/。在 Docker 容器内使用以下命令运行测试二进制文件:
cd /polytracker-build/unittests/src/taintdag/ && ./tests-taintdag
tests/ 中的 Python 单元测试需要测试夹具将插桩的本地测试 C++ 程序。使用 Pytest 在 working 中运行它们
pytest tests
或者使用 pytest 运行单个测试文件:
pytest tests/test_foo.py
PolyTracker 目前仅在 Linux 上运行,因为这是 DataFlowSanitizer 唯一支持的系统。此限制只是因为缺乏对其他操作系统系统调用语义的支持,未来可能会添加这些支持。然而,这意味着在非 Linux 系统上运行 PolyTracker 将需要安装 Docker。
污点不会通过动态加载的库传播,除非这些库是使用 PolyTracker 从源代码编译的,或者 PolyTracker 中实现了对这些库调用的特定支持。目前_确实_支持通过大多数未插桩的 C 标准库调用传播污点。需要说明的是,使用未插桩函数的程序仍然可以正常运行,但是,由不受支持的库调用执行的操作将不会传播污点。我们目前正在致力于为 C++ 程序添加健壮的支持,但目前效果最好的是 C 程序。
如果 Docker 出现问题,请尝试执行系统清理(system prune),并为 PolyTracker 和你尝试运行的任何演示使用 --no-cache 进行构建。
当内存中的单个字节同时被源文件中的大量输入字节污染时,PolyTracker 的性能会达到最差情况。这在插桩具有较大块大小的压缩和加密算法时最为常见。目前正在研究和开发针对此行为的多种缓解措施。
以下是我们使用 PolyTracker 所做的一些公开成果。如果你知道还有其他内容希望列在这里,请告诉我们!
mapping 和 cavities)跟踪分析功能定位了一个 CVE,并在 Trail of Bits 博客上撰文介绍。这项研究由 Trail of Bits 开发,资金来自国防高级研究计划局(DARPA)的 SafeDocs 项目,并作为 Galois 的分包商。它根据 Apache 2.0 许可证 获得许可。© 2019, Trail of Bits。
请使用 [email protected] 联系我们。