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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM