计算机系统应用教程网站

网站首页 > 技术文章 正文

漫话UDS之Service 27

btikc 2024-12-14 10:06:56 技术文章 21 ℃ 0 评论

在引入正题前,先扯点日常生活中熟悉的事:

现在智能手机几乎人手一部,对于机主,其实都会有一些希望对他人隐藏或者不想让他人看到的内容。有需求就会有实现,所以手机设置了密码解锁或者9宫格解锁

只有通过解锁,相当于赋予你权限,你才可以查阅对应的内容。

其实对于车载控制器,有类似与九宫格解锁的操作。因为在Tester对控制器做诊断应用的时候,有些操作是需要赋予权限才可以执行,比如对ECS电子控制转向系统,如果车辆正在运行,黑客恶意修改ECS参数(特别是伴随着车载以太网引入到车载网络中,这种场景更加常见),最终会导致驾驶员车毁人亡。因此在执行该服务时,在需求规范定义中需要执行解锁才可以执行服务(因为本文只讲解锁,当然还有更严格的安全认证措施,后续文章也会分享)。

对于汽车电子诊断范畴UDS协议中,常见需要解锁后才可以执行的服务:

Service 2E

Service 31

Service 2F

Reprogramming services

本文以如下内容,分享Service 27内容:

  1. UDS对Service 27定义
  2. 用图形说明Service 27
  3. CAPL(With CDD and without CDD)

UDS对Service 27定义

UDS协议对Service 27开篇有云:

The purpose of this service is to provide a means to access data and/or diagnostic services, which have restricted access for security, emissions, or safety reasons. Diagnostic services for downloading/uploading routines or data into a server and reading specific memory locations from a server are situations where security access may be required. Improper routines or data downloaded into a server could potentially damage the electronics or other vehicle components or risk the vehicle’s compliance to emission, safety, or security standards.

人话就是:

Service 27提供一种访问数据或者诊断服务的方法,只有通过Seed-key解锁环节才可以执行特定服务和功能。

在UDS协议中关于Service 27请求格式以及响应格式如下:

以上有两个注意事项:

A:Service 27是成对出现,奇数位是请求Seed,偶数位是发送Key;

B:一个ECU中可以有不同安全等级,可通过Subfunction来区分不同安全等级;

而对于安全等级状态模式切换,可参考如下图:

在UDS协议附录I关于安全访问整个状态机做了详细的处理逻辑描述

这里需要注意一点:

Tester尝试解锁控制器,第一次发送错误Key值,控制器响应NRC 35,等到第三次尝试解锁,控制器响应NRC 36(表示尝试次数已>=3),这时再去请求Seed值,会响应NRC 37,意味着需要等待Delay_Timer时间。可类比手机解锁,当使用者连续几次解锁失败后,手机会设置等待时间,这期间不允许尝试解锁,目的是防止持续破解,保护安全。

在等待Delay_Timer后,在最新版UDS协议中定义Att_Cnt=0

用图形说明Service 27


Request

Response

ECU

Tester

只有特定的诊断应用才需要进行解锁流程,而对于解锁过程只是将请求的Seed经过算法输出Key.

Key

Seed

Seed转变Key是将Seed数值做了特定处理:不管是左移还是溢出补零,再相与之类操作。目的是让输出值相对唯一,且不容易破解。

CAPL验证Service 27

通过CAPL验证Service 27解锁给过程。

  1. 首先新建CANoe工程,并新建Test Module(充当Tester)和仿真节点


  1. 整个Tester工程如下:

variables

{

char keyQual[30];

byte seedArray[4];

byte generatedKey[100];

dword actLen;

}

void mainTest()

{

long waitKeyRes;

diagSetTarget("VCU");


Sendrequest1();

testWaitForTimeout(1000);


Sendrequest2();


testWaitForTimeout(1000);

waitKeyRes=TestWaitForGenerateKeyFromSeed( seedArray, elcount( seedArray), 1, generatedKey, elcount(generatedKey), actLen, 10000);

write("waitKeyRes=%d,Key is (hex) %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",waitKeyRes,generatedKey[0],generatedKey[1],generatedKey[2],generatedKey[3],generatedKey[4],generatedKey[5],generatedKey[6],generatedKey[7],generatedKey[8],generatedKey[9],generatedKey[10],generatedKey[11],generatedKey[12],generatedKey[13],generatedKey[14],generatedKey[15]);

}

void Sendrequest1()

{

DiagRequest VCU.ExtendedDiagnosticSession_Start request1;


DiagSendRequest(request1);


testWaitForTimeout(1000);


}

void Sendrequest2()

{

DiagRequest VCU.requestSeed_1_Request request2;


DiagSendRequest(request2);


testWaitForTimeout(1000);

}

on diagResponse VCU.requestSeed_1_Request

{

long ret;


char buffer[100];


write("Go in this function");

if(DiagIsPositiveResponse(this))

{

ret=DiagGetParameterRaw(this,"SecuritySeed",seedArray,elcount(seedArray));


if(ret>=0)

{

write("Seed is (hex) %02X %02X %02X %02X",seedArray[0],seedArray[1],seedArray[2],seedArray[3]);

snprintf(keyQual, elCount(keyQual), "KeyLevel_0x01_Send");


ret=DiagStartGenerateKeyFromSeed("VCU",seedArray,elcount(seedArray),1,"Base Variant","");


if(ret==0)


{

write("Key computation for security level 1 was started");

}


else


{

write("Error code %ld during key calculation",ret);


if(ret==-84)


write("invalid security level");


if(ret==-86)


write("buffer too small");


}

}

else


write("Could not retrieve seed-parameter");


}

else

{

diagGetParameter(this, "RC", buffer, elCount(buffer));


write("Negative response received.\nNegative response code: 0x%02X - %s", (byte)DiagGetResponseCode(this), buffer);

}

}

  1. 仿真ECU工程如下:

on diagRequest VCU.requestSeed_1_Request

{

Diagresponse this resp;

byte seedArray[4]={0x11,0x22,0x33,0x44};


DiagSetParameterRaw(resp,"SecuritySeed",seedArray,elcount(seedArray));

DiagSendResponse(resp);

}

  1. 如下路径添加待测dll文件:

运行后结果如下图;

初步验证该dll文件可以进行ECU解锁。

若连接真实ECU也可以通过该工程实现ECU解锁过程。

愿你我相信时间的力量,

做一个长期主义者!

作者简介 | 穿拖鞋的汉子

汽车电子工程师

公众号:车载诊断技术

chuantuoxiedehanzi@163.com

来,每天进步一点点!

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表