文章总结: 这篇文章介绍了强网杯2025中PolyEncryption题目的解题过程,作者使用AI辅助完成了多层加密算法的分析和解密脚本编写。文章详细描述了C#、Java和Python三层的解密方法,以及如何通过Docker调试确定最终细节,最终提供了完整的Python实现代码用于解密加密的flag文件。 综合评分: 91 文章分类: CTF,逆向分析,漏洞POC,二进制安全,安全工具
强网杯2025-PolyEncryption之Vibe Reing的胜利
SleepAlone
看雪学苑
2025年12月20日 18:04 上海
1.由于代码太多太长,导致上传失败同时也影响读感,所以一些非关键的脚本贴了github链接。
#
2.以下所有代码全部由AI完成(少量人工排查),Vibe Reing已经到来!燃烧吧!token!
各个阶段解密脚本
00
C#层解密
1.c#层奇数轮(rr=1)
2.c#层奇数轮(rr!=1)
3.c#层偶数轮(rr=2,rr!=0)
java层解密
https://github.com/Savagel0ve/CTFWP/blob/main/qwb2025/polyenc/exp/decrypt_all_horror_commands.py
python层解密(自动生成patch后dll的反编译结果)
1.rr=0
2.rr=1
3.偶数
4.最后共同的
处理解密脚本产生的文件
01
Vibe Reing使用上一步产生的各层文件,使用cursor让agent根据这些解密文件自动对各个层的代码做出准确注释。
1.saw.cs(main)
2.saw.py
3.saw.java
有了注释之后,让agent自动读取注释,推理出(rr=0, rr=1, rr=2, rr=3)的数据流
1.rr=0
2.rr=1
3.rr=2
4.rr=3
根据AI推理出的数据流,逆向分析写出脚本
02
但是脚本解密失败,有细节不对,解密脚本省略,下面有正确的。
Patch polyencrypt.dll中的saw.python, Hack.java
03
#
Docker Debug看细节
1.Patch dll脚本
2.Patch saw.python 增加日志输出
3.Patch Hack.java 增加Hack中方法被调用的日志记录
4.Debug版本dockerfile
根据Debug docker的日志输出,敲定最终细节
04
#
最终写出解密脚本:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
PolyEnc 纯Python实现 - 清晰版本
不使用中间变量,直接实现加密算法
"""
import struct
# ============================================================================
# S-box (来自 saw.py)
# ============================================================================
SBOX = (
0x9b, 0xac, 0x16, 0x92, 0x5d, 0x9c, 0x1f, 0xed, 0xf8, 0x52, 0x18, 0xc4, 0xd9, 0x59, 0xa0, 0x82,
0x3c, 0x88, 0x69, 0x4a, 0x5a, 0xf6, 0x34, 0xc1, 0xba, 0x27, 0xec, 0x23, 0x10, 0x51, 0x1, 0xe5,
0x5e, 0xb1, 0x12, 0xca, 0xe2, 0x9f, 0x65, 0x22, 0x7b, 0x2f, 0x3b, 0xeb, 0x4c, 0xf3, 0xb6, 0xb8,
0x1d, 0x50, 0xc5, 0x8e, 0x36, 0xd4, 0xd1, 0x89, 0x48, 0xad, 0xfe, 0x6e, 0xc0, 0x37, 0xb2, 0xa4,
0x6f, 0x71, 0x98, 0xa6, 0x49, 0x3a, 0x33, 0xff, 0x31, 0xb0, 0x8f, 0x76, 0xe4, 0xc8, 0x47, 0xab,
0xfd, 0x13, 0xd7, 0xc6, 0xdd, 0x73, 0xb5, 0x90, 0x70, 0x6a, 0xb9, 0x60, 0x1b, 0xfa, 0x1c, 0x45,
0xd8, 0x6, 0x68, 0x99, 0xa2, 0x4f, 0x7, 0x54, 0x4d, 0x17, 0x2a, 0x39, 0xa8, 0xa1, 0x84, 0x83,
0x64, 0x9e, 0x80, 0x7f, 0x29, 0xda, 0x61, 0x58, 0x20, 0x9, 0xdb, 0x8, 0x0f, 0xaf, 0x4, 0xd3,
0xf7, 0x5c, 0xee, 0xc9, 0x0c, 0x9d, 0x5, 0x93, 0xf2, 0x57, 0x4b, 0xf1, 0xcf, 0x15, 0xbf, 0xe8,
0xce, 0xea, 0x0e, 0x67, 0x91, 0x38, 0x6d, 0x3, 0x24, 0x25, 0x32, 0x85, 0xf5, 0xa5, 0x95, 0x5b,
0xbe, 0xbc, 0xdf, 0x0b, 0xbd, 0x7e, 0x35, 0x30, 0xae, 0xde, 0xef, 0x87, 0x8c, 0xb3, 0x1e, 0x28,
0x78, 0x6c, 0x75, 0x0a, 0x8a, 0x0d, 0x66, 0x8d, 0xcd, 0x40, 0x3d, 0xfb, 0x4e, 0xe1, 0xf4, 0x53,
0x2c, 0x77, 0x43, 0x26, 0x74, 0x94, 0x9a, 0xb7, 0x11, 0xa3, 0xe7, 0xfc, 0xd5, 0x96, 0x7c, 0xe0,
0xe6, 0x8b, 0xcb, 0x1a, 0x55, 0x62, 0xdc, 0xaa, 0x2, 0x63, 0x86, 0x7d, 0x14, 0x3f, 0x97, 0xa7,
0x72, 0x2e, 0x19, 0x2b, 0x0, 0x6b, 0xe9, 0x5f, 0xc2, 0x21, 0x2d, 0xd0, 0xf0, 0xd6, 0x7a, 0x3e,
0x46, 0x56, 0xd2, 0xe3, 0xbb, 0xb4, 0x44, 0xf9, 0xc7, 0x79, 0x81, 0x41, 0x42, 0xcc, 0xa9, 0xc3
)
# 构建逆S-box
INV_SBOX = [0] * 256
for i in range(256):
INV_SBOX[SBOX[i]] = i
INV_SBOX = tuple(INV_SBOX)
# ============================================================================
# AES 标准函数
# ============================================================================
def xtime(a):
"""AES xtime: GF(2^8) 乘 2"""
return (((a << 1) ^ 0x1B) & 0xFF) if (a & 0x80) else (a << 1)
def mix_column(col):
"""
AES MixColumns 标准实现
输入: [a0, a1, a2, a3] (4字节)
输出: [b0, b1, b2, b3]
"""
a0, a1, a2, a3 = col
xor_all = a0 ^ a1 ^ a2 ^ a3
b0 = a0 ^ xor_all ^ xtime(a0 ^ a1)
b1 = a1 ^ xor_all ^ xtime(a1 ^ a2)
b2 = a2 ^ xor_all ^ xtime(a2 ^ a3)
b3 = a3 ^ xor_all ^ xtime(a3 ^ a0)
return [b0, b1, b2, b3]
def apply_sbox_to_u32(value):
"""对32位整数应用S-box (小端序)"""
bytes_le = struct.pack("<I", value)
sboxed = bytes([SBOX[b] for b in bytes_le])
return struct.unpack("<I", sboxed)[0]
def rol(value, shift):
"""32位循环左移"""
value &= 0xFFFFFFFF
return ((value << shift) | (value >> (32 - shift))) & 0xFFFFFFFF
def gf_mult(a, b):
"""GF(2^8) 乘法"""
p = 0
for _ in range(8):
if b & 1:
p ^= a
hi_bit_set = a & 0x80
a = (a << 1) & 0xFF
if hi_bit_set:
a ^= 0x1B
b >>= 1
return p
def inv_mix_column(col):
"""
AES 逆 MixColumns 实现
输入: [b0, b1, b2, b3] (4字节)
输出: [a0, a1, a2, a3]
使用矩阵: [0x0E, 0x0B, 0x0D, 0x09]
"""
b0, b1, b2, b3 = col
a0 = gf_mult(0x0E, b0) ^ gf_mult(0x0B, b1) ^ gf_mult(0x0D, b2) ^ gf_mult(0x09, b3)
a1 = gf_mult(0x09, b0) ^ gf_mult(0x0E, b1) ^ gf_mult(0x0B, b2) ^ gf_mult(0x0D, b3)
a2 = gf_mult(0x0D, b0) ^ gf_mult(0x09, b1) ^ gf_mult(0x0E, b2) ^ gf_mult(0x0B, b3)
a3 = gf_mult(0x0B, b0) ^ gf_mult(0x0D, b1) ^ gf_mult(0x09, b2) ^ gf_mult(0x0E, b3)
return [a0, a1, a2, a3]
def apply_inv_sbox_to_u32(value):
"""对32位整数应用逆S-box (小端序)"""
bytes_le = struct.pack("<I", value)
inv_sboxed = bytes([INV_SBOX[b] for b in bytes_le])
return struct.unpack("<I", inv_sboxed)[0]
# ============================================================================
# PolyEnc 加密器
# ============================================================================
class PolyEnc:
def __init__(self):
"""初始化加密器"""
# 轮密钥 (10个,对应 Round 2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
self.round_keys = [
3207972492, 1190065579, 4165979424, 2693353696, 3628337899,
1707638109, 1003779598, 2653425729, 795752593, 2469382657,
0
]
# 初始密钥状态
self.initial_key = [
2427014626, # s[1] - 初始魔数
1166827919, # s[2] - 初始魔数
1240047111, # s[3] - 初始魔数
1038097261 # s[4] - 初始魔数
]
def encrypt(self, plaintext_bytes, verbose=False):
"""
加密16字节明文
算法流程:
- Round 0: 初始化
- Round 1-21: 奇数轮(SubBytes+MixColumns) + 偶数轮(AddRoundKey)
- Round 22: 输出
"""
if len(plaintext_bytes) != 16:
raise ValueError("Input must be 16 bytes")
# 将明文转为4个32位整数 (大端序)
state = list(struct.unpack('>4I', plaintext_bytes))
# 复制初始密钥
key = self.initial_key.copy()
# 轮密钥索引
key_index = 0
if verbose:
print(f"【初始状态】")
print(f" state = {[hex(s) for s in state]}")
print(f" key = {[hex(k) for k in key]}")
# Round 1-21: 主加密循环
# Round 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21 (奇数轮): SubBytes + MixColumns
# Round 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 (偶数轮): ShiftRows + AddRoundKey
for rr in range(1, 23):
if rr % 2 == 1: # 奇数轮: SubBytes + MixColumns
state = self._odd_round(state, key, rr, verbose)
else: # 偶数轮: ShiftRows + AddRoundKey
state, key, key_index = self._even_round(state, key, key_index, rr, verbose)
final_state = state
# 返回密文 (大端序)
return struct.pack('>4I', *final_state)
def _odd_round(self, state, key, rr, verbose):
"""
奇数轮: SubBytes + MixColumns
返回: 16 字节数组 (4x4 矩阵,按行存储)
同时更新密钥状态 s[2], s[3], s[4]:
- s[2] = B ^ A'
- s[3] = C ^ B ^ A'
- s[4] = D ^ C ^ B ^ A'
"""
if verbose:
print(f"\n【Round {rr}】奇数轮 - SubBytes + MixColumns")
print(f" 输入 state = {[hex(s) for s in state]}")
print(f" 输入 key = {[hex(k) for k in key]}")
# 1. 密钥更新 (奇数轮)
if rr == 1:
# Round 1: 密钥保持初始值,不变
pass
else:
# Round 3, 5, 7, ..., 21: 更新 s[2], s[3], s[4]
A_prime = key[0] # 上一个偶数轮更新后的 s[1]
B = key[1]
C = key[2]
D = key[3]
# 密钥级联更新
key[1] = (B ^ A_prime) & 0xFFFFFFFF # s[2] = B ^ A'
key[2] = (C ^ B ^ A_prime) & 0xFFFFFFFF # s[3] = C ^ B ^ A'
key[3] = (D ^ C ^ B ^ A_prime) & 0xFFFFFFFF # s[4] = D ^ C ^ B ^ A'
if verbose:
print(f" 密钥更新:")
print(f" A' = {hex(A_prime)}")
print(f" s[2] = B ^ A' = {hex(key[1])}")
print(f" s[3] = C ^ B ^ A' = {hex(key[2])}")
print(f" s[4] = D ^ C ^ B ^ A' = {hex(key[3])}")
# 2. SubBytes: 对 state 的每个32位整数应用S-box
sboxed = [apply_sbox_to_u32(s) for s in state]
if verbose:
print(f" SubBytes = {[hex(s) for s in sboxed]}")
# 3. MixColumns: 对每个 32位整数拆分成 4字节,MixColumns 后得到 16字节
# 结果按倒序排列(从 Docker 日志观察到)
mixed_bytes = []
for val in sboxed: # 倒序处理
# 拆分成4字节 (大端序)
bytes_be = struct.unpack('4B', struct.pack('>I', val))
# MixColumns
mixed_col = mix_column(list(bytes_be))
mixed_bytes.extend(mixed_col)
if verbose:
print(f" MixColumns 16字节: {[hex(b) for b in mixed_bytes]}")
# 显示为 4x4 矩阵
print(f" MixColumns 4x4矩阵 (按列):")
for row in range(4):
print(f" row{row}: {[hex(mixed_bytes[col*4 + row]) for col in range(4)]}")
return mixed_bytes
def _even_round(self, state_bytes, key, key_index, rr, verbose):
"""
偶数轮: ShiftRows + 字节打包 + AddRoundKey
输入: 16 字节数组 (从奇数轮的 MixColumns 输出)
输出: 4 个 32位整数
1. ShiftRows: 对 4x4 矩阵按对角线重排
2. 字节打包: 每 4 字节打包成一个 32位整数
3. AddRoundKey: state ^= key
4. 密钥更新: s[1] = A ^ sbox(rol(D, 8)) ^ round_key[i]
"""
if verbose:
print(f"\n【Round {rr}】偶数轮 - ShiftRows + AddRoundKey")
print(f" 输入 16字节: {[hex(b) for b in state_bytes]}")
print(f" 输入 key = {[hex(k) for k in key]}")
# 1. ShiftRows: 标准 AES ShiftRows(按行存储)
# 输入: state_bytes 按列存储 [col0_row0-3, col1_row0-3, col2_row0-3, col3_row0-3]
# 需要先转换为按行存储,然后 ShiftRows,最后按列打包
# 标准 ShiftRows 索引(按行存储):
# col0: 0, 5, 10, 15
# col1: 1, 6, 11, 12
# col2: 2, 7, 8, 13
# col3: 3, 4, 9, 14
# 将按列存储转换为按行存储
# state_bytes[0..3] = col0, state_bytes[4..7] = col1, ...
# 转换为 row0 = [0,4,8,12], row1 = [1,5,9,13], ...
row_based = []
for row in range(4):
for col in range(4):
row_based.append(state_bytes[col * 4 + row])
# ShiftRows 索引(倒序,因为 state 要倒序)
shiftrows_indices = [
[3, 4, 9, 14], # col3 (倒序第0个)
[2, 7, 8, 13], # col2 (倒序第1个)
[1, 6, 11, 12], # col1 (倒序第2个)
[0, 5, 10, 15] # col0 (倒序第3个)
]
shifted_state = []
for indices in shiftrows_indices:
# 从 row_based 按索引取4个字节,打包成32位整数
val = (row_based[indices[0]] << 24) | (row_based[indices[1]] << 16) | \
(row_based[indices[2]] << 8) | row_based[indices[3]]
shifted_state.append(val)
if verbose:
print(f" ShiftRows + 打包:")
for col in range(4):
idx0 = 0*4 + col
idx1 = 1*4 + ((col + 1) % 4)
idx2 = 2*4 + ((col + 2) % 4)
idx3 = 3*4 + ((col + 3) % 4)
print(f" state[{col}] = [{hex(state_bytes[idx0])}, {hex(state_bytes[idx1])}, "
f"{hex(state_bytes[idx2])}, {hex(state_bytes[idx3])}] = {hex(shifted_state[col])}")
# 2. AddRoundKey: state ^= key
shifted_state = shifted_state[::-1]
new_state = [(shifted_state[i] ^ key[i]) & 0xFFFFFFFF for i in range(4)]
if verbose:
print(f" AddRoundKey (state ^= key):")
for i in range(4):
print(f" state[{i}] = {hex(shifted_state[i])} ^ {hex(key[i])} = {hex(new_state[i])}")
# 3. 密钥更新: s[1] = A ^ sbox(rol(D, 8)) ^ round_key[i]
A = key[0]
D = key[3]
# rol(D, 8) - 循环左移8位
rotated = rol(D, 8)
# sbox(rotated)
sboxed = apply_sbox_to_u32(rotated)
# A' = A ^ sboxed ^ round_key[i]
round_key = self.round_keys[key_index]
A_prime = (A ^ sboxed ^ round_key) & 0xFFFFFFFF
key[0] = A_prime
key_index += 1
if verbose:
print(f" 密钥更新:")
print(f" rol(s[4], 8) = {hex(rotated)}")
print(f" sbox(rotated) = {hex(sboxed)}")
print(f" round_key[{key_index-1}] = {hex(round_key)}")
print(f" s[1] = {hex(A)} ^ {hex(sboxed)} ^ {hex(round_key)} = {hex(A_prime)}")
return new_state, key, key_index
def decrypt(self, ciphertext_bytes, verbose=False):
"""
解密16字节密文
算法流程:
1. 先正向生成所有轮的密钥状态
2. 从 Round 22 逆向到 Round 1
"""
if len(ciphertext_bytes) != 16:
raise ValueError("Input must be 16 bytes")
# 1. 正向生成所有轮密钥状态
if verbose:
print(f"\n【生成轮密钥】")
key_states = self._generate_all_round_keys()
if verbose:
print(f"生成了 {len(key_states)} 组轮密钥")
for rr in sorted(key_states.keys())[:5]: # 只显示前5个
print(f" Round {rr}: {[hex(k) for k in key_states[rr]]}")
print(f" ...")
# 2. 将密文转为4个32位整数 (大端序)
state = list(struct.unpack('>4I', ciphertext_bytes))
if verbose:
print(f"\n【解密开始】")
print(f" 密文 (bytes): {ciphertext_bytes.hex().upper()}")
print(f" 密文 (u32): {[hex(s) for s in state]}")
# 3. 逆向执行 Round 22 到 Round 1
for rr in range(22, 0, -1):
if rr % 2 == 0: # 偶数轮: 逆AddRoundKey + 逆ShiftRows
state = self._inv_even_round(state, key_states[rr], rr, verbose)
else: # 奇数轮: 逆MixColumns + 逆SubBytes
state = self._inv_odd_round(state, key_states[rr], rr, verbose)
if verbose:
print(f"\n【解密结束】")
print(f" 明文 (u32): {[hex(s) for s in state]}")
# 4. 返回明文 (大端序)
plaintext = struct.pack('>4I', *state)
if verbose:
print(f" 明文 (bytes): {plaintext.hex().upper()}")
return plaintext
def _generate_all_round_keys(self):
"""
正向生成所有轮的密钥状态
返回: 字典 {round_number: key_state}
"""
key = self.initial_key.copy()
key_index = 0
key_states = {0: key.copy()}
# 模拟加密过程中的密钥更新
for rr in range(1, 23):
if rr % 2 == 1: # 奇数轮
if rr > 1:
# Round 3, 5, 7, ..., 21: 更新 s[2], s[3], s[4]
A_prime = key[0]
B = key[1]
C = key[2]
D = key[3]
key[1] = (B ^ A_prime) & 0xFFFFFFFF
key[2] = (C ^ B ^ A_prime) & 0xFFFFFFFF
key[3] = (D ^ C ^ B ^ A_prime) & 0xFFFFFFFF
key_states[rr] = key.copy()
else: # 偶数轮
key_states[rr] = key.copy()
# 更新 s[1]
A = key[0]
D = key[3]
rotated = rol(D, 8)
sboxed = apply_sbox_to_u32(rotated)
round_key = self.round_keys[key_index]
A_prime = (A ^ sboxed ^ round_key) & 0xFFFFFFFF
key[0] = A_prime
key_index += 1
return key_states
def _inv_odd_round(self, state_bytes, key, rr, verbose):
"""
逆奇数轮: 逆MixColumns + 逆SubBytes
输入: 16 字节数组
输出: 4 个 32位整数
"""
if verbose:
print(f"\n【Round {rr} 逆向】奇数轮 - InvMixColumns + InvSubBytes")
print(f" 输入 state (16字节): {[hex(b) for b in state_bytes]}")
print(f" 输入 key = {[hex(k) for k in key]}")
# 显示为 4x4 矩阵
print(f" 输入 4x4矩阵 (按列):")
for row in range(4):
print(f" row{row}: {[hex(state_bytes[col*4 + row]) for col in range(4)]}")
# 1. 逆MixColumns: 对每个32位整数拆分成4字节,逆MixColumns后得到16字节
inv_mixed_bytes = []
for i in range(4):
# 提取4个字节(按列存储)
col_bytes = state_bytes[i*4:(i+1)*4]
# 逆MixColumns
inv_mixed_col = inv_mix_column(list(col_bytes))
inv_mixed_bytes.extend(inv_mixed_col)
if verbose:
print(f" InvMixColumns 16字节: {[hex(b) for b in inv_mixed_bytes]}")
# 显示为 4x4 矩阵
print(f" InvMixColumns 4x4矩阵 (按列):")
for row in range(4):
print(f" row{row}: {[hex(inv_mixed_bytes[col*4 + row]) for col in range(4)]}")
# 2. 重新打包成4个32位整数(大端序)
sboxed = []
for i in range(4):
bytes_4 = inv_mixed_bytes[i*4:(i+1)*4]
val = struct.unpack('>I', bytes(bytes_4))[0]
sboxed.append(val)
if verbose:
print(f" 打包成u32 (应用InvSubBytes之前): {[hex(s) for s in sboxed]}")
# 3. 逆SubBytes: 对每个32位整数应用逆S-box
state = [apply_inv_sbox_to_u32(s) for s in sboxed]
if verbose:
print(f" InvSubBytes (输出state) = {[hex(s) for s in state]}")
return state
def _inv_even_round(self, state, key, rr, verbose):
"""
逆偶数轮: 逆AddRoundKey + 逆ShiftRows
输入: 4 个 32位整数
输出: 16 字节数组
"""
if verbose:
print(f"\n【Round {rr} 逆向】偶数轮 - InvAddRoundKey + InvShiftRows")
print(f" 输入 state = {[hex(s) for s in state]}")
print(f" 使用 key = {[hex(k) for k in key]}")
# 1. 逆AddRoundKey: state ^= key (XOR是自逆的)
unkeyed_state = [(state[i] ^ key[i]) & 0xFFFFFFFF for i in range(4)]
if verbose:
print(f" InvAddRoundKey (state ^= key):")
for i in range(4):
print(f" state[{i}] = {hex(state[i])} ^ {hex(key[i])} = {hex(unkeyed_state[i])}")
# 将4个32位整数拆分成16字节
# 按加密时的打包方式逆向
inv_shiftrows_indices = [
[0, 5, 10, 15], # col0 (对应倒序第3个)
[1, 6, 11, 12], # col1 (对应倒序第2个)
[2, 7, 8, 13], # col2 (对应倒序第1个)
[3, 4, 9, 14] # col3 (对应倒序第0个)
]
# 先将4个u32解包成按行存储的16字节
row_based = []
for val in unkeyed_state:
row_based.append((val >> 24) & 0xFF)
row_based.append((val >> 16) & 0xFF)
row_based.append((val >> 8) & 0xFF)
row_based.append(val & 0xFF)
if verbose:
print(f" 解包成16字节(按行): {[hex(b) for b in row_based]}")
# 创建逆映射
unshifted_row_based = [0] * 16
for col_idx, indices in enumerate(inv_shiftrows_indices):
for byte_idx, src_idx in enumerate(indices):
unshifted_row_based[src_idx] = row_based[col_idx * 4 + byte_idx]
if verbose:
print(f" InvShiftRows后(按行): {[hex(b) for b in unshifted_row_based]}")
# 转换回按列存储
state_bytes = []
for col in range(4):
for row in range(4):
state_bytes.append(unshifted_row_based[row * 4 + col])
if verbose:
print(f" 输出 16字节(按列): {[hex(b) for b in state_bytes]}")
# 显示为 4x4 矩阵
print(f" 输出 4x4矩阵 (按列):")
for row in range(4):
print(f" row{row}: {[hex(state_bytes[col*4 + row]) for col in range(4)]}")
return state_bytes
# ============================================================================
# 测试和验证
# ============================================================================
def test_encrypt():
"""测试加密功能"""
print("="*80)
print("PolyEnc 加密测试")
print("="*80)
# Docker 环境:run.sh 传入 "abe74e3a9c375b3428bf31d1f8fa49c1"
# dotnet 程序将其解析为十六进制并按 32位整数倒序排列
plaintext_hex = "abe74e3a9c375b3428bf31d1f8fa49c1"
# 解析成 4 个 32位整数(每8个字符一组)
chunks = [plaintext_hex[i:i+8] for i in range(0, len(plaintext_hex), 8)]
print(f"\n解析输入字符串: {plaintext_hex}")
print(f" 分组: {chunks}")
# dotnet 按倒序处理(从 Docker 日志观察到)
chunks_reversed = chunks
print(f" 倒序: {chunks_reversed}")
# 转换为字节序列(小端序)
plaintext_bytes = b''.join([bytes.fromhex(c) for c in chunks_reversed])
print(f" 字节序列 (hex): {plaintext_bytes.hex().upper()}")
# 重新组装为大端序的 4 个整数(匹配 polyenc 输入格式)
plaintext = bytes.fromhex(''.join(chunks_reversed))
print(f"\n最终明文 (hex): {plaintext.hex().upper()}")
print(f"最终明文 (u32 大端): {[hex(x) for x in struct.unpack('>4I', plaintext)]}")
# 加密
enc = PolyEnc()
ciphertext = enc.encrypt(plaintext, verbose=True)
print(f"\n密文: {ciphertext.hex().upper()}")
return True
def test_verbose():
"""详细输出测试"""
print("\n" + "="*80)
print("详细加密流程(前4轮)")
print("="*80)
plaintext = bytes.fromhex("abe74e3a9c375b3428bf31d1f8fa49c1")
enc = PolyEnc()
# 修改加密函数以支持部分轮次
state = list(struct.unpack('>4I', plaintext))
key = enc.initial_key.copy()
key_index = 0
print(f"\n明文: {plaintext.hex().upper()}")
print(f"初始 state = {[hex(s) for s in state]}")
print(f"初始 key = {[hex(k) for k in key]}")
# Round 1-4
for rr in range(1, 5):
if rr % 2 == 1:
state = enc._odd_round(state, key, rr, verbose=True)
else:
state, key, key_index = enc._even_round(state, key, key_index, rr, verbose=True)
def test_decrypt(verbose=True):
"""测试加密和解密功能"""
print("="*80)
print("PolyEnc 加密/解密测试")
print("="*80)
plaintext_hex = "abe74e3a9c375b3428bf31d1f8fa49c1"
plaintext = bytes.fromhex(plaintext_hex)
print(f"\n明文 (hex): {plaintext.hex().upper()}")
# 加密
enc = PolyEnc()
ciphertext = enc.encrypt(plaintext, verbose=False)
print(f"密文 (hex): {ciphertext.hex().upper()}")
print("\n" + "="*80)
print("开始解密...")
print("="*80)
# 解密
decrypted = enc.decrypt(ciphertext, verbose=verbose)
print("\n" + "="*80)
print("解密完成")
print("="*80)
print(f"解密后 (hex): {decrypted.hex().upper()}")
# 验证
if plaintext == decrypted:
print("\n✓ 解密成功!明文与解密结果一致")
return True
else:
print("\n✗ 解密失败!明文与解密结果不一致")
print(f" 期望: {plaintext.hex().upper()}")
print(f" 实际: {decrypted.hex().upper()}")
return False
def test_with_separate_logs():
"""将加密和解密日志分别输出到不同文件"""
import sys
plaintext_hex = "abe74e3a9c375b3428bf31d1f8fa49c1"
plaintext = bytes.fromhex(plaintext_hex)
print("="*80)
print("PolyEnc 加密/解密测试 (分离日志)")
print("="*80)
print(f"明文: {plaintext.hex().upper()}")
# 1. 加密并输出到文件
print("\n正在生成加密日志...")
with open('encrypt_log.txt', 'w', encoding='utf-8') as f:
old_stdout = sys.stdout
sys.stdout = f
enc = PolyEnc()
ciphertext = enc.encrypt(plaintext, verbose=True)
sys.stdout = old_stdout
print(f"✓ 加密日志已保存到: encrypt_log.txt")
print(f" 密文: {ciphertext.hex().upper()}")
# 2. 解密并输出到文件
print("\n正在生成解密日志...")
with open('decrypt_log.txt', 'w', encoding='utf-8') as f:
old_stdout = sys.stdout
sys.stdout = f
decrypted = enc.decrypt(ciphertext, verbose=True)
sys.stdout = old_stdout
print(f"✓ 解密日志已保存到: decrypt_log.txt")
print(f" 解密结果: {decrypted.hex().upper()}")
# 3. 验证
print("\n" + "="*80)
if plaintext == decrypted:
print("✓ 解密成功!明文与解密结果一致")
return True
else:
print("✗ 解密失败!明文与解密结果不一致")
print(f" 期望: {plaintext.hex().upper()}")
print(f" 实际: {decrypted.hex().upper()}")
return False
def decrypt_flag_file(flag_file='../flag.enc', output_file='flag.txt'):
"""解密 flag.enc 文件"""
print("="*80)
print("解密 FLAG 文件")
print("="*80)
# 1. 读取加密文件
try:
with open(flag_file, 'r') as f:
ciphertext_hex = f.read().strip()
except FileNotFoundError:
print(f"✗ 错误: 找不到文件 {flag_file}")
return False
print(f"读取文件: {flag_file}")
print(f"密文 (hex): {ciphertext_hex}")
print(f"密文长度: {len(ciphertext_hex)} 字符 ({len(ciphertext_hex)//2} 字节)")
# 2. 解析十六进制
try:
ciphertext = bytes.fromhex(ciphertext_hex)
except ValueError as e:
print(f"✗ 错误: 无法解析十六进制: {e}")
return False
# 3. 检查长度是否为16的倍数
if len(ciphertext) % 16 != 0:
print(f"✗ 错误: 密文长度不是16的倍数")
return False
num_blocks = len(ciphertext) // 16
print(f"\n密文分块数: {num_blocks} 块 (每块 16 字节)")
# 4. 解密每个块
enc = PolyEnc()
plaintext_blocks = []
print("\n开始解密...")
for i in range(num_blocks):
block_start = i * 16
block_end = block_start + 16
block = ciphertext[block_start:block_end]
print(f"\n块 {i+1}/{num_blocks}:")
print(f" 密文: {block.hex().upper()}")
try:
plaintext_block = enc.decrypt(block, verbose=False)
print(f" 明文: {plaintext_block.hex().upper()}")
# 尝试解码为ASCII
try:
ascii_text = plaintext_block.decode('ascii', errors='ignore')
printable = ''.join(c if c.isprintable() else '.' for c in ascii_text)
print(f" ASCII: {printable}")
except:
pass
plaintext_blocks.append(plaintext_block)
except Exception as e:
print(f" ✗ 解密失败: {e}")
return False
# 5. 合并所有块
plaintext = b''.join(plaintext_blocks)
print("\n" + "="*80)
print("解密结果")
print("="*80)
print(f"明文 (hex): {plaintext.hex().upper()}")
print(f"明文长度: {len(plaintext)} 字节")
# 尝试解码为文本
print("\n尝试解码为文本:")
for encoding in ['utf-8', 'ascii', 'latin-1']:
try:
text = plaintext.decode(encoding)
print(f" [{encoding}] {text}")
except:
print(f" [{encoding}] 解码失败")
# 6. 保存到文件
try:
with open(output_file, 'wb') as f:
f.write(plaintext)
print(f"\n✓ 明文已保存到: {output_file}")
except Exception as e:
print(f"\n✗ 保存文件失败: {e}")
return True
if __name__ == "__main__":
import sys
# 检查命令行参数
if len(sys.argv) > 1:
if sys.argv[1] == '--separate-logs':
# 使用分离日志模式
test_with_separate_logs()
elif sys.argv[1] == '--flag':
# 解密 flag.enc
flag_file = sys.argv[2] if len(sys.argv) > 2 else '../flag.enc'
decrypt_flag_file(flag_file)
elif sys.argv[1] == '--help':
print("用法:")
print(" python polyenc_clean.py # 运行加密/解密测试")
print(" python polyenc_clean.py --separate-logs # 生成分离的日志文件")
print(" python polyenc_clean.py --flag [文件] # 解密 flag.enc (默认: ../flag.enc)")
print(" python polyenc_clean.py --help # 显示帮助")
else:
print(f"未知选项: {sys.argv[1]}")
print("使用 --help 查看帮助")
else:
# 运行加密测试
success = test_encrypt()
if success:
print("\n" + "="*80)
print("加密算法实现验证成功!")
print("="*80)
# 运行解密测试
print("\n")
decrypt_success = test_decrypt(verbose=False)
if decrypt_success:
print("\n" + "="*80)
print("加密/解密功能验证完成!")
print("="*80)
# 提示可以解密 flag
print("\n提示:")
print(" - 使用 'python polyenc_clean.py --separate-logs' 生成分离的日志文件")
print(" - 使用 'python polyenc_clean.py --flag' 解密 flag.enc")
else:
print("\n提示: 使用 'python polyenc_clean.py --separate-logs' 生成分离的日志文件")
完整的题目附件以及脚本请见左下角【阅读原文】
#
看雪ID:SleepAlone
https://bbs.kanxue.com/user-home-950548.htm
*本文为看雪论坛优秀文章,由 SleepAlone 原创,转载请注明来自看雪社区
往期推荐
KernelSU检测之“时间侧信道攻击”
记录工作中解决bug用到的逆向知识
写一个简单的ollvm混淆还原
VmProtect.3.0.0beta分析之虚拟机流程
AI辅助逆向APP白盒AES分析
球分享
球点赞
球在看
点击阅读原文查看更多
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:看雪学苑 SleepAlone《强网杯2025-PolyEncryption之Vibe Reing的胜利》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论