codefans

          導航

          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          統計

          常用鏈接

          留言簿(2)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          程序設計鏈接

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          用Bochs調試NTLDR

          創建時間:2004-08-05
          文章屬性:原創
          文章提交:tombkeeper (t0mbkeeper_at_hotmail.com)

          用Bochs調試NTLDR

          作  者:于旸
          郵  件:tombkeeper[0x40]nsfocus[0x2e]com
                  tombkeeper[0x40]xfocus[0x2e]org
          完成于:2004.7.9
          關鍵字:bochs, bochsdbg, 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:
          這樣是可以的:
          <bochs:1>  setpmem 0x00000000 0x4 0x11223344
          <bochs:2> x /4 0x00000000
          [bochs]:
          0x00000000 <bogus+       0>:    0x11223344 0x00000000 0x00000000 0x00000000
          這樣也可以:
          <bochs:1>  setpmem 0x00000000 0x2 0x11223344
          <bochs:2> x /4 0x00000000
          [bochs]:
          0x00000000 <bogus+       0>:    0x00003344 0x00000000 0x00000000 0x00000000
          或者:
          <bochs:1>  setpmem 0x00000000 0x1 0x20
          <bochs:2> x /4 0x00000000
          [bochs]:
          0x00000000 <bogus+       0>:    0x00000020 0x00000000 0x00000000 0x00000000
          下面的做法都會導致出錯:
          <bochs:1>  setpmem 0x00000000 0x3 0x112233
          Error: setpmem: bad length value = 3
          <bochs:2>  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
          <bochs:1> b 0x00007c00    //MBR和引導扇都會加載在0000:7c00。
          <bochs:2> c
          (0) Breakpoint 1, 0x7c00 in ?? () //第一次會在MBR上中斷下來。
          Next at t=772567
          (0) [0x00007c00] 0000:7c00 (unk. ctxt): cli                   ; fa
          <bochs:3> c
          (0) Breakpoint 1, 0x7c00 in ?? () //第二次會在引導扇上中斷。
          Next at t=773872
          (0) [0x00007c00] 0000:7c00 (unk. ctxt): jmp 0x7c5d            ; eb5b
          <bochs:4>b 0x00020000  //ntldr會加載在2000:0000,事實上無論是CDFS、NTFS還是FAT,
                                 //Windows加載啟動文件都是這個地址。
          <bochs:5> 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



          參考文獻:
          Bochs的文檔和源碼。

          posted on 2005-10-05 13:13 春雷的博客 閱讀(200) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 即墨市| 彭泽县| 天峻县| 日照市| 沙田区| 丹江口市| 桐城市| 中西区| 嘉善县| 泾阳县| 定襄县| 金乡县| 噶尔县| 涞水县| 洛宁县| 池州市| 上林县| 兴文县| 全州县| 南丹县| 郓城县| 崇明县| 库伦旗| 巍山| 玛多县| 丹棱县| 商城县| 孝昌县| 琼中| 道孚县| 浮山县| 衡阳市| 克东县| 固安县| 庆城县| 乐安县| 隆安县| 青神县| 乃东县| 永安市| 仙游县|