zoukankan      html  css  js  c++  java
  • STM32 & RT-Thread的逆向入门

    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函数的位置。但是由于任务名称可能修改,从启动代码 逐步分析是最可靠的方法。

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

  • 相关阅读:
    面试笔记之手写单例模式
    Java学习笔记六:Java最基础
    Mac下终端工具iTerm2的快捷键
    Typescript引用类型--字符串
    Typescript引用类型--数组
    Typescript函数作用域
    Typescript的函数定义方式
    初识Typescript以及Typescript的安装
    VS Code前端开发常用插件和常用快捷键
    Vue CLI3项目构建
  • 原文地址:https://www.cnblogs.com/backahasten/p/11646002.html
Copyright © 2011-2022 走看看