汇编中的JCC指令 (逆向分析)

目录

[为什么 JCC 指令必须配合 TEST / CMP 使用?](#为什么 JCC 指令必须配合 TEST / CMP 使用?)

核心原因:

[最常用的"裁判助手"就是 TEST 和 CMP:](#最常用的“裁判助手”就是 TEST 和 CMP:)

决策指令

[TEST 指令](#TEST 指令)

技术原理:

指令格式:

影响的标志位:

用途:

用途:

[CMP 指令](#CMP 指令)

技术原理:

指令格式:

示例代码:

比较规则:

[1. 无符号数比较(主要看 CF 标志):](#1. 无符号数比较(主要看 CF 标志):)

[2. 有符号数比较(主要看 SF 和 OF 标志):](#2. 有符号数比较(主要看 SF 和 OF 标志):)

[JCC 指令(条件跳转指令)](#JCC 指令(条件跳转指令))

[什么是 JCC 指令:](#什么是 JCC 指令:)

[主要 JCC 指令分类及含义:](#主要 JCC 指令分类及含义:)

[1. 通用跳转](#1. 通用跳转)

[2. 零标志 / 相等判断](#2. 零标志 / 相等判断)

[3. 符号标志](#3. 符号标志)

[4. 溢出标志](#4. 溢出标志)

[5. 奇偶标志](#5. 奇偶标志)

[6. 无符号比较跳转](#6. 无符号比较跳转)

[7. 有符号比较跳转](#7. 有符号比较跳转)

[JCC 指令的执行流程](#JCC 指令的执行流程)

指令获取与解码

检查标志位

计算目标地址

[更新 EIP](#更新 EIP)

流水线与分支预测

案例


为什么 JCC 指令必须配合 TEST / CMP 使用?

核心原因:

JCC 本身不进行任何计算,它只"看"标志寄存器(EFLAGS)里的状态。

JCC(Jump if Condition Code)是一组条件跳转指令(je、jg、jb、jl 等)。它们的工作原理是:

  • 执行前检查 EFLAGS 寄存器中的标志位(ZF、CF、SF、OF、PF 等);
  • 根据标志位的值决定是否跳转

JCC 自己不会修改标志位,它只是一个"裁判",需要前面有指令先把"比赛结果"写到标志位里。

最常用的"裁判助手"就是 TEST 和 CMP:

  • CMP :负责数值大小比较(通过减法设置标志位)
  • TEST :负责位测试 / 逻辑与(通过与运算设置标志位)

如果不配合 TEST 或 CMP(或 AND、SUB、OR 等能改标志位的指令),JCC 就无法做出正确判断,跳转条件会使用上一次指令遗留的标志位,导致程序逻辑错误。

总结一句话: JCC 是决策指令,TEST 和 CMP 是提供决策依据的指令。 它们是"搭档"关系,缺一不可。

决策指令

TEST 指令

技术原理:
  • TEST 指令执行按位与(AND)运算,但不保存运算结果

    • 仅用于修改 EFLAGS 寄存器中的标志位

    • 它本质上是对两个操作数进行"与"操作,用于位测试和标志位设置。

指令格式:

TEST 操作数1, 操作数2

影响的标志位:
  • ZF(Zero Flag):结果为0时置1,否则置0

  • SF(Sign Flag):结果最高位为1时置1,否则置0

  • PF(Parity Flag):结果中1的个数为偶数时置1

  • CF 和 OF:总是被清零(不受影响)

示例代码:

复制代码
mov eax, 1001b          ; EAX = ...00001001
test eax, 1001b         ; 1001 & 1001 = 1001 → ZF=0(非零)
jnz bit_set             ; 如果该位被置位则跳转

mov eax, 0
test eax, 1             ; 0 & 1 = 0 → ZF=1
jz bit_clear            ; 如果该位未置位则跳转
用途:
  • 常用于检测特定位是否置位(如权限标志、状态标志、设备控制位等),是位操作和条件判断的重要手段。
用途:
  • 常用于检测特定位是否置位(如权限标志、状态标志、设备控制位等),是位操作和条件判断的重要手段。

CMP 指令

技术原理:
  • CMP 指令执行减法运算(操作数1 - 操作数2),但不保存结果

  • 仅根据减法结果更新 EFLAGS 寄存器的标志位

  • 为后续的条件跳转(JCC)提供判断依据。

指令格式:

CMP 操作数1, 操作数2

示例代码:
复制代码
mov eax, 10
mov ebx, 5
cmp eax, ebx            ; 相当于 10 - 5,设置相关标志位
比较规则:
1. 无符号数比较(主要看 CF 标志):
  • A < B:CF=1,ZF=0

  • A > B:CF=0,ZF=0

  • A == B:ZF=1

  • A <= B:CF=1 或 ZF=1

  • A >= B:CF=0

2. 有符号数比较(主要看 SF 和 OF 标志):
  • A < B:SF ≠ OF

  • A > B:SF = OF 且 ZF=0

  • A == B:ZF=1

  • A >= B:SF = OF

  • A <= B:ZF=1 或 SF ≠ OF

补充说明:

  • SF 表示结果的符号(1为负,0为正)

  • OF 表示有符号运算是否发生溢出

JCC 指令(条件跳转指令)

什么是 JCC 指令:

  • JCC 是 x86 汇编中"Jump if Condition Code"(条件码跳转)的统称

  • 是一系列根据 EFLAGS 寄存器中特定标志位状态决定是否跳转的指令。

  • JCC 本身不修改任何寄存器或内存,仅改变程序的执行流程(EIP/RIP)。

  • JCC 指令必须紧跟在能修改标志位的指令(如 CMP、TEST、AND、OR、SUB 等)之后使用

    • 是实现高级语言中 if、else、while、for、switch 等控制结构的核心机制

    • 在逆向工程和底层优化中极其重要。

主要 JCC 指令分类及含义:

1. 通用跳转
  • JMP:无条件跳转(始终跳转)
2. 零标志 / 相等判断
  • JE / JZ:ZF=1 → 相等 或 结果为零

  • JNE / JNZ:ZF=0 → 不相等 或 结果非零

3. 符号标志
  • JS:SF=1 → 结果为负数

  • JNS:SF=0 → 结果为非负数

4. 溢出标志
  • JO:OF=1 → 有符号溢出

  • JNO:OF=0 → 无溢出

5. 奇偶标志
  • JP / JPE:PF=1 → 偶校验

  • JNP / JPO:PF=0 → 奇校验

6. 无符号比较跳转
  • JB / JNAE:CF=1 → 低于(A < B,无符号)

  • JNB / JAE:CF=0 → 不低于(A >= B,无符号)

  • JBE / JNA:CF=1 或 ZF=1 → 低于等于(A <= B,无符号)

  • JA / JNBE:CF=0 且 ZF=0 → 高于(A > B,无符号)

7. 有符号比较跳转
  • JL / JNGE:SF ≠ OF → 小于(A < B,有符号)

  • JGE / JNL:SF = OF → 大于等于(A >= B,有符号)

  • JLE / JNG:ZF=1 或 SF ≠ OF → 小于等于(A <= B,有符号)

  • JG / JNLE:ZF=0 且 SF = OF → 大于(A > B,有符号)

JCC 指令的执行流程

JCC 指令的执行是一个多步骤的过程,涉及 CPU 的指令解码、标志位检查和控制流调整。以下是详细的底层流程:

指令获取与解码

  • 步骤

    • CPU 从内存中读取 JCC 指令的机器码(通过指令指针 EIP 定位)。

    • 指令解码单元解析操作码(如 74 表示 JE)和操作数(目标地址的偏移量)。

  • 细节

    • JCC 指令通常是 2 字节或更多字节:

      • 1 字节操作码(如 74 表示 JE)。

      • 1 字节或 4 字节的相对偏移量(短跳转或长跳转)。

    • 例如:JE label 在内存中可能是 74 05,表示"如果 ZF=1,跳转到当前地址 + 5"。

检查标志位

  • 步骤

    • CPU 根据 JCC 的类型,读取 EFLAGS 中对应的标志位。

    • 执行条件判断逻辑。

  • 示例

    • JE(Jump if Equal):检查 ZF 是否为 1。

    • JB(Jump if Below):检查 CF 是否为 1。

    • JL(Jump if Less):检查 SF 和 OF 是否不同(SF ≠ OF)。

计算目标地址

  • 步骤

    • 如果条件满足,计算目标地址。

    • 目标地址 = 当前 EIP + 偏移量(偏移量是有符号数,可能正或负)。

  • 细节

    • 偏移量是相对跳转,范围取决于指令类型:

      • 短跳转(EB):1 字节偏移量,-128 到 +127。

      • 近跳转(E9):4 字节偏移量,范围更大。

    • 例如:JE 0x05 表示"如果条件满足,EIP = EIP + 5"。

更新 EIP

  • 步骤

    • 如果条件满足,将计算出的目标地址写入 EIP。

    • 如果条件不满足,EIP 指向下一条指令(EIP = EIP + 指令长度)。

  • 细节

    • EIP(指令指针)是 CPU 的关键寄存器,始终指向下一条待执行指令的地址。

    • JCC 的跳转本质上是修改 EIP 的值。

流水线与分支预测

  • 背景:现代 CPU 使用流水线技术并行处理指令,跳转可能导致流水线停顿。

  • 优化

    • 分支预测器:预测 JCC 是否跳转,预取可能的目标指令。

    • 预测失败:如果预测错误,丢弃预取的指令,重新加载正确路径的指令。

  • 细节

    • 分支预测基于历史跳转模式(如"总是跳转"或"从不跳转")。

    • 提高了 JCC 的执行效率,但增加了硬件复杂度。

案例

案例1:简单 if-else 等价结构

复制代码
mov eax, 15
mov ebx, 10

cmp eax, ebx
jg  greater_case        ; 如果 eax > ebx(有符号)则跳转

; else 分支
mov ecx, 0
jmp end_if

greater_case:
mov ecx, 1

end_if:

案例2:使用 TEST 的位检测

复制代码
mov eax, 0x00000004     ; 第2位被置位

test eax, 0x00000004    ; 测试第2位
jnz bit_is_set          ; 如果该位为1则跳转

; 该位为0的处理
jmp done

bit_is_set:
; 该位为1的处理

done:
相关推荐
浩浩测试一下3 小时前
汇编中的段与段寄存器(大小)段序 (逆向分析)
汇编·逆向·二进制·字节序·windows编程·内存地址排序
浩浩测试一下1 天前
汇编 call与ret 函数与堆栈 (逆向分析)
汇编·push·函数·pop·call·ret·堆栈逆向
山屿落星辰1 天前
昇腾NPU算子开发:从“手写汇编“到“搭积木“
汇编
浩浩测试一下1 天前
汇编 汇编寻址 (逆向分析)
汇编·寻址·windows编程·二进制逆向·机器码
浩浩测试一下2 天前
汇编 位运算 (逆向分析)
汇编·逆向·位运算·asm·windows编程·二进制逆向
浩浩测试一下2 天前
汇编 高低八位寄存器数据存储方式(逆向分析)
汇编·网络安全·逆向·二进制·免杀·寄存器·windows编程
a83331963 天前
C语言嵌入汇编详解
汇编·单片机·语言
yoyo_zzm3 天前
汇编到PHP:五大编程语言核心特性全解析
开发语言·汇编·php
ComputerInBook5 天前
X64 汇编 MOVSD 的两种用法
汇编·汇编指令·movsd