vxworks固件分析
前言
vxworks
的固件分析流程
1.用binwalk查看固件基本信息并解压固件
2.获取固件相关信息, cpu架构,大小端
3.确定固件的加载地址
4.用IDA加载固件,并修复符号表
5. 分析固件
实战分析
一道CTF题
分析固件
用到的例子
http://www.icsmaster.org/wp-content/uploads/2018/01/2018013004153995.zip
首先用 binwalk
扫描下固件的信息
$ binwalk ctf_vxworks.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
901 0x385 Zlib compressed data, default compression
发现就是 zlib
压缩的数据, 用 binwalk
直接解开, 然后用 binwalk
对解开后的文件扫描,发现 vxworks
关键信息, 于是拿到 vxworks
的固件。
$ 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]
同时还扫到了符号表的位置
计算固件加载地址
固件加载地址的计算可以通过vxworks
固件中的符号表计算得出的。
固件的符号表一般在固件的最后,有明显的规律。
以 16个字节 为一组数据:
-
4个字节 符号对应字符串的内存地址
-
4个字节 符号的内存地址
-
4个字节 特征数据
-
4个字节
0x00
, 标识一组数据的结尾
计算加载地址的方法就是
加载地址 = 符号表中字符串的地址 - 相应字符串在固件中的偏移
这里还有一个小 tips
字符串表里面的最后一个字符串 在 符号表的第一项被引用
首先根据特征找到符号表, 根据 binwalk -A
可知固件为大端,所以 第一个符号表项对应字符串在内存中的地址为 0x27656c
然后找到字符串表中最后一个字符串所在偏移为 0x26656c
所以加载地址为
$ python -c "print hex(0x27656c - 0x26656c)"
0x10000
恢复符号表
拿到加载地址后,把固件用 IDA
加载起来,然后用 idapython
的脚本恢复即可、
from idaapi import *
from idc import *
loadaddress = 0x10000
eaStart = 0x301e64 + loadaddress
eaEnd = 0x3293a4 + loadaddress
ea = eaStart
eaEnd = eaEnd
while ea < eaEnd:
create_strlit(Dword(ea), BADADDR)
sName = get_strlit_contents(Dword(ea))
print sName
if sName:
eaFunc = Dword(ea + 4)
MakeName(eaFunc, sName)
MakeCode(eaFunc)
MakeFunction(eaFunc, BADADDR)
ea = ea + 16
就是遍历符号表项,在指定位置命名 + 设置函数。
参考
http://www.icsmaster.org/archives/ics/784
http://www.freebuf.com/vuls/177036.html
TP-Link wr886v6 分析
下载固件
网上可以搜到
http://www.drvsky.com/TP-Link/TL-WR886N.htm
分析固件
首先 binwalk
看看信息
这里 binwalk
只识别到了 u-boot
镜像,和一大堆 lzma
压缩的数据。通过 u-boot
的信息可以知道固件的加载地址为 0x80010000
发现其中有个 lzma
压缩的数据大小和其他的不在一个数量级, 把它拿出来解析。
41472 0xA200 LZMA compressed data, properties: 0x6E, dictionary size: 8388608 bytes, uncompressed size: 2365616 bytes
然后用 dd
把它 拿出来
dd if=wr886v6.bin of=large.lzma bs=1 skip=41472 count=749632
然后用 binwalk
解出来
$ binwalk _large.lzma.extracted/0
0 0.7z
$ binwalk _large.lzma.extracted/0
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
1846464 0x1C2CC0 Certificate in DER format (x509 v3), header length: 4, sequence length: 4
1853752 0x1C4938 Certificate in DER format (x509 v3), header length: 4, sequence length: 4
1899120 0x1CFA70 VxWorks operating system version "5.5.1" , compiled: "Oct 20 2017, 16:17:22"
1968188 0x1E083C Copyright string: "Copyright(C) 2001-2011 by TP-LINK TECHNOLOGIES CO., LTD."
1997876 0x1E7C34 VxWorks WIND kernel version "2.6"
2042936 0x1F2C38 HTML document header
2043001 0x1F2C79 HTML document footer
2062828 0x1F79EC PEM certificate
2062884 0x1F7A24 PEM RSA private key
2072188 0x1F9E7C Base64 standard index table
2107248 0x202770 CRC32 polynomial table, big endian
2108272 0x202B70 CRC32 polynomial table, big endian
2109296 0x202F70 CRC32 polynomial table, big endian
2110320 0x203370 CRC32 polynomial table, big endian
2130920 0x2083E8 XML document, version: "1.0"
2150332 0x20CFBC SHA256 hash constants, big endian
2248421 0x224EE5 StuffIt Deluxe Segment (data): f
2248452 0x224F04 StuffIt Deluxe Segment (data): fError
2248533 0x224F55 StuffIt Deluxe Segment (data): f
可以看到有 vxworks
的字符串,前面已经拿到了固件的基地址,用 ida
加载。
恢复符号表
使用 grep
来找符号表
$ binwalk -Me wr886v6.bin
........
$ cd _wr886v6.bin.extracted/
$ grep -r bzero
Binary file C2E3A matches
然后打开 C2E3A
看看
开头 8 字节表示文件大小和符号表大小, 然后就是符号表了, 0x9d00
为字符串表的位置。
然后用脚本恢复
# coding=utf-8
import idc
import idaapi
import idautils
sym_file = open("PATH OF SYM FILE", 'rb').read()
table_data = sym_file[0x08:0x9f80]
print(table_data[-8:].encode('hex'))
string_table = sym_file[0x9f80:]
def get_string(offset):
string = ""
while True:
if string_table[offset] != '\x00':
string += string_table[offset]
offset += 1
else:
break
return string
def get_sym_data():
sym_data = []
for offset in range(0, len(table_data), 8):
table = table_data[offset: offset + 8]
flag = table[0]
# print('flag: %s' % flag)
string_offset = int(table[1:4].encode('hex'), 16)
# print('string_offset: %s' % string_offset)
string = get_string(string_offset)
# print('string: %s' % string)
target_address = int(table[-4:].encode('hex'), 16)
# print('target_address: %s' % hex(target_address))
sym_data.append([flag, string, target_address])
return sym_data
def fix_idb(sym_data):
for sym in sym_data:
flag, string, target_address = sym
idc.MakeName(target_address, string)
if flag == '\x54':
print("Start fix Function %s at %s" % (string, hex(target_address)))
idc.MakeCode(target_address)
idc.MakeFunction(target_address, idc.BADADDR)
# print('flag: %s' % flag)
# print('string: %s' % string)
# print('target_address: %s' % hex(target_address))
if __name__ == '__main__':
sym_data = get_sym_data()
fix_idb(sym_data)
参考
https://www.secpulse.com/archives/75635.html