re
babyconnet
Server.exe 有主逻辑

使用XOR 解密
flag_dll_check(buf); 验证flag

WASD移动
SMC:解密

inside.dll的check,2是终点,1是正常
mov eax, 0; ret 是可通过
mov eax, [eax] (eax=0 时崩溃 ) 不可通过
mov dword_10014AC8, 1 终点

这里是

Patch了53

Patch了85

这里实现了nop功能
完整的迷宫是

from collections import deque
def solve_maze():
# 初始通路 + 特殊位置(传送门)
initial_paths = {1, 11, 13, 15, 16, 17, 18, 21, 23, 25, 28, 31, 33, 35, 38,
41, 42, 43, 45, 46, 48, 56, 58, 61, 62, 63, 64, 66, 68,
71, 74, 76, 78, 81, 82, 84, 86, 88}
start, end = 1, 88
queue = deque([((start, frozenset()), “D”)])
visited = {(start, frozenset())}
while queue:
(pos, opened), path = queue.popleft()
if pos == end:
return path
current_paths = initial_paths | opened
for direction, delta in [(‘W’, -10), (‘S’, 10), (‘A’, -1), (‘D’, 1)]:
new_pos = pos + delta
# 边界检查…
if new_pos in current_paths:
new_opened = set(opened)
if new_pos == 13: new_opened.add(53) # 打开位置53
if new_pos == 82: new_opened.add(85) # 打开位置85
new_state = (new_pos, frozenset(new_opened))
if new_state not in visited:
visited.add(new_state)
queue.append((new_state, path + direction))
return None
# 结果
path = “DSSSSDDWWWSSSSSAASSDAWWDDDSSDDWWWWAWWWDDDSSSSSSS”
flag.dll里面是主要的检查那么看这里

按照后面四个字节来求解,密文在&unk_10015000里面是0x50,0x73,0x65,0xCC,0x0,0xC,0x11,0x2E,0x2,0x26,0x2,0x3,0xD,0x7A,0x7A,0x1B,0x36,0x61,0x4C,0x6,0x18,0x4C,0xF,0x46,0x58,0x30,0x30,0x53,0x62,0x58,0x5A,0x68,0xE,0x34,0x55,0x5,0x5B,0x6C,0x4A,0x44,0x5E,0x36,0x42,0x7D
exp
maze_path = “DSSSSDDWWWSSSSSAASSDAWWDDDSSDDWWWWAWWWDDDSSSSSSS”
# flag.dll 的目标密文
target = bytes([
0x50, 0x73, 0x65, 0xCC, 0x00, 0x0C, 0x11, 0x2E,
0x02, 0x26, 0x02, 0x03, 0x0D, 0x7A, 0x7A, 0x1B,
0x36, 0x61, 0x4C, 0x06, 0x18, 0x4C, 0x0F, 0x46,
0x58, 0x30, 0x30, 0x53, 0x62, 0x58, 0x5A, 0x68,
0x0E, 0x34, 0x55, 0x05, 0x5B, 0x6C, 0x4A, 0x44,
0x5E, 0x36, 0x42, 0x7D,
])
print(f”目标密文 ({len(target)} 字节): {target.hex()}”)
# 分析 nullsub_1 的 XOR 逻辑
# 看起来是: data[i] ^= data[i+1] 的循环
# 尝试逆向 XOR 操作
def reverse_xor(data):
“””逆向 XOR 操作: 从后往前”””
result = bytearray(data)
for i in range(len(result) – 2, -1, -1):
result[i] ^= result[i + 1]
return bytes(result)
# 尝试多次逆向(因为代码中有3个类似的循环)
decrypted = target
for round_num in range(3):
decrypted = reverse_xor(decrypted)
try:
text = decrypted.decode(‘ascii’)
if text.startswith(‘flag’) or text.startswith(‘PCC’) or ‘ctf’ in text.lower():
print(f”\n第 {round_num + 1} 轮解密后: {text}”)
except:
pass
print(f”第 {round_num + 1} 轮: {decrypted.hex()}”)
# 检查是否有可打印字符
printable = ”.join(chr(b) if 32 <= b < 127 else ‘.’ for b in decrypted)
print(f” 可打印: {printable}”)
More more flower
字节码是
bytecode = bytes([
0x01, 0x08, 0x06, 0x01, 0x01, 0x02, 0x02, 0x04, 0x02, 0x09, 0x01, 0x01,
0x02, 0x04, 0x05, 0x01, 0x08, 0x08, 0x01, 0x03, 0x04, 0x02, 0x09, 0x01,
0x01, 0x02, 0x04, 0x05, 0x01, 0x08, 0x08, 0x01, 0x03, 0x04, 0x02, 0x09,
0x01, 0x01, 0x02, 0x04, 0x05, 0x01, 0x08, 0x08, 0x01, 0x03, 0x03, 0x04,
0x06, 0x00, 0x03, 0x03, 0x06, 0x1E, 0x01, 0x08, 0x56, 0x01, 0x08, 0x11,
0x01, 0x08, 0x25, 0x01, 0x08, 0x23, 0x02, 0x08, 0x04, 0x04, 0x06, 0x01,
0x07, 0x03, 0x05, 0x01, 0x05, 0x05, 0x05, 0x09, 0x05, 0x04, 0x06, 0x01,
0x04, 0x09, 0x05, 0x01, 0x02, 0x07, 0x04, 0x01, 0x05, 0x07, 0x03, 0x01,
0x0A, 0x03, 0x36, 0x01, 0x07, 0x07, 0x06, 0x01, 0x03, 0x03, 0x08, 0x04,
0x02, 0x09, 0x0A, 0x03, 0x03, 0x03, 0x03, 0x06, 0x18, 0x03, 0x02, 0x06,
0x00, 0x02, 0x02, 0x03, 0x04, 0x07, 0x07, 0x01, 0x00, 0x0A, 0x01, 0x8F,
0x07, 0x03, 0x01, 0x04, 0x02, 0x09, 0x0A, 0x03, 0x79, 0x0B, 0x01, 0x0B
])
目标值
target = bytes([
0x21, 0x7A, 0x01, 0x1C, 0x33, 0xD3, 0x3E, 0xF7,
0x03, 0x78, 0x25, 0x5E, 0x2F, 0xB8, 0x8B, 0x3B,
0x93, 0x84, 0xAE, 0x5B, 0xDE, 0xA5, 0xD6, 0xE9
])
根据VM可以得到
下面的指令
opcode
1
2
3
4
5
6
7
8
9
10
11
指令
PUSH
POP
MOV
ADD
SHL
SHR
SUB
OR
XOR
JNZ
RET
反VM
0: PUSH imm 0x6 ; 外层循环计数器 = 6
; === 读取 4 字节组成 32-bit 值 ===
3: PUSH input[R1] ; 读取输入字节
5: POP R0
7: ADD R1, 1
10: PUSH input[R1]
12: POP R2
14: SHL R0, 8 ; R0 = R0 << 8
17: OR R0, R2 ; R0 |= R2
… (重复读取 4 字节)
; === 初始化加密参数 ===
46: MOV R3, 0x0 ; delta = 0
50: MOV R2, 0x1E ; 内层循环 30 次
54: PUSH imm 0x56 ; 压入 KEY 的 4 个字节
57: PUSH imm 0x11
60: PUSH imm 0x25
63: PUSH imm 0x23
66: POP dword (var_8) ; var_8 = 0x23251156 (KEY)
; === 加密内层循环 ===
68: ADD R3, var_8 ; delta += KEY
71: PUSH R0_dword ; 保存 R0
73: MOV R6, R0 ; R6 = R0
76: SHL R6, 5 ; R6 = R0 << 5
79: XOR R6, R3 ; R6 ^= delta
82: SHR R0, 4 ; temp = R0 >> 4
85: XOR R6, R0 ; R6 ^= (R0 >> 4)
88: POP R0_dword ; 恢复 R0
90: ADD R0, R6 ; R0 += R6
93: SUB R2, 1 ; 计数器–
96: JNZ R2, 54 ; 循环 30 次
99: PUSH R0_dword ; 保存加密结果
…
; === 验证阶段 ===
121: POP R0 ; 逐字节弹出
123: MOV R3, target[R1] ; 与目标比较
126: SUB R0, R3
129: JNZ R0, 143 ; 不等则失败
…
141: RET 1 ; 成功返回 1
143: RET 0 ; 失败返回 0
得到算法
KEY = 0x23251156
def encrypt_block(v):
delta = 0
for _ in range(30):
delta = (delta + KEY) & 0xFFFFFFFF
r6 = ((v << 5) & 0xFFFFFFFF) ^ delta ^ (v >> 4)
v = (v + r6) & 0xFFFFFFFF
return v
exp
import hashlib
target = bytes([
0x21, 0x7A, 0x01, 0x1C, 0x33, 0xD3, 0x3E, 0xF7,
0x03, 0x78, 0x25, 0x5E, 0x2F, 0xB8, 0x8B, 0x3B,
0x93, 0x84, 0xAE, 0x5B, 0xDE, 0xA5, 0xD6, 0xE9
])
# 正确的加密函数
KEY = 0x23251156 # var_8 的值
def encrypt_block_correct(v):
“””正确的加密:delta 累加 KEY”””
delta = 0
for _ in range(30):
delta = (delta + KEY) & 0xFFFFFFFF
# R6 = (R0 << 5) ^ delta ^ (R0 >> 4)
r6 = ((v << 5) & 0xFFFFFFFF) ^ delta ^ (v >> 4)
v = (v + r6) & 0xFFFFFFFF
return v
def decrypt_single_round_all(v_new, delta):
“””解密单轮”””
def calc_encrypted(v_old):
r6 = ((v_old << 5) & 0xFFFFFFFF) ^ delta ^ (v_old >> 4)
return (v_old + r6) & 0xFFFFFFFF
stage1 = []
for low16 in range(1 << 16):
r6 = ((low16 << 5) & 0xFFFFFFFF) ^ delta ^ (low16 >> 4)
result = (low16 + r6) & 0xFFFFFFFF
if (result & 0xFF) == (v_new & 0xFF):
stage1.append(low16)
stage2 = []
for low16 in stage1:
for mid8 in range(256):
low24 = low16 | (mid8 << 16)
r6 = ((low24 << 5) & 0xFFFFFFFF) ^ delta ^ (low24 >> 4)
result = (low24 + r6) & 0xFFFFFFFF
if (result & 0xFFFF) == (v_new & 0xFFFF):
stage2.append(low24)
solutions = []
for low24 in stage2:
for high8 in range(256):
v_old = low24 | (high8 << 24)
if calc_encrypted(v_old) == v_new:
solutions.append(v_old)
return solutions
def decrypt_block_correct(enc):
“””正确的解密:30轮,delta从30*KEY递减”””
current = [enc]
delta = (30 * KEY) & 0xFFFFFFFF
for r in range(30):
next_solutions = []
for v in current:
sols = decrypt_single_round_all(v, delta)
next_solutions.extend(sols)
current = next_solutions
delta = (delta – KEY) & 0xFFFFFFFF
if not current:
return []
return current
# 验证加密
print(“=== Verify encryption ===”)
test_val = 0x41424344
enc = encrypt_block_correct(test_val)
print(f”encrypt(0x41424344) = {enc:#010x}”)
# 验证解密
print(“\n=== Verify decryption ===”)
solutions = decrypt_block_correct(enc)
print(f”Solutions: {len(solutions)}”)
if test_val in solutions:
print(f”Original value {test_val:#010x} found!”)
else:
print(“Original not found”)
for s in solutions[:5]:
print(f” {s:#010x}”)
# 解密所有块
print(“\n=== Decrypting flag ===”)
all_solutions = []
for i in range(6):
start = i * 4
block = (target[start] << 24) | (target[start + 1] << 16) | (target[start + 2] << 8) | targ
print(f”Block {i}: {block:#010x}”, end=” -> “)
solutions = decrypt_block_correct(block)
print(f”{len(solutions)} solutions”)
# 过滤可打印
printable = []
for sol in solutions:
b = bytes([(sol >> 24) & 0xFF, (sol >> 16) & 0xFF, (sol >> 8) & 0xFF, sol & 0xFF])
if all(0x20 <= c < 0x7F for c in b):
printable.append((sol, b))
print(f” Printable: {len(printable)}”)
for sol, b in printable[:5]:
print(f” {sol:#010x} = {b}”)
all_solutions.append(
printable if printable else [(s, bytes([(s >> 24) & 0xFF, (s >> 16) & 0xFF, (s >> 8) &
in solutions])
# 组合求解
print(“\n=== Finding flag ===”)
from itertools import product
expected_sha = “3dbe89f66cb189f9cac1fb5ec23fac941df69119792aad4b6d61d63b98ddb527”
total = 1
for sols in all_solutions:
total *= len(sols)
print(f”Total combinations: {total}”)
if total > 0 and total < 10000000:
for combo in product(*all_solutions):
flag = b”
for sol, _ in combo:
flag += bytes([(sol >> 24) & 0xFF, (sol >> 16) & 0xFF, (sol >> 8) & 0xFF, sol & 0xF
sha = hashlib.sha256(flag).hexdigest()
if sha == expected_sha:
print(f”\n*** FOUND FLAG ***”)
print(f”Flag: {flag}”)
try:
print(f”String: {flag.decode()}”)
except:
pass
print(f”SHA256: {sha}”)
break
else:
print(“Not found”)
Get_My_Emoji_wp
先看emoji_encoder
标准的RC4加密

那么很好写了.
import shutil
import subprocess
from pathlib import Path
import numpy as np
from PIL import Image
def encode_constant(binary: Path, workdir: Path, value: int, h: int, w: int) -> np.ndarray:
# 构造全常数 RGBA 图 -> 调用 encoder -> 读回 enc_emoji.png 的 RGBA 数组
plain = np.full((h, w, 4), value, dtype=np.uint8)
Image.fromarray(plain, “RGBA”).save(workdir / “my_emoji.png”)
subprocess.run(
[str(binary)],
cwd=str(workdir),
check=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
enc = Image.open(workdir / “enc_emoji.png”).convert(“RGBA”)
return np.array(enc, dtype=np.uint8)
def main():
workdir = Path(__file__).resolve().parent
binary = workdir / “emoji_encoder”
target = workdir / “enc_emoji.png” # 题目给的噪声图
backup = workdir / “enc_emoji_orig.png”
out = workdir / “decoded_emoji.png”
if not binary.exists():
raise FileNotFoundError(“emoji_encoder not found”)
if not target.exists():
raise FileNotFoundError(“enc_emoji.png not found”)
# 备份原始密文图,避免被 encoder 覆盖
if not backup.exists():
shutil.copyfile(target, backup)
# 读取题目密文(从 backup 读,避免后续被覆盖)
cipher_img = Image.open(backup).convert(“RGBA”)
cipher = np.array(cipher_img, dtype=np.uint8)
h, w = cipher.shape[:2]
# Oracle:全 0 & 全 255
e0 = encode_constant(binary, workdir, 0, h, w)
eF = encode_constant(binary, workdir, 255, h, w)
# 恢复 A 和 X
add = ((e0.astype(np.uint16) + eF.astype(np.uint16) + 1) % 256)
add = (add // 2).astype(np.uint8)
xor = ((e0.astype(np.int16) – add.astype(np.int16)) % 256).astype(np.uint8)
# 解密:P = (C – A) XOR X
plain = ((cipher.astype(np.int16) – add.astype(np.int16)) % 256).astype(np.uint8)
plain = np.bitwise_xor(plain, xor).astype(np.uint8)
Image.fromarray(plain, “RGBA”).save(out)
print(f”[+] decoded saved to: {out}”)
if __name__ == “__main__”:
main()
LinuxChal
主要的是

这里得到一个叫ghost_bin的文件
然后在正常 Linux 环境运行就可以得到flag
exp
#!/usr/bin/env python3
from pathlib import Path
PATCH_OFF = 0x9789
OLD = 0x74 # JE rel8
NEW = 0xEB # JMP rel8
def main():
p = Path(“chal”)
data = bytearray(p.read_bytes())
if data[PATCH_OFF] != OLD:
raise SystemExit(
f”[!] unexpected byte at 0x{PATCH_OFF:x}: “
f”got 0x{data[PATCH_OFF]:02x}, expected 0x{OLD:02x}”
)
data[PATCH_OFF] = NEW
out = Path(“chal_patched”)
out.write_bytes(data)
out.chmod(0o755)
print(f”[+] patched ok -> {out}”)
print(“[+] run it:”)
print(” ./chal_patched”)
print(” # or: sudo ./chal_patched (if challenge env requires)”)
if __name__ == “__main__”:
main()
meddddgo
DIE查

GO语言的,无壳.根据Input your flag: 定位到 sub_140001A20()里面
可以看到是处理了\r和\n.
检查位置sub_1400B3740()
汇编里面test rsi, 0xf,要求了是16倍数
输出正确
return sub_1400AA4E0(41, &v6, v3, “Congratulate! The mad go flag is flag{%s}”, (const char *)1);
里面有个魔改的SM4
在sub_1400B32A0()

然后s-box是
0xD6,0x90,0xE9,0xFE,0xCC,0xE1,0x3D,0xB7,0x16,0xB6,0x14,0xC2,0x28,0xFB,0x2C,0x5,0x2B,0x67,0x9A,0x76,0x2A,0xBE,0x4,0xC3,0xAA,0x44,0x13,0x26,0x49,0x86,0x6,0x99,0x9C,0x42,0x50,0xF4,0x91,0xEF,0x98,0x7A,0x33,0x54,0xB,0x43,0xED,0xCF,0xAC,0x62,0xE4,0xB3,0x1C,0xA9,0xC9,0x8,0xE8,0x95,0x80,0xDF,0x94,0xFA,0x75,0x8F,0x3F,0xA6,0x47,0x7,0xA7,0xFC,0xF3,0x73,0x17,0xBA,0x83,0x59,0x3C,0x19,0xE6,0x85,0x4F,0xA8,0x68,0x6B,0x81,0xB2,0x71,0x64,0xDA,0x8B,0xF8,0xEB,0xF,0x4B,0x70,0x56,0x9D,0x35,0x1E,0x24,0xE,0x5E,0x63,0x58,0xD1,0xA2,0x25,0x22,0x7C,0x3B,0x1,0x21,0x78,0x87,0xD4,0x0,0x46,0x57,0x9F,0xD3,0x27,0x52,0x4C,0x36,0x2,0xE7,0xA0,0xC4,0xC8,0x9E,0xEA,0xBF,0x8A,0xD2,0x40,0xC7,0x38,0xB5,0xA3,0xF7,0xF2,0xCE,0xF9,0x61,0x15,0xA1,0xE0,0xAE,0x5D,0xA4,0x9B,0x34,0x1A,0x55,0xAD,0x93,0x32,0x30,0xF5,0x8C,0xB1,0xE3,0x1D,0xF6,0xE2,0x2E,0x82,0x66,0xCA,0x60,0xC0,0x29,0x23,0xAB,0xD,0x53,0x4E,0x6F,0xD5,0xDB,0x37,0x45,0xDE,0xFD,0x8E,0x2F,0x3,0xFF,0x6A,0x72,0x6D,0x6C,0x5B,0x51,0x8D,0x1B,0xAF,0x92,0xBB,0xDD,0xBC,0x7F,0x11,0xD9,0x5C,0x41,0x1F,0x10,0x5A,0xD8,0xA,0xC1,0x31,0x88,0xA5,0xCD,0x7B,0xBD,0x2D,0x74,0xD0,0x12,0xB8,0xE5,0xB4,0xB0,0x89,0x69,0x97,0x4A,0xC,0x96,0x77,0x7E,0x65,0xB9,0xF1,0x9,0xC5,0x6E,0xC6,0x84,0x18,0xF0,0x7D,0xEC,0x3A,0xDC,0x4D,0x20,0x79,0xEE,0x5F,0x3E,0xD7,0xCB,0x39,0x48
SM4是K[i] = MK[i] ^ FK[i]这里是K[i] = MK[i] ^ FK[i] ^ MAGIC[i]
可以从里面找到seed是10 23 45 67 89 ab cd ef 01 35 79 bd f0 22 44 66
exp是
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import struct
# ————————
# SM4 S-Box / FK / CK
# ————————
SBOX = [
0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05,
0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99,
0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62,
0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6,
0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8,
0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35,
0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87,
0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e,
0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1,
0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3,
0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f,
0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51,
0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8,
0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0,
0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84,
0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48,
]
FK = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc]
CK = [
0x00070e15,0x1c232a31,0x383f464d,0x545b6269,0x70777e85,0x8c939aa1,0xa8afb6bd,0xc4cbd2d9,
0xe0e7eef5,0xfc030a11,0x181f262d,0x343b4249,0x50575e65,0x6c737a81,0x888f969d,0xa4abb2b9,
0xc0c7ced5,0xdce3eaf1,0xf8ff060d,0x141b2229,0x30373e45,0x4c535a61,0x686f767d,0x848b9299,
0xa0a7aeb5,0xbcc3cad1,0xd8dfe6ed,0xf4fb0209,0x10171e25,0x2c333a41,0x484f565d,0x646b7279
]
# 程序里额外 xor 的那组常量(魔改点)
MAGIC = [0xA5A5A5A5, 0x3C3C3C3C, 0x5A5A5A5A, 0xC3C3C3C3]
def rotl32(x, n):
x &= 0xFFFFFFFF
return ((x << n) & 0xFFFFFFFF) | (x >> (32 – n))
def tau(a):
b = 0
for i in range(4):
byte = (a >> (24 – 8*i)) & 0xFF
b = (b << 8) | SBOX[byte]
return b
def L(b):
return b ^ rotl32(b, 2) ^ rotl32(b, 10) ^ rotl32(b, 18) ^ rotl32(b, 24)
def Lp(b):
return b ^ rotl32(b, 13) ^ rotl32(b, 23)
def T(x):
return L(tau(x))
def Tp(x):
return Lp(tau(x))
def rk_mad(key_bytes: bytes):
”’
魔改 SM4 key schedule:
K[i] = MK[i] ^ FK[i] ^ MAGIC[i]
其余流程与标准 SM4 相同
”’
MK = [struct.unpack(“>I”, key_bytes[i*4:(i+1)*4])[0] for i in range(4)]
K = [MK[i] ^ FK[i] ^ MAGIC[i] for i in range(4)]
rk = []
for i in range(32):
t = K[i+1] ^ K[i+2] ^ K[i+3] ^ CK[i]
K.append(K[i] ^ Tp(t))
rk.append(K[i+4])
return rk
def sm4_encrypt_block(block16: bytes, rk):
X = [struct.unpack(“>I”, block16[i*4:(i+1)*4])[0] for i in range(4)]
for i in range(32):
t = X[i+1] ^ X[i+2] ^ X[i+3] ^ rk[i]
X.append(X[i] ^ T(t))
Y = [X[35], X[34], X[33], X[32]]
return b””.join(struct.pack(“>I”, y) for y in Y)
def sm4_decrypt_ecb(cipher: bytes, key_bytes: bytes) -> bytes:
rk = rk_mad(key_bytes)
rk_rev = list(reversed(rk))
out = b””
for i in range(0, len(cipher), 16):
out += sm4_encrypt_block(cipher[i:i+16], rk_rev)
return out
def derive_key_from_seed(seed16: bytes) -> bytes:
”’
按二进制里的那段 16 字节 key 派生逻辑还原:
– 第一轮生成 tmp[16]
– 然后三轮原地混淆(round=0,1,2)
”’
assert len(seed16) == 16
arr = list(seed16)
# 第一轮
tmp = []
for i in range(16):
idx = (i*5 + 3) & 0xF
b = arr[idx]
b = ((b << 1) & 0xFF) | (b >> 7) # rol1
v = (11*i) ^ b ^ 0xA5
tmp.append(v & 0xFF)
# 三轮原地混淆
for r in range(3):
for j in range(16):
old = tmp[j]
b5 = tmp[(j + 5) & 0xF]
b1 = tmp[(j + 1) & 0xF]
add = (b5 + b1 + 17*r) & 0xFF
tmp[j] = (old ^ add) & 0xFF
return bytes(tmp)
def main():
# 从二进制里提取到的常量
seed = bytes.fromhex(“1023456789abcdef013579bdf0224466”)
cipher = bytes.fromhex(
“fc66b270e8874c9d734ecd5b766aa589”
“6dda6cc5349d5f3b44b54aaf5ef9ce49”
)
key = derive_key_from_seed(seed)
plain = sm4_decrypt_ecb(cipher, key)
inner = plain.decode()
print(“[+] seed :”, seed.hex())
print(“[+] key :”, key.hex())
print(“[+] inner:”, inner)
print(“[+] flag :”, f”flag{{{inner}}}”)
if __name__ == “__main__”:
main()
评论(0)
暂无评论