首页
社区
课程
招聘
[原创] 看雪 2024 KCTF 大赛 第七题 星际移民
发表于: 2024-8-28 23:50 536

[原创] 看雪 2024 KCTF 大赛 第七题 星际移民

2024-8-28 23:50
536

IDA打开,函数不多,主要逻辑都在 sub_401120

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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
int __cdecl sub_401120(unsigned __int8 **a1)
{
  char *v1; // eax
  unsigned __int8 *global_buf_401120; // esi
  int i; // ecx
  char t; // cl
  int j; // eax
  char v6; // dl
  char v; // dl
  _BYTE *p_serial_; // eax
  int v9; // ecx
  char v10; // cl
  char xor1; // al
  char *k; // edx
  unsigned __int8 *global_buf_4010d0; // esi
  unsigned __int8 *p_serial; // edx
  int index; // eax
  unsigned int ii; // ebp
  unsigned __int8 *p_buf_4010d0; // edi
  int v18; // ecx
  unsigned int jj; // edi
  unsigned __int8 *v20; // ecx
  unsigned __int8 *v21; // edx
  int v22; // eax
  char *v23; // esi
  unsigned __int8 *global_buf_401120_; // esi
  _BYTE *p_final; // ebp
  int i_; // edi
  char v27; // bl
  char v28; // al
  unsigned int v29; // edx
  const char *finalcheck; // eax
  _BYTE *final; // ecx
  char *p_serial_index; // [esp+10h] [ebp-4Ch]
  _BYTE serial[68]; // [esp+14h] [ebp-48h] BYREF
 
  v1 = hexdecode(global_serial);
  qmemcpy(serial, v1, 67u);
  free(v1);
  global_buf_401120 = a1[1];                    // 0x401120
  for ( i = 0; i < 697; ++i )
    serial[i % 67u] ^= global_buf_401120[i];
  t = serial[0];
  for ( j = 1; j < 66; t ^= serial[j - 2] ^ serial[j - 1] ^ serial[j - 3] ^ v6 )
  {
    v6 = serial[j + 1] ^ serial[j];
    j += 5;
  }
  v = t ^ serial[66];
  serial[66] ^= t;
  p_serial_ = serial;
  v9 = 66;
  do
  {
    *p_serial_++ ^= v;
    --v9;
  }
  while ( v9 );
  v10 = global_user[0];
  xor1 = 0;
  for ( k = global_user; *k; v10 = *k )
  {
    ++k;
    xor1 ^= v10;
  }
  global_buf_4010d0 = *a1;                      // 4010d0
  p_serial = serial;
  p_serial_index = &serial[2 * (xor1 & 0xF)];
  index = 2 * (xor1 & 0xF);
  if ( index >= 0 && p_serial_index != serial )
  {
    ii = index;
    p_buf_4010d0 = global_buf_4010d0;
    if ( (unsigned int)index < 4 )
    {
LABEL_13:
      if ( !ii )
        goto LABEL_22;
    }
    else
    {
      while ( *(_DWORD *)p_buf_4010d0 == *(_DWORD *)p_serial )
      {
        ii -= 4;
        p_serial += 4;
        p_buf_4010d0 += 4;
        if ( ii < 4 )
          goto LABEL_13;
      }
    }
    v18 = *p_buf_4010d0 - *p_serial;
    if ( !v18 )
    {
      if ( ii <= 1 )
        goto LABEL_22;
      v18 = p_buf_4010d0[1] - p_serial[1];
      if ( !v18 )
      {
        if ( ii <= 2 )
          goto LABEL_22;
        v18 = p_buf_4010d0[2] - p_serial[2];
        if ( !v18 )
        {
          if ( ii <= 3 )
            goto LABEL_22;
          v18 = p_buf_4010d0[3] - p_serial[3];
        }
      }
    }
    if ( (v18 >> 31) | 1 )
      return printf("fail.\n");
  }
LABEL_22:
  jj = 44 - index;
  if ( 44 - index > 0 )
  {
    v20 = &serial[index + 23];
    v21 = &global_buf_4010d0[index + 23];
    if ( jj < 4 )
    {
LABEL_26:
      if ( !jj )
        goto LABEL_35;
    }
    else
    {
      while ( *(_DWORD *)v21 == *(_DWORD *)v20 )
      {
        jj -= 4;
        v20 += 4;
        v21 += 4;
        if ( jj < 4 )
          goto LABEL_26;
      }
    }
    v22 = *v21 - *v20;
    if ( v22 )
      goto LABEL_34;
    if ( jj > 1 )
    {
      v22 = v21[1] - v20[1];
      if ( v22 )
        goto LABEL_34;
      if ( jj > 2 )
      {
        v22 = v21[2] - v20[2];
        if ( v22 )
          goto LABEL_34;
        if ( jj > 3 )
        {
          v22 = v21[3] - v20[3];
LABEL_34:
          if ( (v22 >> 31) | 1 )
            return printf("fail.\n");
        }
      }
    }
  }
LABEL_35:
  qmemcpy(&global_final, p_serial_index, 20u);
  v23 = p_serial_index + 20;
  *((_WORD *)&global_final + 10) = *((_WORD *)p_serial_index + 10);
  *((_BYTE *)&global_final + 22) = v23[2];
  global_buf_401120_ = a1[1];
  p_final = &global_final;
  i_ = 23;
  do
  {
    v27 = *p_final >> (8 - (*global_buf_401120_ & 7));
    v28 = *p_final++ << (*global_buf_401120_++ & 7);
    --i_;
    *(p_final - 1) = v28 | v27;
  }
  while ( i_ );
  v29 = 23;
  finalcheck = "KCTF-2024-CRACK-SUCCESS";
  final = &global_final;
  while ( *(_DWORD *)final == *(_DWORD *)finalcheck )
  {
    v29 -= 4;
    finalcheck += 4;
    final += 4;
    if ( v29 < 4 )
    {
      if ( *finalcheck == *final && finalcheck[1] == final[1] && finalcheck[2] == final[2] )
        return printf("***success***.\n");
      return printf("fail.\n");
    }
  }
  return printf("fail.\n");
}

对全局变量和一些局部变量做了重命名。该函数调用自_main,第一个参数是&off_403FD0,指向0x4010d0和0x401120两个值,也即_main函数和sub_401120函数的位置。
程序基于这两个函数代码所在内存做了大量运算,可能主要想坑软件断点调试(软件断点会修改断点处的字节为int3),不过此题逻辑非常简单,静态分析足够了。如果真的要调试,可以下硬件断点避免修改内存数据。
 
整理出来的检查逻辑和逆向的serial生成逻辑如下:

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
with open("decode.exe", "rb") as f:
    content = f.read()
 
global_buf_401120 = content[0x520:0x520+697]
global_buf_4010d0 = content[0x4d0:0x4d0+697]
 
 
def name_to_index(u):
    xor1 = 0
    for i in range(len(u)):
        xor1 ^= u[i]
    index = 2 * (xor1 & 0xf)
    return index
 
 
def change_bytes(b):
    r = bytearray(b)
    for i, c in enumerate(r):
        o = global_buf_401120[i] & 7
        r[i] = (c >> (8-o)) | ((c << o) & 0xff)
    return r
 
 
def rev_change_bytes(b):
    r = bytearray(b)
    for i, c in enumerate(r):
        o = global_buf_401120[i] & 7
        r[i] = (c << (8-o) & 0xff) | ((c >> o) & 0xff)
    return r
 
 
def xor_all(s):
    r = 0
    for c in s:
        r ^= c
    return r
 
 
def calc_final(name, serial):
    u = bytearray(name.encode())
    s = bytearray(bytes.fromhex(serial))
    for i in range(697):
        s[i % 67] ^= global_buf_401120[i]
    t = s[0]
    for i in range(1, 66, 5):
        t ^= s[i] ^ s[i+1] ^ s[i+2] ^ s[i+3] ^ s[i+4]
    v = t ^ s[66]
    v = xor_all(s)
    s[66] = v
    for i in range(66):
        s[i] ^= v
 
    index = name_to_index(u)
 
    part1 = s[:index]
    part2 = s[index+23:]
 
    assert part1 == global_buf_4010d0[:index], ()
    assert part2 == global_buf_4010d0[index+23:len(s)]
 
    b = bytearray(s[index:index+23])
    r = change_bytes(b)
 
    assert r == b"KCTF-2024-CRACK-SUCCESS"
 
 
def calc_serial(name):
    u = bytearray(name.encode())
    index = name_to_index(u)
 
    s = bytearray(global_buf_4010d0[:67])
    s[index:index+23] = rev_change_bytes(b'KCTF-2024-CRACK-SUCCESS')
 
    v = s[66]
    for i in range(66):
        s[i] ^= v
 
    s[66] ^= xor_all(s[:66])
 
    for i in range(697):
        s[i % 67] ^= global_buf_401120[i]
 
    return s.hex()
     
 
# calc_final("39881BA5569BBADD", "d287e2bb87cbda561717c90e61e7a78ec1e8e1e904a2ccf5558045a3f792aeebba09dadcb1f7f19b4d110f2a4121e0d1fd330ed9c21474e364a4e4d6b02c4644b1b580")
 
assert calc_serial("39881BA5569BBADD") == "d287e2bb87cbda561717c90e61e7a78ec1e8e1e904a2ccf5558045a3f792aeebba09dadcb1f7f19b4d110f2a4121e0d1fd330ed9c21474e364a4e4d6b02c4644b1b580"
print(calc_serial("KCTF"))  # d287e2bb87cbda561717c90e08eba2ad13cf09e4eb4428f36cf11cf83cea678dfa19e081bc5d66cdc17d1c2a4121e0d1fd330ed9c21474e364a4e4d6b02c4644b1b5cc

最终答案:
name: KCTF
serial: d287e2bb87cbda561717c90e08eba2ad13cf09e4eb4428f36cf11cf83cea678dfa19e081bc5d66cdc17d1c2a4121e0d1fd330ed9c21474e364a4e4d6b02c4644b1b5cc


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//