mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5mobile wallpaper 6
1260 字
6 分钟
花指令题型 - GFCTF 2021 wordy 解题记录

题目分析#

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

发现程序从

jmp short near ptr loc_1144+1

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

什么是花指令?#

花指令(Junk Code)是故意插入到程序中的无用或混淆代码,目的是干扰反汇编器和静态分析工具。

花指令的干扰方式#

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

比如很经典的一种:

jmp short $-1 ; EB FF → 无限自跳,死循环
; 后面其实还有一大段正常代码

CPU 真实执行: 跳到自己这条指令,又跳回来 → 死循环,后面的代码根本不会被执行。

反汇编器视角: 它沿着控制流往下分析,看到 jmp,就认为:“后面这条指令永远执行不到,是不可达的”。于是后面真正有用的代码,被当成”数据”或”垃圾”直接忽略;函数边界、控制流图全乱。

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

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

反汇编有两种常见策略:

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

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

db 0x90, 0x90, 0x90, 0xE8, 0xAA, 0xBB, 0xCC, 0xDD
; 这一串既可以被解释成一堆 NOP + CALL
; 也可以被解释成完全不同的几条指令

CPU 只按真实执行路径那一种解码;但反汇编器如果从”错的边界”开始解,就会得到一堆看似莫名其妙的指令;再加上一些奇怪的 jmp / call,就会导致函数被切成多段,伪代码特别割裂。

3. 搞乱”函数识别”——工具找不到 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='')

代码含义:

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

将上述代码用 IDAPython 运行即可得到结果:

GFCTF{u_are2wordy}

总结#

花指令是逆向分析中常见的混淆手段,主要通过:

  1. 混淆控制流:插入无效跳转,干扰反汇编器的路径分析
  2. 混淆指令边界:制造重叠指令,让工具错将代码当数据
  3. 破坏函数识别:让函数被错误分割,难以理解整体逻辑

对抗方法包括手动 patch、脚本模式匹配、动态调试等。在实际分析中,需要根据具体情况选择合适的方法。

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

花指令题型 - GFCTF 2021 wordy 解题记录
https://chaojixin.ren/posts/花指令题型-gfctf2021-wordy解题记录/
作者
超級の新人
发布于
2025-11-29
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

封面
Sample Song
Sample Artist
封面
Sample Song
Sample Artist
0:00 / 0:00