作者:Hcamael@知道創(chuàng)宇404實驗室

時間:2019年11月29日
原文鏈接:https://paper.seebug.org/1090/
最近在研究IoT設(shè)備的過程中遇到一種情況。一個IoT設(shè)備,官方不提供固件包,網(wǎng)上也搜不到相關(guān)的固件包,所以我從flash中直接讀取。因為系統(tǒng)是VxWorks,能看到flash布局,所以能很容易把uboot/firmware從flash中分解出來。對于firmware的部分前一半左右是通過lzma壓縮,后面的一半,是相隔一定的區(qū)間有一部分有l(wèi)zma壓縮數(shù)據(jù)。而固件的符號信息就在這后半部分。因為不知道后半部分是通過什么格式和前半部分代碼段一起放入內(nèi)存的,所以對于我逆向產(chǎn)生了一定的阻礙。所以我就想著看看uboot的邏輯,但是uboot不能直接丟入ida中進(jìn)行分析,所以有了這篇文章,分析uboot格式,如何使用ida分析uboot。
正常的一個uboot格式應(yīng)該如下所示:
$?binwalk?bootimg.bin DECIMAL???????HEXADECIMAL?????DESCRIPTION --------------------------------------------------------------------------------13648?????????0x3550??????????CRC32?polynomial?table,?big?endian14908?????????0x3A3C??????????uImage?header,?header?size:?64?bytes,?header?CRC:?0x25ED0948,?created:?2019-12-02?03:39:51,?image?size:?54680?bytes,?Data?Address:?0x80010000,?Entry?Point:?0x80010000,?data?CRC:?0x3DFB76CD,?OS:?Linux,?CPU:?MIPS,?image?type:?Firmware?Image,?compression?type:?lzma,?image?name:?"u-boot?image"14972?????????0x3A7C??????????LZMA?compressed?data,?properties:?0x5D,?dictionary?size:?33554432?bytes,?uncompressed?size:?161184?bytes
而這uboot其實還得分為三部分:
1.從0x00 - 0x346C是屬于bootstrap的部分?
2.0x346C-0x34AC有0x40字節(jié)的uboot image的頭部信息?
3.從0x34AC到結(jié)尾才是uboot image的主體,經(jīng)過lzma壓縮后的結(jié)果
那么uboot是怎么生成的呢?Github上隨便找了一個uboot源碼:https://github.com/OnionIoT/uboot,編譯安裝了一下,查看uboot的生成過程。
1.第一步,把bootstrap和uboot源碼使用gcc編譯成兩個ELF程序,得到bootstrap和uboot
2.第二步,使用objcopy把兩個文件分別轉(zhuǎn)換成二進(jìn)制流文件。
$?mips-openwrt-linux-uclibc-objcopy?--gap-fill=0xff?-O?binary?bootstrap?bootstrap.bin $?mips-openwrt-linux-uclibc-objcopy?--gap-fill=0xff?-O?binary?uboot?uboot.bin $?binwalk?u-boot/bootstrap DECIMAL???????HEXADECIMAL?????DESCRIPTION --------------------------------------------------------------------------------0?????????????0x0?????????????ELF,?32-bit?MSB?executable,?MIPS,?version?1?(SYSV)13776?????????0x35D0??????????CRC32?polynomial?table,?big?endian28826?????????0x709A??????????Unix?path:?/uboot/u-boot/cpu/mips/start_bootstrap.S $?binwalk?u-boot/bootstrap.bin DECIMAL???????HEXADECIMAL?????DESCRIPTION --------------------------------------------------------------------------------13648?????????0x3550??????????CRC32?polynomial?table,?big?endian $?binwalk?u-boot/u-boot DECIMAL???????HEXADECIMAL?????DESCRIPTION --------------------------------------------------------------------------------0?????????????0x0?????????????ELF,?32-bit?MSB?executable,?MIPS,?version?1?(SYSV)132160????????0x20440?????????U-Boot?version?string,?"U-Boot?1.1.4??(Dec??2?2019,?11:39:50)"132827????????0x206DB?????????HTML?document?header133794????????0x20AA2?????????HTML?document?footer134619????????0x20DDB?????????HTML?document?header135508????????0x21154?????????HTML?document?footer135607????????0x211B7?????????HTML?document?header137363????????0x21893?????????HTML?document?footer137463????????0x218F7?????????HTML?document?header138146????????0x21BA2?????????HTML?document?footer138247????????0x21C07?????????HTML?document?header139122????????0x21F72?????????HTML?document?footer139235????????0x21FE3?????????HTML?document?header139621????????0x22165?????????HTML?document?footer139632????????0x22170?????????CRC32?polynomial?table,?big?endian179254????????0x2BC36?????????Unix?path:?/uboot/u-boot/cpu/mips/start.S $?binwalk?u-boot/u-boot.bin DECIMAL???????HEXADECIMAL?????DESCRIPTION --------------------------------------------------------------------------------132032????????0x203C0?????????U-Boot?version?string,?"U-Boot?1.1.4??(Dec??2?2019,?11:39:50)"132699????????0x2065B?????????HTML?document?header133666????????0x20A22?????????HTML?document?footer134491????????0x20D5B?????????HTML?document?header135380????????0x210D4?????????HTML?document?footer135479????????0x21137?????????HTML?document?header137235????????0x21813?????????HTML?document?footer137335????????0x21877?????????HTML?document?header138018????????0x21B22?????????HTML?document?footer138119????????0x21B87?????????HTML?document?header138994????????0x21EF2?????????HTML?document?footer139107????????0x21F63?????????HTML?document?header139493????????0x220E5?????????HTML?document?footer139504????????0x220F0?????????CRC32?polynomial?table,?big?endian
3.把u-boot.bin使用lzma算法壓縮,得到u-boot.bin.lzma
$?binwalk?u-boot/u-boot.bin.lzma DECIMAL???????HEXADECIMAL?????DESCRIPTION --------------------------------------------------------------------------------0?????????????0x0?????????????LZMA?compressed?data,?properties:?0x5D,?dictionary?size:?33554432?bytes,?uncompressed?size:?161184?bytes
4.使用mkimage,給u-boot.bin.lzma加上0x40字節(jié)的頭部信息得到u-boot.lzming
$?binwalk?u-boot/u-boot.lzimg DECIMAL???????HEXADECIMAL?????DESCRIPTION --------------------------------------------------------------------------------0?????????????0x0?????????????uImage?header,?header?size:?64?bytes,?header?CRC:?0x25ED0948,?created:?2019-12-02?03:39:51,?image?size:?54680?bytes,?Data?Address:?0x80010000,?Entry?Point:?0x80010000,?data?CRC:?0x3DFB76CD,?OS:?Linux,?CPU:?MIPS,?image?type:?Firmware?Image,?compression?type:?lzma,?image?name:?"u-boot?image"64????????????0x40????????????LZMA?compressed?data,?properties:?0x5D,?dictionary?size:?33554432?bytes,?uncompressed?size:?161184?bytes
5.最后把bootstrap.bin和u-boot.lzming合并到一起,然后根據(jù)需要uboot的實際大小,比如需要一個128k的uboot,在末尾使用0xff補齊到128k大小
在上面的結(jié)構(gòu)中,需要注意幾點:
1.Data Address: 0x80010000, Entry Point: 0x80010000表示設(shè)備啟動后,會把后續(xù)uboot通過lzma解壓出來的數(shù)據(jù)存入內(nèi)存地址0x80010000,然后把$pc設(shè)置為: 0x80010000,所以uboot最開頭4字節(jié)肯定是指令。
2.uncompressed size: 161184 bytes,可以使用dd把LZMA數(shù)據(jù)單獨取出來,然后使用lzma解壓縮,解壓縮后的大小要跟這個字段一樣。如果還想確認(rèn)解壓縮的結(jié)果有沒有問題,可以使用CRC算法驗證。
接下來就是通過dd或者其他程序把二進(jìn)制流從uboot中分離出來,再丟到ida中。先來看看bootstrap,首先指定相應(yīng)的CPU類型,比如對于上例,則需要設(shè)置MIPS大端。

隨后我們暫時設(shè)置一下起始地址為0x80010000,通電以后CPU第一個執(zhí)行的地址默認(rèn)情況下我們是不知道的,不同CPU有不同的起始地址。設(shè)置如下圖所示:

bootstrap最開頭也指令,所以按C轉(zhuǎn)換成指令,如下圖所示:

跳轉(zhuǎn)到0x80010400, 隨后是一段初始化代碼,下一步我們需要確定程序基地址,因為是mips,所以我們可以根據(jù)$gp來判斷基地址。

如上圖所示,因為bootstrap的大小為0x3a3c bytes,所以可以初步估計基地址為0x9f000000,所以下面修改一下基地址:

并且修改在Options -> General -> Analysis -> Processor specific ......設(shè)置$gp=0x9F0039A0

0x9F0039A0地址開始屬于got表的范圍,存儲的是函數(shù)地址,所以把0x9F0039A0地址往后的數(shù)據(jù)都轉(zhuǎn)成word:

到此就處理完畢了,后面就是存逆向的工作了,具體bootstrap代碼都做了什么,不是本文的重點,所以暫不管。
處理bootstrap,我們再看看uboot,和上面的處理思路大致相同。
1.使用dd或其他程序,把uboot數(shù)據(jù)先分離出來。 2.使用lzma解壓縮 3.丟到ida,設(shè)置CPU類型,設(shè)置基地址,因為uboot頭部有明確定義基地址為0x80010000,所以不用再自己判斷基地址 4.同樣把第一句設(shè)置為指令

正常情況下,uboot都是這種格式,0x80010008為got表指針,也是$gp的值。
5.根據(jù)0x80010008的值,去設(shè)置$gp 6.處理got表,該地址往后基本都是函數(shù)指針和少部分的字符串指針。結(jié)尾還有uboot命令的結(jié)構(gòu)體。
到此uboot也算基礎(chǔ)處理完了,后續(xù)也都是逆向的工作了,也不是本文的關(guān)注的內(nèi)容。
拿uboot的處理流程進(jìn)行舉例,使用Python編寫一個ida插件,自動處理uboot二進(jìn)制流文件。
1.我們把0x80010000設(shè)置為__start函數(shù)
idc.add_func(0x80010000)idc.set_name(0x80010000,?"__start")
2.0x80010008是got表指針,因為我們處理了0x80010000,所以got表指針地址也被自動翻譯成了代碼,我們需要改成word格式。
idc.del_items(0x80010008)idc.MakeDword(0x80010008)got_ptr?=?idc.Dword(0x80010008)idc.set_name(idc.Dword(0x80010008),?".got.ptr")
3.把got表都轉(zhuǎn)成Word格式,如果是字符串指針,在注釋中體現(xiàn)出來
def?got(): ????assert(got_ptr) ????for?address?in?range(got_ptr,?end_addr,?4): ????????value?=?idc.Dword(address) ????????if?value?==?0xFFFFFFFF:2019-12-03?15:36:56?星期二 ????????????break ????????idc.MakeDword(address) ????????idaapi.autoWait() ????????if?idc.Dword(value)?!=?0xFFFFFFFF: ????????????func_name?=?idc.get_func_name(value) ????????????if?not?idc.get_func_name(value): ????????????????idc.create_strlit(value,?idc.BADADDR) ????????????else: ????????????????funcs.append(func_name)
基本都這里就ok了,后面還可以加一些.text段信息,但不是必要的,最后的源碼如下:
#!/usr/bin/env?python#?-*-?coding=utf-8?-*-import?idcimport?idaapiclass?Anlysis:
????def?__init__(self):
????????self.start_addr?=?idc.MinEA()
????????self.end_addr?=?idc.MaxEA()
????????self.funcs?=?[]
????def?uboot_header(self):
????????idc.add_func(self.start_addr)
????????idc.set_name(self.start_addr,?"__start")
????????idc.del_items(self.start_addr?+?0x8)
????????idc.MakeDword(self.start_addr?+?0x8)
????????self.got_ptr?=?idc.Dword(self.start_addr+8)
????????idc.set_name(idc.Dword(self.start_addr+8),?".got.ptr")
????def?got(self):
????????assert(self.got_ptr)
????????for?address?in?range(self.got_ptr,?self.end_addr,?4):
????????????value?=?idc.Dword(address)
????????????if?value?==?0xFFFFFFFF:
????????????????break
????????????idc.MakeDword(address)
????????????idaapi.autoWait()
????????????if?idc.Dword(value)?!=?0xFFFFFFFF:
????????????????func_name?=?idc.get_func_name(value)
????????????????if?not?idc.get_func_name(value):
????????????????????idc.create_strlit(value,?idc.BADADDR)
????????????????else:
????????????????????self.funcs.append(func_name)
????def?get_max_text_addr(self):
????????assert(self.funcs)
????????max_addr?=?0
????????for?func_name?in?self.funcs:
????????????addr?=?idc.get_name_ea_simple(func_name)
????????????end_addr?=?idc.find_func_end(addr)
????????????if?end_addr?>?max_addr:
????????????????max_addr?=?end_addr
????????if?max_addr?%?0x10?==?0:
????????????self.max_text_addr?=?max_addr
????????else:
????????????self.max_text_addr?=?max_addr?+?0x10?-?(max_addr?%?0x10)
????def?add_segment(self,?start,?end,?name,?type_):
????????segment?=?idaapi.segment_t()
????????segment.startEA?=?start
????????segment.endEA?=?end
????????segment.bitness?=?1
????????idaapi.add_segm_ex(segment,?name,?type_,?idaapi.ADDSEG_SPARSE?|?idaapi.ADDSEG_OR_DIE)
????def?start(self):
????????#?text?seg
????????self.uboot_header()
????????self.got()
????????self.get_max_text_addr()
????????self.add_segment(self.start_addr,?self.max_text_addr,?".text",?"CODE")
????????#?end
????????idc.jumpto(self.start_addr)if?__name__?==?"__main__":
????print("Hello?World")另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)建站www.chinadenli.net,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。
標(biāo)題名稱:使用IDA處理U-Boot二進(jìn)制流文件-創(chuàng)新互聯(lián)
當(dāng)前地址:http://www.chinadenli.net/article4/deegoe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、品牌網(wǎng)站制作、云服務(wù)器、商城網(wǎng)站、建站公司、App設(shè)計
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容