基于QEMU的NVRAM仿真
本文翻譯自 http://www.devttys0.com/2012/03/emulating-nvram-in-qemu/
能夠在Qemu中模擬嵌入式應用程序非常有用,但并非沒有陷阱。我遇到的最常見的問題可能是的二進制程序試圖從NVRAM中讀取配置數據。由于二進制文件在Qemu中運行,而不是在目標設備上運行,因此顯然沒有要讀取的NVRAM。
嵌入式應用程序通常通過共享庫與NVRAM交互。該庫又與包含設備當前配置設置的MTD分區接口交互。如果沒有NVRAM配置數據,許多程序將無法正常運行,需要我們攔截NVRAM庫調用并返回有效數據,以便在Qemu中正確執行應用程序。
這是從固件更新映像中提取的Web服務器,該二進制程序拒絕在Qemu下啟動:
看起來httpd無法啟動,因為它不知道要綁定到哪個IP地址。IP無法通過命令行參數設置,因此必須從其他位置獲取此數據。讓我們啟動IDA并開始破解吧!
快速瀏覽httpd的主要功能可以發現罪魁禍首。httpd服務器嘗試通過調用nvram_get來獲取IP地址和協議設置。如果這些調用失敗,則會打印出我們在上面看到的錯誤消息:
nvram_get函數是從共享庫中導入的,使用LD_PRELOAD可以很容易地進行攔截:
但是,在我們開始攔截函數調用之前,我們需要了解有關nvram_get的更多信息。它似乎只接受一個參數,該參數是一個字符串(特別是上面的“lan_ipaddr”和“lan_proto”),但是它返回什么類型的數據?
從前面的反匯編中可以看出,nvram_get(“ lan_proto”)的返回值保存在寄存器R5中。后來,使用strcmp將R5指向的數據與字符串“ static”和“ dhcp”進行比較:
同樣,nvram(“ lan_ipaddr”)的返回值保存在寄存器R6中,該值稍后作為第一個參數傳遞給inet_aton:
因此,nvram_get的參數是鍵值對中的鍵字符串并返回相應的值字符串。我們可以使用以下代碼輕松模擬此功能以及一些虛擬配置數據:
我們需要將此代碼作為共享庫進行交叉編譯,并將其復制到squashfs-root目錄中,這個目錄是我們運行qemu的目錄:
eve@eve:~$ arm-linux-gcc -shared nvram.c -o nvram.so eve@eve:~$ cp nvram.so squashfs-root/nvram.so現在,我們將嘗試再次在Qemu中運行httpd,這一次在LD_PRELOAD環境變量中指定nvram.so文件的路徑:
eve@eve:~/squashfs-root$ sudo chroot . ./qemu-arm -E LD_PRELOAD="/nvram.so" usr/sbin/httpd usr/sbin/httpd: relocation error: /nvram.so: symbol __register_frame_info, version GLIBC_2.0 not defined in file libgcc_s.so.1 with link time reference看起來nvram.so文件期望引用__register_frame_info函數,該函數符號在目標系統的libgcc_s.so庫中不存在。發生這種情況是因為我們用來構建nvram.so的工具鏈與供應商用來為目標系統構建固件的工具鏈不同。我們希望__register_frame_info存在,而他們卻沒有。
由于供應商未為其系統發布GPL代碼,因此我們不能簡單地使用其工具鏈來重新構建nvram.so。我們可以向公司發起GPL請求,但是有一種更簡單(更快!)的方法。我們只需要在nvram.c中為__register_frame_info符號添加占位符定義(函數聲明):
#include <stdio.h> #include <string.h>void __register_frame_info(void) { } void __deregister_frame_info(void) { } void __unregister_frame_info(void) { }char *nvram_get(char *key) {char *value = NULL;if(strcmp(key, "lan_ipaddr") == 0){value = strdup("127.0.0.1");}if(strcmp(key, "lan_proto") == 0){value = strdup("static");}printf("nvram_get(%s) == %s\n", key, value);return value; }然后重新構建nvram.so,再次嘗試運行httpd
eve@eve:~/squashfs-root$ sudo chroot . ./qemu-arm -E LD_PRELOAD="/nvram.so" usr/sbin/httpd httpd server started at port 80 (delay 0 second) nvram_get(lan_ipaddr) == 127.0.0.1 nvram_get(lan_proto) == static我們已成功攔截nvram_get調用,httpd錯誤消息已消失,服務器似乎正在運行。讓我們測試一哈:
成功!httpd現在可以與IDA的調試器進行一對一的交互了。
總結
以上是生活随笔為你收集整理的基于QEMU的NVRAM仿真的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU 1247(Hat’s Words
- 下一篇: 《快速构建Windows 8风格应用》系