车联网安全入门(1)——UDS服务学习

车联网通信主要是基于CAN协议的,但是从UDS服务开始学起更易于新手理解。UDS服务是基于CAN协议的,可以把两者的关系类比IP协议和HTTP协议,UDS和HTTP都是在应用层上我们能直接接触到的服务,有明确的报文格式,请求和响应。

学习本文的目的就是能够看懂CAN日志中的UDS报文(请求和响应都要能看懂),类比下面在burp中的HTTP请求和响应:

我们能看懂数据包中的各种字段的含义,请求从哪里发起,服务器响应了什么,那么对于UDS,
我们就需要能看懂我们向车或是ECU发送了什么请求,它们又响应返回了什么数据。

常规的CAN Log如上,读完本篇文章能够掌握并且看懂上面的UDS报文即可。

UDS服务定义

UDS(Unified Diagnostic Services,统一的诊断服务)诊断协议是在汽车电子ECU环境下的一种诊断通讯协议。简单来说,可以理解为UDS诊断协议就是ISO 14229协议,在ISO 14229协议中定义了UDS服务用法、服务格式等信息。UDS诊断最主要目的是为了能够快速准确判断车辆或者某个控制器的故障以及故障原因,从而为维修提供可靠的依据。

应用场景就是使用诊断仪向车辆发送UDS指令来判断车辆功能是否正常,达到诊断的目的以及单独对某个ECU芯片的功能和安全测试。

UDS可以说是外界与汽车内部建立诊断的语言,若外部诊断仪与汽车内部ECU共同遵循UDS协议,诊断仪即可通过UDS相应的指令向汽车内部ECU获取相应的反馈信息,如诊断仪需要读取ECU里面的软件版本等信息,可以通过22服务指令,想写入ECU配置信息,可以通过2E服务写指令,想读取故障信息可通过19服务指令。详细服务指令本文将逐个讲解说明。汽车里的诊断由请求与响应组成,这好比医院看病,医生请求诊断,病人回答医生的问题,汽车中诊断是由外部设备发起,如诊断仪,响应是汽车内部ECU执行,如BCM、GW、PEPS等车身电子器件。

ECU可以理解成是车上的一个用于控制某个模块的组件,例如:有个ECU负责打开和关闭车大灯,当向ECU发送打开大灯的信号,ECU则会控制打开大灯。

UDS诊断服务概览

这一部分不理解可以先跳过,后面讲到具体的报文格式和数据可以参照下面的表格。

UDS诊断包括6大类,26种服务,每种服务都有自己独立的ID,即SID(Service Identifier)。

这里的SID(service identifier)也就是服务id,都是十六进制的。

关键字段含义解释:

字段 解释 在CAN日志中
SID 服务 ID,如 $10,是 UDS 报文的第一个字节 在 CAN 日志中,你会看到类似 280#10 01 00,其中 10 就是 SID
Available in Default Session 是否可在默认会话使用 如果一个服务不能在默认会话使用,必须先切换会话(如 $10)才能调用
Available for RoE 是否支持事件响应 若支持,则可配置 ECU 在特定条件下主动上报数据(如检测到故障)
Has Sub-Function 有没有子服务(或者说额外参数) 如 $22 需要传 DID,所以报文中会有更多字节

Diagnostic and Communication Management(诊断与通信管理)

这是最基础也是最重要的功能组,用于建立诊断连接、设置安全级别等。

SID 名称 说明
$10 Diagnostic Session Control (DSC) 切换诊断会话模式(如默认、编程、扩展等)
$11 ECU Reset (ER) 复位 ECU(重启)
$27 Security Access (SA) 请求进入安全访问模式(需密码或种子密钥)
$28 Communication Control (CC) 控制 ECU 的通信(启用/禁用发送接收)
$3E Tester Present (TP) 告诉 ECU “测试仪还在”,防止超时断开连接
$83 Access Timing Parameter (ATP) 设置定时参数(如响应延迟)
$84 Secured Data Transmission (SDT) 加密数据传输(常用于安全更新)
$85 Control DTC Setting (CDTCS) 控制故障码是否被设置
$86 Response On Event (ROE) 在特定事件发生时自动返回响应(如故障码触发)
$87 Link Control (LC) 控制通信链路(如切换波特率)

调试时先发 $10 进入扩展会话 → 发 $27 获取安全访问权限 → 再执行读写操作。

Data Transmission(数据传输)

用于读取或写入 ECU 内部的数据。

SID 名称 说明
$22 Read Data By Identifier (RDBI) 根据 DID(Data Identifier)读取数据(如车速、转速)
$23 Read Memory By Address (RMBA) 直接按内存地址读取(如固件版本信息)
$24 Read Scaling Data By Identifier (RSDBI) 读取带比例因子的数据(如传感器值转换)
$2A Read Data By Periodic Identifier (RDBPI) 定期读取某项数据(周期性监控)
$2C Dynamically Define Data Identifier (DDDI) 动态定义一个新的 DID(临时用)
$2E Write Data By Identifier (WDBI) 写入数据到指定 DID(如调整参数)
$3D Write Memory By Address (WMBA) 写入内存地址(如刷写程序)

$2E 和 $3D 是写操作,通常需要先通过 $27 获得权限。

Stored Data Transmission(存储数据传输)

主要用来读取或清除故障码(DTC)。

SID 名称 说明
$14 Clear Diagnostic Information (CDTCI) 清除所有故障码
$19 Read DTC Information (RDTCI) 读取故障码信息(包括状态、ID、时间等)

用途:
维修后清码:发送 $14 → ECU 返回确认
查看当前故障:发送 $19 + 子功能 → 获取 DTC 列表

Input Output Control(输入输出控制)

控制 ECU 的物理输出(如灯光、继电器等)

SID 名称 说明
$2F Input Output Control By Identifier (IOCBI) 按 ID 控制某个输出(如点亮大灯)

如果想让 ECU 打开前照灯,可能会发送 2F XXXX YY,其中 XXXX 是控制 ID,YY 是控制命令(开启/关闭)。

Remote Activation of Routine(远程例行程序激活)

运行 ECU 内部的诊断例程(如自检、校准)

SID 名称 说明
$31 Routine Control (RC) 启动、停止、查询某个内部例程

有些车支持“自动对齐四轮定位”的例程,可通过 $31 触发。

Upload Download(上传下载)

用于刷写软件或读取固件

SID 名称 说明
$34 Request Download (RD) 请求开始下载(如固件升级)
$35 Request Upload (RU) 请求上传(如读取闪存内容)
$36 Transfer Data (TD) 传输数据块(分包发送)
$37 Request Transfer Exit (RTE) 结束传输过程

OTA升级的核心流程:
$34 → $36 × N → $37

UDS报文格式

所有的UDS服务都有相同的请求与响应格式,掌握好该格式,对理解UDS将会容易很多。诊断是通过诊断仪和 ECU 之间的请求和响应完成的,诊断的请求通常是从诊断仪到 ECU,响应则从ECU到诊断仪。
请求报文区分带子服务的请求与不带子服务的请求,响应分正响应与负响应,其中正响应区分对应带子服务的响应与不带子服务的响应,负响应都一样。

下述表格中缩写字母解释
M:强制的
S:强制的,需从参数列表中选择一个
U:用户自定义,可选择的
注:以下所有例子中的数据都为16进制格式,为表达简明,省去“0x”前缀

含有子功能的请求报文
含有子功能的请求报文由请求ID,子服务ID,数据参数[可选]组成,如下图所示:

例:10 01(请求切换默认会话模式)
例:19 02 FF(请求读取以0xFF为Mask的故障信息)

不含子功能的请求报文
不含有子功能的请求报文由请求ID,数据参数[可选]组成,如下图所示:

例:22 F1 90(请求读取DID为0xF190的数据)
例:37(请求数据传输退出)

含有子功能正响应报文
含有子功能的响应报文由响应ID,子服务ID,数据参数[可选]组成,其中
响应ID值为对应请求ID加0x40,如下图所示:

不含有子功能正响应报文
不含有子功能的响应报文由响应ID,数据参数[可选]组成,其中响应ID值为对应请求ID加0x40,如下图所示:

例:
请求:22 F1 90(读取DID为0xF190的数据)
响应:62 F1 90 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10(返回DID为0xF190的数值为00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10)

负响应报文

例:
请求:10 02(切换编程会话模式)
响应:7F 10 7E (错误切换至编程会话模式,NRC为7E )

请求

类比HTTP,UDS协议也有请求和响应,也有固定的报文格式。HTTP请求需要包含请求方法(如GET、POST等)、请求URI(统一资源标识符)和HTTP协议版本,各种请求字段(Referer、Cookie、host等),空行,请求体等。而UDS的格式相对来讲就要简单很多,标准的UDS报文如下:

1
2
3
4
5
6
7
Time: 12.345 ms, ID: 0x7DF, DLC: 8, Data: 10 01 00 00 00 00 00 00
UDS 使用标准 CANID 0x7DF(或 0x7E80x7EF,取决于协议)。
DLC(Data Length Code)指数据长度,也就是八个字节。
DLC是CAN帧中的长度字段(18字节),实际数据长度由DLC决定(如DLC=8表示8字节数据)。
首先看到第一个字节SID,比如 10 → Diagnostic Session Control。
看后续字节,如果是 $10,后面可能是子功能(如 01 = Programming Session)
如果是 $22,后面是 DID(如 00 0C = Vehicle Speed)

再看到一个例子:
7DF#02 11 01 00 00 00 00 00
7DF是CAN ID(后续讲到寻址还会再解释),#是canid和后面uds指令数据的分隔符。
UDS请求报文一般跟上面一样是八个字节,02是报文数据长度,也就是两个字节,对应上面的11一个字节和01一个字节,后面00都是用来填充至完整8字节数据的。
11:服务ID
01:子服务ID

响应

肯定响应(正响应)

UDS诊断的响应分为肯定相应和否定相应(就是请求成功和失败了),格式也有所不同。

还是以7DF#02 11 01 00 00 00 00 00为例,如果我们通过诊断仪等测试工具成功发送该请求,并且ECU能够理解并且执行该指令,ECU则会返回一个肯定响应如下:

1
02 51 01 00 00 00 00 00

可以看到,功能ID+40,这就是肯定响应的格式。,并且后面五个字节不一定还是00,实际测试中可能会有别的数据,这里我没修改。

否定响应(NRC)(负响应)

如果请求失败,ECU则会返回如下否定响应:

1
2
3
4
5
6
7F 11 11 00 00 00 00 00

7F:否定响应固定首字节。
第一个11:服务ID
第二个11:否定响应码(NRC)表示ECU不支持所请求的诊断服务
与肯定相应相同,这里后面五个字节不一定还是00,实际测试中可能会有别的数据,我没修改。

如图,存在以下否定相应码:

区分响应和请求

请求:源地址是测试仪(如 0x7E8),目标是 ECU(0x7DF)
响应:ECU 发送,ID 为 0x7E8,第一个字节是 6x(如 60 是 $10 的响应)
这里可以类比web中的客户端和服务器端,测试仪也就是客户端,当我们发送一个HTTP请求时,会有源ip地址,在UDS中就是上面提到的0x7E8,
而请求的目的地址就是服务器地址,也就是0x7DF。

UDS诊断具体服务

这里不详细介绍每一中服务,只介绍几个比较重要的,其他的可以在碰到的时候再查阅对应id、格式和功能。

10服务

10服务即Diagnostic Session Control (DSC),用于切换诊断会话模式(如默认、编程、扩展等)。
10服务存在子服务,子服务ID=01对应切换到默认会话模式,02对应切换到编程会话模式,03则对应切换到扩展会话模式。
会话模式可以理解为诊断的功能模式,即在不同的会话模式下,能够支持不能的诊断功能,如在默认会话模式下,一般情况下不允许支持写服务(WriteDataByIdentifier0x2E),也不允许支持请求下载服务(RequestDownload0x34),而在拓展诊断会话模式下,就允许支持写服务(WriteDataByIdentifier0x2E),在编程会话模式下,就可以支持(RequestDownload0x34)。

请求格式:

参考我们前面的示例UDS指令02 11 01 00 00 00 00 00,我们将服务ID(SID)11改为10,即
02 10 01 00 00 00 00 00
那么该请求就是请求切换到默认会话模式。
响应:50 01 xx xx xx xx(成功切换默认会话模式)

11服务

ECU复位ECUReset(0x11)是控制ECU端执行复位的服务。诊断仪发送11 01复位请求后,ECU复位动作执行前,正响应需先发送给诊断仪,然后ECU执行复位操作,成功复位后,ECU需进入默认会话模式。

22服务

22服务即Read Data By Identifier (RDBI),功能是从ECU存储器中读取由DID(Data Identifier)所确定的数据记录值(如车速、转速),其中DID为两个字节长度的数值。

22服务不存在子服务,但是需要通过DID读取车上信息,例如:
22 F1 90(请求读取DID为0xF190的数据)
根据DID的不同可以读取到不同的信息,如0xF190 = Vehicle Identification Number (VIN),即车辆识别码(17位车架号)
车速的DID = 0x000C(标准ISO 14229-1定义)
转速的DID = 0x000B(或 0x000D,取决于ECU)

响应数据可能如下:62 F1 90 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10(返回DID为0xF190的数值为00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10)
62是SID+40的结果。

27服务

27服务的请求响应格式较复杂,这里先不展开.
安全访问SecurityAccess(0x27),此服务是提供访问ECU内部数据或者出于安全因素需被限制的诊断服务的请求权限。常见的如读服务(0x22)读取非安全信息时能够直接读取,不需要利用27服务进行安全访问,而通过写服务(0x2E)写入数据时,则通常需要通过27服务进行安全访问才可以写,刷新程序也需要利用27服务通过相关的安全等级才能够对ECU进行程序下载,显然这些都是需要利用27服务进行权限管控,从而保障ECU的安全可靠。

安全访问的流程如下:
1、诊断仪先发送请求seed的报文(27 01)
2、ECU响应seed(67 01 xx xx xx xx)
3、诊断仪根据返回的seed按照约定算法计算key值,并发送给ECU请求验证(27 02 xx xx xx xx)
4、ECU收到请求之后,也按照约定的算法对该key进行校验,并给出响应,若计算一致,则为正响应(67 02),否则为负响应(7F 27 NRC)

ECU若校验key一致,则ECU则切换安全状态至对应的解锁状态,此时在该解锁状态下能够支持的服务都应该可以工作。如果ECU已经处于解锁状态,此时诊断仪再次发送请求seed的报文,ECU应该响应seed为0的正响应。

1
2
诊断仪 → 27 01 → ECU → 67 01 AA BB (Seed=0xAABB)
诊断仪 → 27 02 CC DD → ECU → 67 02 (解锁成功)

27服务还有安全等级,这里先不做讲解。

2E服务(WriteDataByIdentifier)

根据DID写入数据服务允许诊断仪将数据写入由DID指定的内部存储单元。ECU应在数据写入成功后发送该服务的肯定响应。

19服务

19服务的请求响应格式较复杂,这里先不展开.
读故障码信息ReadDTCInformation,该服务有子服务,请求时报文可能如下:
19 01
01就是子功能,其他功能如下:

值(hex) 功能
01 根据状态掩码报告诊断故障代码数量
02 根据状态掩码报告诊断故障代码
04 根据诊断故障代码报告诊断故障代码快照记录
06 根据诊断故障代码报告诊断故障代码扩展数据记录
0A 报告支持的诊断故障代码

寻址方式

CAN是一种广播式的通信方式,即一条CAN报文发送出去后,在同一条CAN网络中的所有节点都能够收到该条CAN报文,那诊断仪在发出诊断请求报文后,具体是想诊断哪个节点,是通过什么方式判断呢?这里引出寻址方式的概念。
寻址方式有两种,一个叫物理寻址,另一个为功能寻址,物理寻址是诊断仪与单个ECU之间的诊断,而功能寻址是诊断仪与多个ECU之间的诊断,即诊断仪通过物理寻址方式发送请求报文时,只有指向的ECU可以回复响应报文;诊断仪通过功能寻址方式发送请求报文时,同一网络中支持功能寻址的所有ECU都需要回复响应报文。ECU收到诊断请求后,则通过消息的ID区分是物理寻址还是功能寻址,一般功能寻址的信号ID为0x7DF,物理寻址的消息ID为客户自定义,每个ECU都不一样。

例:整车同一网络中有ECU A, B, C, D多个节点,假设他们的物理请求消息ID为0x701, 0x702, 0x703, 0x704,响应消息地址分别为0x70A, 0x70B, 0x70C, 0x70D,所有ECU的功能寻址ID为0x7DF。
物理寻址时:
0x701 0x10 0x01 (对ECU A进行诊断请求)
0x70A 0x50 0x01 xx xx xx xx (仅ECU A响应)
功能寻址时:
0x7DF 0x10 0x01 (对所有ECU进行诊断请求)
0x70A 0x50 0x01 xx xx xx xx (ECU A响应)
0x70B 0x50 0x01 xx xx xx xx (ECU B响应)
0x70C 0x50 0x01 xx xx xx xx (ECU C响应)
0x70D 0x50 0x01 xx xx xx xx (ECU D响应)

总结

读完前面的内容后我们再重新看会开头的canlog中的uds报文:

现在我们可以理解,0x7F0就是我们在物理寻址请求的canid,而0x7F1就是ECU响应消息地址的id。
图中标记的两行分别是一条请求和一个肯定相应,02和06都表示数据长度,请求1001切换到默认会话,响应5001说明请求成功,后面的00 32 13 88 CC则是返回的数据。

通过本文的学习能看懂CAN日志后,为后续车载测试和对ECU相关的测试和渗透打下基础。
这里先简单的介绍一种测试流程,我们通过can收发设备将电脑和车辆或ECU连接,利用candump工具把车和ECU通信时的canlog抓下来,后续就可以进行报文伪造、重发、DOS、FUZZ等安全测试。

详细的测试环境的搭建和测试步骤以及UDS下的CAN底层原理在后续文章中再学习。