# Visit https://www.lddgo.net/string/pyc-compile-d...

تم الإنشاء في: ٢٥ يناير ٢٠٢٦

تمت الإجابة باستخدام GPT-5.2 Thinking بواسطة Chat01

سؤال

Visit https://www.lddgo.net/string/pyc-compile-decompile for more information

Version : Python 3.9

import dis
import struct

def MX(y, z, sum, k, p, e):
return (z >> 5 ^ y >> 2) + (y << 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z)

def btea(v, n, k):

text
u32 = lambda x: x & 0xFFFFFFFFL y = v[0] sum = 0 DELTA = 1163219540 if n > 1: z = v[n - 1] q = 6 + 52 // n if q > 0: q -= 1 sum = u32(sum + DELTA) e = u32(sum >> 2) & 3 p = 0 if p < n - 1: y = v[p + 1] z = v[p] = u32(v[p] + MX(y, z, sum, k, p, e)) p += 1 continue y = v[0] z = v[n - 1] = u32(v[n - 1] + MX(y, z, sum, k, p, e)) continue return True

if name == 'main':
print('WOW')

Visit https://www.lddgo.net/string/pyc-compile-decompile for more information

Version : Python 3.9

import struct
from crypto import *
from sys import *
import base64
import myalgo
welcome_msg = 'V2VsYzBtMyBUbyBUaGUgV29ybGQgb2YgTDFsYWMgPDM='
input_msg = ':i(G#8T&KiF<F_)F`JToCggs;'
right_msg = 'UmlnaHQsIGNvbmdyYXR1bGF0aW9ucyE='
wrong_msg = 'V3JvbmcgRmxhZyE='
print(b64decode(welcome_msg).decode())
flag = input(a85decode(input_msg).decode())
if not flag.startswith('LilacCTF{') and flag.endswith('}') or len(flag) == 26:
print(b64decode(wrong_msg).decode())
else:
flag = flag[9:25]
res = [
761104570,
1033127419,
0xDE446C05L,
795718415]
key = struct.unpack('<IIII', b'1111222233334444')
input = list(struct.unpack('<IIII', flag.encode()))
myalgo.btea(input, 4, key)
if input[0] == res[0] and input[1] == res[1] and input[2] == res[2] and input[3] == res[3]:
print(b64decode(right_msg).decode())
else:
print(b64decode(wrong_msg).decode())

flag是LilacCTF{}包裹的,给我脚本得到flag

Python

python
def MX(y,z,sum_,k,p,e): return ((z >> 5 ^ y >> 2) + (y << 3 ^ z << 4)) ^ ((sum_ ^ y) + (k[(p & 3) ^ e] ^ z)) def btea(v, n, k, DELTA=1163219540): # v list of unsigned 32-bit ints, modified in place, return v def u32(x): return x & 0xFFFFFFFF if n > 1: rounds = 6 + 52 // n sum_ = 0 z = v[n-1] for _ in range(rounds): sum_ = u32(sum_ + DELTA) e = (sum_ >> 2) & 3 for p in range(n-1): y = v[p+1] v[p] = u32(v[p] + MX(y,z,sum_,k,p,e)) z = v[p] y = v[0] v[n-1] = u32(v[n-1] + MX(y,z,sum_,k,n-1,e)) z = v[n-1] return v elif n < -1: n = -n rounds = 6 + 52 // n sum_ = u32(rounds * DELTA) y = v[0] for _ in range(rounds): e = (sum_ >> 2) & 3 for p in range(n-1, 0, -1): z = v[p-1] v[p] = u32(v[p] - MX(y,z,sum_,k,p,e)) y = v[p] z = v[n-1] v[0] = u32(v[0] - MX(y,z,sum_,k,0,e)) y = v[0] sum_ = u32(sum_ - DELTA) return v else: return v key = struct.unpack('<IIII', b'1111222233334444') key (825307441, 842150450, 858993459, 875836468)

Python

python
res = [761104570, 1033127419, 0xDE446C05, 795718415] res [761104570, 1033127419, 3729026053, 795718415]

Python

python
v = res.copy() btea(v, -4, list(key)) v [1227042847, 2879229022, 1054597645, 2882160295]

Python

python
plaintext_bytes = struct.pack('<IIII', *v) plaintext_bytes, len(plaintext_bytes), plaintext_bytes.hex() (b'\x1f0#I^\x8c\x9d\xab\r\xe2\xdb>\xa7F\xca\xab', 16, '1f3023495e8c9dab0de2db3ea746caab')

Python

python
test = list(struct.unpack('<IIII', plaintext_bytes)) enc = test.copy() btea(enc, 4, list(key)) enc, res, enc==res ([761104570, 1033127419, 3729026053, 795718415], [761104570, 1033127419, 3729026053, 795718415], True)

Python

python
def solve_for_delta(delta): v=res.copy() btea(v,-4,list(key),DELTA=delta) pt=struct.pack('<IIII',*v) return pt for delta in [0x9E3779B9, 1163219540, 0x9E3779B8, 0x61C88647, 0x7F4A7C15]: pt=solve_for_delta(delta) print(hex(delta), pt, pt.hex(), all(32<=b<127 for b in pt))

الفكرة

Final flag representation considerations

The flag involves control and extended characters, possibly with special symbols like '0#I^' and '«'. If the scoreboard accepts unicode, it might be possible to submit it that way. Alternatively, providing a script that outputs the flag in multiple formats like latin1 or escaped bytes could work.

Crafting script for flag retrieval

Plan: Define the encryption logic and constants. Decrypt the message using the provided method, convert the output to bytes, and show the results in different formats — hex, ASCII, and Latin-1 with escapes. Additionally, demonstrate how to interact with the remote service. Finally, consider creating transformations for the printable variant.

Reevaluating algorithm based on decompiler limitations

It seems the decompiled code might not accurately represent the algorithm due to missing loops and incomplete encryption. The actual behavior could differ if loops were present in the compiled code. I’m considering whether the original compiled code contains the full logic, and possibly using disassembly to explore this further.

Reconstructing algorithm from decompiled code

The decompiled code seems incomplete, likely due to missing loop handling. But from what I can infer, it sets certain variables and runs loops using conditional statements like while. This leads me to believe the algorithm is correct, so I’ll provide a script with an explanation, as well as the derived flag in hex and base64/latin1, in Chinese.

Thought for 3m 37s

الإجابة

下面是可直接跑的解密脚本(把 res 用同一套 btea/XXTEA 反向运算解出来),会同时打印 raw byteshex、以及用 latin1 强行显示的版本。

按你贴的逻辑,程序对 flag[9:25] 这 16 字节做 struct.unpack('<IIII', ...),然后 btea(input, 4, key) 再和 res 比较;所以我们要做的是对 res 执行 btea(res, -4, key) 得到那 16 字节明文。

python
# solve_flag.py import struct import base64 DELTA = 1163219540 def MX(y, z, sum_, k, p, e): # 按你给的 myalgo.MX 公式(注意 Python 运算符优先级) return ((z >> 5 ^ y >> 2) + (y << 3 ^ z << 4)) ^ ((sum_ ^ y) + (k[(p & 3) ^ e] ^ z)) def btea(v, n, k): def u32(x): return x & 0xFFFFFFFF if n > 1: # encrypt rounds = 6 + 52 // n sum_ = 0 z = v[n - 1] for _ in range(rounds): sum_ = u32(sum_ + DELTA) e = (sum_ >> 2) & 3 for p in range(n - 1): y = v[p + 1] v[p] = u32(v[p] + MX(y, z, sum_, k, p, e)) z = v[p] y = v[0] v[n - 1] = u32(v[n - 1] + MX(y, z, sum_, k, n - 1, e)) z = v[n - 1] return v if n < -1: # decrypt n = -n rounds = 6 + 52 // n sum_ = u32(rounds * DELTA) y = v[0] for _ in range(rounds): e = (sum_ >> 2) & 3 for p in range(n - 1, 0, -1): z = v[p - 1] v[p] = u32(v[p] - MX(y, z, sum_, k, p, e)) y = v[p] z = v[n - 1] v[0] = u32(v[0] - MX(y, z, sum_, k, 0, e)) y = v[0] sum_ = u32(sum_ - DELTA) return v return v def main(): res = [761104570, 1033127419, 0xDE446C05, 795718415] key = list(struct.unpack("<IIII", b"1111222233334444")) v = res[:] btea(v, -4, key) # 反向解出明文 4*32bit pt = struct.pack("<IIII", *v) # 16 bytes flag_bytes = b"LilacCTF{" + pt + b"}" print("[+] inner raw bytes repr:", repr(pt)) print("[+] inner hex:", pt.hex()) print("[+] inner base64:", base64.b64encode(pt).decode()) # 如果你需要“显示出来”而不是 bytes,可以用 latin1 保持 0-255 一一映射 print("[+] inner latin1:", pt.decode("latin1")) print("[+] full flag bytes repr:", repr(flag_bytes)) if __name__ == "__main__": main()

用这份脚本解出来的 16 字节内层数据是:

  • hex1f3023495e8c9dab0de2db3ea746caab
  • raw reprb'\x1f0#I^\x8c\x9d\xab\r\xe2\xdb>\xa7F\xca\xab'

如果你是要“能提交的平台字符串”,要看题目平台是否接受非 ASCII(很多平台只接受可见字符)。这份解密结果本质上是 16 个任意字节;若平台只收可见字符,通常题目还会再包一层编码(比如 hex/base64)——但你贴的校验代码里没有这一步。你如果把题目服务端/原始附件(尤其是实际的 myalgo 文件)再贴出来,我可以按真实行为把“可提交形式”的 flag 也还原成纯可见字符。

سؤال

main.exe_extracted.zip

解出flag,flag是用LilacCTF{}包裹的

مشاركة هذا السؤال والجواب