Reverse

84次阅读
没有评论

Reverse

Welcome

Reverse

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

左移三位即可解密
Reverse

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 中的有符号整数转换成无符号十六进制:

  1. -1605326664​ -> 0xA050E8B8
  2. -1446105387​ -> 0xA9CD6ED5
  3. 1590482979​ -> 0x5ECD0623
  4. 1040045873​ -> 0x3DFD9731
  5. 505225631​ -> 0x1E1D119F
  6. 1713322116​ -> 0x661F6884
  7. 1924870785​ -> 0x72BB5281
  8. -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 (示例,具体内容取决于计算结果)

注意点:

  1. Delta 的符号​:代码中是 -= 1640531527​。由于 1640531527​ 实际上是 0x61C88647​,所以 -= 0x61C88647​ 相当于 += 0x9E3779B9​ (这是标准的 Delta)。我的脚本中直接使用了标准的 DELTA = 0x9E3779B9 和标准的 XXTEA 解密逻辑。
  2. 文件格式:题目通过 CreateFile​ 读取 flag.loveyou,所以你在本地复现或者提交时,可能需要将计算出的字符串写入到这个文件中,或者直接提交字符串作为 Flag。

Reverse

大胃袋

Reverse

发现反调试

Reverse

原值为21

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

Reverse

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");

Reverse

Reverse

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}")

Reverse

Welcome

Reverse

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

左移三位即可解密
Reverse

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 中的有符号整数转换成无符号十六进制:

  1. -1605326664​ -> 0xA050E8B8
  2. -1446105387​ -> 0xA9CD6ED5
  3. 1590482979​ -> 0x5ECD0623
  4. 1040045873​ -> 0x3DFD9731
  5. 505225631​ -> 0x1E1D119F
  6. 1713322116​ -> 0x661F6884
  7. 1924870785​ -> 0x72BB5281
  8. -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'))

Reverse

大胃袋

Reverse

发现反调试

Reverse

原值为21

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

Reverse

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");

Reverse

Reverse

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}")

Reverse

BF5

Reverse

Reverse

Reverse

发现一个异常处理

Reverse

大概率是中间换表了

Reverse

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

Reverse

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位字符串

Reverse

由此可知

[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

Reverse

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

ReverseReverse

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

-----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-----

然后到新的程序中 竟然发现公钥是一样的,那么说明私钥相同
Reverse

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

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)

Reverse

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位字符串

Reverse

由此可知

[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?}

正文完
 0
评论(没有评论)