Tổng quan
Binary có 2 nhánh đáng chú ý:
- Nhánh yêu cầu key 8 byte (tính từ time(0)%256 + các byte rải rác trong xmmword_4060/4070/4080/byte_4096) - phục vụ cho logic khác
- Nhánh in ra kết quả bằng hàm sub_1670, gọi sub_15B0 (nạp dữ liệu) và sub_1380 (giải mã), rồi in thẳng ra stdout
Để lấy flag nhanh nhất, bám theo nhánh sub_1670:
- sub_15B0 chép 26 byte ciphertext vào v9 và 16 byte key vào v8 từ .data
- sub_1380 (v9, len=26, v8, len=16) thực hiện 2 pass XOR theo "chương trình" ở byte_4020
- sub_1670 in từng byte của v9 (sau khi đã decrypt)
Kết quả plaintext chứa luôn flag
Dữ liệu cố định trong .data
Trích nguyên từ dump bạn đưa (little‑endian):
Ciphertext v9 (26 bytes) nạp bởi sub_15B0:
dword_403A = 0x751CF86C
byte_403E = 0x19
word_4037 = 0x4781
byte_4039 = 0x80
dword_4033 = 0xCDF5210E
dword_402F = 0x4A1210CA
dword_402B = 0x3E4E6305
word_4028 = 0x7991
byte_402A = 0x40
word_4025 = 0x1D95
byte_4027 = 0x91
=> v9.hex() = 6cf81c75198147800e21f5cdca10124a05634e3e917940951d91
Key buffer v8 (16 bytes) nạp bởi sub_15B0:
dword_404C = 0x05114B29
qword_4040 = 0x6655764F69042D31
dword_4048 = 0x7E539182
=> v8.hex() = 294b1105312d04694f7655668291537e
Chương trình ở byte_4020:
0x10, 0x01, 0x10, 0x00, 0xFF, ...
Mỗi cặp [0x10, mode] tương ứng một pass. Dừng khi byte kế tiếp != 0x10
→ Có hai pass: mode=1 rồi mode=0
Thuật toán sub_1380
Với n = len(v9), m = len(v8), j = 0..n-1, s = j % 3, b = v8[j % m]:
- Pass 1 (mode=1):
if (s == 0) delta = 0;
else delta = b >> (8 - s);
v9[j] ^= delta;
- Pass 2 (mode=0):
v9[j] ^= (b << s);
Không có bước sub_1460 trong nhánh in flag (bước này dùng cho mảng khác trong main)
Script
File solve.py đính kèm tái tạo đúng dữ liệu và thuật toán, in ra plaintext/flag
def build_cipher_v9() -> bytearray:
v9 = bytearray()
v9 += 0x751CF86C.to_bytes(4, "little")
v9 += bytes([0x19])
v9 += 0x4781.to_bytes(2, "little")
v9 += bytes([0x80])
v9 += 0xCDF5210E.to_bytes(4, "little")
v9 += 0x4A1210CA.to_bytes(4, "little")
v9 += 0x3E4E6305.to_bytes(4, "little")
v9 += 0x7991.to_bytes(2, "little")
v9 += bytes([0x40])
v9 += 0x1D95.to_bytes(2, "little")
v9 += bytes([0x91])
return v9
def build_key_v8() -> bytes:
v8 = bytearray()
v8 += 0x05114B29.to_bytes(4, "little")
v8 += 0x6655764F69042D31.to_bytes(8, "little")
v8 += 0x7E539182.to_bytes(4, "little")
return bytes(v8)
def sub_1380_decrypt(data: bytearray, key: bytes) -> bytes:
for j in range(len(data)):
s = j % 3
b = key[j % len(key)]
if s == 0:
delta = 0
else:
delta = (b >> (8 - s)) & 0xFF
data[j] ^= delta
for j in range(len(data)):
s = j % 3
b = key[j % len(key)]
data[j] ^= (b << s) & 0xFF
return bytes(data)
pt = sub_1380_decrypt(bytearray(build_cipher_v9()), build_key_v8())
flag = pt.decode('latin-1')
print('[+] Flag:', flag)
Chạy:
python3 solve.py
Kết quả (rút gọn):
[+] Plaintext : EnXp{5CR3W_TH3_4WN_4UTH0R}
[+] FLAG: EnXp{5CR3W_TH3_4WN_4UTH0R}
Ghi chú kỹ thuật
- Endianness: mọi dw/dd/dq trong .data là little‑endian. Khi build v9, v8 phải dùng to_bytes(..., 'little') đúng như sub_15B0
- Điểm dừng trình tại byte_4020: code dừng khi v7[2] != 16. Với byte tiếp theo là 0xFF, chỉ có 2 pass
- Nhánh key 8 byte (sub_14C0) không cần thiết để lấy flag trong nhánh sub_1670
Kết luận
Decrypt theo sub_1380 với dữ liệu cố định từ .data cho plaintext chứa flag:
EnXp{5CR3W_TH3_4WN_4UTH0R}
'WriteUp > RE' 카테고리의 다른 글
| Square Cipher - BuckeyeCTF 2025 (0) | 2025.11.09 |
|---|---|
| Python 0bf (0) | 2025.11.02 |
| [RE] S0urc3 - POC CTF 2025 (0) | 2025.10.13 |
| [RE] Dsp - POC CTF 2025 (0) | 2025.10.13 |
| [RE] Mystery Zone (0) | 2025.09.01 |
