开头包装的一层调用可以手动清理出来,他调用了sub_4026D2
作为窗口回调,在WM_COMMAND
里面
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
|
v21
=
(
*
(
int
(__stdcall
*
*
)(
int
,
int
))(dword_4ABE44
+
92
))(a1,
1001
);
/
/
GetDlgItem
if
( v21 )
{
for
( i
=
0
; i <
0x100
;
+
+
i )
v7[i]
=
0
;
v42
=
(
*
(
int
(__stdcall
*
*
)(
int
))(v35
+
96
))(v21);
/
/
GetWindowTextLengthA
if
( v42 <
=
210
&& v42 >
=
1
)
{
(
*
(void (__stdcall
*
*
)(
int
, char
*
,
int
))(v35
+
100
))(v21, v7,
255
);
/
/
GetWindowTextA
v42
=
(
*
(
int
(__stdcall
*
*
)(char
*
))(v35
+
24
))(v7);
/
/
lstrlenA
if
( v42 >
=
1
&& v42 <
=
128
)
{
for
( j
=
v42; j <
128
;
+
+
j )
{
if
( j
%
2
)
v7[j]
=
0x20
;
else
v7[j]
=
0x7F
;
}
v34
=
1
;
}
else
{
v34
=
0
;
}
}
else
{
v34
=
0
;
}
}
else
{
v34
=
0
;
}
if
( v34 )
{
v43
=
dword_4ABE44;
if
( (
*
(
int
(__stdcall
*
*
)(_DWORD, char
*
,
int
))(dword_4ABE44
+
56
))(
0
, v5,
255
) )
{
strcpy(v27,
"h"
);
v27[
2
]
=
0
;
v27[
3
]
=
0
;
v27[
4
]
=
0
;
v27[
5
]
=
0xB8
;
v27[
6
]
=
0
;
v27[
7
]
=
0
;
v27[
8
]
=
0
;
v27[
9
]
=
0
;
v27[
10
]
=
0xFF
;
v27[
11
]
=
0xD0
;
Eax
=
0
;
v31
=
0
;
v8[
17
]
=
0xFFFFFFFF
;
for
( k
=
0
; k <
0x44
;
+
+
k )
*
((_BYTE
*
)v8
+
k)
=
0
;
v8[
0
]
=
68
;
for
( m
=
0
; m <
0x10
;
+
+
m )
*
((_BYTE
*
)&v37
+
m)
=
0
;
if
( (
*
(
int
(__stdcall
*
*
)(char
*
, _DWORD, _DWORD, _DWORD, _DWORD,
int
, _DWORD, _DWORD,
int
*
,
int
*
))(v43
+
28
))(
/
/
CreateProcessW
v5,
0
,
0
,
0
,
0
,
4
,
0
,
0
,
v8,
&v37) )
{
v6.ContextFlags
=
0x10007
;
if
( !(
*
(
int
(__stdcall
*
*
)(
int
, CONTEXT
*
))(v43
+
32
))(v38, &v6) )
/
/
GetThreadContext
goto LABEL_69;
Eax
=
v6.Eax;
v31
=
(
*
(
int
(__stdcall
*
*
)(
int
, _DWORD,
int
,
int
,
int
))(v43
+
44
))(v37,
0
,
128
,
4096
,
4
);
if
( !v31 )
goto LABEL_69;
for
( n
=
0
; n <
0x80
; n
+
=
v17 )
{
v17
=
0
;
if
( !(
*
(
int
(__stdcall
*
*
)(
int
, unsigned
int
, char
*
, unsigned
int
,
int
*
))(v43
+
0x30
))(
/
/
WriteProcessMemory
v37,
n
+
v31,
&v7[n],
128
-
n,
&v17) )
{
v16
=
0
;
goto LABEL_45;
}
}
v16
=
1
;
if
( !v16 )
goto LABEL_69;
LABEL_45:
v20
=
(PIMAGE_DOS_HEADER)(
*
(
int
(__stdcall
*
*
)(_DWORD))(v43
+
20
))(
0
);
/
/
GetModuleHandleW
v10
=
(
int
)v20
+
v20
-
>e_lfanew;
v9
=
Eax
-
*
(_DWORD
*
)(v10
+
40
);
v11
=
(char
*
)sub_401000
-
(char
*
)v20;
*
(_DWORD
*
)&v27[
1
]
=
v31;
*
(_DWORD
*
)&v27[
6
]
=
(char
*
)sub_401000
-
(char
*
)v20
+
v9;
for
( ii
=
0
; ii <
0xC
; ii
+
=
v15 )
{
v15
=
0
;
if
( !(
*
(
int
(__stdcall
*
*
)(
int
, unsigned
int
, char
*
, unsigned
int
,
int
*
))(v43
+
48
))(
v37,
ii
+
Eax,
&v27[ii],
12
-
ii,
&v15) )
{
v14
=
0
;
goto LABEL_52;
}
}
v14
=
1
;
LABEL_52:
if
( v14 )
{
(
*
(void (__stdcall
*
*
)(
int
))(v43
+
36
))(v38);
/
/
ResumeThread
v30
=
2
;
if
( (
*
(
int
(__stdcall
*
*
)(
int
,
int
))(v43
+
60
))(v37,
30000
) )
/
/
WaitForSingleObject
{
(
*
(void (__stdcall
*
*
)(
int
,
int
))(v43
+
64
))(v37,
2
);
/
/
TerminateProcess
}
else
{
v18
=
0
;
if
( (
*
(
int
(__stdcall
*
*
)(
int
,
int
*
))(v43
+
52
))(v37, &v18) && v18 !
=
2
)
/
/
GetExitCodeProcess
v30
=
v18;
}
|
会再执行一次crackme
,将入口点改为
1
2
3
|
push
input
mov eax,
0x401000
call eax
|
0x401000通过调用Decompress
函数,解压数据
类似格式是
1
2
3
4
|
struct CodeData{
uint32_t CodeSize;
uint8_t code[CodeSize];
};
|
在这里进行调用,v47
用于加密,v45
用于最后的验证
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
|
if
( v38 )
{
v90
=
0
;
v29[
0
]
=
5
;
v29[
1
]
=
0
;
v29[
2
]
=
4
;
v29[
3
]
=
3
;
v29[
4
]
=
2
;
v29[
5
]
=
1
;
for
( ii
=
0
; ii <
6
;
+
+
ii )
{
v32
=
v29[ii];
v92
=
0
;
v47
=
0
;
for
( jj
=
0
; jj <
=
v32;
+
+
jj )
{
v47
=
(
int
(__stdcall
*
)(_DWORD, _DWORD, _DWORD, _DWORD))(v108[
30
]
+
v92
+
4
);
v46
=
*
(_DWORD
*
)(v108[
30
]
+
v92);
v92
+
=
v46
+
4
;
}
v90
=
v47;
if
( !v47(
*
v108, v108[
1
], v108[
2
], a1) )
goto LABEL_134;
}
v56
=
1
;
v91
=
0
;
v45
=
0
;
for
( kk
=
0
; kk <
=
6
;
+
+
kk )
{
v45
=
(
int
(__stdcall
*
)(_DWORD, _DWORD, _DWORD, _DWORD))(v108[
30
]
+
v91
+
4
);
v48
=
*
(_DWORD
*
)(v108[
30
]
+
v91);
v91
+
=
v48
+
4
;
}
v90
=
v45;
if
( !v45(
*
v108, v108[
1
], v108[
2
], a1) )
v56
=
0
;
}
|
通过强制F5了几个函数发现,对应输入只进行了基于字节的异或加密、交换、查表,修改其中一个字节,只会对加密结果产生一个字节的影响。
这些代码花式调用了大量API
,拖慢了计算速度,同时也有反调试。
其实根据附带的题目描述我感觉是叫你硬看,但我就偏要硬爆
将最后一个函数F5
找到比对逻辑,将其导出。
将原始文件patch 入口点,push 0x402d4c call 0x401000
后 跟一个int3
,然后nop
掉0x04026C8
的ExitProcess
,到达int3
后读取和重写flag的值,然后更改Eip
为入口点进行下次爆破。
需要用到ScyllaHide
,爆的时候执行一下InjectorCLIx86.exe sb.exe HookLibraryx86.dll nowait
加载一下反反调试,配置文件选Themida x86/x64
。
预计时间是(128 + 94) * 10 / 60 = 37
分钟,
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
|
#include <windows.h>
#include <TlHelp32.h>
#include <stdint.h>
#include <stdio.h>
char trueflag[
0x81
]
=
{
0
};
/
/
char flag[
0x81
]
=
{
0x3a
,
0x2a
,
0x44
,
0x23
,
0x4f
,
0x2b
,
0x5f
,
0x49
,
0x33
,
0x3b
,
0x60
,
0x7d
,
0x30
,
0x4e
,
0x66
,
0x50
,
/
/
0x2d
,
0x3d
,
0x32
,
0x2f
,
0x2b
,
0x59
,
0x22
,
0x5f
,
0x3e
,
0x41
,
0x38
,
0x53
,
0x36
,
0x5d
,
0x4c
,
0x7c
,
/
/
0x34
,
0x47
,
0x3b
,
0x55
,
0x48
,
0x69
,
0x41
,
0x35
,
0x6d
,
0x6e
,
0x6f
,
0x6c
,
0x5e
,
0x6b
,
0x3b
,
0x23
,
/
/
0x4f
,
0x68
,
0x57
,
0x32
,
0x21
,
0x55
,
0x45
,
0x4a
,
0x66
,
0x30
,
0x22
,
0x37
,
0x3f
,
0x44
,
0x74
,
0x35
,
/
/
0x6d
,
0x7b
,
0x43
,
0x71
,
0x45
,
0x2a
,
0x41
,
0x5a
,
0x72
,
0x7e
,
0x24
,
0x31
,
0x28
,
0x7a
,
0x57
,
0x40
,
/
/
0x54
,
0x42
,
0x58
,
0x4b
,
0x4c
,
0x26
,
0x32
,
0x72
,
0x3f
,
0x2b
,
0x33
,
0x6b
,
0x77
,
0x78
,
0x43
,
0x39
,
/
/
0x30
,
0x4f
,
0x27
,
0x25
,
0x26
,
0x50
,
0x79
,
0x56
,
0x6f
,
0x7e
,
0x29
,
0x27
,
0x51
,
0x25
,
0x5a
,
0x40
,
/
/
0x36
,
0x62
,
0x7d
,
0x52
,
0x45
,
0x4b
,
0x46
,
0x5b
,
0x63
,
0x67
,
0x46
,
0x65
,
0x2f
,
0x2d
,
0x3f
,
0x49
};
char flag[
0x81
]
=
{
0
};
int
flagcount
=
0
;
int
_current
=
0
;
uint8_t encrelative[
0x80
]
=
{
0
};
uint8_t enctable[
0x80
]
=
{
0
};
/
/
uint8_t enctable[
0x80
]
=
{
0x09
,
0x0a
,
0x07
,
0x08
,
0x05
,
0x06
,
0x03
,
0x04
,
0x01
,
0x02
,
0x40
,
0x00
,
0x42
,
0x41
,
0x44
,
0x43
,
/
/
0x46
,
0x45
,
0x48
,
0x47
,
0x4a
,
0x49
,
0x4c
,
0x4b
,
0x4e
,
0x4d
,
0x50
,
0x4f
,
0x52
,
0x51
,
0x54
,
0x53
,
/
/
0x56
,
0x55
,
0x58
,
0x57
,
0x5a
,
0x59
,
0x5c
,
0x5b
,
0x5e
,
0x5d
,
0x60
,
0x5f
,
0x62
,
0x61
,
0x64
,
0x63
,
/
/
0x66
,
0x65
,
0x68
,
0x67
,
0x6a
,
0x69
,
0x6c
,
0x6b
,
0x6e
,
0x6d
,
0x70
,
0x6f
,
0x72
,
0x71
,
0x74
,
0x73
,
/
/
0x76
,
0x75
,
0x78
,
0x77
,
0x7a
,
0x79
,
0x7c
,
0x7b
,
0x7e
,
0x7d
,
0x3f
,
0x7f
,
0x3d
,
0x3e
,
0x3b
,
0x3c
,
/
/
0x39
,
0x3a
,
0x37
,
0x38
,
0x35
,
0x36
,
0x33
,
0x34
,
0x31
,
0x32
,
0x2f
,
0x30
,
0x2d
,
0x2e
,
0x2b
,
0x2c
,
/
/
0x29
,
0x2a
,
0x27
,
0x28
,
0x25
,
0x26
,
0x23
,
0x24
,
0x21
,
0x22
,
0x1f
,
0x20
,
0x1d
,
0x1e
,
0x1b
,
0x1c
,
/
/
0x19
,
0x1a
,
0x17
,
0x18
,
0x15
,
0x16
,
0x13
,
0x14
,
0x11
,
0x12
,
0x0f
,
0x10
,
0x0d
,
0x0e
,
0x0b
,
0x0c
};
int
stage
=
1
;
int
guess
=
33
;
uint8_t enc[
0x80
]
=
{
121
,
23
,
66
,
107
,
59
,
80
,
122
,
227
,
70
,
208
,
222
,
78
,
36
,
167
,
138
,
106
,
105
,
208
,
2
,
6
,
240
,
39
,
36
,
189
,
192
,
187
,
227
,
30
,
9
,
163
,
151
,
48
,
60
,
182
,
235
,
104
,
144
,
9
,
208
,
234
,
17
,
242
,
196
,
96
,
165
,
203
,
195
,
252
,
69
,
251
,
92
,
83
,
192
,
128
,
58
,
153
,
89
,
111
,
47
,
84
,
74
,
217
,
14
,
106
,
52
,
222
,
210
,
236
,
175
,
74
,
11
,
164
,
138
,
182
,
250
,
147
,
31
,
4
,
16
,
68
,
238
,
228
,
214
,
158
,
244
,
69
,
18
,
77
,
55
,
60
,
240
,
17
,
248
,
200
,
68
,
118
,
99
,
16
,
115
,
45
,
104
,
215
,
157
,
47
,
195
,
132
,
42
,
182
,
204
,
181
,
55
,
97
,
79
,
15
,
22
,
188
,
187
,
140
,
83
,
39
,
238
,
119
,
170
,
31
,
156
,
194
,
24
,
222
};
uint8_t tmp[
0x80
]
=
{
0
};
int
main(void) {
STARTUPINFOA si
=
{ sizeof(si) };
PROCESS_INFORMATION pi
=
{ sizeof(pi) };
DWORD ret
=
CreateProcessA(
"D:/Users/CShi/Desktop/sb.exe"
, "", NULL, NULL, FALSE, DEBUG_PROCESS | CREATE_SUSPENDED, NULL, NULL, &si, &pi);
DWORD __sb
=
0
;
uint8_t original
=
0
;
uint8_t int3
=
0xcc
;
ReadProcessMemory(pi.hProcess,
0x004041B5
, &original,
1
, &__sb);
WriteProcessMemory(pi.hProcess,
0x004041B5
, &int3,
1
, &__sb);
ResumeThread(pi.hThread);
DEBUG_EVENT de
=
{
0
};
CONTEXT ThreadContext
=
{
0
};
ThreadContext.ContextFlags
=
0x10007
;
while
(
1
){
WaitForDebugEvent(&de, INFINITE);
if
(de.dwDebugEventCode
=
=
EXCEPTION_DEBUG_EVENT){
if
(de.u.Exception.ExceptionRecord.ExceptionCode
=
=
0x80000003
){
if
(de.u.Exception.ExceptionRecord.ExceptionAddress
=
=
(LPVOID)
0x004041B5
){
puts(
"InjectorCLIx86.exe sb.exe HookLibraryx86.dll nowait"
);
system(
"pause"
);
WriteProcessMemory(pi.hProcess,
0x4041b5
, &original,
1
, &__sb);
HANDLE hThread
=
OpenThread(THREAD_ALL_ACCESS, FALSE, de.dwThreadId);
GetThreadContext(hThread, &ThreadContext);
WriteProcessMemory(pi.hProcess,
0x402d4c
, &flag,
0x80
, &__sb);
ThreadContext.Eip
=
0x4041b5
;
SetThreadContext(hThread, &ThreadContext);
CloseHandle(hThread);
}
else
if
(de.u.Exception.ExceptionRecord.ExceptionAddress
=
=
(LPVOID)
0x04041BF
){
if
(stage
=
=
1
){
if
(encrelative[
0
]
=
=
0
){
ReadProcessMemory(pi.hProcess,
0x402d4c
, &encrelative,
0x80
, &__sb);
}
else
{
ReadProcessMemory(pi.hProcess,
0x402d4c
, &tmp,
0x80
, &__sb);
for
(
int
i
=
0
;i<
0x80
;i
+
+
){
if
(tmp[i] !
=
encrelative[i]){
enctable[_current
-
1
]
=
i;
break
;
}
}
}
memset(flag,
0
, sizeof(flag));
if
(_current
=
=
0x81
) {
memset(flag,
0
, sizeof(flag));
stage
=
2
;
_current
=
0
;
flag[_current]
=
guess;
}
else
{
flag[_current]
=
1
;
_current
+
=
1
;
}
puts(
"enctable debug:"
);
for
(
int
i
=
0
; i <
128
; i
+
+
) {
printf(
"0x%02x,"
, enctable[i]);
if
(i
%
16
=
=
15
) {
puts("");
}
}
}
else
{
ReadProcessMemory(pi.hProcess,
0x402d4c
, &tmp,
0x80
, &__sb);
for
(
int
i
=
0
;i<
0x80
;i
+
+
){
if
(tmp[i]
=
=
enc[i]) {
for
(
int
j
=
0
; j <
0x80
; j
+
+
) {
if
(enctable[j]
=
=
i){
printf(
"%x: %c OK!\n"
, j, flag[j]);
flagcount
+
=
1
;
trueflag[j]
=
flag[j];
if
(flagcount
=
=
0x80
) {
printf(
"%s\n"
, trueflag);
system(
"pause"
);
}
break
;
}
}
}
}
puts("");
memset(flag, guess,
128
);
guess
+
=
1
;
printf(
"%x: %c current\n"
, _current, flag[_current]);
puts(
"flag debug:"
);
for
(
int
i
=
0
; i <
128
; i
+
+
) {
printf(
"0x%02x,"
, trueflag[i]);
if
(i
%
16
=
=
15
) {
puts("");
}
}
if
(guess
=
=
128
) {
puts(
"No Solve!"
);
}
}
HANDLE hThread
=
OpenThread(THREAD_ALL_ACCESS, FALSE, de.dwThreadId);
GetThreadContext(hThread, &ThreadContext);
WriteProcessMemory(pi.hProcess,
0x402d4c
, &flag,
0x80
, &__sb);
ThreadContext.Eip
=
0x4041b5
;
SetThreadContext(hThread, &ThreadContext);
CloseHandle(hThread);
}
}
ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
}
else
{
ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
}
}
}
|
更多【KCTF2022秋季赛 第八题 商贸往来 题解】相关视频教程:www.yxfzedu.com