x86汇编语言之转移指令和Call和Ret进阶

1,330 阅读3分钟

「这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战

转移指令jmp ,jcxz和retf

如果我们想要实现以下效果:

mov bx,3333H ;假如这条这条指令数据所对应的物理地址为0710:0000
mov ax,2000H ;假如这条这条指令数据所对应的物理地址为0710:0003


;如果我想跳过第一条指令 直接执行第二条指令 那么直接修改CS:IP的值为0710:0003即可

修改方法:

  • 调试器直接修改

  • 使用jmp指令

    jmp 0100h:8H
    mov bx,3333H 
    mov ax,2000H 
    
    
    ;如果在同一个段中 可以直接使用jmp+偏移地址的形式
    jmp 8H
    mov bx,3333H 
    mov ax,2000H 
    

    或者使用标记

    jmp me
    mov bx,3333H 
    me:
    	mov ax,2000H 
    
  • 使用jcxz指令

    jcxz (jmp cx zero):条件转移指令,功能和jmp一样,只是需要满足条件,也就是当cx寄存器中的值为0时,进行跳转

    mov cx,0
    jcxz me
    mov bx,3333H 
    me:
    	mov ax,2000H 
    
  • 使用retf指令

    retf需要配合栈进行使用,当程序执行到retf这条指令时,会连续从栈中pop两次数据,第一次的数据赋值给CS,第二次的数据赋值给IP,那么如果我们想要跳转到指定的指令,需要将该指令的段地址和偏移地址分别push进栈中

    stack segment
    	db 128 dup(0)
    stack ends
    
    code segment
    	start:
    		mov ax,stack
    		mov ss,ax
    		mov sp,128
    		
    		mov ax,0710H ;指定段地址
    		push ax
    		mov ax,0003H ;指定偏移地址
    		push ax
    		
    		retf ;程序跳转到0710:0003H这个位置
    code ends
    end start
    

Call和Ret进阶

call在执行时会先将下一条指令所对应的ip地址入栈,然后修改ip的值实现跳转, ret指令执行的时候,将ip地址pop出来进行跳转

call s ;标号里面存放的是ip偏移地址 如果写成call 3H  那么意思就是跳转到CS:0003h这个位置

call Far ptr 执行时会将下一条指令做对应的csip都入栈,retf指令执行的时候,将ipcs值pop出来进行跳转

ret和call配套使用,retf和call Far ptr 配套使用

可以通过标号(函数名称)之间数值相减计算函数体代码所占用的内存空间大小

code segment          
    mov ax,func1 
    mov bx, func2
    sub bx,ax ;计算函数func1占用的内存空间大小
 
  func1: 
    mov ax,3333H 
    ret             
  func2:       
    mov bx,4444H
    ret
code ends

直接从内存中获取ip地址然后跳转

call word ptr ds:[0] ;ds:[0]存放ip值

直接从内存中获取cs和ip地址然后跳转

call dword ptr ds:[0] ;ds:[0]存放的是ip值, ds:[2]存放的是cs值

;这种方式同样会将cs和ip入栈 可以配合retf使用

以上两种直接从内存中获取cs:ip的方式对于jmp指令同样有效

call指令和jmp指令的区别

  • jmp指令仅仅只是修改了cs:ip的值
  • call指令除了修改cs:ip的值之外,还将下一条指令的ip值入栈,方便ret指令跳转调用

iret指令:

iret指令执行,将ipcs值pop出来进行跳转,同时还执行了popf,相当于执行了以下三步操作

pop ip
pop cs
popf