codefans

          導(dǎo)航

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

          統(tǒng)計

          常用鏈接

          留言簿(2)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          程序設(shè)計鏈接

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          用Bochs調(diào)試NTLDR

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

          用Bochs調(diào)試NTLDR

          作  者:于旸
          郵  件:tombkeeper[0x40]nsfocus[0x2e]com
                  tombkeeper[0x40]xfocus[0x2e]org
          完成于:2004.7.9
          關(guān)鍵字:bochs, bochsdbg, ntldr, 調(diào)試



              對一臺安裝了Windows NT 系列操作系統(tǒng)的PC來說,按下電源開關(guān)之后,CPU中首
          先開始運行的是Bios,然后是MBR,接著是引導(dǎo)扇,然后就是NTLDR。ntoskrnl.exe和
          hal.dll 都是由NTLDR來加載的。也就是說,運行NTLDR的時候,系統(tǒng)中還沒有任何應(yīng)
          用程序或者驅(qū)動,當(dāng)然也就沒有任何基于軟件的調(diào)試器可用。當(dāng)然,無所不能的硬件
          調(diào)試器肯定是可以的,可惜我們沒有硬件調(diào)試器。

              幸好有了Bochs。Bochs是一個基于LGPL的開源x86 虛擬機(jī)軟件。Bochs的CPU指令
          是完全自己模擬出來的,這種方式的缺點是速度比較慢;優(yōu)點是具有無以倫比的可移
          植性:有Gcc的地方就可以有Bochs。甚至已經(jīng)有了跑在PocketPC上的Bochs。

              現(xiàn)在的Bochs 已經(jīng)實現(xiàn)了一定程度的調(diào)試功能,雖然在易用性和功能上還無法和
          WinDbg、SoftICE相比,但優(yōu)勢也是很明顯的:對跑在Bochs里面的代碼來說,這就是
          “硬件調(diào)試器”。

              對Windows 版本的Bochs來說,安裝目錄下的bochsdbg.exe就是Bochs的調(diào)試版本。
          用它來運行Bochs虛擬機(jī)就可以進(jìn)行“硬件調(diào)試”。

              Bochs的調(diào)試命令風(fēng)格是按照GDB習(xí)慣來設(shè)計的,這對于用慣了WinDbg的人來說無
          疑是痛苦的,好在這是個開源軟件,看著不順眼可以考慮自己改改。

              目前版本的Bochs(Version 2.1.1)支持的調(diào)試命令如下:

          [注意]

          1、Bochs的文檔和幫助信息中的使用說明與真實情況之間存在很大的差錯和缺失,
             下面的命令說明根據(jù)源碼作了很多補充和修正。

          2、其中涉及到的seg(段)、off(偏移)、addr(地址)、val(值)等數(shù)字,
             可以使用十六進(jìn)制、十進(jìn)制或者八進(jìn)制,但必須按照如下形式書寫:

          十六進(jìn)制  0xCDEF0123
          八進(jìn)制    01234567
          十進(jìn)制    123456789
          尤其要注意,Bochs不能自動識別16進(jìn)制的數(shù)字,也不接受12345678h這種寫法。

          [執(zhí)行控制]

          c|cont                  向下執(zhí)行,相當(dāng)于WinDBG的“g”。

          s|step|stepi [count]    單步執(zhí)行,相當(dāng)于WinDBG的“t”,count 默認(rèn)為 1。

          p|n|next                單步執(zhí)行,類似于WinDBG的“p”。

          q|quit|exit             退出調(diào)試,同時關(guān)閉虛擬機(jī)。

          Ctrl-C                  結(jié)束執(zhí)行狀態(tài),返回調(diào)試器提示符。

          Ctrl-D                  if at empty line on command line, exit
                                  (至少在Windows版本中我沒有發(fā)現(xiàn)Ctrl-D有什么功能)

          [執(zhí)行斷點]

          vb|vbreak [seg:off]         在虛擬地址上下斷點。

          lb|lbreak [addr]            在線性地址上下斷點,相當(dāng)于WinDBG的“bp”。

          pb|pbreak|b|break [addr]    在物理地址上下斷點。(為了兼容GDB的語法,地址前
                                      可以加上一個“*”)。

          blist                       顯示斷點狀態(tài),相當(dāng)于WinDBG的“bl”。

          bpd|bpe [num]               禁用/啟用斷點,WinDBG的“be”和“bd”。num是斷
                                      點號,可以用blist命令查詢。

          d|del|delete [num]          刪除斷點,相當(dāng)于WinDBG的“bc”。mum是斷點號,可
                                      以用blist命令查詢。

          [讀寫斷點]

          watch read [addr]       設(shè)置讀斷點。
          watch write [addr]      設(shè)置寫斷點。
          unwatch read [addr]     清除讀斷點。
          unwatch write [addr]    清除寫斷點。
          watch                   顯示當(dāng)前所有讀寫斷點。
          unwatch                 清除當(dāng)前所有讀寫斷點。
          watch stop|continue     開關(guān)選項,設(shè)置遇到讀寫斷點時中斷下來還是顯示出來但
                                  是繼續(xù)運行。


          [內(nèi)存操作]

          x  /nuf [addr]  顯示線性地址的內(nèi)容
          xp /nuf [addr]  顯示物理地址的內(nèi)容
              n           顯示的單元數(shù)
              u           每個顯示單元的大小,u可以是下列之一:
                              b BYTE
                              h WORD
                              w DWORD
                              g DWORD64
                              注意: 這種命名法是按照GDB習(xí)慣的,而并不是按照inter的規(guī)范。

              f           顯示格式,f可以是下列之一:
                              x 按照十六進(jìn)制顯示
                              d 十進(jìn)制顯示
                              u 按照無符號十進(jìn)制顯示
                              o 按照八進(jìn)制顯示
                              t 按照二進(jìn)制顯示
                              c 按照字符顯示
              n、f、u是可選參數(shù),如果不指定,則u默認(rèn)是w,f默認(rèn)是x。如果前面使用過x或
              者xp命令,會按照上一次的x或者xp命令所使用的值。n默認(rèn)為1。addr 也是一個
              可選參數(shù),如果不指定,addr是0,如過前面使用過x或者xp命令,指定了n=i,
              則再次執(zhí)行時n默認(rèn)為i+1。

          setpmem [addr] [size] [val]    設(shè)置物理內(nèi)存某地址的內(nèi)容。

          需要注意的是,每次最多只能設(shè)置一個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
          下面的做法都會導(dǎo)致出錯:
          <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之間數(shù)據(jù)的CRC。


          [寄存器操作]

          set $reg = val              設(shè)置寄存器的值。現(xiàn)在版本可以設(shè)置的寄存器包括:
                                      eax ecx edx ebx esp ebp esi edi
                                      暫時不能設(shè)置:
                                      eflags  cs  ss  ds  es  fs  gs

          r|reg|registers reg = val   同上。

          dump_cpu                    顯示完整的CPU信息。

          set_cpu                     設(shè)置CPU狀態(tài),這里可以設(shè)置dump_cpu所能顯示出來的
                                      所有CPU狀態(tài)。

          [反匯編命令]

          u|disas|disassemble [/num] [start] [end]
                                              反匯編物理地址start到end 之間的代碼,如
                                              果不指定參數(shù)則反匯編當(dāng)前EIP指向的代碼。
                                              num是可選參數(shù),指定處理的代碼量。
          set $disassemble_size = 0|16|32     $disassemble_size變量指定反匯編使用的段
                                              大小。

          set $auto_disassemble = 0|1         $auto_disassemble決定每次執(zhí)行中斷下來的
                                              時候(例如遇到斷點、Ctrl-C等)是否反匯
                                              編當(dāng)前指令。

          [其他命令]
          trace-on|trace-off      Tracing開關(guān)打開后,每執(zhí)行一條指令都會將反匯編的結(jié)果
                                  顯示出來。

          ptime                   顯示Bochs自本次運行以來執(zhí)行的指令條數(shù)。

          sb [val]                再執(zhí)行val條指令就中斷。val是64-bit整數(shù),以L結(jié)尾,形
                                  如“1000L”

          sba [val]               執(zhí)行到Bochs自本次運行以來的第val條指令就中斷。val是
                                  64-bit整數(shù),以L結(jié)尾,形如“1000L”

          modebp                  設(shè)置切換到v86模式時中斷。

          record ["filename"]     將輸入的調(diào)試指令記錄到文件中。文件名必須包含引號。

          playback ["filename"]   回放record的記錄文件。文件名必須包含引號。

          print-stack [num]       顯示堆棧,num默認(rèn)為16,表示打印的條數(shù)。

          ?|calc                  和WinDBG的“?”命令類似,計算表達(dá)式的值。

          load-symbols [global] filename [offset]
                                  載入符號文件。如果設(shè)定了“global”關(guān)鍵字,則符號針
                                  對所有上下文都有效。offset會默認(rèn)加到所有的symbol地
                                  址上。symbol文件的格式為:"%x %s"。

          [info命令]

          info program            顯示程序執(zhí)行的情況。
          info registers|reg|r    顯示寄存器的信息。
          info pb|pbreak|b|break  相當(dāng)于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              顯示狀態(tài)寄存器。
          info cr                 顯示CR系列寄存器。
          info symbols            顯示symbol信息。
          info ne2k|ne2000        顯示虛擬的ne2k網(wǎng)卡信息。


              弄明白了調(diào)試命令,接下來就可以著手進(jìn)行NTLDR的調(diào)試工作了。下面所進(jìn)行的工
          作都是在Windows版Bochs 2.1.1上實現(xiàn)的。我們假設(shè)讀者了解Bochs的基本使用方法和
          術(shù)語。

              首先要安裝一個Windows NT 4的Bochs虛擬機(jī)。

          1、創(chuàng)建虛擬硬盤。
              運行bximage.exe,創(chuàng)建一個500M、flat模式的虛擬硬盤文件“C.img”。

          2、創(chuàng)建一個Windows NT安裝光盤的ISO文件“nt.iso”
              如果你打算直接用光盤安裝,也可以省去這一步。

          3、創(chuàng)建bochsrc.txt
              內(nèi)容可參考下面:
          ###############################################################
          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、創(chuàng)建start.bat
              內(nèi)容如下:
          :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
          ::假設(shè)你的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,
          進(jìn)行Windows NT的安裝。

              事實上,如果只是為了調(diào)試MBR、引導(dǎo)扇和NTLDR 的話,并沒有必要安裝完整的操
          作系統(tǒng),只要根目錄下有ntldr等那幾個文件就可以了。這里之所以安裝Windows NT而
          不是Windows 2000或者更高版本,一方面是考慮速度問題,另一方面,Windows NT 是
          可以在Bochs上確保順利完成安裝的。如果要調(diào)試Windows 2000/XP/2003 的NTLDR,只
          需用這些操作系統(tǒng)的ntldr文件替換Windows NT的即可。

              安裝完Windows NT之后,可以進(jìn)行NTLDR的調(diào)試了。把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和引導(dǎo)扇都會加載在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 ?? () //第二次會在引導(dǎo)扇上中斷。
          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的第一條指令上斷下來了,可以開始進(jìn)行調(diào)試。
          Next at t=861712
          (0) [0x00020000] 2000:0000 (unk. ctxt): jmp 0x1f6             ; e9f301


              現(xiàn)在,我們可以像上帝俯看蕓蕓眾生一樣,看著操作系統(tǒng)一步一步啟動起來,一
          切盡在眼底,甚至可以看到系統(tǒng)啟動過程中實模式切換到保護(hù)模式的情景:

          (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



          參考文獻(xiàn):
          Bochs的文檔和源碼。

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


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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 普定县| 佛坪县| 友谊县| 台东县| 孟村| 永兴县| 海淀区| 安乡县| 五河县| 通许县| 洪湖市| 赫章县| 梧州市| 绿春县| 嘉义县| 思南县| 陆川县| 秭归县| 兴化市| 乌兰察布市| 南川市| 南丰县| 衡水市| 岳池县| 福鼎市| 昌黎县| 年辖:市辖区| 天柱县| 松阳县| 华宁县| 定陶县| 织金县| 敦化市| 汉川市| 乌鲁木齐市| 高州市| 班戈县| 鲁甸县| 铜川市| 儋州市| 和静县|