STM32 & RT-Thread的逆向入门

backahasten@0xFA

​                现在,各种MCU的价格越来越低,同等条件下能买到的ROM和RAM资源也多了。对一些复杂逻辑的应用,相比于花费大量的时间去扣底层还不如使用操作系统加快开发速度,使用了操作系统之后,针对固件的逆向会比无os的固件逆向有一些不同。

​                RT-Thread是国产实时操作系统的典范,我个人的特别喜欢。RT-Thread有很多的BSP可以适配众多的芯片和架构,在本文还是使用最常见的stm32来进行介绍。

​                硬件上我是用了正点原子核RT-Thread联合开发的潘多拉开发板,在本文中没有使用潘多拉的硬件,我比较偷懒的使用了开发板配套的例子去做逆向。

启动

​                我一直相信一句话,不会开发也就不会安全,开发能力决定着安全能力的天花板。在逆向STM32 & RT-Thread的过程中也是这个样子的。我们打开一个bin文件,第一件事就是找到main函数,这个main函数并不是stm32的main函数而是操作系统的main函数。例如在stm32 & keil开发中,RT-Thread使用$Sub$$main调用初始化操作系统,如果是不带操作系统的裸开发,这个函数就是逻辑的main函数了。

​                详细的启动过程可以在https://www.rt-thread.org/document/site/tutorial/quick-start/stm32f103-simulator/stm32f103-simulator/中找到,为了本文的完整,我们复制过来一些代码。

//components.c 中定义
/* re-define main function */
int $Sub$$main(void)
{
    rt_hw_interrupt_disable();
    rtthread_startup();
    return 0;
}

这里面调用了两个函数,第一个函数关闭了中断,开始初始化操作系统。

int rtthread_startup(void)
{
    rt_hw_interrupt_disable();
    /* board level initalization
     * NOTE: please initialize heap inside board initialization.
     */
    rt_hw_board_init();
    /* show RT-Thread version */
    rt_show_version();
    /* timer system initialization */
    rt_system_timer_init();
    /* scheduler system initialization */
    rt_system_scheduler_init();
#ifdef RT_USING_SIGNALS
    /* signal system initialization */
    rt_system_signal_init();
#endif
    /* create init_thread */
    rt_application_init();
    /* timer thread initialization */
    rt_system_timer_thread_init();
    /* idle thread initialization */
    rt_thread_idle_init();
    /* start scheduler */
    rt_system_scheduler_start();
    /* never reach here */
    return 0;
}

rtthread_startup();函数中,进行各个组件的初始化,其他我们不用管,重点看其中的rt_application_init();函数,这个函数用于线程任务的初始化,在其中,我们就可以脱离操作系统代码的范畴,进入到真正的逻辑代码的位置。

操作

​                我们使用潘多拉开发板的例子29_iot_web_server,这个例子复杂程度中等,可以充分的分析各个点。keil编译之后,会的带axf文件和Hex文件,其中axf带有符号表,而hex文件只有基础的组织结构,由于嵌入式的特点,为了节约资源,烧录进芯片里的固件基本都不会带符号表。为了仿造真实情况下拿到的固件,我们使用jlink的工具打开hex文件之后保存成bin文件。之后使用ida pro打开。

​                打开文件之后,正确载入逆向,显示如下:(使用IDA PRO逆向ARM M核心的方法请参考我之前的文章

选中的地址 0x8000495为芯片的上电PC载入地址,找到地址之后,如下:

由于最开始是硬件PC设置,没有软件引用关系,ida pro没有识别,在0x8000494处按C,进行反汇编:

发现可以看到stm32的启动代码,进入函数0x800188:

发现0x800018C处的函数没有识别,依旧按C:

发现识别出来一个函数的跳转,继续跟踪,进入:

发现有四个函数,具体函数的意义是什么,没有符号表不得而知。

这里介绍一个小技巧,我们现在处于上帝模式,我们有axf文件,axf文件中有符号表,并且,这一段程序在操作系统中,所有的stm32都是一样的,我们现在反汇编axf文件,与bin文件互相参照,可以更好的分析启动过程。打开axf文件,找到位置:

选中的函数,也就是第二个函数,是有关操作系统线程的设置,选择进入:

发现又是一堆函数,我们依旧参考axf文件:

第六个函数跳转是任务的设置,选择进入:

在这里我们可以发现任务main函数的设置,进入函数0x802485C

还有两个函数,参考一下axf: 

上面的是任务进入的设置,下面是main函数的逻辑,进入main函数:

按F5转变成伪代码:

这就是任务main函数的逻辑,接下来就可以进行下一步的分析了。

实际上,还有另外一个方法,直接搜索字符串main:

同样可以找到main函数的位置。但是由于任务名称可能修改,从启动代码 逐步分析是最可靠的方法。

没有符号表依然很难受,我在那篇文章中也介绍了恢复符号表的方法,有需要大家可以参考。

最新文章

  1. Ubuntu 网络参数设置
  2. Maven教程(转载)
  3. android 数据存储----文件方式 总结
  4. Session,ViewState用法
  5. reaver使用相关
  6. 02 nodejs命令参数(NodeJS基础入门)
  7. unity游戏设计之背包系统
  8. YUI Compressor
  9. 前端学习之CSS
  10. 【Git】在GitHub或OSChina上新建项目后,如何在本地第一次push代码到服务器
  11. 如何手动删除服务?Windows手动删除服务列表中残留服务的方法
  12. 为什么Github要把代码合并请求称为pull request而不是push request?
  13. IO读 BufferedReader+FileReader
  14. zedgraph右键菜单的汉化
  15. Redis安装步骤 - linux系统下
  16. list.contains
  17. 用注册表更改DNS的代码分享
  18. LeetCode OJ:Merge k Sorted Lists(归并k个链表)
  19. Data Flow ->> OLE DB Destination ->> Fast Load
  20. 【hihoCoder 第133周】【hihoCoder 1467】2-SAT·hihoCoder音乐节

热门文章

  1. Java类加载器和双亲委派机制
  2. golang学习笔记(一):包,变量,函数
  3. 【WPF学习】第四十六章 效果
  4. Maven项目pom文件的节点释意
  5. 基于python的密码字典生成器
  6. 解决intellij idea新建maven项目,加载archetype慢的问题
  7. 【转载】Linux设备树(Device Tree)机制
  8. 第一篇 Springboot + Web MVC + MyBatis + 简单UI + Thymeleaf实现
  9. Windows远程连接Ubuntu上的MySQL数据库
  10. css常用样式对文本的处理演练