1. 程式人生 > >一步步學習彙編(10)之jmp指令原理分析

一步步學習彙編(10)之jmp指令原理分析

jmp指令

解釋:

n       jmp為無條件轉移,可以只修改IP,也可以同時修改CS和IP;

n       jmp指令要給出兩種資訊:

n       轉移的目的地址

n       轉移的距離(段間轉移、段內短轉移,段內近轉移)

格式:

一.Jump short 標號

   這種格式的 jmp 指令實現的是段內短轉移,它對IP的修改範圍為 -128~127,也就是說,它向前轉移時可以最多越過128個位元組,向後轉移可以最多越過127個位元組。

示例:

assume cs:codesg

codesg segment

  start:mov ax,0

          jmp short s

          add ax,1

       s:inc ax

codesg ends

end start

說明:上面的程式執行後, ax中的值為 1 ,因為執行  jmp short s 後 ,越過了add ax,1 ,IP 指向了標號 s處的 inc ax。也就是說,程式只進行了一次ax加1操作。

注意:

n       彙編指令jmp short s 對應的機器指令應該是什麼樣的呢?

n       我們先看一下別的彙編指令和其對應的機器指令

81.jpg

可以看到,在一般的彙編指令中,彙編指令中的idata(立即數),不論它是表示一個數據還是記憶體單元的偏移地址,都會在對應的機器指令中出現,因為CPU執行的是機器指令,它必須要處理這些資料或地址。

n       但是:當我們檢視jmp short s或jmp 0008所對應的機器碼,卻發現了問題。

   82.jpg

看到了嗎?機器碼中並不含有立即數。為什麼呢,解釋如下

n       在“jmp short 標號”指令所對應的機器碼中,並不包含轉移的目的地址,而包含的是轉移的位移

n       這個位移,使編譯器根據彙編指令中的“標號”計算出來的

如果我們在第一行程式後加上Mov bx,0000,你會發器機器碼沒變,還是EB03,為什麼呢?jmp 0008對應的偏移就是0003大家可以回憶一下cpu中指令的執行流程,就會發現當執行完EB03後,ip=ip+2=0005,大家注意看EB03後面有個03,表示再向後三個單位,這樣就到了0008這個偏移處了。所以我們說包含 的是轉移的位移。

轉移位移具體的計算方法如下圖

83.jpg

二.還有一種和指令“jmp short 標號”功能相近的指令格式:

    jump near ptr 標號

    實現的時段內近轉移。

指令“jmp near ptr 標號”的功能為:(IP)=(IP)+16位位移。

n           指令“jmp near ptr 標號”的說明:

n                 (1)16位位移=“標號”處的地址-jmp指令後的第一個位元組的地址;

n                 (2)near ptr指明此處的位移為16位位移,進行的是段內近轉移;

n                 (3)16位位移的範圍為

   -32769~32767,用補碼錶示;

n                 (4)16位位移由編譯程式在編譯時算出。

我們發現jump short 標號與jump near ptr 標號非常相似,不同點在哪兒呢?實際上就是跳轉的範圍,看下面一段程式碼:

assume cs:codesg

codesg segment

  start:mov ax,0

          jmp near ptr s

          add ax,1

         dw 200 dup(2)此處表示生成若干條彙編指令,從而產生多個地址,方便測試

          s:inc ax

codesg ends

end start

如果我們將此處的jmp near ptr s 改為jmp short s,那麼編譯時會報這樣的錯誤 jump out of range by 276 bytes,即jump越界了。也就是說:

在編譯的時候由編譯程式算出是8位還是16位位移。8位位移的範圍是2的7次方,而16位位移的範圍是2的15次方。

三.回顧前面講的jmp指令,其對應的機器碼中並沒有轉移的目的地址,而是相對於當前IP的轉移位移

指令 “jmp far ptr 標號”

   實現的是段間轉移,又稱為遠轉移

n       指令 “jmp far ptr 標號” 功能如下:

n       (CS)=標號所在段的段地址;

n       (IP)=標號所在段中的偏移地址。

n       far ptr指明瞭指令用標號的段地址和偏移地址修改CS和IP。

例項:

assume cs:codesg

           codesg segment

           start:mov ax,0

                     mov bx,0

               jmp far ptr  s

               db 256 dup (0)

               s: add ax,1

                 inc ax

           codesg ends

           end start

分析:用U命令檢視後如圖:

84.jpg

“0B 01 BD 0B” 是目的地址在指令中的儲存順序,高地址的“BD 0B”是轉移的段地址:0BBDH,低地址的“0B 01” 是偏移地址:010BH。看到了嗎?標號所在的段地址與偏移地址為:0BBD:010B,可能是位於另一個程式碼段中。

前面三者的區別,我用程式碼總結一下,大家一看就明白了:

jmp   short   xxx和jmp   near   ptr   xxx可以寫成jmp   xx   
  例如:   。。。   
  jmp   exit   
  。。。   
        exit: mov   ax,4c00h   
        int   21h   
  。。。   
 

 2.jmp   far   ptr   xxx   
        code1   segment   
  。。。   
  jmp far   ptr   new_seg   
  。。。   
        code1 ends   
        code2 segment   
  。。。   
        new_seg:   
  。。。   
        code2 ends  

現在我們再來看第四種:

四.先看程式碼,再來闡述:

JMP   DWORD   PTR   XXXX是段間間接定址   
  由xxxx的定址方式求得偏移地址(假如是adress後),【adress】和【adress+2】分別就是轉移目的地址得偏移地址和段地址   
  還是舉個例吧:   
  code1 segment   
  。。。   
  jmp dword   ptr   [bx][di]   
  。。。   
  code1 ends   
  code2 segment   
  。。。   
  jmp_here:   
  。。。   
  code2 ends   
  設(ds)=1000h,(di)=0300h,(bx)=0150h,則adress=10000h+150h+300h=10450h,即轉移目的地址jmp_here的值存放在以10450h地址開始的4個位元組中   
    
  jmp   word   ptr   adress是段內間接定址

明白了吧,程式碼已經描述得很清楚了。

現在,關於jump的用法用一個圖全部總結一下:

格式

描述

舉例

類別

說明

jmp 16位暫存器

以16位暫存器的值改變IP

jmp ax

段內轉移

jmp 段地址:偏移地址

以立即數改變段地址和偏移地址

jmp 0045H:0020H

段間轉移

jmp short 標號

以標號地址後第一個位元組的地址來改變IP,實際上這個功能可以作如下描述:
(IP)=(IP)+8bit位移
8bit位移指的是從jmp指令後第一個位元組開始算起

jmp short sign

段內短轉移

對IP的修改範圍是-128->127,實際演算法是編譯器根據當前IP指標的指向來計算到底偏移多少個位元組來指向下一條指令,下面這段程式碼就會出編譯錯誤
jmp short s
dw 200 dup(2)
s: mov ax,4
因為跳轉超過了範圍

jmp near ptr 標號

以標號地址後第一個字的地址來改變IP,
實際上這個功能可以作如下描述:
(IP)=(IP)+16bit位移
16bit位移指的是從jmp指令後第一個位元組開始算起

jmp near ptr sign

段內近轉移

對IP的修改範圍是-32768->32767

jmp far ptr標號

以標號的段地址和指令地址同時改變CS和IP

jmp far ptr sign

段間轉移

jmp word ptr 記憶體地址

以記憶體地址單元處的字修改IP,記憶體單元可以以任何合法的方式給出

jmp word ptr ds:[si]
jmp word ptr ds:[0]
jmp word ptr [bx]
jmp word ptr [bp+si+idata]

段內轉移

jmp dword ptr記憶體地址

以記憶體地址單元處的雙字來修改指令,高地址內容修改CS,低地址內容修改IP,記憶體地址可以以任何合法的方式給出

jmp dword ptr [bx]

段間轉移

s1 segment
dw 0a0bh, 0c0dh
s1 ends

mov ax,s1
mov ds,ax
jmp dword ptr ds:[0]

前面我們講到了,jmp是指無條件的跳轉,我們知道,在c,或java或c#中總會存在這樣或那樣的條件判斷,那麼彙編中如何進行有條件的跳轉呢?

1. jcxz指令jcxz指令為有條件轉移指令,所有的有條件轉移指令都是短轉移,在對應的機器碼中包含轉移的位移,而不是目的地址。對IP的修改範圍都為-128~127。

指令格式:jcxz 標號 

   (如果(cx)=0,則轉移到標號處執行。)

2.含義:

n       jcxz 標號 指令操作:

n       當(cx)=0時,(IP)=(IP)+8位位移)

n       8位位移=“標號”處的地址-jcxz指令後的第一個位元組的地址;

n       8位位移的範圍為-128~127,用補碼錶示;

n       8位位移由編譯程式在編譯時算出。

n       當(cx)=0時,什麼也不做(程式向下執行)。

 3.例項:

我們從 jcxz的功能中可以看出,指令“jcxz 標號”的功能相當於:

   if((cx)==0)jmp short 標號;

 (這種用C語言和組合語言進行的綜合描述,或許能使你對有條件指令理解得更加清楚。)

當然,有條件的跳轉還有其它多種情況,不過原理是一樣的。現在我們再來看看破解外掛中常用的迴圈指令:loop

n       loop指令為迴圈指令,所有的迴圈指令都是短轉移,在對應的機器碼中包含轉移的位移,而不是目的地址。對IP的修改範圍都為-128~127。

n       指令格式:loop 標號

    ((cx))=(cx)-1,如果(cx)≠0,轉移到標號處執行。