VxWorks固件分析方法总结
最近研究基于VxWorks系统的iot设备的固件分析方法,将学习心得记录于此,以备将来的查询需要。
1.VxWorks是什么?
VxWorks是美国WindRiverSystem公司(风河公司)推出的一个RTOS(实时操作系统),凭借良好的持续发展能力、高性能的内核以及友好的用户开发环境,在嵌入式实时操作系统领域占据一席之地。自从1987年首次问世以来,VxWorks系统版本经历了5.x,6.x到如今的7版本。VxWorks系统凭借其优秀的实时性占据着不小的市场份额,包括NASA的火星探测器、波音787客机、网络路由器等,市场范围跨越各种安全领域。
按照所运行的操作系统区分,嵌入式iot设备可以大致上分为基于linux和基于VxWorks的两类。VxWorks支持几乎所有现代市场上的嵌入式CPU架构,包括x86系列、MIPS、PowerPC、Freescale ColdFire、Intel i960、SPARC、SH-4、ARM、StrongARM以及xScale CPU。
2.如何定位VxWorks固件的加载地址
使用ida pro、ghidra等反汇编工具进行分析时,需要了解固件的加载地址,否则无法正确的分析固件。下图所示为填写固件加载地址前后的函数识别情况的对比,可以看出确定了固件加载地址之后函数的识别度更高。
2.1通过ELF文件头读取
通常固件文件会使用ELF格式进行封装,因此可以使用readelf等工具对头部文件进行分析,进而得到固件的加载地址。IDA pro已经集成了这个功能,可以直接分析出常见的固件的加载地址。
2.2通过分析内存中的相邻位置
如图所示为VxWorks固件在mips架构中的内存分布图,可知固件加载地址与栈初始化地址相邻,可以通过定位栈初始化地址确定固件的加载地址。
那么如何定位栈初始化地址呢?那就是寻找栈指针寄存器sp的位置。根据VxWorks官网给出的Initial Stack的说明,可知Initial Stack是usrInit()函数的初始化栈。
又因为UsrInit()是VxWorks系统引导后的运行的第一个函数,因此可以通过在ida中寻找sp寄存器首次出现的位置(此时的ida并没有指定固件加载地址),通过sp的值确定栈初始化的值,从而确定固件的加载地址。
如果所示,sp寄存器中保存0x80000FF0,因此固件的加载地址应该是0x80001000。
2.3通过定位bss在内存中的地址
这个方法在原理上同2.2的方法一样,但是需要一定的计算。根据UsrInit()的描述,第一个跳转的函数就是负责初始化BBS区的函数,因此可以寻找第一个跳转的指令的位置;还有另外一个方法确定初始化BBS区的位置,由于在系统启动过程中VxWorks会使用bzero函数对bss区的数据进行清零,所以可以在固件中用命令grep -r bzero
查找bzero字符串出现的位置,此方法可以作为验证。
2.4其他方法
通过焊接UART接口查看系统引导过程的串口输出;通过查阅开发者手册等。
3.使用符号表修复函数名
3.1寻找符号表的位置
如果固件本身已经编入了符号表,那么可以使用binwalk确定符号表的位置。
VxWorks系统的符号表按照每16个字节一组,前四个字节用0x00进行填充,第二个四字节表示符号名字符串在内存中的位置,第三个四字节表示符号在内存中的位置,最后四个字节代表符号的类型,如0x0500表示函数名。
但是如果分析固件没有得到符号表,可能存在两种可能:一种是固件本身就没有编入符号表,这种情况使得函数分析变得比较困难;另一种是符号表被开发者隐藏了起来,防止固件被顺利逆向。
如何寻找隐藏了的符号表还在学习中,之后会另开一篇专门介绍。
3.2修复函数名
在ida pro中,函数名的修复需要编写脚本,用符号表中的函数名替换当前无意义的函数名。在ghidra中,加载完固件之后可以运行vxhunter脚本,将函数名替换为符号表中的函数名。
ghidra修复完函数名之后的效果,可以很明显的看出施耐德PLC以太网模块固件NOE77101.bin固件中所存在的后门账户漏洞CVE-2011-4859。