题目给的是bin文件,基本上就是需要我们手动修复的固件逆向。
如果给的是hex文件,我们可能需要使用MKD进行动态调试
主要还是以做题为目的
详细的可以去看文档:https://pdf1.alldatasheet.com/datasheet-pdf/view/201596/STMICROELECTRONICS/STM32F103C8T6.html
SVD文件下载:https://github.com/posborne/cmsis-svd
本文参考了网上多篇文章,最终汇总在一篇,对这道新的STM32题进行解题。
IDA分析设置
1、基础设置
STM32主要信息:
- • 内核:ARM32位Cortex-M3 CPU
- • ARM Little-endian
- • Cortex-M架构属于ARMv7-M
IDA32位打开
ARM little-endian
点击ok之后进入
- • flash的映射地址是 0x08000000 ~ 0x0807ffff (512KB)
flash就是我们装代码的地方,也是STM32入口
下面这张图来自STM32中文参考手册
从这张表中,可以了解的信息是,在偏移4的位置存储的是RESET,并且是固定的。
Reset就是充电就会执行并进入的地方,因此将其当做固件入口
在IDA偏移为4的地方,按下“D”键进行转换
得到了RESET的地址:0x80004D1
可以看到为奇数,说明是thumb指令
按下 "G" 键进行跳转
然后神奇的一幕发生了
自动识别了很多函数
其实这没有固定的套路,我们跟踪跳转,一步一步的分析,最终会到达关键步骤
分析函数 :sub_8000260
发现爆红了,需要我们手动添加一些段
- • Flash Memory: 0x8000000 ~ 0x801FFFF (128K)
- • SRAM: 0x20000000 ~ 0x20004FFF (20K)
- • Peripherals: 0x40000000 ~ 0x40023400
2、添加段-SRAM
单片机内存被总分为flash(rom)和sram(ram),flash里面的数据掉电可保存,sram中的数据掉电就丢失,sram的执行速度要快于flash,flash容量大于sram
单片机的程序存储分为code(代码存储区)、RO-data(只读数据存储区)、RW-data(读写数据存储区) 和 ZI-data(零初始化数据区)
Flash 存储 code和RO-data
Sram 存储 RW-data 和ZI-data
所以,SRAM段需要我们自己添加
[
0x20000000
,
0x2000ffff
]
SRAM:
0x20000000
~
0x20004FFF
(
20
K) 存放程序动态执行时的变量
3、添加段-Peripherals
Peripherals:
0x40000000
~
0x400234ff
#这里还是改为了
0x400234ff
而不是
0x40023400
在实战中发现多有多余的爆红,因此范围扩大总没错
外设寄存器的映射地址,程序通过读写这些内存地址实现对外围设备的控制
Peripherals 段中包含了我们要了解的寄存器
4、恢复中断向量表
地址0x8000000
-0x80000eb
存储了中断向量表的相关信息
使用python脚本,主要功能是删除旧的分析,添加dword类型分析
for
i in
range
(
0x8000000
,
0x80000eb
,
1
):
del_items(i)
for i in range(
0x8000000
,
0x80000eb
,
4
):
create_dword(i)
print(
"ok"
)
可以看到均已恢复
修复完成后,发现了很多重复的地址,比如:0x8000519 这些函数并没有定义
跳转过去,将其全部生成对应的函数,使用(P 键)
官方图:
5、恢复符号
bindiff来恢复符号表
如果有闲工夫或者是对stm32的开发非常上手,就可以自己写一个demo,尽可能多的使用到各种库函数,然后编译出一个axf文件。我这里的话,由于好久没有用stm32了,开发起来有些生疏,所以就不自己手写了,我选择捡现成的项目,编译出axf文件
可以多选几个例程,能涵盖更多的库函数,将这些axf文件用IDA打开,然后生成idb文件。然后在我们的目标bin文件中,使用bindiff加载idb文件。
网上随便找一个,下载axf文件
选择一个idb文件,然后会出现这样一个比较界面:
选取similarity大的函数导入到bin文件中
导入之后实际上就能恢复大部分的函数名了。
6、恢复外设
导入SVD文件,恢复外设结构
在IDA7.5以后,就自带SVD文件加载插件了,如下图:
打开之后如下:
我们可以自行下载相应的SVD文件,或者加载GitHub上的仓库,我这里选择自行下载然后在本地加载。
下载链接是这个:
stm32-svd-main.zip
选中想要加载的svd文件之后,IDA就会自动恢复bin文件中的外设结构,体现在伪代码中就是这样:
(在这题中好像没什么用)
2、解题
基本上做完上面的操作后
STM32就能看了
进入main函数
继续分析
题目说的是要找key
但是发现Key没有值。。。也就是说要么动调要么爆破,给了密文,就差了key
因此写出解密脚本
先转换一下
int
main
() {
int
v19[
8
] = {
0
};
v19[
0
] =
0xF4DD0F64
;
v19[
1
] =
0x5173B9F8
;
v19[
2
] =
0xC7D238B2
;
v19[
3
] =
0x9B9FCA8
;
v19[
4
] =
0x286D3C51
;
v19[
5
] =
0x429DE399
;
v19[
6
] =
0x8084307B
;
LOWORD
(v19[
7
]) =
0x9175
;
for
(
size_t
i =
0
; i <
8
; i++)
{
for
(
size_t
j =
0
; j <
4
; j++)
{
printf
(
"%02x "
, (v19[i] >>
8
* j)&
0xff
);
}
}
return
0
;
}
写出解密脚本:
from itertools
import
product
from Crypto.Cipher
import
ARC4
xorkey =
"flag{tH14.l4_F@kKkEeeE---f41g}"
enc =
bytearray
([
0x64
,
0x0f
,
0xdd
,
0xf4
,
0xf8
,
0xb9
,
0x73
,
0x51
,
0xb2
,
0x38
,
0xd2
,
0xc7
,
0xa8
,
0xfc
,
0xb9
,
0x09
,
0x51
,
0x3c
,
0x6d
,
0x28
,
0x99
,
0xe3
,
0x9d
,
0x42
,
0x7b
,
0x30
,
0x84
,
0x80
,
0x75
,
0x91
])
l =
list
(
range
(
0x20
,
0x7f
))
for
k in
product
(l, repeat=
4
):
key =
bytearray
(k)
res = ARC4.
new
(key).
decrypt
(xorkey.
encode
())
if
res == enc:
(
'get'
)
(key)
exit
(
0
)
使用C语言爆破会更快
#
include
<stdio.h>
#
include
<stdlib.h>
#
include
<string.h>
#
include
<stdint.h>
#
include
<unistd.h>
#
include
<openssl/arc4.h>
#
define
XOR_KEY
"flag{tH14.l4_F@kKkEeeE---f41g}"
#
define
ENC_SIZE 29
int
main
() {
uint8_t
enc[ENC_SIZE] = {
0x64
,
0x0f
,
0xdd
,
0xf4
,
0xf8
,
0xb9
,
0x73
,
0x51
,
0xb2
,
0x38
,
0xd2
,
0xc7
,
0xa8
,
0xfc
,
0xb9
,
0x09
,
0x51
,
0x3c
,
0x6d
,
0x28
,
0x99
,
0xe3
,
0x9d
,
0x42
,
0x7b
,
0x30
,
0x84
,
0x80
,
0x75
,
0x91
};
int
l[] = {
0x20
,
0x21
,
0x22
,
0x23
,
0x24
,
0x25
,
0x26
,
0x27
,
0x28
,
0x29
,
0x2a
,
0x2b
,
0x2c
,
0x2d
,
0x2e
,
0x2f
,
0x30
,
0x31
,
0x32
,
0x33
,
0x34
,
0x35
,
0x36
,
0x37
,
0x38
,
0x39
,
0x3a
,
0x3b
,
0x3c
,
0x3d
,
0x3e
,
0x3f
,
0x40
,
0x41
,
0x42
,
0x43
,
0x44
,
0x45
,
0x46
,
0x47
,
0x48
,
0x49
,
0x4a
,
0x4b
,
0x4c
,
0x4d
,
0x4e
,
0x4f
,
0x50
,
0x51
,
0x52
,
0x53
,
0x54
,
0x55
,
0x56
,
0x57
,
0x58
,
0x59
,
0x5a
,
0x5b
,
0x5c
,
0x5d
,
0x5e
,
0x5f
,
0x60
,
0x61
,
0x62
,
0x63
,
0x64
,
0x65
,
0x66
,
0x67
,
0x68
,
0x69
,
0x6a
,
0x6b
,
0x6c
,
0x6d
,
0x6e
,
0x6f
,
0x70
,
0x71
,
0x72
,
0x73
,
0x74
,
0x75
,
0x76
,
0x77
,
0x78
,
0x79
,
0x7a
,
0x7b
,
0x7c
,
0x7d
,
0x7e
,
0x7f
};
int
l_size =
sizeof
(l) /
sizeof
(
int
);
uint8_t
key[
4
];
uint8_t
dec[ENC_SIZE];
for
(
int
i =
0
; i < l_size; i++) {
for
(
int
j =
0
; j < l_size; j++) {
for
(
int
k =
0
; k < l_size; k++) {
for
(
int
m =
0
; m < l_size; m++) {
key[
0
] = l[i];
key[
1
] = l[j];
key[
2
] = l[k];
key[
3
] = l[m];
ARC4_CTX ctx;
ARC4_set_key
(&ctx,
4
, key);
ARC4
(&ctx, ENC_SIZE, enc, dec);
if
(
memcmp
(dec, XOR_KEY, ENC_SIZE) ==
0
) {
printf
(
"getn"
);
printf
(
"%c%c%c%cn"
, key[
0
], key[
1
], key[
2
], key[
3
]);
exit
(
0
);
}
}
}
}
}
return
0
;
}
爆破出秘钥:
d4@d
原文始发于微信公众号(合天网安实验室):STM32在CTF中的应用和快速解题
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论