Contents
  1. 1. 固件内存加载地址
  2. 2. 符号表修复函数名

固件下载地址:https://github.com/ameng929/NOE77101_Firmware/blob/master/FLASH0/wwwroot/conf/exec/NOE77101.bin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ binwalk -Me NOE77101.bin
$ cd _NOE77101.bin.extracted/
$ binwalk 385

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
2054252 0x1F586C EST flat binary
2088936 0x1FDFE8 HTML document header
2108532 0x202C74 HTML document footer
2110048 0x203260 HTML document header
2115564 0x2047EC HTML document footer
2119528 0x205768 XML document, version: "1.0"
2119796 0x205874 XML document, version: "1.0"
2119912 0x2058E8 XML document, version: "1.0"
2192512 0x217480 Base64 standard index table
2192580 0x2174C4 Base64 standard index table
2211604 0x21BF14 VxWorks WIND kernel version "2.5"
2225264 0x21F470 Copyright string: "Copyright Wind River Systems, Inc., 1984-2000"
2321952 0x236E20 Copyright string: "copyright_wind_river"
3118988 0x2F978C Copyright string: "Copyright, Real-Time Innovations, Inc., 1991. All rights reserved."
3126628 0x2FB564 Copyright string: "Copyright 1984-1996 Wind River Systems, Inc."
3153524 0x301E74 VxWorks symbol table, big endian, first entry: [type: function, code address: 0x1FF058, symbol address: 0x27655C]

固件的操作系统为VxWorks2.5,符号表位于0x301E74

确定CPU架构为PowerPC big endian

1
2
3
4
5
6
7
8
9
10
11
12
13
$ binwalk -A 385

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
160 0xA0 PowerPC big endian instructions, function epilogue
400 0x190 PowerPC big endian instructions, function epilogue
408 0x198 PowerPC big endian instructions, function prologue
460 0x1CC PowerPC big endian instructions, function epilogue
468 0x1D4 PowerPC big endian instructions, function prologue
516 0x204 PowerPC big endian instructions, function epilogue
524 0x20C PowerPC big endian instructions, function prologue
616 0x268 PowerPC big endian instructions, function epilogue
624 0x270 PowerPC big endian instructions, function prologue

固件内存加载地址

嵌入式系统固件需要加载到内存中特定位置运行,这个特定位置就是固件加载地址

固件加载地址 = 符号表中字符串的地址 - 相应字符串在固件中的偏移

嵌入式系统固件的函数调用地址是基于固件加载地址所计算出的内存位置,而不是固件中的地址

1、ELF封装的固件文件,在ELF文件的头部有特定的数据位记录了该固件的加载地址,

如果有ELF封装头部,因此我们可以直接读取ELF文件头,从而直接获取到固件的加载地址。

1
2
3
4
$ readelf -a vxworks
...
Entry point address: 0x10000
...

2、分析固件头部的初始化代码,如usrInit这是vxWorks系统引导后运行的第一个函数,它初始化栈的地址(R1寄存器)就是固件的内存加载地址【不太明白为什么不是0xFFF0,因为我后面算出来也是0xFFF0】(因为我已经修复好符号表,并加载了基址,我也没有那种拖进去就有一部分函数的版本,所以下面就用这个已经修复好的分析了)

3、找到bss区数据初始化代码,bss区在VxWorks中主要用于存储一些当前未赋值的变量,系统启动过程中Vxworks使用bzero函数对bss数据清零

usrInit函数还会首先对bss进行清理,第一个跳转函数就是bss初始化函数,进入后的第一个跳转函数就是bzero,根据他的两个参数可以分析出bss的起始和结束地址,r3=bss_startaddr r4=bss_endaddr

r3=bss_startaddr r4=bss_endaddr

由于VxWorks系统的内存布局为

所以用_end - 固件大小即可得到加载地址 0x490d2c - 0x480d2c = 0x10000

4、如果IDA可以分析出少数函数,可以根据 调用地址 一般写为 偏移量+绝对地址 中的绝对地址,来确定固件加载地址

5、分析符号表查看,本例介绍

拖入ida查看

什么都没解析出来。

VxWorks系列的字节排序有独特的格式,以16个字节为一组数据,前4个字节是函数名的内存地址,后4个字节是函数的内存位置,然后以另4个特征字节数据+4个字节0x00结尾。

0x301e74

最后一个字符串会在符号表中第一个被引用,最后的字符串为APP_STATION_MODBUS(我也不确定为什么)

最后一个字符串

0x27655c - 0x26656c = 0xFFF0….(根据后面用idc跑出来的函数列表来看,这是错误的固件加载地址,应该是0x10000,这又是为什么啊)

加载后还是什么都咩有…

符号表修复函数名

符号表的起始地址为0x301E64+load_addr,结束地址为0x3293a4+load_addr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/* Ruben Santamarta - IOActive */
/* Rebuild VxWorks Symbol Table */

#include <idc.idc>

static main()
{
auto load_addr;
auto ea;
auto offset;
auto sName;
auto eaStart;
auto eaEnd;

// You'll need to adjust these values
load_addr = 0x10000;
eaStart = 0x301E64 + load_addr;
eaEnd = 0x3293a4 + load_addr;

SetStatus(IDA_STATUS_WORK);
ea = eaStart;

while( ea < eaEnd) {
MakeDword( ea );
offset = 0;
if ( Dword( ea ) == 0x900 || Dword( ea ) == 0x500)
{
offset = 8;
}
else if( Dword( ea ) == 0x90000 || Dword( ea ) == 0x50000 )
{
offset = 0xc;
}
if( offset )
{
MakeStr( Dword( ea - offset ), BADADDR);
sName = GetString( Dword( ea - offset ), -1, ASCSTR_C ) ;
if ( sName )
{
if( Dword( ea ) == 0x500 || Dword( ea ) == 0x50000)
{
if ( GetFunctionName( Dword( ea - offset + 4) ) == "" )
{
MakeCode( Dword( ea - offset + 4) );
MakeFunction( Dword( ea - offset + 4), BADADDR );
}
}
MakeName( Dword( ea - offset + 4 ), sName );
}
}
ea = ea + 4;
}

SetStatus(IDA_STATUS_READY);
}

通过调用关系_sysInit -> usrInit -> usrKernelInit -> usrRoot -> usrAppInit

发现后门账号

【密码通过vxEncrypt加密(VxWorks 5.x系统默认加密方式)】

reference:

https://paper.seebug.org/613/#1

https://blog.csdn.net/weixin_43815930/article/details/107646507

https://paper.seebug.org/771/