一句话概括:OBD-II 是每辆车都有的诊断插座,CAN 总线是车上各个 ECU 之间传递指令的内部网络。把一根线接到 OBD 口,你就能看到这辆车”说话”的内容。本文从硬件采购讲到 Linux 抓包,再到把一堆十六进制读成”车速 60km/h、转速 1726rpm”,最后落到安全防护与合规要求。
⚠️ 请先读这一段,再往下看
汽车安全是授权制领域,不是”技术中立”。
- 只对你本人名下的车辆、或取得书面授权的车辆/实验台架动手;
- 不要在公共道路、他人车场、租赁车、二手待售车上做任何测试;
- 抓包阶段只监听、不发送(listen-only),本文所有发送命令都在虚拟总线或台架上演示;
- 绝不修改里程表、防盗系统、排放数据——这已经不是技术问题,是刑事问题;
- 车辆在行驶中不要插拔 OBD 设备,误发帧可能导致动力/制动系统进入保护状态。
本文第 11 节给出的 ICSim 方案零风险,建议先在虚拟环境把流程走通,再碰真车。
一、为什么 2026 年值得学汽车安全
三件事同时发生了,把这个方向推到了台前。
第一,攻击面外扩。传统汽车的安全边界就是那个 OBD 口——想攻击得先物理接触。现在 T-Box、蓝牙钥匙、手机 App、OTA 升级、V2X 通信全都连上来了。2023 年以后的量产车,单车 ECU 数量普遍在 70 到 150 个之间,信号总量以万计,CAN/CAN-FD 依然是车身与动力域的主干。
第二,法规强制。联合国 UN R155(网络安全)与 UN R156(软件升级)2022 年 7 月起对新车型强制,2024 年 7 月起覆盖所有新下线车辆,配套的 ISO/SAE 21434 成了主机厂和 Tier1 的流程标准。国内对应的 GB 44495-2024《汽车整车信息安全技术要求》和 GB 44496-2024《汽车软件升级通用技术要求》于 2024 年 8 月 23 日发布,自 2026 年 1 月 1 日起正式实施——也就是现在。
第三,入门成本极低。一套能用的硬件两百块上下,软件全免费开源。对比移动端要脱壳、要过反调试,CAN 总线这个入口干净得像是二十年前的 Web——没有鉴权、没有加密、没有签名,谁在总线上谁就能发言。
💡 学习路径建议
物理层 → 抓包工具 → 帧语义 → 诊断协议(ISO-TP / UDS)→ 逆向方法论 → 攻击面与防护。前四步两三个晚上就能走完,真正花时间的是第五步:从”能看懂帧”到”能定位某个功能对应哪几条 ID”。
二、60 秒搞懂 CAN 总线
2.1 物理层:两根线的差分信号
高速 CAN(HS-CAN)用的是一对双绞线,叫 CAN-H 和 CAN-L。它不是靠对地电压判断 0 和 1,而是靠两条线的电压差。
| 状态 | CAN-H | CAN-L | 差分电压 | 逻辑值 |
|---|---|---|---|---|
| 隐性(Idle / 空闲) | ≈2.5V | ≈2.5V | ≈0V | 1 |
| 显性(Dominant) | ≈3.5V | ≈1.5V | ≈2V | 0 |
差分传输的好处是共模干扰会被抵消——发动机点火、电机逆变器产生的噪声同时叠加在两根线上,做减法就消掉了。这也是 CAN 能在电磁环境极差的发动机舱里活到今天的原因。
总线两端各要接一个 120Ω 终端电阻,用于吸收信号反射。两端并联后,你断电用万用表量 OBD 口 6 脚与 14 脚之间,读数应该在 60Ω 左右。如果量到 120Ω,说明有一端断路;量到无穷大,说明这条 CAN 根本没接到 OBD 口(有些车型的诊断 CAN 和动力 CAN 是分开的)。
2.2 帧结构:一帧最多 8 个字节
经典 CAN 一帧的结构如下,标准帧(11 位 ID)全长 108~111 位左右(含位填充):
| SOF | ID | RTR | IDE | r0 | DLC | Data | CRC | ACK | EOF | IFS |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 bit | 11 bit | 1 bit | 1 bit | 1 bit | 4 bit | 0~8 字节 | 16 bit | 2 bit | 7 bit | 3 bit |
三个关键点:
- ID 决定优先级,不是决定目的地。CAN 是广播总线,每一帧所有节点都能收到。ID 越小(二进制里显性位越多)优先级越高。两个节点同时发,低 ID 的赢,输的那个自动重发——这叫非破坏性仲裁,不会丢数据。
- 没有源地址,也没有目标地址。接收方靠 ID 过滤,靠 DLC 和负载内容的约定解释含义。这个约定就是后面要讲的 DBC 文件。
- CAN-FD 是升级版。数据段最多 64 字节,速率可到 5Mbps(仲裁段仍用低速保证兼容)。新势力车型上已经大量使用,但本文先讲经典 CAN,原理一致。
2.3 速率
动力/底盘域通常是 500 kbps,车身舒适域常见 250 kbps 或 125 kbps,少数老车用 33.333 kbps。速率必须精确匹配,差一点就一个字节都收不到——这是新手最常踩的坑。
三、硬件怎么买
核心原则:要能收发任意帧,不要买 ELM327。
| 设备 | 芯片/方案 | 能否监听任意帧 | 参考价 | 评价 |
|---|---|---|---|---|
| ELM327(各种克隆版) | STN1110 / PIC 克隆 | ❌ 只做标准 PID 轮询 | ¥30~60 | 只能读故障码和少量 PID,玩不动抓包。别买。 |
| CANable 2.0 / M8 | gs_usb(candleLight 固件) | ✅ | ¥150~300 | 入门首选,Linux 免驱,插上就是 can0 |
| USB2CAN(国产) | 各家自研 | ✅ | ¥100~200 | 便宜好用,注意要装厂商驱动 |
| CANalyst-II / ZLG USBCAN | 国产专业方案 | ✅ | ¥300~800 | 稳定性好,Windows 工具链成熟 |
| PCAN-USB / Kvaser | PEAK / Kvaser | ✅ | ¥1500+ | 工业级,时序精度高,做研究/写报告用 |
| 树莓派 + MCP2515 HAT | SPI 转 CAN | ✅ | ¥200~400 | 适合做车载常驻记录仪 |
另外还要准备:
- OBD 转接线/转接板:把 16 针 OBD 口引出成 6/14 两根线 + 电源,几块钱一根但极大提升体验;
- 万用表:量终端电阻和电平,判断接线对不对;
- 杜邦线/鳄鱼夹:部分车型 OBD 口被盖板挡住,需要从线束侧取信号;
- 一台跑 Linux 的笔记本:Kali、Ubuntu 都行,虚拟机也行(USB 直通给虚拟机)。
关于供电:OBD 口 16 脚是常电 12V,4 脚和 5 脚是地。如果要给树莓派供电,务必加保险丝并用降压模块(12V→5V),直接从 16 脚取电烧过车的人不在少数。
四、找到 OBD 口,先量一量
OBD-II 是 16 针梯形接口,位置一般在方向盘下方靠左,部分车型在中央扶手箱里或副驾脚部。针脚定义(ISO 15765-4):
| 针脚 | 定义 | 说明 |
|---|---|---|
| 4 | 底盘地 Chassis Ground | 车身金属 |
| 5 | 信号地 Signal Ground | ECU 参考地 |
| 6 | CAN-H | 高速 CAN 高 |
| 7 | K-Line | 老车用,ISO 9141 |
| 14 | CAN-L | 高速 CAN 低 |
| 16 | 常电 +12V | 直接连蓄电池 |
三步验证:
- 断电测电阻:钥匙拔掉,万用表电阻档量 6-14 脚,读数 55~65Ω 说明总线和终端电阻正常。
- 上电测电平:钥匙拧到 ON,直流电压档量 6 脚对 4 脚,应接近 2.5V;14 脚也接近 2.5V。
- 看有没有数据:接到适配器上抓 10 秒,如果全是零流量,先怀疑速率错了,再怀疑这条 CAN 没引到 OBD 口(很多车 OBD 只接了诊断 CAN,动力 CAN 走另一条支路)。
注意:部分车型的 OBD 口只暴露诊断 CAN(网关后面的那一段),你抓到的是网关转发的报文,不是动力 CAN 的原始流量。想要原始流量,得拆中控从网关侧或 CAN 分配器取信号——这一步就涉及拆车了,务必在授权和保险前提下进行。
五、十分钟搭好 Linux 抓包环境
以 Kali/Ubuntu 为例,can-utils 是全部工作的基础。
sudo apt update
sudo apt install -y can-utils
# 插入 CANable(gs_usb)后,内核会自动创建 can0
ip link show type can
# 启动接口,波特率按实际填(500k 最常见)
sudo ip link set can0 up type can bitrate 500000
# 看看状态
ip -details -statistics link show can0
如果设备不叫 can0,用 dmesg | tail 看它被识别成什么名字。gs_usb 方案通常开箱即用;国产 USB2CAN 需要装厂商的 .ko 驱动并手动 modprobe。
速率不对怎么办?CAN 对时序极其敏感,500k 的接口收到 250k 的流量就是一片错误帧。可以先扫一遍常见速率:
for br in 125000 250000 500000 1000000; do
echo "== try $br =="
sudo ip link set can0 down 2>/dev/null
sudo ip link set can0 up type can bitrate $br
timeout 2 candump -n 5 can0 || true
done
哪一档能抓到帧,就是哪一档。少数非标速率(比如 33333)需要额外给 sample-point 参数,或者换支持自定义时钟的方案。
六、第一帧:把数据抓下来
最基础的命令是 candump,它把总线上每一帧打印成一行:
# 实时打印
candump can0
# 只看某几个 ID(7DF 是诊断请求,7E8 是发动机 ECU 响应)
candump can0,7DF:7FF
# 存成日志,后面分析
candump -l can0 # 生成 candump-2026-10-21_120000.log
# 回放日志(虚拟总线上演示用)
canplayer -I candump-2026-10-21_120000.log
输出长这样,从左到右依次是:接口名、ID、DLC、8 个字节的数据。
can0 7DF [8] 02 01 00 00 00 00 00 00
can0 7E8 [8] 06 41 00 BE 3F A8 13 00
can0 201 [8] 00 00 00 00 00 00 00 00
can0 0C9 [8] 1A 00 3C 00 00 00 00 00
can0 3D1 [8] 00 0F 8C 00 00 00 00 00
另一个非常有用的工具是 cansniffer:它按 ID 分组,实时刷新每个 ID 最新一帧的内容,并给变化的字节高亮反色。定位”哪个字节在动”比一行行翻日志快得多。
cansniffer -c can0
再配一个带宽监控,判断总线负载:
canbusload can0@500000
七、读懂数据:周期、ID、负载
先把日志做一次统计,摸清这辆车的”说话节奏”。用 candump -l 存下来的日志是文本格式,可以直接用 awk 处理:
# 统计每个 ID 出现的次数,按次数排序
awk '{print $3}' candump-*.log | sort | uniq -c | sort -rn | head -30
你会发现一个规律:绝大多数车身信号是周期性广播的,周期常见 10ms、20ms、100ms、500ms、1s。周期越短,通常越关键(比如轮速、扭矩、转向角)。
判断周期的土办法是数一个 ID 在 1 秒内出现几次:
timeout 1 candump -n 10000 can0,0C9:0C9 | wc -l
# 输出 100 左右 → 10ms 周期;输出 10 左右 → 100ms 周期
再看哪些字节在变。车辆静止怠速时,绝大多数字节不变,只有转速、水温、电压这几个在动。把车挂挡起步,再抓一段对比——变化的字节就暴露出”油门/车速”这类信号的载体。
💡 速记:字节序
CAN 里的多字节信号大多是大端(Motorola)排列,也就是高位字节在前。你看到的 1A F8 应该读成 0x1AF8,不是 0xF81A。极少数厂商用 Intel 小端,遇到对不上的值先怀疑字节序。
八、诊断层:0x7DF 与 ISO-TP
到这里你抓的是”广播流量”。而 OBD 诊断走的是请求-响应模式,这才是能直接读懂车辆状态的部分。
8.1 请求 ID 与响应 ID 的对应关系
| 功能寻址 | 物理寻址范围 | 响应范围 | 说明 |
|---|---|---|---|
0x7DF |
0x7E0~0x7E7 |
0x7E8~0x7EF |
0x7DF 是广播请求,所有 ECU 都会应答;0x7E0 起是点对点 |
经验公式:响应 ID = 请求 ID + 8。你发到 7E0,发动机 ECU 从 7E8 回你;发到 7E1,变速箱从 7E9 回。
8.2 ISO-TP:把长数据切成多帧
CAN 一帧只有 8 字节,但 UDS 诊断消息经常几十上百字节,所以有 ISO 15765-2(ISO-TP)做分片与重组。首字节的高 4 位就是帧类型:
| 高 4 位 | 类型 | 含义 |
|---|---|---|
0x0 |
Single Frame | 单帧,低 4 位是数据长度 |
0x1 |
First Frame | 多帧的第一帧,低 4 位 + 下一字节共 12 位表示总长度 |
0x2 |
Consecutive Frame | 后续帧,低 4 位是序号(从 1 递增) |
0x3 |
Flow Control | 接收方告诉发送方”继续发 / 等一下” |
抓包时你会看到一长串 21 / 22 / 23 ... 开头的帧,就是连续帧;中间夹着的 30 00 00 是流控。
8.3 实战:读转速和车速
服务 0x01 是”读当前数据”,PID 0x0C 是转速,PID 0x0D 是车速。请求报文 02 01 0C 表示:长度 2、服务 01、PID 0C。
# 在台架/虚拟总线上发送请求
cansend can0 7DF#02010C0000000000
# 抓响应
candump can0,7E8:7EF
收到这样一帧:
can0 7E8 [8] 04 41 0C 1A F8 00 00 00
拆解:04 是 ISO-TP 单帧长度(后面 4 个有效字节),41 = 服务 0x01 + 0x40(正响应标志),0C 是 PID,1A F8 是两个数据字节。
转速公式:((A × 256) + B) / 4
A = 0x1A = 26
B = 0xF8 = 248
((26 × 256) + 248) / 4 = (6656 + 248) / 4 = 1726 rpm
车速 PID 0x0D 更简单,一个字节直接就是 km/h:03 41 0D 3C → 0x3C = 60,即 60km/h。
常用 PID 记住这几个就够日常用:
| PID | 含义 | 换算 |
|---|---|---|
| 0x05 | 冷却液温度 | A − 40(℃) |
| 0x0C | 发动机转速 | ((A×256)+B)/4(rpm) |
| 0x0D | 车速 | A(km/h) |
| 0x11 | 节气门开度 | A×100/255(%) |
| 0x2F | 燃油液位 | A×100/255(%) |
| 0x42 | 控制模块电压 | ((A×256)+B)/1000(V) |
九、逆向方法论:差分采集定位功能帧
广播帧没有文档,只能靠”实验 + 对比”。核心方法是单变量差分:保持其他一切不变,只改变一个动作,看哪几个字节跟着变。
- 采基线:车辆静止、点火、所有电器关闭,抓 30 秒存为
base.log。 - 改一个变量:只开左转向灯,抓 30 秒存为
left.log。 - 做差分:对比两个日志里同一 ID 的负载,字段从 00 变 01 的那一位就是转向灯状态。
- 验证:关掉转向灯再抓一次,确认字段回到 00;再开右转向灯,确认是另一个 bit。
用 Python 做自动差分,比肉眼翻日志靠谱得多:
import collections
def load(path):
db = collections.defaultdict(list)
for line in open(path):
p = line.split()
if len(p) < 5 or not p[1]: continue
db[p[1]].append(p[4:])
return db
a, b = load('base.log'), load('left.log')
for cid in sorted(set(a) & set(b)):
fa, fb = a[cid][-1], b[cid][-1]
if fa != fb:
print(cid, ''.join(fa), '->', ''.join(fb))
输出里同时变化、且只在开灯时变化的 ID,就是候选。通常一个功能由 1~3 个字节承载,可能有冗余(网关会同时转发到舒适 CAN 和诊断 CAN)。
💡 更高效的做法
把 candump -l 的日志导入 SavvyCAN 或 cabana,它们能把每个 ID 的字节画成曲线。开灯那一瞬间曲线上出现方波,一眼就能定位到具体 bit,比写脚本快。
十、零风险练习:ICSim 虚拟台架
真车成本高、风险大,先用 ICSim 把整套流程走通。它是 OpenGarages 出的仪表盘模拟器,用 socketCAN 的虚拟总线。
# 1. 建一条虚拟 CAN 总线
sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0
# 2. 编译并运行
git clone https://github.com/zombieCraig/ICSim.git
cd ICSim && make
./icsim vcan0 # 仪表盘窗口
./controls vcan0 # 控制窗口
控制窗口里用方向键加速、刹车、打转向灯,同时另开一个终端 candump vcan0,你会看到仪表盘动作对应的帧实时出现。这就是”动作 → 帧”的因果链,在真车上你要花一整天才能建立,这里五分钟。
还可以直接把文献里公开的 ID 打进去验证理解:
cansend vcan0 244#0000000000 # 转向灯
cansend vcan0 191#0000000000
cansend vcan0 3E9#0000000000
做完这一步,你就具备了在授权车辆上复现的完整肌肉记忆:接线、设速率、抓包、过滤、差分、验证。
十一、用 DBC 把十六进制变成人能读的信号
DBC 是 Vector 定义的报文描述文件,用文本描述”ID 0x0C9,偏移 0 位,长度 16 位,大端,系数 0.1,单位 km/h,叫 VehicleSpeed”。有了它,工具能直接把负载解析成物理量。
BO_ 201 VehicleStatus: 8 ECU_Engine
SG_ VehicleSpeed : 0|16@0+ (0.01,0) [0|250] "km/h" Gateway
SG_ EngineOn : 23|1@0+ (1,0) [0|1] "" Gateway
没有厂商 DBC 的时候就自己写:抓到帧、定位字段、量出系数和偏移、写成 DBC,然后导入 cabana(Linux 原生,配合 CANable 直接实时看图)或 SavvyCAN(跨平台)。
pip install canmatrix
canconvert my.dbc my.json
这一步的意义是:你从”看十六进制”进阶到”看物理量”。写报告、做异常检测、做 IDS 都需要这个抽象层。
十二、安全视角:CAN 到底危险在哪
回到”安全”这个主题。CAN 的设计目标是可靠和便宜,安全性从来不在设计目标里。
| 缺陷 | 后果 | 典型利用 |
|---|---|---|
| 无身份认证 | 任何节点都能冒充任何 ECU | 伪造轮速/车门状态 |
| 无加密 | 总线可被任意监听 | 窃取位置、驾驶行为 |
| 无完整性校验 | 帧可被篡改、重放 | 重放解锁指令 |
| 广播 + 低优先级仲裁 | 高优先级 ID 可占满带宽 | ID 0x000 泛洪造成 DoS |
| UDS 诊断权限弱 | 部分 ECU 的 SecurityAccess 可被暴力破解 | 进入编程会话后写入任意数据 |
2015 年 Miller 和 Valasek 那篇著名的 Jeep 远程利用,就是从娱乐系统一路打进 CAN,最后在高速上切断了刹车。十年过去,物理层的这些特性没有变,变的是边界被网关和 T-Box 围起来了。
主机厂现在的做法
- SecOC(AUTOSAR Secure Onboard Communication):给关键帧加 MAC 和新鲜度值,接收方校验,防伪造和重放,代价是带宽和延迟;
- 网关分区:动力、车身、诊断、娱乐分成不同网段,跨域必须过网关白名单;
- IDS 入侵检测:基于周期偏差、ID 白名单、负载熵值做异常检测,检测到异常就降级或断连;
- 诊断加固:UDS 的 0x27 服务用非对称挑战响应、速度限制、会话超时,诊断口加物理锁或需要在 4S 店内网才开放。
自己做研究时的建议:先只读监听,建立基线;发帧前先在台架验证;任何写操作(0x2E WriteDataByIdentifier、0x31 RoutineControl)只在报废件或虚拟总线上做。
十三、合规地图:想把这事做成职业,得知道这些
| 标准/法规 | 范围 | 要点 |
|---|---|---|
| UN R155 | 整车网络安全 | 建立 CSMS 体系,做 TARA 威胁分析;2022-07 起新车型强制,2024-07 起全部新车 |
| UN R156 | 软件升级 | SUMS 体系,OTA 过程的安全性与失败回滚 |
| ISO/SAE 21434 | 工程流程 | 从概念、开发、生产到运维的全生命周期网络安全 |
| GB 44495-2024 | 中国整车信息安全 | 2024-08-23 发布,2026-01-01 起实施 |
| GB 44496-2024 | 中国软件升级 | 同上,对应 UN R156 |
对个人学习者的意义很直接:招聘方要的是”能出 TARA 报告 + 能复现漏洞”的人。只会抓包不够,能说清”这个信号被篡改后影响哪个安全目标、风险等级多少、缓解措施是什么”才是岗位要求。
十四、新手最常见的 8 个坑
- 抓不到任何帧:90% 是波特率不对,其次是 OBD 口没接这条 CAN,再次是设备没 up。
- 帧全是错误帧:终端电阻缺失(少了 120Ω)或线太长、分支太长。总线拓扑应该是主干 + 极短分支。
- ELM327 抓不到广播帧:正常,它只做 PC 端发起的 PID 轮询,硬件层面不给你任意帧。
- 同一 ID 抓到的内容对不上手册:字节序搞反了,或者这是网关转发后的重组报文。
- 日志太大打不开:500k 满载每秒约 4 万帧,抓 10 分钟就是几十 MB。用
candump can0,ID:ID先过滤。 - 虚拟机里看不到 can0:USB 直通没配对,或者宿主机抢先加载了驱动。
- 发了帧车没反应:可能被网关丢弃(跨域白名单),也可能需要先发诊断会话进入指令。
- 误以为抓到 ID 就等于控制了车:绝大多数广播帧是状态不是指令,改它只会让仪表显示异常,不会改变执行器。
十五、下一步怎么走
把本文流程走完,你已经能:接线、设速率、抓包、读 PID、做差分、写 DBC。接下来三条分支,按兴趣选:
- 深入诊断:啃 ISO 14229(UDS)的服务清单,特别是 0x10 会话控制、0x27 安全访问、0x22 读数据、0x2E 写数据、0x31 例程控制,这是”从观察到操作”的门槛。
- 深入逆向:拿报废件或拆车件搭台架,做完整的”信号 → 功能 → 协议”还原,练习写 TARA 报告。
- 深入防护:研究 SecOC 的报文格式、CAN IDS 的检测算法(时序、熵、信息论),这块人才缺口最大。
最后再说一次边界:本文所有内容仅用于本人车辆或取得书面授权的车辆、台架、虚拟总线。未经授权对他人的车辆、车队、租赁车辆进行测试,在国内可能触犯《刑法》第 285 条(非法侵入计算机信息系统)与第 286 条(破坏计算机信息系统),并需承担民事赔偿。技术能力越强,越要清楚这条线在哪。
本文所述方法与工具均可公开获取,仅作安全研究与防御体系建设参考。文中数值与协议细节基于经典 CAN 与 ISO 15765-4,不同车型的实际实现可能存在差异,请以实车抓包结果为准。
- 1、本网站名称: 星宇安全实验室
- 2、本站永久网址:https://bk.zhaozhiqiang.pw/
- 3、本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
- 4、本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
- 5、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
- 6、本站资源大多存储在云盘,如发现链接失效,请联系我们我们会第一时间更新。
- 7、文章版权归作者所有,未经允许请勿转载。









- 最新
- 最热
查看全部