第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 实战:一个完整的请求-响应流程

咱们拿读取发动机转速来演示一下完整流程:

  1. 构建请求:01 0C(SID=01,PID=0C=转速)
  2. 发送:通过CAN总线发送7E0 03 01 0C
  3. 接收响应:7E8 04 41 0C 0E 74
  4. 解析:
    • 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解析,包括车速、转速、氧传感器这些常用数据的计算公式。到时候我会带几个真实案例,保证你听完就能上手。