G.O.S.S.I.P 阅读推荐 2022-11-07 寻找特斯拉彩蛋

在每天整理稿件的时候,最开心的事情莫过于为大家推荐那些曾经在G.O.S.S.I.P生活学习过的小伙伴的研究论文,今天推荐的这篇论文的第一作者温昊煌同学,不仅学术搞得超级棒,踢球也是好手,在交大闵行校区的大草坪上飞驰~那我们就来看看学霸+球霸(好像有什么歧义哈哈哈)的USENIX Security 2023论文吧!

G.O.S.S.I.P 阅读推荐 2022-11-07 寻找特斯拉彩蛋

研究背景

Qt作为最流行的 C++ 开发框架之一,已经被广泛应用到开发各种GUI程序。迄今为止,市场上已经有数以亿计的Qt程序,包括PC/移动端的应用程序、嵌入式与IoT设备,甚至医疗应用和车机系统(如Tesla和奔驰车的中控系统)等等。Qt框架具备了许多原生C++语言无法支持的特性,包括跨平台、跨语言,以及许多独特的开发机制。本文着重介绍其中的两种重要机制:(1)Qt的信号与信号槽以及(2)Qt的动态反射。基于这两个独特机制的运行原理,我们提出一套针对Qt二进制程序的分析方法,解决逆向工程中的两个重要但是困难的问题:回调函数(callback)以及程序符号(symbol)的还原。同时,我们以特斯拉(对,就是twitter的老板他们家的Tesla)的中控系统固件中的彩蛋挖掘为案例,展示Qt二进制分析的实际应用。

Qt的独特开发机制

  • 信号与信号槽:回调函数(callback)在GUI程序中非常普遍且常用于实现各种UI操作与业务逻辑的交互。Qt的信号与信号槽极大程度上降低了开发人员实现回调函数的难度,免于操作大量的C++指针造成的麻烦与错误。在此机制中,回调函数的触发事件被称为信号(signal),而对应的触发函数被称为信号槽(slot)。如图1的一个Qt二进制示例程序所示,某UI控件中定义了一个textChanged信号(实际上是一种特殊的函数)。当用户从UI控件中编辑文字后,对应的信号槽MainWindow::updateText()将会被调用来更新控件中的text成员变量。每个信号与信号槽的绑定是通过Qt的库函数connect()来实现的,其中开发者必须声明信号与信号槽的类实例以及函数签名。

G.O.S.S.I.P 阅读推荐 2022-11-07 寻找特斯拉彩蛋

图1: Qt的信号与信号槽机制

  • 动态反射:在程序的运行状态中动态查询或改变类中信息(如变量)的操作称为动态反射,例如Java语言中的反射功能。图2的示例展示了Qt动态反射的原理。首先,在代码26行中开发者可以通过setProperty()方法来动态改变MainWindow类中的text成员变量并将其设置为test。这个动态反射的过程是由Qt的内部机制完成的。首先,反射函数(如setProperty())被调用后将从内存中查询MainWindow类的元数据表,包括属性表与字符串表等等。这些表由Qt的编译器MoC在运行时自动生成在二进制程序中,用于保留类变量的索引与符号信息等。当得到了目标成员变量的索引后,Qt内部调用一个qt_metacall()函数(由MoC编译时生成,作为每一个Qt类的私有成员函数)来执行相应的动态反射逻辑。例如,在程序的34行中此函数把test赋值给*(this+0x48)地址中的变量,即MainWindow.text

G.O.S.S.I.P 阅读推荐 2022-11-07 寻找特斯拉彩蛋

图2: Qt的动态反射运行原理

QtRE设计与实现

动机与目标:从以上两个Qt独特开发机制中,我们发现它们不仅方便了开发者实现特定的程序功能,而且给二进制程序分析者打开了一扇大门:这些独特的机制可以用于逆向还原程序中的回调函数(进而构建一个更完整的call graph)以及大量的程序符号(函数和变量名等)。这些方法将会给分析者审计Qt程序代码带来极大的方便。从根源上说,Qt对这些独特机制的支持意味着Qt的编译器(MoC)必须在编译时保留大量对逆向者有用的程序信息(如符号等等)。并且这些信息无法被常规的反逆向保护手段(如stripping)消除(否则这些机制就不再有用了)。基于这些观察,我们提出了一套针对Qt二进制程序的分析工具:QtRE。下面将简单介绍QtRE的方法原理,更详细的步骤请查阅原论文(见文末)。

1. Qt回调函数的识别与还原

此步骤包括两个部分。首先,QtRE通过Qt独特的connect()函数识别出回调函数的具体位置(connect()函数共有两种不同的重载形式)。然后,QtRE通过逆向回溯的方法分析connect()函数中关键参数(即信号与信号槽的类成员变量和函数签名),并计算出具体的类实例与类成员函数来组成一个完成的信号或信号槽对象。其中值得一提的是,由于C++的多态机制,仅仅计算出信号/信号槽的函数签名并不能达到精确识别的目的(如A.foo()B.foo()作为不同类的同一成员函数)。因此,QtRE通过一个基于类定义的推测方法来还原信号/信号槽所在的类名。

2. Qt程序符号的还原

此步骤也通过两个部分实现。对于每一个Qt类,QtRE首先从Qt程序中找到其对应的元数据表(即metadata table),并且解析其所有的符号表来获取相应的符号信息(索引与符号字符串等)。然而,仅仅获取到符号本身的字符串仍不足以还原到对应的程序符号,QtRE仍然需要计算出符号对应的相对地址。如图2所示,从符号表中解析出的text符号需要被还原到对应的地址中,即MainWindow类的*(this+0x48)相对地址。因此,QtRE利用了一个轻量级的符号执行引擎来解决符号地址的计算问题。简单来说,QtRE通过符号执行每一个类对应的qt_metacall()函数,并利用函数内部的计算逻辑自然地推导出目标符号在类中的相对地址。

实验与案例分析

我们通过两个Qt二进制程序数据集来测试QtRE,其中包括80个来自开源的KDE程序库以及43个从Tesla中控系统固件中提取的闭源应用程序(来自一辆2015年的Model S)。QtRE从中一共还原出10867个回调函数实例以及24973个程序符号,并且这些函数与符号不能被一般的二进制分析工具(Ghidra,Angr,BinaryNinja等)识别。QtRE基于Ghidra实现,并且将会在未来开源。

G.O.S.S.I.P 阅读推荐 2022-11-07 寻找特斯拉彩蛋

图3: QtRE实验结果

Tesla固件的彩蛋挖掘:我们通过一个有趣的案例来展示QtRE的实际应用。Tesla的中控系统存在许多的彩蛋功能,例如用户通过在隐藏的彩蛋菜单中输入“mars”即可将导航地图变为火星的表面(图3)。通过对固件代码中用户输入变量进行系统的数据流分析,我们可以挖掘出这些已知的彩蛋或者其它隐藏的命令。QtRE还原出来的回调函数call graph以及程序符号能帮助定位到关键的用户输入变量展开对应的程序分析。

G.O.S.S.I.P 阅读推荐 2022-11-07 寻找特斯拉彩蛋

图4: Tesla中控系统的Mars彩蛋(图源https://www.teslarati.com/elon-musk-apparently-baked-mars-based-tesla-easter-egg/tesla-mars-easter-egg-rover/)

我们惊奇地发现,Tesla固件中还存在5个特殊的隐藏口令和管理员密码,能够用于启动开发者模式以及任意地退出代客泊车模式。我们已于2021年将所有的发现报告给了Tesla公司,目前这些漏洞的利用途径(如通过HTTP API来更改前置条件的环境变量)已在新版的固件中被安全移除。另外,这些隐藏命令存在比较严格的使用限制,例如需要把内部变量GUI_isDevelopmentCar设置为真,或取得车机系统的root权限。其它取得这些高权限的途径,如腾讯在2017年披露的远程入侵漏洞,已经在新版本的固件中被修补。所以,对于所有Tesla车主用户来说,只要把固件升级至最新版本即可保证安全

G.O.S.S.I.P 阅读推荐 2022-11-07 寻找特斯拉彩蛋

图5: Tesla固件中的彩蛋以及隐藏命令

更多细节请阅读我们的论文:http://web.cse.ohio-state.edu/~wen.423/papers/QtRE_USENIX_23.pdf


作者简介: 温昊煌,俄亥俄州立大学博士生,SecLab成员,主要研究兴趣为移动平台、物联网、汽车、以及移动网络(5G)安全。相关研究成果已发表在USENIX Security, CCS, NDSS, PETS, RAID等知名国际安全会议上。个人主页:https://web.cse.ohio-state.edu/~wen.423/


原文始发于微信公众号(安全研究GoSSIP):G.O.S.S.I.P 阅读推荐 2022-11-07 寻找特斯拉彩蛋

版权声明:admin 发表于 2022年11月7日 下午8:24。
转载请注明:G.O.S.S.I.P 阅读推荐 2022-11-07 寻找特斯拉彩蛋 | CTF导航

相关文章

暂无评论

暂无评论...