// blog / 逆向笔记

条件跳转字节码速查

条件跳转字节码速查(x86 / x64)

一、条件跳转短编码(rel8)总表

rel8:relative 相对8位,即1字节 短跳转的操作码范围是 0x70 ~ 0x7F,指令长度 2 字节(操作码 + 1 字节相对偏移,例:74 08),偏移范围 -128 ~ +127 字节。

操作码助记符跳转条件含义
70JOOF=1溢出
71JNOOF=0无溢出
72JB / JC / JNAECF=1低于 / 有进位
73JAE / JNB / JNCCF=0高于等于 / 无进位
74JE / JZZF=1相等 / 为零
75JNE / JNZZF=0不相等 / 非零
76JBE / JNACF=1 或 ZF=1低于等于
77JA / JNBECF=0 且 ZF=0高于
78JSSF=1符号为负
79JNSSF=0符号非负
7AJP / JPEPF=1奇偶性为偶
7BJNP / JPOPF=0奇偶性为奇
7CJL / JNGESF≠OF有符号小于
7DJGE / JNLSF=OF有符号大于等于
7EJLE / JNGZF=1 或 SF≠OF有符号小于等于
7FJG / JNLEZF=0 且 SF=OF有符号大于

二、近跳转编码(rel32,0F 8x 系列)

近跳转以 0F 为前缀,第二字节在 0x80 ~ 0x8F,共 6 字节指令(2 字节操作码 + 4 字节偏移),偏移范围约 ±2GB。这是 32 位和 64 位模式下编译器为较远目标生成的默认编码。

操作码(十六进制字节序列)助记符跳转条件
0F 80 cdJOOF=1
0F 81 cdJNOOF=0
0F 82 cdJB / JCCF=1
0F 83 cdJAE / JNCCF=0
0F 84 cdJE / JZZF=1
0F 85 cdJNE / JNZZF=0
0F 86 cdJBECF=1 或 ZF=1
0F 87 cdJACF=0 且 ZF=0
0F 88 cdJSSF=1
0F 89 cdJNSSF=0
0F 8A cdJP / JPEPF=1
0F 8B cdJNP / JPOPF=0
0F 8C cdJLSF≠OF
0F 8D cdJGESF=OF
0F 8E cdJLEZF=1 或 SF≠OF
0F 8F cdJGZF=0 且 SF=OF

三、x32 与 x64 的关键差异(Patch 时必看)

1. rel8 短跳转在两种架构下完全相同。 0x74 / 0x75 在 x86 和 x64 下含义一致,补丁方式完全一样。

2. 0F 84 / 0F 85 的近跳转在 64 位模式下有效,但操作数大小有限制。

  • rel16 编码在 64 位模式下不支持。Intel 手册明确标注 JE rel16(0F 84 cw)在 64-bit mode 下为 Not Supported。
  • rel32 编码在 64 位模式下正常支持。0F 84 cd(JE rel32)和 0F 85 cd(JNE rel32)在 x64 下完全可用,偏移量会符号扩展为 64 位。
  • 如果在 64 位代码中看到 0F 84 后跟 4 字节偏移(共 6 字节指令),直接 patch 为 0F 85 即可反转条件;如果 0F 84 后跟的是 2 字节偏移(rel16),那是 16 位兼容模式的编码,x64 下不会出现。

3. 64 位模式下新增的专用条件跳转:

  • JRCXZ(操作码 E3):检查 RCX 寄存器是否为 0,仅在 64 位模式可用。
  • JECXZ(操作码同为 E3):检查 ECX 寄存器是否为 0,在 32 位和 64 位模式下都有效。
  • 在 64 位模式下,E3 默认按 JRCXZ 解释(取决于地址大小前缀)。

四、patch实战速查

最常用的反转对

原始目标Patch 方式
74 (JZ short)75 (JNZ short)改 1 字节
75 (JNZ short)74 (JZ short)改 1 字节
0F 84 (JZ near)0F 85 (JNZ near)改第 2 字节
0F 85 (JNZ near)0F 84 (JZ near)改第 2 字节

其他常用反转对

  • 72 ↔ 73(JB ↔ JNB)
  • 76 ↔ 77(JBE ↔ JA)
  • 7C ↔ 7D(JL ↔ JGE)
  • 7E ↔ 7F(JLE ↔ JG)

Patch 注意事项

  • 先确认是短跳转还是近跳转:看指令起始字节是单字节操作码(74/75)还是 0F 前缀。74 XX 是 2 字节短跳转,0F 84 XX XX XX XX 是 6 字节近跳转。
  • 仅反转条件时不要改变指令长度:短跳转改短跳转,近跳转改近跳转。把 0F 84 改成 74 会破坏后续字节的解析。
  • 偏移量是相对当前指令末尾的:短跳转的 rel8 从下一条指令的地址开始计算,补丁后偏移量不变,目标地址不变。

五、标志位速记

标志位名称置 1 条件常用于
ZF零标志结果为 0JE/JZ、JNE/JNZ
CF进位标志无符号运算产生进位/借位JB/JC、JAE/JNC
SF符号标志有符号结果为负JS、JNS
OF溢出标志有符号运算溢出JO、JNO
PF奇偶标志结果低字节中 1 的个数为偶JP、JNP

JZ/JE 只关心 ZF,与 CF、SF、OF 无关。 无论前面的 cmp 是有符号还是无符号比较,只要结果相等(差值为 0),ZF 就置 1。

六、简单总结

  • JZ 就是 JE,操作码 74(短)/ 0F 84(近),条件 ZF=1。
  • JNZ 就是 JNE,操作码 75(短)/ 0F 85(近),条件 ZF=0。
  • x32 和 x64 下这两个指令的操作码完全一样,区别仅在于近跳转不支持 rel16 编码,但 rel8 和 rel32 都正常可用。
  • Patch 时看前缀:单字节直接改,0F 前缀改第二个字节。

// comments

评论

加载中…

正在读取评论…