记录|DCM 0x27服务
前言
0x27 服务是 UDS(ISO 14229)标准中的安全访问服务,目的是防止未授权的诊断操作。采用 Seed-Key 挑战-应答机制:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20Tester(上位机/诊断仪) ECU(板子)
│ │
│ ① 27 03 (Request Seed, Level 3) │
│─────────────────────────────────────→│
│ │ 生成 16 字节随机 Seed
│ ② 67 03 [Seed_16B] │ 保存 Seed 供后续比较
│←─────────────────────────────────────│
│ │
│ 用 Seed + Secret Key │
│ 计算 HMAC-SHA1 │
│ 取前 16 字节作为 Key │
│ │
│ ③ 27 04 [Key_16B] │
│─────────────────────────────────────→│
│ │ 用相同的 Seed + Secret Key
│ │ 计算 HMAC-SHA1
│ │ 比较结果是否一致
│ ④ 67 04 (Positive Response) │
│←─────────────────────────────────────│
│ │ 解锁对应安全等级
逆向
推测算法实现
证据 1:头文件声明了完整的输入/输出规范
Crypto_30_SecAccessFord_Algo.h 是公开的,明确定义了:
函数签名(参数类型、个数、含义)
输入长度(key=12, seed=16, mac=16/18)
输出(0=匹配,1=不匹配)
返回值(E_OK / E_NOT_OK)
接口契约是完全确定的。
证据 2:数据结构暴露了算法身份
密钥提取
原理:原静态库(.a / .lib)不是加密文件,它就是一堆 .o 目标文件的打包,其中并没有任何加密。
静态库的格式和 .exe/.elf 一样,都是标准的 ELF(或 COFF)格式,里面分段存储:
段|内容|加密?
—-|—-|—-
.text|机器码(函数体)|❌ 明文
.rodata|只读数据(常量、字符串、密钥)|❌ 明文
.data|可读写全局变量|❌ 明文
.symtab|符号表(函数名、变量名)|❌ 明文
第一步:看库里有什么符号
1 | arm-none-eabi-nm -S libService27.a |
nm = name list,列出所有符号。输出含义:1
200000000 0000000c R level01SecretKey
↑地址 ↑大小12字节 ↑类型:R=只读数据(.rodata)
符号类型标记:
T = 代码段(函数),t = 局部函数
R = 只读数据,r = 局部只读数据
D = 可读写数据
U = 未定义(引用外部符号)
第二步:导出段内容(提取数据)
1 | arm-none-eabi-objdump -s libService27.a |
-s = 显示所有段的十六进制 dump。找到目标段:1
2
3
4Contents of section .rodata.level01SecretKey:
0000 11223344 55667788 99aabbcc 123123
↑ ↑ ↑ ↑
每组4字节,这就是密钥的原始字节
读法:11 22 33 44 55 66 77 88 99 aa bb cc = 12 字节密钥。右边是 ASCII 对照(不可打印字符显示为 .)。
代码实现
各部分代码分析。
ECU端
1 | UdsSecurityInit() ← canstack_init() 启动时调用 |
上位机端
整体逻辑
1 | 上位机 (Tester/Python脚本) ECU (MSPM0G3519) |

