How I Hacked my Car Part 4: CAN Bus/Micom Access

If you haven’t read the earlier parts, please do so: Part 1Part 2Part 3.
如果您还没有阅读前面的部分,请阅读:第 1 部分、第 2 部分、第 3 部分。

Why 为什么 ⌗

Some time after hacking my head unit I came up with an idea. I wanted to create an application which added more features to the standard key fob. By this I mean by entering a certain code of locks, unlocks, or other button presses on the fob, would do something else in the vehicle like start the engine. This would make the research and work I’ve done legitimately useful to the common user as it would add practical functionality to their vehicle.

Where I Ended Up

While theorizing the best way to do this, I decided it would be beneficial to figure out how the various applications in the system communicate with the rest of the car. I knew this would eventually lead me into how I can read and write to at least one of the vehicle’s CAN buses. If I could access this data I could potentially see the button presses from the fob, or at least see the consequences of the button presses.

Starting Off 开始 ⌗

To figure out how an app evenutally sends a signal into the CAN bus, I needed to find at least one good example of a function where the CAN bus would be needed so I could trace it back. I decided on ccOS’s HBody library.
为了弄清楚应用程序如何均匀地将信号发送到CAN总线,我需要找到至少一个需要CAN总线的函数的好例子,以便我可以追溯它。我决定使用 ccOS 的 HBody 库。

As I mentioned in Part 3ccOS is a joint project made by Hyundai and Nvidia to make a new car operating system which is highly integrated into the vehicle. Some early work of the core components of ccOS, including a couple of libraries is available in D-Audio 2V. These libraries offer numerous functions which can query certain statuses of the car like checking if a door is open, or perform certain actions like setting the temperature of the A/C. For the library to do these things, it inevitably needs to access the CAN bus. So, I started by reverse engineering the HVehicle library found at /usr/lib/
正如我在第 3 部分中提到的,ccOS 是现代和 Nvidia 的联合项目,旨在制造一种高度集成到车辆中的新汽车操作系统。ccOS 核心组件的一些早期工作,包括几个库,都可以在 D-Audio 2V 中找到。这些库提供了许多功能,可以查询汽车的某些状态,例如检查车门是否打开,或执行某些操作,例如设置空调的温度。对于磁带库来说,要做这些事情,它不可避免地需要访问CAN总线。因此,我首先对 /usr/lib/ 中的 HVehicle 库进行逆向工程。

The method I chose to investigate was requestDoorLock() on HBody. I found it’s implementation method called “ccos::vehicle::general::HBody::HBodyImpl::requestDoorLock” in the HVehicle library.
我选择调查的方法是 HBody 上的 requestDoorLock()。我在 HVehicle 库中找到了它的实现方法,称为“ccos::vehicle::general::HBody::HBodyImpl::requestDoorLock”。
How I Hacked my Car Part 4: CAN Bus/Micom Access

This method called another function named “requestRemoteControlVehicle”, which eventually called a method on the same name on the HBodyGDBus.
此方法调用了另一个名为“requestRemoteControlVehicle”的函数,该函数最终在 HBodyGDBus 上调用了同名方法。

GDBus? GDBus?⌗

Ok, what is a “GDBus”?

I Googled the term and it looks like “GDBus” is “a specific implementation of D-Bus”.

Great that clears things up.

What’s a “D-Bus”? 什么是“D-Bus”?

One more Google later and I learned D-Bus is short for “Desktop Bus” and is a messaged based communication mechanism that allows different processes on a computer to talk to each other. Neat.
后来又在谷歌上搜索了一下,我了解到 D-Bus 是“桌面总线”的缩写,是一种基于消息的通信机制,允许计算机上的不同进程相互通信。整洁。

So it looks like some other process must be receiving this “requestRemoteControlVehicle” D-Bus method call and that process communicates with the CAN Bus.

I pulled out one of my favorite tools, Agent Ransack(A super cool and fast file search tool for Windows) and searched for the string “requestRemoteControlVehicle” in my head unit’s firmware.
我拿出我最喜欢的工具之一,Agent Ransack(一款超酷且快速的 Windows 文件搜索工具),并在主机的固件中搜索字符串“requestRemoteControlVehicle”。
How I Hacked my Car Part 4: CAN Bus/Micom Access

Agent Ransack found 3 files which contained the method name, automotivefw, HBody.h, and I already knew of the header file itself and it’s library, so it must be in automotivefw!
特工 Ransack 发现了 3 个文件,其中包含方法名称、automotivefw、HBody.h 和。我已经知道头文件本身和它的库,所以它一定在 automotivefw 中!

I searched for the method name and found HBodyStubImpl::requestRemoteControlVehicle(). Within it, I found multiple calls to the HBodyStubImpl::sendPacket() method. I guessed that this is what sends data to the CAN bus.
我搜索了方法名称并找到了 HBodyStubImpl::requestRemoteControlVehicle()。在其中,我发现了对 HBodyStubImpl::sendPacket() 方法的多次调用。我猜这就是向CAN总线发送数据的原因。
How I Hacked my Car Part 4: CAN Bus/Micom Access

I went into that function and found it called MicomService::sendPacket(), which called into MicomPacketRunner::sendPacket(), which called into MicomPacketRunner::rawsend(), which finally used the native send() function to actually send the data. I love programming and its consequences.
我进入了该函数,发现它名为 MicomService::sendPacket(),它调用了 MicomPacketRunner::sendPacket(),它调用了 MicomPacketRunner::rawsend(),它最终使用本机 send() 函数实际发送数据。我喜欢编程及其后果。

The method send() is used to send some buffer through a socket. This meant the CAN bus is either directly or indirectly accessable through some socket that is open in the system. All I had to do is find out which socket.
send() 方法用于通过套接字发送一些缓冲区。这意味着CAN总线可以通过系统中打开的某个插座直接或间接访问。我所要做的就是找出哪个插座。

Since the send function requires a socket to be opened using the socket() function, I searched for uses of it. There was only a single call to socket() in automotivefw, the constructor for MicomPacketRunner:
由于 send 函数需要使用 socket() 函数打开套接字,因此我搜索了它的用法。在 automotivefw 中只有一次对 socket() 的调用,这是 MicomPacketRunner 的构造函数:
How I Hacked my Car Part 4: CAN Bus/Micom Access

The socket() method has 3 parameters: domain, type, & protocol. The domain was set to 1 which indicates it is a AF_UNIX/Unix domain socket. Based on the string “micom_mux” in the _socket_make_sockaddr_un() call I guessed that the socket I was looking for was a Unix domain socket named “micom_mux”.
socket() 方法有 3 个参数:domain、type 和 protocol。域设置为 1,表示它是 AF_UNIX/Unix 域套接字。根据 _socket_make_sockaddr_un() 调用中的字符串“micom_mux”,我猜想我要找的套接字是名为“micom_mux”的 Unix 域套接字。

When I was first playing around with my backdoor that I created in Part 2, I saved the output of the netstat command. I looked through it and found multiple connections to the “@micom_mux” socket. The “@” in the name means the socket is held in an abstract namespace which isn’t in the filesystem.
当我第一次使用我在第 2 部分中创建的后门时,我保存了 netstat 命令的输出。我浏览了它,发现了与“@micom_mux”套接字的多个连接。名称中的“@”表示套接字保存在不在文件系统中的抽象命名空间中。
How I Hacked my Car Part 4: CAN Bus/Micom Access

So now I needed to access that socket, what better way to do that then using socat? socat is a powerful relay utility built into linux which allows you to relay data between two connections. I decided the easiest way to get the data would be to pipe the output from the @micom_mux socket into my flash drive, which I could copy and analyse later.
所以现在我需要访问那个套接字,还有什么比使用 socat 更好的方法呢?SoCat 是 Linux 中内置的一个强大的中继实用程序,它允许您在两个连接之间中继数据。我决定获取数据的最简单方法是将输出从@micom_mux插槽传输到我的闪存驱动器中,以便稍后复制和分析。

I “cd”ed into my flash drive and I ran the command:

socat ABSTRACT-CLIENT:micom_mux STDIO > micomOutput

and waited for a bit. After a minute or so I killed the process and pulled out my flash drive to look at the file. I opened it up and quickly found it was completely empty. I retried the command and tried a few things in the car like opening and locking the doors, then stopped socat and running “sync”. I looked at the file and yet again it was completely empty.
等了一会儿。大约一分钟后,我终止了该进程并拔出闪存驱动器查看文件。我打开它,很快发现它完全是空的。我重试了这个命令,在车里尝试了一些事情,比如打开和锁上车门,然后停止 socat 并运行“同步”。我看了看文件,它又是完全空的。

The socket must not automatically send the CAN bus data through it. Maybe it needed some kind of starting packet or secret to start listening in on the data?
套接字不得自动通过它发送 CAN 总线数据。也许它需要某种起始数据包或秘密来开始监听数据?

The Magic Packet
魔术包 ⌗

I started search for this magic packet by looking at every application which talked to the “micom_mux” socket. I found that every app sent a specific packet once it connected to the micom_mux socket.

I found at least 6 apps/libraries that used micom_mux:
我发现至少有 6 个应用程序/库使用了micom_mux:

  • app-logic-nmode:  应用逻辑 nmode:
    • Used for N Mode which is an app which allow users to monitor and tune certain advanced settings like the Launch RPM or traction control in Hyundai N vehicles.
      用于 N 模式,这是一个应用程序,允许用户监控和调整某些高级设置,例如现代 N 车辆的启动 RPM 或牵引力控制。
  • CANManager:  CANManager:
    • Used by BlueLink to talk to the CAN bus.
      由 BlueLink 用于与 CAN 总线通信。
  • RDOPacketRunner:  RDOPacketRunner:
    • Used by the radio app.
  • HevService:  Hev服务:
    • Used to monitor hybrid vehicle stats.
  • EvService:  Ev服务:
    • Used to monitor electric vehicle stats.
  • Automotivefw:  汽车FW:
    • The core framework that most apps talk to to control the vehicle.

Each of these apps had different Magic packets:
这些应用程序中的每一个都有不同的 Magic 数据包:

App Magic Packet 魔术包
app-logic-nmode FF8AFFF3FFFF00038ACA00
CANManager FF8AFFF3FFFF00028E00
RDOPacketRunner FF8AFFF3FFFF0003879000
HevService FF8AFFF3FFFF00028800
EvService FF8AFFF3FFFF000388C200
Automotivefw FF8AFFF1FFFF00018A

Now I just had to figure out what these meant. By comparing these packets I did notice a few patterns:

  • They all started with FF8AFF
  • Which is followed by either a F1 or F3
    其次是 F1 或 F3
  • Then FFFF 然后是FFFF
  • A length (In this case 0001, 0002, or 0003)
    长度(在本例中为 0001、0002 或 0003)
  • n amount of bytes of the length previously, most end with 00
    之前长度的 n 个字节数,大多数以 00 结尾

I wasn’t entirely sure on what to make of this information, so I decided to try to find what application is actually receiving these packets to find out more.

micomd 米科姆 ⌗

I found an application called “micomd” in /usr/bin/ which appeared to be the source of the socket. After reverse engineering it I found out the app followed this flow:
我在 /usr/bin/ 中发现了一个名为“micomd”的应用程序,它似乎是套接字的来源。经过逆向工程后,我发现该应用程序遵循以程:

  • Connects to “/dev/tcc_ipc”. (Where the micom data comes from)
  • Creates the “micom_mux” abstract unix socket.
    创建“micom_mux”抽象 unix 套接字。
  • Waits for a new client.
  • Once a client joins it will start reading a packet.
  • It will check if it is a Magic Packet by seeing if the 2nd byte is 8A and the 3rd byte is FF.
    它将通过查看第 2 个字节是否为 8A 和第 3 个字节是否为 FF 来检查它是否是 Magic Packet。
  • Then it checks the 4th byte
    然后它检查第 4 个字节

    • F1: It is an AutomotiveFW packet, it reads the rest of the packet and sends out a special hardcoded packet to the CAN bus.
    • F2: It is an AutomotiveFW packet, it reads the rest of the packet
      F2:它是一个 AutomotiveFW 数据包,它读取数据包的其余部分
    • F3: It is a different app’s packet, it reads the rest of the packet

This explained a couple of things, but I still didn’t know what the entire packet meant, especially the variable length part. But, while looking at micomd I saw that it is heavily logged, so I decided to check that out.
这解释了一些事情,但我仍然不知道整个数据包是什么意思,尤其是可变长度部分。但是,在查看 micomd 时,我发现它被大量记录,所以我决定检查一下。

While looking at micom related logs from my previous log dumps I found this:
在查看我以前的日志转储中的 micom 相关日志时,我发现了这一点:

Hev_Packet: sendPacket:0550:send sid:88, rid:0c, type:01, Func:0x0c03, paylL:0, FuncName:HEV_RESET_GRAPH_C
Hev_Packet: sendPacket:0556:send sid:88, rid:0c, type:01, Func:0x0c03, paylL:1, FuncName:HEV_RESET_GRAPH_C
Hev_Packet: send sid:88, rid:0c, type:01, Func:0x0c03, paylL:1, FuncName:HEV_RESET_GRAPH_C
Hev_Packet: S => D micom :ff880c010c030001:74

Hmm, it looked like the last log entry here was a micom packet and the logs above it had it parted out with names.
嗯,看起来这里的最后一个日志条目是一个 micom 数据包,它上面的日志用名称分开了。

This might have been what I needed. It looks like the packet format is:

  • Always FF (Byte) 始终 FF(字节)
  • SID (Byte) SID (Byte)
  • RID (Byte) RID(字节)
  • Type: (Byte) 类型:(Byte)
  • Function (Int16, Big Endian)
    函数 (Int16, Big Endian)
  • Payload Length (Int16, Big Endian)
  • Payload (Array of {Payload Length} Bytes)
    Payload ({Payload length} 字节数组)

I also found some more logs related to the micom:
我还发现了更多与 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 

It looks like a function called checkDiagState() sends out a packet with a SID of 87 and a RID of 03 and receives a packet back with the SID and RID reversed. I guessed SID was a Sender ID and RID was a Receiver ID.
它看起来像一个名为 checkDiagState() 的函数发送一个 SID 为 87 且 RID 为 03 的数据包,并接收一个 SID 和 RID 相反的数据包。我猜 SID 是发件人 ID,RID 是收件人 ID。

While looking at all of the logs I noticed that every RID I saw was in the payload of the magic packets I found earlier:
在查看所有日志时,我注意到我看到的每个 RID 都在我之前发现的魔术包的有效负载中:

Example Packet:  示例数据包:

MicomD  : ReceivedData[SUCCESS]: m => c : : ff 03 87 01 83 5b 00 05 01 22 2e 00 aa

Has a RID of 87, which is in the payload of RDOPacketRunner
RID 为 87,位于 RDOPacketRunner 的有效负载中

App Magic Packet 魔术包
RDOPacketRunner FF8AFFF3FFFF0003879000

Which might mean the magic packet is used to subscribe to packets on from the micom which have a ceratin RID set.
这可能意味着魔术数据包用于订阅来自 micom 的数据包,这些数据包具有 ceratin RID 集。

Ok, since I probably knew what the magic packet does, I could now use socat to try to read some real data. I used the following command to use socat to open the micom socket, send the magic packet from CANManager (FF8AFFF3FFFF00028E00) and then write everything it receives to a file on my flash drive:
好的,既然我可能知道魔术包的作用,我现在可以使用 socat 尝试读取一些真实数据。我使用以下命令使用 socat 打开 micom 套接字,从 CANManager (FF8AFFF3FFFF00028E00) 发送魔术数据包,然后将它收到的所有内容写入我的闪存驱动器上的文件:

printf "\xFF\x8A\xFF\xF3\xFF\xFF\x00\x02\x8E\x00" | socat ABSTRACT-CLIENT:micom_mux STDIO > micomOutput

After letting it run for a minute I closed the socat process, ran sync, and pulled out my flash drive. This time I had some data, now I just had to read it some way.
让它运行一分钟后,我关闭了 socat 进程,运行同步,然后拔出我的闪存驱动器。这次我有一些数据,现在我只需要以某种方式阅读它。

Reading The Data
读取数据 ⌗

To get a basic layout of the data I used a the hex editor 010 to view the data.How I Hacked my Car Part 4: CAN Bus/Micom AccessThe first packet I captured was:
为了获得数据的基本布局,我使用了十六进制编辑器 010 来查看数据。我捕获的第一个数据包是:

  • Packet Start: FF 数据包开始:FF
  • SID: 0B SID:0B
  • RID: 8E RID:8E
  • Type: 01 类型: 01
  • Function: 8BC7 功能:8BC7
  • Payload Length: 0100 (256)
    有效载荷长度:0100 (256)

I guess I captured some large packets, which might make it hard to see and highlight where one ends and another begins. But luckily, 010 has a super handy tool which helped me with my problem: Templates.
我想我捕获了一些大数据包,这可能会使人们难以看到和突出显示一个结束和另一个开始的地方。但幸运的是,010 有一个超级方便的工具可以帮助我解决我的问题:模板。
How I Hacked my Car Part 4: CAN Bus/Micom Access

Templates are a super cool feature which allow you to write a C/C++ struct like layout and have 010 turn it into more readable/parsable data.
模板是一个非常酷的功能,它允许您编写类似布局的 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: 

            byte FF;
            byte sid;
            byte rid;
            byte type;
            ushort func;
            ushort payloadLength;
            byte payload[payloadLength];
        } MicomPacket;
} MicomDataStream;

This template I created does this: Declares the file represents a struct called MicomDataStream. MicomDataStream contains many MicomPackets and it will keep reading MicomPackets until it reaches the end of the file (!FEof()). MicomPacket contains 7 fields: FF, sid, rid, type, func, payloadLength, and payload.
我创建的这个模板是这样做的:声明文件表示一个名为 MicomDataStream 的结构。MicomDataStream 包含许多 MicomPackets,它将继续读取 MicomPackets,直到它到达文件的末尾 ( !FEof())。MicomPacket 包含 7 个字段:FF、sid、rid、type、func、payloadLength 和 payload。

Because 010 was able to parse every packet I received I could see that I received 1070 packets in total, and all of them had a 256 byte payload.
因为 010 能够解析我收到的每个数据包,我可以看到我总共收到了 1070 个数据包,并且所有数据包的有效负载都为 256 字节。

The Numbers Mason, What do they Mean‽
数字梅森,它们是什么意思‽ ⌗

I could now tell where one packet ends and another begins, but the data inside of them was still unknown to me.

I am a programmer at heart so I decided that I would write a program which takes in a data stream of these packets and then logs/decodes them live.

I ended up creating a C# program which listens on a TCP port for this data stream and parses it.
我最终创建了一个 C# 程序,该程序在 TCP 端口上侦听此数据流并对其进行解析。

I used the following command to relay the traffic from @micom_mux to my packet decoder server which was running on my laptop:

socat ABSTRACT-CLIENT:micom_mux TCP4:

Then I started to play around with it. I used my program to send a magic packet with every possible RID so I could listen to everything, then I figured out the RIDS that didn’t seem like noisy “garbage” and then isolated a couple of useful packets.
然后我开始玩它。我使用我的程序发送了一个包含所有可能的 RID 的神奇数据包,这样我就可以收听所有内容,然后我找出了看起来不像嘈杂的“垃圾”的 RIDS,然后隔离了几个有用的数据包。

One of the ones I found were the packets which indicated if the driver door opened or closed:

  • Packet Start: FF 数据包开始:FF
  • SID: 44 SID:44
  • RID: C1 RID:C1
  • Type: 00 类型: 00
  • Function: C403 功能:C403
  • PayloadLength: 02 有效载荷长度:02
  • Payload: (00 if closed 01 if open) ?? (Random byte? Checksum? Timing?)
    有效载荷:(00 如果关闭,01 如果打开)??(随机字节?校验和?时机?

I continued dumping the micom data while trying to do various actions. Slowly but surely I figured out a few more packets.
我继续转储 micom 数据,同时尝试执行各种操作。慢慢地,但肯定地,我又想出了几个包。

I even made a little UI to show the status of the doors:
How I Hacked my Car Part 4: CAN Bus/Micom Access

I may release this application sometime in the future once I get a chance to clean it up and add some more packet types to it.

Once I got the hang of reading this data I went to see if I could get any data from my key fob, unfortunately I could not. I could not read button presses from the fob or see if the fob was within range. The only thing I could read was the status of the door’s locks if they changed. This severely limited my ability to add new functionality to the fob.

You can’t win every time

While my inital research into the micom wasn’t very fruitful for my intended application, it was still nice to get a breif glimspe into how the head unit, and the car itself worked. For now I will stop looking into the micom system. Besides, there is a new firmware update to hack!
虽然我对 micom 的初步研究对于我的预期应用来说并不是很有成效,但能够深入了解主机和汽车本身的工作方式仍然很好。现在,我将停止研究micom系统。此外,还有一个新的固件更新可以破解!

Further Reading 延伸阅读 ⌗

If this post did not quite scratch the itch of reading a deep dive into the micom system, try reading Reversing Kia Motors Head Unit to discover and exploit software vulnerabilities by Gianpiero Costantino & Ilaria Matteucci. The paper goes into a vulnerability Gianpiero & Ilaria found in Kia head units that exploit a similar micom process. They go pretty deep into their findings and it is overall a good read.
如果这篇文章没有完全触及对micom系统的深入研究,请尝试阅读Gianpiero Costantino和Ilaria Matteucci的Reversing Kia Motors Head Unit以发现和利用软件漏洞。这篇论文探讨了Gianpiero和Ilaria在起亚主机中发现的漏洞,该漏洞利用了类似的micom过程。他们非常深入地研究他们的发现,总的来说是一本很好的读物。

原文始发于Programming With Style:How I Hacked my Car Part 4: CAN Bus/Micom Access

版权声明:admin 发表于 2024年6月9日 上午10:05。
转载请注明:How I Hacked my Car Part 4: CAN Bus/Micom Access | CTF导航