首页
论坛
课程
招聘
[原创]KCTF2020秋季赛 第七题 鱼目混珠
2020-12-5 00:36 3233

[原创]KCTF2020秋季赛 第七题 鱼目混珠

2020-12-5 00:36
3233

程序有很多花指令,不过都有特征,写个OD脚本去掉就行。
去掉以后dump下来丢给IDA 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
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
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char *v3; // edx
  int v4; // ecx
  unsigned int v5; // eax
  char *v6; // edx
  int v7; // ecx
  unsigned int v8; // eax
  char *v9; // kr00_4
  int v10; // esi
  int v11; // ecx
  int v12; // edi
  int v13; // ebx
  int v14; // esi
  int v16; // edx
  unsigned int v17; // eax
  int v18; // edx
  unsigned int v19; // eax
  int v20; // edx
  unsigned int v21; // eax
  unsigned int v22; // eax
  int v23; // [esp+1Ch] [ebp-A0h]
  unsigned int v24; // [esp+20h] [ebp-9Ch]
  int v25; // [esp+24h] [ebp-98h]
  int v26; // [esp+28h] [ebp-94h]
  char v27; // [esp+2Ch] [ebp-90h]
  _DWORD antidebug[9]; // [esp+3Ch] [ebp-80h]
  int (*v29)(void); // [esp+60h] [ebp-5Ch]
  int (*v30)(void); // [esp+64h] [ebp-58h]
  _DWORD v31[2]; // [esp+68h] [ebp-54h] BYREF
  char v32[76]; // [esp+70h] [ebp-4Ch] BYREF
 
  sub_40CA20();
  antidebug[0] = sub_401700;                    // 一大堆反调试
  antidebug[1] = sub_401740;
  antidebug[2] = sub_4017B0;
  antidebug[3] = sub_401890;
  antidebug[4] = sub_4018F0;
  antidebug[5] = sub_401570;
  dword_4C5028 = 0;
  antidebug[6] = sub_401820;
  antidebug[7] = sub_401950;
  antidebug[8] = sub_401AB0;
  v29 = sub_402F20;
  v30 = sub_402F90;
  dword_4C5024 = 0;
  v31[0] = sub_401620;
  v3 = a104010010e4b4c;
  do
  {
    v4 = *(_DWORD *)v3;
    v3 += 4;
    v5 = ~v4 & (v4 - 16843009) & 0x80808080;
  }
  while ( !v5 );
  if ( (~v4 & (v4 - 16843009) & 0x8080) == 0 )
    v5 >>= 16;
  if ( (~v4 & (v4 - 16843009) & 0x8080) == 0 )
    v3 += 2;
  hexdecode((int *)&result, (int)a104010010e4b4c, (int)&v3[-__CFADD__((_BYTE)v5, (_BYTE)v5) - 0x4B9083]);// 解码两个大数 每字节的高位和低位互换
  v6 = a1e9705f8d92146;
  do
  {
    v7 = *(_DWORD *)v6;
    v6 += 4;
    v8 = ~v7 & (v7 - 16843009) & 0x80808080;
  }
  while ( !v8 );
  if ( (~v7 & (v7 - 16843009) & 0x8080) == 0 )
    v8 >>= 16;
  if ( (~v7 & (v7 - 16843009) & 0x8080) == 0 )
    v6 += 2;
  hexdecode((int *)&big_c2, (int)a1e9705f8d92146, (int)&v6[-__CFADD__((_BYTE)v8, (_BYTE)v8) - 4952147]);
  v23 = *(_DWORD *)&result.buf[8];
  v24 = *(_DWORD *)&result.buf[4];
  print(*(_DWORD *)&result.buf[12]);
  memset(v32, 0, 0x40u);
  scan((int)&dword_4BA660, v32);
  v9 = &v32[strlen(v32)];
  if ( (unsigned int)(v9 - v32 - 13) > 0x32 )
    goto LABEL_22;
  v10 = sub_4030E0(v32, 7);
  v12 = sub_4030E0((_BYTE *)v31 + v9 - v32 + 1, 7);
  v13 = 0;
  v26 = 0;
  v25 = 0;
  do
  {
    v27 = 15 - v13;
    if ( (v13 & 1) == ((int (__fastcall *)(int))antidebug[v13])(v11) )// 执行反调试
    {
      ++v25;
      v10 = v29() ^ __ROR4__(v10, v13);         // 两个crc防patch
      v12 = v30() ^ __ROR4__(v12, v27);
    }
    else
    {
      ++v26;
      v10 = v30() ^ __ROR4__(v10, v27);
      v12 = ((int (__fastcall *)(int))v29)(v13) ^ __ROR4__(v12, v13);
    }
    ++v13;
  }
  while ( v13 != 9 );
  if ( !v25 )
    goto LABEL_22;
  if ( !v26 )
    goto LABEL_22;
  v14 = dword_4B904C ^ v10;
  if ( v14 != v23 || (v12 ^ dword_4B9048) != v24 || hexdecode((int *)&input, (int)v32, strlen(v32)) < 0 )// 比较crc是否与预设值一样 动态调试时patch掉
    goto LABEL_22;
  big_r.buf[4] = 0;
  *(_DWORD *)big_r.buf = *(_DWORD *)result.buf;
  v16 = 4;
  while ( 1 )
  {
    v17 = v16 - 1;
    if ( big_r.buf[v16 - 1] )
      break;
    --v16;
    if ( !v17 )
      goto LABEL_29;
  }
  v17 = v16;
LABEL_29:
  big_r.len = v17;
  big_mul(&big_n, &input, &big_r);
  input.buf[4] = 0;
  *(_DWORD *)input.buf = 0xE053D0F;
  v18 = 4;
  while ( 1 )
  {
    v19 = v18 - 1;
    if ( input.buf[v18 - 1] )
      break;
    --v18;
    if ( !v19 )
      goto LABEL_32;
  }
  v19 = v18;
  input.len = v19;
  big_div(&big_n, &big_n, &input);              // *0xE053D0F
  big_add(&big_n, &big_n, &result);
  big_add(&big_n, &big_n, &big_c2);             // +0xfea1bd9e6964129d8f5079e1
  big_mul(&big_c, &result, &big_c2);
  big_sub(&big_r, &big_n, &big_c);              // -0x3f58d70f55459ad75491a4c3ea858c4961226c27f5a1f8a95b18fde1
  if ( (int)big_r.len > 16 )
    goto LABEL_22;
LABEL_32:
  big_mul(&big_n, &big_n, &input);              // *0xE053D0F
  input.buf[4] = 0;
  *(_DWORD *)input.buf = 37;
  v20 = 4;
  while ( 1 )
  {
    v21 = v20 - 1;
    if ( input.buf[v20 - 1] )
      break;
    --v20;
    if ( !v21 )
      goto LABEL_36;
  }
  v21 = v20;
LABEL_36:
  input.len = v21;
  big_mul(&big_c, &big_n, &input);              // *37
  big_add(&big_c, &big_c, &big_c);              // 此处溢出,最高位为1,刚好覆盖了result的长度
  v22 = big_r.len;
  if ( big_r.len == result.len )
  {
    while ( (--v22 & 0x80000000) == 0 )
    {
      if ( big_r.buf[v22] != result.buf[v22] )  // 表面上跟0x3faffa2b01b6ba9744c4b4e010010401比较 实际上是1
        goto LABEL_22;
    }
    print(v14);                                 // GOOD
  }
  else
  {
LABEL_22:
    print(v24);                                 // ERROR
  }
  return 0;
}

逻辑很清晰,除了最后那个溢出覆盖len比较坑了点
解开方程,再把结果按hexdecode的方法转回字符串就可以了

1
2
x * 0x10010401 / 0xE053D0F + 0x3faffa2b01b6ba9744c4b4e010010401 + 0xfea1bd9e6964129d8f5079e1 - 0x3f58d70f55459ad75491a4c3ea858c4961226c27f5a1f8a95b18fde1 == 1
x = 0x377EF3DC43F112E46ACF040E9077C8D23C530FB3654C9B33803F7C01

按hexdecode的方法转回字符串得到flag
10C7F30833B9C4563BF035C32D8C7709E040FCA64E211F34CD3FE773


第五届安全开发者峰会(SDC 2021)议题征集正式开启!

收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回