welcom ! Handel home

2008年3月8日 星期六

[DOS TOOL] DEBUG 指令用法 dos 時代的工具


DEBUG是為組譯語言設計的一種高度工具,它通過單步、設定斷點等方式為組譯語言程序員提供了非常有效的偵錯手段。
一、DEBUG程序的使用
在DOS的提示號下,可按鍵輸入指令:
C:\DEBUG [D:][PATH][FILENAME[.EXT]][PARM1][PARM2]
其中,檔案名是被偵錯文件的名字。如用戶按鍵輸入文件,則DEBUG將指定的文件裝入儲存於器中,用戶可對其進行偵錯。如果未按鍵輸入檔案名,則用戶可以用當前儲存於器的內容工作,或者用DEBUG指令N和L把需要的文件裝入儲存於器後再進去行偵錯。指令中的D指定驅動器PATH為路徑,PARM1和PARM2則為執行被偵錯文件時所需要的指令參數。
在DEBUG程序調入後,將出現提示號,此時就可用DEBUG指令來偵錯程序。
二、DEBUG的主要指令
1、顯示儲存於單元的指令D(DUMP),格式為:
_D[address]或_D[range]
例如,按指定範圍顯示儲存於單元內容的方法為:
-d100 120
18E4:0100 c7 06 04 02 38 01 c7 06-06 02 00 02 c7 06 08 02 G...8.G.....G...
18E$:0110 02 02 bb 04 02 e8 02 00-CD 20 50 51 56 57 8B 37 ..;..h..M PQVW.
7
18E4:0120 8B
其中0100至0120是DEBUG顯示的單元內容,左邊用十六進製表示每個字元,右邊用ASCII字串表示每個字元,·表示不可顯示的字串。這裡沒有指定段位址,D指令自動顯示DS段的內容。如果只指定首位址,則顯示從首位址開始的80個字元的內容。如果完全沒有指定位址,則顯示上一個D指令顯示的最後一個單元後的內容。
2、修改儲存於單元內容的指令有兩種。
·輸入指令E(ENTER),有兩種格式如下:第一種格式可以用給定的內容表來替代指定範圍的儲存於單元內容。指令格式為:
-E address

例如,-E DS:100 F3'XYZ'8D
其中F3,'X','Y','Z'和各佔一個字元,該指令可以用這五個字元來替代儲存於單元DS:0100到0104的原先的內容。
第二種格式則是採用逐個單元相繼修改的方法。指令格式為:
-E address
例如,-E DS:100
則可能顯示為:
18E4:0100 89.-
如果需要把該單元的內容修改為78,則用戶可以直接按鍵輸入78,再按"空格"鍵可接著顯示下一個單元的內容,如下:
18E4:0100 89.78 1B.-
這樣,用戶可以不斷修改相繼單元的內容,直到用ENTER鍵結束該指令為止。
·填寫指令F(FILL),其格式為:
-F range list
例如:-F 4BA:0100 5 F3'XYZ'8D
使04BA:0100~0104單元包含指定的五個字元的內容。如果list中的字元數超過指定的範圍,則忽略超過的項;如果list的字元數小於指定的範圍,則重複使用list填入,直到填滿指定的所有單元為止。
3)檢查和修改暫存器內容的指令R(register),它有三種格式如下:
·顯示CPU內所有暫存器內容和標誌位狀態,其格式為:
-R
例如,-r
AX=0000 BX=0000 CX=010A DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=18E4 ES=18E4 SS=18E4 CS=18E4 IP=0100 NV UP DI PL NZ NA PO NC
18E4:0100 C70604023801 MOV WORD PTR [0204],0138 DS:0204=0000
·顯示和修改某個暫存器內容,其格式為:
-R register name
例如,按鍵輸入
-R AX
系統將回應如下:
AX F1F4

即AX暫存器的當前內容為F1F4,如不修改則按ENTER鍵,否則,可按鍵輸入欲修改的內容,如:

-R bx
BX 0369
:059F
則把BX暫存器的內容修改為059F。
·顯示和修改標誌位狀態,指令格式為:
-RF系統將回應,如:
OV DN EI NG ZR AC PE CY-
此時,如不修改其內容可按ENTER鍵,否則,可按鍵輸入欲修改的內容,如:
OV DN EI NG ZR AC PE CY-PONZDINV
即可,可見按鍵輸入的順序可以是任意的。
4)執行指令G,其格式為:
-G[=address1][address2[address3…]]
其中,位址1指定了執行的起始位址,如不指定則從現用的CS:IP開始執行。後面的位址均為斷點位址,當指令執行到斷點時,就停止執行並顯示當前所有暫存器及標誌位的內容,和下一條將要執行的指令。
5)跟蹤指令T(Trace),有兩種格式:
·逐條指令跟蹤
-T [=address]
從指定位址起執行一條指令後停下來,顯示所有暫存器內容及標誌位的值。如未指定位址則從現用的CS:IP開始執行。
·多條指令跟蹤
-T [=address][value]
從指定位址起執行n條指令後停下來,n由value指定。
6)組譯指令A(Assemble),其格式為:
-A[address]
該指令允許按鍵輸入組譯語言語句,並能把它們組譯成機器程式碼,相繼地存放在從指定位址開始的儲存於區中。必須注意:DEBUG把按鍵輸入的數位均看成十六進制數,所以如要按鍵輸入十進制數,則其後應加以說明,如100D。
7)反組譯指令U(Unassemble)有兩種格式。
·從指定位址開始,反組譯32個字元,其格式為:
-U[address]
例如:
-u100
18E4:0100 C70604023801 MOV WORD PTR[0204],0138
18E4:0106 C70606020002 MOV WORD PTR[0206],0200
18E4:010C C70606020202 MOV WORD PTR[0208],0202
18E4:0112 BBO4O2 MOV BX,0204
18E4:0115 E80200 CALL 011A
18E4:0118 CD20 INT 20
18E4:011A 50 PUSH AX
18E4:011B 51 PUSH CX
18E4:011C 56 PUSH SI
18E4:011D 57 PUSH DI
18E4:011E 8B37 MOV SI,[BX]

如果位址被省略,則從上一個U指令的最後一條指令的下一個單元開始顯示32個字元。
·對指定範圍內的儲存於單元進行反組譯,格式為:
-U[range]
例如:
-u100 10c
18E4:0100 C70604023801 MOV WORD PTR[0204],0138
18E4:0106 C70606020002 MOV WORD PTR[0206],0200
18E4:010C C70606020202 MOV WORD PTR[0208],0202

-u100 112
18E4:0100 C70604023801 MOV WORD PTR[0204],0138
18E4:0106 C70606020002 MOV WORD PTR[0206],0200
18E4:010C C70606020202 MOV WORD PTR[0208],0202

可見這兩種格式是等效的。
8)命名指令N(Name),其格式為:
-N filespecs [filespecs]
指令把兩個文件標幟符格式化在CS:5CH和CS:6CH的兩個文件控制塊中,以便在其後用L或W指令把文件裝入儲存碟。filespecs的格式可以是:
[d:][path] filename[.ext]
例如,
-N myprog
-L
-
可把文件myprog裝入儲存於器。


9)裝入指令(Load),有兩種功能。
·把磁牒上指定扇區範圍的內容裝入到儲存於器從指定位址開始的區域中。其格式為:
-L[address[drive sector sector]
·裝入指定文件,其格式為:
-L[address]
此指令裝入已在CS:5CH中格式化了文件控制塊所指定的文件。如未指定位址,則裝入CS:0100開始的儲存於區中。
10)寫指令W(Write),有兩種功能。
·把資料寫入磁牒的指定扇區。其格式為:
-W address drive sector sector
·把資料寫入指定的文件中。其格式為:
-W[address]
此指令把指定的儲存於區中的資料寫入由CS:5CH處的文件控制塊所指定的文件中。如未指定位址則資料從CS:0100開始。要寫入文件的字元數應先放入BX和CX中。
11)結束DEBUG指令Q(Quit),其格式為:
-Q
它結束DEBUG,返回DOS。本指令並無儲存碟功能,如需儲存碟應先使用W指令。

問題:初學者問一個低級問題,執行debug-a後,如果有一行輸入錯誤,如何更改這一行?

回答:
加入進行如下輸入:
D:\PWIN95\Desktop>debug
-a
2129:0100movax,200
2129:0103movbx,200
2129:0106movcx,200
2129:0109
此時,發現movbx,200一句錯誤,應為movbx,20,可以敲Enter鍵返回"-"狀態,然後輸入:
-a103
2129:0103movbx,20
如果多或者少若干行,不必重新輸入,可以用M指令移動後面的程序來去掉或者增加程序空間。

如何除錯和組譯你的第一個PC x86組譯語言程序呢?

以下這些簡單的解釋可以讓一個組譯語言新手使用DEBUG:

0)在使用時,如何快速獲得debug的使用說明 呢。
1)讓我們開始工作吧,例如:顯示BIOS的日期。
2)在你的電腦的COMMANG.COM文件裡搜尋"IBM"這幾個字串。
3) 一位十六進制數的運算。
4) 檢查 x86暫存器內容。
5) 我們來編寫我們的第一個用機械語言編寫的程序-列印一個字串。
6) 我們現在用組譯語言指令來做和例5一樣的事情。
7) 現在,我們不但要編寫一個組譯程序,而且我們還要把它儲存碟。
8) 現在,我們試一試檢視一個已經編好的程序。
9)你可以用DEBUG的計算功能計算程序的長度。
10)另一種顯示在螢幕上字串串的方法。
11)讓我們試一試反覆輸出。
12)我們現在把兩個程序連接起來。
13) 讓我們逐步執行這個剛剛修補的程序。
14)如果一開始的指令不是跳轉指令,那麼可能就要用這種方法了。

以下所有的指令都是可以執行在WIN9x的MS-DOS方式下的。
進入MS-DOS的方式有:
[開始][程序][MS-DOS方式]

[開始][執行][開啟]COMMAND[確定]

或者你可以雙按它:
C:\Windows\Command.com

0)在使用時,如何快速獲得debug的使用說明 呢
以下PROMPT>表示目錄提示號:一般為:C:\WINDOWS\COMMAND\
PROMPT> DEBUG /?<按Enter鍵press the enter key now>
怎樣?出現錯誤了吧。顯示如下
C:\WINDOWS>DEBUG/?
Runs Debug, a program testing and editing tool.

DEBUG [[drive:][path]filename [testfile-parameters]]

[drive:][path]filename Specifies the file you want to test.
testfile-parameters Specifies command-line information required by
the file you want to test.

After Debug starts, type ? to display a list of debugging commands.
因為錯了所以它給你顯示一些提示。留意到最後一句了嗎?


現在我們再來試一試:
PROMPT> DEBUG<按Enter鍵> (注意, DEBUG程序的指令是在一條橫線"-"後出現的。)
-?<在出現的橫線後面輸入?再Enter鍵> (下面的內容是按字母順序排列的)
(注意:Note: Don't type the dash or comments -- just the ?)
顯示如下,但是沒有中文的哦,中文是我加上去的。


組譯assemble A [address]
比較compare C range address
傾倒dump D [range]
進入enter E address

填充fill F range list
進行go G [=address] [addresses]
十六進制hex H value1 value2
輸入input I port
安裝載入load L [address] [drive] [firstsector] [number]
移動move M range address
命名name N [pathname] [arglist]
輸出output O port byte
進行proceed P [=address] [number]
離開quit Q
紀錄register R [register]
搜尋search S range list
描述trace T [=address] [value]
反組譯unassemble U [range]
寫write W [address] [drive] [firstsector] [number]
分配增強記憶體allocate expanded memory XA [#pages]
解壓縮增強記憶體deallocate expanded memory XD [handle]
map expanded memory pages XM [Lpage] [Ppage] [handle]
display expanded memory status XS
-q<按Enter鍵> (這是結束DEBUG回到DOS狀態)This quits out of debug, returning to the DOS prompt)

Tested examples below walk the user thru the following debug examples:
在下面的例子裡讀者必須明白以下幾條DEBUG指令。
-D 顯示一定範圍記憶體的內容Display the contents of an area of memory
-Q 結束DEBUG程序Quit the debug program
-S 搜尋Search for whatever
-H 十六進制的運算Hex arithmatic
-R 顯示或者改變一個或者多個暫存器的內容Display or change the contents of one or more registers
-E 輸入資料進入記憶體,在一個詳細的位址裡Enter data into memory, beginning at a specific location
-G 執行現在在記憶體裡的程序。Go run the executable program in memory
-U 反組譯,把我們不認識的機械程式碼變為我們可以認識組譯語言符號Unassemble machine code into symbolic code
-T 描述一條指令的用法。Trace the contents of one instruction
-P 進行或者執行一個相關的指令Proceed, or execute a set of related instructions
-A 編譯,把組譯指令變為機械程式碼Assemble symbolic instructions into machine code
-N 命名一個程序Name a program
-W 把一個已經命名的程序寫進磁牒Write the named program onto disk
-L 把程序安裝載入進記憶體Load the named program back into memory

返回目錄

1)讓我們開始工作吧,例如:顯示BIOS的日期
(以下PROMPT>表示目錄提示號:一般為:C:\WINDOWS\COMMAND\)

PROMPT> DEBUG<按Enter鍵>
-D FFFF:0006 L 8<按Enter鍵> (顯示 FFFFh, 偏移位址 6h, 長度 8 bytes)
在作者的電腦上這裡顯示為 "1/10/96."
譯者的電腦顯示" FFFF:0000 37 2F-30 36 2F 30 30 00 7/06/00."相信作者的電腦裡也是用這種格式顯示的。這裡顯示出來的是使用者BIOS的日期,有興趣的話可以重新開機看看,注意開機時的顯示。
-Q<按Enter鍵> (結束DEBUG)

思考:當只按DEBUG的時候,編輯的是什麼?為什麼可以找到BIOS的日期?(譯者這裡也不是很清楚所以請大家知道的也留言給斑竹,改正。譯者認為可能是記憶體的真實物理位址。)

返回目錄

2)在你的電腦的COMMANG.COM文件裡搜尋"IBM"這幾個字串
下面的"C:\Win95\"是根據每不電腦不同的。像譯者的電腦裡就是"C:\WINDOWS"

PROMPT> DEBUG C:\Win95\Command.com<按Enter鍵>
-S 0 L FFFF "IBM"<按Enter鍵>(從0開始搜尋"IBM",搜尋FFFFh多個單元格)
-Q<按Enter鍵> (結束DEBUG)

以下是譯者做的:

C:\WINDOWS>DEBUG C:\WINDOWS\COMMAND.COM
-S 0 L FFFF "IBM"
-S 0 L FFFF "COMMAND"
12A7:008D
12A7:04F7
12A7:3870
12A7:38BE
12A7:38DD
-S 0 L FFFF "PATH"
12A7:38AD
12A7:CCB7
12A7:CF55
-S 0 L FFFF "COMSPEC"
12A7:38D4
12A7:3A4D
12A7:CCC4
-Q

C:\WINDOWS>

(注意:搜尋是要區分大小寫的)
(你可以看到上面是沒有找到"IBM"的, 可以試一試"PATH" , "COMSPEC" , "COMMAND")
(注意: 這種方法用在尋找加密資料和已被移除的資料等方面時是十分有用的)

返回目錄

3) 一位十六進制數的運算:

PROMPT> DEBUG<按Enter鍵>
-H 9 1<按Enter鍵> (加減兩個十六進制的數, 9h+1h=Ah & 9h-1h=8h)
結果是顯示: 000A 0008
-Q<按Enter鍵> (結束DEBUG)

C:\WINDOWS>debug
-h 9 1
000A 0008
-q
C:\WINDOWS>

返回目錄

4) 檢查x86暫存器內容

PROMPT> DEBUG<按Enter鍵>
-R<按Enter鍵> (顯示x86暫存器內容)
-Q<按Enter鍵> (結束DEBUG)

C:\WINDOWS>debug
-R
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0100 NV UP EI PL NZ NA PO NC
127C:0100 043C ADD AL,3C
-Q

下面是對暫存器的簡單介紹:

資料儲存於器
在本類中,一般講的AH就是AX的前八位,AL就是AX的後八位,後面的以此類推。
AX Accumulator;作為累加器,所以它是算術運算的主要暫存器。另外所有的I/O指令都使用這一暫存器與外部設備傳送訊息。
BX Base register;可以作為通用暫存器使用,此外在計算儲存於器位址時,它經常用作基位址暫存器。
CX Counting register;可以作為通用暫存器使用,此外在循環(LOOP)和串處理指令中作隱含的計數器。
DX Data register;可以作為通用暫存器使用,一般在作雙字長運算時,把DX和AX組合在一起存放一個雙字長數,DX用來存放高位字。此外,對某些I/O操作,DX可用來存放I/O的連接阜位址。

游標及變址暫存器
BP Base pointers register ;機制游標暫存器
SI Source index register ;堆疊游標暫存器
DI Destiny index register ;目的變址暫存器
SP Battery pointer register ;堆疊游標暫存器

段暫存器
CS Code segment register ;程式碼段暫存器,存放正在執行的程序指令
DS Data segment register ;資料段暫存器,存放當前執行程序所用的資料
SS Battery segment register ;堆疊段暫存器,定義了堆疊所在區域
ES Extra segment register ;附加段暫存器,存放附加的資料,是一個輔助性的資料區,

控制暫存器
IP Next instruction pointer register;指令游標暫存器,它用來存放程式碼段中的偏移位址,在程序執行的程序中,它始終指向下一條指令的首位址,它與CS暫存器聯用確定下一條指令的物理位址
F Flag register;標誌暫存器 "NV UP EI PL NZ NA PO NC"就是了,也有人稱之為PSW Program Status Wold程序狀態暫存器

(這裡有一點必須講明白的現在在,其實從奔騰開始這些暫存器(除了所有段暫存器,標誌暫存器 )都是32位的。並且加多了兩個16位段暫存器FS,GS。dos下面看到這些暫存器是16位的。要看32位暫存器可以使用soft-ice。對於FS,GS的作用我也不是很清楚,希望有高手指點,謝謝。)

返回目錄

2004-5-26 09:45

IceMe
正式會員





積分 170
發帖 305
註冊 2004-3-15
來自 紫色星雲
狀態 離線 5)我們來編寫我們的第一個用機械語言編寫的程序-列印一個字串
(這裡用機械語言的主要原因是考慮到有一些用戶不懂組譯指令,現在就要讓他有一個認識電腦程序實質是一些數位)

PROMPT> DEBUG<按Enter鍵>
-E 100<按Enter鍵> (在偏移位址為100的地方輸入機械指令程序)
B4<按空格>02<按空格> (在AX暫存器的前八位存入02)
B2<按空格>41<按空格> (在DX暫存器的後八位存入41h,41h就是大寫A的ASCII碼,身邊有ASCII表的朋友可以對著表改改數位試一試)
CD<按空格>21<按空格> (當AH=02時這是DOS顯示輸出的中斷號)
CD<按空格>20<按Enter鍵> (結束DOS)
-G<按Enter鍵> (程序執行,並在螢幕上顯示出"A")
程序執行完以後你將看到"Program terminated normally"(程序正常結束了).
-U 100<按Enter鍵> (我們把它反組譯,就是把機械指令變為組譯語言指令)
107F:0100 B402 MOV AH,02
:0102 B2 MOV DL,41
:0104 CD21 INT 21
:0106 CD20 INT 20
(下面會有一堆無用的東西)
(對了,你的段位址可能與我的段位址CS=107F不同哦)
-R<按Enter鍵> (讓我們來看看暫存器的值; IP==100h, AX==0000h, DX==0000h)
好極了,我們看到電腦又做好了準備下一次執行程序了。
-T<按Enter鍵> (執行第一步操作... IP=>102h, AX=>0200h,指令游標暫存器指向下一條指令,AX的值被改變。
-T<按Enter鍵> (執行第二步操作... IP=>104h, , DX=>0041h,指令游標暫存器指向下一條指令,DX的值被改變。
-P<按Enter鍵> (繼續執行 INT 21,IP=>106h, AX=>02h,)
-P<按Enter鍵> (繼續執行INT 20)
-Q<按Enter鍵> (結束DEBUG)
(注意:你必須小心使用"T".因為如果你在程序完結以後繼續執行這條指令,因為我們無法預知下面的指令是什麼,所以我們也無法預知它可能帶來的後果)
C:\WINDOWS>DEBUG
-E 100
127C:0100 B4.B4 02.02 B2.B2 41.41 CD.CD 21.21 CD.CD 20.20
-G
A
Program terminated normally
-U 100
127C:0100 B402 MOV AH,02
127C:0102 B241 MOV DL,41
127C:0104 CD21 INT 21
127C:0106 CD20 INT 20
127C:0108 C706F1E30900 MOV WORD PTR [E3F1],0009
127C:010E EB59 JMP 0169
127C:0110 57 PUSH DI
127C:0111 BFF1E3 MOV DI,E3F1
127C:0114 8BDF MOV BX,DI
127C:0116 06 PUSH ES
127C:0117 0E PUSH CS
127C:0118 07 POP ES
127C:0119 32D2 XOR DL,DL
127C:011B EB34 JMP 0151
127C:011D 006B12 ADD [BP+DI+12],CH
-R
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0100 NV UP EI PL NZ NA PO NC
127C:0100 B402 MOV AH,02
-T

AX=0200 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0102 NV UP EI PL NZ NA PO NC
127C:0102 B241 MOV DL,41
-T

AX=0200 BX=0000 CX=0000 DX=0041 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0104 NV UP EI PL NZ NA PO NC
127C:0104 CD21 INT 21
-P
A
AX=0241 BX=0000 CX=0000 DX=0041 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0106 NV UP EI PL NZ NA PO NC
127C:0106 CD20 INT 20
-P

Program terminated normally
-Q

C:\WINDOWS>

返回目錄

6) 我們現在用組譯語言指令來做和例5一樣的事情

PROMPT> DEBUG<按Enter鍵>
-A 100<按Enter鍵> (在偏移位址為100的地方輸入組譯語言程序)
MOV AH,02<按Enter鍵> (選用DOS的02號功能使用,顯示輸出)
MOV DL,<按Enter鍵> (在DX暫存器的後八位存入41h,41h就是大寫A的ASCII碼,身邊有ASCII表的朋友可以對著表改改數位試一試)
INT 21<按Enter鍵> (當AH=02時這是DOS顯示輸出的中斷號,顯示"A")
INT 20<按Enter鍵> (結束DOS)
<按Enter鍵> (結束組譯語言編程狀態,回到DEBUG指令狀態)
-G =100<按Enter鍵> (執行程序,其實可以不要"=100"因為一般預設啟始位置是100)
-Q<按Enter鍵> (結束DEBUG)


C:\WINDOWS>DEBUG
-A 100
127C:0100 MOV AH,02
127C:0102 MOV DL,41
127C:0104 INT 21
127C:0106 INT 20
127C:0108
-G
A
Program terminated normally
-Q

返回目錄

7) 現在,我們不但要編寫一個組譯程序,而且我們還要把它儲存碟
(下面這個程序就要比原來的程序複雜一點了-顯示輸出:"ABC")

PROMPT> DEBUG<按Enter鍵>(執行DEBUG程序;系統預設啟始IP暫存器值為100h)
-A 100<按Enter鍵> (用組譯語言編寫一個程序,啟始位址是100h)
MOV AH,02<按Enter鍵> (選項DOS的02號功能使用, 顯示輸出)
MOV DL,<按Enter鍵> (在DX暫存器的後八位存入41h,41h就是大寫A的ASCII碼)
INT 21<按Enter鍵> (當AH=02時這是DOS顯示輸出的中斷號,顯示"A")
MOV DL,42<按Enter鍵> (在DX暫存器的後八位存入41h,41h就是大寫B的ASCII碼)
INT 21<按Enter鍵> (當AH=02時這是DOS顯示輸出的中斷號,顯示"B")
MOV DL,43<按Enter鍵> (在DX暫存器的後八位存入41h,41h就是大寫C的ASCII碼)
INT 21<按Enter鍵> (當AH=02時這是DOS顯示輸出的中斷號,顯示"C")
INT 20<按Enter鍵> (程序結束,結束DEBUG)
<按Enter鍵> (結束組譯指令輸入,回到DEBUG指令輸入)
-R BX<按Enter鍵> (檢視暫存器BX的值)
:0000<按Enter鍵> (設定BX為0000h,這是程序的結尾位址是BX:CX)
(注意,只要BX = 0000, 文件的大小就小於 <> (設定CX為Fh,這是程序的長度:16位)
:0010<按Enter鍵> (現在我們可以把這個16字元的程序寫入硬碟了)
-N printabc.com<按Enter鍵> (將要儲存碟的程序命名)
-W<按Enter鍵> (把這十六字元寫到文件裡面)
-Q<按Enter鍵> (結束DEBUG)
PROMPT> DIR printabc.com<按Enter鍵>
這裡將會報告這個文件的大小是16字元 (10h 字元).
PROMPT> printabc.com<按Enter鍵>
會馬上在螢幕上列印出"ABC"

C:\WINDOWS>DEBUG
-A 100
127C:0100 MOV AH,02
127C:0102 MOV DL,41
127C:0104 INT 21
127C:0106 MOV DL,42
127C:0108 INT 21
127C:010A MOV DL,43
127C:010C INT 21
127C:010E INT 20
127C:0110
-R
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0100 NV UP EI PL NZ NA PO NC
127C:0100 B402 MOV AH,02
-R BX
BX 0000
:
-R CX
CX 0000
:0010
-N PRINTABC.COM
-W
Writing 00010 bytes
-Q
C:\WINDOWS>DIR PRINTABC.COM
Volume in drive C has no label
Volume Serial Number is 28FB-70BA
Directory of C:\WINDOWS
PRINTABC COM 16 03-21-01 11:02 PRINTABC.COM
1 file(s) 16 bytes
0 dir(s) 557,711,360 bytes free
C:\WINDOWS>PRINTABC
ABC
C:\WINDOWS>

這裡可以有人告訴我,為什麼要存入是BX:CX代表程序長度嗎?(寫信給譯者,謝謝)

返回目錄

8) 現在,我們試一試檢視一個已經編好的程序:

PROMPT> DEBUG<按Enter鍵>(執行DEBUG程序在CS:IP = CS:0100h)
-N printabc.com<按Enter鍵> (告訴電腦你想安裝載入的程式名稱)
-L<按Enter鍵> (安裝載入那個名字的程序進入記憶體)
-U 100 L 10<按Enter鍵> (從偏移位址100開始反組譯16位字元)
-R<按Enter鍵> (現在看看暫存器裡面的內容)
注意:DEBUG本身是沒有自動紀錄文件大小的。
-G (執行被命名的程序,列印"ABC")
你將看到"ABC",然後是"Program terminated normally")

C:\WINDOWS>DEBUG
-N PRINTABC.COM
-L
-U 100 L 10
12A4:0100 B402 MOV AH,02
12A4:0102 B241 MOV DL,41
12A4:0104 CD21 INT 21
12A4:0106 B242 MOV DL,42
12A4:0108 CD21 INT 21
12A4:010A B243 MOV DL,43
12A4:010C CD21 INT 21
12A4:010E CD20 INT 20
-R
AX=0000 BX=0000 CX=0010 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=12A4 ES=12A4 SS=12A4 CS=12A4 IP=0100 NV UP EI PL NZ NA PO NC
12A4:0100 B402 MOV AH,02
-G
ABC
Program terminated normally

返回目錄

2004-5-26 09:45

IceMe
正式會員





積分 170
發帖 305
註冊 2004-3-15
來自 紫色星雲
狀態 離線 9)你可以用DEBUG的計算功能計算程序的長度。

一開始的時候你的程序初始位址是在0100h:
107F:0100 MOV AH,02 <--這就是 100h 你的程序的最後一行在010Eh: 107F:010E INT 20 <--最後一行 然後,最後一條指令的下一行的位址是0110h: 107F:0110 <--這就是110h 所以,從0110h裡減去100h我們得到得長度是10h 字元. PROMPT> DEBUG<按Enter鍵>
-H 110 100<按Enter鍵> (這條指令將運算110h+100h和110h-100h)
0210 0010<按Enter鍵> (匯報 110h-100h=0010h; 16-byte 程序長度16位)
-Q<按Enter鍵> (結束DEBUG)


C:\WINDOWS>debug
-H 110 100
0210 0010
-Q

返回目錄

10)另一種顯示在螢幕上字串串的方法

注意:在你輸入資料的時候,按"-"鍵將會可以讓你回退一格。

PROMPT> DEBUG<按Enter鍵>
-E 200<按Enter鍵> (從偏移位址200開始。輸入"Hello,World")
48<按空格>65<按空格> (輸入48h (H)和65h (e))
6C<按空格>6C<按空格> (輸入6Ch (l)和6Ch (l))
6F<按空格>2C<按空格> (輸入6Fh (o)和2Ch (,))
57<按空格>6F<按空格> (輸入57h (W)和6Fh (o))
72<按空格>6C<按空格> (輸入72h (r)和6Ch (l))
64<按空格>24<按空格> (輸入64h (d)和24h ($))
<按Enter鍵> ("Hello,World" 已經輸入完畢)
-D 200<按Enter鍵> (顯示你剛剛輸入的內容:
48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 ... HELLO,WORLD$...)
-A 100<按Enter鍵> (用組譯語言寫一個新程序在IP-100h處開始)
MOV AH,09<按Enter鍵> (選項DOS的09號功能使用,顯示字串串)
MOV DX,0200<按Enter鍵> (把輸出位址(200h),放進暫存器)
INT 21<按Enter鍵> (執行DOS功能使用,顯示"Hello,World")
INT 20<按Enter鍵> (結束程序回到DOS狀態)
<按Enter鍵> (結束組譯語言輸入,回到DEBUG輸入狀態)
-G<按Enter鍵> (從 CS:IP開始執行程序, 就是從107F:0100h開始執行程序)

現在,我們可以把這個程序儲存進一硬碟

-D 100<按Enter鍵> (紀錄:程序的起始點在100h)
-D 200<按Enter鍵> (紀錄:程序資料單元的結束點是在020Bh)
-H 20B 100<按Enter鍵> (運算 20Bh-100h=10Bh;程序長度267字元)
-R BX<按Enter鍵> (檢查BX暫存器的值)
:0000<按Enter鍵> (設定BX為0000h,程序的長度是BX:CX,實際上你可以把和CX寫到一起,
即實際長度為:0000010Bh,這樣些的目的是使你可以計算更大的程序的長度)
-R CX<按Enter鍵> (設定CX 為010Bh, 這就是這個程序的長度了)
:010B<按Enter鍵> (現在你可以把這個108字元的程序寫入硬碟了)
-N printhw.com<按Enter鍵> (將要寫入硬碟的程序命名)
-W<按Enter鍵> (把這10Bh 即267個字元寫入文件)
-Q<按Enter鍵> (結束DEBUG)
PROMPT> DIR printhw.com<按Enter鍵>
將會匯報程序的長度是267字元(10Bh字元).
PROMPT> printhw.com<按Enter鍵>
執行這個程序,這將會在螢幕上顯示出"Hello,World" :

C:\WINDOWS>DEBUG
-E 200
127C:0200 2C.48 D5.65 BA.6C FF.6C FF.6F B8.2C 00.57 AE.6F
127C:0208 CD.72 2F.6C 3C.64 00.24 C3.
-D 200
127C:0200 48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 C3 A0 ED E3 Hello,World$
127C:0210 0A C0 74 09 56 57 E8 84-21 5F 5E 73 0A B9 04 01 ..t.VW..!_^s
127C:0220 FC 56 57 F3 A4 5F 5E C3-50 56 33 C9 33 DB AC E8 .VW.._^.PV3.
127C:0230 C3 23 74 19 3C 0D 74 15-F6 C7 20 75 06 3A 06 1E .#t.<.t... u 127C:0240 D4 74 0A 41 3C 22 75 E6-80 F7 20 EB E1 5E 58 C3 .t.A<"u... . 127C:0250 A1 F3 D8 8B 36 F5 D8 C6-06 37 DA 00 C6 06 33 DA ....6....7.. 127C:0260 00 8B 36 F5 D8 8B 0E F3-D8 8B D6 E3 42 51 56 5B ..6......... 127C:0270 2B DE 59 03 CB 8B D6 C6-06 D7 DC 00 E3 31 49 AC +.Y......... -A 100 127C:0100 MOV AH,09 127C:0102 MOV DX,0200 127C:0105 INT 21 127C:0107 INT 20 127C:0109 -G Hello,World Program terminated normally -D200 127C:0200 48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 C3 A0 ED E3 Hello,World$ 127C:0210 0A C0 74 09 56 57 E8 84-21 5F 5E 73 0A B9 04 01 ..t.VW..!_^s 127C:0220 FC 56 57 F3 A4 5F 5E C3-50 56 33 C9 33 DB AC E8 .VW.._^.PV3. 127C:0230 C3 23 74 19 3C 0D 74 15-F6 C7 20 75 06 3A 06 1E .#t.<.t... u 127C:0240 D4 74 0A 41 3C 22 75 E6-80 F7 20 EB E1 5E 58 C3 .t.A<"u... . 127C:0250 A1 F3 D8 8B 36 F5 D8 C6-06 37 DA 00 C6 06 33 DA ....6....7.. 27C:0260 00 8B 36 F5 D8 8B 0E F3-D8 8B D6 E3 42 51 56 5B ..6......... 127C:0270 2B DE 59 03 CB 8B D6 C6-06 D7 DC 00 E3 31 49 AC +.Y......... -H 20B 100 030B 010B -R BX BX 0000 : -R CX CX 0000 :010B -N PRINTHW.COM -W Writing 0010B bytes -Q C:\WINDOWS>DIR PRINTHW.COM
Volume in drive C has no label
Volume Serial Number is 28FB-70BA
Directory of C:\WINDOWS
PRINTHW COM 267 03-22-01 11:53 PRINTHW.COM
1 file(s) 267 bytes
0 dir(s) 555,089,920 bytes free

返回目錄

11)讓我們試一試反覆輸出:

PROMPT> DEBUG<按Enter鍵>
-A 100<按Enter鍵> (用組譯語言寫一個新的程序,起始位址是100h)
JMP 125<按Enter鍵> (從102h接跳到125h)
<按Enter鍵> (結束輸入組譯指令。譯者註:這裡是為了例12做準備)
-E 102 'Hello World' 0d 0a '$'<按Enter鍵> (把字串串輸入記憶體)
-A 125<按Enter鍵> (從125h開始繼續編寫我們的組譯語言程序)
MOV DX,0102<按Enter鍵> (把字串串的首位址(102h)放入DX暫存器)
MOV CX,0005<按Enter鍵> (指定這條指令將被顯示5次)
MOV AH,09<按Enter鍵> (選項DOS的09號功能使用, 顯示字串串)
INT 21<按Enter鍵> (執行DOS的功能使用, 顯示"Hello, World")
DEC CX<按Enter鍵> (每次執行到這裡CX都減去1)
JCXZ 0134<按Enter鍵> (如果計數器CX=0,那麼跳到位址0134h)
JMP 012D<按Enter鍵> (其他情況下,即CX≠O時跳到012Dh)
INT 20<按Enter鍵> (程序結束DOS狀態)
<按Enter鍵> (結束組譯語言程序輸入,回到DEBUG)
-U 100<按Enter鍵> (從位址100h 開始反組譯)
-U<按Enter鍵> (繼續執行反組譯指令,直至你看到INT 20)
-H 0136 100<按Enter鍵> (運算程序長度為36h)
-U 100 L 36<按Enter鍵> ( 從100h反組譯到136h ,來驗證你的計算)
-R BX<按Enter鍵> (檢視暫存器BX的值)
:0000<按Enter鍵> (設定BX為0000h)
-R CX<按Enter鍵> (把CX 設定為36h, 這就是程序長度36字元)
:0036<按Enter鍵> (現在你可以把這36字元寫入文件了)
-N printhw5.com<按Enter鍵>(命名我,我們要寫入的檔案名)
-W<按Enter鍵> (把這36字元的內容寫進新文件)
-G<按Enter鍵> (執行程序,在螢幕上顯示"Hello-World ")
-Q<按Enter鍵> (結束DEBUG)
PROMPT> DIR printhw5.com<按Enter鍵>
將會匯報文件大小為54字元,換算為十六進制就是36h字元
PROMPT> printhw5.com<按Enter鍵>
將在螢幕上顯示五次"Hello World"

返回目錄

12)我們現在把兩個程序連接起來。

我們現在把printhw.com做為修補程式 寫進printhw5.com, 新版本的printhw5 將先執行原來的printhw.com再執行原來的printhw5.com

PROMPT> COPY printhw5.com printhw5.bak<按Enter鍵>
首先,制作備份printhw5.com,以後可以用於比較
PROMPT> DIR printhw5.com<按Enter鍵>
現在,檢視到得仍然是以前的54字元(36h 字元)
PROMPT> DEBUG printhw5.com<按Enter鍵>
-R<按Enter鍵> (現在檢視仍然是BX:CX=0000 0036h bytes)
-U 100<按Enter鍵> (檢視到最後的是 EB 23 (JMP 0125))
-H 100 36<按Enter鍵> (最後的指令是在 100h+36h=136h)
-H 136 1<按Enter鍵> (下一個可用的儲存於器位置是136h+1h=137h)
現在你擁有足夠的資料,去修補那個程序
-E 110<按Enter鍵> (把"Hello,World"輸入記憶體)
48<按空格>65<按空格> (輸入48h (H)和65h (e))
6C<按空格>6C<按空格> (輸入6Ch (l)和6Ch (l))
6F<按空格>2C<按空格> (輸入6Fh (o)和2Ch (,))
57<按空格>6F<按空格> (輸入57h (W)和6Fh (o))
72<按空格>6C<按空格> (輸入72h (r)和6Ch (l))
64<按空格>24<按空格> (輸入64h (d)和24h ($))
<按Enter鍵> (停止輸入"Hello,World")
-D 110<按Enter鍵> (顯示更才輸入記憶體的資料:
48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 ...HELLO,WORLD$...)
-A 100<按Enter鍵> (在IP位址的(100h)開始奪取原來的程序的控制權,原來這裡是"JMP 125")
JMP 137<按Enter鍵> (替代原來執行的程序首先執行我們現在的修補程式)
<按Enter鍵> (結束組譯指令輸入,回到DEBUG指令輸入)
-A 137<按Enter鍵> (在下面的可用通姦編譯這個修補程式)
MOV AH,09<按Enter鍵> (選項DOS的09號功能使用,顯示輸出)
MOV DX,110<按Enter鍵> (把我們要輸出的字段的首位址(110h)給DX暫存器)
INT 21<按Enter鍵> (執行DOS 的功能使用,顯示"Hello,World")
JMP 0125<按Enter鍵> (這裡用跳轉到原程序來替代結束到DOS指令(INT 20))
<按Enter鍵> (結束組譯指令輸入,回到DEBUG指令輸入)

-U 125<按Enter鍵> (驗證一下源程序沒有被我們誤改了,如果無改了就馬上結束DEBUG重新來過)
-U 100 L 1<按Enter鍵> (驗證已經使程序跳轉到我們的修補程式位址137h)
-D 110 L C<按Enter鍵> (驗證資料區已經有了我們想要的資料)
-U 137<按Enter鍵> (驗證我們的新程序已經輸入了)

現在我們可以把這個小程序存入硬碟了:
(注意:在現在整個程序的最後一條指令"JMP 0125" 的後面一條的位址是0140h)
-H 0140h 100<按Enter鍵> (計算140h-100h=40h; 答案是我們現在有一個長度為64字元的小程序)
-RBX<按Enter鍵> (檢查BX暫存器的值是否為"0")
:<按Enter鍵> (如果BX是0000h那麼就不需要改動啦)
-RCX<按Enter鍵> (要把CX改為40h。這是我們的程序的長度)
:40<按Enter鍵> (現在你可以把這0000:0040h個字元的小程序放入硬碟啦)
-W<按Enter鍵> (覆蓋我們的原程序)
-G<按Enter鍵> (嘗試執行我們的新程序)
-Q<按Enter鍵> (結束DEBUG回到DOS)

PROMPT> DIR printhw5.com<按Enter鍵>
現在你再看就發現文章大小不再是54字元, 變成了64字元.
PROMPT> printhw5.com<按Enter鍵>
現在是首先在螢幕上列印 "Hello,World"一次,然後再列印"Hello,World" 5 次(譯者註:這裡其實可以在編程的時候換一換內容試一試.

返回目錄

13) 讓我們逐步執行這個剛剛修補的程序:

PROMPT> DEBUG printhw5.com<按Enter鍵>
-R<按Enter鍵> (第1步:位址0100h內容是 EB35 "JMP 0137")
-T<按Enter鍵> (第2步:位址0137h內容是B409 "MOV AH,09")
-T<按Enter鍵> (第3步:位址0139h內容是BA1001 "MOV DX,0110")
-T<按Enter鍵> (第4步:位址0139h內容是CD21 "INT 21")
-P<按Enter鍵> (執行第5:"Hello,World"位址013Eh內容是EBE5 "JMP 0125")
-T<按Enter鍵> (到這裡控制權已經回到了原程序)
如果你想的話,你可以一步一步的執行完全部程序;方法就是一直按"T",直至到達下一個功能使用執行完成後。到那時按一個"P"就可以繼續按"T".

返回目錄

14)如果一開始的指令不是跳轉指令,那麼可能就要用這種方法了:

例如:如果我們想叫程序printhw 先列印"ABC",就要獲取控制權了。然後列印"ABC"的程序把控制權給回原來的printhw.

在這個事例裡 ,printhw在100h的位址有兩字元的程序;
不能像上面那樣簡單的替代(一個JMP替代另一個JMP)就完事。
解決辦法就是使用NOP指令。


PROMPT> DIR printhw.com<按Enter鍵>
將匯報程序的長度為267字元(10Bh 字元).

PROMPT> DEBUG printhw.com<按Enter鍵>
-R<按Enter鍵> (IP=100h 並且printhw's 的文件大小=BX:CX=0000:010Bh)
-U 100<按Enter鍵> (第一條指令B4 09 (MOV AH,09)是兩個字元的)
(第二條指令是三個字元的 BA 00 02 (MOV DX,0200))
-H 100 10B<按Enter鍵> (最後一條printhw的指令是在100h+10Bh=20Bh)
(DOS的INT 21功能使用是在105h開始的)
現在你有足夠的資料輸入你的程序了!
-A 100<按Enter鍵> (要在printhw 的IP開始位置就奪取程序的控制權)
JMP 20B<按Enter鍵> (跳到20Bh增加一個程序)
NOP<按Enter鍵> (用空指令填充直至你去到下一條完整的指令)
NOP<按Enter鍵> (你可以用它來覆蓋你不想只執行的原程序指令 ,而不改變原來的位址。但是在這裡我們只需要兩個NOP)
譯者註:為了使大家更加明白所以我將各條指令對應的機械指令的長度寫在下面
B409 MOV AH,09
BA0002 MOV DX,0200
E90301 JMP 020B
90 NOP
這樣我們就很清楚的看到JMP 020B的長度比MOV AH,09多了1個字元,但是MOV DX,0200有是3個字元,而NOP是空指令,是不執行任何操作的,它只是占1個字元。所以我們現在把前兩條指令用一個JMP 020B和兩個NOP替代。後面再加上去。
<按Enter鍵> (結束組譯指令回到DEBUG指令輸入)
-U 100<按Enter鍵> (看一看前面我們做了些什麼)
(注意DOS INT 21中斷任然是在 IP=105h的地方開始)
-A 20B<按Enter鍵> (現在把我們的原程序寫在後面)
MOV AH,02<按Enter鍵> (選項DOS 的 2號功能使用, 字串顯示輸出)
MOV DL,41<按Enter鍵> (在DL暫存器存入"A"的ASCII碼41h)
INT 21<按Enter鍵> (執行DOS 的功能使用,顯示字串"A")
MOV DL,42<按Enter鍵> (在DL暫存器存入"B"的ASCII碼42h)
INT 21<按Enter鍵> (執行DOS 的功能使用,顯示字串"B")
MOV DL,43<按Enter鍵> (在DL暫存器存入"C"的ASCII碼43h)
INT 21<按Enter鍵> (執行DOS 的功能使用,顯示字串"C")
MOV AH,09<按Enter鍵> (現在重新輸入原來在100h的程序指令)
MOV DX,0200<按Enter鍵> (現在要打掃暫存器了,還原原來的200h的值)
JMP 105<按Enter鍵> (跳到INT 21指令的位置105h)
<按Enter鍵> (請注意一下你這裡最後的位址是0221h)
-H 221 100<按Enter鍵> (計算221h-100h=121h 就是289字元的程序)
-R CX<按Enter鍵> (把CX的值設為121h, 這就設定了程序的新長度)
:0121<按Enter鍵> (現在用121h (也就是289字元)覆蓋原值)
-W<按Enter鍵> (把這289個字元寫回原程序)
-Q<按Enter鍵> (結束DEBUG)

PROMPT> DIR printhw.com<按Enter鍵>
現在在看就會是新程序的長度289字元而不是,267字元)
現在在螢幕上先出現"ABC"再出現"Hello,World"

沒有留言: