首页
社区
课程
招聘
1
[原创]看雪.纽盾 KCTF晋级赛2019 Q2 第四题 达芬奇密码
发表于: 2019-6-18 16:01 3546

[原创]看雪.纽盾 KCTF晋级赛2019 Q2 第四题 达芬奇密码

2019-6-18 16:01
3546

运行程序,随便输入点什么,信息框提示“Wrong!”,在MessageBoxW下断点,回溯就能定位到点击事件了。

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
int __thiscall click(CWnd *this)
{
  CWnd *v1; // esi
  int v2; // eax
  WCHAR String; // [esp+Ch] [ebp-310h]
  char v5; // [esp+Eh] [ebp-30Eh]
  char input; // [esp+20Ch] [ebp-110h]
  char v7; // [esp+20Dh] [ebp-10Fh]
  DWORD v8; // [esp+30Ch] [ebp-10h]
  CWnd *v9; // [esp+310h] [ebp-Ch]
  int v10; // [esp+314h] [ebp-8h]
  DWORD flOldProtect; // [esp+318h] [ebp-4h]
 
  v1 = this;
  v9 = this;
  String = 0;
  memset(&v5, 0, 0x1FEu);
  input = 0;
  memset(&v7, 0, 0xFFu);
  CWnd::GetDlgItemTextW(v1, 1000, &String, 20);
  if ( wcslen(&String) == 16 )                  // key的长度为16
  {
    v2 = 0;
    while ( !(*(&String + v2) & 0xFF00) )       // unicode转ascii
    {
      *(&input + v2) = *((_BYTE *)&String + 2 * v2);
      if ( ++v2 >= 16 )
      {
        v8 = 64;
        flOldProtect = 0;
        VirtualProtect(check, 0xD17u, 0x40u, &flOldProtect);
        if ( GetLastError() )
          return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
        qmemcpy(check, byte_11C47B8, 0x330u);   // 修改check函数
        VirtualProtect(check, 0xD17u, flOldProtect, &v8);
        if ( !GetLastError() )
        {
          v10 = 0;
          v10 = check(&input);                  // 调用
          if ( v10 == 1 )
            return CWnd::MessageBoxW(v9, L"Congratulations! You are right!", 0, 0);
        }
        v1 = v9;
        return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
      }
    }
  }
  return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
}
代码调用的是修改后的check函数,我们可以动态调试,在执行过qmemcpy后,把修改后的check函数复制到文件中,方便IDA分析。真正的check函数如下
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
int __thiscall click(CWnd *this)
{
  CWnd *v1; // esi
  int v2; // eax
  WCHAR String; // [esp+Ch] [ebp-310h]
  char v5; // [esp+Eh] [ebp-30Eh]
  char input; // [esp+20Ch] [ebp-110h]
  char v7; // [esp+20Dh] [ebp-10Fh]
  DWORD v8; // [esp+30Ch] [ebp-10h]
  CWnd *v9; // [esp+310h] [ebp-Ch]
  int v10; // [esp+314h] [ebp-8h]
  DWORD flOldProtect; // [esp+318h] [ebp-4h]
 
  v1 = this;
  v9 = this;
  String = 0;
  memset(&v5, 0, 0x1FEu);
  input = 0;
  memset(&v7, 0, 0xFFu);
  CWnd::GetDlgItemTextW(v1, 1000, &String, 20);
  if ( wcslen(&String) == 16 )                  // key的长度为16
  {
    v2 = 0;
    while ( !(*(&String + v2) & 0xFF00) )       // unicode转ascii
    {
      *(&input + v2) = *((_BYTE *)&String + 2 * v2);
      if ( ++v2 >= 16 )
      {
        v8 = 64;
        flOldProtect = 0;
        VirtualProtect(check, 0xD17u, 0x40u, &flOldProtect);
        if ( GetLastError() )
          return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
        qmemcpy(check, byte_11C47B8, 0x330u);   // 修改check函数
        VirtualProtect(check, 0xD17u, flOldProtect, &v8);
        if ( !GetLastError() )
        {
          v10 = 0;
          v10 = check(&input);                  // 调用
          if ( v10 == 1 )
            return CWnd::MessageBoxW(v9, L"Congratulations! You are right!", 0, 0);
        }
        v1 = v9;
        return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
      }
    }
  }
  return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
}
代码调用的是修改后的check函数,我们可以动态调试,在执行过qmemcpy后,把修改后的check函数复制到文件中,方便IDA分析。真正的check函数如下
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
signed int __cdecl check(char *input)
{
  signed int v1; // eax
  char v2; // cl
  signed int v3; // ecx
  signed int v4; // eax
  signed int v5; // eax
  signed int v6; // esi
  signed int v7; // ecx
  __int16 v8; // dx
  char *mul; // edi
  __int16 v10; // ax
  signed int v11; // eax
  signed int v12; // ecx
  unsigned __int16 v13; // bx
  signed int v14; // esi
  signed int v15; // ecx
  __int16 v16; // dx
  char *v17; // edi
  __int16 v18; // ax
  signed int v19; // eax
  signed int v20; // ecx
  unsigned __int16 v21; // bx
  unsigned int v22; // eax
  signed int v23; // ecx
  unsigned __int16 v24; // dx
  char v25; // dl
  signed int v26; // eax
  __int16 v27; // si
  int v28; // eax
  int true// [esp+8h] [ebp-90h]
  int v31; // [esp+Ch] [ebp-8Ch]
  int v32; // [esp+10h] [ebp-88h]
  int v33; // [esp+14h] [ebp-84h]
  int v34; // [esp+18h] [ebp-80h]
  int v35; // [esp+1Ch] [ebp-7Ch]
  int v36; // [esp+20h] [ebp-78h]
  int v37; // [esp+24h] [ebp-74h]
  int calc1; // [esp+28h] [ebp-70h]
  int calc2; // [esp+2Ch] [ebp-6Ch]
  int v40; // [esp+30h] [ebp-68h]
  int v41; // [esp+34h] [ebp-64h]
  int other; // [esp+38h] [ebp-60h]
  int v43; // [esp+3Ch] [ebp-5Ch]
  int re1; // [esp+40h] [ebp-58h]
  int re2; // [esp+44h] [ebp-54h]
  int broad2; // [esp+48h] [ebp-50h]
  int v47; // [esp+4Ch] [ebp-4Ch]
  int v48; // [esp+50h] [ebp-48h]
  int v49; // [esp+54h] [ebp-44h]
  char v50; // [esp+58h] [ebp-40h]
  int result; // [esp+5Ch] [ebp-3Ch]
  int v52; // [esp+60h] [ebp-38h]
  int v53; // [esp+64h] [ebp-34h]
  int v54; // [esp+68h] [ebp-30h]
  char v55; // [esp+6Ch] [ebp-2Ch]
  int broad1; // [esp+70h] [ebp-28h]
  int v57; // [esp+74h] [ebp-24h]
  int v58; // [esp+78h] [ebp-20h]
  int v59; // [esp+7Ch] [ebp-1Ch]
  char v60; // [esp+80h] [ebp-18h]
  int v61; // [esp+84h] [ebp-14h]
  int v62; // [esp+88h] [ebp-10h]
  int v63; // [esp+8Ch] [ebp-Ch]
  int v64; // [esp+90h] [ebp-8h]
  char v65; // [esp+94h] [ebp-4h]
 
  v31 = 0x646E9881;
  v1 = 0;
  true = 0xE38C9616;
  v32 = 0x81DC0884;
  v33 = 0x4F484DBE;
  v34 = 0;
  v35 = 0;
  v36 = 0;
  v37 = 0;
  calc1 = 0;
  calc2 = 0;
  re1 = 0;
  re2 = 0;
  do
  {
    v2 = *((_BYTE *)&v32 + v1) ^ input[v1 + 8];
    *((_BYTE *)&calc1 + v1) = *((_BYTE *)&true + v1) ^ *((_BYTE *)&true + v1 + input - (char *)&true);
    *((_BYTE *)&re1 + v1++) = v2;
  }
  while ( v1 < 8 );                             // 异或解密两个long long数字
  true = 0;
  broad1 = 0;
  v57 = 0;
  v58 = 0;
  v59 = 0;
  v60 = 0;
  v61 = 0;
  v62 = 0;
  v63 = 0;
  v64 = 0;
  v65 = 0;
  broad2 = 0;
  v47 = 0;
  v48 = 0;
  v49 = 0;
  v50 = 0;
  result = 0;
  v52 = 0;
  v53 = 0;
  v54 = 0;
  v55 = 0;
  v31 = 0;
  v32 = 0;
  v33 = 0;
  LOBYTE(v34) = 0;
  v3 = 8;
  LOBYTE(true) = 8;
  v4 = 7;
  do
  {
    if ( *((_BYTE *)&calc1 + v4) )              // 最后一位char不为0,即第一个数字要>0x00FFFFFFFFFFFFFF
      break;
    --v3;
    --v4;
  }
  while ( v4 >= 0 );
  if ( v3 == 8 )
  {
    v5 = 7;
    do
    {
      if ( *((_BYTE *)&re1 + v5) )              // 同上
        break;
      --v3;
      --v5;
    }
    while ( v5 >= 0 );
    if ( v3 == 8 && !(calc2 & 0xF0000000) )     // calc2不得大于0x0fffffff,即第一个数字要<0x0FFFFFFFFFFFFFFF
    {
      v6 = 0;
      do
      {
        v40 = 0;
        v41 = 0;
        other = 0;
        v43 = 0;
        v7 = 0;
        v8 = *((unsigned __int8 *)&calc1 + v6);
        mul = (char *)&v40 + v6;
        do
        {                                       // 每位key乘以key,等价于求平方
          v10 = *((unsigned __int8 *)&other + v6) + v8 * *((unsigned __int8 *)&calc1 + v7);
          mul[v7] = *((_BYTE *)&other + v6) + v8 * *((_BYTE *)&calc1 + v7);
          ++v7;
          *((_BYTE *)&other + v6) = HIBYTE(v10);
        }
        while ( v7 < 8 );
        LOBYTE(v11) = 0;
        v12 = 0;
        do
        {
          v13 = (char)v11 + *((unsigned __int8 *)&broad1 + v12 + v6) + (unsigned __int8)mul[v12];
          *((_BYTE *)&broad1 + v12++ + v6) = v13;
          v11 = (signed int)v13 >> 8;
        }
        while ( v12 < 9 );
        ++v6;
      }
      while ( v6 < 8 );
      v14 = 0;
      do                                        // 跟上面一模一样
      {
        v40 = 0;
        v41 = 0;
        other = 0;
        v43 = 0;
        v15 = 0;
        v16 = *((unsigned __int8 *)&re1 + v14);
        v17 = (char *)&v40 + v14;
        do
        {
          v18 = *((unsigned __int8 *)&other + v14) + v16 * *((unsigned __int8 *)&re1 + v15);
          v17[v15] = *((_BYTE *)&other + v14) + v16 * *((_BYTE *)&re1 + v15);
          ++v15;
          *((_BYTE *)&other + v14) = HIBYTE(v18);
        }
        while ( v15 < 8 );
        LOBYTE(v19) = 0;
        v20 = 0;
        do
        {
          v21 = (char)v19 + *((unsigned __int8 *)&v61 + v20 + v14) + (unsigned __int8)v17[v20];
          *((_BYTE *)&v61 + v20++ + v14) = v21;
          v19 = (signed int)v21 >> 8;
        }
        while ( v20 < 9 );
        ++v14;
      }
      while ( v14 < 8 );
      LOBYTE(v22) = v50;
      v23 = 0;
      do
      {
        v24 = (unsigned __int8)v22 + 7 * *((unsigned __int8 *)&v61 + v23);// 第二个数字计算平方后乘以7
        *((_BYTE *)&broad2 + v23++) = v24;
        v22 = (unsigned int)v24 >> 8;
      }
      while ( v23 < 17 );
      v50 = HIBYTE(v24);
      v25 = 0;
      v26 = 0;
      do
      {
        v27 = *((unsigned __int8 *)&broad1 + v26) - *((unsigned __int8 *)&broad2 + v26) - v25;// 两个结果相减
        *((_BYTE *)&result + v26) = v27;
        if ( v27 < 0 )
          v25 = 1;
        ++v26;
      }
      while ( v26 < 17 );
      if ( !v25 )
      {
        v28 = 0;
        while ( *((_BYTE *)&result + v28) == *((_BYTE *)&true + v28) )// 对比结果是否等于8
        {
          if ( ++v28 >= 17 )
            return 1;
        }
      }
    }
  }
  return 0;
}
我们设解密出来的第一个数字为x,第二个为y,结合代码可以得到一道方程
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
signed int __cdecl check(char *input)
{
  signed int v1; // eax
  char v2; // cl
  signed int v3; // ecx
  signed int v4; // eax
  signed int v5; // eax
  signed int v6; // esi
  signed int v7; // ecx
  __int16 v8; // dx
  char *mul; // edi
  __int16 v10; // ax
  signed int v11; // eax
  signed int v12; // ecx
  unsigned __int16 v13; // bx
  signed int v14; // esi
  signed int v15; // ecx
  __int16 v16; // dx
  char *v17; // edi
  __int16 v18; // ax
  signed int v19; // eax
  signed int v20; // ecx
  unsigned __int16 v21; // bx
  unsigned int v22; // eax
  signed int v23; // ecx
  unsigned __int16 v24; // dx
  char v25; // dl
  signed int v26; // eax
  __int16 v27; // si
  int v28; // eax
  int true// [esp+8h] [ebp-90h]
  int v31; // [esp+Ch] [ebp-8Ch]
  int v32; // [esp+10h] [ebp-88h]
  int v33; // [esp+14h] [ebp-84h]
  int v34; // [esp+18h] [ebp-80h]
  int v35; // [esp+1Ch] [ebp-7Ch]
  int v36; // [esp+20h] [ebp-78h]
  int v37; // [esp+24h] [ebp-74h]
  int calc1; // [esp+28h] [ebp-70h]
  int calc2; // [esp+2Ch] [ebp-6Ch]
  int v40; // [esp+30h] [ebp-68h]
  int v41; // [esp+34h] [ebp-64h]
  int other; // [esp+38h] [ebp-60h]
  int v43; // [esp+3Ch] [ebp-5Ch]
  int re1; // [esp+40h] [ebp-58h]
  int re2; // [esp+44h] [ebp-54h]
  int broad2; // [esp+48h] [ebp-50h]
  int v47; // [esp+4Ch] [ebp-4Ch]
  int v48; // [esp+50h] [ebp-48h]
  int v49; // [esp+54h] [ebp-44h]
  char v50; // [esp+58h] [ebp-40h]
  int result; // [esp+5Ch] [ebp-3Ch]
  int v52; // [esp+60h] [ebp-38h]
  int v53; // [esp+64h] [ebp-34h]
  int v54; // [esp+68h] [ebp-30h]
  char v55; // [esp+6Ch] [ebp-2Ch]
  int broad1; // [esp+70h] [ebp-28h]
  int v57; // [esp+74h] [ebp-24h]
  int v58; // [esp+78h] [ebp-20h]
  int v59; // [esp+7Ch] [ebp-1Ch]
  char v60; // [esp+80h] [ebp-18h]
  int v61; // [esp+84h] [ebp-14h]
  int v62; // [esp+88h] [ebp-10h]
  int v63; // [esp+8Ch] [ebp-Ch]
  int v64; // [esp+90h] [ebp-8h]
  char v65; // [esp+94h] [ebp-4h]
 
  v31 = 0x646E9881;
  v1 = 0;
  true = 0xE38C9616;
  v32 = 0x81DC0884;
  v33 = 0x4F484DBE;
  v34 = 0;
  v35 = 0;
  v36 = 0;
  v37 = 0;
  calc1 = 0;
  calc2 = 0;
  re1 = 0;
  re2 = 0;
  do
  {
    v2 = *((_BYTE *)&v32 + v1) ^ input[v1 + 8];
    *((_BYTE *)&calc1 + v1) = *((_BYTE *)&true + v1) ^ *((_BYTE *)&true + v1 + input - (char *)&true);
    *((_BYTE *)&re1 + v1++) = v2;
  }
  while ( v1 < 8 );                             // 异或解密两个long long数字
  true = 0;
  broad1 = 0;
  v57 = 0;
  v58 = 0;
  v59 = 0;
  v60 = 0;
  v61 = 0;
  v62 = 0;
  v63 = 0;
  v64 = 0;
  v65 = 0;
  broad2 = 0;
  v47 = 0;
  v48 = 0;
  v49 = 0;
  v50 = 0;
  result = 0;
  v52 = 0;
  v53 = 0;
  v54 = 0;
  v55 = 0;
  v31 = 0;
  v32 = 0;
  v33 = 0;
  LOBYTE(v34) = 0;
  v3 = 8;
  LOBYTE(true) = 8;
  v4 = 7;
  do
  {
    if ( *((_BYTE *)&calc1 + v4) )              // 最后一位char不为0,即第一个数字要>0x00FFFFFFFFFFFFFF
      break;
    --v3;
    --v4;
  }
  while ( v4 >= 0 );
  if ( v3 == 8 )
  {
    v5 = 7;
    do
    {
      if ( *((_BYTE *)&re1 + v5) )              // 同上
        break;
      --v3;
      --v5;
    }
    while ( v5 >= 0 );
    if ( v3 == 8 && !(calc2 & 0xF0000000) )     // calc2不得大于0x0fffffff,即第一个数字要<0x0FFFFFFFFFFFFFFF
    {
      v6 = 0;
      do
      {
        v40 = 0;
        v41 = 0;
        other = 0;
        v43 = 0;
        v7 = 0;
        v8 = *((unsigned __int8 *)&calc1 + v6);
        mul = (char *)&v40 + v6;
        do
        {                                       // 每位key乘以key,等价于求平方
          v10 = *((unsigned __int8 *)&other + v6) + v8 * *((unsigned __int8 *)&calc1 + v7);
          mul[v7] = *((_BYTE *)&other + v6) + v8 * *((_BYTE *)&calc1 + v7);
          ++v7;
          *((_BYTE *)&other + v6) = HIBYTE(v10);
        }
        while ( v7 < 8 );
        LOBYTE(v11) = 0;
        v12 = 0;
        do
        {
          v13 = (char)v11 + *((unsigned __int8 *)&broad1 + v12 + v6) + (unsigned __int8)mul[v12];
          *((_BYTE *)&broad1 + v12++ + v6) = v13;
          v11 = (signed int)v13 >> 8;
        }
        while ( v12 < 9 );
        ++v6;
      }
      while ( v6 < 8 );
      v14 = 0;
      do                                        // 跟上面一模一样
      {
        v40 = 0;
        v41 = 0;
        other = 0;
        v43 = 0;
        v15 = 0;
        v16 = *((unsigned __int8 *)&re1 + v14);
        v17 = (char *)&v40 + v14;
        do
        {
          v18 = *((unsigned __int8 *)&other + v14) + v16 * *((unsigned __int8 *)&re1 + v15);
          v17[v15] = *((_BYTE *)&other + v14) + v16 * *((_BYTE *)&re1 + v15);
          ++v15;
          *((_BYTE *)&other + v14) = HIBYTE(v18);
        }
        while ( v15 < 8 );
        LOBYTE(v19) = 0;
        v20 = 0;
        do
        {
          v21 = (char)v19 + *((unsigned __int8 *)&v61 + v20 + v14) + (unsigned __int8)v17[v20];
          *((_BYTE *)&v61 + v20++ + v14) = v21;
          v19 = (signed int)v21 >> 8;
        }
        while ( v20 < 9 );
        ++v14;
      }
      while ( v14 < 8 );
      LOBYTE(v22) = v50;
      v23 = 0;
      do
      {
        v24 = (unsigned __int8)v22 + 7 * *((unsigned __int8 *)&v61 + v23);// 第二个数字计算平方后乘以7
        *((_BYTE *)&broad2 + v23++) = v24;
        v22 = (unsigned int)v24 >> 8;
      }
      while ( v23 < 17 );
      v50 = HIBYTE(v24);
      v25 = 0;
      v26 = 0;
      do
      {
        v27 = *((unsigned __int8 *)&broad1 + v26) - *((unsigned __int8 *)&broad2 + v26) - v25;// 两个结果相减
        *((_BYTE *)&result + v26) = v27;
        if ( v27 < 0 )
          v25 = 1;
        ++v26;
      }
      while ( v26 < 17 );
      if ( !v25 )
      {
        v28 = 0;
        while ( *((_BYTE *)&result + v28) == *((_BYTE *)&true + v28) )// 对比结果是否等于8
        {
          if ( ++v28 >= 17 )
            return 1;
        }
      }
    }
  }
  return 0;
}
我们设解密出来的第一个数字为x,第二个为y,结合代码可以得到一道方程
x*x-7*y*y=8 (x>0x00FFFFFFFFFFFFFF)
这是非标准佩尔方程,解法参考维基百科

我们可以算出方程的初始解为(6,2),接下来的可以写代码解决,具体代码如下

[注意]看雪招聘,专注安全领域的专业人才平台!

收藏
免费 1
支持
分享
赞赏记录
参与人
雪币
留言
时间
PLEBFE
为你点赞~
2023-1-25 03:29
最新回复 (0)
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册