文章目录
写在最前:注意下载最新版lib(6月2日更新版),并结合自己的lib分析。分析过程我写得有点长,是为了帮助大家找到自己的地址、并理解它。实际上,需要写进报告的内容只有子任务2那么点。
实验二比较麻烦,附加内容我其实已经写进博客了,如果想写的话,请自行整理吧。实验三很简单,实验二比较麻烦而且比较长,考虑到大家应该还要写一下报告,我就分开先发实验二了。
实验二 基于 MPU 的物联网设备攻击缓解技术
实验要求
实验的 lib 库代码中开启了多项 MPU 区域保护
请根据不同的子任务重配置 MPU 区域解除相应的区域保护
- 子任务 1 解除代码段不可写入保护将指定代码段改为可写
- 子任务 2 解除特定外设区域保护将指定外设区域改为可读写
注:请通过逆向分析出触发 Memfault 的指令,从而在满足任务要求的同时尽可能用最 少的 MPU 区域配置、最小的 MPU 区域范围,最小的特权级。
特权级排序:rwx(可读可写可执行)> rw>rx>r>无权限
注意:任务2要用架构
mps2-an386
。
实验准备
Keil安装及使用
安装破解过程:
- 安装
Keil5
:一路Next
就行,名称邮箱全部任意填,安装驱动什么的一律选是,安装路径最好不要包含中文,或者直接默认。 - 破解
Keil5
:以管理员权限打开刚刚安装的Keil5
,关掉弹出来的让安装包的窗口,然后点击File-License Management
,复制CID
到破解软件中。破解软件填写CID
、设置Target
为ARM
之后,点击Generate
生成LIC
,粘贴到Keil5
的LIC
输入框中。点击Add LIC
就行。 - 安装
ARM CMSDK_CM4_FP
:老师发的Keil5
默认是没有我们要的ARM CMSDK_CM4_FP
。不过老师还发了两个.pack
文件,双击安装就行。一路Next
,安装路径要和Keil5的安装目录相对应。
新建项目并添加文件:
Project-New uVersion Project
,然后配置直接按实验指导书就行,后面也直接按指导书。添加文件可以直接拖进去。编译就是
Project-build
。
注意:如果之前装过其他版本的
Keil
,并新建了项目,记得删掉项目目录中的
Listings、Objects、RTE
,否则它会自动优先从这些目录下读取配置,版本就不对。
如果配置项完全正确,和指导书完全一致,直接运行时就会0 Error。
可执行文件会生成在
Objects/
下,运行如下指令运行:
~/qemu-7.0.0/build/qemu-system-arm -M mps2-an386 -cpu cortex-m4 -m 16M -nographic -d in_asm,nochain -kernel ~/exp6/task2/task2.axf -D log.txt
分析给出的
.c
/
.h
/
.lib
文件的内容和作用
先简单地分析一下
task2.c
的内容。
main
函数:
① 定义无符号整型变量
a
,赋值为学号末4位;
② 调用
prvSetupHardware()
,硬件初始化;
③ 调用
xTaskCreate
,创建任务,任务内容为
vTaskStart
,任务名称为"
Task2
",权限为特权级;
④ 调用
StartFreeRTOS(a)
;
⑤ 使用
for(;;)
让程序不退出。
在
vTaskStart
的任务中,调用了
AttackTest()
。
在逆向分析过后,可以进一步确定:在
StartFreeRTOS(a)
中包含对任务序列的启动。当启动了Task2后,将会调用
AttackTest()
。如果AttackTest没有触发
MemMange_Handler
异常,在一定的条件下,就会顺利打印输出
flag
;当AttackTest触发异常后,该任务就会结束。
MemMange_Handler
异常有触发延时,所以旧的lib总是在异常还没被触发时,就已经打印了
flag
,所以老师更新了新版lib文件。
通过查看
task2.h
,可以看到
AttackTest
、
prvSetupHardware
、
StartFreeRTOS
的函数声明,而这些函数的具体实现,正是在
task2x_xx.lib
文件中。
当项目构建完成之后,所有的文件的内容都会被链接到可执行文件
task2.axf
中。
子任务1 解除代码段不可写入保护将指定代码段改为可写
本任务中,需要将
task2.c
、
task2.h
、
task2a_89.lib
添加到Project中,注意要下载最新版的
.lib
文件。
逆向分析 AttackTest 函数
首先,不加修改地直接编译项目,得到
task2.axf
,以便逆向分析
AttackTest
函数。编译结果如下图所示:
在IDA Pro中打开文件
task2.axf
,选择的选项和上一个实验一致。
根据之前对三个文件的分析,我们能很轻易地找到
AttackTest
函数在逆向中的位置,顺着点开它,它的内容如下图所示:
F5
反汇编得到的结果如下图所示:
接下来,先保证能正确进入输出flag的条件分支内。
《ARM Cortex-M3与Cortex权威指南》(后简称为权威指南),第11章写了与MPU区域设置相关的寄存器,其中
0xE000ED94
就是寄存器
CTRL
。根据静态地址和寄存器的对应关系,预定义如下:
#defineMACRO_CTRL0xE000ED94#defineMACRO_RNR0xE000ED98#defineMACRO_RBAR0xE000ED9C#defineMACRO_RASR0xE000EDA0
然后,在
vTaskStart
里添加如下几行代码,以便通过指针形式来访问寄存器,并打印所有原始区域:
volatileunsignedint* pCTRL=(volatileunsignedint*)MACRO_CTRL;volatileunsignedint* pRNR=(volatileunsignedint*)MACRO_RNR;volatileunsignedint* pRBAR=(volatileunsignedint*)MACRO_RBAR;volatileunsignedint* pRASR=(volatileunsignedint*)MACRO_RASR;for(int i=0;i<8;i++){*pRNR=i;printf("%d,%d,%08x,%08x\n",*pRNR,*pCTRL,*pRBAR,*pRASR);}
寄存器有自己的结构,这里先定义结构体、再定义结构体指针会更合适一些。但是,由于实验任务简单,并没有太多需要修改的内容,所以我干脆直接用无符号整数赋值了。
为保证至少有一个MPU是使能的,再在
vTaskStart
里的循环体后添加一行代码:
*pCTRL=5;
然后Rebuild并直接运行一下,看看在哪里触发了异常,运行后的结果如下图:
根据老师的说法,MemMange_Handler这个异常会有延时,所以违反 MPU 区域保护的指令是触发异常的部分上面几行代码,而不是紧随其后的其他代码。即:
0x000002c2: f44f 40e0 mov.w r0, #0x7000
0x000002c6: 490c ldr r1, [pc, #0x30]
0x000002c8: 6001 str r1, [r0]
0x000002ca: f8c0 1080 str.w r1, [r0, #0x80]
0x000002ce: e7ec b #0x2aa
对应的
AttackTest
在IDA Pro中的汇编代码如下:
LDR指令的作用:将存储器地址所指地址处连续的4个字节的数据传送到目的寄存器中。
MOV.W R0, #0x7000 ; 将0x7000赋值给R0寄存器
LDR R1, =0x12345678 ; 将0x12345678赋值给R1寄存器
STR R1, [R0] ; 将R1的连续4字节的数据传送到R0寄存器指向的地址中
STR.W R1, [R0,#0x80] ; 将R1的连续4字节的数据传送到(R0寄存器指向的地址+0x80)中
B Judge ; 跳转执行Judge
显然,访问了
#0x7000
和
#0x7080
这两个地址,并且都需要写权限。
分析老师设置的所有的MPU的RASR的AP属性,可以看出,区域0、1、3都是只读的,其他区域对特权级都是可读可写的,区域6和7暂时没有设置。AP域编码对应的访问权限如下图所示(摘自权威指南):
而结合基址RBAR和RASR中的区域大小属性,可以看出,
#0x7000
和
#0x7080
这两个地址都在区域0和1内,而它们都是不可写的。
不过,除了这几行指令,保不齐后面还有别的访问不了的呢?继续往后看。
打印flag函数的条件分支体如下:
其中打印flag的条件分支体对应的代码解释如下:
1 ldr R0, #0x20000038 ; 将0x20000038赋值给R0寄存器
2 ldr R1, [R0] ; 将R0寄存器指向的地址上的值读出并赋值给R1
3 adds R1, R1, #2 ; R1 = R1 + 2,影响进位标志位C的加操作
4 str R1, [R0] ; 将R1的连续4字节的数据传送到R0寄存器指向的地址中
5 adr R0, aFlagU ; 把格式化字符串的地址赋值给R0
6 b.w __2printf ; 调用__2printf
总之,Judge中还涉及了内存地址
0xE000ED94
的读权限和
0x20000038
的读写权限。好在,通过MPU的信息可以看出,
0x20000038
虽然在区域2内,但是区域2可读写。
0xE000ED94
则不被约束。
因此这两个地址并不是违反MPU保护的地址。
违反 MPU 区域保护的指令
综合以上所有分析,可知,违反MPU区域保护的指令是AttackTest函数中的:
STR R1, [R0] ; 将R1的连续4字节的数据传送到R0寄存器指向的地址中
STR.W R1, [R0,#0x80] ; 将R1的连续4字节的数据传送到(R0寄存器指向的地址+0x80)中
违反的权限
对
0x7000
和
0x7080
这两个地址的写权限。
解除 AttackTest 函数违反规则的新 MPU 区域重配置代码
总的来说,我添加的解除AttackTest函数违反规则的新 MPU 区域重配置代码如下:
运行并得到flag的结果如下图:
设置的区域说明
CTRL
CTRL=
5
。表示使能。
RNR
RNR=
6
,表示区域6。
为了不覆盖老师的设置,我选择区域6来配置新的MPU区域。
RBSR
RBSR设置为
0x7000
。
RBSR的结构如下图(摘自权威指南):
上表的误导性非常强,我起初以为ADDR是独立出来的,比如当地址是0x7000、区域是1时,对应ADDR部分是0x7000,对应RBAR是0x70001。好在一位同学及时点醒了我,往后看一下权威指南,会发现地址部分是直接赋值的,根本没有考虑最后四位数。
经过实践,可以得到结论如下:
一方面,当倒数第五位数VALID是0的时候,REGION位的设置不会影响修改的MPU区域编号寄存器,程序会使用MPU区域编号寄存器选择的区域,因此最后四位数可以是任意值;
另一方面,地址必须是REGION域大小的整数倍。首先,我们需要知道每一位地址能索引8比特的数据。对于大小为32B即(32×8)bits的数据,理论上需要用
l o g 2 ( 32 ) log_2(32) log2(32)位、也就是5位地址去表示,而每4位二进制数对应一个16进制数。因此,使用(00~1f)即可表示32B的数据,而每32B的数据之间的间隔,应当是0x20。
REGION域大小最小为32B,地址是N×0x20,N为整数。因此,非零地址最小是0x20。即使直接令RBAR=0x20,都不会影响到倒数5位二进制数的设置。(相当于,倒数5位本来是保留位,只是为了方便,所以多定义了VALID域和REGION域)
地址对应容量大小参考博客:【嵌入式基础】为什么0x100是256个字节、0x400是1KB、0x800是2KB、0x1000是4KB?。
总之,RBSR=
0x7000
,意思就是MPU的基址是
0x7000
。
RASR
RASR=
0x0102EE0F
,对应属性如下:
- AP = 001,对应只支持特权级读/写;
- TEX S C B = 000 0 1 0,对应ROM, Flash(可编程存储器);
- SRD = 11101110,对应子区域0和4启用,其他禁用;
- 区域大小 = 00111,对应区域大小256B;
- 使能 = 1,使这块MPU能用。
接下来解释一下我设置的AP、SRD、区域大小、类型为什么是最小的:
- APAP编码与访问权限的对应关系如下图(摘自权威指南):对比上表可以看出,满足我们特权级任务、读写权限要求的最小访问权限就是
001
。 - 区域大小区域大小的编码如下图(摘自权威指南):想要取最小的,那就取32B,也就是b00100。可惜我需要访问
0x7000
和0x7080
这两个地址,只取128B都不行,因为取128B、基址是0x7000的时候,MPU对应的区域只有0x7000~0x707F
。所以取256B,对应b00111
。 - SRD当区域大小达到256B的时候,这个MPU足够大,能够设置8个子区域了。因此,我还得考虑子区域禁止属性SRD的设置。(我问过别人,别人的lib只访问了一个地址,或者访问的地址跨度没这么大。因此,我这居然是属于特殊情况)我的子区域0和子区域4是必须启用的,其他都可以禁用。所以设置为
11101110
。 - 类型只是简单介绍一下大类,不对TEX、S、C、B做详细介绍。本实验涉及到的TEX、S、C、B的设置如下图(摘自权威指南): 显然,设置成ROM,Flash是权限最小的。
子任务 2 解除特定外设区域保护将指定外设区域改为可读写
在子任务1的分析基础上,不需要太多解释。
再加上预设的MPU没变,所以基本上只要改改地址范围即可。
实验结果如下。
逆向分析 AttackTest 函数
违反 MPU 区域保护的指令
AttackTest中的
STR R0, [R1]
。
违反的权限
0x40010000
的写权限。
解除 attackTest 函数违反规则的新 MPU 区域重配置代码
代码,以及相比子任务1的关键修改:
运行结果:
设置的区域说明
RNR=6。
CTRL=5。
RBSR设置为
0x40010000
。
RASR=
0x01020009
,对应属性如下:
- AP = 001,对应只支持特权级读/写;
- TEX S C B = 000 0 1 0,对应ROM, Flash(可编程存储器);
- SRD = 00000000,区域大小未达到256B,因此该属性不需要配置;
- 区域大小 = 00100,对应区域大小32B;
- 使能 = 1,使这块MPU能用。
版权归原作者 shandianchengzi 所有, 如有侵权,请联系我们删除。