SmileyCTF 2025 wp

比赛前面一度打到3rd,但后面实在干不动了,web队友他们爆了,听说和国内很不一样。我这边re也是巨离谱,简单的前3题队友直接秒了,后面我做了俩中等难度,剩下三道题,一道8解,两道0解,也是离谱,完全没搞懂咋做的

先写下做出来的两道题wp,还是挺有可以学习的点

DNA

看到给的vm.dna我就知道是个虚拟机题目,反编译出pyc果然如此

需要做的很清楚,就是把每个指令打印出来,看输入的数据到底去做了什么,直接喂给gemini让他先帮我分析一波,然后我手动print大法把每个指令和值打印出来(跑代码时要注意python3.10,不然marshal.loads出来的不对)

import marshal
import sys

# 初始化虚拟机状态
s = []  # 栈
m = {}  # 内存
nm = {'A': 0, 'T': 1, 'G': 2, 'C': 3}  # DNA 碱基到整数的映射

# 包含混淆代码的列表
unlucky = [b'\x8coooooooooooonooolooo,ooo\x9cSooo\x06o\x12o\x1bo\x0bnvo\x13o\x0bmSo\x1bo\x0blvo\x13o\x0bnSo\x1bo\x0bkvo\x13o\x0blSo\x1bo\x0bmvo\x13o\x0bkSo\x13o\x0eo\x0bo<oFj!\xb5n;\xb5n.\xb5n(\xb5n,\xc6n\xb5m\x01\x02\xc6n\xb5l\x1b\x02\x1f\xc6o\x1deooo\x95fS\x1a\x01\x03\x1a\x0c\x04\x16Q\xb5h\x1a\x01\x03\x1a\x0c\x04\x16booo\x9ccoookmcncncncngn', b'\x96uuuuuuuuuuuuruuu}uuu6uuu\x86\x11uuu\x11t\x08u\x11w\x08t\x11v\x08w\x11q\x11p\xf1u\tu1u\xf6t\x08v\tu\tt\tw\x13v1u(n\x08q\x01u\x01t\x01w\xd5v\xd4u\xf6t\xf6t1u(e)w\x08p\x08s\tv\tspulu\x01w\tq\tpluluMuvuIu\x04i\x04g\tv\x14w\x11u&u\\s;\xafq426!\xafq!642\xafq6!24\x16tuuuuuuuuuuuwuuusuuu&uuu\x86ouuu\x1cu\tu(|\x08t\tt\x01u\x01t\xd5w\xd4u\xf6t\xe6w\x04w&u\\u\xdcv\xafv\x06\x00\x18\xafw\x1b\x18\xafs\x03\x14\x19\x00\x10\x06\xdcw\xafw[E\xaft\x16\xdcu\x07xuuu\x8f|I\x00\x1b\x19\x00\x16\x1e\x0cK\xafr\x00\x1b\x19\x00\x16\x1e\x0cnuuu\x86wuuuou\x8fh\x00\x1b\x19\x00\x16\x1e\x0c*G[I\x19\x1a\x16\x14\x19\x06K[I\x11\x1c\x16\x01\x16\x1a\x18\x05K\xdcq\xaf|\x10\x1b\x00\x18\x10\x07\x14\x01\x10\xafs\x06\x1a\x07\x01\x10\x11\x07}uuu\xafq\x1e\x10\x0c\x06\xdcr\xafw\x06D\xafw\x06G\xafw\x06F\xafv\x01\x18\x05\xaft\x06\xaft\x1c\x07yuuu\x07xuuu\x07xuuu\x07{uuu\x07zuuucuuu\x86guuuqwqtqt{t{tmtotw\x8a}w', b"\x8aiiiiiiiiiiiihiiiniiijiii\x9a/iii\x1di\rh\xeah\xe0i\xe1i\xc9h\x1di\rk\xeah\xc9k\rj\rm\xedi\x1dj\xc9m\xc8i\xc8k\xc8hhi.i\xeei\x0fh\rl\ro\xeda\ro\x1dl\xeaj\x14i\x15i\x1dj\xeah\x08j\ri:i@n'\xb3o\x1b\x08\x07\r\x06\x04\xb3`\x0f\x1c\x07\n\x1d\x06\x06\x05\x1a\nkiiiiiiiiiiikiiikiii:iii\x9aaiii\x15i\x15h(i:i@h'\xc0i\xc0k\xb3h\x11\xb3h\x10\x1bliii\x1bliii\x93`U\x1c\x07\x05\x1c\n\x02\x10W\xb3n\x1c\x07\x05\x1c\n\x02\x10Miii\x9akiiiai\x93r\x1c\x07\x05\x1c\n\x02\x106ZGU\x05\x06\n\x08\x05\x1aWGU\x05\x08\x04\x0b\r\x08W\niiiiiiiiiiiiiiiijiiiiiii\x9aCiii\x0ci3h\ri3k\xeei\xeeh\x0fk\rh\rk\xeda3j\xeei\x0fh\rj\rm\xeda3m\xeeimi3l:i@l\x93s\x1c\x07\x05\x1c\n\x02\x106ZGU\x05\x06\n\x08\x05\x1aWG\x1c\x07\x05\x1c\n\x02\x10\nkiiiiiiiiiiimiiiliiiziii\x9a-iii\x1di\xeai\xc9h\x15h\xc8hhi\x1dk\rh\xeah\x14k\xe1h\xc9j\x15k\xc8hhi\x1dm\rk\xeah-i4e\x14j\x15h\x15k\x15jpipi\x15i\rh\x15jpiUi\x18z\ri:i@j'\xb3m(*.=\x80miii\xc0l\xb3l\x1a\x1c\x19\x0c\x1b\xb3a66\x00\x07\x00\x1d66\xb3m\x05\x00\x1a\x1d\xb3n\x1a\x01\x1c\x0f\x0f\x05\x0c\xb3l\x1b\x08\x07\x0e\x0c\xc0m\xb3m\x1a\x0c\x05\x0f\xb3n\x04\x08\x19\x19\x00\x07\x0e\xb3m\x02\x0c\x10\x1a\xb3h\x00\xc0k\xb3`66\n\x05\x08\x1a\x1a66\xb3h\x1b\x1bliii\x1b`iii\x1bciiiOiii\x9aeiiiehahcheh\x7fhm\x96\x93J\x1c\x07\x05\x1c\n\x02\x106ZGU\x05\x06\n\x08\x05\x1aWG\x1c\x07\x05\x1c\n\x02\x10G66\x00\x07\x00\x1d66\nkiiiiiiiiiiiliiiliiiziii\x9a;iii\x1di\rh\xeah\x14k\x1di\rk\xeah\x14j`i\x15k\xc9h\rm\xc8h\x14m\x1dk\xeei\x0fh\rl\ro\xeda\x15j\xc9j\x15m\xc8h\xc9m\xc8i\ri\rn\xeckpi-i\xeah\xeah\x1bA\x1dl\xeai\xc9o\xe1i\xc8h:i\x18`@a'\x1bkiii\xb3n\x01\x08\x1a\x01\x05\x00\x0b=\x80Iiii\nhiiiiiiiiiiikiiimiiiZiii\x9auiii\xe8i\x15i4`\x14h\x15h\x1di\xe1i\xeah\x02k?ihi\x18k\ri:i@h'\xc0h\xb3j\x06\x1b\r\xc0k\xb3kGY\x1bniii\xc0h\xb3j\x02\x0c\x10\x1bliii\x1b`iii\x1bciii[iii\x9amiiik\xe9si\x93P\x1c\x07\x05\x1c\n\x02\x106ZGU\x05\x06\n\x08\x05\x1aWG\x1c\x07\x05\x1c\n\x02\x10G66\x0e\x0c\x1d\x00\x1d\x0c\x0466GU\x05\x06\n\x08\x05\x1aWGU\x0e\x0c\x07\x0c\x11\x19\x1bW\x80hiii\xc0n\xb3c66\x00\x04\x19\x06\x1b\x1d66\xb3`\x1b\x08\x07\r\x0b\x10\x1d\x0c\x1a\xb3j\x08\x05\x05\xb3o\x1a\x01\x08[\\_\xb3o\r\x00\x0e\x0c\x1a\x1d\x1bziii\xb3b66\x0e\x0c\x1d\x00\x1d\x0c\x0466\xc0l\x1bpiii\x1bBiii\xb3m\x01\x05\x00\x0b\xb3m\x1b\x05\x00\x0b\xb3h\x0b\xc0h\x1bwiii\x1bCiii\x1b`iii\x1bciiiDiii\x9agiiiahahkhchAhehk\x94\x93O\x1c\x07\x05\x1c\n\x02\x106ZGU\x05\x06\n\x08\x05\x1aWG\x1c\x07\x05\x1c\n\x02\x10G66\x0e\x0c\x1d\x00\x1d\x0c\x0466\xc0o\xb3a66\x07\x08\x04\x0c66\xb3c66\x04\x06\r\x1c\x05\x0c66\xb3e66\x18\x1c\x08\x05\x07\x08\x04\x0c66\x1b}iii\x1b\\iii\xb3d66\n\x05\x08\x1a\x1a\n\x0c\x05\x0566\x1bliii\xc0h\x1bviii\x1bSiii\x1b`iii\x1bciiiLiii\x9aoiiiaigh}n\x1bciii\xc0o\x1bYiii\xb3m\x1a\x0c\x0c\r\xb3o\x1b\x0c\r\x1c\n\x0c\xb3k\x07\x04\xb3o\x1f\x08\x05\x1c\x0c\x1a\xb3m\r\x00\n\x1d\xc0h\x1bciii\x1bliii\x1b+iii\x1b`iii\x1bciiiHiii\x9aaiiiakwh}hey", b'\x82aaaaaaaaaaaacaaagaaa"aaa\x92]aaa&a\x05`\x05c\xe5a\x05c\x15a\xe2b\x1ca&a\x05b\x05e\xe5a\x05e\x15`\x1da\x05d\xece\x1c`\x15c\x05g\x15`\x15b\xe2`\xfaa\x05f\xfcb\xe2``a\x05a2aHi/\x02aaaaaaaaaaaaaaaabaaaaaaa\x92Iaaa\x04a;`\x05a;c\xe6a\x07`\x05`\x05c\xe5i;b\xe6a\x07`\x05b\x05e\xe5i;e\xe6aea;d2aHd\x9bt\x14\x0f\r\x14\x02\n\x18>UO]\r\x0e\x02\x00\r\x12_O,,\x02eaaaaaaaaaaaeaaagaaaraaa\x92saaa\x15a\xe2a\xc1`\x1da\x1d`\x1dc\x1db\xc0e2aH`/\xc8c\xbbd\x12\x14\x11\x04\x13\xbbf>>\x0f\x04\x16>>\xc8e\xbbb\x02\r\x12\xbbe\x0f\x00\x0c\x04\xbbd\x03\x00\x12\x04\x12\xbbb\x05\x02\x15\xc8`\xbbh>>\x02\r\x00\x12\x12>>\xc8a\x9bh]\x14\x0f\r\x14\x02\n\x18_\xbbf\x14\x0f\r\x14\x02\n\x18Zaaa\x92caaas`\x9b|\x14\x0f\r\x14\x02\n\x18>UO]\r\x0e\x02\x00\r\x12_O,,O>>\x0f\x04\x16>>\x02`aaaaaaaaaaafaaadaaa~aaa\x92\x05aaa\x15a\xe2a\x0b`\x1d`\x08a\x1dc\xc5`\xef`\x1cb\x15c\x1db\xc1b\xc0a\xe2`\x1ce\x1de\x05a\x05a\x05`\xe4bxa\x1de\x05c\x05a\x05`\xe4bxava\x1ce\x15e\x15d\x1db\xc1g\xc0a\xe2`\xe2`%a<k=c\x1cd\x1cg\x1de\x1ddxa\x1db\x1dg]a\x10D\x1db2aHb/\x88caaa\x88`aaa\xc8f\x13gaaa\xbbi>>\x02\x00\r\r>>\xbbe\r\x08\x12\x15\xbbg\x17\x00\r\x14\x04\x12\xbbh\x04\x0f\x14\x0c\x04\x13\x00\x15\x04\xbbg\x12\x0e\x13\x15\x04\x05\xbbe\n\x04\x18\x12\xc8f\x13haaa\xbbe\x00\x13\x06\x12\xbbg\n\x16\x00\x13\x06\x12\xbbi\x08\x0f\x12\x15\x00\x0f\x02\x04\xbbe\x17\x00\r\x12\xbb`\x08\xbb`\n\x13laaa\x13naaa\x13qaaa\x13paaa_aaa\x92maaas`m`}`y`o`e`\x9b\x7f\x14\x0f\r\x14\x02\n\x18>UO]\r\x0e\x02\x00\r\x12_O,,O>>\x02\x00\r\r>>\xc8g\xbbi>>\x0f\x00\x0c\x04>>\xbbk>>\x0c\x0e\x05\x14\r\x04>>\xbbm>>\x10\x14\x00\r\x0f\x00\x0c\x04>>\x13faaa\x13yaaa\xbbl>>\x02\r\x00\x12\x12\x02\x04\r\r>>\x13naaa\x13naaa\x13laaa\x13qaaa\x13paaa[aaa\x92gaaaiam`ub\xbbc,,\x02aaaaaaaaaaaaaaaa`aaa!aaa\x92maaa\x04a;`\x05a;c\x05`2aHc\x9bt\x14\x0f\r\x14\x02\n\x18>UO]\r\x0e\x02\x00\r\x12_O,%/\xc8b\x13Iaaa\x13Haaa\x13Kaaa\x13naaa\x13naaa\x13naaa\x13qaaa\x13paaa\'aaa\x92eaaaiae`\xbbc,%\xc8`\xbbh\x0c\x04\x15\x00\x02\r\x00\x12\x12\x9b@\x06\r\x0e\x03\x00\r\x12IH:F\x0f\x14\x02\r\x04\x0e\x15\x08\x05\x04>\x0c\x00\x11F<A\\A,%I\x9b`H\xc8e\xbbe\x15\x18\x11\x04\xbbe\x05\x08\x02\x15\xbbe\x04\x19\x04\x02\xbbc\x0f\x0c\xc8c\x13Laaa\x13Saaa\x13naaa\x13naaa\x13qaaa\x13paaaVaaa\x92gaaaqbumyb']

# 将 DNA 序列转换为整数。这等效于将一个四进制数转换为十进制数。
trans = lambda dna_seq: sum(nm[c] << (2 * i) for i, c in enumerate(dna_seq))

# --- 主程序开始 ---

# 检查命令行参数
if len(sys.argv) != 2:
    print(f"Usage: {sys.argv[0]} <dna_file>")
    sys.exit(1)

# 读取 DNA 代码文件
try:
    with open(sys.argv[1], 'r') as f:
        code = f.read().strip()
except FileNotFoundError:
    print(f"Error: File '{sys.argv[1]}' not found.")
    sys.exit(1)

# 获取并验证用户输入的 flag
flag = input("> ").encode()

if len(flag) != 56:
    print("WRONG!")
    exit()

if flag[:6] != b'.;,;.{':
    print("WRONG!")
    exit()

if flag[-1] != 125:  # ord('}')
    print("WRONG!")
    exit()

# 提取 flag 的核心部分并加载到内存
flag_core = flag[6:-1]
for i in range(len(flag_core)):
    m[640 + i] = flag_core[i]

# 初始化程序计数器 (Program Counter)
pc = 0
mul_list = []
cmp_list = []
# 虚拟机主循环
while pc < len(code):
    # 解码指令和操作数
    # pri 是操作码 (opcode), pro 是操作数 (operand)
    op_slice = code[pc: pc + 2]
    arg_slice = code[pc + 2: pc + 12]
    pri = trans(op_slice)
    pro = trans(arg_slice)

    # --- 指令分派 ---
    if pri == 0:  # PUSH: 将操作数压入栈
        s.append(pro)
        print(f"push {pro}")
        pc += 12
    elif pri == 1:  # POP: 弹出一个值
        if not s: raise Exception("Stack underflow")
        print(f"pop {s[-1]}")
        s.pop()
        pc += 2
    elif pri == 2:  # LOAD: 从内存加载值到栈
        if pro not in m: raise Exception(f"Uninitialized memory access at {pro}")
        print(f"push {m[pro]} ({pro})")
        s.append(m[pro])
        pc += 12
    elif pri == 3:  # STORE: 将栈顶值存入内存
        if not s: raise Exception("Stack underflow")
        print(f"mov m[{pro}], {s[-1]}")
        m[pro] = s.pop()
        pc += 12
    elif pri == 4:  # ADD: 加法
        if len(s) < 2: raise Exception("Stack underflow")
        b, a = s.pop(), s.pop()
        print(f"pop {b} + pop {a} + push {a+b} (add)")
        s.append(a + b)
        pc += 2
    elif pri == 5:  # SUB: 减法
        if len(s) < 2: raise Exception("Stack underflow")
        print(f"pop {b} + pop {a} + push {a - b} (sub)")
        b, a = s.pop(), s.pop()
        s.append(a - b)
        pc += 2
    elif pri == 6:  # MUL: 乘法
        if len(s) < 2: raise Exception("Stack underflow")
        b, a = s.pop(), s.pop()
        print(f"pop {b} + pop {a} + push {a * b} (mul)")
        mul_list.append(b)
        s.append(a * b)
        pc += 2
    elif pri == 7:  # MOD: 取模
        if len(s) < 2: raise Exception("Stack underflow")
        b, a = s.pop(), s.pop()
        print(f"pop {b} + pop {a} + push {a % b} (mod)")
        if a == 0: raise Exception("Division by zero")
        s.append(a % b)
        pc += 2
    elif pri == 8:  # EQ: 比较是否相等
        if len(s) < 2: raise Exception("Stack underflow")
        b, a = s.pop(), s.pop()
        print(f"pop {b} + pop {a} + push {a==b} (cmp)")
        cmp_list.append(b)
        s.append(1 if a == b else 0)
        pc += 2
    elif pri == 9:  # JMP: 无条件跳转
        pc = pro
        print(f"jmp {pc}")
    elif pri == 10:  # JIF: 如果栈顶为 1 则跳转
        if not s: raise Exception("Stack underflow")
        print(f"jmp {pro} if {s[-1]}==1 else pc+=12")
        if s.pop() == 1:
            pc = pro
        else:
            pc += 12
    elif pri == 11:  # JIN: 如果栈顶不为 1 则跳转
        if not s: raise Exception("Stack underflow")
        print(f"jmp {pro} if {s[-1]}!=1 else pc+=12")
        if s.pop() != 1:
            pc = pro
        else:
            pc += 12
    elif pri == 12:  # OUT: 输出字符
        if not s: raise Exception("Stack underflow")
        print(chr(s.pop()), end='')
        pc += 2
    elif pri == 13:  # 动态代码执行
        if not s: raise Exception("Stack underflow")
        key = s.pop()

        def f():
            return
        print("marshal xor", key)
        # 解密并加载字节码
        decrypted_code = bytes([b ^ key for b in unlucky.pop(0)])
        f.__code__ = marshal.loads(decrypted_code)
        f()  # 执行动态生成的代码
        pc += 2
    elif pri == 14:  # SWAP: 交换碱基映射
        if len(s) < 2: raise Exception("Stack underflow")
        b, a = chr(s.pop()), chr(s.pop())  # 注意,这里应该是字符
        print(b, a)
        if a not in nm or b not in nm: raise Exception(f"Invalid characters for nm swap: {a}, {b}")
        nm[a], nm[b] = nm[b], nm[a]
        pc += 2
    elif pri == 15:  # HALT: 停止执行
        break
    else:
        raise Exception(f"Unknown instruction: {pri}")
print(mul_list)
print(cmp_list)

需要关注的点是opcode为13时做了一个异或,然后marshal.loads转为codetype类,因此该key可以爆破

import marshal
import types

unlucky = [b'\x8coooooooooooonooolooo,ooo\x9cSooo\x06o\x12o\x1bo\x0bnvo\x13o\x0bmSo\x1bo\x0blvo\x13o\x0bnSo\x1bo\x0bkvo\x13o\x0blSo\x1bo\x0bmvo\x13o\x0bkSo\x13o\x0eo\x0bo<oFj!\xb5n;\xb5n.\xb5n(\xb5n,\xc6n\xb5m\x01\x02\xc6n\xb5l\x1b\x02\x1f\xc6o\x1deooo\x95fS\x1a\x01\x03\x1a\x0c\x04\x16Q\xb5h\x1a\x01\x03\x1a\x0c\x04\x16booo\x9ccoookmcncncncngn', b'\x96uuuuuuuuuuuuruuu}uuu6uuu\x86\x11uuu\x11t\x08u\x11w\x08t\x11v\x08w\x11q\x11p\xf1u\tu1u\xf6t\x08v\tu\tt\tw\x13v1u(n\x08q\x01u\x01t\x01w\xd5v\xd4u\xf6t\xf6t1u(e)w\x08p\x08s\tv\tspulu\x01w\tq\tpluluMuvuIu\x04i\x04g\tv\x14w\x11u&u\\s;\xafq426!\xafq!642\xafq6!24\x16tuuuuuuuuuuuwuuusuuu&uuu\x86ouuu\x1cu\tu(|\x08t\tt\x01u\x01t\xd5w\xd4u\xf6t\xe6w\x04w&u\\u\xdcv\xafv\x06\x00\x18\xafw\x1b\x18\xafs\x03\x14\x19\x00\x10\x06\xdcw\xafw[E\xaft\x16\xdcu\x07xuuu\x8f|I\x00\x1b\x19\x00\x16\x1e\x0cK\xafr\x00\x1b\x19\x00\x16\x1e\x0cnuuu\x86wuuuou\x8fh\x00\x1b\x19\x00\x16\x1e\x0c*G[I\x19\x1a\x16\x14\x19\x06K[I\x11\x1c\x16\x01\x16\x1a\x18\x05K\xdcq\xaf|\x10\x1b\x00\x18\x10\x07\x14\x01\x10\xafs\x06\x1a\x07\x01\x10\x11\x07}uuu\xafq\x1e\x10\x0c\x06\xdcr\xafw\x06D\xafw\x06G\xafw\x06F\xafv\x01\x18\x05\xaft\x06\xaft\x1c\x07yuuu\x07xuuu\x07xuuu\x07{uuu\x07zuuucuuu\x86guuuqwqtqt{t{tmtotw\x8a}w', b"\x8aiiiiiiiiiiiihiiiniiijiii\x9a/iii\x1di\rh\xeah\xe0i\xe1i\xc9h\x1di\rk\xeah\xc9k\rj\rm\xedi\x1dj\xc9m\xc8i\xc8k\xc8hhi.i\xeei\x0fh\rl\ro\xeda\ro\x1dl\xeaj\x14i\x15i\x1dj\xeah\x08j\ri:i@n'\xb3o\x1b\x08\x07\r\x06\x04\xb3`\x0f\x1c\x07\n\x1d\x06\x06\x05\x1a\nkiiiiiiiiiiikiiikiii:iii\x9aaiii\x15i\x15h(i:i@h'\xc0i\xc0k\xb3h\x11\xb3h\x10\x1bliii\x1bliii\x93`U\x1c\x07\x05\x1c\n\x02\x10W\xb3n\x1c\x07\x05\x1c\n\x02\x10Miii\x9akiiiai\x93r\x1c\x07\x05\x1c\n\x02\x106ZGU\x05\x06\n\x08\x05\x1aWGU\x05\x08\x04\x0b\r\x08W\niiiiiiiiiiiiiiiijiiiiiii\x9aCiii\x0ci3h\ri3k\xeei\xeeh\x0fk\rh\rk\xeda3j\xeei\x0fh\rj\rm\xeda3m\xeeimi3l:i@l\x93s\x1c\x07\x05\x1c\n\x02\x106ZGU\x05\x06\n\x08\x05\x1aWG\x1c\x07\x05\x1c\n\x02\x10\nkiiiiiiiiiiimiiiliiiziii\x9a-iii\x1di\xeai\xc9h\x15h\xc8hhi\x1dk\rh\xeah\x14k\xe1h\xc9j\x15k\xc8hhi\x1dm\rk\xeah-i4e\x14j\x15h\x15k\x15jpipi\x15i\rh\x15jpiUi\x18z\ri:i@j'\xb3m(*.=\x80miii\xc0l\xb3l\x1a\x1c\x19\x0c\x1b\xb3a66\x00\x07\x00\x1d66\xb3m\x05\x00\x1a\x1d\xb3n\x1a\x01\x1c\x0f\x0f\x05\x0c\xb3l\x1b\x08\x07\x0e\x0c\xc0m\xb3m\x1a\x0c\x05\x0f\xb3n\x04\x08\x19\x19\x00\x07\x0e\xb3m\x02\x0c\x10\x1a\xb3h\x00\xc0k\xb3`66\n\x05\x08\x1a\x1a66\xb3h\x1b\x1bliii\x1b`iii\x1bciiiOiii\x9aeiiiehahcheh\x7fhm\x96\x93J\x1c\x07\x05\x1c\n\x02\x106ZGU\x05\x06\n\x08\x05\x1aWG\x1c\x07\x05\x1c\n\x02\x10G66\x00\x07\x00\x1d66\nkiiiiiiiiiiiliiiliiiziii\x9a;iii\x1di\rh\xeah\x14k\x1di\rk\xeah\x14j`i\x15k\xc9h\rm\xc8h\x14m\x1dk\xeei\x0fh\rl\ro\xeda\x15j\xc9j\x15m\xc8h\xc9m\xc8i\ri\rn\xeckpi-i\xeah\xeah\x1bA\x1dl\xeai\xc9o\xe1i\xc8h:i\x18`@a'\x1bkiii\xb3n\x01\x08\x1a\x01\x05\x00\x0b=\x80Iiii\nhiiiiiiiiiiikiiimiiiZiii\x9auiii\xe8i\x15i4`\x14h\x15h\x1di\xe1i\xeah\x02k?ihi\x18k\ri:i@h'\xc0h\xb3j\x06\x1b\r\xc0k\xb3kGY\x1bniii\xc0h\xb3j\x02\x0c\x10\x1bliii\x1b`iii\x1bciii[iii\x9amiiik\xe9si\x93P\x1c\x07\x05\x1c\n\x02\x106ZGU\x05\x06\n\x08\x05\x1aWG\x1c\x07\x05\x1c\n\x02\x10G66\x0e\x0c\x1d\x00\x1d\x0c\x0466GU\x05\x06\n\x08\x05\x1aWGU\x0e\x0c\x07\x0c\x11\x19\x1bW\x80hiii\xc0n\xb3c66\x00\x04\x19\x06\x1b\x1d66\xb3`\x1b\x08\x07\r\x0b\x10\x1d\x0c\x1a\xb3j\x08\x05\x05\xb3o\x1a\x01\x08[\\_\xb3o\r\x00\x0e\x0c\x1a\x1d\x1bziii\xb3b66\x0e\x0c\x1d\x00\x1d\x0c\x0466\xc0l\x1bpiii\x1bBiii\xb3m\x01\x05\x00\x0b\xb3m\x1b\x05\x00\x0b\xb3h\x0b\xc0h\x1bwiii\x1bCiii\x1b`iii\x1bciiiDiii\x9agiiiahahkhchAhehk\x94\x93O\x1c\x07\x05\x1c\n\x02\x106ZGU\x05\x06\n\x08\x05\x1aWG\x1c\x07\x05\x1c\n\x02\x10G66\x0e\x0c\x1d\x00\x1d\x0c\x0466\xc0o\xb3a66\x07\x08\x04\x0c66\xb3c66\x04\x06\r\x1c\x05\x0c66\xb3e66\x18\x1c\x08\x05\x07\x08\x04\x0c66\x1b}iii\x1b\\iii\xb3d66\n\x05\x08\x1a\x1a\n\x0c\x05\x0566\x1bliii\xc0h\x1bviii\x1bSiii\x1b`iii\x1bciiiLiii\x9aoiiiaigh}n\x1bciii\xc0o\x1bYiii\xb3m\x1a\x0c\x0c\r\xb3o\x1b\x0c\r\x1c\n\x0c\xb3k\x07\x04\xb3o\x1f\x08\x05\x1c\x0c\x1a\xb3m\r\x00\n\x1d\xc0h\x1bciii\x1bliii\x1b+iii\x1b`iii\x1bciiiHiii\x9aaiiiakwh}hey", b'\x82aaaaaaaaaaaacaaagaaa"aaa\x92]aaa&a\x05`\x05c\xe5a\x05c\x15a\xe2b\x1ca&a\x05b\x05e\xe5a\x05e\x15`\x1da\x05d\xece\x1c`\x15c\x05g\x15`\x15b\xe2`\xfaa\x05f\xfcb\xe2``a\x05a2aHi/\x02aaaaaaaaaaaaaaaabaaaaaaa\x92Iaaa\x04a;`\x05a;c\xe6a\x07`\x05`\x05c\xe5i;b\xe6a\x07`\x05b\x05e\xe5i;e\xe6aea;d2aHd\x9bt\x14\x0f\r\x14\x02\n\x18>UO]\r\x0e\x02\x00\r\x12_O,,\x02eaaaaaaaaaaaeaaagaaaraaa\x92saaa\x15a\xe2a\xc1`\x1da\x1d`\x1dc\x1db\xc0e2aH`/\xc8c\xbbd\x12\x14\x11\x04\x13\xbbf>>\x0f\x04\x16>>\xc8e\xbbb\x02\r\x12\xbbe\x0f\x00\x0c\x04\xbbd\x03\x00\x12\x04\x12\xbbb\x05\x02\x15\xc8`\xbbh>>\x02\r\x00\x12\x12>>\xc8a\x9bh]\x14\x0f\r\x14\x02\n\x18_\xbbf\x14\x0f\r\x14\x02\n\x18Zaaa\x92caaas`\x9b|\x14\x0f\r\x14\x02\n\x18>UO]\r\x0e\x02\x00\r\x12_O,,O>>\x0f\x04\x16>>\x02`aaaaaaaaaaafaaadaaa~aaa\x92\x05aaa\x15a\xe2a\x0b`\x1d`\x08a\x1dc\xc5`\xef`\x1cb\x15c\x1db\xc1b\xc0a\xe2`\x1ce\x1de\x05a\x05a\x05`\xe4bxa\x1de\x05c\x05a\x05`\xe4bxava\x1ce\x15e\x15d\x1db\xc1g\xc0a\xe2`\xe2`%a<k=c\x1cd\x1cg\x1de\x1ddxa\x1db\x1dg]a\x10D\x1db2aHb/\x88caaa\x88`aaa\xc8f\x13gaaa\xbbi>>\x02\x00\r\r>>\xbbe\r\x08\x12\x15\xbbg\x17\x00\r\x14\x04\x12\xbbh\x04\x0f\x14\x0c\x04\x13\x00\x15\x04\xbbg\x12\x0e\x13\x15\x04\x05\xbbe\n\x04\x18\x12\xc8f\x13haaa\xbbe\x00\x13\x06\x12\xbbg\n\x16\x00\x13\x06\x12\xbbi\x08\x0f\x12\x15\x00\x0f\x02\x04\xbbe\x17\x00\r\x12\xbb`\x08\xbb`\n\x13laaa\x13naaa\x13qaaa\x13paaa_aaa\x92maaas`m`}`y`o`e`\x9b\x7f\x14\x0f\r\x14\x02\n\x18>UO]\r\x0e\x02\x00\r\x12_O,,O>>\x02\x00\r\r>>\xc8g\xbbi>>\x0f\x00\x0c\x04>>\xbbk>>\x0c\x0e\x05\x14\r\x04>>\xbbm>>\x10\x14\x00\r\x0f\x00\x0c\x04>>\x13faaa\x13yaaa\xbbl>>\x02\r\x00\x12\x12\x02\x04\r\r>>\x13naaa\x13naaa\x13laaa\x13qaaa\x13paaa[aaa\x92gaaaiam`ub\xbbc,,\x02aaaaaaaaaaaaaaaa`aaa!aaa\x92maaa\x04a;`\x05a;c\x05`2aHc\x9bt\x14\x0f\r\x14\x02\n\x18>UO]\r\x0e\x02\x00\r\x12_O,%/\xc8b\x13Iaaa\x13Haaa\x13Kaaa\x13naaa\x13naaa\x13naaa\x13qaaa\x13paaa\'aaa\x92eaaaiae`\xbbc,%\xc8`\xbbh\x0c\x04\x15\x00\x02\r\x00\x12\x12\x9b@\x06\r\x0e\x03\x00\r\x12IH:F\x0f\x14\x02\r\x04\x0e\x15\x08\x05\x04>\x0c\x00\x11F<A\\A,%I\x9b`H\xc8e\xbbe\x15\x18\x11\x04\xbbe\x05\x08\x02\x15\xbbe\x04\x19\x04\x02\xbbc\x0f\x0c\xc8c\x13Laaa\x13Saaa\x13naaa\x13naaa\x13qaaa\x13paaaVaaa\x92gaaaqbumyb']
for j in range(4):
    for i in range(0xff):
        try:
            decrypted_code = bytes([b ^ i for b in unlucky[j]])
            code = marshal.loads(decrypted_code)
            print(code)
            if isinstance(code, types.CodeType):
                print(j, chr(i), code)
        except:
            continue

提前得到了key

0 o <code object unlucky at 0x000001DE8FE57030, file "<unlucky>", line 13>
1 u <code object unlucky at 0x000001DE8FE57190, file "<unlucky>", line 22>
2 i <code object unlucky at 0x000001DE8FE57EA0, file "<unlucky>", line 33>
3 a <code object unlucky at 0x000001DE8FE577C0, file "<unlucky>", line 55>

然后是分析输入日志(已知flag头和flag长度为56),输入.;,;.{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}测试

观察到很有规律,先是每个flag里每个位置上的字母乘以常数然后求和

> .;,;.{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}
push 97 (640)
push 106
pop 106 + pop 97 + push 10282 (mul)
push 97 (641)
push 27
pop 27 + pop 97 + push 2619 (mul)
push 97 (642)
push 140
pop 140 + pop 97 + push 13580 (mul)
push 97 (643)
push 138
pop 138 + pop 97 + push 13386 (mul)
push 97 (644)
push 108
pop 108 + pop 97 + push 10476 (mul)
push 97 (645)
push 91
pop 91 + pop 97 + push 8827 (mul)
push 97 (646)
push 131
pop 131 + pop 97 + push 12707 (mul)
push 97 (647)
push 138
pop 138 + pop 97 + push 13386 (mul)
push 97 (648)
push 106
pop 106 + pop 97 + push 10282 (mul)
push 97 (649)
push 127
pop 127 + pop 97 + push 12319 (mul)
push 97 (650)
push 161
pop 161 + pop 97 + push 15617 (mul)
push 97 (651)
push 115
pop 115 + pop 97 + push 11155 (mul)
push 97 (652)
push 177
pop 177 + pop 97 + push 17169 (mul)
push 97 (653)
push 152
pop 152 + pop 97 + push 14744 (mul)
push 97 (654)
push 15
pop 15 + pop 97 + push 1455 (mul)
push 97 (655)
push 55
pop 55 + pop 97 + push 5335 (mul)
push 97 (656)
push 230
pop 230 + pop 97 + push 22310 (mul)
push 97 (657)
push 131
pop 131 + pop 97 + push 12707 (mul)
push 97 (658)
push 147
pop 147 + pop 97 + push 14259 (mul)
push 97 (659)
push 183
pop 183 + pop 97 + push 17751 (mul)
push 97 (660)
push 235
pop 235 + pop 97 + push 22795 (mul)
push 97 (661)
push 197
pop 197 + pop 97 + push 19109 (mul)
push 97 (662)
push 200
pop 200 + pop 97 + push 19400 (mul)
push 97 (663)
push 104
pop 104 + pop 97 + push 10088 (mul)
push 97 (664)
push 188
pop 188 + pop 97 + push 18236 (mul)
push 97 (665)
push 196
pop 196 + pop 97 + push 19012 (mul)
push 97 (666)
push 118
pop 118 + pop 97 + push 11446 (mul)
push 97 (667)
push 28
pop 28 + pop 97 + push 2716 (mul)
push 97 (668)
push 21
pop 21 + pop 97 + push 2037 (mul)
push 97 (669)
push 97
pop 97 + pop 97 + push 9409 (mul)
push 97 (670)
push 151
pop 151 + pop 97 + push 14647 (mul)
push 97 (671)
push 217
pop 217 + pop 97 + push 21049 (mul)
push 97 (672)
push 118
pop 118 + pop 97 + push 11446 (mul)
push 97 (673)
push 22
pop 22 + pop 97 + push 2134 (mul)
push 97 (674)
push 212
pop 212 + pop 97 + push 20564 (mul)
push 97 (675)
push 31
pop 31 + pop 97 + push 3007 (mul)
push 97 (676)
push 101
pop 101 + pop 97 + push 9797 (mul)
push 97 (677)
push 227
pop 227 + pop 97 + push 22019 (mul)
push 97 (678)
push 155
pop 155 + pop 97 + push 15035 (mul)
push 97 (679)
push 237
pop 237 + pop 97 + push 22989 (mul)
push 97 (680)
push 146
pop 146 + pop 97 + push 14162 (mul)
push 97 (681)
push 68
pop 68 + pop 97 + push 6596 (mul)
push 97 (682)
push 75
pop 75 + pop 97 + push 7275 (mul)
push 97 (683)
push 71
pop 71 + pop 97 + push 6887 (mul)
push 97 (684)
push 218
pop 218 + pop 97 + push 21146 (mul)
push 97 (685)
push 173
pop 173 + pop 97 + push 16781 (mul)
push 97 (686)
push 41
pop 41 + pop 97 + push 3977 (mul)
push 97 (687)
push 220
pop 220 + pop 97 + push 21340 (mul)
push 97 (688)
push 161
pop 161 + pop 97 + push 15617 (mul)
pop 15617 + pop 21340 + push 36957 (add)
pop 36957 + pop 3977 + push 40934 (add)
pop 40934 + pop 16781 + push 57715 (add)
pop 57715 + pop 21146 + push 78861 (add)
pop 78861 + pop 6887 + push 85748 (add)
pop 85748 + pop 7275 + push 93023 (add)
pop 93023 + pop 6596 + push 99619 (add)
pop 99619 + pop 14162 + push 113781 (add)
pop 113781 + pop 22989 + push 136770 (add)
pop 136770 + pop 15035 + push 151805 (add)
pop 151805 + pop 22019 + push 173824 (add)
pop 173824 + pop 9797 + push 183621 (add)
pop 183621 + pop 3007 + push 186628 (add)
pop 186628 + pop 20564 + push 207192 (add)
pop 207192 + pop 2134 + push 209326 (add)
pop 209326 + pop 11446 + push 220772 (add)
pop 220772 + pop 21049 + push 241821 (add)
pop 241821 + pop 14647 + push 256468 (add)
pop 256468 + pop 9409 + push 265877 (add)
pop 265877 + pop 2037 + push 267914 (add)
pop 267914 + pop 2716 + push 270630 (add)
pop 270630 + pop 11446 + push 282076 (add)
pop 282076 + pop 19012 + push 301088 (add)
pop 301088 + pop 18236 + push 319324 (add)
pop 319324 + pop 10088 + push 329412 (add)
pop 329412 + pop 19400 + push 348812 (add)
pop 348812 + pop 19109 + push 367921 (add)
pop 367921 + pop 22795 + push 390716 (add)
pop 390716 + pop 17751 + push 408467 (add)
pop 408467 + pop 14259 + push 422726 (add)
pop 422726 + pop 12707 + push 435433 (add)
pop 435433 + pop 22310 + push 457743 (add)
pop 457743 + pop 5335 + push 463078 (add)
pop 463078 + pop 1455 + push 464533 (add)
pop 464533 + pop 14744 + push 479277 (add)
pop 479277 + pop 17169 + push 496446 (add)
pop 496446 + pop 11155 + push 507601 (add)
pop 507601 + pop 15617 + push 523218 (add)
pop 523218 + pop 12319 + push 535537 (add)
pop 535537 + pop 10282 + push 545819 (add)
pop 545819 + pop 13386 + push 559205 (add)
pop 559205 + pop 12707 + push 571912 (add)
pop 571912 + pop 8827 + push 580739 (add)
pop 580739 + pop 10476 + push 591215 (add)
pop 591215 + pop 13386 + push 604601 (add)
pop 604601 + pop 13580 + push 618181 (add)
pop 618181 + pop 2619 + push 620800 (add)
pop 620800 + pop 10282 + push 631082 (add)
mov m[4096], 631082
push 97 (640)
push 56
pop 56 + pop 97 + push 5432 (mul)
push 97 (641)
push 249
pop 249 + pop 97 + push 24153 (mul)
push 97 (642)
push 152
pop 152 + pop 97 + push 14744 (mul)
push 97 (643)
push 225
pop 225 + pop 97 + push 21825 (mul)
push 97 (644)
push 66
pop 66 + pop 97 + push 6402 (mul)
push 97 (645)
push 136
pop 136 + pop 97 + push 13192 (mul)
push 97 (646)
push 113
pop 113 + pop 97 + push 10961 (mul)
push 97 (647)
push 243
pop 243 + pop 97 + push 23571 (mul)
push 97 (648)
push 63
pop 63 + pop 97 + push 6111 (mul)
push 97 (649)
push 233
pop 233 + pop 97 + push 22601 (mul)
push 97 (650)
push 254
pop 254 + pop 97 + push 24638 (mul)
push 97 (651)
push 69
pop 69 + pop 97 + push 6693 (mul)
push 97 (652)
push 191
pop 191 + pop 97 + push 18527 (mul)
push 97 (653)
push 1
pop 1 + pop 97 + push 97 (mul)
push 97 (654)
push 147
pop 147 + pop 97 + push 14259 (mul)
push 97 (655)
push 169
pop 169 + pop 97 + push 16393 (mul)
push 97 (656)
push 118
pop 118 + pop 97 + push 11446 (mul)
push 97 (657)
push 97
pop 97 + pop 97 + push 9409 (mul)
push 97 (658)
push 193
pop 193 + pop 97 + push 18721 (mul)
push 97 (659)
push 175
pop 175 + pop 97 + push 16975 (mul)
push 97 (660)
push 25
pop 25 + pop 97 + push 2425 (mul)
push 97 (661)
push 141
pop 141 + pop 97 + push 13677 (mul)
push 97 (662)
push 234
pop 234 + pop 97 + push 22698 (mul)
push 97 (663)
push 105
pop 105 + pop 97 + push 10185 (mul)
push 97 (664)
push 9
pop 9 + pop 97 + push 873 (mul)
push 97 (665)
push 53
pop 53 + pop 97 + push 5141 (mul)
push 97 (666)
push 115
pop 115 + pop 97 + push 11155 (mul)
push 97 (667)
push 162
pop 162 + pop 97 + push 15714 (mul)
push 97 (668)
push 104
pop 104 + pop 97 + push 10088 (mul)
push 97 (669)
push 104
pop 104 + pop 97 + push 10088 (mul)
push 97 (670)
push 153
pop 153 + pop 97 + push 14841 (mul)
push 97 (671)
push 57
pop 57 + pop 97 + push 5529 (mul)
push 97 (672)
push 11
pop 11 + pop 97 + push 1067 (mul)
push 97 (673)
push 28
pop 28 + pop 97 + push 2716 (mul)
push 97 (674)
push 3
pop 3 + pop 97 + push 291 (mul)
push 97 (675)
push 146
pop 146 + pop 97 + push 14162 (mul)
push 97 (676)
push 14
pop 14 + pop 97 + push 1358 (mul)
push 97 (677)
push 70
pop 70 + pop 97 + push 6790 (mul)
push 97 (678)
push 154
pop 154 + pop 97 + push 14938 (mul)
push 97 (679)
push 102
pop 102 + pop 97 + push 9894 (mul)
push 97 (680)
push 169
pop 169 + pop 97 + push 16393 (mul)
push 97 (681)
push 66
pop 66 + pop 97 + push 6402 (mul)
push 97 (682)
push 133
pop 133 + pop 97 + push 12901 (mul)
push 97 (683)
push 29
pop 29 + pop 97 + push 2813 (mul)
push 97 (684)
push 107
pop 107 + pop 97 + push 10379 (mul)
push 97 (685)
push 155
pop 155 + pop 97 + push 15035 (mul)
push 97 (686)
push 22
pop 22 + pop 97 + push 2134 (mul)
push 97 (687)
push 231
pop 231 + pop 97 + push 22407 (mul)
push 97 (688)
push 61
pop 61 + pop 97 + push 5917 (mul)
pop 5917 + pop 22407 + push 28324 (add)
pop 28324 + pop 2134 + push 30458 (add)
pop 30458 + pop 15035 + push 45493 (add)
pop 45493 + pop 10379 + push 55872 (add)
pop 55872 + pop 2813 + push 58685 (add)
pop 58685 + pop 12901 + push 71586 (add)
pop 71586 + pop 6402 + push 77988 (add)
pop 77988 + pop 16393 + push 94381 (add)
pop 94381 + pop 9894 + push 104275 (add)
pop 104275 + pop 14938 + push 119213 (add)
pop 119213 + pop 6790 + push 126003 (add)
pop 126003 + pop 1358 + push 127361 (add)
pop 127361 + pop 14162 + push 141523 (add)
pop 141523 + pop 291 + push 141814 (add)
pop 141814 + pop 2716 + push 144530 (add)
pop 144530 + pop 1067 + push 145597 (add)
pop 145597 + pop 5529 + push 151126 (add)
pop 151126 + pop 14841 + push 165967 (add)
pop 165967 + pop 10088 + push 176055 (add)
pop 176055 + pop 10088 + push 186143 (add)
pop 186143 + pop 15714 + push 201857 (add)
pop 201857 + pop 11155 + push 213012 (add)
pop 213012 + pop 5141 + push 218153 (add)
pop 218153 + pop 873 + push 219026 (add)
pop 219026 + pop 10185 + push 229211 (add)
pop 229211 + pop 22698 + push 251909 (add)
pop 251909 + pop 13677 + push 265586 (add)
pop 265586 + pop 2425 + push 268011 (add)
pop 268011 + pop 16975 + push 284986 (add)
pop 284986 + pop 18721 + push 303707 (add)
pop 303707 + pop 9409 + push 313116 (add)
pop 313116 + pop 11446 + push 324562 (add)
pop 324562 + pop 16393 + push 340955 (add)
pop 340955 + pop 14259 + push 355214 (add)
pop 355214 + pop 97 + push 355311 (add)
pop 355311 + pop 18527 + push 373838 (add)
pop 373838 + pop 6693 + push 380531 (add)
pop 380531 + pop 24638 + push 405169 (add)
pop 405169 + pop 22601 + push 427770 (add)
pop 427770 + pop 6111 + push 433881 (add)
pop 433881 + pop 23571 + push 457452 (add)
pop 457452 + pop 10961 + push 468413 (add)
pop 468413 + pop 13192 + push 481605 (add)
pop 481605 + pop 6402 + push 488007 (add)
pop 488007 + pop 21825 + push 509832 (add)
pop 509832 + pop 14744 + push 524576 (add)
pop 524576 + pop 24153 + push 548729 (add)
pop 548729 + pop 5432 + push 554161 (add)
mov m[4100], 554161
push 97 (640)
...
pop 647184 + pop 20952 + push 668136 (add)
pop 668136 + pop 5432 + push 673568 (add)
pop 673568 + pop 3007 + push 676575 (add)
mov m[4136], 676575
push 97 (666)
marshal xor 97
Traceback (most recent call last):
  File "xxxx\smileyCTF2025\dna\main.py", line 146, in <module>
    f.__code__ = marshal.loads(decrypted_code)
ValueError: bad marshal data (unknown type code)

发现最后marshal.loads报错,说明之前异或key不对,要满足条件,结合push 97 (666)和以下代码可知读取的是第26位的字符

# 提取 flag 的核心部分并加载到内存
flag_core = flag[6:-1]
for i in range(len(flag_core)):
    m[640 + i] = flag_core[i]

那么我需要确保正确的key,才能不报错,跑几次就知道固定位是哪些了

flag = ["a"] * 49
flag[26] = "o"
flag[27] = "u"
flag[22] = "i"
flag[33] = "a"
print(".;,;.{"+"".join(flag)+"}")

此时完整的跑完了所有代码,日志最后如下,可以看到做了cmp并打印了WRONG!

push 692012
pop 692012 + pop 634894 + push False (cmp)
push 560883 (4100)
push 611030
pop 611030 + pop 560883 + push False (cmp)
push 611342 (4104)
push 658676
pop 658676 + pop 611342 + push False (cmp)
push 509003 (4108)
push 556679
pop 556679 + pop 509003 + push False (cmp)
push 546430 (4112)
push 588728
pop 588728 + pop 546430 + push False (cmp)
push 579826 (4116)
push 628470
pop 628470 + pop 579826 + push False (cmp)
push 602413 (4120)
push 659130
pop 659130 + pop 602413 + push False (cmp)
push 577942 (4124)
push 623012
pop 623012 + pop 577942 + push False (cmp)
push 550513 (4128)
push 590356
pop 590356 + pop 550513 + push False (cmp)
push 613384 (4132)
push 670831
pop 670831 + pop 613384 + push False (cmp)
push 680525 (4136)
push 734960
pop 734960 + pop 680525 + push False (cmp)
push 644669 (4140)
push 694096
pop 694096 + pop 644669 + push False (cmp)
push 629106 (4144)
push 673431
pop 673431 + pop 629106 + push False (cmp)
push 617752 (4148)
push 676517
pop 676517 + pop 617752 + push False (cmp)
push 587496 (4152)
push 638313
pop 638313 + pop 587496 + push False (cmp)
push 669877 (4156)
push 730305
pop 730305 + pop 669877 + push False (cmp)
push 596543 (4160)
push 651347
pop 651347 + pop 596543 + push False (cmp)
push 570569 (4164)
push 612947
pop 612947 + pop 570569 + push False (cmp)
push 563354 (4168)
push 614037
pop 614037 + pop 563354 + push False (cmp)
push 663445 (4172)
push 722768
pop 722768 + pop 663445 + push False (cmp)
push 600977 (4176)
push 662232
pop 662232 + pop 600977 + push False (cmp)
push 562147 (4180)
push 608720
pop 608720 + pop 562147 + push False (cmp)
push 549327 (4184)
push 598699
pop 598699 + pop 549327 + push False (cmp)
push 574252 (4188)
push 626932
pop 626932 + pop 574252 + push False (cmp)
push 606902 (4192)
push 659018
pop 659018 + pop 606902 + push False (cmp)
push 509219 (4196)
push 554138
pop 554138 + pop 509219 + push False (cmp)
push 577055 (4200)
push 627484
pop 627484 + pop 577055 + push False (cmp)
push 563062 (4204)
push 620929
pop 620929 + pop 563062 + push False (cmp)
push 604593 (4208)
push 655810
pop 655810 + pop 604593 + push False (cmp)
push 549613 (4212)
push 598103
pop 598103 + pop 549613 + push False (cmp)
push 612597 (4216)
push 664749
pop 664749 + pop 612597 + push False (cmp)
push 715765 (4220)
push 772833
pop 772833 + pop 715765 + push False (cmp)
push 653362 (4224)
push 710796
pop 710796 + pop 653362 + push False (cmp)
push 613421 (4228)
push 669747
pop 669747 + pop 613421 + push False (cmp)
push 533243 (4232)
push 576742
pop 576742 + pop 533243 + push False (cmp)
push 654872 (4236)
push 715958
pop 715958 + pop 654872 + push False (cmp)
push 628632 (4240)
push 682073
pop 682073 + pop 628632 + push False (cmp)
push 634846 (4244)
push 687276
pop 687276 + pop 634846 + push False (cmp)
push 737893 (4248)
push 806029
pop 806029 + pop 737893 + push False (cmp)
push 608557 (4252)
push 660519
pop 660519 + pop 608557 + push False (cmp)
push 669695 (4256)
push 728567
pop 728567 + pop 669695 + push False (cmp)
push 634701 (4260)
push 689664
pop 689664 + pop 634701 + push False (cmp)
push 686508 (4264)
push 746796
pop 746796 + pop 686508 + push False (cmp)
push 549765 (4268)
push 597800
pop 597800 + pop 549765 + push False (cmp)
push 570832 (4272)
push 629625
pop 629625 + pop 570832 + push False (cmp)
push 541830 (4276)
push 585142
pop 585142 + pop 541830 + push False (cmp)
push 620926 (4280)
push 678960
pop 678960 + pop 620926 + push False (cmp)
push 609713 (4284)
push 665322
pop 665322 + pop 609713 + push False (cmp)
push 655189 (4288)
push 710793
pop 710793 + pop 655189 + push False (cmp)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
pop 0 + pop 0 + push 0 (add)
push 49
pop 49 + pop 0 + push False (cmp)
jmp 69308 if 0!=1 else pc+=12
push 87
Wpush 82
Rpush 79
Opush 78
Npush 71
Gpush 33
!push 10

观察cmp值正是之前求和,此时就清楚了要用z3求解,把乘的常数和cmp的常数全部打印下来

from z3 import *

mul = [106, 27, 140, 138, 108, 91, 131, 138, 106, 127, 161, 115, 177, 152, 15, 55, 230, 131, 147, 183, 235, 197, 200, 104, 188, 196, 118, 28, 21, 97, 151, 217, 118, 22, 212, 31, 101, 227, 155, 237, 146, 68, 75, 71, 218, 173, 41, 220, 161, 56, 249, 152, 225, 66, 136, 113, 243, 63, 233, 254, 69, 191, 1, 147, 169, 118, 97, 193, 175, 25, 141, 234, 105, 9, 53, 115, 162, 104, 104, 153, 57, 11, 28, 3, 146, 14, 70, 154, 102, 169, 66, 133, 29, 107, 155, 22, 231, 61, 149, 104, 66, 72, 140, 134, 140, 174, 236, 10, 209, 162, 15, 223, 191, 183, 77, 137, 106, 69, 54, 1, 122, 195, 62, 99, 155, 10, 18, 117, 164, 216, 231, 150, 255, 127, 193, 145, 190, 34, 46, 64, 189, 182, 27, 163, 156, 156, 150, 67, 113, 188, 13, 173, 1, 115, 188, 151, 10, 188, 30, 74, 224, 175, 170, 60, 43, 188, 162, 85, 16, 28, 80, 4, 32, 83, 156, 173, 222, 92, 105, 251, 218, 180, 75, 122, 7, 11, 68, 26, 140, 122, 201, 116, 65, 5, 101, 84, 105, 219, 67, 72, 186, 183, 69, 249, 212, 86, 31, 81, 27, 207, 68, 16, 188, 133, 25, 94, 132, 72, 83, 9, 154, 87, 12, 149, 255, 225, 199, 114, 138, 200, 131, 175, 62, 39, 7, 21, 135, 83, 25, 47, 58, 72, 235, 230, 127, 198, 192, 176, 56, 51, 114, 132, 115, 180, 236, 17, 23, 145, 148, 54, 152, 33, 78, 191, 203, 193, 236, 77, 7, 196, 202, 134, 145, 61, 50, 244, 0, 37, 103, 162, 172, 246, 250, 147, 114, 45, 196, 24, 150, 13, 21, 64, 115, 24, 29, 45, 240, 12, 189, 166, 2, 253, 204, 91, 7, 70, 163, 182, 166, 31, 139, 1, 229, 118, 218, 229, 40, 169, 59, 97, 224, 67, 195, 95, 13, 72, 186, 53, 122, 229, 42, 113, 117, 246, 182, 69, 90, 135, 192, 156, 122, 181, 111, 114, 134, 171, 106, 59, 64, 227, 11, 105, 240, 221, 87, 76, 80, 204, 240, 26, 196, 170, 24, 140, 68, 48, 64, 238, 238, 141, 106, 221, 82, 151, 24, 233, 67, 216, 197, 4, 22, 82, 235, 152, 195, 53, 12, 27, 134, 42, 163, 2, 127, 63, 220, 64, 42, 237, 19, 182, 58, 14, 15, 176, 7, 57, 158, 119, 231, 97, 35, 167, 21, 40, 238, 111, 119, 116, 99, 12, 8, 77, 120, 201, 101, 218, 27, 109, 24, 109, 234, 245, 230, 138, 154, 174, 159, 184, 56, 146, 81, 253, 185, 175, 59, 219, 231, 246, 46, 101, 95, 237, 171, 242, 134, 95, 152, 121, 232, 43, 50, 135, 70, 144, 122, 118, 75, 138, 57, 120, 120, 198, 38, 202, 51, 17, 142, 190, 122, 111, 110, 16, 60, 130, 147, 180, 70, 200, 71, 39, 31, 56, 216, 186, 8, 162, 252, 157, 136, 117, 254, 188, 72, 113, 153, 135, 218, 103, 228, 91, 99, 234, 249, 144, 235, 70, 17, 86, 161, 143, 241, 234, 87, 152, 247, 109, 154, 231, 193, 48, 174, 41, 118, 139, 244, 43, 115, 41, 50, 60, 107, 224, 167, 53, 64, 187, 212, 249, 64, 32, 237, 18, 155, 194, 215, 15, 1, 30, 239, 163, 225, 161, 87, 228, 113, 71, 153, 183, 62, 146, 54, 231, 201, 56, 252, 112, 130, 208, 205, 11, 255, 91, 7, 114, 91, 175, 246, 37, 135, 96, 194, 108, 97, 191, 20, 140, 113, 63, 145, 97, 221, 100, 89, 38, 8, 31, 47, 68, 225, 54, 124, 140, 215, 189, 167, 210, 93, 149, 172, 5, 14, 207, 186, 124, 188, 247, 161, 238, 215, 226, 48, 26, 185, 170, 84, 253, 92, 221, 229, 12, 122, 30, 173, 171, 188, 64, 199, 16, 209, 221, 139, 5, 249, 240, 118, 37, 126, 252, 253, 95, 92, 73, 241, 156, 69, 44, 229, 224, 8, 58, 35, 146, 47, 177, 142, 100, 156, 37, 0, 97, 227, 100, 53, 12, 220, 212, 95, 87, 172, 60, 150, 10, 71, 141, 50, 204, 201, 212, 248, 235, 115, 76, 56, 32, 82, 169, 83, 206, 175, 83, 223, 100, 244, 34, 127, 24, 76, 136, 128, 226, 146, 187, 51, 232, 236, 53, 60, 38, 54, 51, 0, 228, 114, 34, 185, 251, 59, 207, 64, 175, 77, 94, 243, 222, 81, 138, 176, 175, 83, 74, 160, 243, 128, 222, 56, 7, 160, 112, 141, 64, 237, 21, 110, 83, 217, 222, 54, 194, 201, 227, 149, 242, 10, 78, 254, 196, 130, 232, 115, 62, 159, 164, 30, 72, 110, 186, 42, 142, 162, 231, 238, 121, 109, 214, 64, 222, 178, 67, 114, 193, 78, 90, 39, 35, 181, 182, 99, 7, 177, 20, 131, 106, 249, 101, 153, 43, 237, 17, 54, 97, 173, 63, 193, 115, 17, 192, 11, 252, 75, 7, 214, 163, 137, 157, 175, 119, 133, 215, 235, 223, 6, 195, 165, 156, 63, 72, 2, 193, 184, 39, 231, 155, 98, 79, 183, 185, 146, 62, 84, 216, 246, 91, 217, 82, 93, 52, 161, 74, 13, 36, 50, 34, 86, 102, 38, 21, 122, 67, 28, 186, 24, 191, 166, 92, 195, 65, 177, 193, 150, 153, 235, 164, 177, 52, 39, 143, 24, 85, 197, 41, 84, 78, 36, 18, 232, 243, 57, 110, 145, 18, 75, 55, 164, 81, 116, 21, 122, 122, 181, 171, 57, 20, 63, 147, 66, 226, 188, 141, 104, 194, 81, 250, 180, 121, 157, 28, 204, 8, 242, 114, 156, 5, 240, 115, 129, 142, 194, 160, 36, 136, 193, 181, 241, 63, 253, 254, 211, 57, 35, 89, 66, 63, 73, 59, 171, 217, 209, 126, 155, 247, 43, 150, 99, 153, 215, 132, 103, 16, 86, 242, 176, 180, 114, 217, 233, 76, 158, 79, 35, 127, 167, 46, 119, 222, 128, 169, 191, 253, 120, 190, 123, 236, 110, 163, 65, 94, 22, 31, 35, 231, 16, 174, 168, 106, 95, 93, 160, 29, 179, 53, 183, 7, 60, 162, 189, 74, 110, 106, 103, 248, 69, 173, 169, 88, 169, 73, 188, 107, 110, 150, 138, 26, 123, 0, 127, 113, 245, 44, 14, 67, 52, 165, 224, 252, 82, 28, 110, 54, 122, 1, 30, 183, 104, 206, 46, 8, 207, 183, 138, 182, 117, 156, 110, 128, 157, 171, 7, 91, 8, 156, 69, 25, 236, 68, 60, 213, 4, 172, 95, 27, 5, 124, 203, 55, 111, 229, 133, 98, 107, 120, 40, 156, 95, 115, 180, 208, 106, 59, 47, 57, 104, 29, 53, 166, 204, 120, 186, 112, 86, 85, 154, 77, 166, 211, 120, 219, 118, 226, 143, 174, 202, 237, 226, 42, 101, 79, 81, 213, 110, 180, 81, 38, 104, 24, 89, 112, 177, 161, 121, 81, 34, 81, 196, 75, 3, 110, 134, 218, 104, 242, 130, 140, 38, 49, 75, 139, 62, 110, 172, 106, 86, 142, 77, 167, 105, 105, 80, 17, 66, 212, 94, 125, 6, 41, 160, 157, 182, 200, 154, 66, 212, 231, 77, 42, 249, 125, 129, 208, 128, 20, 192, 243, 33, 162, 17, 164, 94, 246, 186, 143, 50, 185, 248, 186, 123, 60, 80, 66, 62, 33, 247, 129, 8, 239, 31, 81, 139, 25, 57, 233, 229, 185, 96, 173, 22, 47, 37, 104, 128, 20, 133, 176, 50, 37, 250, 84, 13, 246, 72, 102, 23, 30, 204, 231, 98, 17, 106, 39, 1, 7, 253, 94, 230, 87, 32, 191, 23, 167, 150, 140, 55, 80, 67, 119, 105, 196, 90, 196, 124, 253, 35, 0, 91, 143, 122, 176, 71, 215, 5, 108, 122, 252, 188, 219, 200, 159, 159, 241, 232, 83, 79, 17, 194, 208, 15, 62, 67, 80, 123, 29, 47, 168, 234, 68, 56, 24, 46, 45, 89, 46, 132, 221, 86, 69, 12, 13, 225, 71, 76, 254, 169, 78, 135, 82, 5, 193, 231, 141, 149, 251, 25, 132, 26, 57, 222, 26, 210, 42, 138, 145, 47, 201, 59, 135, 71, 160, 129, 127, 45, 47, 151, 54, 241, 57, 219, 71, 248, 77, 91, 44, 145, 176, 240, 164, 45, 125, 101, 228, 50, 221, 161, 175, 235, 92, 65, 229, 128, 14, 254, 144, 9, 147, 4, 6, 152, 66, 147, 157, 193, 85, 253, 174, 112, 181, 86, 158, 90, 42, 94, 244, 58, 125, 199, 111, 8, 89, 37, 218, 9, 200, 50, 178, 247, 234, 21, 251, 76, 5, 175, 105, 22, 51, 139, 244, 146, 22, 202, 54, 65, 76, 43, 205, 86, 158, 124, 71, 178, 67, 2, 64, 121, 13, 76, 108, 29, 193, 114, 48, 103, 219, 111, 131, 122, 124, 167, 83, 217, 11, 110, 232, 131, 235, 213, 78, 227, 127, 52, 163, 62, 234, 203, 174, 73, 12, 61, 208, 167, 214, 4, 132, 152, 31, 115, 211, 189, 158, 201, 87, 121, 228, 246, 15, 236, 9, 96, 222, 112, 108, 104, 139, 89, 56, 48, 132, 111, 20, 7, 72, 174, 235, 34, 250, 173, 179, 188, 218, 123, 30, 226, 40, 228, 207, 17, 141, 21, 172, 128, 23, 26, 117, 175, 128, 202, 44, 239, 161, 166, 253, 191, 107, 183, 138, 127, 213, 50, 133, 75, 184, 199, 199, 255, 67, 180, 159, 152, 232, 84, 239, 155, 61, 154, 162, 51, 85, 204, 216, 23, 125, 151, 251, 116, 139, 196, 231, 180, 54, 24, 111, 13, 90, 158, 61, 118, 133, 150, 228, 195, 38, 121, 224, 156, 179, 162, 0, 241, 91, 38, 162, 115, 63, 188, 196, 70, 239, 131, 241, 164, 158, 107, 181, 167, 146, 147, 68, 213, 184, 252, 52, 167, 10, 23, 35, 2, 182, 150, 103, 196, 58, 132, 146, 243, 222, 104, 27, 63, 212, 76, 195, 92, 188, 107, 92, 96, 145, 141, 177, 108, 174, 23, 17, 229, 178, 64, 209, 44, 190, 223, 69, 65, 108, 111, 229, 104, 201, 105, 188, 81, 192, 56, 53, 82, 83, 241, 15, 97, 166, 194, 23, 241, 86, 72, 141, 116, 86, 21, 68, 54, 237, 96, 66, 240, 11, 53, 119, 39, 63, 139, 180, 19, 202, 23, 15, 195, 123, 52, 157, 177, 129, 30, 248, 141, 245, 255, 19, 91, 249, 52, 3, 211, 225, 82, 142, 212, 72, 223, 175, 219, 22, 211, 250, 121, 209, 45, 70, 128, 208, 70, 128, 124, 6, 247, 52, 156, 1, 137, 79, 174, 69, 170, 98, 230, 213, 102, 33, 44, 246, 209, 236, 70, 70, 180, 71, 155, 207, 228, 14, 137, 43, 94, 45, 53, 176, 121, 255, 206, 56, 61, 140, 191, 87, 197, 142, 155, 55, 67, 19, 139, 155, 21, 106, 88, 239, 224, 208, 203, 45, 212, 62, 173, 174, 58, 227, 54, 6, 179, 3, 126, 149, 167, 108, 150, 33, 219, 198, 233, 251, 168, 115, 36, 55, 160, 235, 16, 76, 142, 228, 123, 184, 221, 116, 74, 85, 147, 59, 113, 61, 166, 245, 23, 172, 132, 10, 24, 199, 47, 199, 66, 203, 197, 253, 129, 193, 113, 238, 10, 19, 231, 203, 51, 138, 219, 210, 176, 236, 182, 147, 23, 25, 251, 52, 161, 213, 230, 194, 61, 229, 224, 19, 243, 233, 43, 26, 77, 198, 245, 153, 232, 122, 253, 150, 121, 206, 176, 248, 177, 99, 98, 198, 130, 57, 179, 156, 111, 253, 204, 184, 159, 220, 72, 176, 156, 79, 160, 40, 201, 95, 63, 240, 9, 140, 44, 36, 92, 17, 251, 178, 81, 226, 91, 66, 50, 241, 73, 84, 24, 64, 187, 27, 52, 61, 241, 181, 155, 135, 47, 113, 191, 232, 207, 56, 58, 179, 252, 193, 242, 85, 168, 251, 47, 196, 147, 166, 223, 251, 42, 55, 28, 185, 38, 23, 230, 239, 105, 238, 217, 197, 238, 107, 178, 212, 27, 95, 77, 134, 159, 61, 229, 7, 85, 96, 87, 232, 125, 89, 44, 152, 66, 61, 223, 181, 77, 50, 127, 215, 247, 134, 13, 30, 98, 64, 199, 77, 161, 210, 128, 124, 91, 239, 20, 186, 222, 151, 186, 92, 172, 13, 223, 215, 65, 161, 108, 172, 64, 40, 117, 189, 227, 135, 81, 174, 204, 183, 45, 61, 83, 195, 51, 183, 203, 42, 52, 215, 162, 208, 149, 221, 184, 64, 219, 6, 155, 196, 206, 240, 226, 168, 94, 189, 28, 146, 209, 84, 250, 204, 204, 246, 112, 223, 29, 30, 69, 244, 100, 37, 250, 20, 255, 174, 193, 91, 65, 126, 75, 7, 114, 141, 55, 232, 108, 24, 251, 61, 153, 121, 90, 58, 27, 45, 142, 3, 88, 54, 29, 122, 145, 160, 70, 146, 125, 187, 40, 78, 91, 155, 111, 153, 33, 106, 232, 210, 198, 47, 122, 223, 154, 4, 155, 60, 81, 255, 225, 22, 92, 56, 93, 170, 52, 165, 34, 229, 99, 90, 18, 232, 42, 19, 180, 144, 219, 231, 114, 6, 186, 245, 172, 151, 112, 252, 168, 232, 127, 113, 221, 83, 250, 60, 74, 88, 163, 23, 47, 120, 226, 13, 10, 34, 60, 26, 255, 3, 165, 0, 57, 96, 116, 77, 227, 18, 191, 216, 169, 246, 185, 113, 45, 118, 0, 8, 144, 142, 29, 145, 171, 42, 224, 138, 39, 154, 53, 119, 154, 232, 47, 128, 43, 175, 200, 50, 100, 215, 98, 202, 98, 137, 17, 66, 64, 21, 208, 5, 31, 0, 192, 34, 0, 106, 198, 153, 63, 224, 94, 25, 27, 181, 44, 170, 243, 237, 126, 249, 108, 196, 100, 241, 164, 136, 38, 103, 123, 131, 35, 83, 182, 252, 16, 54, 209, 223, 2, 62, 199, 158, 39, 122, 118, 145, 30, 65, 212, 199, 70, 205, 216, 97, 227, 167, 124, 20, 193, 221, 116, 101, 164, 158, 33, 116, 181, 150, 215, 123, 248, 30, 214, 155, 77, 105, 188, 139, 162, 95, 118, 219, 66, 246, 136, 92, 197, 7, 199, 216, 112, 29, 200, 22, 80, 64, 7, 203, 100, 80, 26, 1, 10, 177, 31, 35, 108, 132, 53, 119, 122, 72, 51, 62, 160, 167, 251, 191, 245, 142, 79, 235, 184, 142, 194, 218, 240, 66, 226, 179, 125, 18, 246, 234, 25, 56, 4, 240, 215, 214, 42, 143, 32, 87, 5, 215, 62, 231, 179, 186, 219]
cmp = [692012, 611030, 658676, 556679, 588728, 628470, 659130, 623012, 590356, 670831, 734960, 694096, 673431, 676517, 638313, 730305, 651347, 612947, 614037, 722768, 662232, 608720, 598699, 626932, 659018, 554138, 627484, 620929, 655810, 598103, 664749, 772833, 710796, 669747, 576742, 715958, 682073, 687276, 806029, 660519, 728567, 689664, 746796, 597800, 629625, 585142, 678960, 665322, 710793]
flag = [BitVec(f'flag{i}', 8) for i in range(49)]
s = Solver()
for i in range(0, len(mul), 49):
    sum = 0
    for j in range(49):
        sum += flag[j] * mul[i+j]
    s.add(sum == cmp[i//49])
s.add(flag[26] == ord("o"))
s.add(flag[27] == ord("u"))
s.add(flag[22] == ord("i"))
s.add(flag[33] == ord("a"))
if s.check() == sat:
    m = s.model()
    for i in flag:
        print(chr(m[i].as_long()), end='')

稍等一小会就得到flag为we_ought_to_start_storing_our_data_as_dna_instead

liqUID glASS

挺有创新性的,结合最近苹果他们新出的液态玻璃特效出了个图像处理技术

他们部署了一个在线网站,可以尝试转换下,在网站源代码里找到了liquidglass.wasm,用wasm2c得到c代码然后转为链接文件o就可以ida反编译分析代码

结合源代码下的liquidglass.js可知_applyLiquidGlass调用了wasm里的f函数

var _create_buffer, _destroy_buffer, _applyLiquidGlass, __emscripten_stack_restore, __emscripten_stack_alloc, _emscripten_stack_get_current;
function assignWasmExports(wasmExports) {
    Module["_create_buffer"] = _create_buffer = wasmExports["d"];
    Module["_destroy_buffer"] = _destroy_buffer = wasmExports["e"];
    Module["_applyLiquidGlass"] = _applyLiquidGlass = wasmExports["f"];
    __emscripten_stack_restore = wasmExports["g"];
    __emscripten_stack_alloc = wasmExports["h"];
    _emscripten_stack_get_current = wasmExports["i"]
}

在ida里找到带有liquidglass和f的函数

__int64 __fastcall w2c_liquidglass_f(__int64 a1, unsigned int a2, unsigned int a3, unsigned int a4, unsigned int a5)
{
  return w2c_liquidglass_f_0(a1, a2, a3, a4, a5);
}
_BOOL8 __fastcall w2c_liquidglass_f_0(__int64 a1, int a2, int a3, int a4, int a5)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS NUMPAD "+" TO EXPAND]

  v120 = 0;
  result = a5 <= 0;
  if ( a5 > 0 )
  {
    result = a4 <= 0;
    if ( a4 > 0 )
    {
      v94 = a5 - 1;
      v71 = (float)(a5 - 1);
      v93 = a4 - 1;
      v70 = (float)(a4 - 1);
      v69 = (float)a5;
      v68 = (float)a4;
      do
      {
        v92 = v120 * a4;
        v73 = (float)v120 / v69;
        v72 = v73 + -0.5;
        v121 = 0;
        do
        {
          v102 = *(_DWORD *)(a1 + 8) - 16;
          *(_DWORD *)(a1 + 8) = v102;
          v81 = (float)v121 / v68;
          v116 = (float)(v81 * 25.0) + (float)(v73 * 20.0);
          v105 = i32_reinterpret_f32(*(double *)_mm_cvtsi32_si128(LODWORD(v116)).m128i_i64);
          v110 = v105 & 0x7FFFFFFF;
          if ( (v105 & 0x7FFFFFFFu) > 0x3F490FDA )
          {
            if ( v110 > 0x407B53D1 )
            {
              if ( v110 > 0x40E231D5 )
              {
                if ( v110 >= 0x7F800000 )
                {
                  v116 = v116 - v116;
                  goto LABEL_36;
                }
                v111 = w2c_liquidglass_f5(a1, v102 + 8, *(double *)_mm_cvtsi32_si128(LODWORD(v116)).m128i_i64);
                v65 = f64_load(a1 + 16, v102 + 8LL);
                if ( (v111 & 3) == 3 )
                {
                  v18 = (__m128i)*(unsigned __int64 *)&v65;
                  *(double *)v18.m128i_i64 = w2c_liquidglass_f2(a1, v65);
                  v116 = -COERCE_FLOAT(_mm_cvtsi128_si32(v18));
                }
                else
                {
                  if ( (v111 & 3u) - 1 > 2 )
                    goto LABEL_32;
                  if ( (v111 & 3) == 1 )
                  {
                    v16 = (__m128i)*(unsigned __int64 *)&v65;
                    *(double *)v16.m128i_i64 = w2c_liquidglass_f2(a1, v65);
                    v116 = COERCE_FLOAT(_mm_cvtsi128_si32(v16));
                  }
                  else
                  {
                    if ( (v111 & 3) != 2 )
                    {
LABEL_32:
                      v15 = (__m128i)*(unsigned __int64 *)&v65;
                      *(double *)v15.m128i_i64 = w2c_liquidglass_f1(a1, v65);
                      v116 = COERCE_FLOAT(_mm_cvtsi128_si32(v15));
                      goto LABEL_36;
                    }
                    v17 = (__m128i)(*(_QWORD *)&v65 ^ 0x8000000000000000LL);
                    *(double *)v17.m128i_i64 = w2c_liquidglass_f1(a1, *(double *)v17.m128i_i64);
                    v116 = COERCE_FLOAT(_mm_cvtsi128_si32(v17));
                  }
                }
              }
              else if ( v110 > 0x40AFEDDF )
              {
                if ( v105 >= 0 )
                  v13 = -6.283185307179586;
                else
                  v13 = 6.283185307179586;
                v55 = v13 + wasm_quietf(*(double *)_mm_cvtsi32_si128(LODWORD(v116)).m128i_i64);
                v14 = (__m128i)*(unsigned __int64 *)&v55;
                *(double *)v14.m128i_i64 = w2c_liquidglass_f1(a1, v55);
                v116 = COERCE_FLOAT(_mm_cvtsi128_si32(v14));
              }
              else
              {
                v64 = wasm_quietf(*(double *)_mm_cvtsi32_si128(LODWORD(v116)).m128i_i64);
                if ( v105 >= 0 )
                {
                  v12 = (__m128i)COERCE_UNSIGNED_INT64(v64 + -4.71238898038469);
                  *(double *)v12.m128i_i64 = w2c_liquidglass_f2(a1, *(double *)v12.m128i_i64);
                  v116 = -COERCE_FLOAT(_mm_cvtsi128_si32(v12));
                }
                else
                {
                  v11 = (__m128i)COERCE_UNSIGNED_INT64(v64 + 4.71238898038469);
                  *(double *)v11.m128i_i64 = w2c_liquidglass_f2(a1, *(double *)v11.m128i_i64);
                  v116 = COERCE_FLOAT(_mm_cvtsi128_si32(v11));
                }
              }
            }
            else
            {
              v63 = wasm_quietf(*(double *)_mm_cvtsi32_si128(LODWORD(v116)).m128i_i64);
              if ( v110 > 0x4016CBE3 )
              {
                if ( v105 < 0 )
                  v9 = 3.141592653589793;
                else
                  v9 = -3.141592653589793;
                v10 = (__m128i)COERCE_UNSIGNED_INT64(-(v9 + v63));
                *(double *)v10.m128i_i64 = w2c_liquidglass_f1(a1, *(double *)v10.m128i_i64);
                v116 = COERCE_FLOAT(_mm_cvtsi128_si32(v10));
              }
              else if ( v105 >= 0 )
              {
                v8 = (__m128i)COERCE_UNSIGNED_INT64(v63 + -1.570796326794897);
                *(double *)v8.m128i_i64 = w2c_liquidglass_f2(a1, *(double *)v8.m128i_i64);
                v116 = COERCE_FLOAT(_mm_cvtsi128_si32(v8));
              }
              else
              {
                v7 = (__m128i)COERCE_UNSIGNED_INT64(v63 + 1.570796326794897);
                *(double *)v7.m128i_i64 = w2c_liquidglass_f2(a1, *(double *)v7.m128i_i64);
                v116 = -COERCE_FLOAT(_mm_cvtsi128_si32(v7));
              }
            }
          }
          else if ( v110 >= 0x39800000 )
          {
            v6 = (__m128i)COERCE_UNSIGNED_INT64(wasm_quietf(*(double *)_mm_cvtsi32_si128(LODWORD(v116)).m128i_i64));
            *(double *)v6.m128i_i64 = w2c_liquidglass_f1(a1, *(double *)v6.m128i_i64);
            v116 = COERCE_FLOAT(_mm_cvtsi128_si32(v6));
          }
LABEL_36:
          *(_DWORD *)(a1 + 8) = v102 + 16;
          v76 = v116;
          v103 = *(_DWORD *)(a1 + 8) - 16;
          *(_DWORD *)(a1 + 8) = v103;
          v117 = (float)(v81 * 20.0) + (float)(v73 * 25.0);
          v106 = i32_reinterpret_f32(*(double *)_mm_cvtsi32_si128(LODWORD(v117)).m128i_i64);
          v112 = v106 & 0x7FFFFFFF;
          if ( (v106 & 0x7FFFFFFFu) > 0x3F490FDA )
          {
            if ( v112 > 0x407B53D1 )
            {
              if ( v112 > 0x40E231D5 )
              {
                v115 = v117 - v117;
                if ( v112 >= 0x7F800000 )
                  goto LABEL_68;
                v113 = w2c_liquidglass_f5(a1, v103 + 8, *(double *)_mm_cvtsi32_si128(LODWORD(v117)).m128i_i64);
                v67 = f64_load(a1 + 16, v103 + 8LL);
                if ( (v113 & 3) == 3 )
                {
                  v29 = (__m128i)*(unsigned __int64 *)&v67;
                  *(double *)v29.m128i_i64 = w2c_liquidglass_f1(a1, v67);
                  v115 = COERCE_FLOAT(_mm_cvtsi128_si32(v29));
                }
                else
                {
                  if ( (v113 & 3u) - 1 > 2 )
                    goto LABEL_64;
                  if ( (v113 & 3) == 1 )
                  {
                    v27 = (__m128i)(*(_QWORD *)&v67 ^ 0x8000000000000000LL);
                    *(double *)v27.m128i_i64 = w2c_liquidglass_f1(a1, *(double *)v27.m128i_i64);
                    v115 = COERCE_FLOAT(_mm_cvtsi128_si32(v27));
                  }
                  else
                  {
                    if ( (v113 & 3) != 2 )
                    {
LABEL_64:
                      v26 = (__m128i)*(unsigned __int64 *)&v67;
                      *(double *)v26.m128i_i64 = w2c_liquidglass_f2(a1, v67);
                      v115 = COERCE_FLOAT(_mm_cvtsi128_si32(v26));
                      goto LABEL_68;
                    }
                    v28 = (__m128i)*(unsigned __int64 *)&v67;
                    *(double *)v28.m128i_i64 = w2c_liquidglass_f2(a1, v67);
                    v115 = -COERCE_FLOAT(_mm_cvtsi128_si32(v28));
                  }
                }
              }
              else if ( v112 < 0x40AFEDE0 )
              {
                if ( v106 >= 0 )
                {
                  v25 = (__m128i)COERCE_UNSIGNED_INT64(
                                   wasm_quietf(*(double *)_mm_cvtsi32_si128(LODWORD(v117)).m128i_i64)
                                 + -4.71238898038469);
                  *(double *)v25.m128i_i64 = w2c_liquidglass_f1(a1, *(double *)v25.m128i_i64);
                }
                else
                {
                  v58 = -4.71238898038469 - wasm_quietf(*(double *)_mm_cvtsi32_si128(LODWORD(v117)).m128i_i64);
                  v25 = (__m128i)*(unsigned __int64 *)&v58;
                  *(double *)v25.m128i_i64 = w2c_liquidglass_f1(a1, v58);
                }
                v115 = COERCE_FLOAT(_mm_cvtsi128_si32(v25));
              }
              else
              {
                if ( v106 >= 0 )
                  v23 = -6.283185307179586;
                else
                  v23 = 6.283185307179586;
                v57 = v23 + wasm_quietf(*(double *)_mm_cvtsi32_si128(LODWORD(v117)).m128i_i64);
                v24 = (__m128i)*(unsigned __int64 *)&v57;
                *(double *)v24.m128i_i64 = w2c_liquidglass_f2(a1, v57);
                v115 = COERCE_FLOAT(_mm_cvtsi128_si32(v24));
              }
            }
            else if ( v112 < 0x4016CBE4 )
            {
              v66 = wasm_quietf(*(double *)_mm_cvtsi32_si128(LODWORD(v117)).m128i_i64);
              if ( v106 >= 0 )
                v22 = (__m128i)COERCE_UNSIGNED_INT64(1.570796326794897 - v66);
              else
                v22 = (__m128i)COERCE_UNSIGNED_INT64(v66 + 1.570796326794897);
              *(double *)v22.m128i_i64 = w2c_liquidglass_f1(a1, *(double *)v22.m128i_i64);
              v115 = COERCE_FLOAT(_mm_cvtsi128_si32(v22));
            }
            else
            {
              if ( v106 >= 0 )
                v20 = -3.141592653589793;
              else
                v20 = 3.141592653589793;
              v56 = v20 + wasm_quietf(*(double *)_mm_cvtsi32_si128(LODWORD(v117)).m128i_i64);
              v21 = (__m128i)*(unsigned __int64 *)&v56;
              *(double *)v21.m128i_i64 = w2c_liquidglass_f2(a1, v56);
              v115 = -COERCE_FLOAT(_mm_cvtsi128_si32(v21));
            }
          }
          else
          {
            v115 = 1.0;
            if ( v112 >= 0x39800000 )
            {
              v19 = (__m128i)COERCE_UNSIGNED_INT64(wasm_quietf(*(double *)_mm_cvtsi32_si128(LODWORD(v117)).m128i_i64));
              *(double *)v19.m128i_i64 = w2c_liquidglass_f2(a1, *(double *)v19.m128i_i64);
              v115 = COERCE_FLOAT(_mm_cvtsi128_si32(v19));
            }
          }
LABEL_68:
          *(_DWORD *)(a1 + 8) = v103 + 16;
          v78 = v81 + -0.5;
          v30 = _mm_cvtsi32_si128(
                  COERCE_UNSIGNED_INT(
                    (float)((float)(v81 + -0.5) * (float)(v81 + -0.5))
                  + (float)((float)(v73 + -0.5) * (float)(v73 + -0.5))));
          *(double *)v30.m128i_i64 = wasm_sqrtf(*(double *)v30.m128i_i64);
          v118 = COERCE_FLOAT(_mm_cvtsi128_si32(v30));
          if ( (float)((float)(v115 * 0.1) + (float)(v73 + (float)((float)(v72 * v118) * 0.5))) >= 1.0 )
            v31 = 1.0;
          else
            v31 = (float)(v115 * 0.1) + (float)(v73 + (float)((float)(v72 * v118) * 0.5));
          if ( v31 <= 0.0 )
            v31 = 0.0;
          if ( v31 >= 1.0 )
            v31 = 1.0;
          if ( v31 <= 0.0 )
            v31 = 0.0;
          v51 = v31 * v71;
          v74 = v31 * v71;
          if ( (float)(v31 * v71) < -2147483600.0 )
          {
            v32 = 0x80000000;
          }
          else if ( v51 >= 2147483600.0 )
          {
            v32 = 0x7FFFFFFF;
          }
          else
          {
            v32 = (int)v51;
          }
          v104 = v32;
          if ( v32 + 1 <= v94 )
            v33 = v32 + 1;
          else
            v33 = v94;
          v62 = a4 * v33;
          v99 = a4 * v33;
          if ( (float)((float)(v76 * 0.1) + (float)(v81 + (float)((float)(v78 * v118) * 0.5))) >= 1.0 )
            v34 = 1.0;
          else
            v34 = (float)(v76 * 0.1) + (float)(v81 + (float)((float)(v78 * v118) * 0.5));
          if ( v34 <= 0.0 )
            v34 = 0.0;
          if ( v34 >= 1.0 )
            v34 = 1.0;
          if ( v34 <= 0.0 )
            v34 = 0.0;
          v50 = v34 * v70;
          if ( (float)(v34 * v70) < -2147483600.0 )
          {
            v35 = 0x80000000;
          }
          else if ( v50 >= 2147483600.0 )
          {
            v35 = 0x7FFFFFFF;
          }
          else
          {
            v35 = (int)v50;
          }
          v114 = v35;
          if ( v35 + 1 <= v93 )
            v36 = v35 + 1;
          else
            v36 = v93;
          v96 = v36;
          v107 = 4 * (v36 + v62) + a2;
          v91 = i32_load8_u(a1 + 16, v107 + 1LL);
          v90 = i32_load8_u(a1 + 16, v107 + 2LL);
          v89 = i32_load8_u(a1 + 16, v107);
          v108 = 4 * (v99 + v114) + a2;
          v88 = i32_load8_u(a1 + 16, v108 + 1LL);
          v100 = 4 * (v104 * a4 + v96) + a2;
          v87 = i32_load8_u(a1 + 16, v100 + 1LL);
          v97 = 4 * (v104 * a4 + v114) + a2;
          v95 = i32_load8_u(a1 + 16, v97 + 1LL);
          v86 = i32_load8_u(a1 + 16, v108 + 2LL);
          v85 = i32_load8_u(a1 + 16, v100 + 2LL);
          v84 = i32_load8_u(a1 + 16, v97 + 2LL);
          v83 = i32_load8_u(a1 + 16, v108);
          v101 = i32_load8_u(a1 + 16, v100);
          v98 = i32_load8_u(a1 + 16, v97);
          v109 = 4 * (v92 + v121) + a3;
          v59 = (float)((float)((float)(1.0 - (float)(v118 * 0.30000001)) * 0.80000001)
                      + (float)((float)(v118 * 0.30000001) * 0.94999999))
              * 255.0;
          if ( v59 <= -1.0 )
          {
            v37 = 0;
          }
          else if ( v59 >= 4294967300.0 )
          {
            v37 = -1;
          }
          else
          {
            v37 = (int)v59;
          }
          i32_store8(a1 + 16, (unsigned int)(4 * (v92 + v121) + a3) + 3LL, v37);
          v79 = v118 * 0.5;
          v80 = 1.0 - (float)(v118 * 0.5);
          v60 = (float)(v80 * 0.89999998) + (float)((float)(v118 * 0.5) * 0.80000001);
          v119 = (float)(v34 * v70) - (float)v114;
          v82 = 1.0 - v119;
          v77 = v74 - (float)v104;
          v75 = 1.0 - v77;
          v52 = (float)((float)((float)((float)v98 * v82) + (float)(v119 * (float)v101)) * (float)(1.0 - v77))
              + (float)(v77 * (float)((float)((float)v83 * v82) + (float)(v119 * (float)v89)));
          if ( v52 <= -1.0 )
          {
            v38 = 0;
          }
          else if ( v52 >= 4294967300.0 )
          {
            v38 = -1;
          }
          else
          {
            v38 = (int)v52;
          }
          v61 = v60 * (float)v38;
          if ( v61 >= 255.0 )
            v39 = 255.0;
          else
            v39 = v61;
          if ( v39 <= 0.0 )
            v39 = 0.0;
          if ( v39 <= -1.0 )
          {
            v40 = 0;
          }
          else if ( v39 >= 4294967300.0 )
          {
            v40 = -1;
          }
          else
          {
            v40 = (int)v39;
          }
          i32_store8(a1 + 16, v109, v40);
          v53 = (float)((float)((float)((float)v84 * v82) + (float)(v119 * (float)v85)) * v75)
              + (float)(v77 * (float)((float)((float)v86 * v82) + (float)(v119 * (float)v90)));
          if ( v53 <= -1.0 )
          {
            v41 = 0;
          }
          else if ( v53 >= 4294967300.0 )
          {
            v41 = -1;
          }
          else
          {
            v41 = (int)v53;
          }
          if ( (float)((float)(v80 + (float)(v79 * 0.94999999)) * (float)v41) >= 255.0 )
            v42 = 255.0;
          else
            v42 = (float)(v80 + (float)(v79 * 0.94999999)) * (float)v41;
          if ( v42 <= 0.0 )
            v42 = 0.0;
          if ( v42 <= -1.0 )
          {
            v43 = 0;
          }
          else if ( v42 >= 4294967300.0 )
          {
            v43 = -1;
          }
          else
          {
            v43 = (int)v42;
          }
          i32_store8(a1 + 16, v109 + 2LL, v43);
          v54 = (float)((float)((float)((float)v95 * v82) + (float)(v119 * (float)v87)) * v75)
              + (float)(v77 * (float)((float)((float)v88 * v82) + (float)(v119 * (float)v91)));
          if ( v54 <= -1.0 )
          {
            v44 = 0;
          }
          else if ( v54 >= 4294967300.0 )
          {
            v44 = -1;
          }
          else
          {
            v44 = (int)v54;
          }
          if ( (float)((float)((float)(v80 * 0.94999999) + (float)(v79 * 0.85000002)) * (float)v44) >= 255.0 )
            v45 = 255.0;
          else
            v45 = (float)((float)(v80 * 0.94999999) + (float)(v79 * 0.85000002)) * (float)v44;
          if ( v45 <= 0.0 )
            v45 = 0.0;
          if ( v45 <= -1.0 )
          {
            v46 = 0;
          }
          else if ( v45 >= 4294967300.0 )
          {
            v46 = -1;
          }
          else
          {
            v46 = (int)v45;
          }
          i32_store8(a1 + 16, v109 + 1LL, v46);
          ++v121;
        }
        while ( v121 != a4 );
        result = ++v120 != a5;
      }
      while ( v120 != a5 );
    }
  }
  return result;
}

发现做了很多运算处理,还包含了Π,直接把所有函数喂给gemini就能分析出加密原理

其中w2c_liquidglass_f1实现了sinx的泰勒级数多项式逼近,w2c_liquidglass_f2实现了cosx的泰勒级数多项式逼近,死去的微积分记忆又回来了

image-20250617090840455.png

然后让gemini直接给出逆向脚本

import numpy as np
from PIL import Image

def liquid_glass_forward(input_image: np.ndarray) -> np.ndarray:
    """
    用 Python 和 Numpy 精确地重新实现 liquidglass 正向算法。
    这个函数接收一个图像(作为numpy数组),并返回经过特效处理后的图像。
    注释中的 C 变量名对应您提供的伪代码。
    """
    height, width, _ = input_image.shape
  
    # C 伪代码中的 v68, v69, v70, v71
    f_width, f_height = float(width), float(height)
    f_width_m1, f_height_m1 = float(width - 1), float(height - 1)

    # 创建输出图像的坐标网格 (对应 C 中的 v121, v120 循环)
    x_coords = np.arange(width)
    y_coords = np.arange(height)
    xx, yy = np.meshgrid(x_coords, y_coords)

    # 1. 坐标归一化
    # C: v81 = (float)v121 / v68;  v73 = (float)v120 / v69;
    nx = xx / f_width
    ny = yy / f_height
  
    # 2. 生成三角函数的输入值
    # C: v116 = (float)(v81 * 25.0) + (float)(v73 * 20.0);
    # C: v117 = (float)(v81 * 20.0) + (float)(v73 * 25.0);
    p1 = nx * 25.0 + ny * 20.0
    p2 = nx * 20.0 + ny * 25.0

    # 3. 计算三角函数
    # C 伪代码中庞大的 if/else 链和 f1, f2, f5 函数共同实现了 sin 和 cos
    # 我们可以直接用 numpy 的函数代替,结果一致
    # C: v76 = sin(v116), v115 = cos(v117)
    sin_val = np.sin(p1)
    cos_val = np.cos(p2)

    # 4. 计算位移后的采样坐标
    # C: v78 = v81 + -0.5; v72 = v73 + -0.5;
    nx_m05 = nx - 0.5
    ny_m05 = ny - 0.5
  
    # C: v118 = sqrt((nx_m05*nx_m05) + (ny_m05*ny_m05));
    dist_from_center = np.sqrt(nx_m05**2 + ny_m05**2)

    # C: v35 = (v115 * 0.1) + (v73 + ((v72 * v118) * 0.5));
    new_ny_norm = (cos_val * 0.1) + (ny + (ny_m05 * dist_from_center) * 0.5)
  
    # C: v38 = (v76 * 0.1) + (v81 + ((v78 * v118) * 0.5));
    new_nx_norm = (sin_val * 0.1) + (nx + (nx_m05 * dist_from_center) * 0.5)
  
    # 将归一化坐标变回像素坐标
    source_x = new_nx_norm * f_width_m1
    source_y = new_ny_norm * f_height_m1

    # 5. 双线性插值采样
    x0 = np.floor(source_x).astype(np.int32)
    y0 = np.floor(source_y).astype(np.int32)
    x1 = x0 + 1
    y1 = y0 + 1

    # 计算插值权重
    wa = source_x - x0
    wb = source_y - y0

    # 边界处理 (Clipping)
    x0 = np.clip(x0, 0, width - 1)
    y0 = np.clip(y0, 0, height - 1)
    x1 = np.clip(x1, 0, width - 1)
    y1 = np.clip(y1, 0, height - 1)

    # 从输入图像中获取四个角点的颜色值
    c00 = input_image[y0, x0]
    c10 = input_image[y0, x1]
    c01 = input_image[y1, x0]
    c11 = input_image[y1, x1]

    # 执行插值
    top = c00 * (1 - wa[..., np.newaxis]) + c10 * wa[..., np.newaxis]
    bottom = c01 * (1 - wa[..., np.newaxis]) + c11 * wa[..., np.newaxis]
    interpolated_color = top * (1 - wb[..., np.newaxis]) + bottom * wb[..., np.newaxis]

    # C 伪代码中还有一些额外的颜色混合步骤,但它们不影响几何映射
    # 为了精确还原,我们只关心坐标映射,所以直接返回插值结果即可
    return interpolated_color

def restore_image(distorted_image_path: str, restored_image_path: str):
    """
    执行逆向还原过程
    """
    print(f"[*] 正在加载扭曲的图片: {distorted_image_path}")
    distorted_img = Image.open(distorted_image_path).convert("RGB")
    distorted_arr = np.array(distorted_img)
    height, width, _ = distorted_arr.shape

    print(f"[*] 正在创建 {width}x{height} 的坐标格网图...")
    x_coords = np.arange(width, dtype=np.float32)
    y_coords = np.arange(height, dtype=np.float32)
    xx, yy = np.meshgrid(x_coords, y_coords)
  
    coord_grid = np.zeros((height, width, 3), dtype=np.float32)
    coord_grid[..., 0] = xx
    coord_grid[..., 1] = yy

    print("[*] 正在应用正向 liquidglass 算法以生成位移图...")
    # 这里的 displacement_map 的颜色值(R,G) 代表了源坐标(x,y)
    displacement_map = liquid_glass_forward(coord_grid)

    print("[*] 正在根据位移图重构原始图像...")
    restored_arr = np.full((height, width, 3), 255, dtype=np.uint8)

    # 从位移图中提取源坐标 (sx, sy)
    source_x = np.clip(displacement_map[..., 0], 0, width - 1).astype(int)
    source_y = np.clip(displacement_map[..., 1], 0, height - 1).astype(int)

    # 获取目标图像的原始坐标网格,用于索引
    dest_xx, dest_yy = np.meshgrid(np.arange(width), np.arange(height))

    # 核心逆向映射步骤:
    # restored_image[sy, sx] = distorted_image[y, x]
    # 我们将扭曲图像在 (y,x) 的像素,放回它应该在的原始位置 (sy,sx)
    restored_arr[source_y, source_x] = distorted_arr[dest_yy, dest_xx]

    restored_img = Image.fromarray(restored_arr)
    print(f"[+] 还原成功!已保存为: {restored_image_path}")
    print("[!] 注意:还原的图像可能存在空洞,这是正常的。")
    restored_img.save(restored_image_path)
    restored_img.show()

if __name__ == '__main__':
    # 替换为你的输入文件名
    input_file = 'liquidglass.png'
    output_file = 'restored_qr.png'
    try:
        restore_image(input_file, output_file)
    except FileNotFoundError:
        print(f"\n错误:找不到文件 '{input_file}'。请确保它和脚本在同一目录下。")

上面所做的代码实际上是将像素坐标还原回去,所以可以精确得到原来的图(但是原来的图还做了个颜色混合步骤,导致出来的二维码存在白色噪声)

输入前

liquidglass.png

输入后

restored_qr.png

基本能看出二维码,但是黑框存在很多白点噪声,因此我用了最笨的法手动画图(ps一点不会)

image.png

扫描二维码就能得到flag .;,;.{Do_You_Prefer_Liquid_Glass_Or_Ass?}?好变态

others

后面还没出的3道题等复现完补充回来

最后修改:2025 年 06 月 17 日
如果觉得我的文章对你有用,请随意赞赏