花指令

花指令原理就是在真实代码中插入一些垃圾代码的同时还保证原有程序的正确执行, 而程序无法很好地反编译

jz/jnz 指令

1.
jz(jump if zero) 指令的本质:如果ZF=1(前一条指令的结果为0)则跳转
jnz(jump if not zero) 指令的本质:如果ZF=0(前一条指令的结果不为0)则跳转
连续两条jn、jnz指令且跳转到同一个地址构造出无条件跳转,但 ida 不能正常识别
ida 打开有飘红的地方

看汇编,这个地方有两条跳转指令,jn和jnz,跳转的地方是同一个地址

下面的 mov 指令实际上6个字节,直接 nop 可能会 nop 多,所以先 U(undefine)一下看到更细的汇编再 nop

把 jn/jnz 指令其中一条改成 nop,另一条改成 jmp,直接跳转到后面的代码


最后在标签的位置(loc_413364) U一下,P(变成函数)一下,就修好了

  1. 反编译失败,Tab 切换到汇编
    在 下一条指令即 mov 处 U

    在 跳转到的地方即 unk_41213F 处 C

    又多出来两条新的jz jnz,重复上述步骤

    所有 jz jnz 出来之后,把这部分代码块都 nop 掉,再在最开始的标签处 U P,就能修复了


    最后f5 就可以了

xor test jz/jnz 指令


xor ebx,ebx 将 ebx 清零,设置 ZF=1
test ebx,ebx 测试 ebx 的值,实际执行 ebx AND ebx ,结果为0,保持 ZF =1
jnz short near ptr byte_412AC9 若 ZF=0,则跳转到 byte_412AC9,但此时 ZF=1,条件不满足,继续执行下一条指令
jz short loc_412ACA由于 ZF=1,跳转到 loc_412ACA
所以这种结构的花指令必定会执行 jz 跳转,去花的话就将从 xor 到 jz跳转到的地方 之间的指令都 nop 掉

call-retn 指令

call指令的本质:push 下一条指令地址(函数返回地址)然后jmp 函数地址
ret指令的本质:pop eip

函数反编译失败,查看汇编

  • 将 call 的下一条指令地址(0x412307)压入堆栈
  • 反汇编器会尝试从 0x412307 开始解析指令,但此处被插入的 0xE8(call 的操作码)误导,导致后续代码解析错误
    add [esp+0F0h+var_F0], 8
  • 实际操作:var_F0 是 IDA 生成的变量名,表示偏移 -0xF0,因此 esp+0F0h+var_F0 = esp
  • 等效代码:add [esp], 8,即将栈顶的返回地址(原为 0x412307)加 8,修改为 0x41230F
    retn 的跳转:弹出修改后的返回地址 0x41230F,跳转到此处继续执行
  • 把 call 到 0x41230F 的代码都 nop 掉
  • 最后在 sub_4122B0 处 U P F5,就能修复了

或者也可以动调看 rip/eip 查看执行流程去花


花指令
http://example.com/2025/04/29/hua/
作者
Eleven
发布于
2025年4月29日
许可协议