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核心的方法请参考我之前的文章
<ignore_js_op>

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

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

<ignore_js_op>

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

<ignore_js_op>

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

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

<ignore_js_op>

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

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

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

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

<ignore_js_op>

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

<ignore_js_op>

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


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

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

按F5转变成伪代码:
<ignore_js_op>

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

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

<ignore_js_op>

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

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

猜你喜欢

转载自www.cnblogs.com/backahasten/p/11646002.html