首页
社区
课程
招聘
3
[原创]看雪CTF2019晋级赛Q1 第7题
发表于: 2019-3-22 16:36 6081

[原创]看雪CTF2019晋级赛Q1 第7题

2019-3-22 16:36
6081

 计算出2个常数 ,我们称之为 constKey1 ,constKey2,如下:

4BC080 该值为: 0x1093ACBD

         4BC084 该值为:  0x2cF346

       2、同时将 将2个表中的数据由16进制转换为10进制。  0x1093ACBD  -->278113469    0x2cF346 ->2945862

       

1)根据上面得到的索引值(0x14 0x13 ...),从之前生成的510个buf中,获取2个数值,一个为index,一个为keyvalue.

2)根据index,索引g_sntable,得到另外一个索引index2

3) 根据index2 对全局变量off_4BC060指针进行索引,得到一个数值为 constKey

4) 判断constKey 与前面的keyvalue是否相等,如果相等,则equCnt++

5) 如果 index的值等于0x28则 将equCnt--,进行下一次循环

6) 如果  index  > 0x28 则 index --

7)整个循环0x51次数。

然后利用上面的 equCnt 对 off_4BC05C进行索引并计算checksun数值,  判断checksum是否等于 0x1F1A, 如果不等于则 输入sn错误,直接退出。如果相等,则利用equCnt的数值对off_4BC05C进行解密,然后将解密后的数据打印输出。

(写的比较多。。。。)
一、去掉混淆和程序修改检测                                           
1、程序加入了混淆代码,分析起来比较费劲,先把混淆bypass掉。代码如下:

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
void ByPassOb( void )
{
    char        box[1024];
    int     size;
    int     start       = 0x1000;
    int     end     = 0xBC000;
    unsigned char  jmp_code[16][4] =
    {
        0x7A, 0x03, 0x7B, 0x01,
        0x77, 0x03, 0x76, 0x01,
        0x71, 0x03, 0x70, 0x01,
        0x7C, 0x03, 0x7D, 0x01,
        0x70, 0x03, 0x71, 0x01,
        0x7F, 0x03, 0x7E, 0x01,
        0x78, 0x03, 0x79, 0x01,
        0x75, 0x03, 0x74, 0x01,
        0x7B, 0x03, 0x7A, 0x01,
        0x72, 0x03, 0x73, 0x01,
        0x7D, 0x03, 0x7C, 0x01,
        0x74, 0x03, 0x75, 0x01,
        0x76, 0x03, 0x77, 0x01,
        0x79, 0x03, 0x78, 0x01,
        0x7e, 0x03, 0x7f, 0x01,
        0x73, 0x03, 0x72, 0x01,
    };
    unsigned char  call_code1[5]   = { 0xE8, 0x02, 0x00, 0x00, 0x00 };
    unsigned char  call_code11[5]  = { 0xE8, 0x03, 0x00, 0x00, 0x00 };
    unsigned char  call_code12[5]  = { 0xE8, 0x01, 0x00, 0x00, 0x00 };
    unsigned char  call_code13[6]  = { 0x50, 0xE8, 0x01, 0x00, 0x00, 0x00 };
    unsigned char  call_code15[5]  = { 0xE8, 0x04, 0x00, 0x00, 0x00 };
    unsigned char  call_code2[3]   = { 0x83, 0xC4, 0x04 };
    unsigned char  call_code21[5]  = { 0x83, 0x04, 0x24, 0x06, 0xC3 };
    unsigned char  call_code23[2]  = { 0x58, 0x58 };
    unsigned char  call_code24[1]  = { 0x58 };
    unsigned char  call_code25[2]  = { 0xeb, 0x0c };
    unsigned char  jmp_code1[4]    = { 0x7c, 0x03, 0xeb, 0x03 };
    unsigned char  jmp_code2[2]    = { 0x74, 0xFB };
    unsigned char  stcjb_code[3]   = { 0xF9, 0x72, 0x02 };
    unsigned char  clcjnb_code[3]  = { 0xF8, 0x73, 0x02 };
    unsigned char  clcjnb_code1[3] = { 0xF8, 0x73, 0x01 };
 
    unsigned char  main_code[15]       = { 0xC6, 0x55, 0x5F, 0xF3, 0x00, 0xE8, 0x02, 0x00, 0x00, 0x00, 0xA2, 0x0C, 0x83, 0xC4, 0x04 };
    unsigned char  change_code[0x14]   = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
    unsigned char  main_stack_code1[]  = { 0x83, 0xec, 0x0c };
    unsigned char  jmpEax_code[3]      = { 0x40, 0xEB, 0x01 };
    unsigned char  jmpEax_code2[2]     = { 0xFF, 0xE0 };
 
    unsigned char* buf = GetFileNameBuffer( "DancingCircle.exe", &size );
 
    /* bypass 随机数 */
    buf[0xF77]  = 0xEB;
    buf[0xF78]  = 0x47;
 
    /* by pass anti debug */
    buf[0xB8798]            = 0x33;
    buf[0xB8799]            = 0xc0;
    *(int *) (buf + 0xBB31D)    = 0x24230201;
 
    /* bp pass main开始4B8DFA地址的混淆代码 */
    memcpy( buf + 0x99f, change_code, 5 );
 
    /* 使部分函数F5 OK */
    memcpy( buf + 0xb81e8, main_stack_code1, 3 );
    memcpy( buf + 0xb81fa, change_code, 5 );
 
    int findJmpCnt  = 0;
    int findCallCnt = 0;
    int findMainCnt = 0;
    int findStcjbCnt    = 0;
    int findClcjnbCnt   = 0;
 
    /* 分析代码段,bypass混淆代码 */
    for int i = start; i < end; i++ )
    {
        if ( 0 == memcmp( buf + i, main_code, 15 ) )
        {
            memcpy( buf + i, change_code, 15 );
            i = i + 14;
            findMainCnt++;
        }
        if ( 0 == memcmp( buf + i, stcjb_code, 3 ) )
        {
            memcpy( buf + i, change_code, 5 );
            i = i + 4;
            findStcjbCnt++;
        }
        if ( 0 == memcmp( buf + i, clcjnb_code, 3 ) )
        {
            memcpy( buf + i, change_code, 5 );
            i = i + 4;
            findClcjnbCnt++;
        }
 
        if ( 0 == memcmp( buf + i, clcjnb_code1, 3 ) )
        {
            memcpy( buf + i, change_code, 4 );
            i = i + 3;
            findClcjnbCnt++;
        }
        if ( 0 == memcmp( buf + i, call_code1, 5 ) )
        {
            if ( 0 == memcmp( buf + i + 7, call_code2, 3 ) )
            {
                memcpy( buf + i, change_code, 10 );
                i = i + 9;
                findCallCnt++;
                continue;
            }
        }
 
        if ( 0 == memcmp( buf + i, call_code11, 5 ) )
        {
            if ( 0 == memcmp( buf + i + 8, call_code2, 3 ) )
            {
                memcpy( buf + i, change_code, 11 );
                i = i + 10;
                findCallCnt++;
                continue;
            }
            if ( 0 == memcmp( buf + i + 8, call_code24, 1 ) )
            {
                memcpy( buf + i, change_code, 9 );
                i = i + 8;
                findCallCnt++;
                continue;
            }
        }
        if ( 0 == memcmp( buf + i, call_code12, 5 ) )
        {
            if ( 0 == memcmp( buf + i + 6, call_code2, 3 ) )
            {
                memcpy( buf + i, change_code, 9 );
                i = i + 8;
                findCallCnt++;
                continue;
            }
 
            if ( 0 == memcmp( buf + i + 6, call_code21, 5 ) )
            {
                memcpy( buf + i, change_code, 11 );
                i = i + 10;
                findCallCnt++;
                continue;
            }
        }
 
        if ( 0 == memcmp( buf + i, call_code13, 6 ) )
        {
            if ( 0 == memcmp( buf + i + 7, call_code23, 2 ) )
            {
                memcpy( buf + i, change_code, 9 );
                i = i + 7;
                findCallCnt++;
                continue;
            }
        }
        if ( 0 == memcmp( buf + i, call_code15, 5 ) )
        {
            if ( 0 == memcmp( buf + i + 6, call_code25, 2 ) )
            {
                memcpy( buf + i, change_code, 0x14 );
                i = i + 0x13;
                findCallCnt++;
            }
        }
        if ( 0 == memcmp( buf + i, jmp_code1, 4 ) )
        {
            if ( 0 == memcmp( buf + i + 5, jmp_code2, 2 ) )
            {
                memcpy( buf + i, change_code, 7 );
                i = i + 6;
                findJmpCnt++;
                continue;
            }
        }
        if ( 0 == memcmp( buf + i, jmpEax_code, 3 ) )
        {
            if ( 0 == memcmp( buf + i + 4, jmpEax_code2, 2 ) )
            {
                memcpy( buf + i, change_code, 6 );
                i = i + 6;
                findJmpCnt++;
                continue;
            }
        }
        for int j = 0; j < 16; j++ )
        {
            if ( 0 == memcmp( buf + i, jmp_code[j], 4 ) )
            {
                memcpy( buf + i, change_code, 5 );
                i = i + 4;
                findJmpCnt++;
                break;
            }
        }
    }
    unlink( "DancingCircle-bypassob.exe" );
    WriteFileNameBuffer( "DancingCircle-bypassob.exe", buf, size );
}
去掉混淆后代码如下:
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
.text:00401F58                                     ChangeKeyByAddr proc near               ; CODE XREF: sub_4025D3+1A↓p
.text:00401F58                                                                             ; ChangeKeyAndAntiDebug+25↓p
.text:00401F58                                                                             ; _main+71↓p
.text:00401F58                                                                             ; DATA XREF: sub_4025D3+13↓o
.text:00401F58
.text:00401F58                                     arg_0           = dword ptr  8
.text:00401F58                                     arg_4           = dword ptr  0Ch
.text:00401F58
.text:00401F58 55                                                  push    ebp
.text:00401F59 89 E5                                               mov     ebp, esp
.text:00401F5B 60                                                  pusha
.text:00401F5C 9C                                                  pushf
.text:00401F5D BA 80 C0 4B 00                                      mov     edx, offset source
.text:00401F62 90                                                  nop
.text:00401F63 90                                                  nop
.text:00401F64 90                                                  nop
.text:00401F65 90                                                  nop
.text:00401F66 90                                                  nop
.text:00401F67 90                                                  nop
.text:00401F68 90                                                  nop
 
int __usercall ChangeKeyByAddr@<eax>(int a1@<edx>, int a2@<ecx>, int a3@<esi>, _DWORD *a4, int a5)
{
  unsigned int v5; // et0
  _DWORD *v6; // esi
  int v7; // ecx
  _DWORD *v8; // esi
  int v9; // eax
  int v10; // eax
  unsigned int v12; // [esp-24h] [ebp-24h]
  int v13; // [esp-18h] [ebp-18h]
  int v14; // [esp-4h] [ebp-4h]
  int savedregs; // [esp+0h] [ebp+0h]
  _DWORD *retaddr; // [esp+4h] [ebp+4h]
 
  v14 = a3;
  v13 = a2;
  v5 = __readeflags();
  v12 = v5;
  v6 = a4;
  v7 = a5;
  if ( !a4 )
    v6 = retaddr;
  v8 = (_DWORD *)((char *)v6 + 5);
  v9 = 0;
  do
  {
    v10 = *v8 ^ v9;
    ++v8;
    v9 = __ROR4__(v10 ^ 0x78563412, 9);
    --v7;
  }
  while ( v7 );
  *(_DWORD *)(&source + *((unsigned __int8 *)retaddr + 4)) = *retaddr ^ v9;
  __writeeflags(v12);
  savedregs = v14;
  retaddr = (_DWORD *)((char *)retaddr + 5);
  return nullsub_2(v13, a1);
}
3、关键key生成函数 401F58(如上)
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
.text:00401F58                                     ChangeKeyByAddr proc near               ; CODE XREF: sub_4025D3+1A↓p
.text:00401F58                                                                             ; ChangeKeyAndAntiDebug+25↓p
.text:00401F58                                                                             ; _main+71↓p
.text:00401F58                                                                             ; DATA XREF: sub_4025D3+13↓o
.text:00401F58
.text:00401F58                                     arg_0           = dword ptr  8
.text:00401F58                                     arg_4           = dword ptr  0Ch
.text:00401F58
.text:00401F58 55                                                  push    ebp
.text:00401F59 89 E5                                               mov     ebp, esp
.text:00401F5B 60                                                  pusha
.text:00401F5C 9C                                                  pushf
.text:00401F5D BA 80 C0 4B 00                                      mov     edx, offset source
.text:00401F62 90                                                  nop
.text:00401F63 90                                                  nop
.text:00401F64 90                                                  nop
.text:00401F65 90                                                  nop
.text:00401F66 90                                                  nop
.text:00401F67 90                                                  nop
.text:00401F68 90                                                  nop
 
int __usercall ChangeKeyByAddr@<eax>(int a1@<edx>, int a2@<ecx>, int a3@<esi>, _DWORD *a4, int a5)
{
  unsigned int v5; // et0
  _DWORD *v6; // esi
  int v7; // ecx
  _DWORD *v8; // esi
  int v9; // eax
  int v10; // eax
  unsigned int v12; // [esp-24h] [ebp-24h]
  int v13; // [esp-18h] [ebp-18h]
  int v14; // [esp-4h] [ebp-4h]
  int savedregs; // [esp+0h] [ebp+0h]
  _DWORD *retaddr; // [esp+4h] [ebp+4h]
 
  v14 = a3;
  v13 = a2;
  v5 = __readeflags();
  v12 = v5;
  v6 = a4;
  v7 = a5;
  if ( !a4 )
    v6 = retaddr;
  v8 = (_DWORD *)((char *)v6 + 5);
  v9 = 0;
  do
  {
    v10 = *v8 ^ v9;
    ++v8;
    v9 = __ROR4__(v10 ^ 0x78563412, 9);
    --v7;
  }
  while ( v7 );
  *(_DWORD *)(&source + *((unsigned __int8 *)retaddr + 4)) = *retaddr ^ v9;
  __writeeflags(v12);
  savedregs = v14;
  retaddr = (_DWORD *)((char *)retaddr + 5);
  return nullsub_2(v13, a1);
}
3、关键key生成函数 401F58(如上)
程序去掉混淆后,使得401F58计算的checksum有误,因此在后面需要修正。
程序共三处调用401F58
程序去掉混淆后,使得401F58计算的checksum有误,因此在后面需要修正。
程序共三处调用401F58
1)计算main函数的checksum,放入到全局变量中4BC080 该值为: 0x1093ACBD
1)计算main函数的checksum,放入到全局变量中4BC080 该值为: 0x1093ACBD
2)计算4025D3反调试函数的checksum,放入到全局变量中4BC084 该值为0x2cF346
2)计算4025D3反调试函数的checksum,放入到全局变量中4BC084 该值为0x2cF346
3)计算401F58本身的checksum,并放入到 0x4BC080+0x9D位置, 该值为 0x24230201
3)计算401F58本身的checksum,并放入到 0x4BC080+0x9D位置, 该值为 0x24230201
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
#coding=utf-8
 
import struct
from idaapi import *
from idc import *
from idautils import *
 
'''====================================================
函数名:GetLibAddr
用  途:根据模块名获得模块起始地址
备  注:此函数在SHT被破坏时将不起作用
====================================================='''
def GetLibAddr(targetName):
    targetBase = 0
    for i in Modules():
        #print i.name
        if targetName in i.name:
            targetBase = int("%x"%(i.base), 16)
            #print 'targetName:=' + targetName + 'targetBase:=' + str(targetBase)
            break
    if targetBase == 0:
        #print 'targetBase None!!!'
        return False
 
    return targetBase
 
'''====================================================
函数名:GetSegAddrByName
用  途:根据段名获得段的起始地址
备  注:
====================================================='''
def GetSegAddrByName(targetName):
    tempAddr = FirstSeg()
    while tempAddr!=0:
        if tempAddr == 0:
            break
        name = SegName(tempAddr)
        if targetName in name:
            return tempAddr
        tempAddr = NextSeg(tempAddr)
    return 0
 
'''====================================================
函数名:writeMemoryForAddr
用  途:向模块地址写入指定shellcode
备  注:
====================================================='''
def writeMemoryForAddr(targetName, offset, buf):
    targetBase = 0
    targetBase = GetSegAddrByName(targetName)
    if targetBase == 0:
        #print 'targetBase None!!!'
        return False
 
    addr = targetBase + offset
    if not dbg_write_memory(addr, buf):
        return False
 
    refresh_debugger_memory()
    return True
 
'''====================================================
函数名:addBptForAddr
用  途:给模块指定偏移下断点
备  注:
====================================================='''
def addBptForAddr(targetName, offset, comm):
    soAddr = GetSegAddrByName(targetName)
    if soAddr > 0 :
        AddBpt(soAddr + offset)
        SetBptAttr(soAddr + offset, BPTATTR_FLAGS, BPT_ENABLED | BPT_BRK)
        MakeComm(soAddr + offset, comm)
    else :
        print 'create point fail'
    return True
 
'''====================================================
函数名:DelBptForAddr
用  途:删除模块指定偏移的断点
备  注:
====================================================='''
def DelBptForAddr(targetName, offset):
    soAddr = GetSegAddrByName(targetName)
    if soAddr > 0 :
        AddBpt(soAddr + offset)
        DelBpt(soAddr + offset)
    return True
 
'''====================================================
函数名:makenameForAddr
用  途:给指定模块函数重命名
备  注:
====================================================='''
def makenameForAddr(targetName, offset, comm):
    soAddr = GetSegAddrByName(targetName)
    if soAddr > 0 :
        MakeName(soAddr + offset, comm)
    else :
        print 'makenameForAddr fail'
    return True
 
'''====================================================
函数名:makeCommForAddr
用  途:给指定模块地址下注释
备  注:
====================================================='''
def makeCommForAddr(targetName, offset, comm):
    soAddr = GetSegAddrByName(targetName)
    if soAddr > 0 :
        MakeComm(soAddr + offset, comm)
    else :
        print 'makeCommForAddr fail'
    return True
 
 
'''====================================================
函数名:dumpMem
用  途:dump 指定大小的内存数据
备  注:
====================================================='''
def dumpMem(start, l, target):
    block = 1024
    c = l / block
    left = l % block
    fd = open(target, 'wb')
    if c > 0:
        for i in range(c):
            rawdex = idaapi.dbg_read_memory(start, block)
            fd.write(rawdex)
            start += block
 
    if left > 0:
        rawdex = idaapi.dbg_read_memory(start, left)
        print rawdex == True
        fd.write(rawdex)
    fd.close()
 
'''====================================================
函数名:doDump
用  途:通过窗口dump内存数据
备  注:
====================================================='''
def doDump():
    start = AskAddr(0, 'Input Addr start in hex: ')
    print('start is ' + str(hex(start)))
 
    end = AskAddr(0, 'Input Addr end in hex: ')
    print('end is ' + str(hex(end)))
 
    l = end - start
    target = AskStr('./dump.mem''Input the dump file path')
 
    if l > 0 and start > 0x0 and target and AskYN(1, 'start is 0x%0x, len is %d, dump to %s' % (start, l, target)) == 1:
        dumpMem(start, l, target)
        print('Dump Finish')
 
'''====================================================
函数名:readIntFromMemory
用  途:从内存中读取一个int
备  注:
====================================================='''
def readIntFromMemory(addr):
    flag=0
    temp = addr
    temp1= temp
    if  temp%2:
        temp1= temp-1
        flag=1
    else:
        temp1=temp
    m4=dbg_read_memory(temp1, 4+flag)
    return  struct.unpack('i', m4)[0+flag]
 
'''====================================================
函数名:dbg_read_every_memory
用  途:从内存中读取一个int
备  注:优化过的
====================================================='''
def dbg_read_every_memory(start, len):
 
    tempStart=start - (start%0x1000)
    maxLen = (start%0x1000) + len
    #print maxLen
    #print tempStart
    rawdex = idaapi.dbg_read_memory(tempStart, maxLen)
    #print rawdex
    left = start%0x1000
    #print left
    #print rawdex[left:maxLen]
    return bytearray(rawdex[left:maxLen])
 
'''====================================================
函数名:readShortFromMemory
用  途:从内存中读取一个short
备  注:
====================================================='''
def readShortFromMemory(addr):
    m2=dbg_read_memory(addr, 2)
    return  struct.unpack('h', m2)[0]
 
'''====================================================
函数名:readCharFromMemory
用  途:从内存中读取一个char
备  注:
====================================================='''
def readCharFromMemory(addr):
    m1=dbg_read_memory(addr, 1)
    return  struct.unpack('c', m2)[0]
 
'''====================================================
函数名:readUIntFromMemory
用  途:从内存中读取一个uint
备  注:
====================================================='''
def readUIntFromMemory(addr):
    m4=dbg_read_memory(addr, 4)
    return  struct.unpack('I', m4)[0]
 
'''====================================================
函数名:readUShortFromMemory
用  途:从内存中读取一个ushort
备  注:
====================================================='''
def readUShortFromMemory(addr):
    m2=dbg_read_memory(addr, 2)
    return  struct.unpack('H', m2)[0]
 
'''====================================================
函数名:readUCharFromMemory
用  途:从内存中读取一个uchar
备  注:
====================================================='''
def readUCharFromMemory(addr):
    m1=dbg_read_memory(addr, 1)
    return  struct.unpack('C', m1)[0]
 
'''====================================================
函数名:copyMem
用  途:拷贝内存到另外一个区域r
备  注:
====================================================='''
def copyMem(start, l, target):
    addrTemp = target
    print 'copy start'
    block = 1024
    c = l / block
    left = l % block
    if c > 0:
        for i in range(c):
            print str(hex(start))
            print str(hex(addrTemp))
            rawdex = idaapi.dbg_read_memory(start, block)
            dbg_write_memory(addrTemp, rawdex)
            refresh_debugger_memory()
            start += block
            addrTemp += block
 
    if left > 0:
        rawdex = idaapi.dbg_read_memory(start, left)
        dbg_write_memory(addrTemp, rawdex)
        refresh_debugger_memory()
    print 'copy end'
 
 
'''====================================================
函数名:FindData
用  途:从指定位置查找指定字节的数据
备  注:返回第一个找到的位置
====================================================='''
def FindData(addr, target):
    a = -1
    segStart = SegStart(addr)
    segEnd = SegEnd(addr)
    len=segEnd-segStart
    for i in range(len):
        rawdex1 = idaapi.dbg_read_memory(segStart, 1024)
        a = rawdex1.find(target)
        if a>= 0:
            a = a + segStart
            break;
        segStart = segStart+512
    return a
 
'''====================================================
函数名:FindDataEx
用  途:从指定位置查找指定字节的数据
备  注:返回第一个找到的位置
====================================================='''
def FindDataEx(addr, target,offset, target2):
    a = -1
    segStart = SegStart(addr)
    segEnd = SegEnd(addr)
    len=segEnd-segStart
    for i in range(len):
        rawdex1 = idaapi.dbg_read_memory(segStart, 1024)
        a = rawdex1.find(target)
        if a>= 0:
            rawdex2 = dbg_read_every_memory(segStart+a+offset, 512)
            b = rawdex2.find(target2)
            if b == 0:
                a = a + segStart
                break;
        segStart = segStart+512
    return a
 
#set debug breakpoint
 
 
'''-------------------------------------------------------------
#################start#######################
-------------------------------------------------------------'''
print 'by pass anti debug'
libBase = GetLibAddr('kernel32.dll')
print 'KernelBase addr = ' + str(hex(libBase))
addr = libBase + 0x163E0
print 'kernel32_SetThreadContext addr = ' + str(hex(addr))
write_dbg_memory(addr, "\xc2\x08\x00")
addr = libBase + 0x14030
print 'kernel32_CheckRemoteDebuggerPresent addr = ' + str(hex(addr))
write_dbg_memory(addr, "\x33\xc0\xc2\x08\x00")
print 'kernel32_CheckRemoteDebuggerPresent addr = ' + str(hex(addr))
 
AddBpt(0x4B8EBF)
SetBptAttr(0x4B8EBF, BPTATTR_FLAGS, BPT_ENABLED | BPT_BRK)
 
write_dbg_memory(0x004B9788, changecode)
'''-------------------------------------------------------------
执行so 初始化函数开始时的处理
-------------------------------------------------------------'''
pcValue=GetRegValue('eip')
libBase=GetLibAddr('linker')
if pcValue == 0x4B8EBF:
    print 'bypass memory check'
    write_dbg_memory(0x004BC080, "\xBD\xA3\x9C\x10\x46\xF3\x2C\x00")

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
#coding=utf-8
 
import struct
from idaapi import *
from idc import *
from idautils import *
 
'''====================================================
函数名:GetLibAddr
用  途:根据模块名获得模块起始地址
备  注:此函数在SHT被破坏时将不起作用
====================================================='''
def GetLibAddr(targetName):
    targetBase = 0
    for i in Modules():
        #print i.name
        if targetName in i.name:
            targetBase = int("%x"%(i.base), 16)
            #print 'targetName:=' + targetName + 'targetBase:=' + str(targetBase)
            break
    if targetBase == 0:
        #print 'targetBase None!!!'
        return False
 
    return targetBase
 
'''====================================================
函数名:GetSegAddrByName
用  途:根据段名获得段的起始地址
备  注:
====================================================='''
def GetSegAddrByName(targetName):
    tempAddr = FirstSeg()
    while tempAddr!=0:
        if tempAddr == 0:
            break
        name = SegName(tempAddr)
        if targetName in name:
            return tempAddr
        tempAddr = NextSeg(tempAddr)
    return 0
 
'''====================================================
函数名:writeMemoryForAddr
用  途:向模块地址写入指定shellcode
备  注:
====================================================='''
def writeMemoryForAddr(targetName, offset, buf):
    targetBase = 0
    targetBase = GetSegAddrByName(targetName)
    if targetBase == 0:
        #print 'targetBase None!!!'
        return False
 
    addr = targetBase + offset
    if not dbg_write_memory(addr, buf):
        return False
 
    refresh_debugger_memory()
    return True
 
'''====================================================
函数名:addBptForAddr
用  途:给模块指定偏移下断点
备  注:
====================================================='''
def addBptForAddr(targetName, offset, comm):
    soAddr = GetSegAddrByName(targetName)
    if soAddr > 0 :
        AddBpt(soAddr + offset)
        SetBptAttr(soAddr + offset, BPTATTR_FLAGS, BPT_ENABLED | BPT_BRK)
        MakeComm(soAddr + offset, comm)
    else :
        print 'create point fail'
    return True
 
'''====================================================
函数名:DelBptForAddr
用  途:删除模块指定偏移的断点
备  注:
====================================================='''
def DelBptForAddr(targetName, offset):
    soAddr = GetSegAddrByName(targetName)
    if soAddr > 0 :
        AddBpt(soAddr + offset)
        DelBpt(soAddr + offset)
    return True
 
'''====================================================
函数名:makenameForAddr
用  途:给指定模块函数重命名
备  注:
====================================================='''
def makenameForAddr(targetName, offset, comm):
    soAddr = GetSegAddrByName(targetName)
    if soAddr > 0 :
        MakeName(soAddr + offset, comm)
    else :
        print 'makenameForAddr fail'
    return True
 
'''====================================================
函数名:makeCommForAddr
用  途:给指定模块地址下注释
备  注:
====================================================='''
def makeCommForAddr(targetName, offset, comm):
    soAddr = GetSegAddrByName(targetName)
    if soAddr > 0 :
        MakeComm(soAddr + offset, comm)
    else :
        print 'makeCommForAddr fail'
    return True
 
 
'''====================================================
函数名:dumpMem
用  途:dump 指定大小的内存数据
备  注:
====================================================='''
def dumpMem(start, l, target):
    block = 1024
    c = l / block
    left = l % block
    fd = open(target, 'wb')
    if c > 0:
        for i in range(c):
            rawdex = idaapi.dbg_read_memory(start, block)
            fd.write(rawdex)
            start += block
 
    if left > 0:
        rawdex = idaapi.dbg_read_memory(start, left)
        print rawdex == True
        fd.write(rawdex)
    fd.close()
 
'''====================================================
函数名:doDump
用  途:通过窗口dump内存数据
备  注:
====================================================='''
def doDump():
    start = AskAddr(0, 'Input Addr start in hex: ')
    print('start is ' + str(hex(start)))
 
    end = AskAddr(0, 'Input Addr end in hex: ')
    print('end is ' + str(hex(end)))
 
    l = end - start
    target = AskStr('./dump.mem''Input the dump file path')
 
    if l > 0 and start > 0x0 and target and AskYN(1, 'start is 0x%0x, len is %d, dump to %s' % (start, l, target)) == 1:
        dumpMem(start, l, target)
        print('Dump Finish')
 
'''====================================================
函数名:readIntFromMemory
用  途:从内存中读取一个int
备  注:
====================================================='''
def readIntFromMemory(addr):
    flag=0
    temp = addr
    temp1= temp
    if  temp%2:
        temp1= temp-1
        flag=1
    else:
        temp1=temp
    m4=dbg_read_memory(temp1, 4+flag)
    return  struct.unpack('i', m4)[0+flag]
 
'''====================================================
函数名:dbg_read_every_memory
用  途:从内存中读取一个int
备  注:优化过的
====================================================='''
def dbg_read_every_memory(start, len):
 
    tempStart=start - (start%0x1000)
    maxLen = (start%0x1000) + len
    #print maxLen
    #print tempStart
    rawdex = idaapi.dbg_read_memory(tempStart, maxLen)
    #print rawdex
    left = start%0x1000
    #print left
    #print rawdex[left:maxLen]
    return bytearray(rawdex[left:maxLen])
 
'''====================================================
函数名:readShortFromMemory
用  途:从内存中读取一个short
备  注:
====================================================='''
def readShortFromMemory(addr):
    m2=dbg_read_memory(addr, 2)
    return  struct.unpack('h', m2)[0]
 
'''====================================================
函数名:readCharFromMemory
用  途:从内存中读取一个char
备  注:
====================================================='''
def readCharFromMemory(addr):
    m1=dbg_read_memory(addr, 1)
    return  struct.unpack('c', m2)[0]
 
'''====================================================
函数名:readUIntFromMemory
用  途:从内存中读取一个uint
备  注:
====================================================='''
def readUIntFromMemory(addr):
    m4=dbg_read_memory(addr, 4)
    return  struct.unpack('I', m4)[0]
 
'''====================================================
函数名:readUShortFromMemory
用  途:从内存中读取一个ushort
备  注:
====================================================='''
def readUShortFromMemory(addr):
    m2=dbg_read_memory(addr, 2)
    return  struct.unpack('H', m2)[0]
 
'''====================================================
函数名:readUCharFromMemory
用  途:从内存中读取一个uchar
备  注:
====================================================='''
def readUCharFromMemory(addr):
    m1=dbg_read_memory(addr, 1)
    return  struct.unpack('C', m1)[0]
 
'''====================================================
函数名:copyMem
用  途:拷贝内存到另外一个区域r
备  注:
====================================================='''
def copyMem(start, l, target):
    addrTemp = target
    print 'copy start'
    block = 1024
    c = l / block
    left = l % block
    if c > 0:
        for i in range(c):
            print str(hex(start))
            print str(hex(addrTemp))
            rawdex = idaapi.dbg_read_memory(start, block)
            dbg_write_memory(addrTemp, rawdex)
            refresh_debugger_memory()
            start += block
            addrTemp += block
 
    if left > 0:
        rawdex = idaapi.dbg_read_memory(start, left)
        dbg_write_memory(addrTemp, rawdex)
        refresh_debugger_memory()
    print 'copy end'
 
 
'''====================================================
函数名:FindData
用  途:从指定位置查找指定字节的数据
备  注:返回第一个找到的位置
====================================================='''
def FindData(addr, target):
    a = -1
    segStart = SegStart(addr)
    segEnd = SegEnd(addr)
    len=segEnd-segStart
    for i in range(len):
        rawdex1 = idaapi.dbg_read_memory(segStart, 1024)
        a = rawdex1.find(target)
        if a>= 0:
            a = a + segStart
            break;
        segStart = segStart+512
    return a
 
'''====================================================
函数名:FindDataEx
用  途:从指定位置查找指定字节的数据
备  注:返回第一个找到的位置
====================================================='''
def FindDataEx(addr, target,offset, target2):
    a = -1
    segStart = SegStart(addr)
    segEnd = SegEnd(addr)
    len=segEnd-segStart
    for i in range(len):
        rawdex1 = idaapi.dbg_read_memory(segStart, 1024)
        a = rawdex1.find(target)
        if a>= 0:
            rawdex2 = dbg_read_every_memory(segStart+a+offset, 512)
            b = rawdex2.find(target2)
            if b == 0:
                a = a + segStart
                break;
        segStart = segStart+512
    return a
 
#set debug breakpoint
 
 
'''-------------------------------------------------------------
#################start#######################
-------------------------------------------------------------'''
print 'by pass anti debug'
libBase = GetLibAddr('kernel32.dll')
print 'KernelBase addr = ' + str(hex(libBase))
addr = libBase + 0x163E0
print 'kernel32_SetThreadContext addr = ' + str(hex(addr))
write_dbg_memory(addr, "\xc2\x08\x00")
addr = libBase + 0x14030
print 'kernel32_CheckRemoteDebuggerPresent addr = ' + str(hex(addr))
write_dbg_memory(addr, "\x33\xc0\xc2\x08\x00")
print 'kernel32_CheckRemoteDebuggerPresent addr = ' + str(hex(addr))
 
AddBpt(0x4B8EBF)
SetBptAttr(0x4B8EBF, BPTATTR_FLAGS, BPT_ENABLED | BPT_BRK)
 
write_dbg_memory(0x004B9788, changecode)
'''-------------------------------------------------------------
执行so 初始化函数开始时的处理
-------------------------------------------------------------'''
pcValue=GetRegValue('eip')
libBase=GetLibAddr('linker')
if pcValue == 0x4B8EBF:
    print 'bypass memory check'
    write_dbg_memory(0x004BC080, "\xBD\xA3\x9C\x10\x46\xF3\x2C\x00")

三、去掉反调试
1、40299C函数
    将设置DRX硬件断点为401000、401001、401002、401003,感觉可以不用管,但是先用脚本让SetThreadContext函数直接返回。
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
signed int __usercall ChangeKeyAndAntiDebug@<eax>(int a1@<edx>, int a2@<ecx>, char a3@<bl>, int a4@<esi>, int a5)
{
  int v5; // eax
  int v6; // ebx
  int v7; // esi
  int v9; // [esp+14h] [ebp-2E4h]
  int v10; // [esp+18h] [ebp-2E0h]
  int v11; // [esp+1Ch] [ebp-2DCh]
  int v12; // [esp+20h] [ebp-2D8h]
  int v13; // [esp+24h] [ebp-2D4h]
  int v14; // [esp+2Ch] [ebp-2CCh]
 
  v5 = ChangeKeyByAddr(a1, a2, a4, sub_4025D3, 240);
  *(_BYTE *)(v5 + 82) &= a3;
  v6 = a5 + GetModuleHandleA(0);
  v9 = 65552;
  v7 = GetCurrentThread();
  GetThreadContext(v7, &v9);
  v10 = v6;
  v11 = v6 + 1;
  v13 = v6 + 3;
  v12 = v6 + 2;
  v14 |= 0x11110055u;
  SetThreadContext(v7, &v9);
  return 1;
}
2、反调试函数执行talbe.
main函数计算key的过程中,在某个时间点会调用如下9个反函数数组:
1
2
3
4
5
6
7
8
.data:004BC020 D3 25 40 00                         off_4BC020      dd offset sub_4025D3    ; DATA XREF: _main+5A4↑r
.data:004BC024 19 26 40 00                                         dd offset sub_402619
.data:004BC028 75 26 40 00                                         dd offset sub_402675
.data:004BC02C 22 27 40 00                                         dd offset sub_402722
.data:004BC030 6B 27 40 00                                         dd offset sub_40276B
.data:004BC034 66 25 40 00                                         dd offset sub_402566
.data:004BC038 D1 26 40 00                                         dd offset sub_4026D1
.data:004BC03C BC 27 40 00                                         dd offset sub_4027BC
main的如下位置调用上述函数
1
2
3
4
5
6
7
.text:004B9382 8B 85 44 D4 FF FF                                               mov     eax, [ebp-2BBCh]
.text:004B9388 8B 80 20 C0 4B 00                                               mov     eax, dword_4BC020[eax]
.text:004B938E C7 85 58 D4 FF FF 04 00 00 00                                   mov     dword ptr [ebp-2BA8h], 4
.text:004B9398 FF D0                                                           call    eax
.text:004B939A 83 F8 01                                                        cmp     eax, 1
.text:004B939D 83 95 48 D4 FF FF 00                                            adc     dword ptr [ebp-2BB8h], 0
.text:004B93A4 83 85 44 D4 FF FF 04                                            add     dword ptr [ebp-2BBCh], 4
如果返回结果为0,则累加计数器,只有非在调试器状态下,累加的结果为9,才可以使key计算正确。同时:
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
signed int __usercall ChangeKeyAndAntiDebug@<eax>(int a1@<edx>, int a2@<ecx>, char a3@<bl>, int a4@<esi>, int a5)
{
  int v5; // eax
  int v6; // ebx
  int v7; // esi
  int v9; // [esp+14h] [ebp-2E4h]
  int v10; // [esp+18h] [ebp-2E0h]
  int v11; // [esp+1Ch] [ebp-2DCh]
  int v12; // [esp+20h] [ebp-2D8h]
  int v13; // [esp+24h] [ebp-2D4h]
  int v14; // [esp+2Ch] [ebp-2CCh]
 
  v5 = ChangeKeyByAddr(a1, a2, a4, sub_4025D3, 240);
  *(_BYTE *)(v5 + 82) &= a3;
  v6 = a5 + GetModuleHandleA(0);
  v9 = 65552;
  v7 = GetCurrentThread();
  GetThreadContext(v7, &v9);
  v10 = v6;
  v11 = v6 + 1;
  v13 = v6 + 3;
  v12 = v6 + 2;
  v14 |= 0x11110055u;
  SetThreadContext(v7, &v9);
  return 1;
}
2、反调试函数执行talbe.
main函数计算key的过程中,在某个时间点会调用如下9个反函数数组:
1
2
3
4
5
6
7
8
.data:004BC020 D3 25 40 00                         off_4BC020      dd offset sub_4025D3    ; DATA XREF: _main+5A4↑r
.data:004BC024 19 26 40 00                                         dd offset sub_402619
.data:004BC028 75 26 40 00                                         dd offset sub_402675
.data:004BC02C 22 27 40 00                                         dd offset sub_402722
.data:004BC030 6B 27 40 00                                         dd offset sub_40276B
.data:004BC034 66 25 40 00                                         dd offset sub_402566
.data:004BC038 D1 26 40 00                                         dd offset sub_4026D1
.data:004BC03C BC 27 40 00                                         dd offset sub_4027BC
main的如下位置调用上述函数
1
2
3
4
5
6
7
8
.data:004BC020 D3 25 40 00                         off_4BC020      dd offset sub_4025D3    ; DATA XREF: _main+5A4↑r
.data:004BC024 19 26 40 00                                         dd offset sub_402619
.data:004BC028 75 26 40 00                                         dd offset sub_402675
.data:004BC02C 22 27 40 00                                         dd offset sub_402722
.data:004BC030 6B 27 40 00                                         dd offset sub_40276B
.data:004BC034 66 25 40 00                                         dd offset sub_402566
.data:004BC038 D1 26 40 00                                         dd offset sub_4026D1
.data:004BC03C BC 27 40 00                                         dd offset sub_4027BC
main的如下位置调用上述函数
1
2
3
4
5
6
7
.text:004B9382 8B 85 44 D4 FF FF                                               mov     eax, [ebp-2BBCh]
.text:004B9388 8B 80 20 C0 4B 00                                               mov     eax, dword_4BC020[eax]
.text:004B938E C7 85 58 D4 FF FF 04 00 00 00                                   mov     dword ptr [ebp-2BA8h], 4
.text:004B9398 FF D0                                                           call    eax
.text:004B939A 83 F8 01                                                        cmp     eax, 1
.text:004B939D 83 95 48 D4 FF FF 00                                            adc     dword ptr [ebp-2BB8h], 0
.text:004B93A4 83 85 44 D4 FF FF 04                                            add     dword ptr [ebp-2BBCh], 4
如果返回结果为0,则累加计数器,只有非在调试器状态下,累加的结果为9,才可以使key计算正确。同时:
1
2
3
4
5
6
7
.text:004B9382 8B 85 44 D4 FF FF                                               mov     eax, [ebp-2BBCh]
.text:004B9388 8B 80 20 C0 4B 00                                               mov     eax, dword_4BC020[eax]
.text:004B938E C7 85 58 D4 FF FF 04 00 00 00                                   mov     dword ptr [ebp-2BA8h], 4
.text:004B9398 FF D0                                                           call    eax
.text:004B939A 83 F8 01                                                        cmp     eax, 1
.text:004B939D 83 95 48 D4 FF FF 00                                            adc     dword ptr [ebp-2BB8h], 0
.text:004B93A4 83 85 44 D4 FF FF 04                                            add     dword ptr [ebp-2BBCh], 4
如果返回结果为0,则累加计数器,只有非在调试器状态下,累加的结果为9,才可以使key计算正确。同时:
 1)在函数sub_4025D3中对401F58进行计算checksum;
 1)在函数sub_4025D3中对401F58进行计算checksum;
 2)  sub_4028B3设置了异常处理程序;
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
nt __usercall sub_4025D3@<eax>(int a1@<edx>, int a2@<ecx>, int a3@<esi>)
{
  int v3; // edx
  unsigned __int8 v4; // cf
  unsigned int v5; // ST00_4
  int v6; // eax
  int v8; // [esp+1Ch] [ebp-Ch]
 
  ChangeKeyByAddr(a1, a2, a3, ChangeKeyByAddr, 104);
  JUMPOUT(!(v4 | (v3 == -1)), (char *)&loc_402624 + 6);
  __writeeflags(v5);
  v6 = GetCurrentProcess();
  CheckRemoteDebuggerPresent(v6, (char *)&v8 + 1);
  return *(int *)((char *)&v8 + 1);
}
 
signed int sub_4028B3()
{
  signed int v1; // [esp+18h] [ebp-10h]
  int v2; // [esp+1Ch] [ebp-Ch]
 
  v2 = 0;
  v1 = 0;
  if ( !setjmp3(Buf, 0) )
  {
    __debugbreak();
    v2 = SetUnhandledExceptionFilter(sub_40254C);
    v1 = 1;
  }
  SetUnhandledExceptionFilter(v2);
  return v1;
}
 在前面去混淆的时候直接让call eax,变为xor eax,eax,不去调用9个反调试函数,并能够使返回结果累加为9。(可能会使后面的计算key有误,先暂时这样处理)
至此准备工作做完,开始进行分析。
三、main 函数
去掉混淆后main函数如下:
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
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // ebx
  int v4; // ebp
  int cur1; // edi
  int v6; // esi
  void *v7; // esp
  int v8; // edx
  int v9; // ecx
  int v10; // edx
  int v11; // ecx
  int v12; // ecx
  int v13; // eax
  int i; // edx
  int v15; // eax
  char *v16; // ebx
  unsigned __int8 *dataSN; // esi
  unsigned __int8 *dataSnEnd; // edx
  char v19; // t2
  char v20; // ah
  int v21; // eax
  int num; // eax
  int *tempBuf; // eax
  int *malocBufEnd; // edx
  int *keyVectorBuf; // ebx
  int k; // eax
  int curIndex1; // ebx
  int muti9_Value; // ebx
  int *tempBuf1; // eax
  int i1; // edx
  int v31; // ebx
  int *pmalloc2Buf; // edx
  int *v33; // eax
  int v34; // ecx
  signed int nextKeyValue; // eax
  int v36; // edx
  int v37; // et1
  int *v38; // ebx
  int cnt_9; // edi
  __int64 m3; // rax
  signed __int64 v41; // rt2
  __int64 m1; // rax
  signed __int64 leftValue; // rt2
  int keyValue1; // edi
  char v45; // al
  int v46; // ebx
  int v47; // eax
  signed int v48; // eax
  int v49; // edx
  char *v50; // ecx
  int v51; // eax
  int v52; // ebx
  bool v53; // zf
  _DWORD *v54; // eax
  int curIndex2; // [esp+0h] [ebp-2C0Ch]
  int sn_value; // [esp+4h] [ebp-2C08h]
  int *dataSn; // [esp+18h] [ebp-2BF4h]
  int max; // [esp+1Ch] [ebp-2BF0h]
  int v60; // [esp+20h] [ebp-2BECh]
  int m_Index; // [esp+24h] [ebp-2BE8h]
  int v62; // [esp+28h] [ebp-2BE4h]
  int index; // [esp+2Ch] [ebp-2BE0h]
  int stepIndex; // [esp+30h] [ebp-2BDCh]
  int v65; // [esp+34h] [ebp-2BD8h]
  int curIndex; // [esp+38h] [ebp-2BD4h]
  int keyValue; // [esp+3Ch] [ebp-2BD0h]
  int m; // [esp+40h] [ebp-2BCCh]
  int m2; // [esp+44h] [ebp-2BC8h]
  int snLen; // [esp+48h] [ebp-2BC4h]
  int v71; // [esp+4Ch] [ebp-2BC0h]
  int step; // [esp+50h] [ebp-2BBCh]
  char *(__cdecl *v73)(intint__int64, _BYTE *, int); // [esp+64h] [ebp-2BA8h]
  int *v74; // [esp+68h] [ebp-2BA4h]
  int *v75; // [esp+6Ch] [ebp-2BA0h]
  void *v76; // [esp+70h] [ebp-2B9Ch]
  int *v77; // [esp+74h] [ebp-2B98h]
  struct vector lastKeyTable; // [esp+80h] [ebp-2B8Ch]
  struct vector v79; // [esp+8Ch] [ebp-2B80h]
  struct vector keyVector; // [esp+98h] [ebp-2B74h]
  struct vector temKeyValueVetor; // [esp+A4h] [ebp-2B68h]
  int inputSn; // [esp+C0h] [ebp-2B4Ch]
  unsigned __int8 v83; // [esp+1C0h] [ebp-2A4Ch]
  int v84; // [esp+2C0h] [ebp-294Ch]
  struct DataTable newKeyTable; // [esp+3C0h] [ebp-284Ch]
  struct DataTable key2Table; // [esp+17D0h] [ebp-143Ch]
  int v87; // [esp+2BE0h] [ebp-2Ch]
  int *v88; // [esp+2BE8h] [ebp-24h]
  int v89; // [esp+2BECh] [ebp-20h]
  int v90; // [esp+2BF0h] [ebp-1Ch]
  int v91; // [esp+2BF4h] [ebp-18h]
  int v92; // [esp+2BF8h] [ebp-14h]
  int v93; // [esp+2BFCh] [ebp-10h]
  int retaddr; // [esp+2C0Ch] [ebp+0h]
 
  v93 = retaddr;
  v92 = v4;
  v91 = cur1;
  v90 = v6;
  v89 = v3;
  v88 = &argc;
  v7 = alloca(11240);
  v73 = sub_4B85B0;
  v74 = dword_4B9D1C;
  v76 = &loc_4B9827;
  v75 = &v87;
  v77 = &curIndex2;
  sub_40D9D0(&v71);
  sub_40C510();
  ChangeKeyByAddr(v8, v9, v6, 0, 0x25A);
  step = -1;
  ChangeKeyAndAntiDebug(v10, v11, v3, v6, 0x1000);
  create0x400Random(&newKeyTable);
  step = 1;
  create0x400Random(&key2Table);
  step = 2;
  sub_4B5240((int)&stdio, &inputSn);
  for ( snLen = 0; ; ++snLen )
  {
    v13 = snLen;
    if ( !*((_BYTE *)&v92 + snLen - 0x2B38) )
      break;
  }
  i = 0;
  LOBYTE(v3) = 0x37;
  while ( i != snLen )
  {
    LOBYTE(v13) = *((_BYTE *)&v92 + i - 0x2B38);// sn
    LOBYTE(v12) = '0';
    if ( (char)v13 > '9' )
    {
      LOBYTE(v12) = '=';
      if ( (char)v13 < 'a' )
        v12 = v3;
    }
    v15 = v13 - v12;
    *((_BYTE *)&v92 + i - 0x2A38) = v15;        // data_sn
    v13 = v15 - 1;
    if ( (unsigned __int8)v13 > 0xEu )
      goto LABEL_61;
    ++i;
  }
  v16 = (char *)&v84;
  dataSN = &v83;
  *((_BYTE *)&v92 + snLen - 0x2A38) = 0;
  while ( snLen )
  {
    dataSnEnd = &v83 + snLen;
    do
    {
      v19 = *dataSnEnd % 0xAu;
      *dataSnEnd /= 0xAu;
      *(dataSnEnd-- - 1) += 16 * v19;
    }
    while ( &v83 != dataSnEnd );
    v20 = v83 % 0xAu;
    v83 /= 0xAu;
    *v16 = v20;                                 // 余数
    do
    {
      cur1 = snLen;
      v21 = snLen - 1;
      if ( *(&v83 + snLen - 1) )
        break;
      --snLen;
    }                                           // ((c0*0X0a+c1)*0x0a + c2) ....
    while ( v21 );
    ++v16;
  }
  step = 2;
  SetTableAndDiv0x0A(&newKeyTable, &source, 0x10);
  sn_value = SetTableAndDiv0x0A(&key2Table, &byte_4BC088, 16);
  table_Mul_Tablue((struct DataTable *)v16, &newKeyTable, &key2Table);
  curIndex2 = cur1;
  CallTableDiv(&newKeyTable);                   // 转换成new constKeyTable 
  lastKeyTable.start = 0;
  lastKeyTable.last = 0;
  lastKeyTable.end = 0;
  v62 = 0;
  v65 = 0;
  index = 0;
  m = 0;
  while ( 1 )
  {
    step = 3;
    num = GetTableNum(&newKeyTable);
    if ( index >= num )
      break;
    keyValue = GetTableValueByIndex(&newKeyTable, index);
    keyVector.start = 0;
    keyVector.last = 0;
    keyVector.end = 0;
    tempBuf = (int *)malloc_0(0x510);
    malocBufEnd = tempBuf + 0x144;
    keyVectorBuf = tempBuf;
    keyVector.start = tempBuf;
    k = 0;
    keyVector.end = malocBufEnd;
    do
    {
      keyVectorBuf[k] = 0;                      // clear buf
      ++k;
    }
    while ( k != 0x144 );
    keyVector.last = malocBufEnd;
    if ( keyValue )
    {
      if ( keyValue <= 9 )
      {
        m1 = m;
        keyVectorBuf[(_DWORD)m1] = 1;
        leftValue = m1 % 9;
        keyValue1 = keyValue;
        keyVectorBuf[keyValue + 9 * (unsigned int)(m1 / 9) + 0x50] = 1;
        LODWORD(m1) = keyValue1 + 9 * (unsigned __int64)(m1 % 9) + 0xA1;
        cur1 = 3;
        keyVectorBuf[(_DWORD)m1] = 1;
        dataSN = (unsigned __int8 *)keyValue;
        keyVectorBuf[keyValue + 9 * (3 * (m / 27) + (signed int)leftValue / 3) + 0xF2] = 1;
        step = 4;
        Vector_push(&lastKeyTable, &keyVector);
        stepIndex = v65 + 1;
        sn_value = SetTableValueByIndex(&g_snTable, v65, keyValue);// 对于constKey 小于等于9 插入到g_snTable中,大于不放
        curIndex2 = sn_value;
        ++m;
      }
      else
      {
        curIndex = 0;
        dataSn = (int *)((char *)&v92 + v62 - 0x2938);// 获取SN指针
        while ( 1 )
        {
          m_Index = curIndex + v62;
          stepIndex = curIndex + v65;
          m2 = curIndex + m;
          if ( curIndex >= keyValue - 9 )
            break;
          curIndex1 = curIndex;
          sn_value = *((unsigned __int8 *)dataSn + curIndex);// 取出SN
          step = 4;
          SetTableValueByIndex(&g_snTable, stepIndex, sn_value);
          sn_value = curIndex1;
          curIndex2 = curIndex1;
          m_Index = 4 * m2;
          muti9_Value = 9 * (m2 / 9);
          stepIndex = 36 * (m2 / 9) + 0x144;
          max = 36 * (m2 / 9) + 0x168;
          v60 = 4 * (9 * (m2 % 9) - muti9_Value);
          m2 = 4 * (9 * (m2 % 9 / 3 + 3 * (m2 / 27)) - muti9_Value);
          do
          {
            temKeyValueVetor.start = 0;
            temKeyValueVetor.last = 0;
            temKeyValueVetor.end = 0;
            step = 4;
            tempBuf1 = (int *)malloc_0(0x510);
            temKeyValueVetor.start = tempBuf1;
            i1 = 0;
            temKeyValueVetor.end = tempBuf1 + 0x144;
            do
            {
              tempBuf1[i1] = 0;
              ++i1;
            }
            while ( i1 != 0x144 );
            cur1 = stepIndex;
            v31 = v60;
            temKeyValueVetor.last = tempBuf1 + 0x144;
            *(int *)((char *)tempBuf1 + m_Index) = 1;// 0
            *(int *)((char *)tempBuf1 + cur1) = 1;// 51
            pmalloc2Buf = (int *)((char *)tempBuf1 + v31);
            v33 = (int *)((char *)tempBuf1 + m2);
            *(int *)((char *)pmalloc2Buf + cur1 + 0x144) = 1;// A1
            *(int *)((char *)v33 + cur1 + 0x288) = 1;// F2
            step = 5;
            Vector_push(&lastKeyTable, &temKeyValueVetor);
            curIndex2 = v34;
            free_0((int *)&temKeyValueVetor);
            stepIndex += 4;
            dataSN = (unsigned __int8 *)stepIndex;
          }
          while ( max != stepIndex );
          ++curIndex;
        }
        step = 4;
        nextKeyValue = GetTableValueByIndex(&newKeyTable, index + 1);
        curIndex2 = v36;
        if ( nextKeyValue <= 9 )
        {
          v62 = m_Index;
          m = m2;
        }
        else
        {
          m = 0;
          keyValue = 0;
          do
          {
            v37 = *(int *)((char *)&off_4BC020 + keyValue);
            step = 4;
            ++m;                                // 应该等于9
            keyValue += 4;
          }
          while ( keyValue != 0x24 );
          v38 = keyVector.start;
          cnt_9 = m;
          m3 = m2;
          keyVector.start[m3] = 1;
          v41 = m3 % 9;
          v38[cnt_9 + 9 * (unsigned int)(m3 / 9) + 0x50] = 1;
          LODWORD(m3) = cnt_9 + 9 * (unsigned __int64)(m3 % 9) + 0xA1;
          cur1 = 3;
          v38[(_DWORD)m3] = 1;
          dataSN = (unsigned __int8 *)m;
          v38[m + 9 * (3 * (m2 / 27) + (signed int)v41 / 3) + 0xF2] = 1;
          step = 4;
          curIndex2 = (int)Vector_push(&lastKeyTable, &keyVector);
          m = m2 + 1;
          v62 = m_Index;
        }
      }
    }
    else
    {
      stepIndex = v65;
    }
    free_0((int *)&keyVector);
    ++index;
    v65 = stepIndex;
  }
  step = 3;
  sub_402BEE(
    &temKeyValueVetor,
    (int)&lastKeyTable,
    0xAAAAAAAB * ((_DWORD)((char *)lastKeyTable.last - (char *)lastKeyTable.start) >> 2),
    0x144);
  step = 6;
  v45 = sub_402DB6(&temKeyValueVetor, 0);
  curIndex2 = cur1;
  if ( v45 )
  {
    step = 6;
    vectorCpy(&v79, (struct vector *)((char *)&temKeyValueVetor + 4));
    curIndex2 = (int)dataSN;
    m = 0;
    keyValue = 0;
    do
    {
      v46 = keyValue;
      curIndex2 = (int)&lastKeyTable.start[3 * (*(int *)((char *)v79.start + keyValue) - 1)];
      step = 8;
      vectorCpy(&keyVector, (struct vector *)curIndex2);
      curIndex2 = v46;
      m2 = 0;
      do
      {
        if ( keyVector.start[m2] == 1 )
          break;
        ++m2;
      }
      while ( m2 != 81 );
      if ( m2 == 0x28 )
      {
        --m;
      }
      else
      {
        m2 -= m2 >= 41;
        v47 = 0;
        do
        {
          if ( keyVector.start[v47 + 81] == 1 )
            break;
          ++v47;
        }
        while ( v47 != 81 );
        curIndex = v47 % 9 + 1;
        step = 7;
        GetTableValueByIndex(&g_snTable, m2);
        v65 = (int)off_4BC060;
        v48 = GetTableValueByIndex(&g_snTable, m2);
        curIndex2 = v49;
        m += curIndex == *(unsigned __int8 *)(v65 + v48);
      }
      free_0((int *)&keyVector);
      keyValue += 4;
    }
    while ( keyValue != 0x144 );
    v50 = off_4BC05C;
    v51 = 0;
    do
    {
      v52 = (unsigned __int8)v50[v51];
      snLen += 9 * (v52 ^ m) ^ 0x37;
      v53 = m == v52;
      v50[v51] = v52 ^ m;
      if ( v53 )
        break;
      ++v51;
    }
    while ( v51 != 0x201 );
    if ( snLen == 0x1F1A )                      // 成功
    {
      step = 8;
      v54 = (_DWORD *)sub_4B3F00((int)&dword_4BD9A0, off_4BC05C);// 输出
      sub_4B0DB0(v54);
    }
    free_0((int *)&v79);
  }
  j_free(temKeyValueVetor.start);
  free_0((int *)&temKeyValueVetor.last);
  sub_402966((int *)&lastKeyTable);
LABEL_61:
  nop();
  nop();
  sub_40DA40(&v71);
  return 0;
}
流程如下:
1、调用 40D9D0  40C510 进行初始化变量同时初始化g_snTable(4C8020)用于最后校验的一个表,里面包含输入sn信息。
2、进行如下调用,
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
nt __usercall sub_4025D3@<eax>(int a1@<edx>, int a2@<ecx>, int a3@<esi>)
{
  int v3; // edx
  unsigned __int8 v4; // cf
  unsigned int v5; // ST00_4
  int v6; // eax
  int v8; // [esp+1Ch] [ebp-Ch]
 
  ChangeKeyByAddr(a1, a2, a3, ChangeKeyByAddr, 104);
  JUMPOUT(!(v4 | (v3 == -1)), (char *)&loc_402624 + 6);
  __writeeflags(v5);
  v6 = GetCurrentProcess();
  CheckRemoteDebuggerPresent(v6, (char *)&v8 + 1);
  return *(int *)((char *)&v8 + 1);
}
 
signed int sub_4028B3()
{
  signed int v1; // [esp+18h] [ebp-10h]
  int v2; // [esp+1Ch] [ebp-Ch]
 
  v2 = 0;
  v1 = 0;
  if ( !setjmp3(Buf, 0) )
  {
    __debugbreak();
    v2 = SetUnhandledExceptionFilter(sub_40254C);
    v1 = 1;
  }
  SetUnhandledExceptionFilter(v2);
  return v1;
}
 在前面去混淆的时候直接让call eax,变为xor eax,eax,不去调用9个反调试函数,并能够使返回结果累加为9。(可能会使后面的计算key有误,先暂时这样处理)
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
nt __usercall sub_4025D3@<eax>(int a1@<edx>, int a2@<ecx>, int a3@<esi>)
{
  int v3; // edx
  unsigned __int8 v4; // cf
  unsigned int v5; // ST00_4
  int v6; // eax
  int v8; // [esp+1Ch] [ebp-Ch]
 
  ChangeKeyByAddr(a1, a2, a3, ChangeKeyByAddr, 104);
  JUMPOUT(!(v4 | (v3 == -1)), (char *)&loc_402624 + 6);
  __writeeflags(v5);
  v6 = GetCurrentProcess();
  CheckRemoteDebuggerPresent(v6, (char *)&v8 + 1);
  return *(int *)((char *)&v8 + 1);
}
 
signed int sub_4028B3()
{
  signed int v1; // [esp+18h] [ebp-10h]
  int v2; // [esp+1Ch] [ebp-Ch]
 
  v2 = 0;
  v1 = 0;
  if ( !setjmp3(Buf, 0) )
  {
    __debugbreak();
    v2 = SetUnhandledExceptionFilter(sub_40254C);
    v1 = 1;
  }
  SetUnhandledExceptionFilter(v2);
  return v1;
}
 在前面去混淆的时候直接让call eax,变为xor eax,eax,不去调用9个反调试函数,并能够使返回结果累加为9。(可能会使后面的计算key有误,先暂时这样处理)
至此准备工作做完,开始进行分析。
三、main 函数
去掉混淆后main函数如下:
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
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // ebx
  int v4; // ebp
  int cur1; // edi
  int v6; // esi
  void *v7; // esp
  int v8; // edx
  int v9; // ecx
  int v10; // edx
  int v11; // ecx
  int v12; // ecx
  int v13; // eax
  int i; // edx
  int v15; // eax
  char *v16; // ebx
  unsigned __int8 *dataSN; // esi
  unsigned __int8 *dataSnEnd; // edx
  char v19; // t2
  char v20; // ah
  int v21; // eax
  int num; // eax
  int *tempBuf; // eax
  int *malocBufEnd; // edx
  int *keyVectorBuf; // ebx
  int k; // eax
  int curIndex1; // ebx
  int muti9_Value; // ebx
  int *tempBuf1; // eax
  int i1; // edx
  int v31; // ebx
  int *pmalloc2Buf; // edx
  int *v33; // eax
  int v34; // ecx
  signed int nextKeyValue; // eax
  int v36; // edx
  int v37; // et1
  int *v38; // ebx
  int cnt_9; // edi
  __int64 m3; // rax
  signed __int64 v41; // rt2
  __int64 m1; // rax
  signed __int64 leftValue; // rt2
  int keyValue1; // edi
  char v45; // al
  int v46; // ebx
  int v47; // eax
  signed int v48; // eax
  int v49; // edx
  char *v50; // ecx
  int v51; // eax
  int v52; // ebx
  bool v53; // zf
  _DWORD *v54; // eax
  int curIndex2; // [esp+0h] [ebp-2C0Ch]
  int sn_value; // [esp+4h] [ebp-2C08h]
  int *dataSn; // [esp+18h] [ebp-2BF4h]
  int max; // [esp+1Ch] [ebp-2BF0h]
  int v60; // [esp+20h] [ebp-2BECh]
  int m_Index; // [esp+24h] [ebp-2BE8h]
  int v62; // [esp+28h] [ebp-2BE4h]
  int index; // [esp+2Ch] [ebp-2BE0h]
  int stepIndex; // [esp+30h] [ebp-2BDCh]
  int v65; // [esp+34h] [ebp-2BD8h]
  int curIndex; // [esp+38h] [ebp-2BD4h]
  int keyValue; // [esp+3Ch] [ebp-2BD0h]
  int m; // [esp+40h] [ebp-2BCCh]
  int m2; // [esp+44h] [ebp-2BC8h]
  int snLen; // [esp+48h] [ebp-2BC4h]
  int v71; // [esp+4Ch] [ebp-2BC0h]
  int step; // [esp+50h] [ebp-2BBCh]
  char *(__cdecl *v73)(intint__int64, _BYTE *, int); // [esp+64h] [ebp-2BA8h]
  int *v74; // [esp+68h] [ebp-2BA4h]
  int *v75; // [esp+6Ch] [ebp-2BA0h]
  void *v76; // [esp+70h] [ebp-2B9Ch]
  int *v77; // [esp+74h] [ebp-2B98h]
  struct vector lastKeyTable; // [esp+80h] [ebp-2B8Ch]
  struct vector v79; // [esp+8Ch] [ebp-2B80h]
  struct vector keyVector; // [esp+98h] [ebp-2B74h]
  struct vector temKeyValueVetor; // [esp+A4h] [ebp-2B68h]
  int inputSn; // [esp+C0h] [ebp-2B4Ch]
  unsigned __int8 v83; // [esp+1C0h] [ebp-2A4Ch]
  int v84; // [esp+2C0h] [ebp-294Ch]
  struct DataTable newKeyTable; // [esp+3C0h] [ebp-284Ch]
  struct DataTable key2Table; // [esp+17D0h] [ebp-143Ch]
  int v87; // [esp+2BE0h] [ebp-2Ch]
  int *v88; // [esp+2BE8h] [ebp-24h]
  int v89; // [esp+2BECh] [ebp-20h]
  int v90; // [esp+2BF0h] [ebp-1Ch]
  int v91; // [esp+2BF4h] [ebp-18h]
  int v92; // [esp+2BF8h] [ebp-14h]
  int v93; // [esp+2BFCh] [ebp-10h]
  int retaddr; // [esp+2C0Ch] [ebp+0h]
 
  v93 = retaddr;
  v92 = v4;
  v91 = cur1;
  v90 = v6;
  v89 = v3;
  v88 = &argc;
  v7 = alloca(11240);
  v73 = sub_4B85B0;
  v74 = dword_4B9D1C;
  v76 = &loc_4B9827;
  v75 = &v87;
  v77 = &curIndex2;
  sub_40D9D0(&v71);
  sub_40C510();
  ChangeKeyByAddr(v8, v9, v6, 0, 0x25A);
  step = -1;
  ChangeKeyAndAntiDebug(v10, v11, v3, v6, 0x1000);
  create0x400Random(&newKeyTable);
  step = 1;
  create0x400Random(&key2Table);
  step = 2;
  sub_4B5240((int)&stdio, &inputSn);
  for ( snLen = 0; ; ++snLen )
  {
    v13 = snLen;
    if ( !*((_BYTE *)&v92 + snLen - 0x2B38) )
      break;
  }
  i = 0;
  LOBYTE(v3) = 0x37;
  while ( i != snLen )
  {
    LOBYTE(v13) = *((_BYTE *)&v92 + i - 0x2B38);// sn
    LOBYTE(v12) = '0';
    if ( (char)v13 > '9' )
    {
      LOBYTE(v12) = '=';
      if ( (char)v13 < 'a' )
        v12 = v3;
    }
    v15 = v13 - v12;
    *((_BYTE *)&v92 + i - 0x2A38) = v15;        // data_sn
    v13 = v15 - 1;
    if ( (unsigned __int8)v13 > 0xEu )
      goto LABEL_61;
    ++i;
  }
  v16 = (char *)&v84;
  dataSN = &v83;
  *((_BYTE *)&v92 + snLen - 0x2A38) = 0;
  while ( snLen )
  {
    dataSnEnd = &v83 + snLen;
    do
    {
      v19 = *dataSnEnd % 0xAu;
      *dataSnEnd /= 0xAu;
      *(dataSnEnd-- - 1) += 16 * v19;
    }
    while ( &v83 != dataSnEnd );
    v20 = v83 % 0xAu;
    v83 /= 0xAu;
    *v16 = v20;                                 // 余数
    do
    {
      cur1 = snLen;
      v21 = snLen - 1;
      if ( *(&v83 + snLen - 1) )
        break;
      --snLen;
    }                                           // ((c0*0X0a+c1)*0x0a + c2) ....
    while ( v21 );
    ++v16;
  }
  step = 2;
  SetTableAndDiv0x0A(&newKeyTable, &source, 0x10);
  sn_value = SetTableAndDiv0x0A(&key2Table, &byte_4BC088, 16);
  table_Mul_Tablue((struct DataTable *)v16, &newKeyTable, &key2Table);
  curIndex2 = cur1;
  CallTableDiv(&newKeyTable);                   // 转换成new constKeyTable 
  lastKeyTable.start = 0;
  lastKeyTable.last = 0;
  lastKeyTable.end = 0;
  v62 = 0;
  v65 = 0;
  index = 0;
  m = 0;
  while ( 1 )
  {
    step = 3;
    num = GetTableNum(&newKeyTable);
    if ( index >= num )
      break;
    keyValue = GetTableValueByIndex(&newKeyTable, index);
    keyVector.start = 0;
    keyVector.last = 0;
    keyVector.end = 0;
    tempBuf = (int *)malloc_0(0x510);
    malocBufEnd = tempBuf + 0x144;
    keyVectorBuf = tempBuf;
    keyVector.start = tempBuf;
    k = 0;
    keyVector.end = malocBufEnd;
    do
    {
      keyVectorBuf[k] = 0;                      // clear buf
      ++k;
    }
    while ( k != 0x144 );
    keyVector.last = malocBufEnd;
    if ( keyValue )
    {
      if ( keyValue <= 9 )
      {
        m1 = m;
        keyVectorBuf[(_DWORD)m1] = 1;
        leftValue = m1 % 9;
        keyValue1 = keyValue;
        keyVectorBuf[keyValue + 9 * (unsigned int)(m1 / 9) + 0x50] = 1;
        LODWORD(m1) = keyValue1 + 9 * (unsigned __int64)(m1 % 9) + 0xA1;
        cur1 = 3;
        keyVectorBuf[(_DWORD)m1] = 1;
        dataSN = (unsigned __int8 *)keyValue;
        keyVectorBuf[keyValue + 9 * (3 * (m / 27) + (signed int)leftValue / 3) + 0xF2] = 1;
        step = 4;
        Vector_push(&lastKeyTable, &keyVector);
        stepIndex = v65 + 1;
        sn_value = SetTableValueByIndex(&g_snTable, v65, keyValue);// 对于constKey 小于等于9 插入到g_snTable中,大于不放
        curIndex2 = sn_value;
        ++m;
      }
      else
      {
        curIndex = 0;
        dataSn = (int *)((char *)&v92 + v62 - 0x2938);// 获取SN指针
        while ( 1 )
        {
          m_Index = curIndex + v62;
          stepIndex = curIndex + v65;
          m2 = curIndex + m;
          if ( curIndex >= keyValue - 9 )
            break;
          curIndex1 = curIndex;
          sn_value = *((unsigned __int8 *)dataSn + curIndex);// 取出SN
          step = 4;
          SetTableValueByIndex(&g_snTable, stepIndex, sn_value);
          sn_value = curIndex1;
          curIndex2 = curIndex1;
          m_Index = 4 * m2;
          muti9_Value = 9 * (m2 / 9);
          stepIndex = 36 * (m2 / 9) + 0x144;
          max = 36 * (m2 / 9) + 0x168;
          v60 = 4 * (9 * (m2 % 9) - muti9_Value);
          m2 = 4 * (9 * (m2 % 9 / 3 + 3 * (m2 / 27)) - muti9_Value);
          do
          {
            temKeyValueVetor.start = 0;
            temKeyValueVetor.last = 0;
            temKeyValueVetor.end = 0;
            step = 4;
            tempBuf1 = (int *)malloc_0(0x510);
            temKeyValueVetor.start = tempBuf1;
            i1 = 0;
            temKeyValueVetor.end = tempBuf1 + 0x144;
            do
            {
              tempBuf1[i1] = 0;
              ++i1;
            }
            while ( i1 != 0x144 );
            cur1 = stepIndex;
            v31 = v60;
            temKeyValueVetor.last = tempBuf1 + 0x144;
            *(int *)((char *)tempBuf1 + m_Index) = 1;// 0
            *(int *)((char *)tempBuf1 + cur1) = 1;// 51
            pmalloc2Buf = (int *)((char *)tempBuf1 + v31);
            v33 = (int *)((char *)tempBuf1 + m2);
            *(int *)((char *)pmalloc2Buf + cur1 + 0x144) = 1;// A1
            *(int *)((char *)v33 + cur1 + 0x288) = 1;// F2
            step = 5;
            Vector_push(&lastKeyTable, &temKeyValueVetor);
            curIndex2 = v34;
            free_0((int *)&temKeyValueVetor);
            stepIndex += 4;
            dataSN = (unsigned __int8 *)stepIndex;
          }
          while ( max != stepIndex );
          ++curIndex;
        }
        step = 4;
        nextKeyValue = GetTableValueByIndex(&newKeyTable, index + 1);
        curIndex2 = v36;
        if ( nextKeyValue <= 9 )
        {
          v62 = m_Index;
          m = m2;
        }
        else
        {
          m = 0;
          keyValue = 0;
          do
          {
            v37 = *(int *)((char *)&off_4BC020 + keyValue);
            step = 4;
            ++m;                                // 应该等于9
            keyValue += 4;
          }
          while ( keyValue != 0x24 );
          v38 = keyVector.start;
          cnt_9 = m;
          m3 = m2;
          keyVector.start[m3] = 1;
          v41 = m3 % 9;
          v38[cnt_9 + 9 * (unsigned int)(m3 / 9) + 0x50] = 1;
          LODWORD(m3) = cnt_9 + 9 * (unsigned __int64)(m3 % 9) + 0xA1;
          cur1 = 3;
          v38[(_DWORD)m3] = 1;
          dataSN = (unsigned __int8 *)m;
          v38[m + 9 * (3 * (m2 / 27) + (signed int)v41 / 3) + 0xF2] = 1;
          step = 4;
          curIndex2 = (int)Vector_push(&lastKeyTable, &keyVector);
          m = m2 + 1;
          v62 = m_Index;
        }
      }
    }
    else
    {
      stepIndex = v65;
    }
    free_0((int *)&keyVector);
    ++index;
    v65 = stepIndex;
  }
  step = 3;
  sub_402BEE(
    &temKeyValueVetor,
    (int)&lastKeyTable,
    0xAAAAAAAB * ((_DWORD)((char *)lastKeyTable.last - (char *)lastKeyTable.start) >> 2),
    0x144);
  step = 6;
  v45 = sub_402DB6(&temKeyValueVetor, 0);
  curIndex2 = cur1;
  if ( v45 )
  {
    step = 6;
    vectorCpy(&v79, (struct vector *)((char *)&temKeyValueVetor + 4));
    curIndex2 = (int)dataSN;
    m = 0;
    keyValue = 0;
    do
    {
      v46 = keyValue;
      curIndex2 = (int)&lastKeyTable.start[3 * (*(int *)((char *)v79.start + keyValue) - 1)];
      step = 8;
      vectorCpy(&keyVector, (struct vector *)curIndex2);
      curIndex2 = v46;
      m2 = 0;
      do
      {
        if ( keyVector.start[m2] == 1 )
          break;
        ++m2;
      }
      while ( m2 != 81 );
      if ( m2 == 0x28 )
      {
        --m;
      }
      else
      {
        m2 -= m2 >= 41;
        v47 = 0;
        do
        {
          if ( keyVector.start[v47 + 81] == 1 )
            break;
          ++v47;
        }
        while ( v47 != 81 );
        curIndex = v47 % 9 + 1;
        step = 7;
        GetTableValueByIndex(&g_snTable, m2);
        v65 = (int)off_4BC060;
        v48 = GetTableValueByIndex(&g_snTable, m2);
        curIndex2 = v49;
        m += curIndex == *(unsigned __int8 *)(v65 + v48);
      }
      free_0((int *)&keyVector);
      keyValue += 4;
    }
    while ( keyValue != 0x144 );
    v50 = off_4BC05C;
    v51 = 0;
    do
    {
      v52 = (unsigned __int8)v50[v51];
      snLen += 9 * (v52 ^ m) ^ 0x37;
      v53 = m == v52;
      v50[v51] = v52 ^ m;
      if ( v53 )
        break;
      ++v51;
    }
    while ( v51 != 0x201 );
    if ( snLen == 0x1F1A )                      // 成功
    {
      step = 8;
      v54 = (_DWORD *)sub_4B3F00((int)&dword_4BD9A0, off_4BC05C);// 输出
      sub_4B0DB0(v54);
    }
    free_0((int *)&v79);
  }
  j_free(temKeyValueVetor.start);
  free_0((int *)&temKeyValueVetor.last);
  sub_402966((int *)&lastKeyTable);
LABEL_61:
  nop();
  nop();
  sub_40DA40(&v71);
  return 0;
}
流程如下:
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
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // ebx
  int v4; // ebp
  int cur1; // edi
  int v6; // esi
  void *v7; // esp
  int v8; // edx
  int v9; // ecx
  int v10; // edx
  int v11; // ecx
  int v12; // ecx
  int v13; // eax
  int i; // edx
  int v15; // eax
  char *v16; // ebx
  unsigned __int8 *dataSN; // esi
  unsigned __int8 *dataSnEnd; // edx
  char v19; // t2
  char v20; // ah
  int v21; // eax
  int num; // eax
  int *tempBuf; // eax
  int *malocBufEnd; // edx
  int *keyVectorBuf; // ebx
  int k; // eax
  int curIndex1; // ebx
  int muti9_Value; // ebx
  int *tempBuf1; // eax
  int i1; // edx
  int v31; // ebx
  int *pmalloc2Buf; // edx
  int *v33; // eax
  int v34; // ecx
  signed int nextKeyValue; // eax
  int v36; // edx
  int v37; // et1
  int *v38; // ebx
  int cnt_9; // edi
  __int64 m3; // rax
  signed __int64 v41; // rt2
  __int64 m1; // rax
  signed __int64 leftValue; // rt2
  int keyValue1; // edi
  char v45; // al
  int v46; // ebx
  int v47; // eax
  signed int v48; // eax
  int v49; // edx
  char *v50; // ecx
  int v51; // eax
  int v52; // ebx
  bool v53; // zf
  _DWORD *v54; // eax
  int curIndex2; // [esp+0h] [ebp-2C0Ch]
  int sn_value; // [esp+4h] [ebp-2C08h]
  int *dataSn; // [esp+18h] [ebp-2BF4h]
  int max; // [esp+1Ch] [ebp-2BF0h]
  int v60; // [esp+20h] [ebp-2BECh]
  int m_Index; // [esp+24h] [ebp-2BE8h]
  int v62; // [esp+28h] [ebp-2BE4h]
  int index; // [esp+2Ch] [ebp-2BE0h]
  int stepIndex; // [esp+30h] [ebp-2BDCh]
  int v65; // [esp+34h] [ebp-2BD8h]
  int curIndex; // [esp+38h] [ebp-2BD4h]
  int keyValue; // [esp+3Ch] [ebp-2BD0h]
  int m; // [esp+40h] [ebp-2BCCh]
  int m2; // [esp+44h] [ebp-2BC8h]
  int snLen; // [esp+48h] [ebp-2BC4h]
  int v71; // [esp+4Ch] [ebp-2BC0h]
  int step; // [esp+50h] [ebp-2BBCh]
  char *(__cdecl *v73)(intint__int64, _BYTE *, int); // [esp+64h] [ebp-2BA8h]
  int *v74; // [esp+68h] [ebp-2BA4h]
  int *v75; // [esp+6Ch] [ebp-2BA0h]
  void *v76; // [esp+70h] [ebp-2B9Ch]
  int *v77; // [esp+74h] [ebp-2B98h]
  struct vector lastKeyTable; // [esp+80h] [ebp-2B8Ch]
  struct vector v79; // [esp+8Ch] [ebp-2B80h]
  struct vector keyVector; // [esp+98h] [ebp-2B74h]
  struct vector temKeyValueVetor; // [esp+A4h] [ebp-2B68h]
  int inputSn; // [esp+C0h] [ebp-2B4Ch]
  unsigned __int8 v83; // [esp+1C0h] [ebp-2A4Ch]
  int v84; // [esp+2C0h] [ebp-294Ch]
  struct DataTable newKeyTable; // [esp+3C0h] [ebp-284Ch]
  struct DataTable key2Table; // [esp+17D0h] [ebp-143Ch]
  int v87; // [esp+2BE0h] [ebp-2Ch]
  int *v88; // [esp+2BE8h] [ebp-24h]
  int v89; // [esp+2BECh] [ebp-20h]
  int v90; // [esp+2BF0h] [ebp-1Ch]
  int v91; // [esp+2BF4h] [ebp-18h]
  int v92; // [esp+2BF8h] [ebp-14h]
  int v93; // [esp+2BFCh] [ebp-10h]
  int retaddr; // [esp+2C0Ch] [ebp+0h]
 
  v93 = retaddr;
  v92 = v4;
  v91 = cur1;
  v90 = v6;
  v89 = v3;
  v88 = &argc;
  v7 = alloca(11240);
  v73 = sub_4B85B0;
  v74 = dword_4B9D1C;
  v76 = &loc_4B9827;
  v75 = &v87;
  v77 = &curIndex2;
  sub_40D9D0(&v71);
  sub_40C510();
  ChangeKeyByAddr(v8, v9, v6, 0, 0x25A);
  step = -1;
  ChangeKeyAndAntiDebug(v10, v11, v3, v6, 0x1000);
  create0x400Random(&newKeyTable);
  step = 1;
  create0x400Random(&key2Table);
  step = 2;
  sub_4B5240((int)&stdio, &inputSn);
  for ( snLen = 0; ; ++snLen )
  {
    v13 = snLen;
    if ( !*((_BYTE *)&v92 + snLen - 0x2B38) )
      break;
  }
  i = 0;
  LOBYTE(v3) = 0x37;
  while ( i != snLen )
  {
    LOBYTE(v13) = *((_BYTE *)&v92 + i - 0x2B38);// sn
    LOBYTE(v12) = '0';
    if ( (char)v13 > '9' )
    {
      LOBYTE(v12) = '=';
      if ( (char)v13 < 'a' )
        v12 = v3;
    }
    v15 = v13 - v12;
    *((_BYTE *)&v92 + i - 0x2A38) = v15;        // data_sn
    v13 = v15 - 1;
    if ( (unsigned __int8)v13 > 0xEu )
      goto LABEL_61;
    ++i;
  }
  v16 = (char *)&v84;
  dataSN = &v83;
  *((_BYTE *)&v92 + snLen - 0x2A38) = 0;
  while ( snLen )
  {
    dataSnEnd = &v83 + snLen;
    do
    {
      v19 = *dataSnEnd % 0xAu;
      *dataSnEnd /= 0xAu;
      *(dataSnEnd-- - 1) += 16 * v19;
    }
    while ( &v83 != dataSnEnd );
    v20 = v83 % 0xAu;
    v83 /= 0xAu;
    *v16 = v20;                                 // 余数
    do
    {
      cur1 = snLen;
      v21 = snLen - 1;
      if ( *(&v83 + snLen - 1) )
        break;
      --snLen;
    }                                           // ((c0*0X0a+c1)*0x0a + c2) ....
    while ( v21 );
    ++v16;
  }
  step = 2;
  SetTableAndDiv0x0A(&newKeyTable, &source, 0x10);
  sn_value = SetTableAndDiv0x0A(&key2Table, &byte_4BC088, 16);
  table_Mul_Tablue((struct DataTable *)v16, &newKeyTable, &key2Table);
  curIndex2 = cur1;
  CallTableDiv(&newKeyTable);                   // 转换成new constKeyTable 
  lastKeyTable.start = 0;
  lastKeyTable.last = 0;
  lastKeyTable.end = 0;
  v62 = 0;
  v65 = 0;
  index = 0;
  m = 0;
  while ( 1 )
  {
    step = 3;
    num = GetTableNum(&newKeyTable);
    if ( index >= num )
      break;
    keyValue = GetTableValueByIndex(&newKeyTable, index);
    keyVector.start = 0;
    keyVector.last = 0;
    keyVector.end = 0;
    tempBuf = (int *)malloc_0(0x510);
    malocBufEnd = tempBuf + 0x144;
    keyVectorBuf = tempBuf;
    keyVector.start = tempBuf;
    k = 0;
    keyVector.end = malocBufEnd;
    do
    {
      keyVectorBuf[k] = 0;                      // clear buf
      ++k;
    }
    while ( k != 0x144 );
    keyVector.last = malocBufEnd;
    if ( keyValue )
    {
      if ( keyValue <= 9 )
      {
        m1 = m;
        keyVectorBuf[(_DWORD)m1] = 1;
        leftValue = m1 % 9;
        keyValue1 = keyValue;
        keyVectorBuf[keyValue + 9 * (unsigned int)(m1 / 9) + 0x50] = 1;
        LODWORD(m1) = keyValue1 + 9 * (unsigned __int64)(m1 % 9) + 0xA1;
        cur1 = 3;
        keyVectorBuf[(_DWORD)m1] = 1;
        dataSN = (unsigned __int8 *)keyValue;
        keyVectorBuf[keyValue + 9 * (3 * (m / 27) + (signed int)leftValue / 3) + 0xF2] = 1;
        step = 4;
        Vector_push(&lastKeyTable, &keyVector);
        stepIndex = v65 + 1;
        sn_value = SetTableValueByIndex(&g_snTable, v65, keyValue);// 对于constKey 小于等于9 插入到g_snTable中,大于不放
        curIndex2 = sn_value;
        ++m;
      }
      else
      {
        curIndex = 0;
        dataSn = (int *)((char *)&v92 + v62 - 0x2938);// 获取SN指针
        while ( 1 )
        {
          m_Index = curIndex + v62;
          stepIndex = curIndex + v65;
          m2 = curIndex + m;
          if ( curIndex >= keyValue - 9 )
            break;
          curIndex1 = curIndex;
          sn_value = *((unsigned __int8 *)dataSn + curIndex);// 取出SN
          step = 4;
          SetTableValueByIndex(&g_snTable, stepIndex, sn_value);
          sn_value = curIndex1;
          curIndex2 = curIndex1;
          m_Index = 4 * m2;
          muti9_Value = 9 * (m2 / 9);
          stepIndex = 36 * (m2 / 9) + 0x144;
          max = 36 * (m2 / 9) + 0x168;
          v60 = 4 * (9 * (m2 % 9) - muti9_Value);
          m2 = 4 * (9 * (m2 % 9 / 3 + 3 * (m2 / 27)) - muti9_Value);
          do
          {
            temKeyValueVetor.start = 0;
            temKeyValueVetor.last = 0;
            temKeyValueVetor.end = 0;
            step = 4;
            tempBuf1 = (int *)malloc_0(0x510);
            temKeyValueVetor.start = tempBuf1;
            i1 = 0;
            temKeyValueVetor.end = tempBuf1 + 0x144;
            do
            {
              tempBuf1[i1] = 0;
              ++i1;
            }
            while ( i1 != 0x144 );
            cur1 = stepIndex;
            v31 = v60;
            temKeyValueVetor.last = tempBuf1 + 0x144;
            *(int *)((char *)tempBuf1 + m_Index) = 1;// 0
            *(int *)((char *)tempBuf1 + cur1) = 1;// 51
            pmalloc2Buf = (int *)((char *)tempBuf1 + v31);
            v33 = (int *)((char *)tempBuf1 + m2);
            *(int *)((char *)pmalloc2Buf + cur1 + 0x144) = 1;// A1
            *(int *)((char *)v33 + cur1 + 0x288) = 1;// F2
            step = 5;
            Vector_push(&lastKeyTable, &temKeyValueVetor);
            curIndex2 = v34;
            free_0((int *)&temKeyValueVetor);
            stepIndex += 4;
            dataSN = (unsigned __int8 *)stepIndex;
          }
          while ( max != stepIndex );
          ++curIndex;
        }
        step = 4;
        nextKeyValue = GetTableValueByIndex(&newKeyTable, index + 1);
        curIndex2 = v36;
        if ( nextKeyValue <= 9 )
        {
          v62 = m_Index;
          m = m2;
        }
        else
        {
          m = 0;
          keyValue = 0;
          do
          {
            v37 = *(int *)((char *)&off_4BC020 + keyValue);
            step = 4;
            ++m;                                // 应该等于9
            keyValue += 4;
          }
          while ( keyValue != 0x24 );
          v38 = keyVector.start;
          cnt_9 = m;
          m3 = m2;
          keyVector.start[m3] = 1;
          v41 = m3 % 9;
          v38[cnt_9 + 9 * (unsigned int)(m3 / 9) + 0x50] = 1;
          LODWORD(m3) = cnt_9 + 9 * (unsigned __int64)(m3 % 9) + 0xA1;
          cur1 = 3;
          v38[(_DWORD)m3] = 1;
          dataSN = (unsigned __int8 *)m;
          v38[m + 9 * (3 * (m2 / 27) + (signed int)v41 / 3) + 0xF2] = 1;
          step = 4;
          curIndex2 = (int)Vector_push(&lastKeyTable, &keyVector);
          m = m2 + 1;
          v62 = m_Index;
        }
      }
    }
    else
    {
      stepIndex = v65;
    }
    free_0((int *)&keyVector);
    ++index;
    v65 = stepIndex;
  }
  step = 3;
  sub_402BEE(
    &temKeyValueVetor,
    (int)&lastKeyTable,
    0xAAAAAAAB * ((_DWORD)((char *)lastKeyTable.last - (char *)lastKeyTable.start) >> 2),
    0x144);
  step = 6;
  v45 = sub_402DB6(&temKeyValueVetor, 0);
  curIndex2 = cur1;
  if ( v45 )
  {
    step = 6;
    vectorCpy(&v79, (struct vector *)((char *)&temKeyValueVetor + 4));
    curIndex2 = (int)dataSN;
    m = 0;
    keyValue = 0;
    do
    {
      v46 = keyValue;
      curIndex2 = (int)&lastKeyTable.start[3 * (*(int *)((char *)v79.start + keyValue) - 1)];
      step = 8;
      vectorCpy(&keyVector, (struct vector *)curIndex2);
      curIndex2 = v46;
      m2 = 0;
      do
      {
        if ( keyVector.start[m2] == 1 )
          break;
        ++m2;
      }
      while ( m2 != 81 );
      if ( m2 == 0x28 )
      {
        --m;
      }
      else
      {
        m2 -= m2 >= 41;
        v47 = 0;
        do
        {
          if ( keyVector.start[v47 + 81] == 1 )
            break;
          ++v47;
        }
        while ( v47 != 81 );
        curIndex = v47 % 9 + 1;
        step = 7;
        GetTableValueByIndex(&g_snTable, m2);
        v65 = (int)off_4BC060;
        v48 = GetTableValueByIndex(&g_snTable, m2);
        curIndex2 = v49;
        m += curIndex == *(unsigned __int8 *)(v65 + v48);
      }
      free_0((int *)&keyVector);
      keyValue += 4;
    }
    while ( keyValue != 0x144 );
    v50 = off_4BC05C;
    v51 = 0;
    do
    {
      v52 = (unsigned __int8)v50[v51];
      snLen += 9 * (v52 ^ m) ^ 0x37;
      v53 = m == v52;
      v50[v51] = v52 ^ m;
      if ( v53 )
        break;
      ++v51;
    }
    while ( v51 != 0x201 );
    if ( snLen == 0x1F1A )                      // 成功
    {
      step = 8;
      v54 = (_DWORD *)sub_4B3F00((int)&dword_4BD9A0, off_4BC05C);// 输出
      sub_4B0DB0(v54);
    }
    free_0((int *)&v79);
  }
  j_free(temKeyValueVetor.start);
  free_0((int *)&temKeyValueVetor.last);
  sub_402966((int *)&lastKeyTable);
LABEL_61:
  nop();
  nop();
  sub_40DA40(&v71);
  return 0;
}
流程如下:
1、调用 40D9D0  40C510 进行初始化变量同时初始化g_snTable(4C8020)用于最后校验的一个表,里面包含输入sn信息。
2、进行如下调用,
ChangeKeyByAddr  
ChangeKeyByAddr  
ChangeKeyAndAntiDebug(v10, v11, v3, v6, 0x1000);
ChangeKeyAndAntiDebug(v10, v11, v3, v6, 0x1000);

 计算出2个常数 ,我们称之为 constKey1 ,constKey2,如下:

 计算出2个常数 ,我们称之为 constKey1 ,constKey2,如下:

4BC080 该值为: 0x1093ACBD

4BC080 该值为: 0x1093ACBD

         4BC084 该值为:  0x2cF346

3、调用  create0x400Random 函数 将变量 key1Table和key2table 初始化,后面会将 0x1093ACBD与 0x2cF346放入其中

         4BC084 该值为:  0x2cF346

3、调用  create0x400Random 函数 将变量 key1Table和key2table 初始化,后面会将 0x1093ACBD与 0x2cF346放入其中
create0x400Random(&key1Table );
create0x400Random(&key1Table );
create0x400Random(&key2Table); 
create0x400Random(&key2Table); 
1) create0x400Random函数,如下:
这个表的结构如下
1
2
3
4
5
6
7
00000000 vtable          dd ?
00000004 num             dd ?                    ; XREF: table_mul_oneValue+A7/r
00000008 value           db 1024 dup(?)
00000408 index           dd 1024 dup(?)
00001408 clock1          dd ?
0000140C clock2          dd ?
00001410 DataTable       ends
1
2
3
4
5
6
7
00000000 vtable          dd ?
00000004 num             dd ?                    ; XREF: table_mul_oneValue+A7/r
00000008 value           db 1024 dup(?)
00000408 index           dd 1024 dup(?)
00001408 clock1          dd ?
0000140C clock2          dd ?
00001410 DataTable       ends

利用clock生成随机数,放在index数组里面,然后根据index的索引定位value数组的位置。
为了分析方便,直接将生成随机数的代码bypass掉,使其顺序为0-0x3FF,这样观察表中的数据比较清晰直观。相应的函数如下:

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
signed int __thiscall create0x400Random(struct DataTable *this)
{
  struct DataTable *v1; // ST0C_4
  int v2; // eax
 
  this->vtable = (int)off_4C5F30;
  v1 = this;
  v2 = clock();
  v1->clock2 = v2;
  v1->clock1 = v2;
  return create0x400RandomByClock(v1);
}
 
signed int __thiscall create0x400RandomByClock(struct DataTable *this)
{
  signed int result; // eax
 
  result = 0;
  do
  {
    this->index[result] = result;
    ++result;
  }
  while ( result != 0x400 );
//去掉后面的随机代码,让函数直接返回
  return result;
}
4、调用sub_4B5240 获取输入的sn
     将sn转换为数字,并且要求输入的字符必须是  123456789ABCDEF,其他的都是非法字符,尤其是 0字符。
     将转换为数字的sn再次进行16to10进制转换,此时生成的为一个10进制大数。比如输入是‘ABC‘’,则对应的数据为 ‘8 5 2 3‘ 小端存储。
5、调用SetTable_16To10函数
       1、将上面的两个常量放入到前面初始化的2个结构体中:key1Table和key2table

       2、同时将 将2个表中的数据由16进制转换为10进制。  0x1093ACBD  -->278113469    0x2cF346 ->2945862

       

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
int __thiscall SetTable_16To10(struct DataTable *this, _BYTE *source, int len)
{
  _BYTE *p; // eax
  int curNum; // edx
  struct DataTable *v5; // esi
  int curNum_1; // eax
 
  this->num = 0;
  for ( p = source; *p; this->value[v5->index[1]] = *(p - 1) & 0xF )
  {
    curNum = this->num;
    ++p;
    v5 = (struct DataTable *)((char *)this + 4 * curNum);
    this->num = curNum + 1;
    this->value[v5->index[0]] = (signed int)(unsigned __int8)*(p - 1) >> 4;
    this->num = curNum + 2;
  }
  while ( 1 )
  {                                             // 去掉0
    curNum_1 = this->num;
    if this->value[*(_DWORD *)&this->value[4 * curNum_1 + 0x3FC]] )
      break;
    this->num = curNum_1 - 1;
  }
  return TableDiv(this, len, 0xA);
}
6、调用table_Mul_Tablue将上面的2个10进制数据进行相乘。使其放入到 newKeyTable中。

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
signed int __thiscall create0x400Random(struct DataTable *this)
{
  struct DataTable *v1; // ST0C_4
  int v2; // eax
 
  this->vtable = (int)off_4C5F30;
  v1 = this;
  v2 = clock();
  v1->clock2 = v2;
  v1->clock1 = v2;
  return create0x400RandomByClock(v1);
}
 
signed int __thiscall create0x400RandomByClock(struct DataTable *this)
{
  signed int result; // eax
 
  result = 0;
  do
  {
    this->index[result] = result;
    ++result;
  }
  while ( result != 0x400 );
//去掉后面的随机代码,让函数直接返回
  return result;
}
4、调用sub_4B5240 获取输入的sn
     将sn转换为数字,并且要求输入的字符必须是  123456789ABCDEF,其他的都是非法字符,尤其是 0字符。
     将转换为数字的sn再次进行16to10进制转换,此时生成的为一个10进制大数。比如输入是‘ABC‘’,则对应的数据为 ‘8 5 2 3‘ 小端存储。
5、调用SetTable_16To10函数
       1、将上面的两个常量放入到前面初始化的2个结构体中:key1Table和key2table

       2、同时将 将2个表中的数据由16进制转换为10进制。  0x1093ACBD  -->278113469    0x2cF346 ->2945862

       

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
int __thiscall SetTable_16To10(struct DataTable *this, _BYTE *source, int len)
{
  _BYTE *p; // eax
  int curNum; // edx
  struct DataTable *v5; // esi
  int curNum_1; // eax
 
  this->num = 0;
  for ( p = source; *p; this->value[v5->index[1]] = *(p - 1) & 0xF )
  {
    curNum = this->num;
    ++p;
    v5 = (struct DataTable *)((char *)this + 4 * curNum);
    this->num = curNum + 1;
    this->value[v5->index[0]] = (signed int)(unsigned __int8)*(p - 1) >> 4;
    this->num = curNum + 2;
  }
  while ( 1 )
  {                                             // 去掉0
    curNum_1 = this->num;
    if this->value[*(_DWORD *)&this->value[4 * curNum_1 + 0x3FC]] )
      break;
    this->num = curNum_1 - 1;
  }
  return TableDiv(this, len, 0xA);
}
6、调用table_Mul_Tablue将上面的2个10进制数据进行相乘。使其放入到 newKeyTable中。

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
signed int __thiscall create0x400Random(struct DataTable *this)
{
  struct DataTable *v1; // ST0C_4
  int v2; // eax
 
  this->vtable = (int)off_4C5F30;
  v1 = this;
  v2 = clock();
  v1->clock2 = v2;
  v1->clock1 = v2;
  return create0x400RandomByClock(v1);
}
 
signed int __thiscall create0x400RandomByClock(struct DataTable *this)
{
  signed int result; // eax
 
  result = 0;
  do
  {
    this->index[result] = result;
    ++result;
  }
  while ( result != 0x400 );
//去掉后面的随机代码,让函数直接返回
  return result;
}
4、调用sub_4B5240 获取输入的sn
     将sn转换为数字,并且要求输入的字符必须是  123456789ABCDEF,其他的都是非法字符,尤其是 0字符。
     将转换为数字的sn再次进行16to10进制转换,此时生成的为一个10进制大数。比如输入是‘ABC‘’,则对应的数据为 ‘8 5 2 3‘ 小端存储。
5、调用SetTable_16To10函数
       1、将上面的两个常量放入到前面初始化的2个结构体中:key1Table和key2table

       2、同时将 将2个表中的数据由16进制转换为10进制。  0x1093ACBD  -->278113469    0x2cF346 ->2945862

       

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
int __thiscall SetTable_16To10(struct DataTable *this, _BYTE *source, int len)
{
  _BYTE *p; // eax
  int curNum; // edx
  struct DataTable *v5; // esi
  int curNum_1; // eax
 
  this->num = 0;
  for ( p = source; *p; this->value[v5->index[1]] = *(p - 1) & 0xF )
  {
    curNum = this->num;
    ++p;
    v5 = (struct DataTable *)((char *)this + 4 * curNum);
    this->num = curNum + 1;
    this->value[v5->index[0]] = (signed int)(unsigned __int8)*(p - 1) >> 4;
    this->num = curNum + 2;
  }
  while ( 1 )
  {                                             // 去掉0
    curNum_1 = this->num;
    if this->value[*(_DWORD *)&this->value[4 * curNum_1 + 0x3FC]] )
      break;
    this->num = curNum_1 - 1;
  }
  return TableDiv(this, len, 0xA);
}
6、调用table_Mul_Tablue将上面的2个10进制数据进行相乘。使其放入到 newKeyTable中。

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
int __thiscall SetTable_16To10(struct DataTable *this, _BYTE *source, int len)
{
  _BYTE *p; // eax
  int curNum; // edx
  struct DataTable *v5; // esi
  int curNum_1; // eax
 
  this->num = 0;
  for ( p = source; *p; this->value[v5->index[1]] = *(p - 1) & 0xF )
  {
    curNum = this->num;
    ++p;
    v5 = (struct DataTable *)((char *)this + 4 * curNum);
    this->num = curNum + 1;
    this->value[v5->index[0]] = (signed int)(unsigned __int8)*(p - 1) >> 4;
    this->num = curNum + 2;
  }
  while ( 1 )
  {                                             // 去掉0
    curNum_1 = this->num;
    if this->value[*(_DWORD *)&this->value[4 * curNum_1 + 0x3FC]] )
      break;
    this->num = curNum_1 - 1;
  }
  return TableDiv(this, len, 0xA);
}
6、调用table_Mul_Tablue将上面的2个10进制数据进行相乘。使其放入到 newKeyTable中。

table_Mul_Tablue((struct DataTable *)v16, &newKeyTable, &key2Table);

table_Mul_Tablue((struct DataTable *)v16, &newKeyTable, &key2Table);

table_Mul_Tablue((struct DataTable *)v16, &newKeyTable, &key2Table);

table_Mul_Tablue((struct DataTable *)v16, &newKeyTable, &key2Table);

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
signed int __userpurge table_Mul_Tablue@<eax>(struct DataTable *key1Table@<ebx>, struct DataTable *a2@<ecx>, struct DataTable *key2Table)
{
  int i; // esi
  void *v4; // esp
  struct DataTable *v5; // ecx
  struct DataTable *key1Table_1; // ebx
  int value; // ST00_4
  signed int v9; // edx
  int v10; // eax
  bool v11; // zf
  bool v12; // sf
  unsigned __int8 v13; // of
  struct DataTable tempVtable1; // [esp+Ch] [ebp-2838h]
  struct DataTable tempVtable2; // [esp+141Ch] [ebp-1428h]
  int div_result; // [esp+2838h] [ebp-Ch]
 
  sub_40D480(0x284Cu, (int)a2, div_result);
  i = 0;
  v4 = alloca(10316);
  key1Table_1 = v5;
  create0x400Random(&tempVtable1);
  div_result = CreatetTableAndSetValue(&tempVtable2, 0);
  if ( key1Table_1->num + key2Table->num > 0x400 )
    return 1;
  while ( i < key2Table->num )
  {
    value = (unsigned __int8)key2Table->value[key2Table->index[i]];
    tabeCopy(&tempVtable1, key1Table_1);
    tableRoR(&tempVtable1, i);
    table_mul_oneValue(&tempVtable1, value);
    v10 = table_add(&tempVtable2, v9, &tempVtable1);
    v13 = __OFSUB__(key1Table_1->num, 0x3FF);
    v11 = key1Table_1->num == 0x3FF;
    v12 = key1Table_1->num - 0x3FF < 0;
    div_result = v10;
    if ( !((unsigned __int8)(v12 ^ v13) | v11) )
      return 1;
    ++i;
  }
  create0x400RandomByClock(key1Table_1);
  tabeCopy(key1Table_1, &tempVtable2);
  return 0;
}
7、调用table_10to16 将  newKeyTable再次转换成16进制。

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
signed int __userpurge table_Mul_Tablue@<eax>(struct DataTable *key1Table@<ebx>, struct DataTable *a2@<ecx>, struct DataTable *key2Table)
{
  int i; // esi
  void *v4; // esp
  struct DataTable *v5; // ecx
  struct DataTable *key1Table_1; // ebx
  int value; // ST00_4
  signed int v9; // edx
  int v10; // eax
  bool v11; // zf
  bool v12; // sf
  unsigned __int8 v13; // of
  struct DataTable tempVtable1; // [esp+Ch] [ebp-2838h]
  struct DataTable tempVtable2; // [esp+141Ch] [ebp-1428h]
  int div_result; // [esp+2838h] [ebp-Ch]
 
  sub_40D480(0x284Cu, (int)a2, div_result);
  i = 0;
  v4 = alloca(10316);
  key1Table_1 = v5;
  create0x400Random(&tempVtable1);
  div_result = CreatetTableAndSetValue(&tempVtable2, 0);
  if ( key1Table_1->num + key2Table->num > 0x400 )
    return 1;
  while ( i < key2Table->num )
  {
    value = (unsigned __int8)key2Table->value[key2Table->index[i]];
    tabeCopy(&tempVtable1, key1Table_1);
    tableRoR(&tempVtable1, i);
    table_mul_oneValue(&tempVtable1, value);
    v10 = table_add(&tempVtable2, v9, &tempVtable1);
    v13 = __OFSUB__(key1Table_1->num, 0x3FF);
    v11 = key1Table_1->num == 0x3FF;
    v12 = key1Table_1->num - 0x3FF < 0;
    div_result = v10;
    if ( !((unsigned __int8)(v12 ^ v13) | v11) )
      return 1;
    ++i;
  }
  create0x400RandomByClock(key1Table_1);
  tabeCopy(key1Table_1, &tempVtable2);
  return 0;
}
7、调用table_10to16 将  newKeyTable再次转换成16进制。
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
signed int __userpurge table_Mul_Tablue@<eax>(struct DataTable *key1Table@<ebx>, struct DataTable *a2@<ecx>, struct DataTable *key2Table)
{
  int i; // esi
  void *v4; // esp
  struct DataTable *v5; // ecx
  struct DataTable *key1Table_1; // ebx
  int value; // ST00_4
  signed int v9; // edx
  int v10; // eax
  bool v11; // zf
  bool v12; // sf
  unsigned __int8 v13; // of
  struct DataTable tempVtable1; // [esp+Ch] [ebp-2838h]
  struct DataTable tempVtable2; // [esp+141Ch] [ebp-1428h]
  int div_result; // [esp+2838h] [ebp-Ch]
 
  sub_40D480(0x284Cu, (int)a2, div_result);
  i = 0;
  v4 = alloca(10316);
  key1Table_1 = v5;
  create0x400Random(&tempVtable1);
  div_result = CreatetTableAndSetValue(&tempVtable2, 0);
  if ( key1Table_1->num + key2Table->num > 0x400 )
    return 1;
  while ( i < key2Table->num )
  {
    value = (unsigned __int8)key2Table->value[key2Table->index[i]];
    tabeCopy(&tempVtable1, key1Table_1);
    tableRoR(&tempVtable1, i);
    table_mul_oneValue(&tempVtable1, value);
    v10 = table_add(&tempVtable2, v9, &tempVtable1);
    v13 = __OFSUB__(key1Table_1->num, 0x3FF);
    v11 = key1Table_1->num == 0x3FF;
    v12 = key1Table_1->num - 0x3FF < 0;
    div_result = v10;
    if ( !((unsigned __int8)(v12 ^ v13) | v11) )
      return 1;
    ++i;
  }
  create0x400RandomByClock(key1Table_1);
  tabeCopy(key1Table_1, &tempVtable2);
  return 0;
}
7、调用table_10to16 将  newKeyTable再次转换成16进制。
       table_10to16(&newKeyTable);
1
2
3
4
int __thiscall table_10to16(struct DataTable *this)
{
  return TableDiv(this, 10, 16);
}
8、里程碑,此时会生成一个长度为2A的16进制数据作为一个固定的key将参与到后面的计算中。这个key的数值入下:

1
2
3
4
5
6
char constKey2A[0x2A] =
    
        0x0B, 0x07, 0x09, 0x0F, 0x03, 0x0D, 0x04, 0x0B, 0x09, 0x0D, 0x05, 0x0A, 0x06, 0x0B, 0x08, 0x0C,
        0x02, 0x03, 0x0B, 0x06, 0x0C, 0x0B, 0x01, 0x0C, 0x03, 0x05, 0x0D, 0x04, 0x0B, 0x05, 0x0A, 0x01,
        0x0B, 0x07, 0x0B, 0x02, 0x0F, 0x08, 0x0E, 0x03, 0x05, 0x0B 
    };
9、生成2个大的数据结构:
1
2
3
4
int __thiscall table_10to16(struct DataTable *this)
{
  return TableDiv(this, 10, 16);
}
8、里程碑,此时会生成一个长度为2A的16进制数据作为一个固定的key将参与到后面的计算中。这个key的数值入下:

1
2
3
4
5
6
char constKey2A[0x2A] =
    
        0x0B, 0x07, 0x09, 0x0F, 0x03, 0x0D, 0x04, 0x0B, 0x09, 0x0D, 0x05, 0x0A, 0x06, 0x0B, 0x08, 0x0C,
        0x02, 0x03, 0x0B, 0x06, 0x0C, 0x0B, 0x01, 0x0C, 0x03, 0x05, 0x0D, 0x04, 0x0B, 0x05, 0x0A, 0x01,
        0x0B, 0x07, 0x0B, 0x02, 0x0F, 0x08, 0x0E, 0x03, 0x05, 0x0B 
    };
9、生成2个大的数据结构:
1
2
3
4
5
6
char constKey2A[0x2A] =
    
        0x0B, 0x07, 0x09, 0x0F, 0x03, 0x0D, 0x04, 0x0B, 0x09, 0x0D, 0x05, 0x0A, 0x06, 0x0B, 0x08, 0x0C,
        0x02, 0x03, 0x0B, 0x06, 0x0C, 0x0B, 0x01, 0x0C, 0x03, 0x05, 0x0D, 0x04, 0x0B, 0x05, 0x0A, 0x01,
        0x0B, 0x07, 0x0B, 0x02, 0x0F, 0x08, 0x0E, 0x03, 0x05, 0x0B 
    };
9、生成2个大的数据结构:
a、多个510buf 组成的vector;
b、sn与constKey2A混合在一起放入到g_sn_table中
a、多个510buf 组成的vector;
a、多个510buf 组成的vector;
b、sn与constKey2A混合在一起放入到g_sn_table中
a、对 constKey2A进行索引,当索引到0x2A个数据时就结束循环。
b、如果 constKey2A的值小于9生成一个510BUF,同时将对应小于A的值放入到 g_sn_table中。继续下一个循环
c、 如果constKey2A的值大于9, 则索引输入的10进制sn数据,放入 (x-9)个字符到 g_sn_table中,同时生成  (x-9)*9个510buf放入到vector中。
d、如果本次 constKey2A的值大于9,同时下一个也大于9,则进入到反调试流程,调用9次反调试函数,返回值为9,根据这个计数9来初始化一个510的buf,如果存在调试器,则计算的数据将使错误的。
e 、将510的buf分成4个部分每个部分长度为可以放入0x51个整数。其中0-50 放入的是索引,51-F1放入的是key值,F2开始的与余数有关。里面的数据时用索引来表示值的,如果该索引位置的数据为1,则表示该值对应的索引为相依的数据信息。
最后生成2个数据其中一个是 510buf 组成的vector 其并不与输入的sn相关,而是只与 constKey2A相关,可以认为是不变的数据。 g_sn_table放入的是 constKey2A与输入的sn的混合。放入的规则为:
a、对 constKey2A进行索引,当索引到0x2A个数据时就结束循环。
b、如果 constKey2A的值小于9生成一个510BUF,同时将对应小于A的值放入到 g_sn_table中。继续下一个循环
c、 如果constKey2A的值大于9, 则索引输入的10进制sn数据,放入 (x-9)个字符到 g_sn_table中,同时生成  (x-9)*9个510buf放入到vector中。
d、如果本次 constKey2A的值大于9,同时下一个也大于9,则进入到反调试流程,调用9次反调试函数,返回值为9,根据这个计数9来初始化一个510的buf,如果存在调试器,则计算的数据将使错误的。
e 、将510的buf分成4个部分每个部分长度为可以放入0x51个整数。其中0-50 放入的是索引,51-F1放入的是key值,F2开始的与余数有关。里面的数据时用索引来表示值的,如果该索引位置的数据为1,则表示该值对应的索引为相依的数据信息。
最后生成2个数据其中一个是 510buf 组成的vector 其并不与输入的sn相关,而是只与 constKey2A相关,可以认为是不变的数据。 g_sn_table放入的是 constKey2A与输入的sn的混合。放入的规则为:
1、如果 constKey2A[i] 大于10, 则放入  constKey2A[i]-10个sn数据到 g_sn_table 中,
2、如果小于10 ,则直接 constKey2A[i]放入 g_sn_table 中。
1、如果 constKey2A[i] 大于10, 则放入  constKey2A[i]-10个sn数据到 g_sn_table 中,
2、如果小于10 ,则直接 constKey2A[i]放入 g_sn_table 中。

10、调用  sub_402BEE
         根据前面的510 buf跟上以及一个常量 0x144生成了一个vector 链表结构,并对其进行初始化,调用如下:
       sub_402BEE(&temKeyValueVetor,(int)&lastKeyTable, ((_DWORD)((char *)lastKeyTable.last - (char *)lastKeyTable.start) >> 2), 0x144);
该函数比较大,大概分析了下数据结构。里面分配了多个0x20大小的链表结构。
11、调用 sub_402DB6
       v45 = sub_402DB6(&temKeyValueVetor, 0);
        这个函数是个递归调用的函数,仔细分析发现其中存在如下调用:
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
.data:004BC044 11 24 40 00                         off_4BC044      dd offset sub_402411    ; DATA XREF: sub_402CD0+32↑r
.data:004BC048 4C 24 40 00                                         dd offset sub_40244C
.data:004BC04C 38 1F 40 00                                         dd offset sub_401F38
.data:004BC050 9C 24 40 00                                         dd offset sub_40249C
.data:004BC054 10 25 40 00                                         dd offset sub_402510
 
_DWORD *__thiscall sub_402CD0(_DWORD *this, _DWORD *a2)
{
  _DWORD *v2; // esi
  signed int v3; // eax
  int v4; // edx
  _DWORD *result; // eax
  _DWORD *i; // edx
  _DWORD *v7; // ecx
  int v8; // ecx
 
  v2 = this;
  v3 = this[6];
  if ( v3 <= 1199 )
    ((void (__usercall *)(int@<eax>))off_4BC044[v3 % 5])(v3 / 5 / 0x3C);
  v4 = a2[3];
  result = (_DWORD *)a2[2];
  ++v2[6];
  result[3] = v4;
  *(_DWORD *)(a2[3] + 8) = result;
  for ( i = (_DWORD *)a2[1]; i != a2; i = (_DWORD *)i[1] )
  {
    result = (_DWORD *)i[3];
    while ( i != result )
    {
      v7 = (_DWORD *)result[1];
      *v7 = *result;
      *(_DWORD *)(*result + 4) = v7;
      v8 = result[4];
      result = (_DWORD *)result[3];
      --*(_DWORD *)(v8 + 28);
    }
  }
  return result;
}
通过分析off_4BC044数组对应的5个函数,整个流程如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for (int j = 0; j < 0x04; j++)
{
        for (int i = 0; i < 0x3C; i++)
        {
            int m = g_xorTable1[i] & 0x7f;
            int n = g_xorTable2[i] & 0x7f;
            OutputDebugPrintf("0x%02x,0x%02x\n", m, n);
            int a = sntable[m];
            int b = sntable[n];
            a = (a * 9) ^ 0x37;
            b = (b * 9) ^ 0x37;
            sntable[m] = b;
            sntable[n] = a;
        }
}  
根据 4Bc098与4BC1D42个table表的值亦或0x7F后得到2个索引,将g_sntable的数据 乘以9并亦或0x37后进行交换。一共循环了 4*60次。
这部分明显对g_snTable进行了置换操作,需要判断最后的置换结构,因此写个程序进行了测试,让g_sntable[0x50]的值为0-4F,只进行置换不进行 乘以9并亦或0x37的操作,发现如下规律:


10、调用  sub_402BEE
         根据前面的510 buf跟上以及一个常量 0x144生成了一个vector 链表结构,并对其进行初始化,调用如下:
       sub_402BEE(&temKeyValueVetor,(int)&lastKeyTable, ((_DWORD)((char *)lastKeyTable.last - (char *)lastKeyTable.start) >> 2), 0x144);
该函数比较大,大概分析了下数据结构。里面分配了多个0x20大小的链表结构。

[注意]看雪招聘,专注安全领域的专业人才平台!

最后于 2019-3-22 22:41 被oooAooo编辑 ,原因:
收藏
点赞 3
支持
分享
赞赏记录
参与人
雪币
留言
时间
PLEBFE
为你点赞~
2022-7-27 01:46
心游尘世外
为你点赞~
2022-7-26 23:40
飘零丶
为你点赞~
2022-7-17 03:23
最新回复 (1)
雪    币: 6051
活跃值: (1441)
能力值: ( LV15,RANK:1473 )
在线值:
发帖
回帖
粉丝
2
其实程序只是在校验用户输入与固定值的匹配,属于明码校验的类型,只是比较绕而已
2019-3-25 18:11
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

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