AI摘要

本文介绍CTF MISC题目中,将01二进制数字串转换为二维码图像的方法:理解二进制与像素矩阵的映射关系,通过计算长度平方根确定边长,使用PIL库按行优先顺序将1映射为黑色、0映射为白色,生成图像后扫码获取flag。

背景

在 CTF竞赛的 MISC(杂项) 类题目中,出题者经常会给出一段由 01 组成的数字串,要求选手将其还原为可视化的二维码图像,进而扫码获取 flag。

这类题目的核心考察点是:理解二进制数据与像素矩阵之间的映射关系,以及如何利用编程手段完成图像重建。


原理分析

为什么 01 串能表示二维码?

二维码(QR Code)本质上是一个二维像素矩阵。每个模块(module)只有两种状态:

像素值二进制表示颜色
深色模块1黑色(0, 0, 0)
浅色模块0白色(255, 255, 255)

当一段 01 数字串的长度恰好是某个整数 n 的平方时(即 len = n × n),它可以被排列成一个 n × n 的正方形矩阵——这正是二维码的像素布局方式。

数据流转换过程

01 数字串 → 一维数组 → 二维像素矩阵 → 二维码图像
  625 bit     [0,1,1,0,...]    25×25 矩阵      RGB 图像

关键约束:数字串长度必须是完全平方数,否则无法构成正方形矩阵,也就不是合法的二维码。

常见尺寸对照

矩阵边长总像素数(bit)适用场景
21441QR Version 1(最小)
25625CTF 常见尺寸
29841QR Version 3
331089QR Version 4
371369QR Version 5
注意:CTF 题目中的矩阵不一定是标准 QR Code 的精确定位图案尺寸,但 25×25 是最常见的出题尺寸。

解题代码

完整脚本

内容已锁定
此处内容已被隐藏,请关注公众号后验证查看

代码逐行解析

代码段说明
Image.new("RGB", (MAX, MAX))创建 25×25 的 RGB 空白图像,默认全黑
for y / for x双重循环按行优先(row-major)顺序遍历像素
binary_str[i]逐字符读取,'1'→ 黑色,'0'→ 白色
putpixel([x, y], color)将指定坐标像素设置为对应颜色
pic.show()调用系统默认图片查看器显示结果
pic.save("flag.png")保存为 PNG 文件,供扫码工具识别

扩展:另一种思路 — 使用 qrcode 库反向识别

如果你拿到 01 串后不想手写转换逻辑,也可以先生成图像再用 pyzbar 等库自动解码:

# 安装依赖: pip install Pillow pyzbar
from pyzbar.pyzbar import decode
from PIL import Image

# 先用上面的方法生成图像,再解码
img = Image.open("flag.png")
results = decode(img)

for r in results:
    print(f"[+] 类型: {r.type}")
    print(f"[+] 内容: {r.data.decode()}")

解题流程总结

┌─────────────────────────────────────────┐
│  1. 获取 01 数字串                        │
│     ↓                                    │
│  2. 计算长度,判断是否为完全平方数            │
│     ↓                                    │
│  3. 求平方根 → 矩阵边长 n                  │
│     ↓                                    │
│  4. 按行优先顺序,1→黑 0→白,填充 n×n 图像   │
│     ↓                                    │
│  5. 保存图像,使用二维码扫描工具读取 flag     │
└─────────────────────────────────────────┘

常见问题

Q: 数字串长度不是完全平方数怎么办?

可能是以下情况:

  • 包含分隔符:检查数据中是否有空格、逗号、换行符需要清理
  • 多层编码:数据可能经过 Base64、Hex 等编码,需先解码
  • 非正方形:极少数题目可能是矩形(长 × 宽),需尝试不同因数组合

Q: 生成的图像扫码失败?

  • 反转颜色:尝试将 10 对应的颜色互换(黑变白、白变黑)
  • 检查行列顺序:确认是行优先还是列优先
  • 添加白边:扫码器可能需要安静区(quiet zone),给图像加一圈白色边距

小结

本题属于 CTF MISC 中的图像隐写与还原类型,核心知识点:

  1. 二进制与像素的映射:01 串本质上是像素矩阵的线性展开
  2. 完全平方数约束:正方形矩阵要求数据长度为
  3. PIL 图像操作Image.new() 创建画布,putpixel() 逐像素绘制
  4. 行优先遍历(y, x) 的双重循环对应从左到右、从上到下的扫描顺序
投币支持一下吧
END