vxworks固件分析

摘要:
固件的符号表通常在固件末尾具有明显的规则。参考资源http://www.icsmaster.org/archives/ics/784http://www.freebuf.com/vuls/177036.htmlTP-可以在线找到Linkwr886v6分析下载固件http://www.drvsky.com/TP-Link/TL-WR886N.htm首先,分析固件。看看binwalk中的信息。在这里,binwalk只识别u-boot映像和大量lzma压缩数据。从u-boot信息中,我们可以知道固件的加载地址是0x80010000。我们发现其中一个lzma压缩数据大小与其他数据大小的数量级不同,因此我们可以对其进行分析。
前言

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, 标识一组数据的结尾

vxworks固件分析第1张

计算加载地址的方法就是

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

这里还有一个小 tips

字符串表里面的最后一个字符串 在 符号表的第一项被引用

首先根据特征找到符号表, 根据 binwalk -A 可知固件为大端,所以 第一个符号表项对应字符串在内存中的地址为 0x27656c

vxworks固件分析第2张

然后找到字符串表中最后一个字符串所在偏移为 0x26656c

vxworks固件分析第3张

所以加载地址为

$ 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 看看信息

iMQJu6.png

这里 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 看看

iMl2sx.png

开头 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

免责声明:文章转载自《vxworks固件分析》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇1.微信公众号---获取关注用户MySQL常见问题下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

C# HTTP请求 异步(async await)

static void Main(string[] args) { new Task(() => { Invoke(); }).Start(); Console.WriteLine("我是主线...

Java 代码实现rar解压最全攻略操作

最全Java 代码实现rar解压操作首先,非常感谢下面几位链接上的支持,之所以写这篇博文,主要在于总结,同时给第一次实现该功能的同学提供完整的参考。因为第一次遇到需要在代码中实现rar和zip的解压操作。而zip其实很简单,jdk自带的ZipUtil就可以实现,这里不做赘述。但是rar的解压,特别是5.0及其以上版本的解压,折腾了我很久。根据这几位博主的思...

开源netcore前后端分离,前端服务端渲染方案

SPA单页面应用容器开源地址:https://github.com/yuzd/Spa 功能介绍 前端应用开发完后打包后自助上传部署发布 配合服务端脚本(javascript)实现服务端业务逻辑编写渲染SSR功能 可以快速回滚到上一个版本 可以设置环境变量供SSR功能使用 服务端脚本提供执行日志 redis db三大组件打造强大的基于js的ssr服务端...

a标签 target="_blank" 需要注意这些

网页里的 a 标签默认在当前窗口跳转链接地址,如果需要在新窗口打开,需要给 a 标签添加一个 target="_blank" 属性。 <a href="http://www.baidu.com"target="_blank">去百度</a> 安全隐患 如果只是加上 target="_blank" ,打开新窗口后,新页面能通过 win...

Asp.Net 4.0 新特性之 使用自定义OutputCache Provider

Asp.Net 4.0 新特性之 使用自定义OutputCache Provider 在Asp.Net 4.0 的web.config文件中添加了关于缓存的配置节,如下所示: <system.web> <compilation debug="true" targetFramework="4.0" /> <...

impala 四舍五入后转换成string后又变成一个double的数值解决(除不尽的情况)

impala 四舍五入后转换成string后又变成一个double的数值解决(除不尽的情况)例如Query: select cast(round(2 / 3, 4)*100 as string)+---------------------------------------+| cast(round(2 / 3, 4) * 100 as string) |...