您的位置:首页 > 其它

深入了解三星的TrustZone(第2部分)

2020-03-19 20:27 197 查看

http://dy.163.com/v2/article/detail/F5AGJN9P0511CJ6O.html


  

  
主线程

  该线程通常从初始化硬件资源开始,它还负责启动本节中描述的所有其他线程。如果正在运行的线程之一引发异常,则主线程将处理该异常,并在需要时重新启动该线程。

  
DCI线程

  可以直接通过NWd与安全驱动程序进行通信,其所使用的系统类似于Trustlet所实现的系统,它基于范围共享的存储区域DCI缓冲区。命令和自变量直接从该缓冲区中的NWd发送,并使用基于drApiIpcSigWait和drApiNotify的类似通知系统。可以利用此处理程序中的漏洞来从NWd直接访问安全驱动程序,而无需通过trustlet。

  
IPC线程

  当对安全驱动程序进行逆向工程时,IPC处理程序通常是有趣的。可以通过调用drApiIpcCallToIPCH来识别它,它是等待IPC消息的drApi函数。将参数传递到单个缓冲区中,以遵守IPC所需的数据格式。从trustlet接收到IPC时,需要使用函数drApiMapClientAndParams将trustlet的内存映射到安全驱动程序的地址空间中,以便可以对其进行访问。此外,如果将指针作为参数发送,则需要检查它们并将其转换为驱动程序的地址空间,以防止外界访问,这个操作可以通过调用drApiAddrTranslateAndCheck来执行。

  
ISR线程

  这个线程只是使用drApiIntrAttach连接到一个中断,然后通过调用drApiWaitForIntr等待中断的发生,通过调用drApiIntrDetach来停止中断。

  
Trustonic信任的系统Kinibi

  Kinibi是Trustonic开发的32位微内核,在三星的TrustZone中作为其受信任的操作系统实现。尽管Samsung Galaxy设备基于64位体系结构,但由于ARMv8 AArch32兼容模式,Kinibi仍能够运行。本节详细介绍了Kinibi在从Samsung Galaxy S6到Galaxy S9的设备上的体系结构。由于Kinibi是微内核,因此它由多个组件组成。这些组件在一个名为image header的表中被引用,并且可以在Kinibi的二进制文件中找到,如下图所示。

  

  通过搜索标记“t-base”或“tee”,可以在二进制文件中找到此表。该表的第一个元素表示TEE-OS本身,其他元素表示TEE-OS内部的组件。存储在该表中的元素可以使用下面代码片段中给出的结构来表示。

  struct element {

  char name[8];

  int offset;

  int size;

  char padding[0x10];

  }这些组件的简要描述如下所示:

  mtk:微型T-base内核,顾名思义,实际的内核负责执行特权操作;

  img-hdr:描述Kinibi元素的表格;

  mclib:实现常用函数的共享库,类似于libc;

  rtm:运行时管理器;

  drcrypt:加密驱动程序;

  tlproxy:用于信任小程序的安全文件系统库;

  sth2:安全驱动程序的安全文件系统;

  (Samsung S9)rpmb:此组件的功能目前未知。

  下图是整个体系结构。

  

  
运行时管理器

  最重要和关键的组件之一是运行时管理器,简称RTM。RTM是一个特殊的SWd用户空间进程,它相当于Linux上的init进程。RTM始终是Kinibi启动的第一个进程,然后负责管理所有其他进程。RTM还负责多项操作,例如:

  启动进程;

  将来自NWd的传入数据通知给信任程序;

  处理进程间通信;

  实现Mobicore控制协议;

  RTM负责Kinibi的所有通信机制,这些机制将在下一节中介绍。

  
Kinibi的内部和外部沟通

  由于Kinibi是微内核,因此IPC是其设计的基本要求。它允许上一部分中描述的所有组件相互交互并交换信息。Kinibi还需要与NWd通信。为了满足这两个需求,Trustonic已在RTM具有NWd的通信通道称为Mobicore通信接口(MCI),它基于一种自定义协议Mobicore控制协议(MCP)。它建立在下面列出的六个SMC fastcall上。

  可直接发送到监视器以切换处理器状态的SMC fastcall:

  MC_SMC_N_YIELD

  MC_SMC_N_SIQ

  可以发送到RTM的SMCfastcall:

  MC_FC_INIT用于配置发送和接收通知队列;

  MC_FC_INFO用于获取有关系统的其他信息,例如Kinibi的版本信息;

  MC_FC_SWAP_CPU用于将Kinibi移动到特定的CPU内核;

  MC_FC_MEM_TRACE用于通过存储器启用SWd跟踪;

  MCI依赖于称为“通知队列”的共享缓冲区,SMC仅用于设置这些缓冲区并将其通知安全监视器。然后,通知被传输到Kinibi, Kinibi再将其传输到RTM。来自NWd的MCP命令被添加到这些队列中,然后由RTM接收和解释,以对TrustZone中运行的安全组件进行操作。它允许RTM知道它是否需要加载、挂起或恢复一个trustlet、映射或取消映射额外的共享内存等。

  内部通信通道没有特定的名称,它为IPC提供了一个媒介,这个通道依赖于SVC 0x11。

  
ARM可信固件和三星显示器

  如上所述,三星用于其显示器的实现基于ARM受信任的固件。可以在Samsung 引导加载程序或SBOOT中找到它,它是Samsung为基于Exynos的设备开发的专有引导加载程序。ATF非常复杂,但是感兴趣的读者可以点此链接查看,因为它介绍了有关显示器内部的有趣细节,另外它还说明了如何从SBOOT二进制文件中查找和提取Kinibi。

  对于运行在AArch64处理器状态的设备,ATF为引导加载程序定义了5个连续的阶段:

  第1阶段(BL1):AP可信ROM;

  第2阶段(BL2):受信任的启动固件;

  阶段3-1(BL31):EL3运行时程序;

  阶段3-2(BL32):Secure-EL1有效载荷(可选);

  阶段3-3(BL33):不受信任的固件。

  有些实现可能同时将BL1和BL2嵌入到bootrom中,或者根本不需要它们,ATF通过允许电路板直接重置为BL31来处理此用例。

  下面列出了SBOOT组件,在下一幅图中也有说明。

  BL1:Exynosbootrom;

  BL31:基于开源的Arm Trusted Firmware(ATF)的EL3运行时程序;

  BL33:可信执行环境操作系统(TEE-OS),在Secure World中运行的固件;

  BL33:NWd Android引导加载程序的基于U-boot的引导加载程序。

  

  从三星Galaxy S8开始,显示器的实现方式被高熵部分替换,这表明它已被加密。目前尚不清楚这是三星最初打算的,还是仅仅是事后的应对反应,以防止对该主题被进行进一步的研究。为了能够读取监视器的代码,必须使用EL3漏洞利用程序,或者至少是一个能够任意读取物理内存的例程。

  在Trustonic的Trusted OS Kinibi部分中,简要介绍了Samsung实施自己的运行时服务的进程,这些服务使用以下代码段中给出的结构进行注册。

  typedef struct rt_svc_desc {

  uint8_t start_oen;

  uint8_t end_oen;

  uint8_t call_type;

  const char *name;

  rt_svc_init_t init;

  rt_svc_handle_t handle;

  } rt_svc_desc_t;这些结构为自定义SMC提供了处理程序,SMC由OEN引用,OEN代表拥有实体编号。该结构定义了将由此特定处理程序处理的OEN号范围。稍后将在后面的文章中专门讨论EL3的开发中使用它,其中将修改SMC处理程序以实现代码执行。

  接下来,我们将介绍在此研究进程中开发的工具,以及如何将其用于逆向工程和更轻松地利用TrustZone组件。

  
逆向工程与工具开发

  在研究过程中,我们开发了许多不同的工具,比如:

  1. trustlet使用的MCLF格式的Ghidra加载器;

  2.自动重命名tlApi函数的IDA Pro/Ghidra脚本;

  3.用于与trustlet通信的Python框架;

  4.基于AFL和Unicorn引擎的仿真器/模糊器;

  5.一个执行符号执行的Manticore脚本;

  6.一个用于SBOOT二进制文件的IDA Pro/Ghidra加载程序;

  
可信应用程序的逆向工程

  Trustlet作为二进制文件位于设备的文件系统上,如上所述,它们采用称为MobiCore可加载格式(MCLF)的自定义文件格式。将它们加载到IDA Pro或Ghidra之类的程序逆向工程(SRE)工具中,这是进入三星TrustZone生态系统的第一步。

  对我们来说幸运的是,已经有一个由Gassan Idriss开发的IDA Pro加载器,称为mclf-ida-loader。尽管如此,我们还是花了一些时间将其移植到Ghidra,以使我们可以使用免费程序。

  两种加载器的运行方式均相似:

  1.它们首先解析二进制文件的MCLF标头文件;

  2.它们将文本、数据和BSS段映射到内存中;

  3.它们标记了标头中定义的入口点;

  4.他们为MobiCore库处理程序添加了一个符号;

  你可以在GitHub上的mclf-ghidra-loader下载loader的Ghidra端口。

  正如所预料的那样,trustlet二进制文件的符号被删除。但是至少有一些函数是很容易识别的:tlApi / drApi存根。我们可以通过编写IDAPython脚本使此进程自动化,然后将其移植到Ghidra。该脚本执行以下操作:

  1.它加载名称和数字标识符之间的映射;

  2.它试图定义可能被遗漏的函数;

  3.迭代交叉引用到mcLib入口点;

  4.它从存根指令中提取标识符;

  5.它会重命名并相应地设置函数的原型。

  下面是应用脚本之前数据库的样子:

  

  下面是它的样子,所有的功能都重命名了:

  

  
模拟受信任的应用程序

  在逆转了几个信任小程序,手动查找漏洞并尝试利用它们之后,很明显,静态地进行操作并不是最好的方法。由于需要进行一些动态分析,因此我们开发了一个仿真器。

  该trustlet模拟器基于Unicorn引擎(使用QEMU),因为我们已经熟悉它并提供Python绑定。它执行与加载程序相同的操作,但还需要处理tlApi调用。

  通过在进入mcLib时拦截控制流来完成此处理,通过读取放入寄存器R0中的标识符,可以推断出tlApi中的哪一个被调用。最低要求是,它至少需要处理tlApiExit,这表明trustlet已完成执行,并且可以简单地为其他操作返回0(成功)。

  这是在trustlet上使用的仿真器的演示:视频地址点这里。

  该仿真器具有在开发阶段提供帮助的功能,例如,可以跟踪执行的指令、打印寄存器的值、转储堆栈的内容等。

  
模糊受信任的应用程序

  事实证明,该仿真器非常有价值,因为它可以插入模糊测试引擎中。这样,它现在可以自动查找漏洞。不再需要人工分析,这是一个繁琐且耗时的进程。利用这些漏洞或对其他组件(安全操作系统,监视器等)进行逆向工程会更好地花费时间。

  为此我们使用了Quarkslab开发的内部项目AFL_Unicorn,该项目将AFL模糊器与Unicorn引擎结合起来。但请放心,我们还将其移植到Battelle的公共项目AFL-Unicorn。

  仿真器和模糊测试之间共享许多代码,主要区别在于:

  1.加载完成后,启动fork服务器;

  2.它将输入从磁盘加载到TCI缓冲区中;

  3.引发Unicorn异常时,它会导致崩溃。

  以下是模糊器发现漏洞的一个示例:视频地址点这里。

  模糊器能够以drcov格式输出覆盖率信息,这样就可以检查代码的哪些部分已经被访问,IDA Pro plugin Lighthouse是完成这项任务的完美工具。

  
尝试符号执行

  虽然该模糊器工作正常,但我们也想尝试其他技术。因此,我们使用Trail of Bits(加密安全团队)的Manticore(一款动态二进制分析工具)开发了一个小程序,因为Quarkslab开发的符号执行器Triton当时没有ARM支持。

  Manticore具有加载ELF可执行文件的内置支持,因此我们必须首先转换trustlet二进制文件。不管信任小程序的细节如何,我们必须制作一系列小补丁才能使之起作用。

  该脚本大致执行以下操作:

  1.在设置阶段,它将映射TCI缓冲区并在mcLib入口点上添加一个挂钩;

  2.当挂钩被触发时,它会检查调用了哪个tlApi:

  3.对于tlApiWaitNotification,它将TCI缓冲区标记为符号,以便搜索整个输入空间。

  4.对于tlApiNotify或tlApiExit,当前状态终止;

  在内存访问中,它询问解决程序地址是否无效。下面是脚本查找无效内存访问的一个演示过程,视频地址点这里。

  
与受信任的应用程序通信

  普通范围的程序堆栈

  如上所述,正常范围可以使用程序中断和范围共享内存的缓冲区到达安全的范围。实际上,这在正常范围中作为复杂的程序堆栈实现。

  为了与安全范围进行通信,一个进程使用了一个本地库libMcClient.so,也可以由应用程序通过Java本机接口使用。该库在用户区域中运行与Mobicore守护程序通信,该守护程序可以在/ system / bin / mcDriverDaemon或在/vendor/bin/mcDriverDaemon中找到。守护程序本身通过/ dev / mobicore-user中公开的虚拟设备与Mobicore驱动程序通信(在内核环境中运行)。

  

  本机库导出许多组成McClient API的函数。为了与Trustlet进行编程交互,应用程序首先使用mcOpenDevice打开与虚拟设备的会话,并在使用mcCloseDevice后关闭该会话。现在,它可以创建与Trustlet或驱动程序的会话。

  可以通过分配WSM缓冲区并使用以下任意一种方法将trustlet或驱动程序加载到安全范围中:

  1.mcOpenTrustlet并指定trustlet二进制文件作为参数;

  2.mcOpenSession并指定trustlet UUID作为参数;

  为了发送命令,应用程序将命令标识符和参数放入WSM缓冲区中,并通过调用mcNotify通知trustlet某些数据可用。然后,它通过调用mcWaitNotification等待Trustlet处理命令。另外,响应标识符和返回值可以在WSM缓冲区中找到。

  
绑定与开发框架

  由于开发的工具存在着许多漏洞,因此是时候继续在实际设备上利用它们了。可以在其GitHub存储库上使用Trustonic自己提供的用户空间组件,但这需要编写大量C代码。即使使用精心制作的Makefile,它也会很快过时,因此我们进行了Python绑定。

  这些称为pymcclient的绑定将我们的漏洞利用脚本与libMcClient.so库进行连接,它们广泛使用with语句上下文来清洁处理会话的打开和关闭以及缓冲区的分配和释放。我们还补充了IPython REPL,使我们能够快速开发漏洞利用程序。

  这样的会话可能如下所示:

  In [1]: # connecting to the virtual device

  ...: device = McDevice(DEVICE_ID)

  device.open()

  In [2]: # allocating the TCI buffer

  ...: tci = device.malloc_wsm(TCI_BUFFER_SIZE)

  In [3]: # loading the trustlet binary

  ...: with open(TRUSTLET_FILE, "rb") as file:

  ...: bs = file.read()

  In [4]: # opening a session to the trustlet

  ...: session = McTrustlet(device, tci, bs)

  ...: session.open()

  In [5]: # writing a command

  ...: tci.seek(0)

  ...: tci.write_dword(0x1234)

  In [6]: # sending the command

  ...: session.notify()

  In [7]: # waiting for a reply

  ...: session.wait_notification()

  In [8]: # closing everything

  ...: session.close()

  ...: device.free_wsm(tci)

  ...: device.close()

  这是使用上下文的过程:

  # connecting to the virtual devicewith McDevice(DEVICE_ID) as device:

  # allocating the TCI buffer

  with device.buffer(TCI_BUFFER_SIZE) as tci:

  # opening a session to the trustlet

  uuid = bytes.fromhex(TRUSTLET_UUID)

  with McSession(device, tci, uuid) as session:

  # writing a command

  tci.seek(0)

  tci.write_dword(0x1234)

  # sending the command

  session.notify()

  # waiting for a reply

  session.wait_notification()

  # reading the reply

  tci.seek(0)

  print(hex(tci.read_dword()))

  
对可信操作系统进行逆向工程

  对Trusted OS进行逆向工程需要从SBOOT二进制文件中提取其组件,并将其映射到适当的地址,我们通过开发用于IDA Pro的加载器以及后来用于Ghidra的加载器来实现这一进程的自动化。

  下一篇文章,我们将详细介绍我们发现的漏洞以及为实现EL3中的代码执行而开发的漏洞。

  本文参考自:https://blog.quarkslab.com/a-deep-dive-into-samsungs-trustzone-part-2.html

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息