2025-basectf-re


week1

You are good at IDA

主函数看到一部分flag-Y0u_4Re_,看提示有f12+shift

image-20250605204033089

这个视图列举出了 IDA 识别到的所有字符串

image-20250605204907502
1
2
3
双击这一行可以跳转到文件中这个字符串的位置,DATA XREF:显示了哪个函数使用了这个字符串,双击可以跳转到那个函数
然后将里面的数值按 R 键以字符形式显示,然后显示伪代码就能得到第二部分
并且函数里面给了最后一部分的提示
image-20250605210942657 image-20250605211004582 image-20250605212239645

得到900d_47_(右键将ascii转换_),看提示,最后一部分在一个名字叫Interesting的函数里面

image-20250605212353348

得到id4

所有flag是BaseCTF{Y0u_4Re_900d_47_id4}

UPX mini

发现有壳

image-20250605212823045

upx脱壳

image-20250605213113940

fn+f5看到伪代码

image-20250605213256362

代码逻辑很清晰,就是将输入的flag进行加密后与Str2进行比较。wp还看这个base64编码的源码是否正确,我一看有base64字符就解码了,结果不出意外是flagBaseCTF{Hav3_@_g0od_t1m3!!!}

ez_maze

64位无壳

image-20250605213928113

fn+f5看到伪代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  char v5[32]; // [rsp+20h] [rbp-60h] BYREF
  __int16 v6; // [rsp+40h] [rbp-40h]
  char v7; // [rsp+42h] [rbp-3Eh]
  int i; // [rsp+48h] [rbp-38h]
  int v9; // [rsp+4Ch] [rbp-34h]

  sub_401840(argc, argv, envp);
  j_puts(Buffer);
  j_puts(aTakeTheShortes);
  j_puts(aShowYourTime);
  memset(v5, 0, sizeof(v5));
  v6 = 0;
  v7 = 0;
  j_scanf("%34s", v5);
  v9 = 0;
  for ( i = 0; v5[i]; ++i )
  {
    v3 = (unsigned __int8)v5[i];
    if ( v3 == 100 )
    {
      if ( v9 % 15 == 14 )
        goto LABEL_20;
      ++v9;
    }
    else if ( (unsigned __int8)v5[i] > 0x64u )
    {
      if ( v3 == 115 )
      {
        if ( v9 > 209 )
          goto LABEL_20;
        v9 += 15;
      }
      else
      {
        if ( v3 != 119 )
        {
LABEL_21:
          j_puts(aInvalidInput);
          return -1;
        }
        if ( v9 <= 14 )
          goto LABEL_20;
        v9 -= 15;
      }
    }
    else
    {
      if ( v3 != 97 )
        goto LABEL_21;
      if ( !(v9 % 15) )
      {
LABEL_20:
        j_puts(aInvalidMoveOut);
        return -1;
      }
      --v9;
    }
    if ( asc_403020[v9] == 36 )
    {
      j_puts(aInvalidMoveHit);
      return -1;
    }
    if ( asc_403020[v9] == 121 )
    {
      j_puts(aYouWin);
      j_puts(aPlzBasectfLowe);
      return 0;
    }
  }
  j_puts(aYouDidnTReachT);
  return 0;
}

这个代码是迷宫逻辑,shift+F12可以查找字符串,对着字符串按 Shift+E 可以提取数据,这个就是迷宫了。

image-20250605221931637

将代码和迷宫给ai,立马就有最短路径了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
def solve_maze(maze_data_hex):
    # Convert hex data to a list of integers
    maze_values = [int(hex_val, 16) for hex_val in maze_data_hex.split()]

    # Maze dimensions
    rows = 15
    cols = 15
    maze = [[] for _ in range(rows)]
    for i in range(rows):
        maze[i] = maze_values[i * cols : (i + 1) * cols]

    # Convert values to characters for easier visualization (optional)
    # maze_chars = [['' for _ in range(cols)] for _ in range(rows)]
    # for r in range(rows):
    #     for c in range(cols):
    #         if maze[r][c] == 120: # 'x'
    #             maze_chars[r][c] = 'x'
    #         elif maze[r][c] == 36: # '$'
    #             maze_chars[r][c] = '$'
    #         elif maze[r][c] == 38: # '&'
    #             maze_chars[r][c] = '&'
    #         elif maze[r][c] == 121: # 'y'
    #             maze_chars[r][c] = 'y'
    #         else:
    #             maze_chars[r][c] = '.' # Unknown

    start_v9 = 0
    goal_v9 = -1

    # Find the goal position
    try:
        goal_v9 = maze_values.index(121) # Find the index of 'y' (121)
    except ValueError:
        return "Goal ('y') not found in the maze."

    # BFS
    queue = [(start_v9, "")] # (current_v9, path_string)
    visited = {start_v9}

    while queue:
        current_v9, path = queue.pop(0)

        # Check for winning condition
        if current_v9 == goal_v9:
            return path

        # Possible moves and their corresponding characters
        moves = {
            'd': (current_v9 + 1, lambda v: v % cols != cols - 1), # Right
            's': (current_v9 + cols, lambda v: v + cols < rows * cols), # Down
            'w': (current_v9 - cols, lambda v: v - cols >= 0), # Up
            'a': (current_v9 - 1, lambda v: v % cols != 0) # Left
        }

        for move_char, (next_v9, condition) in moves.items():
            if condition(current_v9):
                # Check if next position is valid and not a trap
                if 0 <= next_v9 < rows * cols and maze_values[next_v9] != 36 and next_v9 not in visited:
                    visited.add(next_v9)
                    queue.append((next_v9, path + move_char))

    return "No path found to the goal."

# The provided maze data
maze_data_hex = "78 24 24 24 24 24 24 24 24 24 24 24 24 24 24 26 26 26 26 26 26 24 24 24 24 24 24 24 24 24 26 24 26 24 24 26 24 24 26 26 26 26 26 24 24 26 24 26 24 24 24 26 26 24 24 24 24 26 24 24 26 24 24 24 26 26 26 24 24 24 24 24 26 24 24 26 24 24 24 26 24 26 26 24 26 24 24 24 24 24 26 24 24 24 26 24 26 24 24 26 26 26 24 24 24 26 26 26 26 26 24 26 26 26 26 24 26 24 24 24 24 24 24 24 24 24 26 26 26 26 26 26 24 24 24 24 24 24 24 24 24 26 24 24 24 24 24 24 24 24 24 24 24 26 26 26 26 24 24 26 26 26 24 24 24 24 24 24 26 26 26 26 26 26 26 24 24 24 24 24 24 24 24 24 24 24 24 24 24 26 24 24 26 24 24 24 24 24 24 24 24 24 24 24 26 24 26 24 24 24 24 24 24 24 24 24 26 26 26 26 26 26 26 26 79 00"

# Solve the maze
solution_path = solve_maze(maze_data_hex)
print(solution_path)

跑出来md5加密就行

BaseCTF{131b7d6e60e8a34cb01801ae8de07efe}

‍‬‍‬‌‍‍‬⁠‍‌‍‌‍‍⁠‌‍‌‬BaseCTF 2024 官方 Writeup 合集 - 飞书云文档wp手动跑有点意思

BasePlus

image-20250606090036287
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
__int64 __fastcall Encode(const char *a1, __int64 a2)
{
  int v3; // r10d
  char *v4; // r9
  __int64 v5; // r8
  __int64 v6; // rdi
  int v7; // ebp
  __int64 v8; // rax
  __int64 result; // rax
  __int64 v10; // rax
  __int64 v11; // rcx
  bool v12; // r13
  bool v13; // r12
  char v14; // [rsp+8h] [rbp-40h]
  __int16 v15; // [rsp+9h] [rbp-3Fh]
  unsigned __int8 v16; // [rsp+Bh] [rbp-3Dh]
  char v17[60]; // [rsp+Ch] [rbp-3Ch] BYREF

  v3 = strlen(a1);
  if ( v3 <= 0 )
  {
    LODWORD(result) = 0;
  }
  else
  {
    v4 = v17;
    v5 = 4i64;
    v6 = 0i64;
    v7 = 0;
    do
    {
      v15 = 0;
      v16 = 0;
      if ( v3 > v7 )
      {
        v10 = v7 + 1;
        v11 = 1i64;
        do
        {
          v7 = v10;
          *(&v14 + v11) = a1[v10 - 1];
          v12 = (int)v11 <= 2;
          v13 = v3 > (int)v10++;
          ++v11;
        }
        while ( v13 && v12 );
      }
      v17[0] = Secret[(unsigned __int8)v15 >> 2];
      v17[1] = Secret[(HIBYTE(v15) >> 4) | (16 * (_BYTE)v15) & 0x30];
      v17[2] = Secret[(v16 >> 6) | (4 * HIBYTE(v15)) & 0x3C];
      v17[3] = Secret[v16 & 0x3F];
      v8 = v6;
      do
      {
        *(_BYTE *)(a2 + v8) = v4[v8] ^ 0xE;
        ++v8;
      }
      while ( v8 != v5 );
      LODWORD(result) = v5;
      v6 += 4i64;
      v4 -= 4;
      v5 += 4i64;
    }
    while ( v3 > v7 );
  }
  result = (int)result;
  *(_BYTE *)(a2 + (int)result) = 0;
  return result;
}
1
2
3
4
5
6
数组存储的值是Base64编码后异或完(0xE)的结果
根据main函数以及Encode函数中的伪代码,我们可以推出程序的flag处理方式:
输入Str --> 根据Secret数组进行Base64编码 --> 返回Base64编码后的字符串 ^ 0xE 的结果
所以我们要做的是:
取出预定的flag密文 --> 将每个字符都异或0xE --> 用预定的码表去解码这串密文
为了方便,这里使用CyberChef作为解题工具(可以自动识别一些码表)
image-20250606092225078

Ez Xor

无壳base64,直接拖入ida

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [rsp+2Ch] [rbp-74h] BYREF
  char v5[8]; // [rsp+30h] [rbp-70h] BYREF
  __int64 v6; // [rsp+38h] [rbp-68h]
  __int64 v7; // [rsp+40h] [rbp-60h]
  int v8; // [rsp+48h] [rbp-58h]
  char v9; // [rsp+4Ch] [rbp-54h]
  char Str[8]; // [rsp+50h] [rbp-50h] BYREF
  __int64 v11; // [rsp+58h] [rbp-48h]
  __int64 v12; // [rsp+60h] [rbp-40h]
  char v13[8]; // [rsp+68h] [rbp-38h] BYREF
  __int64 v14[3]; // [rsp+70h] [rbp-30h] BYREF
  int v15; // [rsp+88h] [rbp-18h]
  char v16; // [rsp+8Ch] [rbp-14h]
  unsigned int v17; // [rsp+98h] [rbp-8h]
  unsigned int v18; // [rsp+9Ch] [rbp-4h]

  _main(argc, argv, envp);
  memset(v14, 0, sizeof(v14));
  v15 = 0;
  v16 = 0;
  *(_QWORD *)Str = 0x1D0B2D2625050901i64;
  v11 = 0x673D491E20317A24i64;
  v12 = 0x34056E2E2508504Di64;
  strcpy(v13, "\"@;%");
  *(_QWORD *)v5 = 0i64;
  v6 = 0i64;
  v7 = 0i64;
  v8 = 0;
  v9 = 0;
  v4 = 7499608;
  v18 = strlen(Str);
  printf("Please input Your answer:");
  scanf("%s", v5);
  v17 = strlen(v5);
  if ( v17 == 28 )
  {
    KeyStream(&v4, v14, 28i64);
    encrypt(v14, v5, v17);
    if ( (unsigned int)CheckFlag(v5, Str, v18) )
      printf("You are good!");
    else
      printf("It's not flag!");
    return 1;
  }
  else
  {
    printf(aLengthWasWrong);
    return 0;
  }
}

扔给manus,直接出

image-20250606102116256
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/usr/bin/env python3

def key_stream(seed, length):
    """生成密钥流,与原始C代码中的KeyStream函数相同"""
    result = []
    # 提取seed的三个字节
    seed_bytes = [(seed >> 0) & 0xFF, (seed >> 8) & 0xFF, (seed >> 16) & 0xFF]
    
    for i in range(length):
        result.append(i ^ seed_bytes[i % 3])
    
    return result

def decrypt(encrypted_data, key_stream, length):
    """解密函数,逆向原始C代码中的encrypt函数"""
    result = list(encrypted_data)  # 创建副本
    
    for i in range(length):
        result[i] ^= key_stream[length - i - 1]
    
    return bytes(result)

def little_endian_to_bytes(value, size=8):
    """将小端序的64位整数转换为字节数组"""
    result = []
    for i in range(size):
        result.append((value >> (i * 8)) & 0xFF)
    return result

def main():
    # 从C代码中提取的小端序64位整数
    str_value = 0x1D0B2D2625050901
    v11_value = 0x673D491E20317A24
    v12_value = 0x34056E2E2508504D
    
    # 转换为字节数组(小端序)
    str_bytes = little_endian_to_bytes(str_value)
    v11_bytes = little_endian_to_bytes(v11_value)
    v12_bytes = little_endian_to_bytes(v12_value)
    
    # v13字符串 "\"@;%"
    v13_bytes = [ord('"'), ord('@'), ord(';'), ord('%')]
    
    # 合并所有字节
    encrypted_data = bytes(str_bytes + v11_bytes + v12_bytes + v13_bytes)
    length = len(encrypted_data)
    
    print(f"加密数据长度: {length}")
    print("加密数据字节:")
    for i, b in enumerate(encrypted_data):
        print(f"{i:2d}: {b:02X}")
    
    # 种子值(v4)
    seed = 7499608  # 0x726108
    
    # 生成密钥流
    ks = key_stream(seed, length)
    print("\n密钥流:")
    for i, k in enumerate(ks):
        print(f"{i:2d}: {k:02X}")
    
    # 解密
    decrypted = decrypt(encrypted_data, ks, length)
    
    # 输出结果
    print("\n解密后的flag: ", end="")
    try:
        print(decrypted.decode('ascii'))
    except UnicodeDecodeError:
        print("(包含非ASCII字符)")
    
    # 检查是否是有效的ASCII字符
    print("\n解密后的字节:")
    for i, b in enumerate(decrypted):
        print(f"{i:2d}: {b:02X} ('{chr(b) if 32 <= b <= 126 else '?'}')")

if __name__ == "__main__":
    main()

week2

UPX

考点:010修改+upx脱壳+base64换表

有壳

image-20250606104357700

工具脱壳发现报错

image-20250606104607252

010打开,发现把原本大写的标志位改成小写的了,所以导致我们不能正常脱壳,所以我们就得改回来,就可以正常脱壳了,

image-20250606104748463

改完后成功

image-20250606104932798
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
unsigned __int8 *__cdecl b64(const char *input)
{
  int v1; // eax
  int v2; // edx
  int v3; // eax
  unsigned __int8 v4; // al
  unsigned __int8 v5; // al
  unsigned __int8 map[64]; // [rsp+20h] [rbp-70h] BYREF
  int val; // [rsp+64h] [rbp-2Ch]
  unsigned __int8 *out; // [rsp+68h] [rbp-28h]
  int out_len; // [rsp+74h] [rbp-1Ch]
  int pad; // [rsp+78h] [rbp-18h]
  int in_len; // [rsp+7Ch] [rbp-14h]
  unsigned __int8 *in; // [rsp+80h] [rbp-10h]
  int j; // [rsp+88h] [rbp-8h]
  int i; // [rsp+8Ch] [rbp-4h]

  in = (unsigned __int8 *)input;
  _map(map);
  in_len = strlen((const char *)in);
  pad = (3 - in_len % 3) % 3;
  out_len = 4 * ((in_len + pad) / 3);
  out = (unsigned __int8 *)malloc(out_len + 1);
  memset(out, 0, out_len + 1);
  i = 0;
  j = 0;
  while ( i < in_len )
  {
    if ( in_len <= i + 1 )
      v1 = 0;
    else
      v1 = in[i + 1] << 8;
    v2 = v1 + (in[i] << 16);
    if ( in_len <= i + 2 )
      v3 = 0;
    else
      v3 = in[i + 2];
    val = v2 + v3;
    out[j] = map[((v2 + v3) >> 18) & 0x3F];
    out[j + 1] = map[(val >> 12) & 0x3F];
    if ( in_len <= i + 1 )
      v4 = 61;
    else
      v4 = map[(val >> 6) & 0x3F];
    out[j + 2] = v4;
    if ( in_len <= i + 2 )
      v5 = 61;
    else
      v5 = map[val & 0x3F];
    out[j + 3] = v5;
    i += 3;
    j += 4;
  }
  return out;
}

发现其实就是一个base64编码,但是具体是否换表我们得仔细查找一下。我们从上往下看发现有一个字符串,_map很可疑,双击查看,

image-20250606111020775

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import base64

# 你的自定义 Base64 表
custom_b64 = "A,.1fgvw#`/2ehux$~\"3dity%_;4cjsz^+{5bkrA&=}6alqB*-[70mpC()]89noX"
standard_b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

# 构建解码映射表:custom → standard
decode_map = {c: standard_b64[i] for i, c in enumerate(custom_b64)}

# 给定的目标密文
target = "$rg7_dhd~Alidg+zeyhz`vnz_d,7sy0="

# 替换为标准 Base64 字符串
translated = ''.join(decode_map.get(c, c) for c in target)

# Base64 解码
decoded = base64.b64decode(translated)

# 输出结果
print("Decrypted flag:", decoded.decode())

lk

反编译扔给ai就有

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import numpy as np
from scipy.optimize import lsq_linear

# Manually extracted coefficients for each equation (16 equations, 20 variables)
# Each row corresponds to an equation, each column to byte_14000A668[1] ... byte_14000A668[20]
A = np.array([
    [283, 860, 616, 575, 891, 758, 851, 773, 931, 323, 257, 141, 987, 965, 908, 417, 978, 410, 887, 948],
    [148, 421, 151, 111, 80, 580, 62, 974, 954, 589, 718, 938, 708, 35, 68, 568, 50, 920, 490, 938],
    [182, 506, 674, 948, 113, 11, 392, 409, 892, 932, 920, 95, 622, 778, 335, 489, 222, 668, 590, 908],
    [707, 571, 180, 716, 570, 890, 427, 447, 728, 465, 479, 34, 624, 773, 266, 891, 399, 410, 859, 479],
    [807, 771, 199, 437, 169, 873, 49, 282, 814, 459, 679, 142, 304, 949, 901, 71, 716, 380, 798, 556],
    [83, 496, 231, 469, 385, 235, 654, 522, 917, 369, 35, 25, 322, 856, 831, 156, 198, 979, 898, 465],
    [585, 194, 33, 220, 376, 787, 648, 50, 195, 711, 747, 688, 236, 758, 708, 787, 793, 260, 928, 305],
    [859, 273, 803, 976, 7, 443, 541, 653, 701, 311, 964, 848, 0, 136, 588, 598, 909, 22, 573, 767],
    [95, 883, 236, 81, 818, 634, 181, 365, 215, 9, 799, 456, 768, 377, 744, 397, 164, 507, 59, 776],
    [789, 422, 942, 606, 792, 806, 905, 484, 773, 998, 300, 933, 240, 617, 689, 960, 423, 381, 234, 873],
    [988, 898, 212, 175, 845, 114, 828, 414, 603, 817, 736, 590, 696, 343, 305, 211, 900, 283, 7, 766],
    [961, 466, 70, 860, 886, 729, 689, 998, 689, 735, 996, 121, 952, 366, 501, 574, 106, 788, 30, 220],
    [866, 701, 620, 141, 540, 907, 604, 271, 299, 136, 79, 316, 49, 283, 362, 156, 864, 522, 748, 313],
    [913, 999, 674, 979, 147, 646, 701, 749, 991, 110, 406, 144, 770, 438, 224, 159, 26, 425, 399, 922],
    [164, 725, 0, 454, 269, 784, 41, 797, 439, 325, 74, 779, 743, 654, 484, 153, 421, 225, 537, 13],
    [220, 200, 789, 41, 562, 404, 683, 818, 978, 82, 634, 436, 176, 433, 42, 485, 204, 874, 210, 591],
    [915, 721, 268, 410, 715, 587, 491, 409, 822, 848, 899, 124, 240, 820, 858, 902, 532, 928, 597, 584],
    [875, 934, 726, 149, 287, 901, 477, 623, 560, 633, 53, 411, 28, 623, 160, 512, 180, 327, 302, 421],
    [133, 587, 834, 291, 780, 367, 69, 17, 934, 666, 495, 295, 15, 980, 170, 462, 649, 792, 434, 838],
    [391, 316, 66, 495, 554, 894, 745, 300, 684, 42, 69, 620, 179, 233, 854, 475, 224, 420, 422, 41]
])

# Right-hand side vector
B = np.array([
    913686,
    630335,
    707525,
    724203,
    688899,
    604784,
    665485,
    727664,
    572015,
    875498,
    714759,
    778853,
    584591,
    717586,
    537823,
    587367,
    842245,
    610801,
    653127,
    533470
])

# Define bounds for the byte values (0 to 255)
bounds = (0, 255)

# Solve the system using bounded least squares
# We expect an exact solution, so check for residuals near zero.
result = lsq_linear(A, B, bounds=bounds)

# Check the result
if result.success:
    solution = result.x
    # Check if the solution is close to integers and within bounds
    if np.allclose(solution, np.round(solution), atol=1e-5) and np.all((solution >= 0) & (solution <= 255)):
        flag_bytes = np.round(solution).astype(int)
        # Verify the solution by plugging back into the equations
        if np.allclose(np.dot(A, flag_bytes), B, atol=1e-5):
            print("Found integer solution:")
            print(flag_bytes)
            # Convert bytes to ASCII characters
            flag = "".join([chr(b) for b in flag_bytes])
            print("Decoded Flag:", flag)
        else:
            print("Found bounded solution, but it does not satisfy the equations exactly.")
            print("Solution:", solution)
    else:
        print("Found bounded solution, but it is not an integer solution within bounds.")
        print("Solution:", solution)
else:
    print("Optimization failed:", result.message) 

喝杯下午茶

tea加密

image-20250606115139367

DA 识别到的所有字符串,双击这一行可以跳转到文件中这个字符串的位置,DATA XREF:显示了哪个函数使用了这个字符串,双击可以跳转到那个函数,如何反编译得到伪代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
__int64 sub_140016100()
{
  char *v0; // rdi
  __int64 i; // rcx
  char v3[32]; // [rsp+0h] [rbp-20h] BYREF
  char v4; // [rsp+20h] [rbp+0h] BYREF
  int v5[12]; // [rsp+28h] [rbp+8h] BYREF
  int v6[16]; // [rsp+58h] [rbp+38h] BYREF
  char *v7; // [rsp+98h] [rbp+78h]
  char Str[76]; // [rsp+B8h] [rbp+98h] BYREF
  int j; // [rsp+104h] [rbp+E4h]

  v0 = &v4;
  for ( i = 66i64; i; --i )
  {
    *(_DWORD *)v0 = -858993460;
    v0 += 4;
  }
  sub_140011366(&unk_140022015);
  v5[0] = 287454020;
  v5[1] = 1432778632;
  v5[2] = -1716864052;
  v5[3] = -571539695;
  v6[0] = -1800277529;
  v6[1] = 567661394;
  v6[2] = 1380415805;
  v6[3] = 67968151;
  v6[4] = -210862220;
  v6[5] = -1672218865;
  v6[6] = 1793773528;
  v6[7] = 1872692980;
  v6[8] = -352477650;
  v6[9] = 850810359;
  v7 = 0i64;
  memset(Str, 0, 0x29ui64);
  sub_1400113ED("Please input your flag:");
  sub_1400113F7(&unk_14001AC10, Str);
  if ( j_strlen(Str) != 40 )
  {
    sub_1400113ED("Maybe something is wrong~~~");
    exit(0);
  }
  v7 = Str;
  for ( j = 0; j < 5; ++j )
    sub_1400113E3(&v7[8 * j], v5);
  if ( (unsigned int)sub_140011406(v6, v7) )
    sub_1400113ED("You are right!!!");
  else
    sub_1400113ED("NoNoNo!");
  sub_140011302(v3, &unk_14001B9F0);
  return 0i64;
}

标准的tea不过delta变了而已

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
__int64 __fastcall sub_140015FB0(unsigned int *a1, _DWORD *a2)
{
  __int64 result; // rax
  int v3; // [rsp+24h] [rbp+4h]
  int i; // [rsp+44h] [rbp+24h]
  unsigned int v5; // [rsp+64h] [rbp+44h]
  unsigned int v6; // [rsp+84h] [rbp+64h]

  sub_140011366(&unk_140022015);
  v3 = 0;
  v5 = *a1;
  v6 = a1[1];
  for ( i = 0; i < 32; ++i )
  {
    v3 += 1131796;
    v5 += (a2[1] + (v6 >> 5)) ^ (v3 + v6) ^ (*a2 + 16 * v6);
    v6 += (a2[3] + (v5 >> 5)) ^ (v3 + v5) ^ (a2[2] + 16 * v5);
  }
  *a1 = v5;c
  result = 4i64;
  a1[1] = v6;
  return result;
}

扔给manuns,一把梭哈了

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
#!/usr/bin/env python3

def uint32(val):
    """将值转换为32位无符号整数"""
    return val & 0xFFFFFFFF

def int32(val):
    """将值转换为32位有符号整数"""
    val = uint32(val)
    if val & 0x80000000:
        return val - 0x100000000
    return val

def tea_decrypt(v, k):
    """
    TEA解密函数
    v: 包含两个32位整数的列表,表示要解密的数据块
    k: 包含四个32位整数的列表,表示密钥
    """
    v0, v1 = v[0], v[1]
    k0, k1, k2, k3 = k[0], k[1], k[2], k[3]
    delta = 1131796  # 代码中使用的delta值
    sum_val = uint32(delta * 32)  # 初始sum值为delta * 32轮
    
    for _ in range(32):
        # 根据原始代码中的加密逻辑反向操作
        # 原始加密代码:
        # v5 += (a2[1] + (v6 >> 5)) ^ (v3 + v6) ^ (*a2 + 16 * v6);
        # v6 += (a2[3] + (v5 >> 5)) ^ (v3 + v5) ^ (a2[2] + 16 * v5);
        
        # 解密操作:
        v1 = uint32(v1 - ((k3 + (v0 >> 5)) ^ (sum_val + v0) ^ (k2 + 16 * v0)))
        v0 = uint32(v0 - ((k1 + (v1 >> 5)) ^ (sum_val + v1) ^ (k0 + 16 * v1)))
        sum_val = uint32(sum_val - delta)
    
    return [v0, v1]

def bytes_to_int_array(data):
    """将字节数组转换为整数数组"""
    result = []
    for i in range(0, len(data), 4):
        # 小端序转换
        value = int.from_bytes(data[i:i+4], byteorder='little')
        result.append(value)
    return result

def int_array_to_bytes(arr):
    """将整数数组转换为字节数组"""
    result = bytearray()
    for val in arr:
        result.extend(val.to_bytes(4, byteorder='little'))
    return result

def main():
    # 密钥数组v5
    key = [
        287454020,    # 0x11223344
        1432778632,   # 0x55667788
        -1716864052,  # 0x99AABBCC
        -571539695    # 0xDDEEFF01
    ]
    
    # 将负数转换为无符号整数
    key = [uint32(k) for k in key]
    
    # 加密后的数据数组v6
    encrypted_data = [
        -1800277529,  # 0x94AABB07
        567661394,    # 0x21D498C2
        1380415805,   # 0x5245DEAD
        67968151,     # 0x040D0C07
        -210862220,   # 0xF3721234
        -1672218865,  # 0x9C00FFFF
        1793773528,   # 0x6AE0DEAD
        1872692980,   # 0x6FABC0D4
        -352477650,   # 0xEAEAEA0E
        850810359     # 0x32B97777
    ]
    
    # 将负数转换为无符号整数
    encrypted_data = [uint32(d) for d in encrypted_data]
    
    # 解密数据
    decrypted_data = []
    for i in range(0, len(encrypted_data), 2):
        block = encrypted_data[i:i+2]
        decrypted_block = tea_decrypt(block, key)
        decrypted_data.extend(decrypted_block)
    
    # 将解密后的整数数组转换为字节数组
    decrypted_bytes = int_array_to_bytes(decrypted_data)
    
    # 尝试将字节数组转换为ASCII字符串
    try:
        flag = decrypted_bytes.decode('ascii')
        print(f"解密后的flag: {flag}")
    except UnicodeDecodeError:
        print("解密结果不是有效的ASCII字符串")
        print("解密后的字节数组:")
        for i, b in enumerate(decrypted_bytes):
            print(f"{i:2d}: {b:02X} ('{chr(b) if 32 <= b <= 126 else '?'}')")

if __name__ == "__main__":
    main()
谢谢观看