首页
社区
课程
招聘
CrackMe.cycle注册机
2022-5-13 12:01 4398

CrackMe.cycle注册机

2022-5-13 12:01
4398

文章已于2022-05-12凌晨首发于我的个人博客:CrackMe之cycle注册机

 

本来这边想同步发出来的,结果发现新用户不能发帖::>_<::

 

刚刚接触逆向,这是我做的第三个crackme和第二次编写注册机,第一个是crackhead

 

如果有不足之处,希望各位前辈指出

 

references:

要破解的二进制文件

 

下断点的方法和crackhead一样,通过搜索所有引入的函数,从中找出可以用来下断点的函数

 

 

此处为GetDlgItemTextA函数

 

我们在该函数出现的所有位置下断点,然后在cycle程序的输入框中随便输点东西,触发断点即可

 

断点触发之后,我们就不需要这些断点了,在函数调用的下一行下断点即可

 

 

下面我们开始捋代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
004010A6  |. 6A 11          PUSH 11                                  ; /Count = 11 (17.)
004010A8  |. 68 71214000    PUSH cycle.00402171                      ; |Buffer = cycle.00402171
004010AD  |. 68 E9030000    PUSH 3E9                                 ; |ControlID = 3E9 (1001.)
004010B2  |. FF75 08        PUSH DWORD PTR SS:[EBP+8]                ; |hWnd
004010B5  |. E8 0F020000    CALL <JMP.&USER32.GetDlgItemTextA>       ; \GetDlgItemTextA
004010BA  |. 0BC0           OR EAX,EAX
004010BC  |. 74 61          JE SHORT cycle.0040111F
004010BE  |. 6A 11          PUSH 11                                  ; /Count = 11 (17.)
004010C0  |. 68 60214000    PUSH cycle.00402160                      ; |Buffer = cycle.00402160
004010C5  |. 68 E8030000    PUSH 3E8                                 ; |ControlID = 3E8 (1000.)
004010CA  |. FF75 08        PUSH DWORD PTR SS:[EBP+8]                ; |hWnd
004010CD  |. E8 F7010000    CALL <JMP.&USER32.GetDlgItemTextA>       ; \GetDlgItemTextA
004010D2  |. 0BC0           OR EAX,EAX
004010D4  |. 74 49          JE SHORT cycle.0040111F

GetDlgItemTextA函数被调用了两次,返回值存储在EAX中,为获取到的字符串的长度,第三个参数为传出参数,用于存储获取到的字符串,两次调用中分别传入了指针0x0040217100402160

 

根据调试结果,第一次调用获取到的是Serial,第二次调用获取到的是Name

 

只要我们输入不为空(即EAX值不为0),那么上面代码中的JE SHORT cycle.0040111F就不会执行

 

接着往下看

1
2
3
4
5
6
7
004010D6  |. B9 10000000    MOV ECX,10
004010DB  |. 2BC8           SUB ECX,EAX
004010DD  |. BE 60214000    MOV ESI,cycle.00402160                   ;  ASCII "1231231231231231"
004010E2  |. 8BFE           MOV EDI,ESI
004010E4  |. 03F8           ADD EDI,EAX
004010E6  |. FC             CLD
004010E7  |. F3:A4          REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>

这段代码对用户名进行了拷贝,CLD复位DDF标志寄存器,因此在执行REP MOVS时ESI和EDI每次拷贝完成后都会增加,由于此处为REP MOVS BYTE,因此每次拷贝一个字节,ESI和EDI的增加梯度也为1字节

 

拷贝的次数由ECX-EAX的结果决定,即(16-用户名长度),其实就是将用户名的长度扩展到了16位

1
2
3
4
5
6
7
8
9
10
11
12
13
004010E9  |. 33C9           XOR ECX,ECX
004010EB  |. BE 71214000    MOV ESI,cycle.00402171                   ;  ASCII "1234567890000000"
004010F0  |> 41             /INC ECX
004010F1  |. AC             |LODS BYTE PTR DS:[ESI]
004010F2  |. 0AC0           |OR AL,AL
004010F4  |. 74 0A          |JE SHORT cycle.00401100
004010F6  |. 3C 7E          |CMP AL,7E
004010F8  |. 7F 06          |JG SHORT cycle.00401100
004010FA  |. 3C 30          |CMP AL,30
004010FC  |. 72 02          |JB SHORT cycle.00401100
004010FE  |.^EB F0          \JMP SHORT cycle.004010F0
00401100  |> 83F9 11        CMP ECX,11
00401103  |. 75 1A          JNZ SHORT cycle.0040111F

清空ECX,然后将ESI指向Serial

 

下面开始循环,其中有一条指令大家可能没见过

 

LODS指令,Load String Operand

 

比如此处的LODS BYTE PTR DS:[ESI],会将ESI所指向的内容加载到EAX寄存器中,至于是加载到EAX、AX、AL由指令控制,此处由于我们是LODS BYTE,因此内存中的内容会被加载到AL中

 

因此上面代码中的循环就干了一件事,就是检测Serial中的字符是否位于0x300x7E之间,也就是ASCII码表中的48~126之间

 

 

最后判断了一下字符串长度是否为16,因为ECX会多加一次,也就是说比实际长度多1,根据CMP ECX, 11,我们可以确定Serial的长度必须为16位,因为如果无法满足这个条件,程序就会直接跳到RET指令,那就没得玩儿了,你可以自己试一下,如果Serial的长度不是16位,当你点击Check按钮的时候,程序是没有任何反应的

 

接着看

1
2
3
4
5
6
7
8
9
00401105  |. E8 E7000000    CALL cycle.004011F1
0040110A  |. B9 01FF0000    MOV ECX,0FF01
0040110F  |. 51             PUSH ECX
00401110  |. E8 7B000000    CALL cycle.00401190
00401115  |. 83F9 01        CMP ECX,1
00401118  |. 74 06          JE SHORT cycle.00401120
0040111A  |> E8 47000000    CALL cycle.00401166
0040111F  |> C3             RETN
00401120  |> A1 68214000    MOV EAX,DWORD PTR DS:[402168]

我们需要确保JE SHORT cycle.00401120执行,因为如果在这里没有跳转的话,那么不可避免的就一定会执行RETN,程序结束,又没得玩了

 

RETN上面那个CALL只是输出一下错误提示而已

 

因此我们要保证在前两个CALL执行完毕之后,ECX的值为1

 

这里我贴一下这两个函数的汇编代码:

 

cycle.004011f1

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
004011F1  /$ A1 60214000    MOV EAX,DWORD PTR DS:[402160]
004011F6  |. 8B1D 64214000  MOV EBX,DWORD PTR DS:[402164]
004011FC  |. 3305 71214000  XOR EAX,DWORD PTR DS:[402171]
00401202  |. 331D 75214000  XOR EBX,DWORD PTR DS:[402175]
00401208  |. 25 0F1F3F7F    AND EAX,7F3F1F0F
0040120D  |. 81E3 00010307  AND EBX,7030100
00401213  |. 33C9           XOR ECX,ECX
00401215  |> 8BF0           /MOV ESI,EAX
00401217  |. 8BFB           |MOV EDI,EBX
00401219  |. D3E6           |SHL ESI,CL
0040121B  |. D3E7           |SHL EDI,CL
0040121D  |. 81E6 80808080  |AND ESI,80808080
00401223  |. 81E7 80808080  |AND EDI,80808080
00401229  |. 8BD6           |MOV EDX,ESI
0040122B  |. C0EE 07        |SHR DH,7
0040122E  |. 66:C1E2 07     |SHL DX,7
00401232  |. C1EA 08        |SHR EDX,8
00401235  |. C0EE 07        |SHR DH,7
00401238  |. 66:C1E2 07     |SHL DX,7
0040123C  |. C1EA 08        |SHR EDX,8
0040123F  |. C0EE 07        |SHR DH,7
00401242  |. 66:D1EA        |SHR DX,1
00401245  |. 8BF2           |MOV ESI,EDX
00401247  |. 8BD7           |MOV EDX,EDI
00401249  |. C0EE 07        |SHR DH,7
0040124C  |. 66:C1E2 07     |SHL DX,7
00401250  |. C1EA 08        |SHR EDX,8
00401253  |. C0EE 07        |SHR DH,7
00401256  |. 66:C1E2 07     |SHL DX,7
0040125A  |. C1EA 08        |SHR EDX,8
0040125D  |. C0EE 07        |SHR DH,7
00401260  |. 66:C1EA 05     |SHR DX,5
00401264  |. 8BFA           |MOV EDI,EDX
00401266  |. 33FE           |XOR EDI,ESI
00401268  |. 8BD7           |MOV EDX,EDI
0040126A  |. 81E2 FF000000  |AND EDX,0FF
00401270  |. 51             |PUSH ECX
00401271  |. 52             |PUSH EDX
00401272  |. BA 08000000    |MOV EDX,8
00401277  |. 91             |XCHG EAX,ECX
00401278  |. 83F8 03        |CMP EAX,3
0040127B  |. 7F 0F          |JG SHORT cycle.0040128C
0040127D  |. F6E2           |MUL DL
0040127F  |. 5A             |POP EDX
00401280  |. 83C0 08        |ADD EAX,8
00401283  |. 91             |XCHG EAX,ECX
00401284  |. D3C0           |ROL EAX,CL
00401286  |. 33C2           |XOR EAX,EDX
00401288  |. D3C8           |ROR EAX,CL
0040128A  |. EB 0D          |JMP SHORT cycle.00401299
0040128C  |> 83E8 03        |SUB EAX,3
0040128F  |. F6E2           |MUL DL
00401291  |. 5A             |POP EDX
00401292  |. 91             |XCHG EAX,ECX
00401293  |. D3C3           |ROL EBX,CL
00401295  |. 33DA           |XOR EBX,EDX
00401297  |. D3CB           |ROR EBX,CL
00401299  |> 59             |POP ECX
0040129A  |. 41             |INC ECX
0040129B  |. 83F9 08        |CMP ECX,8
0040129E  |.^0F85 71FFFFFF  \JNZ cycle.00401215
004012A4  \. C3             RETN

cycle.00401190

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
00401190  /$ 5F             POP EDI
00401191  |. 59             POP ECX
00401192  |. 57             PUSH EDI
00401193  |. 81F9 80000000  CMP ECX,80
00401199  |. 7E 55          JLE SHORT cycle.004011F0
0040119B  |. 51             PUSH ECX
0040119C  |. 8BF1           MOV ESI,ECX
0040119E  |. 81E1 FF000000  AND ECX,0FF
004011A4  |. 8BF8           MOV EDI,EAX
004011A6  |. 83F9 08        CMP ECX,8
004011A9  |. 7E 05          JLE SHORT cycle.004011B0
004011AB  |. 8BFB           MOV EDI,EBX
004011AD  |. C1E9 04        SHR ECX,4
004011B0  |> C1C7 08        /ROL EDI,8
004011B3  |. D1E9           |SHR ECX,1
004011B5  |.^75 F9          \JNZ SHORT cycle.004011B0
004011B7  |. C1EE 08        SHR ESI,8
004011BA  |. 23FE           AND EDI,ESI
004011BC  |. 81E7 FF000000  AND EDI,0FF
004011C2  |. 59             POP ECX
004011C3  |> BE 80000000    MOV ESI,80
004011C8  |> 85FE           /TEST ESI,EDI
004011CA  |. 74 20          |JE SHORT cycle.004011EC
004011CC  |. 33FE           |XOR EDI,ESI
004011CE  |. 57             |PUSH EDI
004011CF  |. 81E1 00FF0000  |AND ECX,0FF00
004011D5  |. 87CE           |XCHG ESI,ECX
004011D7  |. 32E9           |XOR CH,CL
004011D9  |. 33F1           |XOR ESI,ECX
004011DB  |. 87F1           |XCHG ECX,ESI
004011DD  |. 51             |PUSH ECX
004011DE  |. FF05 82214000  |INC DWORD PTR DS:[402182]
004011E4  |. E8 A7FFFFFF    |CALL cycle.00401190
004011E9  |. 5F             |POP EDI
004011EA  |.^EB D7          |JMP SHORT cycle.004011C3
004011EC  |> D1EE           |SHR ESI,1
004011EE  |.^75 D8          \JNZ SHORT cycle.004011C8
004011F0  \> C3             RETN

指令都认识,但是这两个函数具体做了什么,我是不知道的,肯定是某种算法,但是变成机器码之后,几乎面目全非,根本无法辨识

 

我也是盯着这两段代码看了好久,什么思路都没有,最后就干脆用C语言把这个代码逻辑给实现了

 

https://144.one/s/u14s4

 

在这段代码中,我固定了用户名的前8位以及序列号的前4位,然后爆破序列号的4~7位

 

根据代码逻辑,EBX的初始化过程如下:

1
ebx = name[4-7] ^ serial[4-7] & 0x07030100

由于很多bit位都在与操作中被丢弃了,所以serial[4-7]并没有太多可能的值

 

但是我的这个代码并没有得到合法的Name和Serial,不过我发现了一些规律

 

在第一个函数cycle.004011f1运行完毕之后,EAX的值从未变过,EBX的值呈现周期性循环,循环周期为4

 

经过第二个函数cycle.00401190的运算之后,ecx的值总是同一个

 

后来我就突发奇想,如果我们控制EAX的值,使对应掩码0x7F3F1F0F所有的保留位全部为1,会发生什么?于是得出如下关系式

1
2
name[0-3] ^ serial[0-3] = 0x7F3F1F0F
serial[0-3] = name[0-3] ^ 0x7F3F1F0F

上面表达式中的0x7F3F1F0F可以有多个值,只要每个字节的高4bit的值x分别满足0<= x <10<= x <20<= x <40<= x <8即可,具体逻辑可以看代码

 

但是这样会限制serial[3]的值不能超过0x50,后来放松了第一个字节的限制,使其满足0<= x <2,发现这样也能生成有效的序列号,

 

然后我就随便找了一组,**JEUUUJ

 

结果发现,居然找出了满足ecx=1serial[4-7]

 

虽然我不知道这究竟是为什么,但事实就是只要我们满足上面那个表达式,那么经过最多64次尝试,就能找到一组合法的用户名和序列号

 

在通过ecx==1的检测之后,还有一个检测,但是就比较简单了,具体分析请查看下面的注册机源代码

 

注册机运行效果:

 

image-20220513115712303

 

下面是注册机代码,仍然使用codeblocks编译,你可以取消____DEBUG宏的注释以观察程序运行过程中各变量的变化:

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
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
// Author:  12138
// URL:     http://144.34.164.217
//          https://144.one
// Date:    2022/05/12 04:00 AM
// Desc:    CrackMe.cycle serial generator
 
#include   <windows.h>
#include   <stdio.h>
#include   <string.h>
#include   <time.h>
 
// #define ____DEBUG
 
#ifdef ____DEBUG
#define FUCK(_format, _var) printf(_format, _var);
#define CUM(_str) printf(_str);
#else
#define FUCK(_format, _var);
#define CUM(_str);
#endif
 
typedef unsigned int _ui;
 
// 这个计数器应该是一个全局变量
_ui _TODO_counter = 0xFEDCBA98;
 
char generate_random(char lower, char upper) {
   return (rand() % (upper - lower + 1)) + lower;
}
 
_ui string_to_hex(char* _string, int _begin) {
    char _24_31[3]={0};
    char _16_23[3]={0};
    char _8_15[3]={0};
    char _0_7[3]={0};
 
    sprintf(_24_31, "%02X", _string[_begin]);
    sprintf(_16_23, "%02X", _string[_begin+1]);
    sprintf(_8_15, "%02X", _string[_begin+2]);
    sprintf(_0_7, "%02X", _string[_begin+3]);
 
    char hex_string[8+1] = {0};
    strcpy(hex_string, _0_7);
    strcat(hex_string, _8_15);
    strcat(hex_string, _16_23);
    strcat(hex_string, _24_31);
    _ui _ret_val = (_ui)strtoul(hex_string, NULL, 16);
    return _ret_val;
}
 
int hex_to_string(_ui _hex_value, char* _ret_string) {
    _ui _s_15 = _hex_value & 0xFF000000;
    _s_15 = _s_15 >> 24;
    _ui _s_14 = _hex_value & 0x00FF0000;
    _s_14 = _s_14 >> 16;
    _ui _s_13 = _hex_value & 0x0000FF00;
    _s_13 = _s_13 >> 8;
    _ui _s_12 = _hex_value & 0x000000FF;
    if (_s_12 < 0x30 || _s_12 > 0x7E || _s_13 < 0x30 || _s_13 > 0x7E || _s_14 < 0x30 || _s_14> 0x7E || _s_15 < 0x30 || _s_15 > 0x7E) {
        return 1;
    }
    char hex_string[4+1] = {0};
    char _tmp_val[2] = {0};
    sprintf(_tmp_val, "%c", _s_12);
    strcpy(hex_string, _tmp_val);
    sprintf(_tmp_val, "%c", _s_13);
    strcat(hex_string, _tmp_val);
    sprintf(_tmp_val, "%c", _s_14);
    strcat(hex_string, _tmp_val);
    sprintf(_tmp_val, "%c", _s_15);
    strcat(hex_string, _tmp_val);
    strcpy(_ret_string, hex_string);
    return 0;
}
 
_ui _401190(_ui eax, _ui ebx, _ui ecx) {
    if(ecx > 0x80) {
        _ui _tmp_val = ecx;
        _ui esi = ecx;
        ecx = ecx & 0xFF;
        _ui edi = eax;
        if(ecx > 0x08) {
            edi = ebx;
            ecx = ecx >> 4;
        }
        while (ecx != 0) {
            edi = _rotl(edi, 8);
            ecx = ecx >> 1;
        }
        esi = esi >> 8;
        edi = edi & esi;
        edi = edi & 0xFF;
        ecx = _tmp_val;
        esi = 0x80;
        while (1) {
            if((esi & edi) == 0) {
                esi = esi >> 1;
                // 只有esi和edi与运算的结果等于0且esi右移1位等于0的时候,这个循环才会被打破
                if(esi == 0)
                    break;
                else
                    continue;
            }
            edi = edi ^ esi;
            _tmp_val = edi;
            ecx = ecx & 0xFF00;
            _ui _exch_val = ecx;
            ecx = esi;
            esi = _exch_val;
            // 对CH和CL进行异或运算,并将结果反映到ECX上
            _ui ch = ecx & 0xFF00;
            ch =  ch >> 8;
            _ui cl = ecx & 0xFF;
            ch = ch ^ cl;
            ch = ch << 8;
            ch = ch & 0xFF00;
            ecx = ecx & 0xFFFF00FF;
            ecx = ecx | ch;
            esi = esi ^ ecx;
            _exch_val = ecx;
            ecx = esi;
            esi = _exch_val;
            _TODO_counter += 1;
            FUCK("[*] _TODO counter: 0x%x\n", _TODO_counter);
            ecx = _401190(eax, ebx, ecx);
            edi = _tmp_val;
            esi = 0x80;
            continue;
        }
        return ecx;
    }
    else
        return ecx;
}
 
int register_func(char* extend_user_name, char* serial) {
 
    printf("[*] current Serial: %s\n", serial);
    // 获取用户名的0~3位并转换成整型数
    _ui eax = string_to_hex(extend_user_name, 0);
    FUCK("[*] eax: %x\n", eax);
 
    // 获取用户名的4~7位并转换成整型数
    _ui ebx = string_to_hex(extend_user_name, 4);
    FUCK("[*] ebx: %x\n", ebx);
 
    // 获取序列号的0~3位并转换成整型数
    _ui _xor_eax = string_to_hex(serial, 0);
    FUCK("[*] the oprand xor with eax: %x\n", _xor_eax);
 
    // 获取序列号的4~7位并转换成整型数
    _ui _xor_ebx = string_to_hex(serial, 4);
    FUCK("[*] the oprand xor with ebx: %x\n", _xor_ebx);
 
    eax = eax ^ _xor_eax;
    ebx = ebx ^ _xor_ebx;
    eax = eax & 0x7F3F1F0F;
    ebx = ebx & 0x07030100;
    printf("[*] eax is ready for loop: %x\n", eax);
    printf("[*] ebx is ready for loop: %x\n",ebx);
 
    // 下面开始循环
    int loop_counter = 0, ecx = 0;
    while(loop_counter < 8) {
        FUCK("\n_________________OO<--%d-->OO_________________\n", loop_counter);
        ecx = loop_counter;
        _ui esi = eax;
        _ui edi = ebx;
        esi = esi << ecx;
        edi = edi << ecx;
        // 这一步其实就是获取到esi和edi每个字节中的最高位
        esi = esi & 0x80808080;
        edi = edi & 0x80808080;
        _ui edx = esi;
        // 下面这一堆移位操作其实是把每个字节中的最高位移动到了DL的高四位中
        _ui _d = edx & 0x80000000;
        _d = _d >> 31;
        _ui _c = edx & 0x00800000;
        _c = _c >> 23;
        _ui _b = edx & 0x00008000;
        _b = _b >> 15;
        _ui _a = edx & 0x00000080;
        _a = _a >> 7;
 
        char _DL_H4_0_3[3] = {0};
        sprintf(_DL_H4_0_3, "%X", _d*8+_c*4+_b*2+_a);
        char* hex_string = (char*)malloc(2+1);
        strcpy(hex_string, _DL_H4_0_3);
        edx = (_ui)strtoul(hex_string, NULL, 16);
        free(hex_string);
        edx = edx << 4;
        esi = edx;
        FUCK("[*] esi: 0x%x\n", esi);
        /*
        我们分别用ABCD代表一个32位数中每个字节的最高位
        |-----------------| |--------DX-------|
        |                 | |---DH--| |--DL---|
        D000 0000 C000 0000 B000 0000 A000 0000         DH  >> 7
        D000 0000 C000 0000 0000 000B A000 0000         DX  << 7
        D000 0000 C000 0000 BA00 0000 0000 0000         EDX >> 8
        0000 0000 D000 0000 C000 0000 BA00 0000         DH  >> 7
        0000 0000 D000 0000 0000 000C BA00 0000         DX  << 7
        0000 0000 D000 0000 CBA0 0000 0000 0000         EDX >> 8
        0000 0000 0000 0000 D000 0000 CBA0 0000         DH  >> 7
        0000 0000 0000 0000 0000 000D CBA0 0000         DX  >> 1
        0000 0000 0000 0000 0000 0000 DCBA 0000
        */
        edx = edi;
        // 下面这一堆移位操作其实是把每个字节中的最高位移动到了DL的低四位中
 
        /*
        我们分别用ABCD代表一个32位数中每个字节的最高位
        |-----------------| |--------DX-------|
        |                 | |---DH--| |--DL---|
        D000 0000 C000 0000 B000 0000 A000 0000         DH  >> 7
        D000 0000 C000 0000 0000 000B A000 0000         DX  << 7
        D000 0000 C000 0000 BA00 0000 0000 0000         EDX >> 8
        0000 0000 D000 0000 C000 0000 BA00 0000         DH  >> 7
        0000 0000 D000 0000 0000 000C BA00 0000         DX  << 7
        0000 0000 D000 0000 CBA0 0000 0000 0000         EDX >> 8
        0000 0000 0000 0000 D000 0000 CBA0 0000         DH  >> 7
        0000 0000 0000 0000 0000 000D CBA0 0000         DX  >> 5
        0000 0000 0000 0000 0000 0000 0000 DCBA
        */
        _d = edx & 0x80000000;
        _d = _d >> 31;
        _c = edx & 0x00800000;
        _c = _c >> 23;
        _b = edx & 0x00008000;
        _b = _b >> 15;
        _a = edx & 0x00000080;
        _a = _a >> 7;
 
        char _DL_L4_0_3[3] = {0};
        sprintf(_DL_L4_0_3, "%02X", _d*8+_c*4+_b*2+_a);
        hex_string = (char*)malloc(2+1);
        strcpy(hex_string, _DL_L4_0_3);
        edx = (_ui)strtoul(hex_string, NULL, 16);
        free(hex_string);
        edi = edx;
        FUCK("[*] edi: 0x%x\n", edi);
        edi = edi ^ esi;
        edx = edi;
        edx = edx & 0xFF;
        _ui _tmp_val = ecx;
        ecx = eax;
        eax = _tmp_val;
        FUCK("[*] edx: 0x%x\n", edx);
        if (eax > 3) {
            eax = eax - 3;
            eax = eax * 8;
            _tmp_val = eax;
            eax = ecx;
            ecx = _tmp_val;
            ebx = _rotl(ebx, ecx);
            ebx = ebx ^ edx;
            ebx = _rotr(ebx, ecx);
        } else {
            eax = eax * 8 + 8;
            _tmp_val = eax;
            eax = ecx;
            ecx = _tmp_val;
            eax = _rotl(eax, ecx);
            eax = eax ^ edx;
            eax = _rotr(eax, ecx);
        }
        FUCK("[*] eax: 0x%x\n",eax);
        FUCK("[*] ebx: 0x%x\n", ebx);
        loop_counter += 1;
    }
    printf("[*] after loop, eax: 0x%X\n", eax);
    printf("[*] after loop, ebx: 0x%X\n", ebx);
 
 
    // 下面是函数cycle.401190
    ecx = 0xFF01;
    // 这里需要对一个内存(0x402182)的值进行一个加法运算
    // 我暂时还不清楚这个内存的值是否固定,因此先留一个TODO,经调试,这里的初始值应该是98BADCFE
    // 转换成整型数就是FEDCBA98
    // 该函数并不是简单地循环,是一个递归函数,因此需要单独定义
    ecx = _401190(eax, ebx, ecx);
    FUCK("[*] ecx: 0x%X\n", ecx);
    return ecx;
}
 
 
int main_call() {
    _TODO_counter = 0xFEDCBA98;
    char user_name[16+1] = {0};
    printf("[*] give me a max-16-len string, 'q' to exit:\n\t");
    scanf("%16s", user_name);
    FUCK("%s\n",  user_name);
    if(1==strlen(user_name) && 'q'==user_name[0]) return 'q';
    // 将用户名扩充至16
    int user_name_length = strlen(user_name);
    printf("[*] user name length: %d\n", user_name_length);
    char* extend_user_name = (char*)malloc(16+1);
    strcpy(extend_user_name, user_name);
    int i = 0;
    for(; i<16-user_name_length; i++) {
        char _tmp_val[2] = {0};
        sprintf(_tmp_val, "%c", user_name[i%user_name_length]);
        strcat(extend_user_name, _tmp_val);
    }
    printf("[*] user name after extended: %s\n", extend_user_name);
    // 对于掩码0x7F3F1F0F
    // 0x7F和username[3]进行异或运算
    // 如果username[3]的13bit置位,那么serial[3]的13bit一定会复位
    // 则serial[3]一定会小于0x30,这样就无法通过字符范围的检测了[0x30, 0x7E]
//        if(0x50 <= extend_user_name[3]) {
//            printf("[-] after xor with mask(0x7F), the value would less than 0x30, \n\tusername[3]'s ascii value should not be greater than 0x50\n");
//            continue;
//        }
    // 首先获取到注册码的前4
    // __n_0_3 ^ __s_0_3 == 0x7F3F1F0F
    _ui _n_0_3 = string_to_hex(extend_user_name, 0);
    FUCK("0x%X\n", _n_0_3);
    char _s_0_3[4+1] = {0};
    _ui _hex_xor_res = 0;
    i=0;
    int j = 0;
    int k = 0;
    int l = 0;
    for(; i<8; i++) {
        j=0;
        for(; j<4; j++) {
            k=0;
            for(; k<2; k++) {
                l=0;
                for(; l<2; l++) {
                    memset(_s_0_3, 0, sizeof(_s_0_3));
                    char _tmp_char[2+1] = {0};
                    char hex_string[4+1] = {0};
                    sprintf(_tmp_char, "%02X", (4*l+3)*16+0x0F);
                    strcpy(hex_string, _tmp_char);
                    sprintf(_tmp_char, "%02X", (4*k+3)*16+0x0F);
                    strcat(hex_string, _tmp_char);
                    sprintf(_tmp_char, "%02X", (2*j+1)*16+0x0F);
                    strcat(hex_string, _tmp_char);
                    sprintf(_tmp_char, "%02X", i*16+0x0F);
                    strcat(hex_string, _tmp_char);
 
                    FUCK("hex_string = %s\n", hex_string);
                    // _hex_xor_res = 0x0F0F0F0F;
                    _hex_xor_res = (_ui)strtoul(hex_string, NULL, 16);
                    FUCK("hex_xor_res = 0x%X\n", _hex_xor_res);
                    FUCK("_n_0_3----%x\n", _n_0_3 ^ _hex_xor_res);
                    if(hex_to_string(_n_0_3 ^ _hex_xor_res, _s_0_3)==0) {
                        FUCK("_s_0_3----%s\n", _s_0_3);
                        goto __GOTO_ONCE;
                    }
                }
            }
        }
    }
 
    __GOTO_ONCE:
    FUCK("%s\n", _s_0_3);
 
    // 为了通过注册码长度检测,这里先给序列号填充为16位,其实后八位暂时是用不着的
    char* _s_8_15 = "89abcdef";
    // 由于掩码0x07030100最后会和EBX进行与运算
    // 所以最后EBX的四个字节,从高到低依次拥有3210个有效bit位
    // 也就是说,无论_n_4_7和_s_4_7是什么样的,EBX只有2^(3+2+1+0)=64种可能的值
    // 下面这个组合可以覆盖到所有的可能性
    // 这样一来,我们就可以获取到注册码的4~7位了
    char* _s_4 = "@ABCDEFG";
    char* _s_5 = "@ABC";
    char* _s_6 = "@A";
    char* _s_7 = "A";
    i=0;
    for(; i<8; i++) {
        j=0;
        for(; j<4;j++) {
            k=0;
            for(; k<2; k++) {
                char* hex_string = (char*)malloc(16+1);
                strcpy(hex_string, _s_0_3);
                char _s_4_7[4+1] = {0};
                char _tmp_val[2] = {0};
                sprintf(_tmp_val, "%c", _s_4[i]);
                strcpy(_s_4_7, _tmp_val);
                sprintf(_tmp_val, "%c", _s_5[j]);
                strcat(_s_4_7, _tmp_val);
                sprintf(_tmp_val, "%c", _s_6[k]);
                strcat(_s_4_7, _tmp_val);
                sprintf(_tmp_val, "%c", _s_7[0]);
                strcat(_s_4_7, _tmp_val);
                strcat(hex_string, _s_4_7);
                strcat(hex_string, _s_8_15);
                if(register_func(extend_user_name, hex_string) == 1) {
                    free(hex_string);
                    printf("[+] half success!!! come on!!!\n\n");
                    // 实现剩下的运算
                    char _24_31[3]={0};
                    char _16_23[3]={0};
                    char _8_15[3]={0};
                    char _0_7[3]={0};
 
                    // 获取用户名的8~11并转换成整型数
                    _ui eax = string_to_hex(extend_user_name, 8);
                    FUCK("[*] eax: %x\n", eax);
 
                    // 获取用户名的12~15并转换成整型数
                    _ui ebx = string_to_hex(extend_user_name, 12);
                    FUCK("[*] ebx: %x\n", ebx);
 
                    eax = eax ^ ebx;
                    eax = eax ^ _TODO_counter;
                    eax = eax | 0x40404040;
                    eax = eax & 0x77777777;
                    while(1) {
                        char _eax_bin_format[32+1] = {0};
                        itoa(eax, _eax_bin_format, 2);
                        char __eax_bin_format[32+1] = {0};
                        sprintf(__eax_bin_format, "%032s", _eax_bin_format);
                        int index=0;
                        CUM("[+] this is the binary format of serial_8_11 ^ serial_12_15 result:\n\t");
                        for(; index<32; index++) {
                            FUCK("%c", __eax_bin_format[index]);
                            if((index+1)%4 == 0 && (index+1)!=32) {
                                CUM(" ");
                            }
                            if((index+1)%8 == 0 && (index+1)!=32) {
                                CUM("%% ");
                            }
                        }
                        CUM("\n");
 
                        char _s_8_11[4+1] = {0};
                        sprintf(_tmp_val, "%c", generate_random(0x30, 0x7E));
                        FUCK("random char %s", _tmp_val);
                        strcpy(_s_8_11, _tmp_val);
                        sprintf(_tmp_val, "%c", generate_random(0x30, 0x7E));
                        FUCK("random char %s", _tmp_val);
                        strcat(_s_8_11, _tmp_val);
                        sprintf(_tmp_val, "%c", generate_random(0x30, 0x7E));
                        FUCK("random char %s", _tmp_val);
                        strcat(_s_8_11, _tmp_val);
                        sprintf(_tmp_val, "%c", generate_random(0x30, 0x7E));
                        FUCK("random char %s", _tmp_val);
                        strcat(_s_8_11, _tmp_val);
                        printf("[*] generating random 4-len string: %s\n", _s_8_11);
//                        char _DEBUG_s_8_11[4+1] = "}3d7";
//                        strcpy(_s_8_11, _DEBUG_s_8_11);
                        _ui _s_8_11_hex_value = string_to_hex(_s_8_11, 0);
                        // 根据汇编代码
                        // eax = eax ^ s_8_11
                        // eax = eax ^ s_12_15
                        // eax == 0必须成立
                        // 那么可以推导出 eax ^ s_8_11 == s_12_15
                        FUCK("_s_8_11_hex_value: 0x%X\n", _s_8_11_hex_value);
                        FUCK("eax: 0x%X\n", eax);
                        _ui _s_12_15_hex_value = eax ^ _s_8_11_hex_value;
                        FUCK("_s_12_15_hex_value: 0x%X\n", _s_12_15_hex_value);
                        hex_string = (char*)malloc(4+1);
                        if(1==hex_to_string(_s_12_15_hex_value, hex_string)) {
                            free(hex_string);
                            continue;
                        }
 
                        char serial_number[16+1] = {0};
                        strcpy(serial_number, _s_0_3);
                        strcat(serial_number, _s_4_7);
                        strcat(serial_number, _s_8_11);
                        strcat(serial_number, hex_string);
                        free(hex_string);
 
                        printf("[+] Name:\n\t%s\n", user_name);
                        printf("[+] Serial:\n\t%s\n", serial_number);
                        char c = 0;
                        while ((c = getchar()) != EOF && c != '\n');
                        return 0;
                    }
                }
                free(hex_string);
            }
        }
    }
    return 0;
}
 
int main(int argc, char** argv) {
    while(1)
        if('q' == main_call()) break;
    return 0;
}

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

最后于 2022-5-14 12:10 被12138编辑 ,原因: 动图链接更新
上传的附件:
收藏
点赞3
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回