Reverse
Welcome

一个很简单的比较程序和加密程序 看v6长得有点像凯撒位移之后的结果,重点关注caesarEncrypt

左移三位即可解密

Catch_Tofv
找到关键入口
WndClass.lpfnWndProc = sub_401800;
if ( Msg != 516 )
return DefWindowProcW(hWnd, Msg, wParam, lParam);
// WM_RBUTTONDOWN:右键点击
if ( ...在图片范围内... )
{
sub_4010C0(); // <--- 重点!这就是Flag的入口函数
}
进入了一个XTEA算法
这是一个非常经典的 XXTEA 算法加密题目。
这个函数 sub_4010C0 是验证 Flag 的核心逻辑。它读取文件内容,进行加密,然后与硬编码的密文进行比较。
1. 代码逻辑分析
A. 文件读取与 Flag 输入
C
FileW = CreateFileW(L"flag.loveyou", ...);
ReadFile(FileW, Buffer, 0x400u, &NumberOfBytesRead, 0);
// ...
v23 = (unsigned int *)calloc(8u, 4u);
memcpy(v23, Buffer, i);
- 程序试图打开名为
flag.loveyou的文件。 - 读取的内容被复制到
v23 数组中。v23 是一个unsigned int数组,大小为 8(即 32 字节)。这意味着 Flag 的长度应该是 32 字节(或者补齐到 32 字节)。
B. 密钥生成 (Key)
C
*(_DWORD *)&Text[8] = 286331153; // 0x11111111
qmemcpy(&Text[12], "\"\"\"\"3333DDDD", 12);
这里构造了加密使用的 Key(4个 DWORD):
-
Key[0] = 0x11111111 -
Key[1] = 0x22222222(‘""""’ 的 ASCII 码是 0x22) -
Key[2] = 0x33333333 -
Key[3] = 0x44444444(‘DDDD’ 的 ASCII 码是 0x44)
C. 加密算法 (XXTEA)
C
do
{
v9 = ((unsigned int)(v5 - 1640531527) >> 2) & 3; // Delta 相关逻辑
// ... 一系列的异或、移位操作 ...
v28 += (((16 * v31) ^ (v8 >> 3)) + ((v31 >> 5) ^ (4 * v8))) ^ (((v5 - 1640531527) ^ v8) + (v31 ^ v25));
// ...
v12 = v26-- == 1; // 循环计数
v5 -= 1640531527; // 更新 Delta
}
while ( !v12 );
- 这是一个典型的 XXTEA 加密循环。
- 特征常数:
1640531527 是0x61C88647。在有符号整数中-1640531527 等同于0x9E3779B9(这是 TEA 系列算法的黄金分割率 Delta)。 - 循环次数:代码中
v26 = 12,循环 12 轮。 - 加密对象:
v23 数组,包含 8 个整数(v28 到v30/v11 等变量实际上就是v23[0] 到v23[7])。
D. 密文比对
C
v38[0] = -1605326664; // 0xA050E8B8
v38[1] = -1446105387; // 0xA9CD6ED5
// ...
while ( *v14 == *v15 ) // 比较 v23 (加密后) 和 v38 (硬编码密文)
如果比较成功,就会弹出 "Message" 框,显示解密后的文本(实际上是恭喜信息)。我们要找的 Flag 就是让这个校验通过的输入。
2. 解题思路 (写出解密脚本)
我们需要提取密文数组 v38,使用已知的 Key 和 Delta,逆向执行 XXTEA 算法即可得到 Flag。
密文数据 (v38):
根据 IDA 中的有符号整数转换成无符号十六进制:
-
-1605326664 ->0xA050E8B8 -
-1446105387 ->0xA9CD6ED5 -
1590482979 ->0x5ECD0623 -
1040045873 ->0x3DFD9731 -
505225631 ->0x1E1D119F -
1713322116 ->0x661F6884 -
1924870785 ->0x72BB5281 -
-1738902400 ->0x985A9480
Python 解密脚本:
Python
import struct
# 1. 准备密文 (Ciphertext)
# 将 IDA 中的有符号整数转换为无符号整数
cipher_int = [
-1605326664 & 0xFFFFFFFF,
-1446105387 & 0xFFFFFFFF,
1590482979,
1040045873,
505225631,
1713322116,
1924870785,
-1738902400 & 0xFFFFFFFF
]
# 2. 准备密钥 (Key)
# 0x11111111, 0x22222222, 0x33333333, 0x44444444
key = [0x11111111, 0x22222222, 0x33333333, 0x44444444]
# 3. XXTEA 解密函数
def mx(sum_val, y, z, p, e, k):
return (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum_val ^ y) + (k[(p & 3) ^ e] ^ z)))
def btea_decrypt(v, k):
n = len(v)
DELTA = 0x9E3779B9 # 对应代码中的 -1640531527 (signed)
rounds = 12 # 代码中循环了12次
# 在 C 代码中:
# v5 (sum) 从 0 开始,每次循环结束 v5 -= 1640531527 (即 v5 += DELTA)
# 循环12次后,v5 的值应该是 12 * DELTA
# 解密时我们需要从这个最终的 sum 值开始往回减
sum_val = (rounds * DELTA) & 0xFFFFFFFF
y = v[0]
while rounds > 0:
e = (sum_val >> 2) & 3
# XXTEA 解密是反向遍历数组
for p in range(n - 1, 0, -1):
z = v[p - 1]
y = v[p] = (v[p] - mx(sum_val, y, z, p, e, k)) & 0xFFFFFFFF
# 处理边界 p=0
p = 0
z = v[n - 1]
y = v[0] = (v[0] - mx(sum_val, y, z, p, e, k)) & 0xFFFFFFFF
sum_val = (sum_val - DELTA) & 0xFFFFFFFF
rounds -= 1
return v
# 4. 执行解密
decrypted_int = btea_decrypt(cipher_int, key)
# 5. 转换为字符串
flag = b''
for val in decrypted_int:
flag += struct.pack('<I', val) # 小端序转换
print("Flag:", flag.decode('utf-8', errors='ignore'))
3. 结果验证
运行上述脚本,你应该能得到类似如下的 Flag:
Flag: HACKING_FOR_FUN_AND_NON_PROFIT (示例,具体内容取决于计算结果)
注意点:
- Delta 的符号:代码中是
-= 1640531527。由于1640531527 实际上是0x61C88647,所以-= 0x61C88647 相当于+= 0x9E3779B9 (这是标准的 Delta)。我的脚本中直接使用了标准的DELTA = 0x9E3779B9和标准的 XXTEA 解密逻辑。 - 文件格式:题目通过
CreateFile 读取flag.loveyou,所以你在本地复现或者提交时,可能需要将计算出的字符串写入到这个文件中,或者直接提交字符串作为 Flag。

大胃袋

发现反调试

原值为21
- 数据起始偏移:
dword_42DA64 的值(记为OFFSET)。 - 数据长度:
dword_42DA68 的值(记为SIZE)。

auto i, start_addr, size, key, v;
start_addr = 0x401000; // 0x400000 + 0x1000
size = 0x1654;
key = 0x15;
Message("Start Decrypting...\n");
for ( i = 0; i < size; i++ )
{
// 读取
v = Byte(start_addr + i);
// 异或
PatchByte(start_addr + i, v ^ key);
}
Message("Done! Please press C at 0x401000\n");


int sub_4014D0()
{
size_t v0; // eax
int i; // [esp+14h] [ebp-A4h]
signed int v3; // [esp+18h] [ebp-A0h]
char v4[145]; // [esp+23h] [ebp-95h] BYREF
int v5; // [esp+B4h] [ebp-4h]
sub_4017A0();
v5 = 0;
memset(&v4[17], 0, 0x80u);
strcpy(v4, "C4n_you_f1nd_it?");
puts("Hello,CTFer!\nPlz input...");
sub_401EA0("%s", &v4[17]);
v3 = strlen(&v4[17]);
if ( v3 % 4 )
{
for ( i = 0; i < 4 - v3 % 4; ++i )
v4[v3 + 17 + i] = -52;
}
v0 = strlen(&v4[17]);
sub_4013A0(&v4[17], v0 >> 2, v4);
if ( !memcmp(&v4[17], &unk_405000, 0x80u) )
puts("You find it!!!");
else
puts("NOP");
return 0;
}
TEA 系列算法。但是存在魔改
int __cdecl sub_4013A0(_DWORD *a1, int a2, int a3)
{
int v3; // eax
int v4; // eax
int result; // eax
int v6; // [esp+0h] [ebp-1Ch]
int v7; // [esp+4h] [ebp-18h]
unsigned int i; // [esp+8h] [ebp-14h]
unsigned int v9; // [esp+Ch] [ebp-10h]
unsigned int v10; // [esp+10h] [ebp-Ch]
v7 = 52 / a2 + 6;
v9 = 0;
v10 = a1[a2 - 1];
do
{
v9 += 421101824; //魔改点
v6 = (v9 >> 2) & 3;
for ( i = 0; i < a2 - 1; ++i )
{
v3 = a1[i]
+ (((v10 ^ *(_DWORD *)(a3 + 4 * (v6 ^ i & 3))) + (a1[i + 1] ^ v9)) ^ (((16 * v10) ^ (a1[i + 1] >> 3))
+ ((4 * a1[i + 1]) ^ (v10 >> 5))));
a1[i] = v3;
v10 = v3;
}
v4 = a1[a2 - 1]
+ (((v10 ^ *(_DWORD *)(a3 + 4 * (v6 ^ i & 3))) + (*a1 ^ v9)) ^ (((16 * v10) ^ (*a1 >> 3))
+ ((4 * *a1) ^ (v10 >> 5))));
a1[a2 - 1] = v4;
v10 = v4;
result = v7 - 1;
v7 = result;
}
while ( result );
return result;
}
paylod
import struct
def xxtea_decrypt(v, k):
"""
XXTEA 解密 (自定义 DELTA 版)
"""
n = len(v)
if n == 0: return v
# === 关键修改 ===
# 题目代码中的魔改常数: 421101824 -> 0x19198100
DELTA = 0x19198100
rounds = 6 + 52 // n
# 解密时 sum 的初始值 = rounds * DELTA
sum_value = (rounds * DELTA) & 0xffffffff
y = v[0]
while sum_value != 0:
e = (sum_value >> 2) & 3
for p in range(n - 1, -1, -1):
z = v[p - 1]
# 标准 XXTEA MX 运算
mx = (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum_value ^ y) + (k[(p & 3) ^ e] ^ z)))
v[p] = (v[p] - mx) & 0xffffffff
y = v[p]
sum_value = (sum_value - DELTA) & 0xffffffff
return v
# 1. 密钥 Key: "C4n_you_f1nd_it?"
key_str = "C4n_you_f1nd_it?"
k = list(struct.unpack("<4I", key_str.encode('utf-8')))
# 2. 密文 Ciphertext (从 unk_405000 提取)
raw_cipher = [
0x1B, 0x9F, 0xFF, 0x21, 0xA3, 0x3B, 0x44, 0x5E,
0x2F, 0x5E, 0x34, 0x31, 0xE0, 0x30, 0x1C, 0x50,
0xE6, 0x7F, 0xEF, 0x7B, 0x7F, 0xE4, 0xE3, 0x22,
0x96, 0x2F, 0x95, 0xD4, 0x81, 0xEB, 0xC3, 0xDE
]
cipher_bytes = bytes(raw_cipher)
v = list(struct.unpack(f"<{len(cipher_bytes)//4}I", cipher_bytes))
print("正在解密...")
print(f"使用魔改 DELTA: 0x19198100")
# 3. 执行解密
try:
decrypted_v = xxtea_decrypt(v, k)
flag_bytes = struct.pack(f"<{len(decrypted_v)}I", *decrypted_v)
# 去掉可能的填充字符 (如 \x00)
flag = flag_bytes.decode('utf-8', errors='ignore').strip('\x00')
print("\n[+] 成功获取 Flag:")
print(flag)
except Exception as e:
print(f"[-] 解密失败: {e}")

Welcome

一个很简单的比较程序和加密程序 看v6长得有点像凯撒位移之后的结果,重点关注caesarEncrypt

左移三位即可解密

Catch_Tofv
找到关键入口
WndClass.lpfnWndProc = sub_401800;
if ( Msg != 516 )
return DefWindowProcW(hWnd, Msg, wParam, lParam);
// WM_RBUTTONDOWN:右键点击
if ( ...在图片范围内... )
{
sub_4010C0(); // <--- 重点!这就是Flag的入口函数
}
进入了一个XTEA算法
这是一个非常经典的 XXTEA 算法加密题目。
这个函数 sub_4010C0 是验证 Flag 的核心逻辑。它读取文件内容,进行加密,然后与硬编码的密文进行比较。
1. 代码逻辑分析
A. 文件读取与 Flag 输入
C
FileW = CreateFileW(L"flag.loveyou", ...);
ReadFile(FileW, Buffer, 0x400u, &NumberOfBytesRead, 0);
// ...
v23 = (unsigned int *)calloc(8u, 4u);
memcpy(v23, Buffer, i);
- 程序试图打开名为
flag.loveyou的文件。 - 读取的内容被复制到
v23 数组中。v23 是一个unsigned int数组,大小为 8(即 32 字节)。这意味着 Flag 的长度应该是 32 字节(或者补齐到 32 字节)。
B. 密钥生成 (Key)
C
*(_DWORD *)&Text[8] = 286331153; // 0x11111111
qmemcpy(&Text[12], "\"\"\"\"3333DDDD", 12);
这里构造了加密使用的 Key(4个 DWORD):
-
Key[0] = 0x11111111 -
Key[1] = 0x22222222(‘""""’ 的 ASCII 码是 0x22) -
Key[2] = 0x33333333 -
Key[3] = 0x44444444(‘DDDD’ 的 ASCII 码是 0x44)
C. 加密算法 (XXTEA)
C
do
{
v9 = ((unsigned int)(v5 - 1640531527) >> 2) & 3; // Delta 相关逻辑
// ... 一系列的异或、移位操作 ...
v28 += (((16 * v31) ^ (v8 >> 3)) + ((v31 >> 5) ^ (4 * v8))) ^ (((v5 - 1640531527) ^ v8) + (v31 ^ v25));
// ...
v12 = v26-- == 1; // 循环计数
v5 -= 1640531527; // 更新 Delta
}
while ( !v12 );
- 这是一个典型的 XXTEA 加密循环。
- 特征常数:
1640531527 是0x61C88647。在有符号整数中-1640531527 等同于0x9E3779B9(这是 TEA 系列算法的黄金分割率 Delta)。 - 循环次数:代码中
v26 = 12,循环 12 轮。 - 加密对象:
v23 数组,包含 8 个整数(v28 到v30/v11 等变量实际上就是v23[0] 到v23[7])。
D. 密文比对
C
v38[0] = -1605326664; // 0xA050E8B8
v38[1] = -1446105387; // 0xA9CD6ED5
// ...
while ( *v14 == *v15 ) // 比较 v23 (加密后) 和 v38 (硬编码密文)
如果比较成功,就会弹出 "Message" 框,显示解密后的文本(实际上是恭喜信息)。我们要找的 Flag 就是让这个校验通过的输入。
2. 解题思路 (写出解密脚本)
我们需要提取密文数组 v38,使用已知的 Key 和 Delta,逆向执行 XXTEA 算法即可得到 Flag。
密文数据 (v38):
根据 IDA 中的有符号整数转换成无符号十六进制:
-
-1605326664 ->0xA050E8B8 -
-1446105387 ->0xA9CD6ED5 -
1590482979 ->0x5ECD0623 -
1040045873 ->0x3DFD9731 -
505225631 ->0x1E1D119F -
1713322116 ->0x661F6884 -
1924870785 ->0x72BB5281 -
-1738902400 ->0x985A9480
payload
import struct
# 1. 准备密文 (Ciphertext)
# 将 IDA 中的有符号整数转换为无符号整数
cipher_int = [
-1605326664 & 0xFFFFFFFF,
-1446105387 & 0xFFFFFFFF,
1590482979,
1040045873,
505225631,
1713322116,
1924870785,
-1738902400 & 0xFFFFFFFF
]
# 2. 准备密钥 (Key)
# 0x11111111, 0x22222222, 0x33333333, 0x44444444
key = [0x11111111, 0x22222222, 0x33333333, 0x44444444]
# 3. XXTEA 解密函数
def mx(sum_val, y, z, p, e, k):
return (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum_val ^ y) + (k[(p & 3) ^ e] ^ z)))
def btea_decrypt(v, k):
n = len(v)
DELTA = 0x9E3779B9 # 对应代码中的 -1640531527 (signed)
rounds = 12 # 代码中循环了12次
# 在 C 代码中:
# v5 (sum) 从 0 开始,每次循环结束 v5 -= 1640531527 (即 v5 += DELTA)
# 循环12次后,v5 的值应该是 12 * DELTA
# 解密时我们需要从这个最终的 sum 值开始往回减
sum_val = (rounds * DELTA) & 0xFFFFFFFF
y = v[0]
while rounds > 0:
e = (sum_val >> 2) & 3
# XXTEA 解密是反向遍历数组
for p in range(n - 1, 0, -1):
z = v[p - 1]
y = v[p] = (v[p] - mx(sum_val, y, z, p, e, k)) & 0xFFFFFFFF
# 处理边界 p=0
p = 0
z = v[n - 1]
y = v[0] = (v[0] - mx(sum_val, y, z, p, e, k)) & 0xFFFFFFFF
sum_val = (sum_val - DELTA) & 0xFFFFFFFF
rounds -= 1
return v
# 4. 执行解密
decrypted_int = btea_decrypt(cipher_int, key)
# 5. 转换为字符串
flag = b''
for val in decrypted_int:
flag += struct.pack('<I', val) # 小端序转换
print("Flag:", flag.decode('utf-8', errors='ignore'))

大胃袋

发现反调试

原值为21
- 数据起始偏移:
dword_42DA64 的值(记为OFFSET)。 - 数据长度:
dword_42DA68 的值(记为SIZE)。

auto i, start_addr, size, key, v;
start_addr = 0x401000; // 0x400000 + 0x1000
size = 0x1654;
key = 0x15;
Message("Start Decrypting...\n");
for ( i = 0; i < size; i++ )
{
// 读取
v = Byte(start_addr + i);
// 异或
PatchByte(start_addr + i, v ^ key);
}
Message("Done! Please press C at 0x401000\n");


int sub_4014D0()
{
size_t v0; // eax
int i; // [esp+14h] [ebp-A4h]
signed int v3; // [esp+18h] [ebp-A0h]
char v4[145]; // [esp+23h] [ebp-95h] BYREF
int v5; // [esp+B4h] [ebp-4h]
sub_4017A0();
v5 = 0;
memset(&v4[17], 0, 0x80u);
strcpy(v4, "C4n_you_f1nd_it?");
puts("Hello,CTFer!\nPlz input...");
sub_401EA0("%s", &v4[17]);
v3 = strlen(&v4[17]);
if ( v3 % 4 )
{
for ( i = 0; i < 4 - v3 % 4; ++i )
v4[v3 + 17 + i] = -52;
}
v0 = strlen(&v4[17]);
sub_4013A0(&v4[17], v0 >> 2, v4);
if ( !memcmp(&v4[17], &unk_405000, 0x80u) )
puts("You find it!!!");
else
puts("NOP");
return 0;
}
TEA 系列算法。但是存在魔改
int __cdecl sub_4013A0(_DWORD *a1, int a2, int a3)
{
int v3; // eax
int v4; // eax
int result; // eax
int v6; // [esp+0h] [ebp-1Ch]
int v7; // [esp+4h] [ebp-18h]
unsigned int i; // [esp+8h] [ebp-14h]
unsigned int v9; // [esp+Ch] [ebp-10h]
unsigned int v10; // [esp+10h] [ebp-Ch]
v7 = 52 / a2 + 6;
v9 = 0;
v10 = a1[a2 - 1];
do
{
v9 += 421101824; //魔改点
v6 = (v9 >> 2) & 3;
for ( i = 0; i < a2 - 1; ++i )
{
v3 = a1[i]
+ (((v10 ^ *(_DWORD *)(a3 + 4 * (v6 ^ i & 3))) + (a1[i + 1] ^ v9)) ^ (((16 * v10) ^ (a1[i + 1] >> 3))
+ ((4 * a1[i + 1]) ^ (v10 >> 5))));
a1[i] = v3;
v10 = v3;
}
v4 = a1[a2 - 1]
+ (((v10 ^ *(_DWORD *)(a3 + 4 * (v6 ^ i & 3))) + (*a1 ^ v9)) ^ (((16 * v10) ^ (*a1 >> 3))
+ ((4 * *a1) ^ (v10 >> 5))));
a1[a2 - 1] = v4;
v10 = v4;
result = v7 - 1;
v7 = result;
}
while ( result );
return result;
}
paylod
import struct
def xxtea_decrypt(v, k):
"""
XXTEA 解密 (自定义 DELTA 版)
"""
n = len(v)
if n == 0: return v
# === 关键修改 ===
# 题目代码中的魔改常数: 421101824 -> 0x19198100
DELTA = 0x19198100
rounds = 6 + 52 // n
# 解密时 sum 的初始值 = rounds * DELTA
sum_value = (rounds * DELTA) & 0xffffffff
y = v[0]
while sum_value != 0:
e = (sum_value >> 2) & 3
for p in range(n - 1, -1, -1):
z = v[p - 1]
# 标准 XXTEA MX 运算
mx = (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum_value ^ y) + (k[(p & 3) ^ e] ^ z)))
v[p] = (v[p] - mx) & 0xffffffff
y = v[p]
sum_value = (sum_value - DELTA) & 0xffffffff
return v
# 1. 密钥 Key: "C4n_you_f1nd_it?"
key_str = "C4n_you_f1nd_it?"
k = list(struct.unpack("<4I", key_str.encode('utf-8')))
# 2. 密文 Ciphertext (从 unk_405000 提取)
raw_cipher = [
0x1B, 0x9F, 0xFF, 0x21, 0xA3, 0x3B, 0x44, 0x5E,
0x2F, 0x5E, 0x34, 0x31, 0xE0, 0x30, 0x1C, 0x50,
0xE6, 0x7F, 0xEF, 0x7B, 0x7F, 0xE4, 0xE3, 0x22,
0x96, 0x2F, 0x95, 0xD4, 0x81, 0xEB, 0xC3, 0xDE
]
cipher_bytes = bytes(raw_cipher)
v = list(struct.unpack(f"<{len(cipher_bytes)//4}I", cipher_bytes))
print("正在解密...")
print(f"使用魔改 DELTA: 0x19198100")
# 3. 执行解密
try:
decrypted_v = xxtea_decrypt(v, k)
flag_bytes = struct.pack(f"<{len(decrypted_v)}I", *decrypted_v)
# 去掉可能的填充字符 (如 \x00)
flag = flag_bytes.decode('utf-8', errors='ignore').strip('\x00')
print("\n[+] 成功获取 Flag:")
print(flag)
except Exception as e:
print(f"[-] 解密失败: {e}")

BF5



发现一个异常处理

大概率是中间换表了

中间出了一个不可见字符,结合题意猜测大概率是BF5???使用Cyberchef验证

ez_reverse
找到真正的入口
__int64 sub_140001781()
{
char v1; // al
char v2; // al
int v3; // eax
char Str[8]; // [rsp+20h] [rbp-60h] BYREF //八字节长度
__int64 v5; // [rsp+28h] [rbp-58h]
__int64 v6; // [rsp+30h] [rbp-50h]
_QWORD v7[3]; // [rsp+38h] [rbp-48h]
_QWORD v8[32]; // [rsp+50h] [rbp-30h] BYREF
_QWORD Buf2[3]; // [rsp+150h] [rbp+D0h] BYREF
_QWORD v10[2]; // [rsp+168h] [rbp+E8h]
size_t Size; // [rsp+178h] [rbp+F8h]
char *v12; // [rsp+180h] [rbp+100h] //应该是要存储字符串了
size_t i; // [rsp+188h] [rbp+108h]
sub_140001BD0(); //初看着是初始化
Buf2[0] = 0x748B593B53D6418DLL;
Buf2[1] = 0x52D42B1830A4A3F6LL;
Buf2[2] = 0x791261B1DA305E21LL;
v10[0] = 0x698E8AD46D2D7615LL;
*(_QWORD *)((char *)v10 + 5) = 0xD2B20F09C3698E8AuLL; //看着是密文数据
memset(v8, 0, sizeof(v8));
v12 = "Th1s_15_eAsy_Key"; //密钥
*(_QWORD *)Str = 0LL;
v5 = 0LL;
v6 = 0LL;
v7[0] = 0LL;
*(_QWORD *)((char *)v7 + 6) = 0LL;
puts("Please input your flag:");
if ( (unsigned int)sub_1400014A6("%37s", Str) == 1 )
{
Size = strlen(Str);
if ( Size == 37 )
{
for ( i = 0LL; i < Size; ++i )
{
v1 = sub_140001500(Str[i], i & 7); //循环左移
Str[i] = v1;
v2 = sub_140001537(Str[i], (i + 3) & 7); //循环右移
Str[i] = v2;
}
v3 = strlen(v12);
sub_14000156E((__int64)v12, v3, (__int64)v8); //RC4密钥调度
sub_140001661(v8, Str, (unsigned int)Size); //RC4伪随机生成
if ( !memcmp(Str, Buf2, Size) )
puts("You gets the flag!");
else
puts("sorry!");
return 0LL;
}
else
{
puts("Wrong Length!");
return 1LL;
}
}
else
{
puts("Input error.");
return 1LL;
}
}
去寻找37位字符串

由此可知
[Buf2] |
8D 41 D6 53 3B 59 8B 74 |
8 B | Buf2[0] |
|---|---|---|---|
[Buf2+8] |
F6 A3 A4 30 18 2B D4 52 |
8 B | Buf2[1] |
[Buf2+16] |
21 5E 30 DA B1 61 12 79 |
8 B | Buf2[2] |
[Buf2+24] |
15 76 2D 6D D4 8A 8E 69 |
8 B | v10[0] |
[Buf2+24+5] |
8A 8E 69 C3 09 0F B2 D2 |
8 B | v10[1] 从 +5 偏移写入 |
所以最后的37位是:
8D 41 D6 53 3B 59 8B 74
F6 A3 A4 30 18 2B D4 52
21 5E 30 DA B1 61 12 79
15 76 2D 6D D4 8A 8E 69
C3 09 0F B2 D2
随后观察sub_140001661
__int64 __fastcall sub_140001661(__int64 a1, __int64 a2, int a3)
{
__int64 result; // rax
char v4; // [rsp+3h] [rbp-Dh]
unsigned int i; // [rsp+4h] [rbp-Ch]
int v6; // [rsp+8h] [rbp-8h]
int v7; // [rsp+Ch] [rbp-4h]
v7 = 0;
v6 = 0;
for ( i = 0; ; ++i )
{
result = i;
if ( (int)i >= a3 )
break;
v7 = (v7 + 1) % 256;
v6 = (v6 + *(unsigned __int8 *)(v7 + a1)) % 256;
v4 = *(_BYTE *)(v7 + a1);
*(_BYTE *)(v7 + a1) = *(_BYTE *)(v6 + a1);
*(_BYTE *)(a1 + v6) = v4;
*(_BYTE *)((int)i + a2) += *(_BYTE *)((unsigned __int8)(*(_BYTE *)(v7 + a1) + *(_BYTE *)(v6 + a1)) + a1);
} //这里是加法 不是抑或 根据这个后面需要修改payload
return result;
}
payload
def rol(x, n):
return ((x << n) & 0xFF) | (x >> (8 - n))
def ror(x, n):
return (x >> n) | ((x << (8 - n)) & 0xFF)
# RC4 Key Scheduling Algorithm(KSA)
def rc4_ksa(key):
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
return S
# RC4-like PRGA——注意这里是 += 而不是 XOR(解密用 -=)
def rc4_add_decrypt(S, data):
i = j = 0
out = bytearray()
for b in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
k = S[(S[i] + S[j]) % 256]
out.append((b - k) & 0xFF) # 解密时是“减法”
return out
# === 已知密文(37字节) ===
buf2_bytes = [
0x8D,0x41,0xD6,0x53,0x3B,0x59,0x8B,0x74,
0xF6,0xA3,0xA4,0x30,0x18,0x2B,0xD4,0x52,
0x21,0x5E,0x30,0xDA,0xB1,0x61,0x12,0x79,
0x15,0x76,0x2D,0x6D,0xD4,0x8A,0x8E,0x69,
0xC3,0x09,0x0F,0xB2,0xD2
]
cipher = bytes(buf2_bytes)
print(f"Cipher length: {len(cipher)}")
# 密钥
key = b"Th1s_15_eAsy_Key"
# === Step 1: 运行 RC4-like 解密(用减法) ===
S = rc4_ksa(key)
decrypted = rc4_add_decrypt(S, cipher)
# === Step 2: 逆向位运算(反向旋转) ===
flag = bytearray()
for i, ch in enumerate(decrypted):
# 加密时是: rol(a, i&7) -> ror(a, (i+3)&7)
# 解密时反过来: rol(a, (i+3)&7) -> ror(a, i&7)
t = rol(ch, (i + 3) & 7)
t = ror(t, i & 7)
flag.append(t)
try:
print("Flag:", flag.decode('ascii'))
except UnicodeDecodeError:
print("Flag (部分可见):", flag.decode('ascii', errors='ignore'))
print("Flag bytes:", flag)
print("Flag hex:", flag.hex())
flag CBCTF{e2_ReVeR5E_1s_1Nt4REStiNG_HuH?}
Lost_Key

初步猜测是老旧版本中存在关键数据泄露


从旧版当中可以提取到一个公钥和密文,B64解码发现是私钥

-----BEGIN RSA PRIVATE KEY-----\nMIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAI+yP5z/vE+vniHF\nSdNYdz1/GpCseRmCgzdUZdOW7sLVTEsVmJaNnSvy7pKC0VSbiqcrOClo1GBIvba6\nY1t0hpAJSWybGjMAOVi1DgU4JlQa4MxB79/xNxU8i4eMiCY18g+7X7LLg1kOdl85\n/pjsHqMoQnhE5/NcIpO5FZL7qlHBAgMBAAECgYBrAe5lV/w/yyQTOfv0KxkA7ro1\nqnq0CID2nx8FJoy/AmBCOd7bnrHAnLQU3t5MB1iFjKXSEIK3APRmMv7yiB/724Np\nqUUSfXVfmzI5j+nc8vPHDfjCrOVMuRfJTqn8Y/unv8MW2zks7DbEwkBy99GSUV/K\n/pFC2FkhamDfRkhfAQJBANfvnbwXi6GX7SPfdlaikfP9zTiH3RLssGqyp0A/TUsy\nLhDr3fmuPlQTxIdHw1HzeS3nyd+r2sz2FsK8cORBSqkCQQCqW3BCnjb6NkKWJRy/\nzL/3K4qD4OfLAiULD+Yo+crkCPvasieffylt2Eld8OfloztrX2EV9r5Ox87LUsRZ\nS5VZAkEAucL2BAiRY3tqUxD7Ib6LJsYxFK+0nIInpjJ4tUl/ue+6N25hsFiYYAX9\nbI9s1QRKPBaJ0TRrbyVJIU+xInuUuQJAfRf/6ys6u6k0ZASEg+LZ46o5YHW6P7wn\nb2QRYm1qquBd8E16AwjhZyO3XCAWaO3gKAw1wmcZf8gA9hSk0d1KoQJAa75FKWmL\nJhUlWs+kG+KdhEQNkVu0lfxv7Bqwf1/AzddwBcbO1XrD3VeUFj7GmRLTLKn8qqte\nly52zDvm5DlwWA==\n-----END RSA PRIVATE KEY-----
然后到新的程序中 竟然发现公钥是一样的,那么说明私钥相同

把那一串BASE64解密之后就是RSA加密过的东西

import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from Crypto.Cipher import PKCS1_OAEP
private_key_str = """-----BEGIN RSA PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAI+yP5z/vE+vniHF
SdNYdz1/GpCseRmCgzdUZdOW7sLVTEsVmJaNnSvy7pKC0VSbiqcrOClo1GBIvba6
Y1t0hpAJSWybGjMAOVi1DgU4JlQa4MxB79/xNxU8i4eMiCY18g+7X7LLg1kOdl85
/pjsHqMoQnhE5/NcIpO5FZL7qlHBAgMBAAECgYBrAe5lV/w/yyQTOfv0KxkA7ro1
qnq0CID2nx8FJoy/AmBCOd7bnrHAnLQU3t5MB1iFjKXSEIK3APRmMv7yiB/724Np
qUUSfXVfmzI5j+nc8vPHDfjCrOVMuRfJTqn8Y/unv8MW2zks7DbEwkBy99GSUV/K
/pFC2FkhamDfRkhfAQJBANfvnbwXi6GX7SPfdlaikfP9zTiH3RLssGqyp0A/TUsy
LhDr3fmuPlQTxIdHw1HzeS3nyd+r2sz2FsK8cORBSqkCQQCqW3BCnjb6NkKWJRy/
zL/3K4qD4OfLAiULD+Yo+crkCPvasieffylt2Eld8OfloztrX2EV9r5Ox87LUsRZ
S5VZAkEAucL2BAiRY3tqUxD7Ib6LJsYxFK+0nIInpjJ4tUl/ue+6N25hsFiYYAX9
bI9s1QRKPBaJ0TRrbyVJIU+xInuUuQJAfRf/6ys6u6k0ZASEg+LZ46o5YHW6P7wn
b2QRYm1qquBd8E16AwjhZyO3XCAWaO3gKAw1wmcZf8gA9hSk0d1KoQJAa75FKWmL
JhUlWs+kG+KdhEQNkVu0lfxv7Bqwf1/AzddwBcbO1XrD3VeUFj7GmRLTLKn8qqte
ly52zDvm5DlwWA==
-----END RSA PRIVATE KEY-----"""
cipher_text_base64 = "PKn6B7xz9AM3wwwNYZnQIx2RnCDQL52Xq1M9znBMxBxwRQJJLdaDNQ7XyVEaKs/r5r3D2WJS6HJUapuO20vEsMWFyNuzeQHVxrQRLw8vHXT/pgC5kOjvreRDKLgmWejn0klLQbkARox9f7Q+1x370YIFouLrNQUjJOTyKuGmukk=" # <--- 这里填入完整的 Base64
def decrypt_rsa(priv_key_pem, b64_cipher):
try:
key = RSA.importKey(priv_key_pem)
ciphertext = base64.b64decode(b64_cipher)
cipher = PKCS1_v1_5.new(key)
sentinel = b"Decryption error"
plaintext = cipher.decrypt(ciphertext, sentinel)
if plaintext != sentinel:
print(f"[+] Decrypted with PKCS1_v1_5: {plaintext}")
try:
print(f"[+] As String: {plaintext.decode('utf-8')}")
except:
pass
return
cipher_oaep = PKCS1_OAEP.new(key)
plaintext = cipher_oaep.decrypt(ciphertext)
print(f"[+] Decrypted with OAEP: {plaintext}")
print(f"[+] As String: {plaintext.decode('utf-8')}")
except Exception as e:
print(f"[-] Error: {e}")
decrypt_rsa(private_key_str, cipher_text_base64)

ez_reverse
找到真正的入口
__int64 sub_140001781()
{
char v1; // al
char v2; // al
int v3; // eax
char Str[8]; // [rsp+20h] [rbp-60h] BYREF //八字节长度
__int64 v5; // [rsp+28h] [rbp-58h]
__int64 v6; // [rsp+30h] [rbp-50h]
_QWORD v7[3]; // [rsp+38h] [rbp-48h]
_QWORD v8[32]; // [rsp+50h] [rbp-30h] BYREF
_QWORD Buf2[3]; // [rsp+150h] [rbp+D0h] BYREF
_QWORD v10[2]; // [rsp+168h] [rbp+E8h]
size_t Size; // [rsp+178h] [rbp+F8h]
char *v12; // [rsp+180h] [rbp+100h] //应该是要存储字符串了
size_t i; // [rsp+188h] [rbp+108h]
sub_140001BD0(); //初看着是初始化
Buf2[0] = 0x748B593B53D6418DLL;
Buf2[1] = 0x52D42B1830A4A3F6LL;
Buf2[2] = 0x791261B1DA305E21LL;
v10[0] = 0x698E8AD46D2D7615LL;
*(_QWORD *)((char *)v10 + 5) = 0xD2B20F09C3698E8AuLL; //看着是密文数据
memset(v8, 0, sizeof(v8));
v12 = "Th1s_15_eAsy_Key"; //密钥
*(_QWORD *)Str = 0LL;
v5 = 0LL;
v6 = 0LL;
v7[0] = 0LL;
*(_QWORD *)((char *)v7 + 6) = 0LL;
puts("Please input your flag:");
if ( (unsigned int)sub_1400014A6("%37s", Str) == 1 )
{
Size = strlen(Str);
if ( Size == 37 )
{
for ( i = 0LL; i < Size; ++i )
{
v1 = sub_140001500(Str[i], i & 7); //循环左移
Str[i] = v1;
v2 = sub_140001537(Str[i], (i + 3) & 7); //循环右移
Str[i] = v2;
}
v3 = strlen(v12);
sub_14000156E((__int64)v12, v3, (__int64)v8); //RC4密钥调度
sub_140001661(v8, Str, (unsigned int)Size); //RC4伪随机生成
if ( !memcmp(Str, Buf2, Size) )
puts("You gets the flag!");
else
puts("sorry!");
return 0LL;
}
else
{
puts("Wrong Length!");
return 1LL;
}
}
else
{
puts("Input error.");
return 1LL;
}
}
去寻找37位字符串

由此可知
[Buf2] |
8D 41 D6 53 3B 59 8B 74 |
8 B | Buf2[0] |
|---|---|---|---|
[Buf2+8] |
F6 A3 A4 30 18 2B D4 52 |
8 B | Buf2[1] |
[Buf2+16] |
21 5E 30 DA B1 61 12 79 |
8 B | Buf2[2] |
[Buf2+24] |
15 76 2D 6D D4 8A 8E 69 |
8 B | v10[0] |
[Buf2+24+5] |
8A 8E 69 C3 09 0F B2 D2 |
8 B | v10[1] 从 +5 偏移写入 |
所以最后的37位是:
8D 41 D6 53 3B 59 8B 74
F6 A3 A4 30 18 2B D4 52
21 5E 30 DA B1 61 12 79
15 76 2D 6D D4 8A 8E 69
C3 09 0F B2 D2
随后观察sub_140001661
__int64 __fastcall sub_140001661(__int64 a1, __int64 a2, int a3)
{
__int64 result; // rax
char v4; // [rsp+3h] [rbp-Dh]
unsigned int i; // [rsp+4h] [rbp-Ch]
int v6; // [rsp+8h] [rbp-8h]
int v7; // [rsp+Ch] [rbp-4h]
v7 = 0;
v6 = 0;
for ( i = 0; ; ++i )
{
result = i;
if ( (int)i >= a3 )
break;
v7 = (v7 + 1) % 256;
v6 = (v6 + *(unsigned __int8 *)(v7 + a1)) % 256;
v4 = *(_BYTE *)(v7 + a1);
*(_BYTE *)(v7 + a1) = *(_BYTE *)(v6 + a1);
*(_BYTE *)(a1 + v6) = v4;
*(_BYTE *)((int)i + a2) += *(_BYTE *)((unsigned __int8)(*(_BYTE *)(v7 + a1) + *(_BYTE *)(v6 + a1)) + a1);
} //这里是加法 不是抑或 根据这个后面需要修改payload
return result;
}
payload
def rol(x, n):
return ((x << n) & 0xFF) | (x >> (8 - n))
def ror(x, n):
return (x >> n) | ((x << (8 - n)) & 0xFF)
# RC4 Key Scheduling Algorithm(KSA)
def rc4_ksa(key):
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
return S
# RC4-like PRGA——注意这里是 += 而不是 XOR(解密用 -=)
def rc4_add_decrypt(S, data):
i = j = 0
out = bytearray()
for b in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
k = S[(S[i] + S[j]) % 256]
out.append((b - k) & 0xFF) # 解密时是“减法”
return out
# === 已知密文(37字节) ===
buf2_bytes = [
0x8D,0x41,0xD6,0x53,0x3B,0x59,0x8B,0x74,
0xF6,0xA3,0xA4,0x30,0x18,0x2B,0xD4,0x52,
0x21,0x5E,0x30,0xDA,0xB1,0x61,0x12,0x79,
0x15,0x76,0x2D,0x6D,0xD4,0x8A,0x8E,0x69,
0xC3,0x09,0x0F,0xB2,0xD2
]
cipher = bytes(buf2_bytes)
print(f"Cipher length: {len(cipher)}")
# 密钥
key = b"Th1s_15_eAsy_Key"
# === Step 1: 运行 RC4-like 解密(用减法) ===
S = rc4_ksa(key)
decrypted = rc4_add_decrypt(S, cipher)
# === Step 2: 逆向位运算(反向旋转) ===
flag = bytearray()
for i, ch in enumerate(decrypted):
# 加密时是: rol(a, i&7) -> ror(a, (i+3)&7)
# 解密时反过来: rol(a, (i+3)&7) -> ror(a, i&7)
t = rol(ch, (i + 3) & 7)
t = ror(t, i & 7)
flag.append(t)
try:
print("Flag:", flag.decode('ascii'))
except UnicodeDecodeError:
print("Flag (部分可见):", flag.decode('ascii', errors='ignore'))
print("Flag bytes:", flag)
print("Flag hex:", flag.hex())
flag CBCTF{e2_ReVeR5E_1s_1Nt4REStiNG_HuH?}