STM32在CTF中的应用和快速解题

2023-12-15 18:54:55

题目给的是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就是充电就会执行并进入的地方,因此将其当做固件入口

图片

image

在IDA偏移为4的地方,按下“D”键进行转换

得到了RESET的地址:0x80004D1

可以看到为奇数,说明是thumb指令

按下 "G" 键进行跳转

图片

image

然后神奇的一幕发生了

图片

?

自动识别了很多函数

图片

?

其实这没有固定的套路,我们跟踪跳转,一步一步的分析,最终会到达关键步骤

图片

?

分析函数 :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?(20K)?存放程序动态执行时的变量

图片

?

图片

?

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:
????????print('get')
????????print(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("get\n");
????????????????????????printf("%c%c%c%c\n",?key[0],?key[1],?key[2],?key[3]);
????????????????????????exit(0);
????????????????????}
????????????????}
????????????}
????????}
????}

????return?0;
}

爆破出秘钥:

d4@d

文章来源:https://blog.csdn.net/YJ_12340/article/details/135022571
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。