news 2026/10/14 2:53:22

SavvyCAN 文件对比窗口(File Comparison)实战指南:用 CAN 日志差分定位未知信号

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SavvyCAN 文件对比窗口(File Comparison)实战指南:用 CAN 日志差分定位未知信号
  • 开发工具
  • 逆向工程
  • 嵌入式

【免费下载链接】SavvyCAN

QT based cross platform canbus tool

项目地址:https://gitcode.com/gh_mirrors/sa/SavvyCAN
点击查看免费下载

SavvyCAN 的 File Comparison(文件对比)窗口是一个面向逆向工程场景的 CAN 日志差分工具:它把一批"参考文件"(reference files)的所有报文汇入同一个"帧桶",再与一个"关注文件"(file of interest)逐 ID 对比,找出只在某一边出现的 ID、只在某一边置位的 bit,以及只在某一边出现的数据值与 DBC 信号取值。本文基于仓库中的官方文档 help/filecomparison.md 与源码 re/filecomparatorwindow.cpp 编写,读完你将掌握该窗口的完整操作流程、差异列表三层结构的读法,以及如何用它从海量 CAN 流量中定位顽固的未知信号。

文件对比窗口的用途:用"背景噪音"反衬出目标信号

文件对比窗口的核心思想是把日志分成两侧做差分:

  • Side 1(关注文件,File of interest):只有一个文件,是你要重点研究的那个捕获。
  • Side 2(参考文件,Reference frames):可以加载任意多个文件,程序不会逐个文件分别列出,而是把所有这些文件里的报文全部倾倒进同一个"帧桶"(bucket)里,合成一个统一的参考集合。

因此你可以一次性加载一批文件,然后与唯一的那一个"关注文件"做对比。对比要回答的问题非常具体:

  1. 有没有只在某一侧出现的 ID?
  2. 对于两侧都出现的 ID,有没有只在某一侧被置位的 bit?
  3. 对于两侧都出现的 ID,有没有只在某一侧出现过的数据值或信号值?

这套机制最经典的实战用法,是制造"背景噪音"来反衬出你苦苦寻找的那个信号。文档给出的示例是寻找换挡信号(gear shift signal):

  1. 长时间怠速行驶、让车辆长时间空转,捕获一大批"背景"流量——但绝不做你要找的那个动作(不换挡)。
  2. 再进行第二次捕获,期间做几次你要找的动作(换挡几次)。
  3. 把第二次捕获作为"关注文件",把第一次的大批量背景捕获作为"参考文件",运行对比。
  4. 两边的差异里,就应该藏着那个你始终找不到的换挡信号。

这样得到的候选列表远比"大海捞针"式地逐帧翻日志要窄得多。凡是你能"先抓一段不含目标行为的基线、再抓一段含目标行为的捕获"的场景,都可以套用这个方法——例如定位车门开启、踩刹车、切灯等任何只在特定时刻出现的信号。

界面布局与两侧文件的操作

窗口由 ui/filecomparatorwindow.ui 定义,整体分为上下两部分。

上方:两侧文件选择区

上方是两个并排的区域,中间用一条竖直分隔线隔开:

  • Side 1:显示 "Single file to compare to side 2:",下方有一个显示已加载关注文件名的标签(lblFirstFile)和Load New File按钮(btnInterestedFile)。点击后通过FrameFileIO::loadFrameFile()弹出文件选择对话框,选中的文件名会显示在标签上(见 re/filecomparatorwindow.cpp)。
  • Side 2:显示 "One or more files to compare with the single file on side 1:",包含Load A File按钮(btnLoadRefFile)、Clear Frames按钮(btnClear)和显示 "Loaded frames: N" 的帧计数标签(lblRefFrames)。每点一次Load A File就向参考帧桶追加一个文件,帧计数随之累加;Clear Frames会把参考帧桶清空、同时清空结果树(见 re/filecomparatorwindow.cpp)。

文件加载复用 SavvyCAN 全局的FrameFileIO框架,它具备自动探测格式的能力:程序会通过一系列isXxxFile()预扫描函数判断文件类型,再调用对应的loadXxxFile()加载,支持的格式包括 CRTD、原生/通用 CSV、Log、Microchip、Trace、IXXAT、CANdo、Vehicle Spy、canDump、Lawicel、PCAN、Kvaser、CANalyzer ASC/BLF、CARBUS Analyzer、CANHacker、Cabana、CANopen、Tesla AP、CLX000、CANserver、Wireshark 等(完整清单见 framefileio.h)。也就是说,你手头的各种格式 CAN 日志基本都能直接拖进来对比,无需预先转换。

下方:结果树与导出按钮

下方是一棵结果树(treeDetails,单列显示)、一个Show only data unique to Side 1复选框(ckUniqueToInterested)和一个Save Details to File按钮(btnSaveDetails)。

  • 勾选 "Show only data unique to Side 1" 后,结果树只显示关注文件独有的信息:仅关注文件出现的 ID、仅在关注文件侧置位的 bit、仅在关注文件侧出现的值。参考文件独有的一切都会被隐藏。从源码看,uniqueInterested为真时会跳过 "IDs found only in Side 2" 顶层节点、参考侧 bit 子树和参考侧值子树(见 re/filecomparatorwindow.cpp 与 #L380-L436),适合你只想快速确认"目标行为带来了什么新东西"时使用。
  • Save Details to File会弹出保存对话框,把结果树按层级缩进导出为 UTF-8 文本文件;若文件名不带扩展名会自动补.txt(见 re/filecomparatorwindow.cpp)。

另外两点体验细节:窗口支持 F1 键随时呼出本文档对应的帮助页(见 re/filecomparatorwindow.cpp);在"偏好设置"中勾选恢复窗口位置后,窗口尺寸与位置会按FileComparator/WindowSize、FileComparator/WindowPos键保存并在下次打开时恢复(见 re/filecomparatorwindow.cpp)。

差异列表的三层树结构

计算完成后,结果树会呈现三个顶层节点(当勾选 "Show only data unique to Side 1" 时第二个节点被隐藏),对应三种差异类别。

1. IDs found only in (仅在关注文件中出现的 ID)

子节点是每一个只在关注文件里出现、而在所有参考文件中从未出现的 ID。这是"目标行为"最直接的候选区——例如换挡测试捕获里出现的某个 ID,怠速背景流量里根本没有它。

2. IDs found only in reference frames(仅在参考帧中出现的 ID)

按文档的提示,"理论上这个列表应该相当小"——列出的是那些在关注文件里从未见过的 ID。如果这个列表异常庞大,通常意味着两次捕获的工况差异过大(比如参考文件里包含了另一个总线或另一套功能模块的流量),需要审视捕获方案。由于它的目的是提醒你"参考侧还有这些没对上号的 ID",在只看关注文件独有内容时会被隐藏。

3. IDs found only on both sides(两侧都出现的 ID)

这是最有信息量的区域:两侧共同出现的每个 ID 是一个子节点(节点文本为十六进制 ID,若当前加载了 DBC 且能匹配到消息,还会附上(消息名)),每个 ID 节点下再按三类差异展开:

  • Bits set only in / Bits set only in Side 2:按 bit 粒度列出只在某一侧被置位过的位。源码中对每个帧把 8 个数据字节按bit = 字节值 << (8 * 字节下标)的方式逐字节累积到一个 64 位bitmap上(见 re/filecomparatorwindow.cpp),最终得到"该 ID 在两侧各自所有帧中出现过的所有 bit 的并集",然后逐位做(interestedBits & 1) ^ (referenceBits & 1)式异或,把只在单侧置位的 bit 找出来(见 #L388-L408)。bit 节点的文本形如7 (0:7),即"第 7 位(字节 0 的第 7 位)",方便你直接换算到数据字节的哪个位。注意:这是"曾出现过的位的并集"比较,而非逐帧位翻转比较,所以它回答的是"这个 bit 在两侧是否都出现过",而不是"两侧的 bit 状态是否不同"。
  • Byte N → Values found only in / Values found only in Side 2:按字节(0~7)分组,列出该字节上只在某一侧出现过的取值。源码为每个 ID 维护values[8][256]统计矩阵,values[字节][取值]记录该字节取到某个 0x00~0xFF 值的次数(见 re/filecomparatorwindow.cpp);比较时只要一侧出现次数 >0 而另一侧为 0,就判定为该侧独有值(见 #L424-L437)。如果一个数据字节在关注文件里出现过参考文件没有的值,它就很可能是承载目标信号的字节,而这个新值就是候选信号值。
  • Signal <信号名> → Values found only in / Values found only in Side 2:如果两侧 ID 对应的 DBC 消息里存在信号,并且信号能解析出文本值,程序会把每个信号出现过的文本值收集到signalInstances哈希表中(见 re/filecomparatorwindow.cpp),再对比两侧,列出只在某一侧出现过的信号值。这是把差分能力从"原始字节"提升到"语义信号"的关键一层——你不仅能知道哪个字节变了,还能直接看到某个 DBC 信号在目标行为发生时出现了哪些新取值,这些取值很可能就是你要找的未知信号。

底层原理:两遍扫描 + 三类统计量

从源码可以清晰看到对比算法的整体流程(re/filecomparatorwindow.cpp):

  1. 数据准备阶段:分别遍历关注帧(interestedFrames)和参考帧(referenceFrames)两个QVector<CANFrame>,对每个 ID 构建一个FrameData(见 re/filecomparatorwindow.h):
    • bitmap:64 位位图,标记该 ID 所有帧中哪些 bit 曾被置位(最多覆盖 8 字节);
    • values[8][256]:每个字节上各取值的出现次数;
    • signalInstances:每个 DBC 信号出现过的文本值集合。 DBC 消息查找通过DBCHandler::getReference()获取的全局 DBC 处理器完成,信号解析复用DBC_SIGNAL::processAsText(),因此只有当前已加载并匹配的 DBC 才会产生信号层对比。
  2. 逐 ID 归类:遍历关注文件的所有 ID,凡在参考集合中不存在的归入顶层节点 1;存在的则进入节点 3,并用上面的三类统计量生成 bit、字节取值、信号取值三个维度的差异子节点。
  3. 反向补全:遍历参考文件的所有 ID,把关注文件中没出现过的归入顶层节点 2。
  4. 交互反馈:由于日志可能很大,计算期间会显示一个无进度条的模态"Calculating differences"对话框,并在处理中周期性调用qApp->processEvents()保持界面响应(见 re/filecomparatorwindow.cpp)。

结果树默认不自动展开;若在偏好设置中勾选了 "Auto-expand"(对应设置键InfoCompare/AutoExpand,见 mainsettingsdialog.cpp),计算完成后会自动expandAll()展开全部节点(见 re/filecomparatorwindow.cpp)。

实战操作流程:完整步骤

结合文档与源码,一次完整的对比操作如下:

  1. 从主窗口菜单栏RE Tools → File Comparison打开文件对比窗口(对应动作actionFile_Comparison,见 ui/mainwindow.ui 与 mainwindow.cpp)。
  2. 点击Load New File,选择包含目标行为的"关注文件"(如换挡测试捕获)。
  3. 点击Load A File一次或多次,把不含目标行为的"背景"日志(如怠速捕获)全部加入参考帧桶;窗口会实时显示 "Loaded frames: N"。每加载完一个文件,只要两侧都有帧,程序就会自动重新计算差异。
  4. 阅读结果树的三层节点:先看"仅在关注文件中出现的 ID",再看两侧共有 ID 下的 bit / 字节取值 / 信号取值差异,圈定候选信号。
  5. 若只想关注关注文件的新增内容,勾选Show only data unique to Side 1重新聚焦。
  6. 点击Save Details to File把完整差异树导出为文本,便于存档或在其他工具中继续分析。
  7. 如需换一组背景,点击Clear Frames清空参考帧桶重新开始。

操作提示:对比前建议先通过 DBC 管理器加载与总线匹配的 DBC 文件,否则两侧共有 ID 下将只有 bit 和字节取值两层,缺少信号层差异,信息量会明显下降。

与其他 RE 工具的协同定位

文件对比窗口定位出"嫌疑 ID/bit/值"之后,可以继续用 SavvyCAN 的其他逆向工具接力验证:用 Flow View 观察嫌疑 ID 在时间轴上的出现规律,用 Frame Data Analysis 查看该 ID 的统计细节,用 Graph 工具把嫌疑信号画成曲线确认它是否随目标行为变化,用 DBC Editor 把新信号定义进 DBC 后再次回到文件对比窗口验证信号层差异。这样"日志差分圈定候选 → 信号级验证确认"的闭环,是 SavvyCAN 面向 CAN 逆向的标准打法。

  • 开发工具
  • 逆向工程
  • 嵌入式

【免费下载链接】SavvyCAN

QT based cross platform canbus tool

项目地址:https://gitcode.com/gh_mirrors/sa/SavvyCAN
点击查看免费下载

相关推荐

上一篇:猫抓插件完整指南:如何用免费开源工具轻松嗅探浏览器资源
下一篇:OpenCore Simplify:5分钟完成黑苹果EFI配置的终极工具

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 2:52:55

Java实现华容道自动求解:BFS与A*搜索算法实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/14 2:52:13

Mac Mouse Fix 指南:让 10 美元鼠标好过触控板

Mac Mouse Fix 指南&#xff1a;让 10 美元鼠标好过触控板 【免费下载链接】mac-mouse-fix Mac Mouse Fix - Make Your $10 Mouse Better Than an Apple Trackpad! 项目地址: https://gitcode.com/GitHub_Trending/ma/mac-mouse-fix Mac Mouse Fix 是一款开源的 macOS 鼠…

作者头像 李华
网站建设 2026/10/14 2:52:12

脚本黑客进阶:从Shell底层机制到生产级自动化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/14 2:51:44

用Shader在Cocos Creator中程序化生成魔法阵,告别序列帧动画

之前做项目里的战斗技能时&#xff0c;碰到了一个挺常见又挺烦的需求&#xff1a;要给角色脚下的召唤阵法加一点动态效果。美术那边最开始给的方案是一套序列帧&#xff0c;特效同学做了一个月的8方向循环播放&#xff0c;结果包体大了不少&#xff0c;真机上帧率还波动。后来我…

作者头像 李华
网站建设 2026/10/14 2:51:37

Windows Defender:设置扫描 CPU 占用目标

适用&#xff1a;Windows 10 / Windows 11 家庭版(Home)。目的&#xff1a;把 Microsoft Defender 扫描期间的平均 CPU 占用目标设为 20%&#xff0c;无需关闭防病毒保护。 注意&#xff1a;20% 是扫描引擎的平均 CPU 负载目标&#xff0c;不是严格上限&#xff1b;短时间可能超…

作者头像 李华