导语:前三讲把 CAN 帧结构、UDS 诊断服务、攻击面建模都讲透了,第四讲给到硬件选型。但 Linux 上跑 CAN 才是真正的甜点——内核原生把 CAN 当成网络设备(netdev),candump、cansend 用起来和 tcpdump、ping 一样顺手。再配上 DBC(CAN 数据库)文件解读,一根 USB 转 CAN 线就能开测。下篇把工具链从 C 切到 Python。
一、SocketCAN:Linux 内核原生 CAN 协议栈
SocketCAN 是 Linux 内核从 2.6.25 开始引入的 CAN 协议栈,把 CAN 设备当作网络接口——ifconfig can0 看到的是和 eth0 平级的网卡,ip link set can0 up 拉起接口、ip -d link show can0 看详情,RTNETLINK(路由管理 netlink 套接字)配置比特率、采样点、FD 模式。
这套设计带来三个好处:
- 复用网络栈基础设施 — iptables 可以过滤 CAN 帧(CAN-IDs 匹配),tc(流量控制)可以做带宽限流,Socket 编程直接 read/write
- 统一命名空间 — 物理 CAN、USB 转 CAN、虚拟 CAN(vcan)都是
canX/vcanX,上层工具不用关心硬件差异 - 零拷贝抓包 — SocketCAN 直接在内核环形缓冲区里分发,wireshark 都能直接
.pcapng抓 CAN 帧
对比 tcpdump 的网络视角就懂了:
| 维度 | tcpdump (以太网) | candump (SocketCAN) |
|---|---|---|
| 接口 | eth0 | can0 / vcan0 / slcan0 |
| 帧单位 | packet (含 Ethernet II/ARP/IP) | CAN frame (含 ID + 0-8 字节) |
| 过滤语法 | BPF(伯克利包过滤器) host 1.2.3.4 | candump can0,7FF:7FF 掩码过滤 |
| 记录格式 | pcap / pcapng | .log (文本) 或 .candump 二进制 |
| 实时分析 | wireshark / tshark | cansniffer / candump_decode |
红队的最爽之处:不需要写内核驱动就能做 CAN 渗透。所有工具链的入口都在 userspace(用户态),一个 apt-get install can-utils 就能装齐。

二、零硬件上手:vcan 虚拟 CAN 接口
Linux 内核自带 vcan(虚拟 CAN)驱动——不需要任何硬件,就能创建一对虚拟 CAN 接口互相收发。教学、单元测试、协议开发全靠它:
# 加载内核模块
sudo modprobe can
sudo modprobe vcan
# 创建虚拟接口并拉起
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0
# 验证
ip -d link show vcan0
# 3: vcan0: <NOARP,UP,LOWER_UP> mtu 16 qdisc noqueue state UNKNOWN mode DEFAULT
# link/can promiscuity 0
接下来开两个终端互相发收:
# 终端 A:监听
candump vcan0
# 终端 B:发一帧
cansend vcan0 123#DEADBEEFCAFEBABE
终端 A 会立刻看到:
vcan0 123 [8] DE AD BE EF CA FE BA BE
格式是 接口名 CAN-ID(hex) DLC 数据(hex)——CAN-ID 是仲裁 ID(11/29 位),DLC(Data Length Code)是数据长度(0-8 字节,CAN FD 可到 64 字节),后面是数据字节。
这套虚拟环境能让初学者 30 分钟内跑完协议栈,不花一分钱买硬件。
三、can-utils 工具链六件套
can-utils 包(Debian/Ubuntu 直接 apt install can-utils,源码 linux-can/can-utils)提供了 30+ 工具,按用途分四类。
3.1 显示与记录
- candump — 实时显示、过滤、记录 CAN 帧到文件
candump vcan0实时显示candump -L vcan0记录到.log文件candump vcan0,123:7FF只看 0x123 附近的 ID(掩码过滤)candump -a -A vcan0显示仲裁过程和时间戳
3.2 单帧发送
- cansend — 发一帧就走
cansend vcan0 123#11.22.33.44.55.66.77.88标准帧cansend vcan0 18FF1234##011.22.33.44.55.66.77.88扩展帧(29 位 ID)cansend vcan0 123##0FFCAN FD 帧(## 表示 FD)
3.3 流量生成
- cangen — 生成随机流量,做压力测试
cangen vcan0 -g 100每 100ms 一帧随机帧cangen vcan0 -i 0x100 -e在固定 ID 上生成
- cansequence — 按固定 ID 发递增 payload 的帧序列,用来验证总线稳定性和丢帧率
cansequence vcan0 -i 0x100
3.4 流量分析
- cansniffer — 高阶分析工具,持续发送时显示 payload 哪些字节在变化(差异显示),哪些是常量(静态信号)。渗透测试里识别”哪些字节是计数器/状态位”必备
cansniffer vcan0输出格式:123 [8] 00 1A 02 (00) (FF) (00) (3C) (00)括号里是变化的字节
3.5 回放与重放
- canplayer — 把 candump 录制的
.log文件原速或变速重放到总线上canplayer -I captured.log vcan0canplayer -I captured.log -t 2.0 vcan02 倍速回放
攻击者最爱的组合:candump 录制 → 分析 → canplayer 回放。录一段门锁解锁时的 CAN 帧,过几小时回去 cansend 一下,车门就开了——这就是翻车现场的常客。
3.6 内核网关与 ISO-TP
- cangw — 配置内核 CAN 网关,把一条 CAN 总线上的某些 ID 转发到另一条
cangw -A -s can0 -d can1 -X -f 7ff:7ff把 can0 上 ID 范围 0x000-0x7FF 的帧全量转发到 can1- 实战场景:底盘 CAN 和车身 CAN 之间架桥,过滤特定 ID 做旁路监听
- isotpsend / isotprecv — 第 03 讲提到的 ISO-TP 多帧传输(UDS 的传输层),按 0x27 安全访问发 Seed-Key 都靠它
- isotpsniffer / isotpdump — 抓 ISO-TP 多帧会话并解码,比 cansniffer 更聚焦在诊断层
3.7 总线负载与位时序
- canbusload — 实时算 CAN 总线利用率百分比,超过 70% 就要警惕丢帧风险
canbusload vcan0@1000000指定比特率参数;超过 30% 算繁忙,超过 50% 临界
- can-calc-bit-timing — 给定时钟频率和目标比特率,算出最优的 tq / prop-seg / phase-seg1 / phase-seg2 组合,比 ip link set 手动算省事
- canerrsim — 在总线空闲时人为注入错误帧,用来测试 ECU 的错误处理逻辑(红队很关心这条)
四、DBC 文件解读:从原始字节到物理量
CAN 总线上跑的是裸字节(DEADBEEF 这种),但工程师写代码时关心的是物理量——车速 67.3 km/h、油门开度 23%、方向盘转角 -15.2°。DBC 文件(CAN database)就是这张映射表,由 Vector、CANalyzer、CANoe 这些工具定义。
4.1 DBC 三层结构
DBC 文件是纯文本,三层定义:
- BO_ (Message) — 报文,定义一个 CAN 帧
BO_ 256 VehicleState: 8 ECU1表示 ID=0x100、长 8 字节、来自 ECU1 的报文 VehicleState
- SG_ (Signal) — 信号,定义报文里的一个字段
SG_ VehicleSpeed : 0|16@1+ (0.01,0) [0|655.35] "km/h" ECU1— 第 0 位开始 16 位、有符号 Intel 字节序、精度 0.01、偏移 0、单位 km/h、来自 ECU1
- VAL_ (Value Table) — 枚举值表
VAL_ 256 GearPosition 0 "P" 1 "R" 2 "N" 3 "D" ;把字节值映射成档位字符串
4.2 canmatrix 工具链
直接看 DBC 文件是反人类的——用 CANmatrix(ebroecker/canmatrix):
- 支持 .dbc / .dbf / .kcd / .arxml / .xls(x) / .yaml / .sym / .xml / .lua / .scapy 多种格式互转
- 提供
canconvert命令行工具:canconvert input.dbc output.kcd - 提供
candump_decode.py用 DBC 文件解码 candump 输出,把字节流还原成可读的”车速 67.3 km/h”
pip install canmatrix
canconvert manufacturer.dbc my_project.kcd
python -m canmatrix.tools.candump_decode -d my_project.dbc candump.log
红队实战里 DBC 文件价值极高——拿到一份 DBC 等于拿到了车辆所有 ECU 信号的位级定义,配合 UDS 0x22 服务读 DID(数据标识符)能直接拿到当前车速、里程、电池电压等所有状态。
五、实战:拉起真实 CAN 接口
真车上 OBD-II 接口接入 CANtact、Macchina M2 这种 USB 转 CAN 适配器,驱动层是 slcan(串口线 CAN)或厂商专有驱动(gs_usb for CANtact),下面是通用流程:
# 1. 加载 CAN 内核栈
sudo modprobe can
sudo modprobe can-raw
sudo modprobe slcan # 串口 CAN
# 或厂商驱动
sudo modprobe gs_usb # CANtact / candleLight 固件
# 2. 接 USB 转 CAN,绑定 slcan 设备(/dev/ttyUSB0 为例)
sudo slcand -o -c -s6 -t hw -S 1000000 /dev/ttyUSB0 slcan0
sudo ip link set up slcan0
# 3. 设置 CAN 接口参数(比特率、采样点)
sudo ip link set can0 type can bitrate 500000
sample-point 0.875
tq 125 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1
sudo ip link set up can0
# 4. 开抓
candump -a -A can0,7FF:7FF # 0x000-0x7FF 全捕获,-a 显示仲裁,-A 显示 ASCII
参数含义:
- bitrate 500000 — 500 kbps(高速 CAN,主流车厂默认)
- sample-point 0.875 — 87.5% 采样点(CAN 经典值,容错最好)
- prop-seg / phase-seg1 / phase-seg2 — 位时间分段,相加乘 tq 得位时间
- sjw — 同步跳转宽度
如果接错比特率,看到的就是 CRC(循环冗余校验)错误帧满天飞。candump -e 能看到错误帧。
实际工作中常用 ip -details -statistics link show can0 看收发统计——RX packets 字段异常增长但应用层收到的帧没增加,多半是被内核环形缓冲区丢了,常见于高速 CAN + 低性能 CPU 的组合。
六、思考题
- vcan 接口和真实 CAN 接口在内核代码里走的是同一条路径吗?vcan 的局限是什么——它能模拟 CAN FD 吗?
- cansniffer 显示
123 [8] 00 1A 02 (00) (FF) (00) (3C) (00),括号里的字节变化说明什么信号类型? - 没有 DBC 文件时,红队怎么从字节流反向推断物理量?给你一段 8 字节帧 payload,思路是什么?
- 录制了一段 60 秒的 .log 文件,里面 0x18B0 ID 每 100ms 出现一次,内容都是 8 字节——这是不是一条信号?怎么用 canplayer 回放验证它控制的是哪一项功能?
下一篇 07 讲,把工具链从 C 切到 Python——python-can、Scapy CAN 层、Caring Caribou,写出能批量 fuzz 的脚本。
七、素材出处
- can-utils GitHub:
https://github.com/linux-can/can-utils - SocketCAN 内核文档:
https://www.kernel.org/doc/html/latest/networking/can.html - CANmatrix(ebroecker/canmatrix):
https://github.com/ebroecker/canmatrix - Wikipedia SocketCAN:
https://en.wikipedia.org/wiki/SocketCAN - awesome-vehicle-security 列表 #161 / #135 / #177














暂无评论内容