news 2026/4/15 14:41:49

[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/4/12 9:05:14

MinerU 2.5性能评测:处理复杂PDF的实际表现

MinerU 2.5性能评测&#xff1a;处理复杂PDF的实际表现 1. 引言 1.1 技术背景与选型动因 在当前大模型驱动的内容理解与知识工程实践中&#xff0c;非结构化文档的自动化解析已成为关键瓶颈。尤其是科研论文、技术白皮书、财务报告等专业文档&#xff0c;普遍采用多栏排版、…

作者头像 李华
网站建设 2026/4/15 3:53:32

LangFlow低代码开发:妈妈再也不用担心我装环境报错

LangFlow低代码开发&#xff1a;妈妈再也不用担心我装环境报错 你是不是也经历过这样的场景&#xff1f;刚决定转行做程序员&#xff0c;兴致勃勃地想动手做一个AI项目&#xff0c;结果第一步就被“环境配置”卡住了。Python版本不对、CUDA驱动不匹配、依赖包冲突、路径找不到…

作者头像 李华
网站建设 2026/4/14 9:41:15

FreeRTOS中vTaskDelay实现详解:深度剖析时间片管理

深入 FreeRTOS 的心跳&#xff1a;从 vTaskDelay 看实时系统的延时艺术 在嵌入式开发的世界里&#xff0c;我们常常会遇到这样一个问题&#xff1a; “如何让任务暂停几毫秒&#xff0c;又不把 CPU 空转浪费掉&#xff1f;” 如果你用的是裸机编程&#xff0c;可能写个 …

作者头像 李华
网站建设 2026/4/12 20:08:14

Live Avatar种子控制应用:结果可复现性保证的random seed设置

Live Avatar种子控制应用&#xff1a;结果可复现性保证的random seed设置 1. 引言 1.1 技术背景与问题提出 随着生成式AI在数字人领域的广泛应用&#xff0c;模型输出的可复现性&#xff08;Reproducibility&#xff09;成为工程落地中的关键需求。特别是在内容审核、版本对…

作者头像 李华
网站建设 2026/4/8 16:39:39

Z-Image-ComfyUI多用户协作:权限管理设置实战指南

Z-Image-ComfyUI多用户协作&#xff1a;权限管理设置实战指南 阿里最新开源&#xff0c;文生图大模型。 1. 引言 1.1 业务场景描述 随着生成式AI在设计、内容创作和营销等领域的广泛应用&#xff0c;团队协作使用图像生成工具已成为常态。Z-Image-ComfyUI作为阿里最新推出的文…

作者头像 李华
网站建设 2026/4/13 14:13:20

minidump调试入门必看:用户态崩溃分析基础

minidump调试入门必看&#xff1a;用户态崩溃分析实战指南从一次空指针说起&#xff1a;为什么我们需要minidump&#xff1f;想象这样一个场景&#xff1a;你的程序刚发布到客户现场&#xff0c;突然收到一条反馈——“软件一打开就闪退”。你尝试复现&#xff0c;却在开发机上…

作者头像 李华