AI摘要
本文介绍CTF MISC题目中,将01二进制数字串转换为二维码图像的方法:理解二进制与像素矩阵的映射关系,通过计算长度平方根确定边长,使用PIL库按行优先顺序将1映射为黑色、0映射为白色,生成图像后扫码获取flag。
背景
在 CTF竞赛的 MISC(杂项) 类题目中,出题者经常会给出一段由 0 和 1 组成的数字串,要求选手将其还原为可视化的二维码图像,进而扫码获取 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) | 适用场景 |
|---|---|---|
| 21 | 441 | QR Version 1(最小) |
| 25 | 625 | CTF 常见尺寸 |
| 29 | 841 | QR Version 3 |
| 33 | 1089 | QR Version 4 |
| 37 | 1369 | QR 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: 生成的图像扫码失败?
- 反转颜色:尝试将
1和0对应的颜色互换(黑变白、白变黑) - 检查行列顺序:确认是行优先还是列优先
- 添加白边:扫码器可能需要安静区(quiet zone),给图像加一圈白色边距
小结
本题属于 CTF MISC 中的图像隐写与还原类型,核心知识点:
- 二进制与像素的映射:01 串本质上是像素矩阵的线性展开
- 完全平方数约束:正方形矩阵要求数据长度为
n² - PIL 图像操作:
Image.new()创建画布,putpixel()逐像素绘制 - 行优先遍历:
(y, x)的双重循环对应从左到右、从上到下的扫描顺序
