zoukankan      html  css  js  c++  java
  • 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
    

    下载固件

    网上可以搜到

    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
    
  • 相关阅读:
    第五周作业_2013551605
    第四周作业_2013551605
    第三周作业
    第二周作业-2013551605-黎娜
    软件项目与过程管理第八周作业
    软件项目与过程管理第七周作业
    软件项目与过程管理第六周作业
    软件项目与过程管理第五周作业
    软件项目与过程管理第四周作业
    软件项目与过程管理第三周作业
  • 原文地址:https://www.cnblogs.com/hac425/p/9706815.html
Copyright © 2011-2022 走看看