首页
社区
课程
招聘
[原创][原创]逆向分析 160个CrackMe五星052
2023-12-30 11:03 9281

[原创][原创]逆向分析 160个CrackMe五星052

2023-12-30 11:03
9281

#逆向分析 160个CrackMe 052

闲来无事,工作上有调整,等待来年安排,日常的学习还是不能松懈,好久没搞2进制了,最近正在刷pwn和CrackMe,看到了一个160集合感觉不错,刷了几周了,做了20多个了吧,也不知道哪个好,随便搞了下,感觉这5星级的还是挺有意思的,故分析发文。

参考

160个CrackMe破解思路合集

工具和环境

环境:win10 x64 chs

工具:x64dbg IDA BinaryNinja

编译器:gcc

大体扫一眼

  • 看图标和UI应该是mfc的。
  • 类型应该是Name/Serail类型的。
  • DIE跑一下:UPX的壳。
  • 简单输入Name和Serial测试下,有弹窗。

52

脱壳

那些在xp上好有用的工具都不太兼容win10,魔改版的LoadPE + ImportREC 修复的exe时灵时不灵的。

还好x64dbg仅有的一个插件解决了这个问题。

x64dbg + esp定律找到OEP,使用x64dbg自带的Scylla,三下五除二搞定。

x64dbg

脱壳后的exe

找算法函数

第一种办法就是 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函数

关键函数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                        ; 循环做移动1111 + 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

keygen

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


[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
点赞5
打赏
分享
最新回复 (4)
雪    币: 19349
活跃值: (28971)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2023-12-31 22:48
2
1
感谢分享
雪    币: 1322
活跃值: (1052)
能力值: ( LV7,RANK:155 )
在线值:
发帖
回帖
粉丝
ylml 2 2024-1-8 18:57
3
2

看到有人问,就顺便放上来了。

上传的附件:
雪    币: 31978
活跃值: (7105)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
ninebell 2024-1-8 22:35
4
0
西班牙还有9000多个CrackMe没人分析呢。。
雪    币: 9
活跃值: (1034)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tkschip 2024-3-22 10:21
5
0
多谢分享
游客
登录 | 注册 方可回帖
返回