news 2026/5/28 5:56:50

[GHCTF 2025]Mio?Ryo?Soyo?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
[GHCTF 2025]Mio?Ryo?Soyo?

PyInstaller 打包,使用 pyinstxtractor-ng 解包

反编译

使用 uncompyle6 将 pyc 转成 py 源文件

uncompyle6 program.pyc > program.py

# uncompyle6 version 3.9.2 # Python bytecode version base 3.8.0 (3413) # Decompiled from: Python 3.8.0 (tags/v3.8.0:fa919fd, Oct 14 2019, 19:37:50) [MSC v.1916 64 bit (AMD64)] # Embedded file name: program.py from Secret import * if __name__ == "__main__": print("输入:", end="") aaaaaaaaaaaaa = input() wwwwwwwwwww = l(aaaaaaaaaaaaa) if sssssssssssss == wwwwwwwwwww.encode(): print("哦,对的。") else: print("哎,并非。") input() # okay decompiling program.pyc

发现导入了自定义包 Secret

在PYZ-00.pyz_extracted 文件夹下找到 Secret.pyc

同样的反编译uncompyle6 Secret.pyc > Secret.py

# uncompyle6 version 3.9.2 # Python bytecode version base 3.8.0 (3413) # Decompiled from: Python 3.8.0 (tags/v3.8.0:fa919fd, Oct 14 2019, 19:37:50) [MSC v.1916 64 bit (AMD64)] # Embedded file name: Secret.py from SecretEncrypt import * sssssssssssss = bytes([57, 118, 33, 114, 68, 56, 117, 115, 34, 52, 52, 95, 78, 40, 49, 59, 95, 85, 63, 122, 54, 33, 77, 110, 49, 54, 34, 109, 106, 122, 60, 92, 108, 91, 61, 51, 42, 62, 35, 38, 52, 67, 62, 122, 116, 48, 76, 50, 67, 51, 59, 41, 122, 45, 45, 51, 90]) def l(_: str): return SSSooooyyooo(MMMMiiiiiio.MMMMiiooooooo(SSSooooyyooo(RRRRyyooo.RRRRRRRyyyyooooo(_.encode()), 7).encode()), 9) # okay decompiling Secret.pyc

导入了自定义包SecretEncrypt

同样uncompyle6 SecretEncrypt.pyc > SecretEncrypt.py

# uncompyle6 version 3.9.2 # Python bytecode version base 3.8.0 (3413) # Decompiled from: Python 3.8.0 (tags/v3.8.0:fa919fd, Oct 14 2019, 19:37:50) [MSC v.1916 64 bit (AMD64)] # Embedded file name: SecretEncrypt.py import math class MMMMiiiiiio: MMiiiiiiooo = "".join([chr(Miiooooooooo) for Miiooooooooo in range(33, 118)]) @staticmethod def MMMMiiooooooo(MMMMMMMMMiiiooo: bytes) -> str: MMMMiiiiioooooooooo = "" MMMMMMMiiiiioo = (4 - len(MMMMMMMMMiiiooo) % 4) % 4 MMMMMMMMMiiiooo += b'\x00' * MMMMMMMiiiiioo for MMMMMMiiiiiio in range(0, len(MMMMMMMMMiiiooo), 4): MMMMiiiiiiooooo = MMMMMMMMMiiiooo[MMMMMMiiiiiio[:MMMMMMiiiiiio + 4]] MMMMMMiiioooooo = int.from_bytes(MMMMiiiiiiooooo, "big") MMMMMMMiiooooooooo = "" for _ in range(5): MMMMMMMiiooooooooo = MMMMiiiiiio.MMiiiiiiooo[MMMMMMiiioooooo % 85] + MMMMMMMiiooooooooo MMMMMMiiioooooo //= 85 else: MMMMiiiiioooooooooo += MMMMMMMiiooooooooo else: if MMMMMMMiiiiioo: MMMMiiiiioooooooooo = MMMMiiiiioooooooooo[None[:-MMMMMMMiiiiioo]] return MMMMiiiiioooooooooo class RRRRyyooo: RRRRyooooooo = "".join([chr(RRRRRRRyyyyyoooo) for RRRRRRRyyyyyoooo in range(48, 93)]) @staticmethod def RRRRRRRyyyyooooo(RRRRRRyyyoooooo: bytes) -> str: RRRRyyyyyooo = [] RRyyyyyyyyyoooooo = 0 while RRyyyyyyyyyoooooo < len(RRRRRRyyyoooooo): if RRyyyyyyyyyoooooo + 1 < len(RRRRRRyyyoooooo): RRRRRRRRRyyo = RRRRRRyyyoooooo[RRyyyyyyyyyoooooo] << 8 | RRRRRRyyyoooooo[RRyyyyyyyyyoooooo + 1] RRRRyyyyyooo.append(RRRRyyooo.RRRRyooooooo[RRRRRRRRRyyo % 45]) RRRRRRRRRyyo //= 45 RRRRyyyyyooo.append(RRRRyyooo.RRRRyooooooo[RRRRRRRRRyyo % 45]) RRRRRRRRRyyo //= 45 RRRRyyyyyooo.append(RRRRyyooo.RRRRyooooooo[RRRRRRRRRyyo]) RRyyyyyyyyyoooooo += 2 else: RRRRRRRRRyyo = RRRRRRyyyoooooo[RRyyyyyyyyyoooooo] RRRRyyyyyooo.append(RRRRyyooo.RRRRyooooooo[RRRRRRRRRyyo % 45]) RRRRRRRRRyyo //= 45 RRRRyyyyyooo.append(RRRRyyooo.RRRRyooooooo[RRRRRRRRRyyo]) RRyyyyyyyyyoooooo += 1 return "".join(RRRRyyyyyooo) def SSSooooyyooo(SSSSooyoooooo, SSSSSoyyooooo): SSoooooyyyyyyoo = [] for SSSSSSSSSoyooo in SSSSooyoooooo: if "a" <= SSSSSSSSSoyooo <= "z": SSSSoooyooooooo = (ord(SSSSSSSSSoyooo) - ord("a") + SSSSSoyyooooo) % 26 SSoooooyyyyyyoo.append(chr(ord("a") + SSSSoooyooooooo)) elif "0" <= SSSSSSSSSoyooo <= "9": SSSSoooyooooooo = (ord(SSSSSSSSSoyooo) - ord("0") - SSSSSoyyooooo) % 10 SSoooooyyyyyyoo.append(chr(ord("0") + SSSSoooyooooooo)) else: SSoooooyyyyyyoo.append(SSSSSSSSSoyooo) else: return "".join(SSoooooyyyyyyoo) # okay decompiling SecretEncrypt.pyc

优化变量名

# uncompyle6 version 3.9.2 # Python bytecode version base 3.8.0 (3413) # Decompiled from: Python 3.8.0 (tags/v3.8.0:fa919fd, Oct 14 2019, 19:37:50) [MSC v.1916 64 bit (AMD64)] # Embedded file name: program.py from Secret import * if __name__ == "__main__": print("输入:", end="") user_input = input() encrypted_input = encrypt_flow(user_input) if TARGET_HASH == encrypted_input.encode(): print("哦,对的。") else: print("哎,并非。") input() # okay decompiling program.pyc
# uncompyle6 version 3.9.2 # Python bytecode version base 3.8.0 (3413) # Decompiled from: Python 3.8.0 (tags/v3.8.0:fa919fd, Oct 14 2019, 19:37:50) [MSC v.1916 64 bit (AMD64)] # Embedded file name: Secret.py from SecretEncrypt import * TARGET_HASH = bytes([57, 118, 33, 114, 68, 56, 117, 115, 34, 52, 52, 95, 78, 40, 49, 59, 95, 85, 63, 122, 54, 33, 77, 110, 49, 54, 34, 109, 106, 122, 60, 92, 108, 91, 61, 51, 42, 62, 35, 38, 52, 67, 62, 122, 116, 48, 76, 50, 67, 51, 59, 41, 122, 45, 45, 51, 90]) def encrypt_flow(plain_text: str): return caesar_cipher(Base85Encoder.encode(caesar_cipher(Base45Encoder.encode(plain_text.encode()), 7).encode()), 9) # okay decompiling Secret.pyc
# uncompyle6 version 3.9.2 # Python bytecode version base 3.8.0 (3413) # Decompiled from: Python 3.8.0 (tags/v3.8.0:fa919fd, Oct 14 2019, 19:37:50) [MSC v.1916 64 bit (AMD64)] # Embedded file name: SecretEncrypt.py import math class Base85Encoder: CHARSET = "".join([chr(i) for i in range(33, 118)]) @staticmethod def encode(data: bytes) -> str: result = "" padding_size = (4 - len(data) % 4) % 4 data += b'\x00' * padding_size for i in range(0, len(data), 4): chunk = data[i[:i + 4]] val = int.from_bytes(chunk, "big") chunk_res = "" for _ in range(5): chunk_res = Base85Encoder.CHARSET[val % 85] + chunk_res val //= 85 else: result += chunk_res else: if padding_size: result = result[None[:-padding_size]] return result class Base45Encoder: CHARSET = "".join([chr(i) for i in range(48, 93)]) @staticmethod def encode(data: bytes) -> str: res = [] i = 0 while i < len(data): if i + 1 < len(data): val = data[i] << 8 | data[i + 1] res.append(Base45Encoder.CHARSET[val % 45]) val //= 45 res.append(Base45Encoder.CHARSET[val % 45]) val //= 45 res.append(Base45Encoder.CHARSET[val]) i += 2 else: val = data[i] res.append(Base45Encoder.CHARSET[val % 45]) val //= 45 res.append(Base45Encoder.CHARSET[val]) i += 1 return "".join(res) def caesar_cipher(text, shift): res = [] for char in text: if "a" <= char <= "z": new_val = (ord(char) - ord("a") + shift) % 26 res.append(chr(ord("a") + new_val)) elif "0" <= char <= "9": new_val = (ord(char) - ord("0") - shift) % 10 res.append(chr(ord("0") + new_val)) else: res.append(char) else: return "".join(res) # okay decompiling SecretEncrypt.pyc

通过caesar_cipher(Base85Encoder.encode(caesar_cipher(Base45Encoder.encode(plain_text.encode()), 7).encode()), 9)可以得知加密顺序为:

  • Base45 加密 码表0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\
  • 凯撒密码 偏移 7
  • Base85 加密 码表!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstu
  • 凯撒密码 偏移 9

最后与TARGET_HASH对比验证

代码中的凯撒密码为魔改版,Base45 为非标准码表,Base85 为标准Adobe Ascii85(还有另一种常见的是IPv6 / RFC 1924)

EXP

将加密函数修改成解密函数

import base64 def caesar_cipher(text, shift): res = [] for char in text: if "a" <= char <= "z": new_val = (ord(char) - ord("a") + shift) % 26 res.append(chr(ord("a") + new_val)) elif "0" <= char <= "9": new_val = (ord(char) - ord("0") - shift) % 10 res.append(chr(ord("0") + new_val)) else: res.append(char) else: return "".join(res) def Base45decoder(data): CHARSET = "".join([chr(i) for i in range(48, 93)]) result = "" for i in range(0, len(data), 3): a = CHARSET.index(data[i]) b = CHARSET.index(data[i+1]) c = CHARSET.index(data[i+2]) n = a + (b * 45) + (c * 45 * 45) result += chr(n >> 8) result += chr(n & 0xFF) return result enc = [57, 118, 33, 114, 68, 56, 117, 115, 34, 52, 52, 95, 78, 40, 49, 59, 95, 85, 63, 122, 54, 33, 77, 110, 49, 54, 34, 109, 106, 122, 60, 92, 108, 91, 61, 51, 42, 62, 35, 38, 52, 67, 62, 122, 116, 48, 76, 50, 67, 51, 59, 41, 122, 45, 45, 51, 90] # sourc enc = "".join([chr(i) for i in enc]) print(enc) # caesar enc = caesar_cipher(enc, -9) print(enc) # base85 enc = base64.a85decode(enc).decode() print(enc) # caesar enc = caesar_cipher(enc, -7) print(enc) # base45 enc = Base45decoder(enc) print(enc)
9v!rD8us"44_N(1;_U?z6!Mn16"mjz<\l[=3*>#&4C>zt0L2C3;)z--3Z 8m!iD7lj"33_N(0;_U?q5!Me05"daq<\c[=2*>#&3C>qk9L1C2;)q--2Z JX2NG:CM:KJ?S0=:>?NC>K5<V29Z5<Y:9C=;LA1RQ9G:7 JX9NG:CM:KJ?S7=:>?NC>K2<V96Z2<Y:6C=;LA8RQ6G:4 NSSCTF{Th3y'r3_a11_p1aY_Ba5e!}

NSSCTF{Th3y'r3_a11_p1aY_Ba5e!}

总结

本题考验对算法的熟悉程度,涉及 base45、base85、Caesar 算法,并且需要解包反编译 pyc、反编译自定义 python 库

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/27 13:20:13

Qwen3-4B如何提升响应质量?用户偏好对齐机制实战解析

Qwen3-4B如何提升响应质量&#xff1f;用户偏好对齐机制实战解析 1. 背景与技术演进 大语言模型在通用能力上的持续进化&#xff0c;正推动AI系统从“能回答”向“答得好”转变。阿里云推出的 Qwen3-4B-Instruct-2507 是Qwen系列中面向指令理解和高质量文本生成的40亿参数规模…

作者头像 李华
网站建设 2026/5/22 17:42:08

USB驱动无法识别?深度排查方法汇总

USB驱动无法识别&#xff1f;别慌&#xff0c;一文打通飞控通信“任督二脉” 你有没有过这样的经历&#xff1a; 手握最新款F7飞控&#xff0c;满心期待打开betaflight configurator调参&#xff0c;结果刷新十遍也找不到设备&#xff1b; 设备管理器里清清楚楚显示一个“未…

作者头像 李华
网站建设 2026/5/20 17:29:58

OCR模型选型攻略:cv_resnet18适用于哪些业务场景?

OCR模型选型攻略&#xff1a;cv_resnet18适用于哪些业务场景&#xff1f; 1. 技术背景与选型需求 在当前数字化转型加速的背景下&#xff0c;光学字符识别&#xff08;OCR&#xff09;技术已成为文档处理、信息提取和自动化流程中的关键环节。面对多样化的业务场景——从证件…

作者头像 李华
网站建设 2026/5/20 9:17:31

手把手教程:在Pspice中创建二极管SPICE模型

手把手教你打造专属二极管SPICE模型&#xff1a;从数据手册到Pspice精准仿真 你有没有遇到过这样的情况&#xff1f;在Pspice里搭好一个电源电路&#xff0c;仿真结果看起来一切正常&#xff0c;可一到实测就发现效率偏低、温升高&#xff0c;甚至出现异常振荡。排查半天&…

作者头像 李华
网站建设 2026/5/25 17:05:57

YOLOv9依赖库详解:pytorch 1.10 + torchvision 0.11兼容性测试

YOLOv9依赖库详解&#xff1a;pytorch 1.10 torchvision 0.11兼容性测试 1. 镜像环境说明 本镜像基于 YOLOv9 官方代码库构建&#xff0c;预装了完整的深度学习开发环境&#xff0c;集成了训练、推理及评估所需的所有依赖&#xff0c;开箱即用。该环境专为 YOLOv9 的稳定运行…

作者头像 李华
网站建设 2026/5/25 11:20:12

手把手教程:使用DSL进行es查询语法构建

手把手教你用 DSL 构建高效的 Elasticsearch 查询你有没有遇到过这样的场景&#xff1a;用户在搜索框里输入“张三”&#xff0c;结果却把“李四”也搜出来了&#xff1f;或者查个日志&#xff0c;明明只想要最近一小时的ERROR级别记录&#xff0c;系统却卡了几秒才返回&#x…

作者头像 李华