CTF实战:从二进制到二维码的底层生成与自动化脚本解析
1. 从“0和1的故事”到CTF实战一次关于二维码的深度解构最近在整理CTFCapture The Flag的MISC杂项类题目时遇到一个挺有意思的案例题目名字叫“0和1的故事”核心是围绕二维码生成。乍一看这题可能被归类为简单的隐写或编码转换但实际深入下去你会发现它巧妙地串联了二进制数据处理、图像生成原理以及自动化脚本编写等多个知识点。对于刚接触CTF的新手或者想深入理解数据如何在不同形态间转换的朋友来说这是一个绝佳的练手项目。它不单单是让你“做出一个二维码”而是让你理解从一串最原始的“0”和“1”开始到最终能被手机摄像头识别的图像这中间究竟发生了什么。今天我就结合这个题目把二维码生成的底层逻辑、在CTF中常见的考察方式以及如何用Python和Excel这类看似普通的工具玩出花样从头到尾捋一遍。2. 理解“0和1的故事”二进制数据与二维码的本质这道题的核心提示“0和1的故事”直指计算机世界的基石——二进制。在CTF的MISC题目中这通常意味着你拿到手的初始数据可能就是一段由纯“0”和“1”字符组成的文本。例如题目附件可能是一个名为flag.txt的文件里面密密麻麻地写满了“0100110101101001...”这样的字符串。2.1 二进制字符串的常见编码与转换拿到这样一串二进制字符第一步是理解它的组织方式。它可能直接代表的是ASCII或UTF-8编码的文本。标准的转换方法是每8位一个字节二进制数对应一个字符。例如“01001000”转换为十进制是72在ASCII码中对应大写字母“H”。在Python中我们可以轻松完成这个转换binary_str 0100100001100101011011000110110001101111 # 示例Hello # 确保长度是8的倍数 if len(binary_str) % 8 ! 0: print(二进制字符串长度不是8的倍数可能需要检查填充或编码方式。) # 有时题目会故意去掉前导零需要手动补位这是一个常见坑点。 # 按8位分割并转换 n 8 bytes_list [binary_str[i:in] for i in range(0, len(binary_str), n)] text .join(chr(int(byte, 2)) for byte in bytes_list) print(f解码后的文本: {text})但“0和1的故事”往往没这么简单。这些二进制位可能不是直接对应文本而是图像像素数据每个“1”代表一个黑色像素或白色“0”代表白色像素或黑色。直接按照特定宽度和高度排列就能生成一张二值图像Bitmap而这张图像可能就是二维码。压缩或编码后的数据可能是经过Base64、莫尔斯电码等其他编码后的二进制表示需要先按二进制理解再二次解码。二维码的编码区域数据直接对应二维码编码矩阵中数据模块和纠错模块的值排除了定位图形、格式信息等固定部分。这就需要你了解二维码的物理结构。2.2 二维码的物理结构不只是黑白方块一个标准的QR码Quick Response Code是一个二维矩阵由黑白方块模块组成。但它的结构是高度标准化的并非随意排列。主要部分包括位置探测图形三个角上的“回”字形大方块用于快速定位和旋转校正。分隔符位置探测图形周围的一圈白色区域。定位图形水平和垂直的两条黑白相间的虚线用于辅助模块坐标定位。格式信息存储纠错等级和掩模模式。版本信息版本7以上标识二维码的版本大小。数据和纠错码字核心区域存储实际编码的信息和用于纠错的冗余数据。剩余位填充空白区域。在CTF题目中出题人有时会给你最“纯净”的数据——即仅包含“数据和纠错码字”区域的二进制流甚至可能已经应用了掩模。你的任务就是根据给定的二进制流反向构建出完整的、包含所有必要结构的二维码图像使其能够被标准解码器识别。注意直接画图时一个极易忽略的细节是模块Module的大小。在图像中一个“1”或“0”通常对应图像中的一个像素点。但为了确保扫描成功率生成的二维码图像中每个模块最好由多个像素例如10x10像素组成否则可能因为模块太小或边缘模糊而无法识别。这是从“数据”到“可用图像”的关键一步。3. 工具化实现从Python脚本到Excel的奇思妙想理解了原理接下来就是实操。我们有多种工具可以将二进制流变为二维码图片。3.1 使用Python和qrcode库进行标准生成如果二进制流已经是经过正确编码的、可供二维码编码器使用的数据例如一段文本的URL编码那么使用成熟的库是最快的方式。import qrcode # 假设我们解码二进制后得到的文本是某个URL或Flag data flag{This_is_a_sample_flag} qr qrcode.QRCode( version1, # 版本号控制大小1最小40最大可设为None自动确定 error_correctionqrcode.constants.ERROR_CORRECT_L, # 纠错等级 L/M/Q/H box_size10, # 每个模块的像素数 border4, # 边框包含的模块数最小为4 ) qr.add_data(data) qr.make(fitTrue) img qr.make_image(fill_colorblack, back_colorwhite) img.save(standard_qr.png) print(标准二维码已生成。)但“0和1的故事”题目往往需要你从更底层做起。3.2 手动构建二维码图像PIL库的像素级操作当题目给的是直接的像素数据时我们需要手动绘制。使用Python的PILPillow库是首选。from PIL import Image def binary_to_qr_image(binary_str, width, height, module_size10): 将二进制字符串转换为二维码图像。 :param binary_str: 二进制字符串如101010...长度应为width*height。 :param width: 二维码矩阵的逻辑宽度模块数。 :param height: 二维码矩阵的逻辑高度模块数。 :param module_size: 图像中每个模块的像素大小。 :return: PIL Image对象。 if len(binary_str) ! width * height: raise ValueError(f二进制字符串长度{len(binary_str)}与指定的图像尺寸{width}x{height}{width*height}不匹配) # 创建新图像放大module_size倍 img_width width * module_size img_height height * module_size # 初始化为白色背景 img Image.new(1, (img_width, img_height), 1) # 1模式为1位像素黑白0为黑1为白 for y in range(height): for x in range(width): index y * width x pixel_value 0 if binary_str[index] 1 else 1 # 假设1为黑 # 填充该模块对应的所有像素块 for i in range(module_size): for j in range(module_size): img.putpixel((x * module_size i, y * module_size j), pixel_value) return img # 示例假设我们知道一个5x5的二维码数据且‘1’代表黑 binary_data 1111110001101011111 # 长度需为25此处为示例实际需补全 width height 5 img binary_to_qr_image(binary_data, width, height, module_size20) img.save(manual_qr.png) img.show()关键点尺寸判断width和height是关键参数。有时题目会直接给出有时需要你根据二进制字符串长度去推测例如长度是某个完全平方数。颜色映射务必确认“1”和“0”哪个代表黑色。通常“1”代表深色黑“0”代表浅色白但有时会反过来。如果生成的二维码扫不出来可以尝试反转颜色pixel_value 1 if binary_str[index] 1 else 0。模块大小module_size不能太小否则识别困难。一般不小于5。3.3 利用Excel进行可视化分析与辅助生成你可能会好奇Excel和二维码有什么关系在CTF解题中Excel是一个强大的数据分析和可视化辅助工具尤其当二进制数据需要被审视、转换或调试时。场景一数据规整与转换假设你拿到一段非常长、没有换行的二进制字符串用眼睛看几乎不可能。你可以将其粘贴到Excel的一个单元格比如A1然后使用MID函数将其拆分成单个字符或8位一组。在B1单元格输入公式MID($A$1, ROW(), 1)然后向下拖动填充。这会将A1中的每个字符拆到一列。或者要按8位拆分可以在B1输入MID($A$1, (ROW()-1)*81, 8)然后向下拖动。场景二利用条件格式生成“热力图”这是Excel在解决此类问题中的“杀手锏”。我们可以让Excel根据单元格的值“0”或“1”自动着色从而直观地“看到”二维码的轮廓。将拆分后的单字符数据每个单元格一个“0”或“1”填充到一个矩形区域比如从B2开始宽度和高度你猜测的二维码尺寸。选中这个数据区域。点击“开始”选项卡 - “条件格式” - “新建规则”。选择“只为包含以下内容的单元格设置格式”。设置“单元格值”“等于”“1”假设1是黑色。点击“格式”在“填充”选项卡中选择纯黑色。点击确定。再新建一个规则为值等于“0”的单元格设置白色填充。调整所有单元格为正方形设置相同的行高和列宽单位用像素。这时一个二维码的雏形就会在Excel中显现出来这个方法能帮你快速验证二进制数据对应的图像大概是什么判断宽度高度设置是否正确颜色映射是否反了。如果看到了清晰的定位图形三个角上的“回”字框那就成功了一大半。你可以截图或用Excel的导出功能再导入到画图工具中微调最后用手机扫码。实操心得在CTF比赛中时间紧张。当Python脚本因为一个参数错误反复调试时用Excel快速可视化一下往往能立刻发现问题所在比如数据流方向是行优先还是列优先。它充当了一个快速的“预览器”。4. CTF实战中的进阶技巧与常见“坑点”掌握了基本方法我们来看看在真实CTF场景下围绕“二维码生成”还会有哪些变形和陷阱。4.1 尺寸与方向的陷阱尺寸未知题目只给二进制流不告诉宽度。你需要尝试不同的因数分解。如果二进制流长度是L尝试找到w和h使得w * h L。通常二维码是正方形所以先尝试w h sqrt(L)是否为整数。如果不是则可能是长方形图像或者数据包含了非图像内容如文件头。扫描顺序二进制流填充图像的顺序可能是行优先一行一行填也可能是列优先一列一列填。如果按一种顺序生成的图无法识别尝试另一种。在Python循环中交换x和y的循环次序即可测试。4.2 嵌入多层编码与隐写“0和1”可能只是第一层。例如二进制流解码后是一串Base64字符串。解码Base64得到另一串二进制或十六进制数据。该数据可能是一个PNG文件的字节流将其写入文件后得到的图片里藏着二维码。或者直接生成的二维码图片其像素最低有效位LSB里还藏着别的信息需要用Stegsolve等工具进一步分析。4.3 纠错码的利用二维码有纠错能力L/M/Q/H四个等级。出题人有时会故意损坏二维码的部分模块将一些“0”改成“1”或反之。如果你知道原始数据的一部分比如Flag的格式flag{并且知道使用的纠错等级理论上可以利用纠错算法尝试恢复。不过在实际CTF中更常见的做法是尝试用不同的掩模模式重新编码已知数据看哪个能生成与损坏区域匹配的图案或者直接用PS等工具手动修补损坏的定位图形。4.4 非标准二维码变种题目可能生成的是微型QR码、艺术二维码中间有Logo或彩色二维码。核心依然是找到那些代表数据的黑白模块。对于彩色二维码可能需要提取特定颜色通道如红色通道或计算灰度值后二值化。5. 构建完整的解题工作流与脚本范例结合以上所有点一个稳健的解题流程应该是初步分析检查文件类型file命令、查看字符串strings命令、用十六进制编辑器查看判断数据是纯文本、二进制还是其他格式。提取二进制确认核心数据是“0”和“1”的字符串。可能需要从文件、网络流量或图片的像素中提取。尝试直接转换先假设每8位是一个ASCII字符解码看看是否有明文Flag或提示。可视化探索如果上一步失败将二进制流导入Excel或用简单Python脚本尝试不同的宽度/高度和扫描顺序进行可视化预览寻找二维码的结构特征定位图形。精确生成根据可视化结果确定正确的参数宽度、高度、颜色映射、扫描顺序用PIL库生成高分辨率、带合适边框的二维码图片。解码与验证使用手机扫码软件或Python的pyzbar、opencv库进行解码。深入检查如果解码失败检查生成的图片模块是否清晰边框是否足够至少4个模块宽。如果解码成功但Flag不对考虑是否还有下层编码或隐写。下面是一个综合性的、容错性更好的示例脚本框架import argparse from PIL import Image import math def try_decode_as_text(binary_str): 尝试将二进制字符串解码为文本 print(尝试解码为ASCII文本...) # 补充前导零到8的倍数 padding 8 - len(binary_str) % 8 if padding ! 8: binary_str 0 * padding binary_str print(f补充了{padding}个前导零。) try: text .join(chr(int(binary_str[i:i8], 2)) for i in range(0, len(binary_str), 8)) if all(ord(c) 128 and c.isprintable() or c in \n\r\t for c in text): print(f可能的文本: {text[:200]}...) # 只打印前200字符 return text else: print(解码结果包含非打印字符可能不是纯文本。) except Exception as e: print(f解码失败: {e}) return None def generate_and_save_image(binary_str, width, height, is_black_oneTrue, module_size10, output_prefixqr): 根据给定参数生成图像 if len(binary_str) ! width * height: print(f警告: 数据长度{len(binary_str)} ! 指定尺寸{width}x{height}{width*height}。尝试自动调整...) # 可以尝试裁剪或填充这里简单返回 return False img_width width * module_size img_height height * module_size img Image.new(1, (img_width, img_height), 1) for y in range(height): for x in range(width): idx y * width x # 行优先 # idx x * height y # 列优先 (注释掉需要时启用) pixel_val 0 if (binary_str[idx] 1) is_black_one else 1 for dy in range(module_size): for dx in range(module_size): img.putpixel((x*module_sizedx, y*module_sizedy), pixel_val) filename f{output_prefix}_w{width}_h{height}_{1black if is_black_one else 0black}.png img.save(filename) print(f图像已保存为: {filename}) img.show() return True def main(): parser argparse.ArgumentParser(description处理‘0和1的故事’类型CTF题目) parser.add_argument(input_file, help包含二进制字符串的文本文件) parser.add_argument(--width, typeint, help图像宽度模块数) parser.add_argument(--height, typeint, help图像高度模块数) parser.add_argument(--invert, actionstore_true, help反转颜色‘0’代表黑) parser.add_argument(--module, typeint, default10, help每个模块的像素大小) args parser.parse_args() with open(args.input_file, r) as f: content f.read().strip().replace( , ).replace(\n, ).replace(\r, ) print(f读取到 {len(content)} 位二进制数据。) # 第一步尝试直接解码文本 text_result try_decode_as_text(content) if text_result and flag in text_result.lower(): print(可能在文本解码中直接发现了Flag!) # 这里可以进一步处理text_result # 第二步尝试作为图像生成 if args.width and args.height: generate_and_save_image(content, args.width, args.height, not args.invert, args.module) else: # 自动尝试可能的正方形尺寸 print(未指定尺寸尝试自动寻找正方形尺寸...) L len(content) possible_sides [] for i in range(int(math.sqrt(L)), 0, -1): if L % i 0: possible_sides.append((i, L//i)) print(f可能的尺寸宽x高: {possible_sides[:10]}) # 只显示前10种可能 for w, h in possible_sides[:5]: # 尝试前5种 if w h or abs(w-h) 5: # 优先尝试正方形或接近正方形的 print(f尝试尺寸: {w}x{h}) if generate_and_save_image(content, w, h, True, args.module, fauto_{w}x{h}): input(按回车键尝试下一个尺寸或颜色反转...) # 尝试颜色反转 if generate_and_save_image(content, w, h, False, args.module, fauto_{w}x{h}_inv): input(按回车键尝试下一个尺寸...) if __name__ __main__: main()这个脚本提供了从尝试文本解码到自动探测图像尺寸的完整流程并且每次生成图片后暂停方便你手动扫码测试。在实际比赛中这种系统化的尝试方法比盲目猜测高效得多。最后解决这类问题的乐趣在于它强迫你从最底层的比特流开始思考一步步构建出有意义的信息。这不仅是CTF技能更是理解数据表示、编码和计算机图形学基础的一个绝佳窗口。下次再看到“0和1的故事”希望你不仅能想到二维码还能联想到图像隐写、数据恢复和协议分析等更广阔的场景。

相关新闻

Spring Boot构建流浪宠物救助平台的技术实践

Spring Boot构建流浪宠物救助平台的技术实践

1. 项目概述:流浪宠物救助平台的核心价值去年参与某动物保护组织的技术咨询时,他们提到最大的痛点就是救助信息分散在各个微信群和Excel表格里。这正是Spring Boot技术栈最能发挥价值的场景——通过标准化系统整合零散数据,建立可追溯的救助闭…

2026/10/18 18:03:23 阅读更多 →
紧急通知:小红书已上线AI内容标识系统!未打标账号曝光下降63%,立即启用这3种合规打标方式

紧急通知:小红书已上线AI内容标识系统!未打标账号曝光下降63%,立即启用这3种合规打标方式

更多请点击: https://kaifayun.com 第一章:AI做小红书账号 AI正深度介入小红书内容生态,从选题策划、图文生成到评论互动,均可实现自动化协同。核心在于构建“提示词工程多模态模型平台接口适配”的闭环工作流。 内容生成策略 小…

2026/10/20 5:25:08 阅读更多 →
飞书机器人消息延迟超3秒?扣子侧链路追踪实战(附可复用的Latency诊断脚本)

飞书机器人消息延迟超3秒?扣子侧链路追踪实战(附可复用的Latency诊断脚本)

更多请点击: https://kaifayun.com 第一章:飞书机器人消息延迟超3秒?扣子侧链路追踪实战(附可复用的Latency诊断脚本) 飞书机器人在接入扣子(Coze)平台后,偶发消息端到端延迟超过3…

2026/10/18 14:24:16 阅读更多 →

最新新闻

十大AI论文工具测评:从文献综述到定稿的实战指南

十大AI论文工具测评:从文献综述到定稿的实战指南

凌晨三点半,我收到一位学弟的消息:“文献综述又被导师打回来了,说写得像‘综述生成器’跑出来的。怎么办?”这个场景太常见了。2026年聊到研究生毕业论文写作,已经绕不开AI工具这个话题。它们确实能显著提速&#xff0…

2026/10/20 6:51:43 阅读更多 →
Flink集群架构与运行模式全解析:从角色分工到生产选型排障

Flink集群架构与运行模式全解析:从角色分工到生产选型排障

如果你已经开始在项目里用Flink写流式作业,大概率会碰到这类场景:本地能跑通的WordCount,一提交到集群上就卡住不动;Web UI里明明有4个TaskManager,任务却一直停在SCHEDULED;设置了并行度10,却有…

2026/10/20 6:51:43 阅读更多 →
雷达目标特性仿真:MATLAB实现RCS计算与微多普勒提取

雷达目标特性仿真:MATLAB实现RCS计算与微多普勒提取

简介:雷达目标特性仿真是雷达系统设计与目标识别的重要基础。这套以MATLAB为平台的代码包,面向从事电磁仿真和雷达信号处理的研究者与工程师,围绕微动、成像、极化和雷达散射截面四项核心内容,提供从信号建模、算法实现到特征分析…

2026/10/20 6:51:43 阅读更多 →
YOLO推理服务化实践:TensorRT加速与Triton部署全攻略

YOLO推理服务化实践:TensorRT加速与Triton部署全攻略

1. 为什么部署YOLO要绕这么一大圈先说说我自己的经历。前阵子把一个YOLO检测模型推到生产环境,手里拿到的只有一份训练好的权重。最开始真没想太多,图省事直接用Flask加载权重,收到请求就forward一次、解析结果、返回JSON。单张图跑起来体感并…

2026/10/20 6:51:43 阅读更多 →
内核调度器与实时优先级:机器人低延迟优化实战

内核调度器与实时优先级:机器人低延迟优化实战

做了这么多年机器人系统,我越来越觉得,实时性问题的根子往往不在ROS/ROS2应用代码里,而在更底下那层——任务到底由谁调度、以什么策略调度。之前接过一个移动底盘的活儿,现象很典型:ROS2节点的控制指令在低负载时延稳…

2026/10/20 6:51:43 阅读更多 →
对齐的幻觉:AI模型对齐中的认知陷阱与实操避坑指南

对齐的幻觉:AI模型对齐中的认知陷阱与实操避坑指南

1. 从“对齐的幻觉”说起:一个被过度简化的复杂命题“对齐”这个词,在过去两年里被提及的频率高得离谱。不管是大模型训练、产品设计,还是团队协作,似乎只要挂上“对齐”两个字,问题就解决了一半。但实际情况是&#x…

2026/10/20 6:50:43 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →