第4章:OBD请求与响应机制:Service ID(SID)详解
说实话,搞OBD逆向这么多年,我见过太多人一上来就拿着工具瞎发请求。结果呢?要么车没反应,要么收到一堆乱码。其实OBD的通信机制没那么玄乎,核心就是搞清楚SID和PID怎么搭配。
今天咱们就把这块彻底讲透。我会结合自己踩过的坑,带你一步步搞懂SID、PID,以及Mode 01和Mode 22到底差在哪。
4.1 Service ID(SID)到底是什么?
SID,全称Service Identifier。你可以把它理解成「命令码」。你告诉ECU:我要干什么。
OBD-II标准定义了9个SID,从01到09。每个SID代表一类服务。我整理了一张表,你一看就明白:
| SID | 服务名称 | 功能说明 |
|---|---|---|
| 01 | 请求当前动力系统数据 | 读取实时传感器值、状态 |
| 02 | 请求冻结帧数据 | 读取故障发生时的快照 |
| 03 | 请求排放相关故障码 | 读取已存储的DTC |
| 04 | 清除/复位故障码 | 清除DTC和冻结帧 |
| 05 | 请求氧传感器监测结果 | 非CAN总线专用 |
| 06 | 请求车载监测系统结果 | 读取OBD监测状态 |
| 07 | 请求当前/待定故障码 | 读取未确认的DTC |
| 08 | 请求执行车载系统测试 | 激活特定部件测试 |
| 09 | 请求车辆信息 | 读取VIN、CALID等 |
我个人习惯把SID 01和09称为「最常用兄弟」。一个看实时数据,一个读车辆身份信息。做逆向时,这两个基本天天打交道。
4.2 PID结构:请求的具体参数
SID告诉ECU「我要干什么」,PID告诉ECU「我要哪个具体数据」。两者缺一不可。
举个例子:
请求:01 0D
解释:SID=01(请求当前数据),PID=0D(车速)
响应:41 0D 64
解释:41=01+0x40(响应标识),0D=PID回显,64=车速100km/h
PID的编码规则很简单:
- 每个PID占用1个字节(0x00-0xFF)
- 0x00-0x1F:标准OBD-II PID
- 0x20-0x5F:制造商自定义PID
- 0x60-0xFF:保留或扩展
重点来了:PID 0x00是个特殊存在。它用来查询「支持哪些PID」。你发01 00,ECU会返回一个4字节的位掩码,告诉你哪些PID可用。
我在项目中遇到过一台车,发01 00返回全是0。当时我还以为ECU坏了。后来才发现,那台车用的是Mode 22,不是Mode 01。嗯,这就是咱们接下来要说的坑。
4.3 Mode 01 vs Mode 22:到底差在哪?
很多新手会问:Mode 01和Mode 22不都是读数据吗?
对,都是读数据。但区别大了去了。
| 对比项 | Mode 01 | Mode 22 |
|---|---|---|
| 协议标准 | ISO 15031(OBD-II) | ISO 14229(UDS) |
| PID范围 | 0x00-0xFF(标准+部分自定义) | 0x0000-0xFFFF(完全自定义) |
| 响应格式 | SID+0x40 + PID + 数据 | SID+0x40 + DID(2字节)+ 数据 |
| 适用场景 | 排放相关、通用诊断 | 整车所有ECU、深度诊断 |
| 数据长度 | 固定(通常1-4字节) | 可变(可长可短) |
说白了,Mode 01是「公共接口」,谁都能用。Mode 22是「私有接口」,只有厂家知道怎么用。
我曾经帮朋友逆向一台德系车,用Mode 01死活读不到变速箱油温。后来试了Mode 22,发22 F1 37,嘿,数据就出来了。你想想看,这就是Mode 22的威力——它能访问Mode 01碰不到的数据。
注意:Mode 22的DID(Data Identifier)是2字节的,范围0x0000-0xFFFF。别拿Mode 01的1字节PID去套,会出错的。
4.4 多帧响应处理:数据太长怎么办?
有时候ECU返回的数据太多,一帧装不下。比如读VIN(17个字符),或者读大量DTC。这时候就需要多帧传输。
ISO 15765-2(CAN总线)定义了两种多帧机制:
- 连续帧(CF):第一帧告诉你有多少数据,后续帧接着发
- 流控制帧(FC):接收方告诉发送方「慢点发」或「继续发」
实际抓包看起来是这样的:
请求:09 02(读VIN)
响应:
第一帧(FF):10 14 49 02 01 57 56 47
- 10 = 第一帧标识
- 14 = 后续还有20字节(0x14)
- 49 = 09+0x40
- 02 = PID回显
- 01 = 数据长度
- 57 56 47 = "WVG"(VIN开头)
后续帧(CF):21 5A 30 52 4A 38 4D 33
- 21 = 后续帧标识(2表示第2帧)
- 5A 30 52 4A 38 4D 33 = "Z0RJ8M3"
... 直到所有数据收完
我刚开始做多帧解析时,犯过一个低级错误:没处理流控制帧。结果ECU发完第一帧后,我没发FC,ECU就一直等。程序卡死了。后来我加了个自动回复FC的逻辑,问题就解决了。
我的经验:处理多帧时,建议用状态机。状态包括:等待第一帧、等待后续帧、数据完整。别用简单的循环等待,容易超时。
4.5 实战:一个完整的请求-响应流程
咱们拿读取发动机转速来演示一下完整流程:
- 构建请求:01 0C(SID=01,PID=0C=转速)
- 发送:通过CAN总线发送7E0 03 01 0C
- 接收响应:7E8 04 41 0C 0E 74
- 解析:
- 41 = 01+0x40(响应标识)
- 0C = PID回显
- 0E 74 = 转速值(0x0E74 = 3700 RPM)
公式:转速 = (A*256 + B) / 4
代入:3700 / 4 = 925 RPM
嗯,怠速状态,正常。
4.6 避坑指南
最后分享几个我踩过的坑:
- 别信PID列表:同一款车不同年款,支持的PID可能不一样。每次都要先发01 00确认。
- 响应延迟:ECU不是实时响应的。我见过有些ECU要等500ms才回。别急着超时。
- 多帧别漏帧:特别是连续帧,序号是循环的(0-15)。漏了一帧,整个数据就废了。
- Mode 22的DID别搞错:有些厂家把DID定义成3字节。遇到这种情况,只能靠逆向猜了。
好了,SID和PID这块就讲这么多。下一章咱们聊具体的PID解析,包括车速、转速、氧传感器这些常用数据的计算公式。到时候我会带几个真实案例,保证你听完就能上手。