首页
社区
课程
招聘
3
看雪CTF.TSRC 2018 团队赛-第4题
发表于: 2018-12-8 08:28 4094

看雪CTF.TSRC 2018 团队赛-第4题

2018-12-8 08:28
4094

1. 检测调试器, 修改验证逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.text:00491010                 push    0
.text:00491012                 push    4
.text:00491014                 push    offset g_hDebugObject
.text:00491019                 push    1Eh             ; ProcessDebugObjectHandle
.text:0049101B                 call    ds:GetCurrentProcess
.text:00491021                 push    eax
.text:00491022                 call    ZwQueryInformationProcess
...
.text:0049104F                 cmp     g_hDebugObject, 0
.text:00491056                 jnz     short loc_49106A
.text:00491058                 call    $+5
.text:0049105D                 pop     eax
.text:0049105E                 sub     eax, 8F9A0h
.text:00491063                 mov     byte ptr [eax], 0EBh ; 004016BD
.text:00491066                 inc     eax
.text:00491067                 mov     byte ptr [eax], 0Dh
.text:0049106A                 mov     edi, 0BB40E64Eh
.text:0049106F                 retn
...
.text:004016BD                 jmp     short loc_4016CC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.text:00491010                 push    0
.text:00491012                 push    4
.text:00491014                 push    offset g_hDebugObject
.text:00491019                 push    1Eh             ; ProcessDebugObjectHandle
.text:0049101B                 call    ds:GetCurrentProcess
.text:00491021                 push    eax
.text:00491022                 call    ZwQueryInformationProcess
...
.text:0049104F                 cmp     g_hDebugObject, 0
.text:00491056                 jnz     short loc_49106A
.text:00491058                 call    $+5
.text:0049105D                 pop     eax
.text:0049105E                 sub     eax, 8F9A0h
.text:00491063                 mov     byte ptr [eax], 0EBh ; 004016BD
.text:00491066                 inc     eax
.text:00491067                 mov     byte ptr [eax], 0Dh
.text:0049106A                 mov     edi, 0BB40E64Eh
.text:0049106F                 retn
...
.text:004016BD                 jmp     short loc_4016CC

2. 验证函数及成功条件
sn(16进制)长度16, 记为DWORD sn[2];
sn经过00401C70计算后, 必须满足 sn[0]==87654321 && sn[1]==12345678
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
.text:0040146B                 mov     edx, [ebp+sz_sn]
.text:0040146E                 push    edx
.text:0040146F                 call    strlen
.text:00401474                 add     esp, 4
.text:00401477                 cmp     eax, 10h
.text:0040147A                 jz      short loc_401483
...
.text:00401671                 push    0DEADBEEFh      ; int
.text:00401676                 lea     eax, [ebp+var_104+0C0h]
.text:00401679                 push    eax             ; int
.text:0040167A                 push    0DA8A0600h      ; int
.text:0040167F                 push    172442D7h       ; int
.text:00401684                 push    4914B2B9h       ; int
.text:00401689                 push    7380166Fh       ; int
.text:0040168E                 push    10325476h       ; int
.text:00401693                 push    98BADCFEh       ; int
.text:00401698                 push    0EFCDAB89h      ; int
.text:0040169D                 push    67452301h       ; int
.text:004016A2                 mov     ecx, [ebp+key]
.text:004016A8                 push    ecx             ; int
.text:004016A9                 lea     edx, [ebp+sn]
.text:004016AF                 push    edx             ; int
.text:004016B0                 call    sub_401C70
...
.text:004016D9                 cmp     [ebp+ecx+sn], 87654321h
.text:004016E4                 jnz     short loc_401707
.text:004016E6                 mov     edx, 4
.text:004016EB                 shl     edx, 0
.text:004016EE                 cmp     [ebp+edx+sn], 12345678h
.text:004016F9                 jnz     short loc_401707
.text:004016FB                 mov     [ebp+ok], 1

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
.text:0040146B                 mov     edx, [ebp+sz_sn]
.text:0040146E                 push    edx
.text:0040146F                 call    strlen
.text:00401474                 add     esp, 4
.text:00401477                 cmp     eax, 10h
.text:0040147A                 jz      short loc_401483
...
.text:00401671                 push    0DEADBEEFh      ; int
.text:00401676                 lea     eax, [ebp+var_104+0C0h]
.text:00401679                 push    eax             ; int
.text:0040167A                 push    0DA8A0600h      ; int
.text:0040167F                 push    172442D7h       ; int
.text:00401684                 push    4914B2B9h       ; int
.text:00401689                 push    7380166Fh       ; int
.text:0040168E                 push    10325476h       ; int
.text:00401693                 push    98BADCFEh       ; int
.text:00401698                 push    0EFCDAB89h      ; int
.text:0040169D                 push    67452301h       ; int
.text:004016A2                 mov     ecx, [ebp+key]
.text:004016A8                 push    ecx             ; int
.text:004016A9                 lea     edx, [ebp+sn]
.text:004016AF                 push    edx             ; int
.text:004016B0                 call    sub_401C70
...
.text:004016D9                 cmp     [ebp+ecx+sn], 87654321h
.text:004016E4                 jnz     short loc_401707
.text:004016E6                 mov     edx, 4
.text:004016EB                 shl     edx, 0
.text:004016EE                 cmp     [ebp+edx+sn], 12345678h
.text:004016F9                 jnz     short loc_401707
.text:004016FB                 mov     [ebp+ok], 1

3. 00401C70这个函数中有很多垃圾代码, 先搜索特征码, 把里面的所有垃圾循环patch掉再trace
1
2
3
4
.text:00401DA4                 cmp     ebx, 0F204Ch
.text:00401DAA                 jb      short loc_401D87
.text:00401DAC                 call    $+5
.text:00401DB1                 pop     esi

1
2
3
4
.text:00401DA4                 cmp     ebx, 0F204Ch
.text:00401DAA                 jb      short loc_401D87
.text:00401DAC                 call    $+5
.text:00401DB1                 pop     esi

4. 写代码清理trace文件
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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
import re
 
 
def read_file(file_name):
    = open(file_name, 'r')
    lines = f.readlines()
    f.close()
    return lines
 
 
def write_file(file_name, lines):
    = open(file_name, 'w')
    f.writelines(lines)
    f.close()
    return
 
 
def has_substring(s, s_list):
    if isinstance(s_list, str):
        return s.find(s_list) != -1
    for in s_list:
        if s.find(v) != -1:
            return True
    return False
 
 
def has_consecutive_substring(lines, i, s_list):
    for in range(len(s_list)):
        if not has_substring(lines[i+k], s_list[k]):
            return False
    return True
 
 
def extract_imm_value(s):  # type:(str) -> int
    # reg, 0x12345678
    # -> return 12345678
    pat = ',0x'
    = s.find(pat) + len(pat)
    i_end = s.find(' ', i + 1)
    return int(s[i:i_end], 16)
 
 
def hex_with_sign(v):  # type:(int) -> str
    # 0x12345678 / 0xFFFFFFF8
    # -> return +0x12345678 / -0x8
    = ''
    if v >= 0x80000000:
        = 0x100000000 - v
        += '-'
    else:
        = '+'
    += hex(v)
    = s.replace('L', '')
    return s
 
 
def hex_without_sign(v):  # type:(int) -> str
    # 0x12345678
    # -> return 0x12345678
    = ''
    += hex(v)
    = s.replace('L', '')
    return s
 
 
def evaluate_ss_edi_expr(s, edi):  # type:(str,int) -> str
    # 1. xxx reg,dword ptr ss:[ebp+edi]
    # 2. xxx reg,dword ptr ss:[ebp+edi+0x4BF7590F]
    # 3. xxx reg,dword ptr ss:[ebp+edi*2+0xDB8A93CE]
    # -> xxx reg,dword ptr ss:[ebp+imm]
    if s.find('[ebp+edi+') != -1:
        = re.search('\\[ebp\\+edi\\+0x(.*)\\]', s).group(1)
        = int(v, 16)
        edi += v
    elif s.find('[ebp+edi*') != -1:
        = re.search('\\[ebp\\+edi\\*([^+]+)\\+0x(.*)\\]', s)
        v1 = int(m.group(1), 16)
        v2 = int(m.group(2), 16)
        edi = edi * v1 + v2
    elif s.find('[ebp+edi]'== -1:
        raise Exception('')
    edi %= 0x100000000
    = '[ebp%s]' % hex_with_sign(edi)
    = re.sub('\\[.*\\]', v, s)
    return s
 
 
def pass_nops(lines):
    new_lines = []
    = 0
    while i < len(lines):
        line = lines[i]
 
        if has_substring(line, ['test''cld''cmp''nop''cmc''bt''clc''stc']):
            += 1
            continue
 
        # or exx,0x0
        if re.search('or e..,0x0', line) is not None:
            += 1
            continue
 
        # and exx,0xFFFFFFFF
        if re.search('and e..,0xFFFFFFFF', line) is not None:
            += 1
            continue
 
        line = line.replace('transfor.''0x')
        new_lines.append(line)
        += 1
    return new_lines
 
 
def pass_edi(lines):
    # mov edi,0x
    # add edi,0x
    # ...
    # xxx reg,edi
    # -> xxx reg, imm
    new_lines = []
    = 0
    while i < len(lines):
        line = lines[i]
 
        if has_substring(line, 'mov edi,0x'):
            = 0
            while has_substring(lines[i + + 1], ['sub edi''add edi']):
                += 1
            if k > 0:
                if has_substring(lines[i + + 1], ',edi'):
                    edi = 0
                    for in range(i, i + + 1):
                        = extract_imm_value(lines[z])
                        if has_substring(lines[z], 'sub'):
                            edi -= v
                        else:
                            edi += v
                    edi %= 0x100000000
                    line = lines[i + + 1].replace(',edi '',%s' % hex_without_sign(edi))
                    new_lines.append(line)
                    += + 2
                    continue
        new_lines.append(line)
        += 1
    return new_lines
 
 
def pass_ebp(lines):
    # mov edi,0x
    # add edi,0x
    # ...
    # xxx reg, [ebp+edixxx]
    # -> xxx reg, imm
    new_lines = []
    = 0
    while i < len(lines):
        line = lines[i]
 
        if has_substring(line, 'mov edi,0x'):
            = 0
            while has_substring(lines[i + + 1], ['sub edi''add edi']):
                += 1
            if k > 0:
                if has_substring(lines[i + + 1], 'ebp+edi'):
                    edi = 0
                    for in range(i, i + + 1):
                        = extract_imm_value(lines[z])
                        if has_substring(lines[z], 'sub'):
                            edi -= v
                        else:
                            edi += v
                    edi %= 0x100000000
                    line = evaluate_ss_edi_expr(lines[i + + 1], edi)
                    new_lines.append(line)
                    += + 2
                    continue
        new_lines.append(line)
        += 1
    return new_lines
 
 
def pass_simplify_same_op(lines, op_name, reg_name):
    # xxx reg, imm1
    # xxx reg, imm2
    # ...
    # -> xxx reg, imm
    new_lines = []
    = 0
    while i < len(lines):
        line = lines[i]
        pat = '%s %s,0x' % (op_name, reg_name)
        if has_substring(line, pat):
            = 0
            while has_substring(lines[i + + 1], pat):
                += 1
            if k > 0:
                = 0
                for in range(i, i + + 1):
                    += extract_imm_value(lines[z])
                %= 0x100000000
                if op_name.startswith('ro'):
                    # ror/rol
                    %= 32
                if v != 0:
                    new_lines.append('00000000  %s %s,%s\n' % (op_name, reg_name, hex_without_sign(v)))
                += + 1
                continue
 
        new_lines.append(line)
        += 1
    return new_lines
 
 
def pass_simplify_same_op_all(lines):
    lines = pass_simplify_same_op(lines, 'add''esi')
    lines = pass_simplify_same_op(lines, 'sub''esi')
    lines = pass_simplify_same_op(lines, 'add''edi')
    lines = pass_simplify_same_op(lines, 'sub''edi')
    lines = pass_simplify_same_op(lines, 'add''eax')
    lines = pass_simplify_same_op(lines, 'sub''eax')
    lines = pass_simplify_same_op(lines, 'ror''eax')
    lines = pass_simplify_same_op(lines, 'add''ebx')
    lines = pass_simplify_same_op(lines, 'sub''ebx')
    lines = pass_simplify_same_op(lines, 'ror''ebx')
    lines = pass_simplify_same_op(lines, 'add''ecx')
    lines = pass_simplify_same_op(lines, 'sub''ecx')
    lines = pass_simplify_same_op(lines, 'ror''ecx')
    lines = pass_simplify_same_op(lines, 'add''edx')
    lines = pass_simplify_same_op(lines, 'sub''edx')
    lines = pass_simplify_same_op(lines, 'ror''edx')
    lines = pass_simplify_same_op(lines, 'ror''esp')
    return lines
 
 
def pass_push_pop_eax_ebx_ecx(lines):
    # push eax
    # push ebx
    # push ecx
    # ...
    # pop ecx
    # pop ebx
    # pop eax
    # -> removed
    new_lines = []
    = 0
    while i < len(lines):
        line = lines[i]
        if has_consecutive_substring(lines, i, ['push eax''push ebx''push ecx']):
            = 3
            while not has_consecutive_substring(lines, i+k, ['pop ecx''pop ebx''pop eax']):
                += 1
            += + 3
            continue
        new_lines.append(line)
        += 1
    return new_lines
 
 
def pass_rol_to_ror(lines, reg_name):
    # rol xxx,0x -> ror xxx,0x
    new_lines = []
    pat = 'rol %s,0x' % reg_name
    = 0
    while i < len(lines):
        line = lines[i]
        if has_substring(line, 'rol %s,1' % reg_name):
            new_lines.append('00000000  %s %s,%s\n' % ('ror', reg_name, hex_without_sign(31)))
            += 1
            continue
        if has_substring(line, 'ror %s,1' % reg_name):
            new_lines.append('00000000  %s %s,%s\n' % ('ror', reg_name, hex_without_sign(1)))
            += 1
            continue
        if has_substring(line, pat):
            = extract_imm_value(line)
            %= 32
            = 32 - v
            new_lines.append('00000000  %s %s,%s\n' % ('ror', reg_name, hex_without_sign(v)))
            += 1
            continue
 
        new_lines.append(line)
        += 1
    return new_lines
 
 
def pass_rol_to_ror_all(lines):
    lines = pass_rol_to_ror(lines, 'eax')
    lines = pass_rol_to_ror(lines, 'ebx')
    lines = pass_rol_to_ror(lines, 'ecx')
    lines = pass_rol_to_ror(lines, 'edx')
    lines = pass_rol_to_ror(lines, 'esp')
    return lines
 
 
def pass_unused_before_reassign(lines, reg_name):
    # sub ecx, eax (-> removed)
    # ...
    # mov ecx, edx
    new_lines = []
    pat1 = ' %s,' % reg_name
    = 0
    while i < len(lines):
        line = lines[i]
        if has_substring(line, pat1):
            = 0
            unused = False
            while (i + + 1) < len(lines):
                # if it is used/unused, break immediately
                if has_substring(lines[i + + 1], ',%s,' % reg_name):
                    # imul xxx,reg,0x0
                    break
                dot = lines[i + + 1].find(',')
                if dot == -1:
                    if not has_substring(lines[i + + 1], '%s' % reg_name):
                        # push xxx
                        += 1
                        continue
                    break
                if lines[i + + 1].find(reg_name, dot) != -1:
                    # mov xxx, reg / mov xxx, [reg]
                    break
                if lines[i + + 1].find('['0, dot) != -1 and lines[i + + 1].find(reg_name, 0, dot) != -1:
                    # mov [xxx+ecx], xxx
                    break
                if has_substring(lines[i + + 1], 'mov %s,' % reg_name):
                    unused = True
                    break
                += 1
            # if (i + k + 1) >= len(lines):
            #     unused = True
            if unused:
                += 1
                continue
        new_lines.append(line)
        += 1
    return new_lines
 
 
def pass_unused_before_reassign_all(lines):
    lines = pass_unused_before_reassign(lines, 'ecx')
    lines = pass_unused_before_reassign(lines, 'edx')
    lines = pass_unused_before_reassign(lines, 'eax')
    lines = pass_unused_before_reassign(lines, 'ebx')
    lines = pass_unused_before_reassign(lines, 'edi')
    return lines
 
 
def pass_ror_to_shift(lines, reg_name):
    # ror edx,0x8
    # and edx,0xFFFFFF
    # -> shr edx, 8
 
    # ror ecx,0x1c
    # and ecx,0xFFFFFFF0
    # -> shl ecx,0x4
    new_lines = []
    = 0
    while i < len(lines):
        line = lines[i]
        if has_substring(line, 'ror %s,0x' % reg_name):
            if has_substring(lines[i+1], 'and %s,0x' % reg_name):
                shift = extract_imm_value(line)
                mask = extract_imm_value(lines[i + 1])
                rmask = (1 << (32 - shift)) - 1
                lmask = 0xFFFFFFFF - ((1 << (32 - shift)) - 1)
                if rmask == mask:
                    line = '00000000  shr %s,%s\n' % (reg_name, hex_without_sign(shift))
                    new_lines.append(line)
                    += 2
                    continue
                elif lmask == mask:
                    line = '00000000  shl %s,%s\n' % (reg_name, hex_without_sign(32 - shift))
                    new_lines.append(line)
                    += 2
                    continue
        new_lines.append(line)
        += 1
    return new_lines
 
 
def pass_ror_to_shift_all(lines):
    lines = pass_ror_to_shift(lines, 'eax')
    lines = pass_ror_to_shift(lines, 'ebx')
    lines = pass_ror_to_shift(lines, 'ecx')
    lines = pass_ror_to_shift(lines, 'edx')
    return lines
 
 
def test():
    lines = read_file('trace.txt')
    lines = pass_nops(lines)
    lines = pass_rol_to_ror_all(lines)
    lines = pass_edi(lines)
    lines = pass_ebp(lines)
    lines = pass_simplify_same_op_all(lines)
    lines = pass_push_pop_eax_ebx_ecx(lines)
    lines = pass_simplify_same_op_all(lines)
    lines = pass_rol_to_ror_all(lines)
    lines = pass_simplify_same_op_all(lines)
    lines = pass_push_pop_eax_ebx_ecx(lines)
    lines = pass_ebp(lines)
    lines = pass_edi(lines)
    lines = pass_simplify_same_op_all(lines)
    lines = pass_simplify_same_op_all(lines)
    for in range(5):
        lines = pass_unused_before_reassign_all(lines)
    lines = pass_ror_to_shift_all(lines)
    write_file('trace_new.txt', lines)
    return
 
 
test()


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

最后于 2018-12-20 09:18 被风间仁编辑 ,原因:
收藏
免费 3
支持
分享
赞赏记录
参与人
雪币
留言
时间
PLEBFE
为你点赞~
2022-7-27 22:37
Editor
为你点赞~
2018-12-24 15:50
anhkgg
为你点赞~
2018-12-11 22:57
最新回复 (7)
雪    币: 3140
活跃值: (5883)
能力值: ( LV9,RANK:225 )
在线值:
发帖
回帖
粉丝
2
2018-12-9 12:15
0
雪    币: 19
活跃值: (128)
能力值: ( LV9,RANK:146 )
在线值:
发帖
回帖
粉丝
3
2018-12-9 12:42
0
雪    币: 1470
活跃值: (74)
能力值: ( LV5,RANK:75 )
在线值:
发帖
回帖
粉丝
4
2018-12-9 15:12
0
雪    币: 1617
活跃值: (4742)
能力值: ( LV5,RANK:69 )
在线值:
发帖
回帖
粉丝
5
2018-12-9 16:56
0
雪    币: 4870
活跃值: (53)
能力值: ( LV5,RANK:78 )
在线值:
发帖
回帖
粉丝
6
2018-12-9 16:58
0
雪    币: 2473
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
大佬终于上线了
2018-12-9 17:41
0
雪    币: 2473
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
我估计大佬一直在线的 前几题因为太简单了  大佬不屑做!!!
2018-12-9 17:42
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

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