一步步学习汇编(10)之jmp指令原理分析(破解软件的必修课)

jmp指令

解释:

n       jmp为无条件转移,可以只修改IP,也可以同时修改CSIP

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。也就是说,程序只进行了一次ax1操作。

 

注意:

n       汇编指令jmp short s 对应的机器指令应该是什么样的呢?

n       我们先看一下别的汇编指令和其对应的机器指令

81.jpg

 

可以看到,在一般的汇编指令中,汇编指令中的idata(立即数),不论它是表示一个数据还是内存单元的偏移地址,都会在对应的机器指令中出现,因为CPU执行的是机器指令,它必须要处理这些数据或地址。

 

n       但是:当我们查看jmp short sjmp 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                 116位位移=“标号处的地址-jmp指令后的第一个字节的地址;

n                 2near ptr指明此处的位移为16位位移,进行的是段内近转移;

n                 316位位移的范围为

   -32769~32767,用补码表示;

n                 416位位移由编译程序在编译时算出。

我们发现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位位移的范围是27次方,而16位位移的范围是215次方。

 

三.回顾前面讲的jmp指令,其对应的机器码中并没有转移的目的地址,而是相对于当前IP的转移位移。

指令 “jmp far ptr 标号

   实现的是段间转移,又称为远转移

n       指令 “jmp far ptr 标号功能如下:

n       (CS)=标号所在段的段地址;

n       (IP)=标号所在段中的偏移地址。

n       far ptr指明了指令用标号的段地址和偏移地址修改CSIP

实例:

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   xxxjmp   near   ptr   xxx可以写成jmp   xx  
 
例如:   。。。  
  jmp   exit  
 
。。。  
        exit: mov   ax, 4c 00h  
        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,adress10000h+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标号

以标号的段地址和指令地址同时改变CSIP

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 0a 0bh, 0c 0dh
s1 ends

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

 

 

前面我们讲到了,jmp是指无条件的跳转,我们知道,在c,javac#中总会存在这样或那样的条件判断,那么汇编中如何进行有条件的跳转呢?

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,转移到标号处执行。

 

 

 

 

 

 

 

 

 

 

 

 

  

 

你可能感兴趣的:(学习)