为什么我做DFTK,而不是继续收集脚本工具
摘要
传统电子取证工具成熟但固化,难以适配大模型、Agent、本地向量库等新型AI取证场景,从业者普遍存在工具杂乱、临时脚本多、无法标准化复用的痛点。本文介绍开源工具链DFTK,一款面向AI时代的模块化数字取证工具库,用于补齐传统取证盲区,标准化AI取证研判流程。
我磁盘里有个文件夹,叫 Toolkit。
里面就是各种各样的脚本工具。从我入门CTF/电子取证开始,各种工具就在往里塞。从咸鱼买的整合包到自己去收集下载的工具脚本,工具数量越来越多、越来越杂。
这个文件夹不是像科技大牛电脑里整整有条、赏心悦目的那种。更像从没打扫过:GitHub 扒下来的 release、打比赛AI临时糊的 Python、各路师傅们发来的 exe、几个早忘了干啥用的 jar,外加一堆名叫 new、final、fix 的文件夹。我到现在可以说有一半不知道到底有啥用。
真正烦我的不是它占了多少硬盘,是在碰到赛题时,同一句话越来越频繁地冒出来:
我记得以前有个脚本能干这个。
接下来通常不是分析,而是找脚本。
找到以后再确认 Python 版本、补依赖、看 README、回忆参数。运气不好,工具本身已经几年没更新;运气更不好,找到的是自己写的脚本,而且当时觉得"这种东西不用写说明,过几个月肯定还记得"。
当然不会记得。
有一段时间,我的"工具积累"大概长这样:
tools/
├── apk/
├── sqlite/
├── windows/
├── pcap/
├── misc/
├── misc2/
├── old/
└── ...../工具越来越多,能力却从没稳下来。反而这种整整有条的收集越来越乱,后面就干脆直接乱丢了。
收集的是代码,不是能力
一个脚本跑通过一次,和"我拥有这个能力",中间差得远。
"它跑通过一次" 和 "我随时能再用它",隔着的不是一行命令,而是一整套你早就忘了的前提。
拿 SQLite 说。我手上同时能有好几个相关工具:查表的、看 WAL 的、恢复删除记录的、做全文搜索的,还有一个当年为某道赛题魔改过的。真碰上检材,我还是得重新想用谁、怎么喂、输出怎么看。
乱、杂、旧。这是最贴切的三个形容。
EVTX、Windows Registry 等等脚本都是一个德行。
这些工具单独都没错。错在它们互相不认识,人得坐在中间当胶水:
文件 → 判断格式 → 找工具 → 改参数 → 看结果 → 再找下一个工具做一次没啥。做几十次,烦躁感就来了。
DFTK 的灵感就是从这儿冒出来的。没有"构建下一代数字取证基础设施"那种宏大开场,我就是想把那些真的会反复用到的脚本、能力,变得干净一点。
我的想法其实很简单。
先从工具入口开始。我受不了每半年重新记一次:这个工具是 -f,那个是 --input,另一个把输出目录放第二个位置。理想状态当然不是所有功能都长成一个命令,但常用的东西至少得有个稳定入口——能查、能发现,半年后回来不用重新考古。
我就开始做了。
命令统一只是最浅的一层
一开始我以为把 CLI 统一了,问题就解决大半。很快打脸了。
真正难搞的是输出。
一大堆取证脚本的输出,本来就是写给人坐在终端前看的:
[+] Found URL: https://example.com/api人看到这行,自然知道啥意思,想继续查也能自己复制。程序不行。程序起码还想知道:URL 从哪个文件来的;是结构化字段、字符串扫描还是 carving 捞的;在文件里什么位置;工具跑完没有;没结果到底是"确实没有"还是 parser 压根没干活。
这几个问题一摆出来,print() 就不够看了。
我后来在 DFTK 上耗掉不少时间,不是在写更聪明的 parser,而是在伺候这些"无聊"的东西:结果结构、错误状态、来源、locator、能力声明。这类代码演示起来特别吃亏——没有能让人"哇"的页面,多一个错误枚举也不会让截图更好看。但半年以后,真正决定一个工具还能不能继续接东西的,往往就是这些地方。
比如一个 SQLite 模块因为可选依赖没装,一条记录都没返回。如果上层只拿到:
{"success": true, "records": []}那问题就很大了。"没有记录"和"没完成检查"完全不是一回事。人盯着终端时会替工具补上这个语义;自动化系统不会。
Luduan Agent 接入让问题更加明显了
DFTK 一开始根本不是给 Agent 做的。
直到我尝试将DFTK接入 Luduan 甪端电子取证智能体,才发现以前那些"人看一眼就懂"的接口,丢给 Agent 会被放大成很难看的问题。
人看到一个命令空输出,可能会想:范围错了,换方法。Agent 看到:
{"ok": true, "output": ""}它很可能只记住前半句:成功。然后下一轮沿着原策略继续跑。
在luduan的一个任务中我碰到了这个问题。Agent的动作一个接一个,工具也几乎都正常返回,终端一直在动,看着挺忙。最后状态文件里:
facts.jsonl 0
claims.jsonl 0
evidence.jsonl 0那一刻再回头看 DFTK,很多设计突然有了更硬的理由。不是什么"为了 AI Ready"——这词我自己都不太喜欢。只是如果工具连"刚才到底发生了什么"都说不清,上面不管是人、脚本还是 Agent,都只能猜。
一个工具如果讲不清"刚才到底发生了什么",那它上面无论是人、脚本还是 Agent,都只能靠猜。
不再重新造轮子
工具箱项目很容易滑到另一个极端:既然要统一,就什么都自己写。但是我懒得这样做了。
The Sleuth Kit、Volatility,还有那些成熟的 Registry、EVTX、文件系统和二进制分析库,已经把一堆很难的问题解决了。为了让仓库显得"纯自研"再写一遍,除了多生 bug,我想不出太多好处。
我反而越来越愿意写胶水。这词没"框架"好听,但准。已有能力靠谱就接进来,缺的自己补。真正长期维护的,是外层那套约定:输入是什么、能力怎么发现、失败怎么描述、结果怎么引用、能不能继续组合。
一个成熟工具吐一段文本,我要做的往往不是重写 parser,而是给它补一层稳当的适配。
这也解释了 DFTK 和 scripts/ 之间我现在最在意的区别。如果项目最后只是:
dftk/
├── apk.py
├── sqlite.py
├── pcap.py
└── registry.py那我只是把以前的工具目录换了个名字。我想多出来的,是那些脚本之间原本缺的东西:稳定身份、统一错误、可追溯结果、能力发现,以及以后能被 CLI、Web、Agent 同时调用的接口。
不是所有模块都得很大。我反而更喜欢小的 capability——一个东西干一件事,边界清楚,上层自己组合。
临时脚本反而成了主流
AI赋能的时代来临,在AI决策中很多小任务是直接写成临时脚本去做的。人其实也应该一样。
有时 grep 就够了,有时十几行 Python 明显比拉起一整套工具链快。这不跟 DFTK 冲突。我现在把代码分得更开:这次题专用的,跑完能扔;第二次、第三次又碰上、而且输入输出已经稳了的,再考虑收进长期工具。
不是每段代码都值得产品化。DFTK 也不该变成另一个更大的代码垃圾桶。
这大概是我做这项目以后反而更确定的事。以前碰上一个好脚本,我的动作是下载、收藏。现在如果它真解决了我反复撞上的问题,我会多想一步:
这个能力,半年后还能不能直接用?
如果答案还是"等下,我先找找 README"——那它大概率还只是个我收藏过的程序,不是一项我真正拥有的能力。而能力能不能被 Agent 复用,又是另一笔更麻烦的旧账了。
结语
DFTK 现在已经定位为“Agent工具”,从而适配当前AI赋能下的潮流。
我已经为其做好了全面接入Agent框架的准备。
如果感兴趣可以自行体验:DFTK-Github