這篇文章主要講了如何在模擬環境下調試設備固件。
作者:Zach Cutlip
原文鏈接:http://shadow-file.blogspot.gr/2015/01/dynamically-analyzing-wifi-routers-upnp.html。
在分析嵌入式設備的固件時,只采用靜態分析方式通常是不夠的。你需要實際執行你的分析目標來觀察它的行為。在嵌入式Linux設備的世界里,很容易把一個調試器放在目標硬件上進行調試。如果你能在自己的系統上運行二進制文件,而不是拖著硬件做分析, 將會方便很多。這就需要用QEMU進行仿真。
接下來的一系列文章,我將專注于Netgear的一個比較流行的無線路由器,對其UPnP守護進程進行逆向分析。這篇文章將介紹如何在系統仿真環境下運行守護進程,以便可以通過調試器對其進行分析。
首先,建議你讀一下我的工作區以及所使用的工具的描述。這里是鏈接http://shadow-file.blogspot.com/2013/12/emulating-and-debugging-workspace.html。
你需要一個MIPS Linux的模擬環境。對于這一點,建議讀者查看我之前的搭建QEMU的帖子。http://shadow-file.blogspot.com/2013/05/running-debian-mips-linux-in-qemu.html
你還需要一個MIPS Linux的交叉編譯器。我不會詳細描述交叉編譯器的建立過程,因為它們一團糟。有時候,你需要較舊的工具鏈,而其他時候,你需要較新的工具鏈。最好使用uClibc buildroot project(http://buildroot.uclibc.org/)同時建立big endian和little endian的MIPS Linux工具鏈。除此之外,每當我發現其他交叉編譯工具鏈時,我都會保存他們。類似D-Link和Netgear公司發布GPL版本tarballs是舊工具鏈的好來源。
一旦你有了目標架構的交叉編譯工具鏈,你需要為目標建立GDB調試器。你至少需要適合目標架構的被靜態編譯的gdbserver。如果要使用GDB進行遠程調試,你需要編譯GDB,以便在你的本地機器架構(如X86-64)上運行,來對目標架構(如MIPS或mipsel體系結構)進行調試。同樣,我也不會去討論這些工具的構建,如果你建立了你的工具鏈,這應該很容易了。
后面我將描述如何使用IDA Pro來進行遠程調試。但是,如果你想使用gdb,可以看看我的MIPS gdbinit文件:https://github.com/zcutlip/gdbinit-mips
假設你已經建立了上述工具,并能正常工作,你現在應該能夠通過SSH進入您的模擬MIPS系統。正如我在Debian MIPS QEMU文章中所述,我喜歡連接QEMU的接口到VMWare的NAT接口,這樣就能夠用我的Mac通過SSH來接入,而不需要先登陸我的Ubuntu虛擬機。這也可以讓我通過NFS將我的Mac工作區掛載到QEMU系統。這樣,無論我工作在主機環境中,或是Ubuntu中,還是在QEMU中,我都在用相同的工作區。
[email protected]:~ (130) $ ssh [email protected]
[email protected]'s password:
Linux debian-mipsel 2.6.32-5-4kc-malta #1 Wed Jan 12 06:13:27 UTC 2011 mips
[email protected]:~# mount
/dev/sda1 on / type ext3 (rw,errors=remount-ro)
malastare:/Users/share/code on /root/code type nfs (rw,addr=192.168.127.1)
[email protected]:~#cd code
[email protected]:~/code#
一旦登陸到模擬系統,cd到從設備的固件中提取的文件系統中。你應該能夠chroot到固件的根文件系統。需要使用chroot,因為目標二進制是和固件的庫鏈接的,很可能不能跟Debian的共享庫一起工作。
[email protected]:~#cd code/wifi-reversing/netgear/r6200/extracted-1.0.0.28/rootfs/
[email protected]:[email protected]e ./bin/ls
./bin/ls: symbolic link to `busybox'
[email protected]:[email protected]e ./bin/busybox
./bin/busybox: ELF 32-bit LSB executable, MIPS, MIPS32 version 1 (SYSV), dynamically linked (uses shared libs), stripped
[email protected]:[email protected]oot . /bin/ls -l /bin/busybox
-rwxr-xr-x 1 10001 80 276413 Sep 20 2012 /bin/busybox
[email protected]:~/code/wifi-reversing/netgear/r6200/extracted-1.0.0.28/rootfs#
在上面的例子中,我已切換到所提取的文件系統的根目錄中。然后使用file命令,我了解到busybox是little endian MIPS可執行文件。然后,chroot到提取根目錄,并運行bin/ls,它是busybox的符號鏈接。
如果試圖簡單的通過“chroot .”來地啟動一個shell,將無法正常工作。因為你的默認shell是bash,而大多數嵌入式設備沒有bash。
[email protected]:[email protected]oot . chroot: failed to run command `/bin/bash': No such file or directory [email protected]:~/code/wifi-reversing/netgear/r6200/extracted-1.0.0.28/rootfs#
相反,你可以chroot并執行bin / sh:
[email protected]:[email protected]oot . /bin/sh
BusyBox v1.7.2 (2012-09-20 10:26:08 CST) built-in shell (ash)
Enter 'help' for a list of built-in commands.
#
#
#exit
[email protected]:~/code/wifi-reversing/netgear/r6200/extracted-1.0.0.28/rootfs#
即使有了必要的工具,建立了仿真環境且工作正常,你仍然可能遇到障礙。雖然QEMU在模擬核心芯片組包括CPU上都做的很不錯,但是QEMU往往不能提供你想運行的二進制程序需要的硬件。如果你試圖模仿一些簡單的像/bin/ls的程序,通常能夠正常工作。但更復雜的東西,如肯定有特定的硬件依賴的UPnP守護程序,QEMU就不能夠滿足。尤其對于管理嵌入式系統硬件的程序更是這樣,例如打開或關閉無線適配器。
你將遇到的最常見問題是在運行系統服務,如Web服務器或UPnP守護進程時,缺乏NVRAM。非易失性RAM通常是包含配置參數的設備快速存儲器的一個分區。當一個守護進程啟動時,它通常會嘗試查詢NVRAM,獲取其運行時配置信息。有時一個守護進程會查詢NVRAM的幾十甚至上百個參數。
為了解決在模擬條件下缺乏NVRAM的問題,我寫了一個叫nvram-faker的庫。當你運行二進制程序時,應該使用LD_PRELOAD對nvram-faker庫進行預加載。它會攔截通常由libnvram.so提供的nvram_get()調用。nvram-faker會查詢你提供的一個INI風格的配置文件,而不是試圖查詢NVRAM。
附帶的README提供更完整的說明。這里有一個鏈接:https://github.com/zcutlip/nvram-faker
即使解決了NVRAM問題,該程序可能會假設某些硬件是存在的。如果硬件不存在,該程序可能無法運行,或者即便它運行了,行為可能也與在其目標硬件上運行時有所不同。在這種情況下,你可能需要修補二進制文件。采用二進制補丁的情況各不相同。這取決于期望什么硬件,以及它不存在時的行為是什么。如果硬件缺失,你可能需要修補一個被執行到的條件分支。也可能需要修補針對特殊設備的ioctl()調用,如果你想將其替代為針對常規文件的讀取和寫入時。這里我將不談論修補的細節,但在我的BT HomeHub文章以及44CON的相應講座中進行了討論。
這里是這些資源的鏈接:http://shadow-file.blogspot.com/2013/09/44con-resources.html
一旦在QEMU中運行了二進制程序,就可以附加調試器了。當然你需要gdbserver。同樣,這個工具應該適合目標架構并被靜態編譯,因為你會在chroot下運行它。你需要將它復制到提取的文件系統的根目錄中。
# ./gdbserver
Usage: gdbserver [OPTIONS] COMM PROG [ARGS ...]
gdbserver [OPTIONS] --attach COMM PID
gdbserver [OPTIONS] --multi COMM
COMM may either be a tty device (for serial debugging), or
HOST:PORT to listen for a TCP connection.
Options:
--debug Enable general debugging output.
--remote-debug Enable remote protocol debugging output.
--version Display version information and exit.
--wrapperWRAPPER -- Run WRAPPER to start new programs.
--once Exit after the first connection has closed.
#
你可以將gdbserver附加到正在運行的進程,或者用它來直接執行二進制程序。如果你需要調試只發生一次的初始化程序,你可以選擇后者。
另一方面,你可能要等到守護進程被創建。據我所知沒有辦法讓IDA跟蹤創建的進程(forked processes)。你需要單獨的附加到它們。如果采用這種方式,你可以在chroot外,附加到已經運行的進程。
以下shell腳本將在chroot下執行upnpd。如果DEBUG設置為1,它會附加在upnpd上,并在1234端口上暫停等待遠程調試會話。
#!bash
ROOTFS="/root/code/wifi-reversing/netgear/r6200/extracted-1.0.0.28/rootfs"
chroot$ROOTFS /bin/sh -c "LD_PRELOAD=/libnvram-faker.so /usr/sbin/upnpd"
#Give upnpd a bit to initialize and fork into the background.
sleep 3;
if [ "x1" = "x$DEBUG" ];
then
$ROOTFS/gdbserver --attach 0.0.0.0:1234 $(pgrepupnpd)
fi
你可以在recvfrom()調用之前創建一個斷點,然后當你向upnpd發送M-SEARCH包時,驗證調試器斷點。
然后,在IDA的Debugger菜單中的Process選項中設置“主機名”為你的QEMU系統的IP地址,并設置端口為gdbserver正在監聽的端口。我用的是1234。
接受設置,然后通過IDA的CTRL+8熱鍵連接到遠程調試會話。再次按Ctrl+8繼續執行。你應該能夠發送一個M-SEARCH包1,可以看到調試器命中斷點。
顯然還有很多需要探索,也會遇到有很多這里未提及的情況,但希望這可以讓你開始。
我推薦Craig Heffner用于UPnP分析的miranda工具:https://code.google.com/p/miranda-upnp/