
1. 项目概述为什么我们需要自动化CTF MISC解题如果你参加过几场CTF比赛尤其是MISC杂项方向一定有过这样的体验面对一个压缩包套娃手动解压、改后缀、再解压重复十几次或者拿到一串Base64编码的字符串解码后发现是另一串编码循环往复直到找到Flag。这个过程不仅枯燥而且极易出错一个手滑就可能前功尽弃。更关键的是在紧张的比赛环境中时间就是分数手动操作的低效会让你错失良机。这个项目的核心就是告别这种“体力劳动”将重复、机械的MISC解题步骤用Python脚本自动化。它不是一个全能的AI解题机器人而是一个高度定制化、可扩展的“解题流水线”。通过编写脚本你可以将常见的文件处理、编码分析、数据提取等操作固化下来实现一键执行。这不仅仅是节省时间更是将解题思路从“手工作坊”升级为“工业化生产”让你能更专注于分析线索和逻辑推理本身。简单来说这个项目适合所有CTF爱好者无论你是刚入门的新手想通过实践学习Python和文件处理还是有一定经验的中阶玩家希望提升解题效率和稳定性甚至是团队中的“工具人”需要为队友提供快速解题脚本。接下来我将以一个实战案例为线索拆解如何构建这样一个自动化流程并附上可直接复用的代码。2. 核心思路与工具箱设计自动化解题脚本的核心思想是“模式识别”与“流程封装”。MISC题目虽然千变万化但很多基础操作是共通的。我们的脚本就是要识别这些通用模式并将处理流程模块化。2.1 识别高频操作模式根据我的经验MISC题目中超过70%的“体力活”集中在以下几类文件递归解压与类型探测这是最常见的“套娃”题。文件可能是.zip,.rar,.7z,.tar.gz, 甚至伪装成图片的压缩包。脚本需要能自动识别真实文件类型并递归解压直到出现非压缩文件或找到目标文件。多层编码/加密识别与解码字符串可能经过Base64、Base32、Hex、URL编码、ROT13、摩斯电码、二进制转换等多重包装。脚本需要能自动尝试多种解码方式并判断解码结果是否“像”下一层数据或Flag。文件隐写分析自动化虽然深度隐写分析如LSB、DCT依赖专业工具但脚本可以自动化执行一些前置步骤如用binwalk提取内嵌文件、用exiftool读取元数据、用strings提取可疑字符串、批量调整图片的宽度高度以修复二维码等。数据筛选与Flag模式匹配从海量数据如网络流量包、日志文件中快速筛选出符合Flag格式如flag{.*},CTF{.*}, 特定哈希值的字符串。2.2 工具选型与依赖库我们的脚本将主要依赖Python标准库和几个强大的第三方库确保轻量且高效。以下是核心工具箱文件处理os,shutil: 用于文件和目录的遍历、移动、删除。zipfile,tarfile: Python标准库处理ZIP和TAR压缩包。patool(推荐) 或pyunpack: 这是一个“瑞士军刀”库通过调用系统已安装的后端程序如7z,unrar可以统一处理几乎所有格式的压缩包ZIP, RAR, 7Z, ACE等。这比我们用subprocess一个个调用命令行工具要优雅和稳定得多。编码/加密base64,binascii: 处理Base64, Hex等编码。codecs: 处理一些简单的编码。Crypto(PyCryptodome): 如果题目涉及古典密码如凯撒、维吉尼亚或简单对称加密可能需要这个库。但对于自动化脚本我们更侧重“识别”而非“破解”。文件类型识别magic(python-magic): 这是file命令的Python接口通过读取文件魔数来准确判断文件类型比依赖文件后缀名可靠得多。这是对抗“伪加密”和“改后缀”题目的关键。其他实用工具subprocess: 调用外部命令行工具如exiftool,binwalk,steghide如果已知密码等。re(正则表达式): 用于匹配Flag模式从杂乱文本中提取关键信息。注意使用patool和python-magic前需要安装。建议使用pip安装pip install patool python-magic。在Windows上python-magic可能需要额外安装magic的二进制文件或者使用pip install python-magic-bin。2.3 脚本架构设计一个健壮的自动化脚本不应该是一个巨型的“if-else”怪物。我建议采用模块化、管道化的设计输入层接收一个文件或目录路径作为输入。预处理模块用python-magic识别真实文件类型进行初步分类是压缩包是图片是文本。处理管道压缩包处理流水线递归解压直到提取出所有非压缩的“叶子文件”。解压后的文件重新进入预处理模块判断是否需要继续解压。编码分析流水线针对文本文件或从文件中提取的字符串尝试一系列解码操作Base64 - Hex - ROT13等并使用启发式方法如检查解码后是否包含可打印字符、特定关键字判断解码是否“成功”或需要继续。隐写分析流水线对图片、音频等文件自动执行exiftool、binwalk、strings等命令将输出保存到日志文件供后续分析。输出与报告层将所有提取出的潜在“候选文件”、解码出的可疑字符串、以及处理日志集中输出到一个指定目录方便你进行最终的人工审查。这种设计的好处是每个模块职责单一易于调试和扩展。例如当你遇到一种新的编码只需要在“编码分析流水线”中添加一个新的解码函数即可。3. 实战代码解析构建递归解压与编码探测脚本下面我将结合一个模拟真实场景的案例展示核心模块的代码实现。假设我们拿到一个初始文件challenge.zip里面可能套了多层压缩包并且最终文件里藏着经过多重编码的Flag。3.1 核心模块一智能文件类型识别与递归解压首先我们实现最关键的递归解压功能。这里的关键是使用python-magic来识别文件而不是相信文件后缀。import os import shutil import patoolib import magic from pathlib import Path def get_real_file_type(file_path): 使用magic库获取文件的真实MIME类型。 返回类型字符串如 application/zip, image/png, text/plain。 try: mime magic.from_file(file_path, mimeTrue) return mime except Exception as e: print(f[!] 无法识别文件 {file_path} 的类型: {e}) return None def is_archive_file(mime_type): 判断给定的MIME类型是否属于常见的压缩包格式。 archive_types [ application/zip, application/x-rar-compressed, application/x-7z-compressed, application/gzip, application/x-tar, application/x-bzip2, application/x-lzip, application/x-xz, ] return mime_type in archive_types def extract_archive(archive_path, extract_dir): 使用patoolib解压任意格式的压缩包到指定目录。 try: # patoolib会自动根据文件内容选择解压工具 patoolib.extract_archive(archive_path, outdirextract_dir) print(f[] 成功解压: {archive_path} - {extract_dir}) return True except patoolib.util.PatoolError as e: print(f[-] 解压失败 {archive_path}: {e}) return False except Exception as e: print(f[-] 解压过程发生未知错误 {archive_path}: {e}) return False def recursive_extract(start_path, output_base_dir, max_depth20, current_depth0): 递归解压一个文件或目录中的所有压缩包。 :param start_path: 起始文件或目录路径 :param output_base_dir: 所有解压内容的输出根目录 :param max_depth: 最大递归深度防止无限套娃 :param current_depth: 当前递归深度 if current_depth max_depth: print(f[!] 达到最大递归深度 {max_depth}停止解压: {start_path}) return if os.path.isfile(start_path): file_path start_path # 为当前文件创建一个专属解压目录以文件名命名避免混乱 file_stem Path(file_path).stem extract_dir os.path.join(output_base_dir, fdepth_{current_depth}_{file_stem}) os.makedirs(extract_dir, exist_okTrue) mime_type get_real_file_type(file_path) if mime_type and is_archive_file(mime_type): print(f[*] 深度 {current_depth}: 识别为压缩包 {mime_type} - {file_path}) if extract_archive(file_path, extract_dir): # 解压成功后遍历解压目录对里面的每个文件继续递归解压 for item in os.listdir(extract_dir): item_path os.path.join(extract_dir, item) recursive_extract(item_path, output_base_dir, max_depth, current_depth 1) else: # 解压失败可能不是标准压缩包或已损坏将其作为普通文件复制到输出目录 shutil.copy(file_path, os.path.join(extract_dir, Path(file_path).name)) else: # 不是压缩包直接复制到当前深度目录 print(f[*] 深度 {current_depth}: 非压缩文件 - {file_path} (类型: {mime_type})) shutil.copy(file_path, os.path.join(extract_dir, Path(file_path).name)) elif os.path.isdir(start_path): # 如果是目录遍历目录下的每个文件进行处理 for item in os.listdir(start_path): item_path os.path.join(start_path, item) recursive_extract(item_path, output_base_dir, max_depth, current_depth) # 使用示例 if __name__ __main__: input_file challenge.zip # 你的初始题目文件 output_dir extracted_results os.makedirs(output_dir, exist_okTrue) recursive_extract(input_file, output_dir) print(f[*] 递归解压完成。所有文件已整理至: {output_dir})代码要点与避坑指南深度控制max_depth参数至关重要。真实的CTF题可能有几十层套娃但没有上限的递归可能导致内存耗尽或磁盘塞满。设置一个合理的上限如20-50并在达到后停止然后人工检查最深层的文件。目录组织脚本为每一层解压创建了以depth_X_filename命名的子目录。这能清晰展示解压的层级结构比把所有文件扔到一个文件夹里要清晰得多。解压后你可以快速定位到最深层即没有继续解压的目录进行检查。依赖处理patoolib本身只是一个前端它需要系统安装有对应的解压后端如7z、unrar。在Linux上通常安装p7zip-full和unrar即可。在Windows上你需要确保7-Zip已安装并将其路径添加到系统环境变量或者直接使用7-Zip的命令行版本。这是该脚本能稳定运行的前提。错误处理解压过程可能因为文件损坏、密码保护或特殊格式而失败。代码中进行了基本的异常捕获并将失败的文件原样复制出来防止数据丢失方便后续手动处理。3.2 核心模块二多层编码探测与自动解码解压出最终文件后我们常常面对的是包含编码字符串的文本文件。下面实现一个自动尝试多种解码的函数。import base64 import binascii import codecs import re def is_likely_plaintext(data, threshold0.9): 启发式判断数据是否可能是可读的明文。 计算可打印字符的比例超过阈值则认为可能是明文。 if isinstance(data, bytes): try: data data.decode(utf-8, errorsignore) except: return False if not isinstance(data, str): return False if not data: return False printable_count sum(1 for c in data if c.isprintable() or c in \t\n\r) return (printable_count / len(data)) threshold def try_decode_base64(data): 尝试Base64解码。支持处理字符串和字节。 if isinstance(data, str): data data.encode(utf-8) # Base64解码可能抛出binascii.Error try: decoded base64.b64decode(data, validateTrue) # 检查解码后是否是文本 try: decoded_str decoded.decode(utf-8) return decoded_str, True except UnicodeDecodeError: # 解码成功但不是UTF-8文本返回字节 return decoded, True except (binascii.Error, ValueError): return data, False def try_decode_hex(data): 尝试Hex解码。 if isinstance(data, str): # 移除可能存在的空格或0x前缀 data_str data.strip().replace( , ).replace(0x, ) # 检查是否只包含十六进制字符 if not re.fullmatch(r[0-9a-fA-F], data_str): return data, False try: decoded_bytes bytes.fromhex(data_str) try: return decoded_bytes.decode(utf-8), True except UnicodeDecodeError: return decoded_bytes, True except ValueError: return data, False return data, False def try_decode_rot13(data): 尝试ROT13解码。仅对字符串有效。 if isinstance(data, str): return codecs.encode(data, rot_13), True return data, False def deep_decode(data, max_layers10, current_layer0, seenNone): 递归尝试多种解码方式。 :param data: 初始数据str或bytes :param max_layers: 最大解码层数 :param current_layer: 当前层数 :param seen: 用于检测循环的集合 :return: 一个列表包含每一层解码的结果和使用的解码器 if seen is None: seen set() # 防止无限递归用数据的哈希值作为标识 data_hash hash(str(data)) if data_hash in seen: return [] seen.add(data_hash) if current_layer max_layers: return [] results [] # 定义解码器尝试顺序 decoders [ (base64, try_decode_base64), (hex, try_decode_hex), (rot13, try_decode_rot13), # 可以继续添加URL解码、Base32、摩斯电码等 ] for decoder_name, decoder_func in decoders: decoded_data, success decoder_func(data) if success: layer_info { layer: current_layer 1, decoder: decoder_name, input_preview: str(data)[:50] (... if len(str(data)) 50 else ), output: decoded_data, output_preview: (str(decoded_data)[:100] ...) if len(str(decoded_data)) 100 else str(decoded_data) } results.append(layer_info) # 如果解码后看起来像文本并且可能还有编码就继续递归解码 if isinstance(decoded_data, (str, bytes)) and not is_likely_plaintext(decoded_data): sub_results deep_decode(decoded_data, max_layers, current_layer 1, seen) results.extend(sub_results) # 重要一旦某一层解码成功我们通常按该路径深入但也可以注释掉break以尝试所有可能分支 # break return results def scan_file_for_encoded_strings(file_path): 扫描文件查找可能是编码字符串的行并尝试解码。 potential_flags [] try: with open(file_path, rb) as f: content f.read() # 尝试将整个文件内容作为原始数据解码一次有时flag被直接编码在整个文件中 whole_file_results deep_decode(content, max_layers5) if whole_file_results: print(f[*] 文件整体解码路径:) for res in whole_file_results: print(f 第{res[layer]}层 [{res[decoder]}] - {res[output_preview]}) # 检查输出中是否有flag模式 if re.search(rflag{.*?}|CTF{.*?}, str(res[output])): potential_flags.append(res[output]) # 按行扫描寻找像编码字符串的行 try: text_content content.decode(utf-8, errorsignore) except: text_content content.decode(latin-1, errorsignore) # 尝试其他编码 for line_num, line in enumerate(text_content.splitlines(), 1): line line.strip() # 启发式长度适中且包含非字母数字的常见编码字符如/等Base64特征 if 20 len(line) 500 and re.search(r[/], line): results deep_decode(line, max_layers5) if results: print(f[*] 文件 {file_path} 第{line_num}行发现编码字符串: {line[:50]}...) for res in results: print(f 第{res[layer]}层 [{res[decoder]}] - {res[output_preview]}) if re.search(rflag{.*?}|CTF{.*?}, str(res[output])): potential_flags.append(res[output]) except Exception as e: print(f[-] 处理文件 {file_path} 时出错: {e}) return potential_flags # 使用示例扫描解压结果目录中的所有文本文件 if __name__ __main__: extracted_root extracted_results all_flags [] for root, dirs, files in os.walk(extracted_root): for file in files: file_path os.path.join(root, file) # 简单通过后缀判断是否为文本文件更准确可用python-magic if file.endswith((.txt, .log, .xml, .json, .html, .htm)): print(f\n[*] 扫描文件: {file_path}) flags scan_file_for_encoded_strings(file_path) if flags: all_flags.extend(flags) print(f\n[] 潜在Flag发现: {all_flags})代码要点与避坑指南解码顺序代码中按Base64 - Hex - ROT13的顺序尝试。这个顺序是基于频率经验。Base64在CTF中最常见其特征末尾的、字符集A-Za-z0-9/也容易识别。Hex也极常见。你可以根据比赛风格调整顺序或增加更多解码器如base32,url解码,ascii移位。递归与循环检测deep_decode函数使用seen集合来记录已处理数据的哈希防止因数据解码后变回原样如ROT13两次或进入其他循环而导致无限递归。启发式判断is_likely_plaintext函数是一个简单的启发式方法用于判断解码后的数据是否已经是可读明文。如果已经是明文通常就不需要继续解码了。这个判断不是100%准确但能有效避免过度解码并将明显无意义的数据如解码出乱码过滤掉。分支探索在deep_decode中当某一层解码成功时代码默认会break即只沿着第一个成功的解码器路径深入。这是为了效率。但有些题目可能设计成需要先Hex再Base64而你的顺序是Base64先成功但解出乱码。更稳健的做法是注释掉break让脚本探索所有可能的解码路径分支但这会显著增加计算量。在实际比赛中可以根据时间权衡。Flag模式匹配脚本使用简单的正则表达式flag{.*?}|CTF{.*?}来匹配Flag。你需要根据比赛规则调整这个模式有些比赛可能用FLAG{...}、flag:...或者只是一个特定的哈希值。4. 整合与进阶构建完整的解题流水线将上述模块整合并添加一些辅助功能就能形成一个更完整的自动化脚本框架。4.1 主控脚本框架#!/usr/bin/env python3 CTF MISC 自动化解题脚本框架 作者你的名字 功能递归解压 编码探测 基础隐写分析 import os import sys import logging from pathlib import Path # 导入自定义模块 (假设上面的函数保存在 ctf_utils.py 中) # from ctf_utils import recursive_extract, scan_file_for_encoded_strings, deep_decode # 为了演示我们假设函数都在同一个文件 def setup_logging(): 配置日志方便记录脚本运行过程。 logging.basicConfig( levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s, handlers[ logging.FileHandler(ctf_auto_solver.log), logging.StreamHandler(sys.stdout) ] ) return logging.getLogger(__name__) def run_binwalk_analysis(file_path, output_dir): 对文件运行binwalk提取内嵌文件。 import subprocess log_file os.path.join(output_dir, fbinwalk_{Path(file_path).name}.log) try: with open(log_file, w) as f: # 先扫描 result_scan subprocess.run([binwalk, file_path], capture_outputTrue, textTrue, checkFalse) f.write( Binwalk 扫描结果 \n) f.write(result_scan.stdout) if result_scan.stderr: f.write(\n 错误信息 \n) f.write(result_scan.stderr) # 如果扫描到东西尝试提取 if DECIMAL in result_scan.stdout: extract_dir os.path.join(output_dir, fbinwalk_extracted_{Path(file_path).stem}) os.makedirs(extract_dir, exist_okTrue) f.write(f\n 提取文件到 {extract_dir} \n) result_extract subprocess.run([binwalk, -e, --directory, extract_dir, file_path], capture_outputTrue, textTrue, checkFalse) f.write(result_extract.stdout) if result_extract.stderr: f.write(\n 提取错误信息 \n) f.write(result_extract.stderr) return extract_dir except FileNotFoundError: logging.warning(f未找到binwalk命令请确保已安装。) except Exception as e: logging.error(f运行binwalk分析 {file_path} 时出错: {e}) return None def main(target_path): logger setup_logging() logger.info(f开始处理目标: {target_path}) # 1. 创建输出主目录 base_output_dir ctf_auto_output os.makedirs(base_output_dir, exist_okTrue) # 2. 递归解压阶段 extracted_dir os.path.join(base_output_dir, 01_extracted) logger.info(f阶段1: 递归解压 - {extracted_dir}) recursive_extract(target_path, extracted_dir) # 3. 遍历解压后的所有文件进行分类处理 for root, dirs, files in os.walk(extracted_dir): for file in files: file_path os.path.join(root, file) rel_path os.path.relpath(file_path, extracted_dir) file_type get_real_file_type(file_path) logger.info(f处理文件: {rel_path} (类型: {file_type})) # 3.1 如果是图片/音频/可执行文件等进行基础隐写分析 if file_type and any(img in file_type for img in [image/, audio/, video/]): analysis_dir os.path.join(base_output_dir, 02_steg_analysis, rel_path) os.makedirs(os.path.dirname(analysis_dir), exist_okTrue) # 运行binwalk run_binwalk_analysis(file_path, os.path.dirname(analysis_dir)) # 可以在这里添加exiftool, strings等命令 # run_exiftool(file_path, ...) # run_strings(file_path, ...) # 3.2 如果是文本文件进行编码扫描 if file_type and text/ in file_type: logger.info(f 对文本文件进行编码扫描...) flags scan_file_for_encoded_strings(file_path) if flags: logger.info(f [!] 在 {rel_path} 中发现潜在Flag: {flags}) # 将Flag保存到单独文件 flag_report os.path.join(base_output_dir, 03_potential_flags.txt) with open(flag_report, a, encodingutf-8) as f: f.write(f文件: {rel_path}\n) for flag in flags: f.write(f 可能Flag: {flag}\n) f.write(-*50 \n) # 3.3 其他类型文件可以记录或进行其他处理 # ... logger.info(f处理完成。所有结果保存在: {base_output_dir}) logger.info(f请检查以下文件:) logger.info(f - 解压文件: {extracted_dir}) logger.info(f - 隐写分析日志: {base_output_dir}/02_steg_analysis/) logger.info(f - 潜在Flag报告: {base_output_dir}/03_potential_flags.txt) if __name__ __main__: if len(sys.argv) ! 2: print(f用法: {sys.argv[0]} 目标文件或目录) sys.exit(1) main(sys.argv[1])4.2 使用流程与实战心得准备环境确保你的Python环境安装了所需库pip install patoolib python-magic并且系统安装了必要的后端工具如7-Zip。运行脚本将上面的代码整合到一个Python文件中例如ctf_auto.py。在命令行中运行python ctf_auto.py challenge.zip。分析结果脚本运行后会在当前目录生成ctf_auto_output文件夹里面按阶段组织所有结果。你的首要任务是查看03_potential_flags.txt里面列出了所有匹配到Flag模式的字符串。其次去01_extracted目录下找到最深层的那些非压缩文件手动检查。最后查看02_steg_analysis下的日志看binwalk是否提取出了隐藏文件。实战心得与注意事项不要完全依赖自动化这个脚本是“辅助”工具不是“解题”工具。它帮你完成了80%的重复劳动但最后20%的关键分析如识别出是某种冷门编码、猜出密码、发现图片中的细微差别依然需要你的智慧和经验。脚本的输出是“线索”而不是“答案”。灵活调整解码器如果题目来自某个特定比赛或平台其出题风格往往固定。比如某平台喜欢用Base32你就可以把Base32解码的优先级调高。将解码器函数做成可配置的列表方便调整。处理加密压缩包脚本目前无法处理带密码的压缩包。对于这类题目你需要先用其他方式如暴力破解、社工、注释提示找到密码然后可以修改extract_archive函数或者手动解压后再用脚本处理内部文件。性能考虑递归解压和深度解码在文件很多或层数很深时可能较慢。可以考虑加入多线程处理独立文件但对于有依赖顺序的操作如一层层解压要小心。日志是你的朋友详细的日志如我们使用的logging模块能让你在脚本运行后清晰地复盘整个过程知道在哪一步解压出了什么在哪一步尝试了哪种解码这对于调试脚本和理解题目结构至关重要。5. 常见问题与排查技巧在实际使用中你肯定会遇到各种问题。下面是一些典型场景和解决思路。问题1脚本报错magic库找不到或无法识别文件。排查这是python-magic库最常见的安装问题。在Linux上你可能需要安装libmagic系统库sudo apt-get install libmagic-dev。在Windows上最省事的方法是安装python-magic-binpip install python-magic-bin它包含了预编译的二进制文件。备用方案如果实在搞不定python-magic可以暂时回退到使用文件后缀名判断但这样对抗“改后缀”的题目会失效。或者使用subprocess调用系统的file命令。问题2patoolib解压某些格式如RAR失败。排查patoolib需要调用系统工具。对于RAR格式你需要确保系统安装了unrarLinux或已将WinRAR/7-Zip的命令行工具路径添加到系统环境变量。在Linux上安装unrar和p7zip-full通常能覆盖绝大多数格式。错误信息仔细查看patoolib打印的错误信息通常会明确指出缺少哪个后端程序。问题3递归解压后文件太多太乱找不到重点。技巧这是我们设计目录结构depth_X_filename的原因。直接按修改时间排序查看最晚创建的那些目录里的文件它们很可能就是最终的“叶子”文件。另外可以在脚本最后增加一个“文件类型统计”功能输出所有非压缩文件的类型和数量帮你快速定位到可疑的如单一的、很大的文件。问题4编码探测脚本没有找到Flag但我知道Flag就在文件里。排查步骤检查Flag模式你的正则表达式是否匹配了题目实际的Flag格式有些比赛格式很特别。检查解码深度max_layers是否设置得太小可能Flag藏在更深层的编码里。检查解码顺序题目是否用了冷门编码如Base58、Base91、UUencode或自定义编码你需要将对应的解码函数添加到decoders列表中。检查输入数据脚本是否扫描了正确的文件有时Flag藏在文件头尾的二进制数据里而不是文本行中。可以尝试用hexdump或xxd命令查看文件原始十六进制寻找规律。手动验证选取文件中的一小段可疑字符串用CyberChef一个强大的在线编解码网站手动尝试各种解码如果成功就把这个解码逻辑加到你的脚本里。问题5面对一个全新的、完全没思路的MISC题这个脚本还能帮上忙吗回答当然可以。即使没有任何思路你也可以把题目文件丢给脚本。它的价值在于自动化信息收集自动完成解压、提取内嵌文件、读取元数据、提取字符串等基础工作为你呈现所有“原材料”。减少干扰脚本处理完后你面对的不再是一个黑盒的初始文件而是一堆整理好的、可能包含线索的中间文件。这能帮你排除大量无效的重复操作直接进入分析阶段。启发思路有时看着脚本解码出来的中间结果即使是一堆乱码或者binwalk提取出的奇怪文件能突然给你带来解题灵感。最后这个脚本是一个起点而不是终点。真正的威力在于你根据自己遇到的题目类型不断对它进行定制和扩展。例如增加对PDF文件的分析用pdf-parser提取对象、对流量包文件.pcapng的自动协议分析用tshark提取特定字段、或者集成一些简单的密码学破解函数。久而久之你就会拥有一个独一无二、高度适应你解题风格的自动化武器库。