HowIHackedMyCar 2021款 现代IONIQ (五)CAN Bus分析

HowIHackedMyCar 2021款 现代IONIQ (一)
HowIHackedMyCar 2021款 现代IONIQ (二) Making a Backdoor
HowIHackedMyCar 2021款 现代IONIQ (三) Making Software
HowIHackedMyCar 2021款 现代IONIQ (四)Creating Custom Firmware

本合集共7部分,本篇为第五部分

来源:programmingwithstyle.com,感谢greenluigi1

如果您还没有阅读前几部分,请先阅读第一部分,第二部分,第三部分。


Why

在黑掉我的车载主机之后的某个时候,我想到了一个主意。我想要创建一个应用程序,为钥匙增加更多功能,在车辆上执行其他操作,比如启动引擎。这将使我所做的研究和工作对普通用户真正有用。


What I Ended Up

在思考最佳实现方式时,我决定弄清楚系统中的各种应用程序如何与汽车的其余部分通信。我知道这最终将引导我了解如何至少读取和写入汽车的CAN总线。如果我能访问这些数据,我可能会看到钥匙扣上的按钮按压,或者至少看到按钮按压的后果。


Starting Off

为了弄清楚应用程序最终如何将信号发送到CAN总线,我需要找到至少一个CAN总线的函数示例,这样我就可以从源头追踪回去。我决定选择ccOS的HBody库。


正如我在第三部分中提到的,ccOS是由现代和Nvidia联合开发的一个新汽车操作系统项目,它与汽车高度集成。一些ccOS的核心组件的早期工作,包括一些库在D-Audio 2V中是可用的。这些库提供了许多可以查询汽车某些状态的函数,比如检查门是否打开,或者执行某些操作,比如设置空调的温度。为了让库执行这些事情,它不可避免地需要访问CAN总线。所以我首先通过逆向工程来研究在/usr/lib/libHVehicle.so.1.0.0中发现的HVehicle库。


我选择的是HBody上的requestDoorLock()。我发现它的实现方法叫做“ccos::vehicle::general::HBody::HBodyImpl::requestDoorLock”在HVehicle库中。

HowIHackedMyCar 2021款 现代IONIQ (五)CAN Bus分析
这个方法调用了另一个名为“requestRemoteControlVehicle”的函数,最终调用了同名的HBodyGDBus上的方法。


GDBus?
好吧,什么是“GDBus”?
我谷歌了一下这个词,看起来“GDBus”是“D-Bus的特定实现”。
太好了,这解释清楚了。
什么是“D-Bus”?
又谷歌了一下后,我了解到D-Bus是“Desktop Bus”的缩写,是一种基于消息的通信机制,允许计算机上的不同进程相互通信。真棒。
所以看起来肯定有另一个进程接收这个“requestRemoteControlVehicle” D-Bus方法调用,而那个进程与CAN总线通信。
我拿出了我最喜欢的工具之一,Agent Ransack(一个超酷且快速的Windows文件搜索工具)在我的车载主机固件中搜索了“requestRemoteControlVehicle”字符串。
HowIHackedMyCar 2021款 现代IONIQ (五)CAN Bus分析

Agent Ransack发现了3个包含方法名称的文件,automotivefw,HBody.h和libHVehicle.so.1.0.0。我已经知道了头文件本身和它的库,所以它一定在automotivefw中!

我搜索了方法名称,找到了HBodyStubImpl::requestRemoteControlVehicle()。在其中,我发现了多次调用HBodyStubImpl::sendPacket()方法。我猜测这就是向CAN总线发送数据的方法。HowIHackedMyCar 2021款 现代IONIQ (五)CAN Bus分析

我进入那个函数,发现它调用了MicomService::sendPacket(),调用了MicomPacketRunner::sendPacket(),调用了MicomPacketRunner::rawsend(),最后使用了原生的send()函数来实际发送数据。

send()方法被用来通过套接字发送一些缓冲区。这意味着CAN总线直接或间接地可以通过系统中打开的某个套接字访问。我所要做的就是找出哪个套接字。

由于send函数需要使用socket()函数打开一个套接字,我搜索了它的使用情况。在automotivefw中只有一个对socket()的调用,MicomPacketRunner的构造函数:

HowIHackedMyCar 2021款 现代IONIQ (五)CAN Bus分析
socket()方法有三个参数:domain, type, & protocoldomain被设置为1,表示它是AF_UNIX/Unix domain socket。基于在_socket_make_sockaddr_un()调用中的“micom_mux”字符串,我猜测我要找的套接字是一个名为“micom_mux”的Unix domain socket

当我最初尝试在第二部分中创建的backdoor时,我保存了netstat命令的输出。我查看了它,并发现多个连接到“@micom_mux”套接字。名称中的“@”意味着套接字被保存在一个不在文件系统中的抽象命名空间中。

HowIHackedMyCar 2021款 现代IONIQ (五)CAN Bus分析

所以现在我需要访问那个套接字,有什么比使用socat更好的方法呢?socat是一个强大的中继实用程序,内置于linux中,允许你在两个连接之间中继数据。我决定最简单的方法是将@micom_mux套接字的输出管道到我的闪存驱动器,我可以稍后复制并分析。

我“cd”进入我的闪存驱动器,然后运行命令:

socat ABSTRACT-CLIENT:micom_mux STDIO > micomOutput

等待了一会儿。大约一分钟后,我终止了进程并拔出闪存驱动器查看文件。我打开它,很快发现它完全是空的。我重试了命令,并在车上尝试了一些操作,比如打开和锁定车门,然后停止socat并运行“sync”。我查看文件,再次发现它完全是空的。

套接字可能没有自动通过它发送CAN总线数据。也许它需要某种起始数据包或秘密才能开始监听数据?

The Magic Packet
我开始寻找这个魔法数据包,通过查看每个与“micom_mux”套接字通信的应用程序。我发现每个应用程序一旦连接到micom_mux套接字就会发送一个特定的数据包。
我发现至少有6个app/库使用micom_mux:
app-logic-nmode:
      用于N模式,这是一个允许用户监视和调整某些高级设置的应用程序,如启动RPM或现代N车辆的牵引力控制。
CANManager:      
      – BlueLink用于与CAN总线通信。
RDOPacketRunner:      
      – 由收音机应用程序使用。
HevService:
      用于监视混合动力车辆统计数据。
EvService:
      用于监视电动车辆统计数据。
Automotivefw
      大多数应用程序与之通信以控制车辆的核心框架。

每个应用程序都有不同的 Magic packets
App Magic Packet

app-logic-nmode

FF8AFFF3FFFF00038ACA00

CANManager

FF8AFFF3FFFF00028E00

RDOPacketRunner

FF8AFFF3FFFF0003879000

HevService

FF8AFFF3FFFF00028800

EvService

FF8AFFF3FFFF000388C200

Automotivefw

FF8AFFF1FFFF00018A

现在我只是需要弄清楚这些意味着什么。通过比较这些数据包,我确实注意到了一些模式:
它们都以FF8AFF开头
其次是F1或F3
然后是FFFF
长度(在这种情况下是0001、0002或0003)
之前长度的n个字节,大多数以00结尾

我不太确定如何处理这些信息,所以我决定尝试找出哪个应用程序实际上正在接收这些数据包,以了解更多信息。

micomd

我发现/usr/bin/中有一个名为“micomd”的应用程序,它似乎是套接字的来源。通过逆向工程,我发现应用程序遵循了这个流程:

连接到“/dev/tcc_ipc”。(micom数据来自哪里)

创建“micom_mux”抽象unix socket

等待新客户端。

一旦客户端加入,它将开始读取数据包。

      – 它将检查是否是Magic Packet,方法是查看第二个字节是否为8A,第三个字节是否为FF。

      然后它检查第四个字节

            F1:它是AutomotiveFW数据包,它读取数据包的其余部分,并向CAN总线发送一个特殊的硬编码数据包。

            F2:它是AutomotiveFW数据包,它读取数据包的其余部分

            F3:它是不同应用程序的数据包,它读取数据包的其余部分


这解释了一些事情,但我仍然不知道整个数据包的含义,特别是可变长度部分。但是,我在查看micomd时发现它被大量记录,所以我决定查看一下。
在查看我之前的日志转储中与micom相关的日志时,我发现了这个:
Hev_Packet: sendPacket:0550:send sid:88, rid:0c, type:01, Func:0x0c03, paylL:0, FuncName:HEV_RESET_GRAPH_CHev_Packet: sendPacket:0556:send sid:88, rid:0c, type:01, Func:0x0c03, paylL:1, FuncName:HEV_RESET_GRAPH_CHev_Packet: send sid:88, rid:0c, type:01, Func:0x0c03, paylL:1, FuncName:HEV_RESET_GRAPH_CHev_Packet: S => D micom :ff880c010c030001:74
嗯,看起来这里的最后一个日志条目是一个micom数据包,上面的日志条目有它的名称。
这可能是我需要的。看起来数据包格式是:
Always FF (Byte)
SID (Byte)
RID (Byte)
Type: (Byte)
Function (Int16, Big Endian)
Payload Length (Int16, Big Endian)
Payload (Array of {Payload Length} Bytes)

我还发现了一些与micom相关的更多日志:
src/VRM/Service/DiagnosticUtils/DiagMainUtil.cpp checkDiagState       00120 checkDiagState(): diag type[3], state[0]MicomD  : send_data: c => m : ff 87 03 01 03 5b 00 02 01 21 MicomD  : ReceivedData[SUCCESS]: m => c : : ff 03 87 01 83 5b 00 05 01 28 46 90 58
看起来调用checkDiagState()函数发送了一个SID为87和RID为03的数据包,并接收了一个SID和RID相反的回复数据包。我猜测SID是发送者ID,RID是接收者ID。

在查看所有日志时,我注意到我之前发现的魔法数据包的有效载荷中都有每一个RID:
示例数据包:
MicomD  : ReceivedData[SUCCESS]: m => c : : ff 03 87 01 83 5b 00 05 01 22 2e 00 aa

有一个RID为87,在我的RDOPacketRunner中
App Magic Packet

RDOPacketRunner

FF8AFFF3FFFF0003879000

这可能意味着magic packet用于订阅来自micom的数据包,这些数据包设置了特定的RID。

好的,既然我可能知道魔法数据包的作用了,现在我可以使用socat尝试读取一些真正的数据。我使用以下命令使用socat打开micom套接字,发送CANManager的魔法数据包(FF8AFFF3FFFF00028E00),然后将它接收到的所有内容写入我的闪存驱动器上的文件:
printf "xFFx8AxFFxF3xFFxFFx00x02x8Ex00" | socat ABSTRACT-CLIENT:micom_mux STDIO > micomOutput

运行了大约一分钟,我关闭了socat进程,运行了sync,然后拔出了我的闪存驱动器。这一次我有了数据,现在我只需要某种方式来读取它。


读取数据
为了获得数据的基本布局,我使用了十六进制编辑器010来查看数据。
HowIHackedMyCar 2021款 现代IONIQ (五)CAN Bus分析
我捕获的第一个数据包是:
Packed Start:FF
SID:0B
RID:8E
类型:01
功能:8BC7
负载长度:0100(256)

我猜我捕获了一些大的数据包,这可能会使查看和突出显示一个数据包在哪里结束和另一个数据包在哪里开始变得困难。但幸运的是,010有一个非常方便的工具帮助我解决了这个问题:Templates。
HowIHackedMyCar 2021款 现代IONIQ (五)CAN Bus分析
Templates是一个超级酷的功能,允许您编写类似C/C++结构体的布局,并让010将其转换为更易于阅读/解析的数据。
//------------------------------------------------//--- 010 Editor v12.0.1 Binary Template////      File: MicomPacketTemplate//   Authors: greenluigi1//   Version: 1.0//   Purpose: Decode raw data stream from micomd process on D-Audio 2V systems//  Category: // File Mask: //  ID Bytes: //   History: //------------------------------------------------BigEndian();
struct{ while(!FEof()) { struct { byte FF; byte sid; byte rid; byte type; ushort func; ushort payloadLength; byte payload[payloadLength]; } MicomPacket; }} MicomDataStream;

这个我创建的模板这样做:声明文件代表一个名为MicomDataStream的结构体。MicomDataStream包含许多MicomPackets,它将继续读取MicomPackets,直到到达文件末尾(!FEof)。MicomPacket包含7个字段:FF,sid,rid,type,func,payloadLength和payload。

因为010能够解析我收到的每个数据包,我可以看到我总共收到了1070个数据包,它们都有256字节的有效载荷。


The Numbers Mason,What do they Mean‽
我现在可以告诉一个数据包在哪里结束和另一个数据包在哪里开始,但数据包里面的数据对我来说仍然是未知的。
我本质上是一个程序员,所以我决定编写一个程序,它接受这些数据包的数据流,然后实时记录/解码它们。
最终我创建了一个C#程序,它在一个TCP端口上监听这个数据流并解析它。
我使用以下命令将@micom_mux的流量转发到我的包解码服务器,该服务器运行在我的笔记本电脑上:
socat ABSTRACT-CLIENT:micom_mux TCP4:192.168.0.3:6999

然后我开始摆弄它。我使用我的程序发送一个带有每个可能RID的魔法数据包,这样我可以监听所有内容,然后我弄清楚了哪些RID看起来不像嘈杂的“垃圾”,然后隔离了几个有用的数据包。

我找到的一个是我找到的数据包指示驾驶员车门是打开还是关闭的:
– Packet Start: FF
– SID: 44
– RID: C1
– Type: 00
– Function: C403
– PayloadLength: 02

– Payload: (00 if closed 01 if open) ?? (Random byte? Checksum? Timing?)


我继续转储micom数据,同时尝试执行各种操作。慢慢地,我弄清楚了一些更多的数据包。
我甚至做了一个小UI来显示车门的状态:
HowIHackedMyCar 2021款 现代IONIQ (五)CAN Bus分析
一旦我有机会清理它并添加一些更多的数据包类型,我可能会在未来的某个时候发布这个应用程序。

一旦我掌握了读取这些数据的技巧,我就去看看是否能够从我的钥匙扣获取任何数据,不幸的是,我不能。我无法读取钥匙扣上的按钮按压,也看不到钥匙扣是否在范围内。我只能读取如果车门锁的状态发生变化,这严重限制了我为钥匙扣添加新功能的能力。


You can’t win every time
虽然我对micom的初步研究并不是很有成效,但能够短暂地窥见车载主机以及汽车本身的工作原理还是很好的。现在,我将停止研究micom系统。此外,还有一个新的固件更新要分析!

HowIHackedMyCar 2021款 现代IONIQ (五)CAN Bus分析

HowIHackedMyCar 2021款 现代IONIQ (五)CAN Bus分析



原文始发于微信公众号(安全脉脉):HowIHackedMyCar 2021款 现代IONIQ (五)CAN Bus分析

版权声明:admin 发表于 2024年5月28日 下午5:28。
转载请注明:HowIHackedMyCar 2021款 现代IONIQ (五)CAN Bus分析 | CTF导航

相关文章