花指令题型[GFCTF 2021]wordy

chaoji_xinren 发布于 18 天前 35 次阅读


首先exeinfo发现该程序是Linux 下的 64 位 ELF 动态库/可执行文件没检测出壳,之后将程序拖到ida里进行分析。

发现程序从

jmp short near ptr loc_1144+1

开始就无法分析,推测是jmp花指令导致IDA 认为既像代码又像数据,因此无法进行分析

花指令是怎么搞乱反汇编的?

搞乱“控制流”——让工具判断错“往哪儿走”

比如很经典的一种:

jmp short $-1   ; EB FF  → 无限自跳,死循环
; 后面其实还有一大段正常代码
  • CPU 真实执行
    跳到自己这条指令,又跳回来 → 死循环,后面的代码根本不会被执行。
  • 反汇编器视角
    • 它沿着控制流往下分析,看到 jmp,就认为: “后面这条指令永远执行不到,是不可达的”
    • 于是 后面真正有用的代码,被当成“数据”或“垃圾”直接忽略
    • 函数边界、控制流图全乱。

再加上各种“假跳转”“永远不会成立的条件分支”(所谓 opaque predicate,永真/永假的条件判断),就可以让 IDA 一会觉得往左走,一会觉得往右走,分析路线被拧成麻花。


搞乱“指令边界”——让工具把数据当代码、代码当数据

反汇编有两种常见策略:

  • 线性扫(linear sweep):从某个起点一个字节一个字节往下解码;
  • 递归下降(recursive descent):从入口跟着跳转走,只解自己认为“能到达”的地址。

花指令可以故意制造重叠指令或“伪代码”:

db 0x90, 0x90, 0x90, 0xE8, 0xAA, 0xBB, 0xCC, 0xDD
; 这一串既可以被解释成一堆 NOP + CALL
; 也可以被解释成完全不同的几条指令
  • CPU 只按真实执行路径那一种解码;
  • 但反汇编器如果从“错的边界”开始解,就会得到一堆看似莫名其妙的指令;
  • 再加上一些奇怪的 jmp / call,就会导致 函数被切成多段,伪代码特别割裂。

搞乱“函数识别”——工具找不到 main / check_flag 的真身

像 IDA 识别函数的时候,会用一些套路:

  • 看是否有典型的函数前言(push rbp; mov rbp, rsp);
  • 看有没有被 call 引用;
  • 看返回前是否有 leave; ret 等模式。

花指令可以:

  • 在函数中部插入奇怪的 ret / jmp / “假 call”,
  • 让 IDA 以为“这里是函数结尾了 / 这里是新函数开始”,

最后结果:

  • 一个本来很简单的 check_flag,被拆成 5~6 个小函数;
  • xref 图一片乱麻,伪代码怎么看都不成体系;
  • 你就会感觉:“怎么没有地方在真正比较 flag?”
    ——其实比较逻辑是有的,只是被撕碎了。

遇到花指令逆向比赛里常见几招:

  1. 直接 patch 花指令
    • jmp $-1 这种死循环改成 nop nop
    • 把永真/永假条件改成不跳转;
    • 让控制流恢复正常,再让 IDA 重新分析。
  2. 把代码当数据,自己写脚本扫模式
    像 wordy 那题,我们直接:
    • 不管这堆指令到底跑不跑;
    • 反正我知道“每一段 FF C0 + 某字节就是一位字符”;
    • 用 Python/IDAPython 按字节流扫描,还原字符串。
  3. 配合动态调试
    • 用 gdb / x64dbg 让程序真实跑起来,看 RIP 实际走哪些路径;
    • 发现某些 jmp 从来不走,就可以认定那是花指令。

这道题最简单的方法是在 IDA 里用 Python 把“藏在指令里的字符串直接扫出来”的解法

start_adr = 0x1151 
end_adr = 0x3100
for i in range(start_adr,end_adr):
  if get_wide_byte(i) == 0xc0:
     print(chr(get_wide_byte(i+2)),end='')

含义:

  1. get_wide_byte(i) 是 IDAPython 的 API,用来读某个地址的一个字节。
  2. 你从 0x1151 一直扫到 0x3100逐字节检查
  3. 每遇到一个字节值是 0xC0 的地方,就认定: “这里是一个标记(锚点),真正有用的字符在后面偏移 2 个字节的位置”
  4. 然后 get_wide_byte(i+2) 读出那个字节,把它用 chr() 转成字符拼起来。

将上述代码用 IDAPython运行即可得到结果GFCTF{u_are2wordy}

此作者没有提供个人介绍。
最后更新于 2025-11-29