CAN总线
2023-06-14 18:45:12

CAN总线

简介

​ CAN(Controller Area Network)总线是一种用于在车辆和工业领域中进行通信的串行通信协议。它最初是由德国Bosch公司于1986年开发的,旨在实现高速、可靠和实时的数据传输。CAN总线在汽车电子系统、工业自动化、航空航天、医疗设备等领域得到广泛应用。

特点:

1、可靠性:采用差分信号传输和冲突检测和恢复机制,有效抵抗噪声干扰与信号损耗

2、实时性:支持多主机并行通信,具有优先级机制,确保重要数据的及时传输和处理

3、灵活性:采用分布式通信结构,可以支持多个节点的连接和通信,节点之间可以灵活添加或删除

4、高宽带:支持较高的数据传输速率,几百Kbps到几Mbps不等

5、线缆简单:使用两根双绞线进行数据传输

图例:

CAN总线就像神经系统,通过连接”节点“或”电子控制单元(ECU)“,使其信息能够实现共享;

ECU:在汽车CAN总线中,ECU可以是发动机控制单元,安全气囊,音频系统等;现代汽车拥有70个ECU;

图例:

==》ECU将通过CAN总线(CAN_L与CAN_H)进行连接

当使用CAN总线进行通信时,数据将通过数据帧(Data Frame)的形式进行传输;

CAN帧(CAN 2.0A):

image-20230615170604108

Start of Frame(SOF):起始帧标识,表示数据帧开始;

Identifier(ID):标识符,用于唯一标识数据帧的发送者和接收者(具有优先级);

Remote Transmission Request(RTR):表示发送还是请求

Control Field(Control):控制字段,包含数据帧的控制信息,如数据长度(DLC),帧类型等;

Data Field(Data):数据字段(有效载荷),用于传输实际的数据;数据字段的长度可以根据应用的需求进行配置,最多8字节;

CRC Field(CRC):循环冗余校验字段,用于检测数据传输过程中是否发生错误;

ACK:表示节点是否已经确认正确地接收到数据;

EOF:CAN帧的结束。

CAN协议数据包识别原理:

1、接收CAN数据包:CAN总线上的每个节点都可以接收其他节点发送的数据包,节点通过CAN控制器接收数据包,并将其存储在CAN接收缓冲区中;

2、解析报文ID:接收节点首先解析报文ID,判断数据包是否为其所需要的数据包,解析报文ID时,需判断扩展帧标志位和远程帧标志位,以确定报文ID的长度和数据包类型;

3、判断数据包类型:根据扩展帧标志位和远程帧标志位的值,确定数据包的类型:如果是远程帧,则节点需要向发送方发送数据请求;如果是远程帧,则节点需要读取数据域中的数据;

4、读取数据:若数据包为数据帧,则接收节点需要读取数据域中的数据。

CAN总线通信是广播的方式,所以数据是可以被监听和获取的;CAN总线协议中ID代表报文的优先级,协议中没有原始地址信息==》任何人都可以伪造和发送虚假或恶意的报文;

例:

1、在攻击者使用高优先级的指令抢占正常指令,将导致ECU无法接受相对低优先级的正常指令,造成CAN总线协议的拒绝服务攻击

2、当攻击者截获从合法节点发送的CAN数据帧,在将这些数据帧保存于自己的设备上,从自己的设备上发送到CAN总线上,欺骗接收方这些数据是从合法节点发送,从而达到重放的目的。

通信(模拟)

通过ICSim实现,ICSim是一个汽车上的仪表盘模拟器;

# 安装依赖
sudo apt install libsdl2-dev libsdl2-image-dev can-utils maven autoconf -y
# 下载ICSim
git clone https://github.com/zombieCraig/ICSim.git
# 编译安装
cd ICSim
sudo make

有了模拟器,还需要能与之通信的CAN总线,这里需要用到Socketcand:

# 下载socketcand
git clone https://github.com/linux-can/socketcand.git
cd socketcand# 获取缺少的文件
wget https://raw.githubusercontent.com/dschanoeh/socketcand/master/config.h.in# 编译安装
autoconf
./configure
make clean
make
sudo make install

CAN总线环境也准备好了,那为了能对CAN发送的数据进行分析,还需要一个CAN总线分析工具Kayak:

# 下载
git clone https://github.com/dschanoeh/Kayak.git
# 安装jdk
sudo apt-get install openjdk-8-jdk

echo $JAVA_HOME  #查看安装的JDK对不对

#不符合预期则进行设置
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH

# 安装
cd Kayak
mvn clean package

前置工作已经完成,接下来就是设置虚拟的CAN接口,启动模拟器,实现通信了

# 设置vcan(虚拟CAN)接口
sudo modprobe can  #加载CAN内核模块,启用CAN支持
sudo modprobe vcan  #加载vcan内核模块,启用虚拟CAN支持
# ip link 命令启动 can 接口
sudo ip link add dev vcan0 type vcan  #创建名为vcan0的虚拟CAN接口
sudo ip link set up vcan0   #启用vcan0接口,使其处于活动状态

VCAN工作原理:

1、创建虚拟CAN接口,作为模拟器和其他应用程序之间的通信接口;

2、模拟CAN帧,VCAN模拟器会接收其他应用程序的CAN帧,然后模拟一个类似于真实CAN总线的环境,将CAN帧转发至总线上;

3、监听CAN总线,可以监听到真实的CAN总线,以便将CAN帧发送到真实总线上,并在接收到真实总线上传来的CAN帧时,将其转发至虚拟CAN接口上,以便于其他应用程序接收这些数据;

4、支持多种CAN协议:ISO 11898,SAE J1939等。

至此,你就获得了一个虚拟的CAN接口vcan0,接下来,将启动模拟器:

cd Icsim/
# 打开仪表盘模拟器
./icsim vcan0
# 打开仪表盘控制器
./controls vcan0

image-20230614153734043

通过Wireshark监听vcan0:注意使用root权限启动wireshark(sudo);

image-20230614154248159

成功可以监听CAN总线的通信:

image-20230614154345334

重放(模拟)

通过对仪表盘进行操作(开车门,加速等),利用candump监听模拟器数据包,wireshark也行,再使用canplayer进行重放;

candump开启监听:

sudo candump vcan0 -l

对仪表进行操作,开门,加速;操作完后停止candump,此时生成了一个数据包:candump-xxx.log;

注意此时需要使用(点击一下)那个手柄才能操作:

功能 控制按钮
转向 键盘左右
速度 键盘上下
开/关左前车门 右shift/左shift+A
开/关右前车门 右shift/左shift+B
开/关左后车门 右shift/左shift+X
开/关右后车门 右shift/左shift+Y
开启全部车门 左shift + 右shift
关闭全部车门 右shift + 左shift

例:开启左前车门:右shift + A

成功获取了CAN总线通信的数据包;

在等仪表复原后(关闭车门或直接将仪表重启等),使用canplayer重新发送数据包:

sudo canplayer -I candump.log  #我改了文件名

成功复刻刚刚对仪表的操作:

加速操作:

image-20230614160249044

开车门操作:

image-20230614160342214

但并满足于此,因为CAN是不断在进行通信的,所以有很多数据是我们不需要的,我们可以剔除这些对我们实现操作(开车门)无用的数据,获取能进行操作(开车门)的数据指令;

可以通过二分法将数据包分成两份,再次进行重放,再对能进行操作的数据包进行相同的操作……

import sys

filename = sys.argv[1]

#读取log文件
with open(filename, 'r') as f:
    lines = f.readlines()
num_lines = len(lines)
#使用二分法将内容分别输出到两个新文件
midpoint = num_lines // 2
with open('candump1.log', 'w') as f1, open('candump2.log', 'w') as f2:
    for i, line in enumerate(lines):
        if i < midpoint:
            f1.write(line)
        else:
            f2.write(line)

使用例:

python3 xxx.py candump1.log

在一段时间的重放后Loding…… 最终确定操作开门的数据包为:

通信(物理)

首先需要了解一下OBD接口:
OBD全称 On-Board Diagnostics ,意为“车载诊断系统”。随着汽车电气化程度越来越高,各种电子传感器被大量使用,OBD承担了更多的行车记录功能。与行车记录仪不同, OBD显示的是以汽车为中心的数据,并且很多原车仪表盘不能显示的信息可以通过OBD读出来。如下图所示汽车的OBD接口一般位于方向盘左下方:

640fd71091a3e

OBD接口使用的通信协议由汽车制造商定义,其中最常用的就是基于CAN总线的协议;OBD接口可以提供各种诊断信息,包括但不限于故障码,冻结帧数据,实时数据,监视状态等;

下图就是OBD引脚的定义:

我们主要关注一下CAN_L和CAN_H两个引脚即可:

CAN_L和CAN_H是CAN总线的两个物理信号线,用于传输CAN数据帧。这两个信号线分别代表了CAN总线的差分信号==》

CAN_L(低电平线):用于传输差分信号的低电平部分。在CAN总线上,CAN_L线通常处于电压较低的状态。

CAN_H(高电平线):用于传输差分信号的高电平部分。在CAN总线上,CAN_H线通常处于电压较高的状态。

差分信号传输:CAN总线使用差分信号传输方式,即通过CAN_L和CAN_H两个信号线之间的电压差来表示数据。CAN_L线的电压较低,CAN_H线的电压较高,两者之间的电压差表示传输的数据。

极性:CAN总线的差分信号具有极性,即CAN_L和CAN_H的电压关系可以反转。CAN总线通信中,数据帧的传输是通过CAN_L和CAN_H的电压变化来表示逻辑位的翻转。

终端电阻:CAN总线上通常需要安装终端电阻,用于消除信号反射和保证信号的质量。终端电阻分别连接在CAN_L和CAN_H线的两端。

通过CAN_L和CAN_H两个物理信号线的差分传输,CAN总线能够实现高速、可靠的数据通信;

一般情况下,可以使用OBD接口接线直接接入OBD接口,再将接线连接PCAN,PCAN连接电脑即可完成通信:

OBD接口接线:

接线连接PCAN上的引脚:

我这里直接将仪表总线的CAN_L与CAN_H接出来,直接用杜邦线连接PCAN,PCAN的usb接口接PC;

通过PCAN-View连接获取数据:

常见波特率:

经典CAN:1 Mbit/s
CAN FD:5 Mbit/s

首先设置波特率,我这里是500,成功连接后PCAN的RX和TX灯将亮起来,并能在PCAN-View上接收到数据,例:

image-20230613165108678

在下方可以添加要发送的数据,例:可以打开仪表盘背景灯的指令

按空格即可放松CAN指令,也可以设置timeout,让它自己发

image-20230613165458509

成功打开:

当然也可以通过复制粘贴上方接收的数据重新发送达成重放的目的,但我这里推荐另外一个工具去实现重放

重放(物理)

使用工具

https://github.com/TOSUN-Shanghai/TSMaster

方法与PCAN-View类似,首先设置一些基本信息:

image-20230613170051273

然后点击启动就开始接收CAN数据了

image-20230613170154672

数据例:

image-20230613171642511

在该栏靠右边,有能实现记录数据包地功能:

image-20230613170314307

点击启动记录,然后通过一些物理操作使仪表盘发生变化,例:左右转向灯,加速等;等记录完所需的数据后就领域停止记录了,至此,你就获得了一份记录这些操作的数据包:默认为TSMaster.blf;

image-20230613170749607

通过总线回放也可以查看到,在总线回放中:它会打开默认的文件夹,里面就存放着记录的CAN数据;

image-20230613171152136

点击启动回放,就可以在仪表盘上看到刚刚执行的各个操作:左右转向灯等;这里我验证了转向灯,速度功能,但是由于一些保密原因就不作展示了;

之后就可以通过与上文中模拟CAN重放中定位该功能的指令一样,使用二分法找就好了;

当然,这个记录CAN指令的.blf文件也可以使用Wireshark打开,例:

至此,关于CAN协议解析与通信就先告一段落。