• stm32逆向入门


    点击蓝字

    439b4b4189129ffb16a64efbe2cacf56.png

    关注我们

    一、前言

    本日学习记录

    二、复现

    1、SCTF 2020 Password Lock

    参考链接:https://xuanxuanblingbling.github.io/iot/2020/07/08/stm32/

    题目描述

    这是一个STM32F103C8T6 MCU密码锁 它具有4个按键,分别为1, 2, 3, 4. 分别对应GPIO_PA1, GPIO_PA2, GPIO_PA3, GPIO_PA4 flag1格式为SCTF{正确的按键密码} 输入正确的密码, 它将通过串口(PA9–TX)发送flag2

    解题思路

    题目附件给出了一个Intel hex文件,并且给出了芯片信息我们可以确定程序的内存布局和外设寄存器与内存的对应。而逆向的关键就是读懂程序代码的含义,接下来我们将逐步分析这个hex文件。

    1. hex文件结构

    Intel hex文件格式由纯文本构成,其中包含了程序的加载地址和程序入口地址等信息,读懂这些信息可以帮助我们快速定位程序的起始入口而不用在ida中进行配置。

    • 读懂Intel hex文件

    我们可以使用文本编辑器打开题目附件,其中关键信息如下所示:

    1. :020000040800F2
    2. ...
    3. ...
    4. :04000005080000ED02
    5. :00000001FF
    • 程序加载地址为0x08000000

    • 程序入口地址为0x080000ED

    • 程序以:00000001FF结尾

    • 其余全是文件数据

    2、内存布局

    查找芯片手册的网站:https://www.alldatasheet.com/ 在里面我们可以找到STM32F103C8T6的手册,第一页发现我们需要的一些信息

    a9a704c2d0f5792e7479385890039d93.png

    • Flash memory:32-to-128 Kbytes

    • SRAM:6-to-20 Kbytes

    31页的Memory Map可以让我们更加直观的了解到内存的详细布局

    b846e7036fea2e64147ec86b7ea1d794.png

    综上所述我们得到了程序的完整内存布局信息:

    • Flash Memory: 0x8000000 ~ 0x801FFFF (128K)

    • SRAM: 0x20000000 ~ 0x20004FFF (20K)

    • Peripherals: 0x40000000 ~ 0x40023400

    3、IDA分析

    经过刚才的分析我们了解了程序的内存布局,其中Flash段除了包含代码,还有中断向量表。Periphers段中的寄存器是我们在逆向过程中需要对齐有大体了解。而对于hex文件的分析我们了解到除了加载地址和入口地址,其他的所有内容都不在hex文件中,所以我们需要手动配置这些内存布局信息来告诉IDA怎么识别。 打开ida工具,根据刚才的手册中我们可以查到芯片是arm32 Armv7-M架构,如下图所示进行配置选择然后单击ok

    6715fe611397deb5cb5ffac47a07f898.png

    可以看到已经能识别出一部分函数,其中start函数的地址与我们分析hex文件结构时找到的程序入口地址相同。

    6d98f26caa0d97b37e9068188234bf1c.png

    如果hex文件中没有给出入口地址信息我们也可以通过寻找RESET中断处理函数来确定程序入口函数。其中RESET中断函数的地址可以在STM32中文参考手册V10.pdf中找到相关信息

    e1b6d291706b7598f6bbabd84ff30a0c.png

    参考 STM32 中断向量表的位置 、重定向 中我们可以了解到在中断向量表中RESET的地址0x8000004的地址是固定的,而可变的是程序的加载地址。我们跳转到0x8000004这个地址上,按键盘D键将上面的数据分成4字节形式找到reset的地址为0x8000101

    2458d30792b77c55054b9171db68c4f6.png

    d1f3873b3ad66cdd956842aedac91958.png

    跳转到RESET中断处理函数,存在两次跳转。第一次跳转到nullsub_1上并将下一条指令地址放入LR寄存器,nullsub_1函数的作用是跳回LR寄存器中的地址,所以第一跳没有意义。第二次跳转就是我们的start地址,所以完全可以利用此方式定位到程序的入口地址。

    9e84614bb76832345ebaf57636f3f3f1.png

    一直跟着入口地址走就能找到这个程序的main函数所在,但是进来之后可以发现左边这一大片红色的标记,观察这些红色区域其实就是IDA没有识别的地址,也就是我们之前分析内存布局需要添加的内存段。

    fe98a65469de5aec68c271b7f6517a78.png

    我们在IDA中新建Segment,如下图所示:

    9012125e790002992afcb7f9499ecb32.png

    8f6a7cbca8046830bf9604f2b8141f1b.png

    这时只要我们再次点击F5即可让这些红色的标识变成正常识别的内存了

    c56231ecf7381045cefe1e2a83444643.png

    4、修复中断向量表

    使用IDApython恢复程序入口地址之前的信息

    1. for i in range(0x8000000,0x80000eb,1): 
    2.  del_items(i)
    3. for i in range(0x8000000,0x80000eb,4): 
    4.  create_dword(i)

    修复完成后我们观察这里面的地址,会发现有很多重复的地址0x800016D,跟进去会发现这些地址中没有定义函数功能。继续查看中断向量表会发现下面几个不同的内存地址

    ed23d657485d2fd0ad9cb90e0c0a31f1.png

    参考 STM32中文参考手册V10.pdf中的内容我们可以查找到这些就是EXTI的中断处理函数地址

    21118e11cb841cb588a4cc5ead30408a.png

    • stm32-EXTI

    跟进这些函数地址会发现IDA并没有将其识别为函数,所以我们先在函数起始地址处按P键,然后进行反汇编即可看到这些中断处理函数,这里我以EXTI_4的中断处理函数为例来简单介绍一下这些中断处理函数的功能。

    1. int EXTI_4()
    2. {
    3.   int result; // r0
    4.   EXTI_LINE = 16;
    5.   switch ( sum )
    6.   {
    7.     case 1:
    8.       unk_20000006 = 116;
    9.       return sum++ + 1;
    10.     case 2:
    11.       unk_20000010 = 95;
    12.       return sum++ + 1;
    13.     case 4:
    14.       unk_2000000E = unk_20000001;
    15.       return sum++ + 1;
    16.     default:
    17.       result = 0;
    18.       sum = 0;
    19.       break;
    20.   }
    21.   return result;
    22. }

    程序一开始先设置了中断/事件线,EXTI_4的中断/事件线为0x10,然后使用一块内存(这里记作sum)来作为累加数的保存位置。我们可以看到当sum中的值为1、2、4时sum的值会+1,如果不是的话则会重新开始。所以我们可以判断出1、2、4就是EXTI_4出现在密码中的位数,同理其他的三个按钮也是一样的,通过这些顺序我们可以得到最终的flag为flag{1442413},并且我们可以发现在main函数中程序先模拟输入了一次密码,通过将上面的值与EXTI_LINE进行对应也能得到flag值。

    2、2021 HWS 入营赛-STM32

    经过了上一题的入门接下来我们再来一道题目练习一下,打开IDA类型选择小段arm32,架构选择ARMv7-M架构。

    b8ff0aca44d6737c9d109ff76a45bd38.png

    接下来设置程序的加载地址和读取地址设置为0x8000000,加载地址是指IDA加载的分析地址是多少,而Input File是指固件要从什么位置开始加载,设置好以后我们点击OK完成设置。

    295c1b71b6e6019cdf37766cd854d8b3.png

    进入以后会发现IDA没有识别出任何函数,不用担心我们可以通过定位reset的中断处理来找到main函数的位置。将0x8000004地址处的字节变成4字节,得到reset中断处理函数地址0x8000101

    6e6d36b2ebdee98be11c698e851414bc.png

    可以发现地址的结尾是奇数位,在arm中这代表了thumb模式。我们可以在0x8000101地址按下C键即可生成代码

    4278895f0686aa0c62669a7f5500dd40.png

    一直跟着程序流走我们就能找到main函数所在位置sub_80003C0,并且在其中发现了需要逆向的函数sub_8000314

    1. _BYTE *sub_8000314()
    2. {
    3.   _BYTE *v0; // r4
    4.   char *v1; // r5
    5.   int v2; // r6
    6.   char v3; // t1
    7.   v0 = (_BYTE *)sub_80003F0(48);
    8.   v1 = &byte_8000344;
    9.   v2 = 0;
    10.   while ( v2++ != 0 )
    11.   {
    12.     v3 = *v1++;
    13.     *v0++ = (v3 ^ 0x1E) + 3;
    14.     sub_8000124(v1);
    15.   }
    16.   return v0;
    17. }

    6875b7eebed3ca3d53e09e0e6c7d7d10.png


    写出解题脚本即可获得flag值

    1. li = [0x7D0x770x400x7A0x660x300x2A0x2F0x280x400x7E0x300x330x340x2C0x2E0x2B0x280x340x300x300x7C0x410x340x280x330x7E0x300x340x330x330x300x7E0x2F0x310x2A0x410x7F0x2F0x280x2E0x64]
    2. print(''.join(chr((i ^ 0x1E) + 3for i in li))

    原创稿件征集

    征集原创技术文章中,欢迎投递

    投稿邮箱:edu@antvsion.com

    文章类型:黑客极客技术、信息安全热点安全研究分析等安全相关

    通过审核并发布能收获200-800元不等的稿酬。

    更多详情,点我查看!

    8c18b1c78f32572cc1e43706676e22ec.gif

    靶场实操,戳“阅读原文”

  • 相关阅读:
    非零基础自学Java (老师:韩顺平) 第13章 常用类 13.11 日期类
    前端常用库之-JavaScript工具库lodash
    Kubernets Pod概念浅析
    Linux中jsoncpp的编译使用
    国家开放大学 练习题
    某猫投诉app逆向 【一鱼多吃app逆向】
    蒋鑫鸿:9.10国际黄金原油最新外盘行情趋势点评附解一套技术指导
    消息队列 - RabbitMQ
    微服务架构详解
    利用百度AI接口实现车牌识别功能(二)
  • 原文地址:https://blog.csdn.net/qq_38154820/article/details/125568034