静态编译qemu_使用QEMU chroot进行固件本地调试
閱讀:
2,905
QEMU是開發(fā)者在調(diào)試一些不同架構(gòu)的程序時(shí)經(jīng)常使用的虛擬機(jī)軟件。它有兩種運(yùn)行模式,全系統(tǒng)模擬(System mode)和單程序運(yùn)行(User mode)。System mode和開發(fā)者平常用的VMWare一樣,模擬整個(gè)系統(tǒng)從加載器開始的啟動(dòng)和運(yùn)行。在設(shè)備逆向過(guò)程中,如果僅僅是為了運(yùn)行開發(fā)者提取出文件系統(tǒng)中的某一個(gè)程序,那就可以使用QEMU的user mode來(lái)簡(jiǎn)化整個(gè)操作流程,同時(shí)能夠方便的利用 QEMU 自帶的GDB服務(wù)來(lái)進(jìn)行調(diào)試,免去搭建環(huán)境的煩惱。
但是,單單在命令行中調(diào)用“qemu-arm myprogram”往往沒(méi)有那么簡(jiǎn)單,因?yàn)閯?dòng)態(tài)鏈接的程序都會(huì)依賴幾個(gè)動(dòng)態(tài)鏈接庫(kù)。雖然可以傳入 -L 參數(shù),或者通過(guò)指定環(huán)境變量QEMU_LD_PREFIX解決,但這種方式不但不優(yōu)雅,還會(huì)造成重復(fù)性的工作——每個(gè)程序依賴的庫(kù)不同,因此每次都要選擇不同的目錄。而且使用這種方式啟動(dòng)的程序,所運(yùn)行的程序文件夾(CWD)與原來(lái)不同,很可能訪問(wèn)不了程序中硬編碼的一些文件的絕對(duì)路徑,造成程序出錯(cuò)。
因此最簡(jiǎn)單直接的方法還是使用chroot配合QEMU,來(lái)完全模擬程序的文件系統(tǒng)環(huán)境,以固件的根目錄作為chroot的根目錄,程序也能夠自動(dòng)加載到它所需要的libc與其他各種函數(shù)庫(kù)。綠盟的小伙伴在看雪上做過(guò)一次分享,我聽過(guò)后以為很容易上手,但是操作時(shí)踩到了一些坑。這里總結(jié)一下整個(gè)流程,順便講解一下其中的原理。
編譯安裝
Ubuntu自帶的 QEMU 版本有點(diǎn)老(我的18.04 LTS 附帶的 QEMU 2.11),在調(diào)試時(shí)會(huì)遇到類似下面的報(bào)錯(cuò):~ # ./gdbserver tcp:2333 /usr/bin/messagingagent
qemu: Unsupported syscall: 117
老版本QEMU不能夠很好的處理與調(diào)試相關(guān)的ptrace系統(tǒng)調(diào)用,我們需要從官方的最新版源代碼編譯安裝QEMU。
依賴的安裝可以參考官方教程。安裝好依賴后從git獲取最新的源碼,并使用以下參數(shù)指定編譯的QEMU采用靜態(tài)鏈接,最后進(jìn)行編譯。我在這里指定prefix目錄為當(dāng)前目錄下的 staging,自己操作時(shí)可以隨意更改。git clone git://git.qemu.org/qemu.git --recurse-submodules --depth 1
cd qemu
./configure --static --prefix="$PWD/staging/user-static" --disable-system --enable-linux-user
make –j8 && make install
然后 staging/user-static 目錄下就是我們編譯好的核武器了。
安裝binfmt
binfmt(Binary Format)是一個(gè)內(nèi)核模塊,它的用處如它的名字,通過(guò)二進(jìn)制文件頭來(lái)識(shí)別它的格式,從而指定用哪個(gè)解釋器去啟動(dòng)——可以理解為二進(jìn)制文件的hashbang(用處類似于在Python文件的第一行寫上“#!/usr/bin/env python”)。有了它我們就可以像啟動(dòng)原生ELF一樣啟動(dòng)一個(gè)ARM或其他任何QEMU支持的程序了。sudo apt install qemu-user-binfmt
update-binfmts --display
安裝這個(gè)包會(huì)依賴安裝系統(tǒng)軟件源中的qemu-user。我們用不到它,但裝這個(gè)包的意義在于它包含了幾個(gè)自動(dòng)向內(nèi)核注冊(cè)QEMU binfmt的腳本,這樣我們就不需要再手動(dòng)指定我們的ARM可執(zhí)行文件需要哪個(gè)路徑下的QEMU來(lái)執(zhí)行,非常方便。安裝成功后在命令行中執(zhí)行“update-binfmts –display”。
圖 1 update-binfmts輸出
我們此時(shí)可以測(cè)試一下,臨時(shí)將環(huán)境變量QEMU_LD_PREFIX設(shè)置為我們要chroot進(jìn)去的根目錄,然后運(yùn)行ARM設(shè)備中提取出的ELF可執(zhí)行文件,如果不報(bào)錯(cuò)就可以了。圖中a.out是我編譯的arm64的hello world,這個(gè)程序可在我的測(cè)試設(shè)備上正常運(yùn)行。
圖 2 運(yùn)行示例程序 Hello World
復(fù)制QEMU程序
hello world可以運(yùn)行之后,我們還需要準(zhǔn)備一下我們的rootfs目錄。
將第一步編譯目錄中的“staging/user-static/qemu-aarch64”復(fù)制到“update-binfmts”中顯示的對(duì)應(yīng)位置(/usr/bin/qemu-aarch64),如果必要的話,將這里的aarch64替換成你所要運(yùn)行的程序架構(gòu)。注意必須是相同位置!當(dāng)我們啟動(dòng)為ARM或其他架構(gòu)編譯的應(yīng)用程序時(shí),系統(tǒng)會(huì)調(diào)用binfmts識(shí)別它的類型并調(diào)用之前注冊(cè)的interpreter(如/usr/bin/qemu-aarch64)來(lái)“翻譯”啟動(dòng)。在chroot下,依然會(huì)從這個(gè)路徑中尋找。因此如果chroot后這個(gè)路徑下找不到QEMU,啟動(dòng)任何程序都會(huì)報(bào)錯(cuò)No such file or directory。這個(gè)報(bào)錯(cuò)會(huì)有很多歧義,因此一定要自己確認(rèn)一下QEMU確實(shí)在rootfs的“/usr/bin”目錄中。
運(yùn)行sudo chroot . /bin/sh
到這里,我們就可以像在虛擬機(jī)中一樣,通過(guò)shell運(yùn)行這個(gè)chroot中的所有程序了!
總結(jié) Xxx not found 相關(guān)的問(wèn)題
當(dāng)我運(yùn)行一個(gè)命令時(shí),# ./run_xxx_command
報(bào)一個(gè)錯(cuò)——run_xxx_command :No such file or directory
我的第一反應(yīng)肯定是懷疑自己。程序名稱輸錯(cuò)了?但又不對(duì),我怎么可能這么蠢呢?一路摸爬滾打下來(lái),我發(fā)現(xiàn)最蠢的還是這句模糊的報(bào)錯(cuò)信息。它會(huì)有很多歧義。
根據(jù)我的經(jīng)驗(yàn),這個(gè)報(bào)錯(cuò)會(huì)有以下四種原因。最容易想到的:要運(yùn)行的命令不存在。
動(dòng)態(tài)鏈接器不存在,如下例,運(yùn)行IDA的遠(yuǎn)程調(diào)試器。
運(yùn)行objdump可以看到它需要哪個(gè)解釋器來(lái)讀取它。一般都是ld-xxxx.so
如果ld找不到的話,這程序能運(yùn)行的概率就很小了。QEMU解釋器沒(méi)找到。如果我們注冊(cè)了binfmt卻沒(méi)有將qemu拷貝到“rootfs/usr/bin“中,chroot時(shí)也會(huì)報(bào)一樣的錯(cuò)誤——文件沒(méi)找到。如果沒(méi)有踩過(guò)這個(gè)坑,大概會(huì)很久找不出原因吧。
動(dòng)態(tài)鏈接庫(kù)沒(méi)找到。這種情況比較顯而易見(jiàn),因?yàn)樗麜?huì)告訴你哪個(gè)庫(kù)沒(méi)找到。
以后拿到一個(gè)新的固件包,只需要解壓到一個(gè)文件夾里,把對(duì)應(yīng)架構(gòu)的qemu拷貝進(jìn)去,直接運(yùn)行命令chroot即可。遇到需要調(diào)試的程序,我們通過(guò)運(yùn)行“qemu-aarch64 -g 2331 /path/to/binary”指定-g參數(shù)開啟調(diào)試選項(xiàng),也可以聲明一個(gè)環(huán)境變量QEMU_GDB=2331,帶上這個(gè)環(huán)境變量所啟動(dòng)的程序,都會(huì)自動(dòng)開啟GDB端口并等待調(diào)試器attach,調(diào)試起來(lái)是不是很方便呢?
參考資料:
總結(jié)
以上是生活随笔為你收集整理的静态编译qemu_使用QEMU chroot进行固件本地调试的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: python 单例模式内存泄露_彻底搞懂
- 下一篇: 怎么把series变为datamate_