用Bochs調試NTLDR

對一臺安裝了Windows NT 系列操作系統的PC來說,按下電源開關之後,CPU中首先開始運行的是Bios,然後是MBR,接着是引導扇,然後就是NTLDR。ntoskrnl.exe和 hal.dll 都是由NTLDR來加載的。也就是說,運行NTLDR的時候,系統中還沒有任何應用程序或者驅動,當然也就沒有任何基於軟件的調試器可用。當然,無所不能的硬件調試器肯定是可以的,可惜我們沒有硬件調試器。 幸好有了Bochs。Bochs是一個基於LGPL的開源x86 虛擬機軟件。Bochs的CPU指令是完全自己模擬出來的,這種方式的缺點是速度比較慢;優點是具有無以倫比的可移植性:有Gcc的地方就可以有Bochs。甚至已經有了跑在PocketPC上的Bochs。 現在的Bochs 已經實現了一定程度的調試功能,雖然在易用性和功能上還無法和 WinDbg、SoftICE相比,但優勢也是很明顯的:對跑在Bochs裏面的代碼來說,這就是 “硬件調試器”。 對Windows 版本的Bochs來說,安裝目錄下的bochsdbg.exe就是Bochs的調試版本。用它來運行Bochs虛擬機就可以進行“硬件調試”。 Bochs的調試命令風格是按照GDB習慣來設計的,這對於用慣了WinDbg的人來說無疑是痛苦的,好在這是個開源軟件,看着不順眼可以考慮自己改改。 目前版本的Bochs(Version 2.1.1)支持的調試命令如下: [注意] 1、Bochs的文檔和幫助信息中的使用說明與真實情況之間存在很大的差錯和缺失, 下面的命令說明根據源碼作了很多補充和修正。 2、其中涉及到的seg(段)、off(偏移)、addr(地址)、val(值)等數字, 可以使用十六進制、十進制或者八進制,但必須按照如下形式書寫: 十六進制 0xCDEF0123 八進制 01234567 十進制 123456789 尤其要注意,Bochs不能自動識別16進制的數字,也不接受12345678h這種寫法。 [執行控制] c|cont 向下執行,相當於WinDBG的“g”。 s|step|stepi [count] 單步執行,相當於WinDBG的“t”,count 默認爲 1。 p|n|next 單步執行,類似於WinDBG的“p”。 q|quit|exit 退出調試,同時關閉虛擬機。 Ctrl-C 結束執行狀態,返回調試器提示符。 Ctrl-D if at empty line on command line, exit (至少在Windows版本中我沒有發現Ctrl-D有什麼功能) [執行斷點] vb|vbreak [seg:off] 在虛擬地址上下斷點。 lb|lbreak [addr] 在線性地址上下斷點,相當於WinDBG的“bp”。 pb|pbreak|b|break [addr] 在物理地址上下斷點。(爲了兼容GDB的語法,地址前 可以加上一個“*”)。 blist 顯示斷點狀態,相當於WinDBG的“bl”。 bpd|bpe [num] 禁用/啓用斷點,WinDBG的“be”和“bd”。num是斷 點號,可以用blist命令查詢。 d|del|delete [num] 刪除斷點,相當於WinDBG的“bc”。mum是斷點號,可 以用blist命令查詢。 [讀寫斷點] watch read [addr] 設置讀斷點。 watch write [addr] 設置寫斷點。 unwatch read [addr] 清除讀斷點。 unwatch write [addr] 清除寫斷點。 watch 顯示當前所有讀寫斷點。 unwatch 清除當前所有讀寫斷點。 watch stop|continue 開關選項,設置遇到讀寫斷點時中斷下來還是顯示出來但 是繼續運行。 [內存操作] x /nuf [addr] 顯示線性地址的內容 xp /nuf [addr] 顯示物理地址的內容 n 顯示的單元數 u 每個顯示單元的大小,u可以是下列之一: b BYTE h WORD w DWORD g DWORD64 注意: 這種命名法是按照GDB習慣的,而並不是按照inter的規範。 f 顯示格式,f可以是下列之一: x 按照十六進制顯示 d 十進制顯示 u 按照無符號十進制顯示 o 按照八進制顯示 t 按照二進制顯示 c 按照字符顯示 n、f、u是可選參數,如果不指定,則u默認是w,f默認是x。如果前面使用過x或 者xp命令,會按照上一次的x或者xp命令所使用的值。n默認爲1。addr 也是一個 可選參數,如果不指定,addr是0,如過前面使用過x或者xp命令,指定了n=i, 則再次執行時n默認爲i+1。 setpmem [addr] [size] [val] 設置物理內存某地址的內容。 需要注意的是,每次最多隻能設置一個DWORD:這樣是可以的: setpmem 0x00000000 0x4 0x11223344 x /4 0x00000000 [bochs]: 0x00000000 : 0x11223344 0x00000000 0x00000000 0x00000000 這樣也可以: setpmem 0x00000000 0x2 0x11223344 x /4 0x00000000 [bochs]: 0x00000000 : 0x00003344 0x00000000 0x00000000 0x00000000 或者: setpmem 0x00000000 0x1 0x20 x /4 0x00000000 [bochs]: 0x00000000 : 0x00000020 0x00000000 0x00000000 0x00000000 下面的做法都會導致出錯: setpmem 0x00000000 0x3 0x112233 Error: setpmem: bad length value = 3 setpmem 0x00000000 0x8 0x11223344 Error: setpmem: bad length value = 8 crc [start] [end] 顯示物理地址start到end之間數據的CRC。 [寄存器操作] set $reg = val 設置寄存器的值。現在版本可以設置的寄存器包括: eax ecx edx ebx esp ebp esi edi 暫時不能設置: eflags cs ss ds es fs gs r|reg|registers reg = val 同上。 dump_cpu 顯示完整的CPU信息。 set_cpu 設置CPU狀態,這裏可以設置dump_cpu所能顯示出來的 所有CPU狀態。 [反彙編命令] u|disas|disassemble [/num] [start] [end] 反彙編物理地址start到end 之間的代碼,如 果不指定參數則反彙編當前EIP指向的代碼。 num是可選參數,指定處理的代碼量。 set $disassemble_size = 0|16|32 $disassemble_size變量指定反彙編使用的段 大小。 set $auto_disassemble = 0|1 $auto_disassemble決定每次執行中斷下來的 時候(例如遇到斷點、Ctrl-C等)是否反匯 編當前指令。 [其他命令] trace-on|trace-off Tracing開關打開後,每執行一條指令都會將反彙編的結果 顯示出來。 ptime 顯示Bochs自本次運行以來執行的指令條數。 sb [val] 再執行val條指令就中斷。val是64-bit整數,以L結尾,形 如“1000L” sba [val] 執行到Bochs自本次運行以來的第val條指令就中斷。val是 64-bit整數,以L結尾,形如“1000L” modebp 設置切換到v86模式時中斷。 record ["filename"] 將輸入的調試指令記錄到文件中。文件名必須包含引號。 playback ["filename"] 回放record的記錄文件。文件名必須包含引號。 print-stack [num] 顯示堆棧,num默認爲16,表示打印的條數。 ?|calc 和WinDBG的“?”命令類似,計算表達式的值。 load-symbols [global] filename [offset] 載入符號文件。如果設定了“global”關鍵字,則符號針 對所有上下文都有效。offset會默認加到所有的symbol地 址上。symbol文件的格式爲:"%x %s"。 [info命令] info program 顯示程序執行的情況。 info registers|reg|r 顯示寄存器的信息。 info pb|pbreak|b|break 相當於blist info dirty 顯示髒頁的頁地址。 info cpu 顯示所有CPU寄存器的值。 info fpu 顯示所有FPU寄存器的值。 info idt 顯示IDT。 info gdt [num] 顯示GDT。 info ldt 顯示LDT。 info tss 顯示TSS。 info pic 顯示PIC。 info ivt [num] [num] 顯示IVT。 info flags 顯示狀態寄存器。 info cr 顯示CR系列寄存器。 info symbols 顯示symbol信息。 info ne2k|ne2000 顯示虛擬的ne2k網卡信息。 弄明白了調試命令,接下來就可以着手進行NTLDR的調試工作了。下面所進行的工作都是在Windows版Bochs 2.1.1上實現的。我們假設讀者瞭解Bochs的基本使用方法和術語。 首先要安裝一個Windows NT 4的Bochs虛擬機。 1、創建虛擬硬盤。 運行bximage.exe,創建一個500M、flat模式的虛擬硬盤文件“C.img”。 2、創建一個Windows NT安裝光盤的ISO文件“nt.iso” 如果你打算直接用光盤安裝,也可以省去這一步。 3、創建bochsrc.txt 內容可參考下面: ############################################################### megs: 32 romimage: file=$BXSHARE/BIOS-bochs-latest, address=0xf0000 vgaromimage: $BXSHARE/VGABIOS-lgpl-latest ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 ata0-master: type=disk, path="C.img", mode=flat, cylinders=1015, heads=16, spt=63 ata0-slave: type=cdrom, path="nt.iso", status=inserted newharddrivesupport: enabled=1 boot: cdrom log: nul mouse: enabled=1 clock: sync=realtime, time0=local ############################################################### 4、創建start.bat 內容如下: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::假設你的Bochs安裝在D:/Program/Bochs set BXSHARE=D:/Program/Bochs %BXSHARE%/bochs.exe -q -f bochsrc.txt ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 把C.img、nt.iso、bochsrc.txt、start.bat放到同一個目錄下,運行start.bat,進行Windows NT的安裝。 事實上,如果只是爲了調試MBR、引導扇和NTLDR 的話,並沒有必要安裝完整的操作系統,只要根目錄下有ntldr等那幾個文件就可以了。這裏之所以安裝Windows NT而不是Windows 2000或者更高版本,一方面是考慮速度問題,另一方面,Windows NT 是可以在Bochs上確保順利完成安裝的。如果要調試Windows 2000/XP/2003 的NTLDR,只需用這些操作系統的ntldr文件替換Windows NT的即可。 安裝完Windows NT之後,可以進行NTLDR的調試了。把start.bat中的“bochs.exe” 換成“bochsdbg.exe”。然後運行start.bat。 下面是操作的屏幕拷貝: ======================================================================== Bochs x86 Emulator 2.1.1 February 08, 2004 ======================================================================== 00000000000i[ ] reading configuration from bochsrc.txt 00000000000i[ ] installing win32 module as the Bochs GUI 00000000000i[ ] Warning: no rc file specified. 00000000000i[ ] using log file nul Next at t=0 //啓動bochsdbg.exe,會自動停在Bios的第一條指令上。 (0) context not implemented because BX_HAVE_HASH_MAP=0 [0x000ffff0] f000:fff0 (unk. ctxt): jmp f000:e05b ; ea5be000f0 b 0x00007c00 //MBR和引導扇都會加載在0000:7c00。 c (0) Breakpoint 1, 0x7c00 in ?? () //第一次會在MBR上中斷下來。 Next at t=772567 (0) [0x00007c00] 0000:7c00 (unk. ctxt): cli ; fa c (0) Breakpoint 1, 0x7c00 in ?? () //第二次會在引導扇上中斷。 Next at t=773872 (0) [0x00007c00] 0000:7c00 (unk. ctxt): jmp 0x7c5d ; eb5b b 0x00020000 //ntldr會加載在2000:0000,事實上無論是CDFS、NTFS還是FAT, //Windows加載啓動文件都是這個地址。 c (0) Breakpoint 2, 0x20000 in ?? () //在NTLDR的第一條指令上斷下來了,可以開始進行調試。 Next at t=861712 (0) [0x00020000] 2000:0000 (unk. ctxt): jmp 0x1f6 ; e9f301 現在,我們可以像上帝俯看芸芸衆生一樣,看着操作系統一步一步啓動起來,一切盡在眼底,甚至可以看到系統啓動過程中實模式切換到保護模式的情景: (0).[28734582] [0x00020247] 2000:0247 (unk. ctxt): opsize or eax, 0x1 ; 6683c801 (0).[28734583] [0x0002024b] 2000:024b (unk. ctxt): mov cr0, eax ; 0f22c0 (0).[28734584] [0x0002024e] 2000:0000024e (unk. ctxt): xchg bx, bx ; 87db (0).[28734585] [0x00020250] 2000:00000250 (unk. ctxt): jmp 0x253 ; eb01 (0).[28734586] [0x00020253] 2000:00000253 (unk. ctxt): push 0x58 ; 6a58 (0).[28734587] [0x00020255] 2000:00000255 (unk. ctxt): push 0x259 ; 685902 (0).[28734588] [0x00020258] 2000:00000258 (unk. ctxt): retf ; cb

發佈了1 篇原創文章 · 獲贊 2 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章