【茶余饭后-逆向分析 160个CrackMe之052】此文章归类为:茶余饭后。
#逆向分析 160个CrackMe 052
闲来无事,工作上有调整,等待来年安排,日常的学习还是不能松懈,好久没搞2进制了,最近正在刷pwn和CrackMe,看到了一个160集合感觉不错,刷了几周了,做了20多个了吧,也不知道哪个好,随便搞了下,感觉这5星级的还是挺有意思的,故分析发文。
环境:win10 x64 chs
工具:x64dbg IDA BinaryNinja
编译器:gcc
那些在xp上好有用的工具都不太兼容win10,魔改版的LoadPE + ImportREC 修复的exe时灵时不灵的。
还好x64dbg仅有的一个插件解决了这个问题。
x64dbg + esp定律找到OEP,使用x64dbg自带的Scylla,三下五除二搞定。
第一种办法就是 IDA根据导入表MessageBox函数,交叉引用找到算法。
第二种就是通过OD或者x64dbg动态调试,弹出对话框后,暂停进程,调用栈回溯,也能找到算法函数。
这里我就不过多赘述。
直接拖入IDA,通过导入表MessageBoxA的交叉引用找到4处引用,2个函数。
第一个函数是MFC封装的MsgBox函数,根据它的交叉引用很快找到了数据处理和比较的地方。
封装的MsgBox
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
int
__thiscall sub_4100A8(_DWORD *
this
,
LPCSTR
lpText,
LPCSTR
lpCaption,
UINT
uType)
{
const
CHAR
*v4;
// eax
HWND
v6;
// ecx
v4 = lpCaption;
if
( !lpCaption )
v4 = (
const
CHAR
*)*((_DWORD *)AfxGetModuleState() + 4);
if
(
this
)
v6 = (
HWND
)
this
[7];
else
v6 = 0;
return
MessageBoxA(v6, lpText, v4, uType);
}
|
根据MsgBox交叉引用,找到处理函数
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
|
UPX0:
00401C20
sub esp,
608h
UPX0:
00401C26
push ebx
UPX0:
00401C27
push ebp
UPX0:
00401C28
push esi
UPX0:
00401C29
mov ebp, ecx
UPX0:
00401C2B
push edi
UPX0:
00401C2C
mov ecx,
7Dh
;
'}'
UPX0:
00401C31
xor eax, eax
UPX0:
00401C33
lea edi, [esp
+
3Ch
]
UPX0:
00401C37
rep stosd
UPX0:
00401C39
mov ecx,
7Dh
;
'}'
UPX0:
00401C3E
lea edi, [esp
+
424h
]
UPX0:
00401C45
rep stosd
UPX0:
00401C47
mov ecx,
7Dh
;
'}'
UPX0:
00401C4C
lea edi, [esp
+
230h
]
UPX0:
00401C53
rep stosd
UPX0:
00401C55
lea eax, [esp
+
3Ch
]
UPX0:
00401C59
push
64h
;
'd'
UPX0:
00401C5B
push eax
UPX0:
00401C5C
lea ecx, [ebp
+
5Ch
]
UPX0:
00401C5F
call MfcGetText ; 获取Name的字符串 name
=
esp
+
3c
UPX0:
00401C64
lea ecx, [esp
+
424h
]
UPX0:
00401C6B
push
64h
;
'd'
UPX0:
00401C6D
push ecx
UPX0:
00401C6E
lea ecx, [ebp
+
0ACh
]
UPX0:
00401C74
call MfcGetText ; 获取Code的字符串存在 esp
+
0x424
UPX0:
00401C79
lea edi, [esp
+
3Ch
]
UPX0:
00401C7D
or
ecx,
0FFFFFFFFh
UPX0:
00401C80
xor eax, eax
UPX0:
00401C82
lea edx, [esp
+
230h
]
UPX0:
00401C89
repne scasb
UPX0:
00401C8B
not
ecx ; 求name长度
UPX0:
00401C8D
sub edi, ecx
UPX0:
00401C8F
mov eax, ecx
UPX0:
00401C91
mov esi, edi
UPX0:
00401C93
mov edi, edx
UPX0:
00401C95
shr ecx,
2
UPX0:
00401C98
rep movsd ; name复制到esp
+
230h
UPX0:
00401C9A
mov ecx, eax
UPX0:
00401C9C
and
ecx,
3
UPX0:
00401C9F
rep movsb
UPX0:
00401CA1
lea ecx, [esp
+
230h
]
UPX0:
00401CA8
push ecx
UPX0:
00401CA9
call __strrev ; 将name反转
UPX0:
00401CAE
lea edi, [esp
+
234h
]
UPX0:
00401CB5
or
ecx,
0FFFFFFFFh
UPX0:
00401CB8
xor eax, eax
UPX0:
00401CBA
add esp,
4
UPX0:
00401CBD
repne scasb
UPX0:
00401CBF
not
ecx ; 求反转后长度
UPX0:
00401CC1
sub edi, ecx
UPX0:
00401CC3
lea edx, [esp
+
3Ch
]
UPX0:
00401CC7
mov esi, edi
UPX0:
00401CC9
mov ebx, ecx
UPX0:
00401CCB
mov edi, edx
UPX0:
00401CCD
or
ecx,
0FFFFFFFFh
UPX0:
00401CD0
repne scasb
UPX0:
00401CD2
mov ecx, ebx
UPX0:
00401CD4
dec edi
UPX0:
00401CD5
shr ecx,
2
UPX0:
00401CD8
rep movsd ; strcat(name,strrev(name))
UPX0:
00401CDA
mov ecx, ebx
UPX0:
00401CDC
lea eax, [esp
+
18h
]
UPX0:
00401CE0
and
ecx,
3
UPX0:
00401CE3
push eax
UPX0:
00401CE4
push offset aSoftwareMicros ;
"SOFTWARE\\Microsoft\\Windows\\CurrentVe"
...
UPX0:
00401CE9
push
80000002h
UPX0:
00401CEE
rep movsb
UPX0:
00401CF0
call ds:RegOpenKeyA ; 打开注册表
UPX0:
00401CF6
mov ebx, ds:RegQueryValueExA ; 查询ProductID
UPX0:
00401CFC
lea ecx, [esp
+
14h
]
UPX0:
00401D00
lea edx, [esp
+
230h
]
UPX0:
00401D07
push ecx
UPX0:
00401D08
mov ecx, [esp
+
1Ch
]
UPX0:
00401D0C
lea eax, [esp
+
14h
]
UPX0:
00401D10
push edx
UPX0:
00401D11
push eax
UPX0:
00401D12
push
0
UPX0:
00401D14
push offset aProductid ;
"ProductID"
UPX0:
00401D19
mov dword ptr [esp
+
24h
],
1
UPX0:
00401D21
mov dword ptr [esp
+
28h
],
100h
UPX0:
00401D29
push ecx
UPX0:
00401D2A
call ebx ; RegQueryValueExA ; 查询ProductID
UPX0:
00401D2C
lea edi, [esp
+
230h
]
UPX0:
00401D33
or
ecx,
0FFFFFFFFh
UPX0:
00401D36
xor eax, eax
UPX0:
00401D38
lea edx, [esp
+
3Ch
]
UPX0:
00401D3C
repne scasb
UPX0:
00401D3E
not
ecx
UPX0:
00401D40
sub edi, ecx
UPX0:
00401D42
mov dword ptr [esp
+
10h
],
1
UPX0:
00401D4A
mov esi, edi
UPX0:
00401D4C
mov edi, edx
UPX0:
00401D4E
mov edx, ecx
UPX0:
00401D50
or
ecx,
0FFFFFFFFh
UPX0:
00401D53
repne scasb
UPX0:
00401D55
mov ecx, edx
UPX0:
00401D57
dec edi
UPX0:
00401D58
shr ecx,
2
UPX0:
00401D5B
rep movsd ; 将查询的字符串strcat到name
UPX0:
00401D5D
mov ecx, edx
UPX0:
00401D5F
lea eax, [esp
+
14h
]
UPX0:
00401D63
and
ecx,
3
UPX0:
00401D66
push eax
UPX0:
00401D67
mov eax, [esp
+
1Ch
]
UPX0:
00401D6B
lea edx, [esp
+
14h
]
UPX0:
00401D6F
rep movsb
UPX0:
00401D71
lea ecx, [esp
+
234h
]
UPX0:
00401D78
mov dword ptr [esp
+
18h
],
100h
UPX0:
00401D80
push ecx
UPX0:
00401D81
push edx
UPX0:
00401D82
push
0
UPX0:
00401D84
push offset aRegisteredowne ;
"RegisteredOwner"
UPX0:
00401D89
push eax
UPX0:
00401D8A
call ebx ; RegQueryValueExA ; 查询RegisteredOwner
UPX0:
00401D8C
lea edi, [esp
+
230h
]
UPX0:
00401D93
or
ecx,
0FFFFFFFFh
UPX0:
00401D96
xor eax, eax
UPX0:
00401D98
lea edx, [esp
+
3Ch
]
UPX0:
00401D9C
repne scasb
UPX0:
00401D9E
not
ecx ; 求注册表查询字符串长度
UPX0:
00401DA0
sub edi, ecx
UPX0:
00401DA2
mov esi, edi
UPX0:
00401DA4
mov ebx, ecx
UPX0:
00401DA6
mov edi, edx
UPX0:
00401DA8
or
ecx,
0FFFFFFFFh
UPX0:
00401DAB
repne scasb
UPX0:
00401DAD
mov ecx, ebx
UPX0:
00401DAF
dec edi
UPX0:
00401DB0
shr ecx,
2
UPX0:
00401DB3
rep movsd
UPX0:
00401DB5
mov ecx, ebx
UPX0:
00401DB7
and
ecx,
3
UPX0:
00401DBA
rep movsb ; 将查询的字符串strcat到name
UPX0:
00401DBC
lea edi, [esp
+
3Ch
] ; 由于win10缺少这几个注册表项,其得到的name
=
name
+
strrev(name)
+
strrev(name)
+
strrev(name)
UPX0:
00401DC0
or
ecx,
0FFFFFFFFh
; 如果xp下应该是 name
+
strrev(name)
+
ProducID(查询得到字符串)
+
RegisterOwner(查询的字符串)
UPX0:
00401DC3
repne scasb
UPX0:
00401DC5
not
ecx ; 求组合后的长度
UPX0:
00401DC7
lea eax, [esp
+
2Ch
]
UPX0:
00401DCB
dec ecx
UPX0:
00401DCC
push eax
UPX0:
00401DCD
mov esi, ecx
UPX0:
00401DCF
call Md5InitState ; 初始化md5的
4
个state
UPX0:
00401DD4
lea edx, [esp
+
esi
+
40h
]
UPX0:
00401DD8
mov ecx,
13h
UPX0:
00401DDD
xor eax, eax
UPX0:
00401DDF
mov edi, edx
UPX0:
00401DE1
rep stosd ; 清空name后面
19
*
4
字节
UPX0:
00401DE3
add esp,
4
UPX0:
00401DE6
inc esi
UPX0:
00401DE7
stosw
UPX0:
00401DE9
mov ecx, esi
UPX0:
00401DEB
stosb
UPX0:
00401DEC
and
ecx,
3Fh
; 对齐数据
64
UPX0:
00401DEF
mov eax,
40h
;
'@'
; 对齐数据
64
UPX0:
00401DF4
sub eax, ecx ; 对齐数据
64
UPX0:
00401DF6
mov byte ptr [edx],
80h
;
'€'
; name最后结尾赋值
0x80
UPX0:
00401DF9
cmp
eax,
7
; 对齐数据
64
UPX0:
00401DFC
jg short loc_401E01
UPX0:
00401DFE
add eax,
40h
;
'@'
; 对齐数据
64
UPX0:
00401E01
UPX0:
00401E01
loc_401E01: ; CODE XREF: UPX0:
00401DFC
↑j
UPX0:
00401E01
add esi, eax
UPX0:
00401E03
lea edi, [esp
+
3Ch
]
UPX0:
00401E07
or
ecx,
0FFFFFFFFh
UPX0:
00401E0A
xor eax, eax
UPX0:
00401E0C
repne scasb
UPX0:
00401E0E
not
ecx
UPX0:
00401E10
dec ecx
UPX0:
00401E11
xor edi, edi
UPX0:
00401E13
shl ecx,
3
; 长度
*
8
UPX0:
00401E16
test esi, esi
UPX0:
00401E18
mov [esp
+
esi
+
34h
], ecx ; 添加长度数据
UPX0:
00401E1C
jle short loc_401E37
UPX0:
00401E1E
UPX0:
00401E1E
loc_401E1E: ; CODE XREF: UPX0:
00401E35
↓j
UPX0:
00401E1E
lea edx, [esp
+
2Ch
]
UPX0:
00401E22
lea eax, [esp
+
edi
+
3Ch
]
UPX0:
00401E26
push edx
UPX0:
00401E27
push eax
UPX0:
00401E28
call Md5Transform ; md5Transform
UPX0:
00401E2D
add edi,
40h
;
'@'
; 递增
64
字节
UPX0:
00401E30
add esp,
8
UPX0:
00401E33
cmp
edi, esi
UPX0:
00401E35
jl short loc_401E1E ;
for
(i
=
0
;i < esi(对齐长度);i
+
=
64
)
UPX0:
00401E37
UPX0:
00401E37
loc_401E37: ; CODE XREF: UPX0:
00401E1C
↑j
UPX0:
00401E37
mov ebx, [esp
+
2Ch
]
UPX0:
00401E3B
lea ecx, [esp
+
28h
]
UPX0:
00401E3F
lea edx, [esp
+
24h
]
UPX0:
00401E43
push ecx
UPX0:
00401E44
lea eax, [esp
+
24h
]
UPX0:
00401E48
push edx
UPX0:
00401E49
lea ecx, [esp
+
24h
]
UPX0:
00401E4D
push eax
UPX0:
00401E4E
push ecx
UPX0:
00401E4F
lea edx, [esp
+
434h
]
UPX0:
00401E56
and
ebx,
0FFFFh
; 将state[
0
]的高位抹去
UPX0:
00401E5C
push offset aLxLxLxLx ;
"%lx%lx%lx%lx"
UPX0:
00401E61
push edx
UPX0:
00401E62
mov [esp
+
44h
], ebx
UPX0:
00401E66
call _sscanf ; 从code字符串中获取
4
个UINT数据
UPX0:
00401E6B
add esp,
18h
UPX0:
00401E6E
cmp
eax,
4
; 不够
4
个就报错
UPX0:
00401E71
jz short loc_401E91
UPX0:
00401E73
push
30h
;
'0'
UPX0:
00401E75
push offset aFailed ;
"Failed"
UPX0:
00401E7A
push offset aHmmmYouDonTEve ;
"... Hmmm, you don't even pass the first"
...
UPX0:
00401E7F
mov ecx, ebp
UPX0:
00401E81
call MfcMsgBox
UPX0:
00401E86
pop edi
UPX0:
00401E87
pop esi
UPX0:
00401E88
pop ebp
UPX0:
00401E89
pop ebx
UPX0:
00401E8A
add esp,
608h
UPX0:
00401E90
retn
UPX0:
00401E91
;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
UPX0:
00401E91
UPX0:
00401E91
loc_401E91: ; CODE XREF: UPX0:
00401E71
↑j
UPX0:
00401E91
xor esi, esi
UPX0:
00401E93
lea edi, [esp
+
1Ch
]
UPX0:
00401E97
UPX0:
00401E97
loc_401E97: ; CODE XREF: UPX0:
00401EB3
↓j
UPX0:
00401E97
mov eax,
0BADC0DEh
;
for
(i
=
0
;i <
3
;i
+
+
)
UPX0:
00401E9C
lea ecx, [esi
+
50h
]
UPX0:
00401E9F
cdq
UPX0:
00401EA0
idiv ecx ; loop_cnt
=
0xbadc0de
/
(i
+
80
)
UPX0:
00401EA2
push eax
UPX0:
00401EA3
push edi
UPX0:
00401EA4
call Encode ; 算法关键:将
4
个UINT做
3
轮ENcode
UPX0:
00401EA9
add esp,
8
UPX0:
00401EAC
inc esi
UPX0:
00401EAD
add edi,
4
UPX0:
00401EB0
cmp
esi,
3
UPX0:
00401EB3
jl short loc_401E97 ;
for
(i
=
0
;i <
3
;i
+
+
)
UPX0:
00401EB5
xor eax, eax
UPX0:
00401EB7
UPX0:
00401EB7
loc_401EB7: ; CODE XREF: UPX0:
00401EC9
↓j
UPX0:
00401EB7
mov edx, [esp
+
eax
+
1Ch
]
UPX0:
00401EBB
mov ecx, [esp
+
eax
+
2Ch
]
UPX0:
00401EBF
cmp
edx, ecx
UPX0:
00401EC1
jnz short loc_401EE9
UPX0:
00401EC3
add eax,
4
UPX0:
00401EC6
cmp
eax,
10h
UPX0:
00401EC9
jl short loc_401EB7
UPX0:
00401ECB
push
40h
;
'@'
UPX0:
00401ECD
push offset aWelcome ;
"Welcome"
UPX0:
00401ED2
push offset aManYouReGoodEn ;
"... Man, you're good enough to join COR"
...
UPX0:
00401ED7
mov ecx, ebp
UPX0:
00401ED9
call MfcMsgBox
UPX0:
00401EDE
pop edi
UPX0:
00401EDF
pop esi
UPX0:
00401EE0
pop ebp
UPX0:
00401EE1
pop ebx
UPX0:
00401EE2
add esp,
608h
UPX0:
00401EE8
retn
UPX0:
00401EE9
;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
UPX0:
00401EE9
UPX0:
00401EE9
loc_401EE9: ; CODE XREF: UPX0:
00401EC1
↑j
UPX0:
00401EE9
push
30h
;
'0'
UPX0:
00401EEB
push offset aFailed ;
"Failed"
UPX0:
00401EF0
push offset aBetterLuckNext ;
"... Better luck next time ..."
UPX0:
00401EF5
mov ecx, ebp
UPX0:
00401EF7
call MfcMsgBox
UPX0:
00401EFC
pop edi
UPX0:
00401EFD
pop esi
UPX0:
00401EFE
pop ebp
UPX0:
00401EFF
pop ebx
UPX0:
00401F00
add esp,
608h
UPX0:
00401F06
retn
|
代码分析:
获取name和code分别保存
name + strrev(name) + ProductID(项的值) + RegisterOwner(项的值);由于是win10没有注册表项, 最终结果是 name + strrev(name) + strrev(name) + strrev(name) ;
初始化md5的state
name[-1] = 0x80 ;数据对齐64字节,存储len * 8
循环Md5Tramsform
保留state[0] 低16位,关键跳比较的就是state[0]的数据
读取code中的4个UINT
分别对 UINT[0] UINT[1];UINT[1]UINT[2];UINT[2]UINT[3] 运算
比较 UINT[0] 和 state[0] 如果相等则成功;
关键函数Encode函数
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
|
UPX0:
00401B90
Encode proc near ; CODE XREF: UPX0:
00401EA4
↓p
UPX0:
00401B90
UPX0:
00401B90
arg_0
=
dword ptr
4
UPX0:
00401B90
arg_4
=
dword ptr
8
UPX0:
00401B90
UPX0:
00401B90
mov eax, [esp
+
arg_0]
UPX0:
00401B94
push ebx
UPX0:
00401B95
mov ebx, [esp
+
4
+
arg_4]
UPX0:
00401B99
push esi
UPX0:
00401B9A
mov esi, [eax]
UPX0:
00401B9C
push edi
UPX0:
00401B9D
mov edi, [eax
+
4
]
UPX0:
00401BA0
test ebx, ebx
UPX0:
00401BA2
jbe short loc_401C15
UPX0:
00401BA4
push ebp ; edi
=
高
32
位UINT
UPX0:
00401BA4
; esi
=
低
32
位UINT
UPX0:
00401BA5
UPX0:
00401BA5
loc_401BA5: ; CODE XREF: Encode
+
7E
↓j
UPX0:
00401BA5
mov ebp, edi ;
for
(i
=
0
;i<loop_cnt;i
+
+
)
UPX0:
00401BA5
; 第一步就是实现
2
个UINT的循环左移
1
位
UPX0:
00401BA7
mov ecx,
1
UPX0:
00401BAC
shr ebp,
1Fh
UPX0:
00401BAF
mov [esp
+
10h
+
arg_4], ebp ; 取高
32
位最高位,保存一下
UPX0:
00401BB3
mov eax, esi
UPX0:
00401BB5
mov edx, edi
UPX0:
00401BB7
xor ebp, ebp
UPX0:
00401BB9
call __allshl ;
2
个UINT实现左移
1
位
UPX0:
00401BBE
mov ecx, [esp
+
10h
+
arg_4] ; 再将保存的的高
32
位的最高一位给低
32
位的最低位,实现循环左移
UPX0:
00401BC2
or
ebp, edx
UPX0:
00401BC4
or
ecx, eax
UPX0:
00401BC6
xor edx, edx
UPX0:
00401BC8
mov esi, ecx ; 循环左移结束
UPX0:
00401BCA
mov ecx,
0Bh
; 后面就是取低
32
位的第
2
13
31
位做亦或
UPX0:
00401BCF
mov eax, esi
UPX0:
00401BD1
mov edi, ebp
UPX0:
00401BD3
and
eax,
4
; 取低
32
位数据
2
位
UPX0:
00401BD6
call __allshl ; 循环做移动
11
位
11
+
2
=
13
位
UPX0:
00401BDB
mov ecx, esi
UPX0:
00401BDD
xor ebp, ebp
UPX0:
00401BDF
and
ecx,
2000h
; 取低
32
位数据
13
位
UPX0:
00401BE5
xor edx, ebp
UPX0:
00401BE7
xor eax, ecx ; 然后 亦或
UPX0:
00401BE9
mov ecx,
12h
; 循环做移动
18
位
13
+
18
=
31
位
UPX0:
00401BEE
call __allshl
UPX0:
00401BF3
mov ecx, esi
UPX0:
00401BF5
xor edx, ebp
UPX0:
00401BF7
and
ecx,
80000000h
; 取低
32
位数据
31
位
UPX0:
00401BFD
xor eax, ecx ; eax
=
eax ^
31
位的值
UPX0:
00401BFF
mov ecx,
1
UPX0:
00401C04
call __allshl ; 左移动一位将,亦或结果存入edx
UPX0:
00401C09
xor esi, eax ; eax 不管是
0
还是
0x8000000
左移
1
位后总是
0
UPX0:
00401C0B
xor edi, edx ; 高
32
位的最后一位和亦或结果做亦或
UPX0:
00401C0D
dec ebx
UPX0:
00401C0E
jnz short loc_401BA5 ;
for
(i
=
0
;i<loop_cnt;i
+
+
)
UPX0:
00401C0E
; 第一步就是实现
2
个UINT的循环左移
1
位
UPX0:
00401C10
mov eax, [esp
+
10h
+
arg_0]
UPX0:
00401C14
pop ebp
UPX0:
00401C15
UPX0:
00401C15
loc_401C15: ; CODE XREF: Encode
+
12
↑j
UPX0:
00401C15
mov [eax], esi
UPX0:
00401C17
mov [eax
+
4
], edi
UPX0:
00401C1A
pop edi
UPX0:
00401C1B
pop esi
UPX0:
00401C1C
pop ebx
UPX0:
00401C1D
retn
UPX0:
00401C1D
Encode endp
|
代码解读,直接c代码把
// 编码所用 void AllShl(unsigned int* low32, unsigned int* high32, unsigned int left) { unsigned int _low32, _high32, lowLeft; if (left < 32) { _low32 = *low32; _high32 = *high32; lowLeft = _low32 >> (32 - left); _high32 = _high32 << left; _low32 = _low32 << left; _high32 = _high32 | lowLeft; *low32 = _low32; *high32 = _high32; } } void Encode(unsigned int* low32, unsigned* high32, unsigned int loop) { unsigned int b2,h31,tHigh; for (unsigned int i = 0; i < loop; loop--) { // 第一步就是循环左移一位,高32位最高位会溢出,所以源程序先保存最高位,然后,补到低32位的最低为 // 其实就是一个圈 // 自己实现了一个圈 h31 = (*high32) >> 31; AllShl(low32, high32, 1); *low32 = *low32 | h31; tHigh = 0; b2 = *low32 & 4; // low32取第2位 AllShl(&b2, &tHigh, 11); // 左移11位 + 原来的2位 = 13位 b2 = b2 ^ (*low32 & 0x2000);// 第二位和第13位亦或 AllShl(&b2, &tHigh, 18); // 左移18位 + 原来的13位 = 31位 b2 = b2 ^ (*low32 & 0x80000000);// 第二位和第31位亦或 AllShl(&b2, &tHigh, 1); *low32 = *low32 ^ b2; // b2 始终等于0 *high32 = *high32 ^ tHigh; } }
简化后的Encode
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
|
void
Encode(unsigned
int
* low32, unsigned* high32, unsigned
int
loop) {
unsigned
int
h31, b2, b13, b31;
for
(unsigned
int
i = 0; i < loop; loop--) {
// 第一步就是循环左移一位,高32位最高位会溢出,所以源程序先保存最高位,然后,补到低32位的最低为
// 其实就是一个圈
// 自己实现了一个圈
h31 = (*high32) >> 31;
AllShl(low32, high32, 1);
*low32 = *low32 | h31;
// 其实后面的就是取低32位中第 2,13,31位的值进行亦或;然后和高32位最低为进行亦或
// 简化得到
b2 = ((*low32) & 4) >> 2;
// 取2位
b13 = ((*low32) & 0x2000) >> 13;
// 取13位
b31 = ((*low32) & 0x80000000) >> 31;
// 取31位
b2 = b2 ^ b13 ^ b31;
*high32 = *high32 ^ b2;
}
}
|
简化后其实就2步骤,根据低32位还原高32位;然后循环右移1位
Decode代码可得
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
|
// 解码所用
void
AllShr(unsigned
int
* low32, unsigned
int
* high32, unsigned
int
right) {
unsigned
int
_low32, _high32, highRight;
if
(right < 32)
{
_low32 = *low32;
_high32 = *high32;
highRight = _high32 << (32 - right);
_high32 = _high32 >> right;
_low32 = _low32 >> right;
_low32 = _low32 | highRight;
*low32 = _low32;
*high32 = _high32;
}
}
void
Decode(unsigned
int
* low32, unsigned* high32, unsigned
int
loop) {
unsigned
int
l1, b2, b13, b31;
for
(unsigned
int
i = 0; i < loop; loop--) {
// 第一步还原高32位的最低位
// 还是求低32位的第 2 13 31 位的亦或值,根据亦或特性 还原高32位数值
b2 = ((*low32) & 4) >> 2;
// 取2位
b13 = ((*low32) & 0x2000) >> 13;
// 取13位
b31 = ((*low32) & 0x80000000) >> 31;
// 取31位
b2 = b2 ^ b13 ^ b31;
*high32 = *high32 ^ b2;
// 第二步右旋转1位
l1 = *low32 & 1;
// 取low32最低位
AllShr(low32, high32, 1);
// 右移动1位
l1 = l1 << 31;
*high32 = *high32 | l1;
// 将l1补到高32位上
}
}
|
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
|
unsigned
int
a[4];
a[0] = 0x11111111;
a[1] = 0x22222222;
a[2] = 0x33333333;
a[3] = 0x44444444;
printf
(
"Org : %08lx %08lx %08lx %08lx\n"
, a[0], a[1], a[2], a[3]);
for
(i = 0; i < 3; i++) {
base = 0x0BADC0DE / (i + 0x50);
printf
(
"%d loop = %lx\n"
, i, base);
Encode(a + i, a + i + 1, base);
}
printf
(
"Encode: %08lx %08lx %08lx %08lx\n"
, a[0], a[1], a[2], a[3]);
for
(i = 2; i >= 0; i--) {
base = 0x0BADC0DE / (i + 0x50);
printf
(
"%d loop = %lx\n"
,i, base);
Decode(a + i, a + i + 1, base);
}
printf
(
"Decode: %08lx %08lx %08lx %08lx\n"
, a[0], a[1], a[2], a[3]);
return
;
|
验证结果
1
2
3
4
5
6
7
8
9
|
Org : 11111111 22222222 33333333 44444444
0 loop = 255f35
1 loop = 24e918
2 loop = 2475dd
Encode: 647577db 5250c59b 90dc6469 57a10cc3
2 loop = 2475dd
1 loop = 24e918
0 loop = 255f35
Decode: 11111111 22222222 33333333 44444444
|
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
|
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "md5.h"
char
* _strrev(
char
* s)
{
char
* h = s;
char
* t = s;
char
ch;
while
(*t++) {};
t--;
t--;
while
(h < t)
{
ch = *h;
*h++ = *t;
*t-- = ch;
}
return
(s);
}
// 解码所用
void
AllShr(unsigned
int
* low32, unsigned
int
* high32, unsigned
int
right) {
unsigned
int
_low32, _high32, highRight;
if
(right < 32)
{
_low32 = *low32;
_high32 = *high32;
highRight = _high32 << (32 - right);
_high32 = _high32 >> right;
_low32 = _low32 >> right;
_low32 = _low32 | highRight;
*low32 = _low32;
*high32 = _high32;
}
}
void
Decode(unsigned
int
* low32, unsigned* high32, unsigned
int
loop) {
unsigned
int
l1, b2, b13, b31;
for
(unsigned
int
i = 0; i < loop; loop--) {
// 第一步还原高32位的最低位
// 还是求低32位的第 2 13 31 位的亦或值,根据亦或特性 还原高32位数值
b2 = ((*low32) & 4) >> 2;
// 取2位
b13 = ((*low32) & 0x2000) >> 13;
// 取13位
b31 = ((*low32) & 0x80000000) >> 31;
// 取31位
b2 = b2 ^ b13 ^ b31;
*high32 = *high32 ^ b2;
// 第二步右旋转1位
l1 = *low32 & 1;
// 取low32最低位
AllShr(low32, high32, 1);
// 右移动1位
l1 = l1 << 31;
*high32 = *high32 | l1;
}
}
void
main()
{
int
i, len,buffLen,lenOffset;
unsigned
char
* data;
char
name[128] =
""
;
char
names[16] =
""
;
unsigned
int
base;
MD5_CTX ctx;
printf
(
"pls,input 'name'>"
);
scanf
(
"%s"
, name);
buffLen =
strlen
(name) * 4 + 1 + 8;
// name + 3次name反转 + 一位字符结束的特殊符号0x80,4字节int + 4字节空白
buffLen = (buffLen + 0x40) / 0x40 * 0x40;
// 64对齐
lenOffset = buffLen - 8;
// 最后8字节位置是int=长度<<3
data =
malloc
(buffLen);
memset
(data, 0, buffLen);
printf
(
"name:%s\n"
, name);
strcpy
(data, name);
strcpy
(names, name);
_strrev(names);
for
(i = 0; i < 3; i++)
{
strcat
(data, names);
// 因为win10没有注册表项,结果就是这样子
}
printf
(
"data:%s\n"
, data);
len =
strlen
(data);
data[len] = 0x80;
len += 1;
*(unsigned
int
*)(data + lenOffset) = len * 8;
MD5Init(&ctx);
for
( i = 0; i < buffLen; i+=64)
{
MD5Transform(ctx.state, (unsigned
char
*)data + i);
}
printf
(
"md5 : %08lx %08lx %08lx %08lx\n"
, ctx.state[0], ctx.state[1], ctx.state[2], ctx.state[3]);
ctx.state[0] = ctx.state[0] & 0xffff;
printf
(
"md5 : %08lx %08lx %08lx %08lx\n"
, ctx.state[0], ctx.state[1], ctx.state[2], ctx.state[3]);
for
(i = 2; i >= 0; i--) {
base = 0x0BADC0DE / (i + 0x50);
printf
(
"%d loop = %lx\n"
, i, base);
Decode(ctx.state + i, ctx.state + i + 1, base);
}
printf
(
"code : %08lx %08lx %08lx %08lx\n"
, ctx.state[0], ctx.state[1], ctx.state[2], ctx.state[3]);
return
;
}
|
几组组NS供验证:
helloworld : 7db37660 ae4c5d05 d2783eea 1d6514f2
pediy.com : b3f21c39 e8ca4483 4146d6f6 5644545b
更多【茶余饭后-逆向分析 160个CrackMe之052】相关视频教程:www.yxfzedu.com