4、Diff工具深度使用:GNU Diff、Colordiff、Vimdiff、Beyond Compare对比技巧

做补丁分析,说白了就是找不同。但怎么找、用什么找,差别可大了去了。

我刚开始做漏洞分析那会儿,只会用 diff -u 看个大概。后来有一次,一个关键补丁里藏了个变量类型转换的漏洞,我愣是没看出来。为什么?因为普通 diff 只告诉我「这行变了」,但没告诉我「这行是怎么变的」。从那以后,我开始认真研究各种 diff 工具。

今天我就把这几把刷子都抖搂出来。GNU Diff、Colordiff、Vimdiff、Beyond Compare,各有各的脾气,也各有各的绝活。

4.1 GNU Diff:命令行下的基本功

GNU Diff 是 Linux 下的标配,也是所有 diff 工具的祖宗。你别看它长得丑,功能其实很扎实。

我个人最常用的几个参数:

  • -u:上下文格式,显示改动前后几行。比默认格式清晰十倍。
  • -r:递归比较目录。补丁包经常是一堆文件,这个必须用。
  • -N:把新增文件当成空文件来比较。不然新文件会直接被忽略。
  • -w:忽略空白差异。有些补丁只是改了缩进,用这个能过滤噪音。

举个例子,比较两个版本的补丁目录:

diff -urN patch_v1/ patch_v2/

嗯,这里要注意。如果你只写 diff -r,输出会乱成一锅粥。加上 -u 之后,每段差异前面都有文件名和行号,一眼就能定位。

我的小技巧: 把 diff -urN 设成别名。我习惯在 .bashrc 里写 alias diff='diff -urN',省得每次敲一堆参数。

4.2 Colordiff:给黑白世界加点颜色

GNU Diff 的输出是黑白的。看多了眼睛疼,尤其是几百行的补丁,找差异点跟大海捞针似的。

Colordiff 就是干这个的。它本质上是个 Perl 脚本,把 diff 的输出染上颜色。新增的行是绿色,删除的行是红色,上下文是默认色。

安装很简单:

sudo apt install colordiff   # Debian/Ubuntu
sudo yum install colordiff   # CentOS/RHEL

用法更简单,直接把 diff 换成 colordiff:

colordiff -urN patch_v1/ patch_v2/

我曾经在分析一个内核补丁时,用 colordiff 一眼就发现了一个被删除的空行——那个空行原本是某个宏定义的结尾。补丁作者删了它,导致宏定义范围变了,引发了一连串的编译错误。这种细节,黑白 diff 根本看不出来。

注意: Colordiff 只是给输出染色,它本身不做比较。比较逻辑还是 GNU Diff 那一套。所以该加的参数一个都不能少。

4.3 Vimdiff:在编辑器里直接对比

如果你跟我一样,大部分时间泡在 Vim 里,那 Vimdiff 就是你的神器。

启动方式:

vimdiff file1.c file2.c

或者先打开一个文件,再执行:

:vertical diffsplit file2.c

Vimdiff 最牛的地方是什么?是同步滚动和差异跳转。你滚动左边,右边跟着动。按 ]c 跳到下一个差异点,按 [c 跳到上一个。这比肉眼一行行扫快多了。

我个人习惯的用法:

  • 先用 :diffupdate 刷新比较结果。有时候改了文件,Vim 不会自动重算差异。
  • 用 zo 和 zc 折叠/展开代码块。只看有差异的部分,省得被无关代码干扰。
  • 按 dp 把当前差异「推」到另一边。这个在合并补丁时特别好用。

举个例子。有一次我在分析一个安全补丁,左边是旧代码,右边是新代码。按 ]c 跳了七八次,突然发现一个差异点:新代码里多了一个 if (ptr == NULL) return -EINVAL;。旧代码里没有这个检查。嗯,这就是漏洞点——空指针解引用。

核心思路: Vimdiff 适合「细嚼慢咽」式的分析。你可以一边看差异,一边在脑子里模拟代码执行路径。这是命令行 diff 做不到的。

4.4 Beyond Compare:图形化对比的王者

说到图形化对比工具,Beyond Compare 是我用过最顺手的。虽然它收费,但值那个价。

它有几个功能,是命令行工具完全没法比的:

功能 说明 我的用法
三路合并 同时对比三个版本(原版、你的修改、他的修改) 分析补丁冲突时,一眼看出谁改了哪里
语法高亮 根据语言类型着色,差异点用颜色块标出 看 C 代码时,变量类型、函数名一目了然
文件夹对比 递归对比目录结构,显示新增/删除/修改的文件 分析大型补丁包时,先看文件级差异,再深入看代码
差异统计 显示每个文件有多少处差异,总共有多少行变化 快速评估补丁的「影响范围」

我印象最深的一次,是分析一个 Android 安全补丁。那个补丁改了 30 多个文件,用 Beyond Compare 打开,左边是旧版,右边是新版。我先把文件夹对比打开,发现有个文件是新增的——security/patch_manager.c。点进去一看,好家伙,整个文件都是新写的,里面有个权限检查的逻辑漏洞。如果只用命令行 diff,我可能根本不会注意到这个新增文件。

避坑指南: 我曾经犯过一个错——直接用 Beyond Compare 的「复制到右边」功能合并补丁,结果把注释也复制过去了,导致编译报错。后来我学乖了:合并之前,先手动检查每一处差异,确认没有「误伤」。

4.5 实战对比:选哪个?

你可能会问:这么多工具,到底用哪个?

我的建议是:

  • 快速扫一眼:用 Colordiff。几秒钟出结果,适合初步判断补丁大小。
  • 深入分析代码逻辑:用 Vimdiff。同步滚动 + 差异跳转,效率最高。
  • 处理大型补丁包:用 Beyond Compare。文件夹对比 + 三路合并,没有对手。
  • 写脚本批量对比:用 GNU Diff。配合 grep、awk 做自动化分析。

说白了,没有最好的工具,只有最合适的场景。我自己的习惯是:先用 Colordiff 扫一遍,看看补丁改了哪些文件、大概改了多大。然后用 Vimdiff 逐个文件深入分析。如果遇到特别复杂的合并场景,再请出 Beyond Compare。

嗯,工具是死的,人是活的。关键不是你用哪个工具,而是你能不能从差异中看出漏洞的蛛丝马迹。下一章,我会讲怎么从补丁的「上下文」里挖出隐藏的漏洞——那才是真正的硬功夫。