跳转指令

  1. 控制转移类指令用于实现分支、循环、过程等程序结构
  2. 是仅次于传送指令的最常用指令
  3. 控制转移类指令通过改变IP(和CS)值,实现程序执行顺序的改变

举例:

jmp, loop,call,ret等

无条件跳转 jmp

  1. 不改变段(默认CS段),改变IP

    • 段内转移、直接寻址
    • 段内转移、间接寻址
  2. 改变段,改变IP

    • 段间转移、直接寻址
    • 段间转移、间接寻址
  3. jmp的参数 参考章节4_寻址方式

指令格式:
jmp  [ptr / LABEL]

指令拆分:

100:  EBFE      jmp 100
地址: EB[偏移(一个字节)]  jmp 跳转距离

FE=-2
跳转的地址=下条指令的地址+偏移

显示 转移对照表

  1. 如果不跟 修饰符(near/short/far)
  2. 那么编译器会自动判断
跳转指令参数限制跳转范围机器码作用地址变化
jmp short [寻址参数]立即数的话有限制:-128~+127-128~+127EB 偏移(1个字节)段内短转移ip<-ptr
jmp near [寻址参数]立即数的话有限制:-32768~+32767-32768~+32767E9 偏移(2个字节)段内近转移ip<-ptr
jmp word ptr [寻址参数]寻址参数64KBFF 标识编号段内间接转移ip<-ptr
jmp far ptr [标签]代码的标签1MBEA 偏移 段地址段间直接寻址cs<-lable的断地址,ip<-lable的偏移地址
jmp far ptr [bx]/[bp+si+x][bx]/[bp+si+x] 寄存器1MBFF 偏移 段地址段间间接寻址ip<-[mem],cs<-[men+2]

@@

$代表当前的偏移值

Call $+3
Pop ax

@f:ffront的缩写,可以理解为代码向前执行的方向,@f自动匹配向前的最近@@的位置
@b:bbefore的缩写,@b自动匹配向后的最近@@的位置
使用@@会导致汇编代码可读性差,所以不推荐使用

指令格式的应用

  1. 设置钩子
  2. 花指令/对抗

模拟函数

; 我们在这里设置 
; cs为 代码运行段
; ds为 数据段
; ss为栈空间
assume cs:main_code,ds:this_data,ss:this_stack

this_stack segment stack
    stack_buf db 256 dup(0)
this_stack ends

this_data segment
    addr_jmp_src db 4 dup(0)
    addr_jmp_dst db 4 dup(0)
    str_true db 'true$'
    str_false db 'false$'
this_data ends


main_code segment

; 类似main函数作为asm起始点
start:
    ;锁定栈
    mov ax, seg this_stack
    mov ss, ax
    
    ;锁定数据区
    mov ax, seg this_data
    mov ds,ax
    
    ; 设置要显示的符串
    mov dx,offset str_true
    
    
    ; 准备跳回来的地址
    mov bx, offset addr_jmp_src
    mov word ptr [bx], offset show_back ; 填充 ip
    mov word ptr [bx+2], seg main_code ; 填充 段地址
    ; 准备跳转的目标地址
    mov bx, offset addr_jmp_dst
    mov word ptr [bx], offset show_from_dx ; 填充 ip
    mov word ptr [bx+2], seg show_code ; 填充 段地址

    jmp far ptr [bx]; 跳转
    
;目标地址执行完成后跳转到这里
show_back:


    ; 安全退出
    mov ah,4ch
    int 21h
    
main_code ends

show_code segment

show_from_dx:
    
    ; 显示字符串
    mov ah,09h
    int 21h
    jmp roll_back_to_src


roll_back_to_src:
    ; 回到调用这个代码快的地址
    mov bx, offset addr_jmp_src
    jmp far ptr [bx]; 跳转

show_code ends


end start

有条件跳转 jcc/jxx

JCC指令中文含义检查符号位典型C应用
JZ/JE若为0则跳转;若相等则跳转ZF=1if (i == j);if (i == 0);
JNZ/JNE若不为0则跳转;若不相等则跳转ZF=0if (i != j);if (i != 0);
JS若为负则跳转SF=1if (i < 0);
JNS若为正则跳转SF=0if (i > 0);
JP/JPE若1出现次数为偶数则跳转PF=1"1"的个数为偶数
JNP/JPO若1出现次数为奇数则跳转PF=0"1"的个数为奇数
JO若溢出则跳转OF=1溢出
JNO若无溢出则跳转OF=0无溢出
JC/JB/JNAE若进位则跳转;若低于则跳转;若不高于等于则跳转CF=1if (i < j);
JNC/JNB/JAE若无进位则跳转;若不低于则跳转;若高于等于则跳转;CF=0if (i >= j);
JBE/JNA若低于等于则跳转;若不高于则跳转ZF=1或CF=1if (i <= j);
JNBE/JA若不低于等于则跳转;若高于则跳转ZF=0或CF=0if (i > j);
JL/JNGE若小于则跳转;若不大于等于则跳转SF != OFif (si < sj);
JNL/JGE若不小于则跳转;若大于等于则跳转SF = OFif (si >= sj);
JLE/JNG若小于等于则跳转;若不大于则跳转ZF != OF 或 ZF=1if (si <= sj);
JNLE/JG若不小于等于则跳转;若大于则跳转SF=0F 且 ZF=0if(si>sj)

关键点

  1. jb/ja用于无符号数
  2. jl/jg用有符号数
  3. 搭配cmp使用

loop

  1. LOOP指令为循环指令,其格式为 LOOP 标号
  2. 当cx不为0时就继续循环
  3. 如果标号为0则向下执行(CX默认为循环计数器)
    mov ax,10
    mov cx,5

loopa:
    add ax,1
    add ax,1
    loop loopa ;首先`cx=cx-1`,如果cx==0 就结束循环

call/ret/retf

  1. call 和jmp 都是用来跳转程序运行点
  2. 但是 jmp是无条件跳转
  3. call 除了跳转 还可以配合 ret/retf 回到当初跳转的地方

call/ret

段内跳转:

Call 标号
相当于:
    Push  ip
    Jmp xxx

Jmp xxx:相当于
    push xxx
    ret
ret:
用栈中数据改IP内容,近转移
相当于:
    pop ip

call far ptr /retf

段间跳转

call far ptr 标号
相当于:
    push  cs
    push  ip
    Jmp xxx
retf:
用栈中数据同时改CS,IP,远转移
相当于:
    pop ip
    pop cs

call 复杂跳转

; 我们在这里设置 
; cs为 代码运行段
; ds为 数据段
; ss为栈空间
assume cs:main_code,ds:this_data,ss:this_stack

this_stack segment stack
    stack_buf db 256 dup(0)
this_stack ends

this_data segment
    str_true db 'true',10,13,'$'
    str_false db 'false',10,13,'$'
this_data ends


main_code segment

; 类似main函数作为asm起始点
start:
    ;锁定栈
    mov ax, seg this_stack
    mov ss, ax
    
    ;锁定数据区
    mov ax, seg this_data
    mov ds,ax
    
    ; 模拟 for(;cl!=ch;cl++){echo false}
    mov cl,0
    mov ch,3
    
    ; ----------------if_for
    call far ptr if_for;远掉,push cs,ip
    ; ----------------显示结果
    call far ptr show_from_dx;远掉,push cs,ip

    ; 安全退出
    mov ah,4ch
    int 21h
    
main_code ends

fx_code segment

show_from_dx:
    
    ; 显示字符串
    mov ah,09h
    int 21h
    jmp roll_back_to_src

if_for:
    jmp if_for_main
    
    if_for_true:
    mov dx,offset str_true
    jmp roll_back_to_src
    
    if_for_false:
    add cx,1
    mov dx,offset str_false
    ; 显示字符串
    ; 虽然这里可使用近跳转
    ; 但是 show_from_dx 统一使用远回
    ; 所以我们这里也是用 远掉
    call far ptr show_from_dx
    
    jmp if_for_main
    
    if_for_main:
    cmp cl,ch
    je if_for_true ;cl==ch 就结束
    jmp if_for_false
    
roll_back_to_src:
    ; 回到调用这个代码快的地址
    retf;远回,pop cs,ip



fx_code ends


end start
Last modification:December 17, 2018
如果觉得我的文章对你有用,请随意赞赏