介绍
在本系列博客文章中,我将介绍我修改 2010 款大众高尔夫 Mk6 电子助力转向 (EPS) ECU 固件的尝试。从 2008 年至今,所有大众 PQ 平台汽车都可能配备这种转向齿条。 PQ46 平台的汽车仍在生产(例如 2022 年 Pasat NMS)。这可能意味着这是该领域产量最多的 EPS 模块之一。
尽管该行李架早在 2008 年就已推出,但已经支持大众术语中的车道保持辅助系统 (LKAS) 或航向控制辅助系统 (HCA)。这使得该汽车可以与开源驾驶员辅助系统 openpilot 一起使用。不幸的是,连续运行 6 分钟或低于 50 公里/小时后,转向命令将不被接受。那时你需要脱离一整秒。我认为,当基于摄像头的驾驶员监控系统已经到位时,这些措施会适得其反,并会损害安全。因此,我想对此 EPS 上运行的固件进行一些修改以禁用它们。
在我之前的汽车黑客项目以及对大众 ECU 的研究中,我注意到互联网上很少有好的资源来描述从让 ECU 在桌面上运行到刷新修改后的固件的整个过程。在这一系列博客文章中,我将描述我破解这个 ECU 的旅程,包括死胡同和弯路。对于每个部分,我还将提供一些可能适用于其他 ECU 或其他品牌的背景信息。
在第一部分中,我将在我的办公桌上运行第二个 ECU,并建立诊断通信。在第二部分中,我将无法从模块中提取固件,但会找到一个固件更新文件,并在解密后将其加载到 Ghidra 中。在第三部分中,我将描述实际的逆向工程过程,并确定我想要对固件制作的补丁。在第四部分也是最后一部分中,我将从 ECU 中提取引导加载程序,并描述刷新过程。
获取零件
破解 ECU 的第一步是获取一个(或多个)有问题的 ECU 1 。为此,我们需要获取零件号。如果 ECU 位于可触及的位置,则通常可以从模块中读取零件号。如果 ECU 深埋在汽车内部,您也许可以在制造商零件网站或 咸鱼上找到它。
或者,如果您想 100% 确定,您可以使用诊断工具通过 CAN 询问 ECU。通常,它能够直接向您报告其自己的部件号。本例中使用了后一种方法,部件号为: 1K0909144E
。
有了零件编号,我们就可以寻找二手零件。汽车越旧、销量越多,这就越容易、越便宜。
把东西拆开
现在我们已经有了我们感兴趣的 ECU 的副本,我们可以仔细看看它。我们的首要目标是启动并运行它,并通过 CAN 与它通信,以确保它仍然可以工作。其次,我们希望将调试器连接到内部的微控制器,看看在调试访问未禁用的情况下是否可以提取固件。
要连接到 ECU,我们必须找到连接器的引脚排列。这通常可以使用原始原理图来获得。大多数汽车制造商都提供所有手册和原理图的订阅服务,通常提供便宜的 1 天选项(例如丰田 TIS、本田 Techinfo 和大众 Erwin)。高级订阅通常还附带原始诊断软件,该软件可与任何 J2534 加密狗(例如 panda 或 Tactrix)一起使用。
在本例中,将其连接到 panda 并运行简单的转储工具后,我们看到了一些不错的 CAN 流量。我们可以将其与相应的 Golf DBC 文件进行匹配,并确认这些确实是 EPS 发送的消息( Lenkwinkel_1
、 Lenkhilfe_3
、 Lenkhilfe_1
和 Lenkhilfe_2
)。
hex ( dec) data
0x0C2( 194) b'0000000080224bdd'
0x0D0( 208) b'44b0002004d0'
0x3D0( 976) b'00a10028005d'
0x3D2( 978) b'52411200010000'
建立通信并确保模块处于活动状态后,我们想看看内部,看看我们正在处理什么。然而,打开之后却给我带来了小小的惊喜。这些电子产品似乎是使用附着在某些基板上的裸芯片制造的,可能是为了降低成本并提高高温下的可靠性。该板由两部分组成,一个是带有 CPU 和 CAN 收发器的低功耗部分,另一个是带有 6 个 MOSFET 形成三相 H 桥的高功率部分。
然而,这意味着我们没有部件号来查找数据表,也无法附加调试器。黄色芯片可能是主 CPU 芯片,但标记 ( CL220CA
) 不会出现在 google 中。如果有人认识这个 CPU,我很想了解更多信息!
由于我们不知道我们正在处理的具体微控制器是什么,并且首先没有暴露连接调试器的连接,所以我们无法继续使用这种方法。要了解有关此 ECU 的更多信息,我们必须使用可用的 CAN 接口进行更多探索。
尽管我们没有 CPU 的部件号,但我们仍然可以做出一些有根据的猜测。 ECU 中只使用了几种不同的 CPU,尤其是需要 ASIL D 等级(安全的最高要求)的动力转向电机。这些微控制器通常具有多个以锁步方式运行的内核,并与外部看门狗相连以提供冗余。选项基本上是:
英飞凌 TriCore。例如TC2xxx。我最近在较新的现代 ECU 中看到了这些。如果它们启用 JTAG(我研究过的 ECU 就是这种情况),您可以使用 miniWiggler 轻松转储它们。
-
V850。例如瑞萨PD70Fxxxx。可以通过内置的引导模式转储。我在使用 windows flash 工具方面从来没有什么运气,但是有很好的 python 实现。
-
PowerPC。例如 ST/NXP/Freescale MPC5xxx 或更新的 S32R2x 4 。可以使用多重链接转储。
-
V850。例如瑞萨PD70Fxxxx。可以通过内置的引导模式转储。我在使用 windows flash 工具方面从来没有什么运气,但是有很好的 python 实现。
-
ARM。例如NXP S32K3。这似乎是最新的微控制器系列,我还没有在实际的 ECU 中看到过这一点。由于汽车电子的开发周期较长,几年后你可能才能看到它。
-
C166。比如XC164CS,不过这个架构好像已经停产了。可以通过向 CAN 引导加载程序发送特殊的转储脚本来转储。
通常,连接调试器所需的连接是使用未填充的排针或散布在 PCB 周围的裸焊盘来暴露的。使用数据表和万用表,您可以了解如何连接调试器。
如果微控制器采用 BGA 封装并且引脚未暴露,则可以使用 JTAGULATOR 来“暴力破解”调试器引脚排列。如果这没有产生任何结果,您可以通过拆焊 BGA 组件来牺牲另一个 ECU。
由于我们已经使用 panda 将 ECU 连接到计算机,因此我们可以尝试弄清楚是否可以通过一种标准化诊断协议(例如 UDS 或其前身 KWP2000)与其进行通信。 UDS/KWP2000 有许多有用的“端点”,包括读取内存,因此这将是一个很好的起点。
我们可以从运行一个小的扫描脚本开始。这会将 UDS“测试仪存在”命令发送到最常用的诊断地址(0x700 – 0x7ff、0x18da00f1 – 0x18dafff1)。然而,这并没有返回任何点击。这意味着不使用UDS/KWP2000,至少不使用标准传输ISO-TP。
由于 CAN 消息只能包含 8 个字节,因此通常在诊断协议和原始 CAN 消息之间使用传输层来传输更大的数据块。大多数 ECU 使用 ISO-TP,它使用每个消息中的第一个字节来指示其序列计数器以及是否会跟随更多消息。它还包含一些针对接收 ECU 尚未准备好接收的情况的流量控制。对于 0x7XX 范围内的诊断,响应通常在 TX 地址 + 0x8 上发送,对于 0x18daXXf1 范围内的消息,地址的最后两个字节会被交换。
此时,我决定连接一个商用大众诊断适配器,它使用 Android 应用程序与 ECU 对话,看看会出现什么情况。在说服加密狗连接后(即使大部分汽车不存在于 CAN 总线上),它能够显示有关 ECU 的一些诊断信息。
https://obdeleven.com/
大众汽车传输协议 2.0 (TP 2.0)
现在正在进行一些通信,我使用panda来嗅探 CAN 流量。这给我们带来了以下流量:
time address data
0.339 0x200 b'09c00010000301' # dongle - Request channel open
0.342 0x209 b'00d00003a80701' # ECU - Channel open response
0.343 0x7a8 b'a00f8aff0aff' # dongle - Parameter request
0.352 0x300 b'a10f8aff4aff' # ECU. - Parameter response
0.407 0x7a8 b'1000021089' # dongle - 0x10 0x89 - Enter diagnostics mode 0x89
0.412 0x300 b'b1' # ECU - ACK
0.422 0x300 b'1000025089' # ECU - 0x50 0x89 - Mode 0x89 entered
0.425 0x7a8 b'b1' # dongle - ACK
0.587 0x7a8 b'1100021089' # dongle - 0x10 0x89 - Enter diagnostics mode 0x89
0.592 0x300 b'b2' # ECU - ACK
0.602 0x300 b'1100025089' # ECU - 0x50 0x89 - Mode 0x89 entered
0.605 0x7a8 b'b2' # dongle - ACK
0.643 0x7a8 b'1200021a9b' # dongle - 0x1a 0x9b - Ecu identification
0.652 0x300 b'b3' # ECU - ACK
0.662 0x300 b'2200305a9b314b30' # ECU - "Z.1K0"
0.672 0x300 b'2339303931343445' # ECU - "909144E"
0.682 0x300 b'2420203235303100' # ECU - " 2501."
0.692 0x300 b'2500000000064016' # ECU - ".....@."
0.702 0x300 b'26054d4550535f5a' # ECU - ".MEPS_Z"
0.712 0x300 b'27464c53204b6c2e' # ECU - "FLS Kl."
0.722 0x300 b'2820313834202020' # ECU - " 184. "
0.732 0x300 b'1920' # ECU - " "
0.735 0x7a8 b'ba' # dongle - ACK
您可以看到在 0x200-0x209 对上交换一条消息,然后在 0x7a8 和 0x300 上恢复通信。谷歌快速搜索表明这一定是大众传输协议 2.0 (TP 2.0)。那里的信息并不多,但足以理解正在发生的事情并解码上面的代码片段。
我们可以看到模块 0x9 打开了一个通道。然后我们看到0x10 0x89,它进入使用KWP2000的诊断会话。然后应用程序使用 0x1a 0x9b 请求 ecu 标识,并以 Z.1K0909144E2501......@..MEPS_ZFLSKl.184
作为响应(与我们在上图中的应用程序中看到的内容匹配)。
现在我们知道使用了什么协议,我可以用 Python 编写自己的实现。此 GitHub 存储库包含此项目中使用的所有代码,以防您桌上也有一个 ECU 并且想在家玩。我实现了 TP 2.0 传输层,以及一些有用的 KWP2000 服务。这将在其他部件中用于进行更多诊断并最终刷新 ECU。
为了结束本系列的第一部分,我描述了我的目标(修改在此 EPS 上运行的固件),获得了在我的办公桌上运行的 ECU 的第二个副本,并通过标准化诊断协议 (KWP2000) 与其建立了通信。该项目的下一步是获取 ECU 上运行的(部分)固件。故事在第二部分继续。
免责声明
由于传播、利用本公众号渗透安全团队所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号渗透安全团队及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!
原文始发于微信公众号(车联网攻防日记):【车联网】大众高尔夫动力转向ECU破解(1)