前一段时间破解了WINDOWS优化大师,并写BLOG文在qq空间里。但是这篇文章总的来说算是暴力破解——修改原程序绕过序列号校验的代码,达到注册的目的。最近为了锻炼功力决定把它的注册算法逆向出来。说干就干。 我逆向的版本号是7.86.8.1105。
WINDOWS优化大师是用DEPHI写的,用DEDE分析可以得到注册按钮的入口地址0062196C,在OD里下断点。结合DEDE进行分析一路跟踪到这里
00621C33 E8F077FAFF call 005C9428
00621C38 3DB2000000 cmp eax, $000000B2
这里调用一个函数,然后让EAX和0xB2进行比较,如果相等则注册成功。进入函数005C9428查看,DEDE的分析结果是:
005C9428 8BC8 mov ecx, eax
005C942A B201 mov dl, $01
* Reference to class TBig5RegChkThread
|
005C942C A1488F5C00 mov eax, dword ptr [$005C8F48]
|
005C9431 E8C60A0000 call 005C9EFC
005C9436 8B15406F7500 mov edx, [$00756F40]
005C943C 8B12 mov edx, [edx]
* Reference to field TBig5RegChkThread.OFFS_001C
|
005C943E 89501C mov [eax+$1C], edx
* Reference to field TBig5RegChkThread.OFFS_0018
|
005C9441 C7401814EB6F00 mov dword ptr [eax+$18], $006FEB14
005C9448 C605BCC2760001 mov byte ptr [$0076C2BC], $01
* Reference to: Classes.TThread.Resume(TThread);
|
005C944F E8E81AE6FF call 0042AF3C
005C9454 B8E8030000 mov eax, $000003E8
|
005C9459 E8EEA5E3FF call 00403A4C
005C945E A10C6F7500 mov eax, dword ptr [$00756F0C]
005C9463 8B00 mov eax, [eax]
* Reference to: ActnMenus.TCustomActionMenuBar.ProcessMessages(TCustomActionMenuBar);
| or: Forms.TApplication.ProcessMessages(TApplication);
|
005C9465 E88ECFECFF call 004963F8
005C946A 803DBCC2760000 cmp byte ptr [$0076C2BC], $00
005C9471 75E1 jnz 005C9454
005C9473 A1C0C27600 mov eax, dword ptr [$0076C2C0]
005C9478 C3 ret
该函数启动一个线程计算注册码,然后把结果放在地址0076C2C0处,也就是说,如果最后的计算结果是0XB2的话,则注册成功。
继续逆流而上。在0076C2C0下内存写入断点,竟然断不了?那就是注册不成功,则不执行对该地址的写入操作。想点别的办法。查找命令MOV DWORD PTR DS:[76C2C0],0B2, 找到下列地址中有该函数
5CA312
5CA383
5CA3F4
5CA474
5CA4F8
5CA544
(这里还有个小技巧,也不知道是我笨,还是OD的功能所限,查找MOV DWORD PTR DS:[76C2C0],0B2指令时,查找到的总是第一个指令,无法查找下一条指令, 没办法,只能先把找到的指令改成别的,比如MOV DWORD PTR DS:[76C2C0],0B1,然后继续查找,就会找到下一条MOV DWORD PTR DS:[76C2C0],0B2。)
发现它们统统在一个函数调用里面。那十之八九就是计算注册码的线程函数了。该函数的起始地址是5C9F88 , 用OD跟踪上几遍就会发现起运行步骤:
1. 这个函数是先把注册字符串转换成十六进制16字节,即取注册字符串的前32有效字符字符。(把非0-9,A-F的字符全部滤去)。
2. 通过一定的运算计算出16个字节的数据,再把该16字节数据转换成长度为32的字符串。
3. 取该字符串后16位与一个固定字符串进行比较,如果相等,则注册成功,否则注册失败。
如果要用暴力破解的话,直接把判断是否注册成功的语句改掉就ok了。其实很简单。但我现在的目的是不改动原来的持续,而要把它正确的注册码算出来。接下来的关键就是看步骤2中的加密算法了。
005CA219 > /8D4D C0 LEA ECX,DWORD PTR SS:[EBP-40]
005CA21C . 8D55 D0 LEA EDX,DWORD PTR SS:[EBP-30]
005CA21F . 8D85 F0FEFFFF LEA EAX,DWORD PTR SS:[EBP-110]
005CA225 . E8 3ED9FCFF CALL WoptiUti.00597B68
在此调用了该加密算法,即函数00597B68。ECX是输入参数,EDX是输出参数,EAX可以认为是加密密钥,每次都是不变。进入函数体内,可以看到
00597B68 /$ 53 PUSH EBX
00597B69 |. 56 PUSH ESI
00597B6A |. 57 PUSH EDI
00597B6B |. 55 PUSH EBP
00597B6C |. 83C4 EC ADD ESP,-14
00597B6F |. 890C24 MOV DWORD PTR SS:[ESP],ECX
00597B72 |. 8BDA MOV EBX,EDX
00597B74 |. 8BF8 MOV EDI,EAX
00597B76 |. 8D5424 04 LEA EDX,DWORD PTR SS:[ESP+4]
00597B7A |. 8BC3 MOV EAX,EBX
00597B7C |. B9 04000000 MOV ECX,4
00597B81 |. E8 C6B5E6FF CALL WoptiUti.0040314C
00597B86 |. 8D5424 08 LEA EDX,DWORD PTR SS:[ESP+8]
00597B8A |. 8BF3 MOV ESI,EBX
00597B8C |. 8BC6 MOV EAX,ESI
00597B8E |. 83C0 04 ADD EAX,4
00597B91 |. B9 04000000 MOV ECX,4
00597B96 |. E8 B1B5E6FF CALL WoptiUti.0040314C
00597B9B |. 8D5424 0C LEA EDX,DWORD PTR SS:[ESP+C]
00597B9F |. 8BC6 MOV EAX,ESI
00597BA1 |. 83C0 08 ADD EAX,8
00597BA4 |. B9 04000000 MOV ECX,4
00597BA9 |. E8 9EB5E6FF CALL WoptiUti.0040314C
00597BAE |. 8D5424 10 LEA EDX,DWORD PTR SS:[ESP+10]
00597BB2 |. 8BC6 MOV EAX,ESI
00597BB4 |. 83C0 0C ADD EAX,0C
00597BB7 |. B9 04000000 MOV ECX,4
00597BBC |. E8 8BB5E6FF CALL WoptiUti.0040314C
00597BC1 |. 8B87 CC000000 MOV EAX,DWORD PTR DS:[EDI+CC]
00597BC7 |. 294424 0C SUB DWORD PTR SS:[ESP+C],EAX
00597BCB |. 8B87 C8000000 MOV EAX,DWORD PTR DS:[EDI+C8]
00597BD1 |. 294424 04 SUB DWORD PTR SS:[ESP+4],EAX
00597BD5 |. BE 14000000 MOV ESI,14
00597BDA |> 8B5C24 04 /MOV EBX,DWORD PTR SS:[ESP+4]
00597BDE |. 8B4424 10 |MOV EAX,DWORD PTR SS:[ESP+10]
00597BE2 |. 894424 04 |MOV DWORD PTR SS:[ESP+4],EAX
00597BE6 |. 8B4424 0C |MOV EAX,DWORD PTR SS:[ESP+C]
00597BEA |. 894424 10 |MOV DWORD PTR SS:[ESP+10],EAX
00597BEE |. 8B4424 08 |MOV EAX,DWORD PTR SS:[ESP+8]
00597BF2 |. 894424 0C |MOV DWORD PTR SS:[ESP+C],EAX
00597BF6 |. 895C24 08 |MOV DWORD PTR SS:[ESP+8],EBX
00597BFA |. 8B4424 10 |MOV EAX,DWORD PTR SS:[ESP+10]
00597BFE |. 03C0 |ADD EAX,EAX
00597C00 |. 40 |INC EAX
00597C01 |. F76C24 10 |IMUL DWORD PTR SS:[ESP+10]
00597C05 |. BA 05000000 |MOV EDX,5
00597C0A |. E8 D5FBFFFF |CALL WoptiUti.005977E4
00597C0F |. 8BE8 |MOV EBP,EAX
00597C11 |. 8B4424 08 |MOV EAX,DWORD PTR SS:[ESP+8]
00597C15 |. 03C0 |ADD EAX,EAX
00597C17 |. 40 |INC EAX
00597C18 |. F76C24 08 |IMUL DWORD PTR SS:[ESP+8]
00597C1C |. BA 05000000 |MOV EDX,5
00597C21 |. E8 BEFBFFFF |CALL WoptiUti.005977E4
00597C26 |. 8BD8 |MOV EBX,EAX
00597C28 |. 8BC6 |MOV EAX,ESI
00597C2A |. 03C0 |ADD EAX,EAX
00597C2C |. FF7487 24 |PUSH DWORD PTR DS:[EDI+EAX*4+24]
00597C30 |. 8B4424 10 |MOV EAX,DWORD PTR SS:[ESP+10]
00597C34 |. 5A |POP EDX
00597C35 |. 2BC2 |SUB EAX,EDX
00597C37 |. 8BD3 |MOV EDX,EBX
00597C39 |. E8 BAFBFFFF |CALL WoptiUti.005977F8
00597C3E |. 33C5 |XOR EAX,EBP
00597C40 |. 894424 0C |MOV DWORD PTR SS:[ESP+C],EAX
00597C44 |. 8BC6 |MOV EAX,ESI
00597C46 |. 03C0 |ADD EAX,EAX
00597C48 |. FF7487 20 |PUSH DWORD PTR DS:[EDI+EAX*4+20]
00597C4C |. 8B4424 08 |MOV EAX,DWORD PTR SS:[ESP+8]
00597C50 |. 5A |POP EDX
00597C51 |. 2BC2 |SUB EAX,EDX
00597C53 |. 8BD5 |MOV EDX,EBP
00597C55 |. E8 9EFBFFFF |CALL WoptiUti.005977F8
00597C5A |. 33D8 |XOR EBX,EAX
00597C5C |. 895C24 04 |MOV DWORD PTR SS:[ESP+4],EBX
00597C60 |. 4E |DEC ESI
00597C61 |. 85F6 |TEST ESI,ESI
00597C63 |.^ 0F85 71FFFFFF /JNZ WoptiUti.00597BDA
00597C69 |. 8B47 24 MOV EAX,DWORD PTR DS:[EDI+24]
00597C6C |. 294424 10 SUB DWORD PTR SS:[ESP+10],EAX
00597C70 |. 8B47 20 MOV EAX,DWORD PTR DS:[EDI+20]
00597C73 |. 294424 08 SUB DWORD PTR SS:[ESP+8],EAX
00597C77 |. 8B1424 MOV EDX,DWORD PTR SS:[ESP]
00597C7A |. 8D4424 04 LEA EAX,DWORD PTR SS:[ESP+4]
00597C7E |. B9 04000000 MOV ECX,4
00597C83 |. E8 C4B4E6FF CALL WoptiUti.0040314C
00597C88 |. 8B1C24 MOV EBX,DWORD PTR SS:[ESP]
00597C8B |. 8BD3 MOV EDX,EBX
00597C8D |. 83C2 04 ADD EDX,4
00597C90 |. 8D4424 08 LEA EAX,DWORD PTR SS:[ESP+8]
00597C94 |. B9 04000000 MOV ECX,4
00597C99 |. E8 AEB4E6FF CALL WoptiUti.0040314C
00597C9E |. 8BD3 MOV EDX,EBX
00597CA0 |. 83C2 08 ADD EDX,8
00597CA3 |. 8D4424 0C LEA EAX,DWORD PTR SS:[ESP+C]
00597CA7 |. B9 04000000 MOV ECX,4
00597CAC |. E8 9BB4E6FF CALL WoptiUti.0040314C
00597CB1 |. 8BD3 MOV EDX,EBX
00597CB3 |. 83C2 0C ADD EDX,0C
00597CB6 |. 8D4424 10 LEA EAX,DWORD PTR SS:[ESP+10]
00597CBA |. B9 04000000 MOV ECX,4
00597CBF |. E8 88B4E6FF CALL WoptiUti.0040314C
00597CC4 |. 83C4 14 ADD ESP,14
00597CC7 |. 5D POP EBP
00597CC8 |. 5F POP EDI
00597CC9 |. 5E POP ESI
00597CCA |. 5B POP EBX
00597CCB /. C3 RETN
这就是WINDOWS优化大师核心的注册算法。其中里面调用了一些函数,点进去看看,其实很简单。
CALL 0040314C是内存copy函数。
CALL 005977E4是循环左移位,完全可以用ROL指令替换。
CALL 005977F8是循环右移位,完全可以用ROR指令替换。
OK,用OD把上面函数的反汇编结果转换成汇编代码并把用到的内存数据copy出来,经过调试就是得到一段内嵌汇编的c代码(一开始还想用高级语言重写一下的,后来一想还是直接来汇编的方便。)
运行一下,再和OD中的加密算法出来的结果对比,一样样的,OK。下面开始写逆运算,为了验证逆运算的有效性,我把逆向运算的代码写在注册运算代码之后,也就是说运行完注册算法后立刻运行逆注册运算,看结果和注册之前一样不一样。记过了几番调试,最终的代码如下:
int PassWord[4] = {0x78563412, 0xEFCDAB90, 0x78563412, 0xEFCDAB90};
BYTE data[] =
{
0xA9, 0x8E, 0xA2, 0x84, 0x5B, 0x08, 0x78, 0x5F, 0xE6, 0xD9, 0x9E, 0x1A, 0x69, 0xD0, 0xBC, 0x4D,
0xCE, 0xEA, 0xA1, 0xD3, 0xEF, 0x63, 0x2D, 0x4A, 0x20, 0x0A, 0x4E, 0xCF, 0xAF, 0xFC, 0xB2, 0xA6,
0x88, 0xA1, 0xB0, 0xC9, 0xA3, 0xB9, 0xC3, 0xE1, 0x7B, 0xBB, 0x96, 0x8B, 0x2F, 0x4F, 0xC4, 0xE6,
0x60, 0x7B, 0xCE, 0x8A, 0x11, 0xB4, 0x11, 0x4F, 0xC3, 0xB8, 0x26, 0x72, 0x25, 0x06, 0x35, 0xB1,
0x33, 0x61, 0x41, 0x00, 0x64, 0xD4, 0x4E, 0xD5, 0x9A, 0x42, 0x43, 0xDD, 0x7B, 0xD3, 0x25, 0xF7,
0x8F, 0x38, 0x85, 0x67, 0xDA, 0x41, 0xFB, 0x84, 0xA7, 0x15, 0x5A, 0x62, 0x7A, 0x6F, 0x14, 0x99,
0x36, 0x46, 0x90, 0x90, 0x23, 0xAC, 0x1C, 0x1B, 0x46, 0x81, 0x22, 0xC6, 0x7D, 0xE9, 0x0B, 0x6B,
0x37, 0x67, 0x5B, 0x4B, 0x4C, 0x69, 0xC1, 0x7D, 0xD4, 0x2C, 0x34, 0x1B, 0x6E, 0xC3, 0x17, 0xFD,
0xEF, 0x04, 0x55, 0x86, 0x6C, 0x31, 0xE5, 0x36, 0x3A, 0xA5, 0x63, 0x62, 0x13, 0xA3, 0xDE, 0x73,
0xFA, 0x9A, 0x6E, 0x28, 0x77, 0xF2, 0x69, 0xD3, 0x5C, 0x0E, 0xA4, 0x8D, 0x33, 0xE9, 0x9F, 0xEE,
0xB1, 0xEB, 0xA7, 0xC6, 0xE9, 0x2C, 0x91, 0x30, 0x14, 0xD8, 0xC6, 0x7F, 0x29, 0xE1, 0xD7, 0xB1,
};
void main()
{
__asm
{
push ebp
sub esp, 20
mov edi, offset data
mov eax, 0x78563412
mov [esp+4], eax
mov eax, 0xEFCDAB90
mov [esp+8], eax
mov eax, 0x78563412
mov [esp+0xc], eax
mov eax, 0xEFCDAB90
mov [esp+0x10], eax
mov eax, 0xB1D7E129
sub dword ptr [esp+0xc], eax
mov eax, 0x7FC6D814;
sub dword ptr [esp+4], eax
mov esi, 0x14
L005:
mov ebx, dword ptr [esp+4]
mov eax, dword ptr [esp+0x10]
mov dword ptr [esp+4], eax
mov eax, dword ptr [esp+0xc]
mov dword ptr [esp+0x10], eax
mov eax, dword ptr [esp+8]
mov dword ptr [esp+0xc], eax
mov dword ptr [esp+8], ebx
mov eax, dword ptr [esp+0x10]
add eax, eax
inc eax
imul dword ptr [esp+0x10]
mov edx, 5
mov ecx, edx
rol eax, cl
mov ebp, eax
mov eax, dword ptr [esp+8]
add eax, eax
inc eax
imul dword ptr [esp+8]
mov edx, 5
mov ecx, edx
rol eax, cl
mov ebx, eax
mov eax, esi
add eax, eax
push dword ptr [edi+eax*4+0x4]
mov eax, dword ptr [esp+0x10]
pop edx
sub eax, edx
mov edx, ebx
mov ecx, edx
ror eax, cl
xor eax, ebp
mov dword ptr [esp+0xc], eax
mov eax, esi
add eax, eax
push dword ptr [edi+eax*4]
mov eax, dword ptr [esp+8]
pop edx
sub eax, edx
mov edx, ebp
mov ecx, edx
ror eax, cl
xor ebx, eax
mov dword ptr [esp+4], ebx
dec esi
test esi, esi
jnz L005
mov eax, dword ptr[edi + 4]
sub dword ptr[esp + 0x10], eax
mov eax, dword ptr[edi]
sub dword ptr[esp + 8], eax
;reverse
mov eax, dword ptr[edi]
add dword ptr[esp + 8], eax
mov eax, dword ptr[edi + 4]
add dword ptr[esp + 0x10], eax
mov esi, 0
L006:
inc esi
mov eax, dword ptr [esp+0x10]
add eax, eax
inc eax
imul dword ptr [esp+0x10]
mov edx, 5
mov ecx, edx
rol eax, cl
mov ebp, eax
mov eax, dword ptr [esp+8]
add eax, eax
inc eax
imul dword ptr [esp+8]
mov edx, 5
mov ecx, edx
rol eax, cl
mov ebx, eax
-
mov eax, dword ptr [esp+0xc]
xor eax, ebp
mov edx, ebx
mov ecx, edx
rol eax, cl
push eax
mov eax, esi
add eax, eax
push dword ptr [edi+eax*4+0x4]
pop edx
pop eax
add eax, edx
mov dword ptr [esp+0xc], eax
mov eax, dword ptr [esp+4]
xor eax, ebx
mov edx, ebp
mov ecx, edx
rol eax, cl
push eax
mov eax, esi
add eax, eax
push dword ptr [edi+eax*4]
pop edx
pop eax
add eax, edx
mov dword ptr [esp+4], eax
mov ebx, dword ptr [esp+4]
mov eax, dword ptr [esp+8]
mov dword ptr [esp+4], eax
mov eax, dword ptr [esp+0x0c]
mov dword ptr [esp+8], eax
mov eax, dword ptr [esp+0x10]
mov dword ptr [esp+0xc], eax
mov dword ptr [esp+0x10], ebx
cmp esi, 0x14
jnz L006
mov eax, 0xB1D7E129
add dword ptr [esp+0xc], eax
mov eax, 0x7FC6D814;
add dword ptr [esp+4], eax
mov eax, dword ptr [esp+4]
mov PassWord[0], eax
mov eax, dword ptr [esp+8]
mov PassWord[0] + 4, eax
mov eax, dword ptr [esp+0x0c]
mov PassWord[0] + 8, eax
mov eax, dword ptr [esp+0x10]
mov PassWord[0] + 0x0c, eax
add esp, 20
pop ebp
}
}
;reverse 之后的即为逆向算法,最终的注册机代码如下:
int PassWord[4] = {0};
BYTE data[] =
{
0xA9, 0x8E, 0xA2, 0x84, 0x5B, 0x08, 0x78, 0x5F, 0xE6, 0xD9, 0x9E, 0x1A, 0x69, 0xD0, 0xBC, 0x4D,
0xCE, 0xEA, 0xA1, 0xD3, 0xEF, 0x63, 0x2D, 0x4A, 0x20, 0x0A, 0x4E, 0xCF, 0xAF, 0xFC, 0xB2, 0xA6,
0x88, 0xA1, 0xB0, 0xC9, 0xA3, 0xB9, 0xC3, 0xE1, 0x7B, 0xBB, 0x96, 0x8B, 0x2F, 0x4F, 0xC4, 0xE6,
0x60, 0x7B, 0xCE, 0x8A, 0x11, 0xB4, 0x11, 0x4F, 0xC3, 0xB8, 0x26, 0x72, 0x25, 0x06, 0x35, 0xB1,
0x33, 0x61, 0x41, 0x00, 0x64, 0xD4, 0x4E, 0xD5, 0x9A, 0x42, 0x43, 0xDD, 0x7B, 0xD3, 0x25, 0xF7,
0x8F, 0x38, 0x85, 0x67, 0xDA, 0x41, 0xFB, 0x84, 0xA7, 0x15, 0x5A, 0x62, 0x7A, 0x6F, 0x14, 0x99,
0x36, 0x46, 0x90, 0x90, 0x23, 0xAC, 0x1C, 0x1B, 0x46, 0x81, 0x22, 0xC6, 0x7D, 0xE9, 0x0B, 0x6B,
0x37, 0x67, 0x5B, 0x4B, 0x4C, 0x69, 0xC1, 0x7D, 0xD4, 0x2C, 0x34, 0x1B, 0x6E, 0xC3, 0x17, 0xFD,
0xEF, 0x04, 0x55, 0x86, 0x6C, 0x31, 0xE5, 0x36, 0x3A, 0xA5, 0x63, 0x62, 0x13, 0xA3, 0xDE, 0x73,
0xFA, 0x9A, 0x6E, 0x28, 0x77, 0xF2, 0x69, 0xD3, 0x5C, 0x0E, 0xA4, 0x8D, 0x33, 0xE9, 0x9F, 0xEE,
0xB1, 0xEB, 0xA7, 0xC6, 0xE9, 0x2C, 0x91, 0x30, 0x14, 0xD8, 0xC6, 0x7F, 0x29, 0xE1, 0xD7, 0xB1,
};
void main()
{
__asm
{
push ebp
sub esp, 20
mov edi, offset data
mov dword ptr[esp+4], 0x78563412 ;这个值可以随便填
mov dword ptr[esp+8], 0xEFCDAB90 ;这个值ye 可以随便填
mov dword ptr[esp+0x0c], 0x12d762c3
mov dword ptr[esp+0x010], 0x35a6b629
;reverse
mov eax, dword ptr[edi]
add dword ptr[esp + 8], eax
mov eax, dword ptr[edi + 4]
add dword ptr[esp + 0x10], eax
mov esi, 0
L006:
inc esi
mov eax, dword ptr [esp+0x10]
add eax, eax
inc eax
imul dword ptr [esp+0x10]
mov edx, 5
mov ecx, edx
rol eax, cl
mov ebp, eax
mov eax, dword ptr [esp+8]
add eax, eax
inc eax
imul dword ptr [esp+8]
mov edx, 5
mov ecx, edx
rol eax, cl
mov ebx, eax
mov eax, dword ptr [esp+0xc]
xor eax, ebp
mov edx, ebx
mov ecx, edx
rol eax, cl
push eax
mov eax, esi
add eax, eax
push dword ptr [edi+eax*4+0x4]
pop edx
pop eax
add eax, edx
mov dword ptr [esp+0xc], eax
mov eax, dword ptr [esp+4]
xor eax, ebx
mov edx, ebp
mov ecx, edx
rol eax, cl
push eax
mov eax, esi
add eax, eax
push dword ptr [edi+eax*4]
pop edx
pop eax
add eax, edx
mov dword ptr [esp+4], eax
mov ebx, dword ptr [esp+4]
mov eax, dword ptr [esp+8]
mov dword ptr [esp+4], eax
mov eax, dword ptr [esp+0x0c]
mov dword ptr [esp+8], eax
mov eax, dword ptr [esp+0x10]
mov dword ptr [esp+0xc], eax
mov dword ptr [esp+0x10], ebx
cmp esi, 0x14
jnz L006
mov eax, 0xB1D7E129
add dword ptr [esp+0xc], eax
mov eax, 0x7FC6D814;
add dword ptr [esp+4], eax
mov eax, dword ptr [esp+4]
mov PassWord[0], eax
mov eax, dword ptr [esp+8]
mov PassWord[0] + 4, eax
mov eax, dword ptr [esp+0x0c]
mov PassWord[0] + 8, eax
mov eax, dword ptr [esp+0x10]
mov PassWord[0] + 0x0c, eax
add esp, 20
pop ebp
}
//运算得到的注册码为A282E03E56BB032CC418D93126F525C9
}
WINDOWS优化大师是用DEPHI写的,用DEDE分析可以得到注册按钮的入口地址0062196C,在OD里下断点。结合DEDE进行分析一路跟踪到这里
00621C33 E8F077FAFF call 005C9428
00621C38 3DB2000000 cmp eax, $000000B2
这里调用一个函数,然后让EAX和0xB2进行比较,如果相等则注册成功。进入函数005C9428查看,DEDE的分析结果是:
005C9428 8BC8 mov ecx, eax
005C942A B201 mov dl, $01
* Reference to class TBig5RegChkThread
|
005C942C A1488F5C00 mov eax, dword ptr [$005C8F48]
|
005C9431 E8C60A0000 call 005C9EFC
005C9436 8B15406F7500 mov edx, [$00756F40]
005C943C 8B12 mov edx, [edx]
* Reference to field TBig5RegChkThread.OFFS_001C
|
005C943E 89501C mov [eax+$1C], edx
* Reference to field TBig5RegChkThread.OFFS_0018
|
005C9441 C7401814EB6F00 mov dword ptr [eax+$18], $006FEB14
005C9448 C605BCC2760001 mov byte ptr [$0076C2BC], $01
* Reference to: Classes.TThread.Resume(TThread);
|
005C944F E8E81AE6FF call 0042AF3C
005C9454 B8E8030000 mov eax, $000003E8
|
005C9459 E8EEA5E3FF call 00403A4C
005C945E A10C6F7500 mov eax, dword ptr [$00756F0C]
005C9463 8B00 mov eax, [eax]
* Reference to: ActnMenus.TCustomActionMenuBar.ProcessMessages(TCustomActionMenuBar);
| or: Forms.TApplication.ProcessMessages(TApplication);
|
005C9465 E88ECFECFF call 004963F8
005C946A 803DBCC2760000 cmp byte ptr [$0076C2BC], $00
005C9471 75E1 jnz 005C9454
005C9473 A1C0C27600 mov eax, dword ptr [$0076C2C0]
005C9478 C3 ret
该函数启动一个线程计算注册码,然后把结果放在地址0076C2C0处,也就是说,如果最后的计算结果是0XB2的话,则注册成功。
继续逆流而上。在0076C2C0下内存写入断点,竟然断不了?那就是注册不成功,则不执行对该地址的写入操作。想点别的办法。查找命令MOV DWORD PTR DS:[76C2C0],0B2, 找到下列地址中有该函数
5CA312
5CA383
5CA3F4
5CA474
5CA4F8
5CA544
(这里还有个小技巧,也不知道是我笨,还是OD的功能所限,查找MOV DWORD PTR DS:[76C2C0],0B2指令时,查找到的总是第一个指令,无法查找下一条指令, 没办法,只能先把找到的指令改成别的,比如MOV DWORD PTR DS:[76C2C0],0B1,然后继续查找,就会找到下一条MOV DWORD PTR DS:[76C2C0],0B2。)
发现它们统统在一个函数调用里面。那十之八九就是计算注册码的线程函数了。该函数的起始地址是5C9F88 , 用OD跟踪上几遍就会发现起运行步骤:
1. 这个函数是先把注册字符串转换成十六进制16字节,即取注册字符串的前32有效字符字符。(把非0-9,A-F的字符全部滤去)。
2. 通过一定的运算计算出16个字节的数据,再把该16字节数据转换成长度为32的字符串。
3. 取该字符串后16位与一个固定字符串进行比较,如果相等,则注册成功,否则注册失败。
如果要用暴力破解的话,直接把判断是否注册成功的语句改掉就ok了。其实很简单。但我现在的目的是不改动原来的持续,而要把它正确的注册码算出来。接下来的关键就是看步骤2中的加密算法了。
005CA219 > /8D4D C0 LEA ECX,DWORD PTR SS:[EBP-40]
005CA21C . 8D55 D0 LEA EDX,DWORD PTR SS:[EBP-30]
005CA21F . 8D85 F0FEFFFF LEA EAX,DWORD PTR SS:[EBP-110]
005CA225 . E8 3ED9FCFF CALL WoptiUti.00597B68
在此调用了该加密算法,即函数00597B68。ECX是输入参数,EDX是输出参数,EAX可以认为是加密密钥,每次都是不变。进入函数体内,可以看到
00597B68 /$ 53 PUSH EBX
00597B69 |. 56 PUSH ESI
00597B6A |. 57 PUSH EDI
00597B6B |. 55 PUSH EBP
00597B6C |. 83C4 EC ADD ESP,-14
00597B6F |. 890C24 MOV DWORD PTR SS:[ESP],ECX
00597B72 |. 8BDA MOV EBX,EDX
00597B74 |. 8BF8 MOV EDI,EAX
00597B76 |. 8D5424 04 LEA EDX,DWORD PTR SS:[ESP+4]
00597B7A |. 8BC3 MOV EAX,EBX
00597B7C |. B9 04000000 MOV ECX,4
00597B81 |. E8 C6B5E6FF CALL WoptiUti.0040314C
00597B86 |. 8D5424 08 LEA EDX,DWORD PTR SS:[ESP+8]
00597B8A |. 8BF3 MOV ESI,EBX
00597B8C |. 8BC6 MOV EAX,ESI
00597B8E |. 83C0 04 ADD EAX,4
00597B91 |. B9 04000000 MOV ECX,4
00597B96 |. E8 B1B5E6FF CALL WoptiUti.0040314C
00597B9B |. 8D5424 0C LEA EDX,DWORD PTR SS:[ESP+C]
00597B9F |. 8BC6 MOV EAX,ESI
00597BA1 |. 83C0 08 ADD EAX,8
00597BA4 |. B9 04000000 MOV ECX,4
00597BA9 |. E8 9EB5E6FF CALL WoptiUti.0040314C
00597BAE |. 8D5424 10 LEA EDX,DWORD PTR SS:[ESP+10]
00597BB2 |. 8BC6 MOV EAX,ESI
00597BB4 |. 83C0 0C ADD EAX,0C
00597BB7 |. B9 04000000 MOV ECX,4
00597BBC |. E8 8BB5E6FF CALL WoptiUti.0040314C
00597BC1 |. 8B87 CC000000 MOV EAX,DWORD PTR DS:[EDI+CC]
00597BC7 |. 294424 0C SUB DWORD PTR SS:[ESP+C],EAX
00597BCB |. 8B87 C8000000 MOV EAX,DWORD PTR DS:[EDI+C8]
00597BD1 |. 294424 04 SUB DWORD PTR SS:[ESP+4],EAX
00597BD5 |. BE 14000000 MOV ESI,14
00597BDA |> 8B5C24 04 /MOV EBX,DWORD PTR SS:[ESP+4]
00597BDE |. 8B4424 10 |MOV EAX,DWORD PTR SS:[ESP+10]
00597BE2 |. 894424 04 |MOV DWORD PTR SS:[ESP+4],EAX
00597BE6 |. 8B4424 0C |MOV EAX,DWORD PTR SS:[ESP+C]
00597BEA |. 894424 10 |MOV DWORD PTR SS:[ESP+10],EAX
00597BEE |. 8B4424 08 |MOV EAX,DWORD PTR SS:[ESP+8]
00597BF2 |. 894424 0C |MOV DWORD PTR SS:[ESP+C],EAX
00597BF6 |. 895C24 08 |MOV DWORD PTR SS:[ESP+8],EBX
00597BFA |. 8B4424 10 |MOV EAX,DWORD PTR SS:[ESP+10]
00597BFE |. 03C0 |ADD EAX,EAX
00597C00 |. 40 |INC EAX
00597C01 |. F76C24 10 |IMUL DWORD PTR SS:[ESP+10]
00597C05 |. BA 05000000 |MOV EDX,5
00597C0A |. E8 D5FBFFFF |CALL WoptiUti.005977E4
00597C0F |. 8BE8 |MOV EBP,EAX
00597C11 |. 8B4424 08 |MOV EAX,DWORD PTR SS:[ESP+8]
00597C15 |. 03C0 |ADD EAX,EAX
00597C17 |. 40 |INC EAX
00597C18 |. F76C24 08 |IMUL DWORD PTR SS:[ESP+8]
00597C1C |. BA 05000000 |MOV EDX,5
00597C21 |. E8 BEFBFFFF |CALL WoptiUti.005977E4
00597C26 |. 8BD8 |MOV EBX,EAX
00597C28 |. 8BC6 |MOV EAX,ESI
00597C2A |. 03C0 |ADD EAX,EAX
00597C2C |. FF7487 24 |PUSH DWORD PTR DS:[EDI+EAX*4+24]
00597C30 |. 8B4424 10 |MOV EAX,DWORD PTR SS:[ESP+10]
00597C34 |. 5A |POP EDX
00597C35 |. 2BC2 |SUB EAX,EDX
00597C37 |. 8BD3 |MOV EDX,EBX
00597C39 |. E8 BAFBFFFF |CALL WoptiUti.005977F8
00597C3E |. 33C5 |XOR EAX,EBP
00597C40 |. 894424 0C |MOV DWORD PTR SS:[ESP+C],EAX
00597C44 |. 8BC6 |MOV EAX,ESI
00597C46 |. 03C0 |ADD EAX,EAX
00597C48 |. FF7487 20 |PUSH DWORD PTR DS:[EDI+EAX*4+20]
00597C4C |. 8B4424 08 |MOV EAX,DWORD PTR SS:[ESP+8]
00597C50 |. 5A |POP EDX
00597C51 |. 2BC2 |SUB EAX,EDX
00597C53 |. 8BD5 |MOV EDX,EBP
00597C55 |. E8 9EFBFFFF |CALL WoptiUti.005977F8
00597C5A |. 33D8 |XOR EBX,EAX
00597C5C |. 895C24 04 |MOV DWORD PTR SS:[ESP+4],EBX
00597C60 |. 4E |DEC ESI
00597C61 |. 85F6 |TEST ESI,ESI
00597C63 |.^ 0F85 71FFFFFF /JNZ WoptiUti.00597BDA
00597C69 |. 8B47 24 MOV EAX,DWORD PTR DS:[EDI+24]
00597C6C |. 294424 10 SUB DWORD PTR SS:[ESP+10],EAX
00597C70 |. 8B47 20 MOV EAX,DWORD PTR DS:[EDI+20]
00597C73 |. 294424 08 SUB DWORD PTR SS:[ESP+8],EAX
00597C77 |. 8B1424 MOV EDX,DWORD PTR SS:[ESP]
00597C7A |. 8D4424 04 LEA EAX,DWORD PTR SS:[ESP+4]
00597C7E |. B9 04000000 MOV ECX,4
00597C83 |. E8 C4B4E6FF CALL WoptiUti.0040314C
00597C88 |. 8B1C24 MOV EBX,DWORD PTR SS:[ESP]
00597C8B |. 8BD3 MOV EDX,EBX
00597C8D |. 83C2 04 ADD EDX,4
00597C90 |. 8D4424 08 LEA EAX,DWORD PTR SS:[ESP+8]
00597C94 |. B9 04000000 MOV ECX,4
00597C99 |. E8 AEB4E6FF CALL WoptiUti.0040314C
00597C9E |. 8BD3 MOV EDX,EBX
00597CA0 |. 83C2 08 ADD EDX,8
00597CA3 |. 8D4424 0C LEA EAX,DWORD PTR SS:[ESP+C]
00597CA7 |. B9 04000000 MOV ECX,4
00597CAC |. E8 9BB4E6FF CALL WoptiUti.0040314C
00597CB1 |. 8BD3 MOV EDX,EBX
00597CB3 |. 83C2 0C ADD EDX,0C
00597CB6 |. 8D4424 10 LEA EAX,DWORD PTR SS:[ESP+10]
00597CBA |. B9 04000000 MOV ECX,4
00597CBF |. E8 88B4E6FF CALL WoptiUti.0040314C
00597CC4 |. 83C4 14 ADD ESP,14
00597CC7 |. 5D POP EBP
00597CC8 |. 5F POP EDI
00597CC9 |. 5E POP ESI
00597CCA |. 5B POP EBX
00597CCB /. C3 RETN
这就是WINDOWS优化大师核心的注册算法。其中里面调用了一些函数,点进去看看,其实很简单。
CALL 0040314C是内存copy函数。
CALL 005977E4是循环左移位,完全可以用ROL指令替换。
CALL 005977F8是循环右移位,完全可以用ROR指令替换。
OK,用OD把上面函数的反汇编结果转换成汇编代码并把用到的内存数据copy出来,经过调试就是得到一段内嵌汇编的c代码(一开始还想用高级语言重写一下的,后来一想还是直接来汇编的方便。)
运行一下,再和OD中的加密算法出来的结果对比,一样样的,OK。下面开始写逆运算,为了验证逆运算的有效性,我把逆向运算的代码写在注册运算代码之后,也就是说运行完注册算法后立刻运行逆注册运算,看结果和注册之前一样不一样。记过了几番调试,最终的代码如下:
int PassWord[4] = {0x78563412, 0xEFCDAB90, 0x78563412, 0xEFCDAB90};
BYTE data[] =
{
0xA9, 0x8E, 0xA2, 0x84, 0x5B, 0x08, 0x78, 0x5F, 0xE6, 0xD9, 0x9E, 0x1A, 0x69, 0xD0, 0xBC, 0x4D,
0xCE, 0xEA, 0xA1, 0xD3, 0xEF, 0x63, 0x2D, 0x4A, 0x20, 0x0A, 0x4E, 0xCF, 0xAF, 0xFC, 0xB2, 0xA6,
0x88, 0xA1, 0xB0, 0xC9, 0xA3, 0xB9, 0xC3, 0xE1, 0x7B, 0xBB, 0x96, 0x8B, 0x2F, 0x4F, 0xC4, 0xE6,
0x60, 0x7B, 0xCE, 0x8A, 0x11, 0xB4, 0x11, 0x4F, 0xC3, 0xB8, 0x26, 0x72, 0x25, 0x06, 0x35, 0xB1,
0x33, 0x61, 0x41, 0x00, 0x64, 0xD4, 0x4E, 0xD5, 0x9A, 0x42, 0x43, 0xDD, 0x7B, 0xD3, 0x25, 0xF7,
0x8F, 0x38, 0x85, 0x67, 0xDA, 0x41, 0xFB, 0x84, 0xA7, 0x15, 0x5A, 0x62, 0x7A, 0x6F, 0x14, 0x99,
0x36, 0x46, 0x90, 0x90, 0x23, 0xAC, 0x1C, 0x1B, 0x46, 0x81, 0x22, 0xC6, 0x7D, 0xE9, 0x0B, 0x6B,
0x37, 0x67, 0x5B, 0x4B, 0x4C, 0x69, 0xC1, 0x7D, 0xD4, 0x2C, 0x34, 0x1B, 0x6E, 0xC3, 0x17, 0xFD,
0xEF, 0x04, 0x55, 0x86, 0x6C, 0x31, 0xE5, 0x36, 0x3A, 0xA5, 0x63, 0x62, 0x13, 0xA3, 0xDE, 0x73,
0xFA, 0x9A, 0x6E, 0x28, 0x77, 0xF2, 0x69, 0xD3, 0x5C, 0x0E, 0xA4, 0x8D, 0x33, 0xE9, 0x9F, 0xEE,
0xB1, 0xEB, 0xA7, 0xC6, 0xE9, 0x2C, 0x91, 0x30, 0x14, 0xD8, 0xC6, 0x7F, 0x29, 0xE1, 0xD7, 0xB1,
};
void main()
{
__asm
{
push ebp
sub esp, 20
mov edi, offset data
mov eax, 0x78563412
mov [esp+4], eax
mov eax, 0xEFCDAB90
mov [esp+8], eax
mov eax, 0x78563412
mov [esp+0xc], eax
mov eax, 0xEFCDAB90
mov [esp+0x10], eax
mov eax, 0xB1D7E129
sub dword ptr [esp+0xc], eax
mov eax, 0x7FC6D814;
sub dword ptr [esp+4], eax
mov esi, 0x14
L005:
mov ebx, dword ptr [esp+4]
mov eax, dword ptr [esp+0x10]
mov dword ptr [esp+4], eax
mov eax, dword ptr [esp+0xc]
mov dword ptr [esp+0x10], eax
mov eax, dword ptr [esp+8]
mov dword ptr [esp+0xc], eax
mov dword ptr [esp+8], ebx
mov eax, dword ptr [esp+0x10]
add eax, eax
inc eax
imul dword ptr [esp+0x10]
mov edx, 5
mov ecx, edx
rol eax, cl
mov ebp, eax
mov eax, dword ptr [esp+8]
add eax, eax
inc eax
imul dword ptr [esp+8]
mov edx, 5
mov ecx, edx
rol eax, cl
mov ebx, eax
mov eax, esi
add eax, eax
push dword ptr [edi+eax*4+0x4]
mov eax, dword ptr [esp+0x10]
pop edx
sub eax, edx
mov edx, ebx
mov ecx, edx
ror eax, cl
xor eax, ebp
mov dword ptr [esp+0xc], eax
mov eax, esi
add eax, eax
push dword ptr [edi+eax*4]
mov eax, dword ptr [esp+8]
pop edx
sub eax, edx
mov edx, ebp
mov ecx, edx
ror eax, cl
xor ebx, eax
mov dword ptr [esp+4], ebx
dec esi
test esi, esi
jnz L005
mov eax, dword ptr[edi + 4]
sub dword ptr[esp + 0x10], eax
mov eax, dword ptr[edi]
sub dword ptr[esp + 8], eax
;reverse
mov eax, dword ptr[edi]
add dword ptr[esp + 8], eax
mov eax, dword ptr[edi + 4]
add dword ptr[esp + 0x10], eax
mov esi, 0
L006:
inc esi
mov eax, dword ptr [esp+0x10]
add eax, eax
inc eax
imul dword ptr [esp+0x10]
mov edx, 5
mov ecx, edx
rol eax, cl
mov ebp, eax
mov eax, dword ptr [esp+8]
add eax, eax
inc eax
imul dword ptr [esp+8]
mov edx, 5
mov ecx, edx
rol eax, cl
mov ebx, eax
-
mov eax, dword ptr [esp+0xc]
xor eax, ebp
mov edx, ebx
mov ecx, edx
rol eax, cl
push eax
mov eax, esi
add eax, eax
push dword ptr [edi+eax*4+0x4]
pop edx
pop eax
add eax, edx
mov dword ptr [esp+0xc], eax
mov eax, dword ptr [esp+4]
xor eax, ebx
mov edx, ebp
mov ecx, edx
rol eax, cl
push eax
mov eax, esi
add eax, eax
push dword ptr [edi+eax*4]
pop edx
pop eax
add eax, edx
mov dword ptr [esp+4], eax
mov ebx, dword ptr [esp+4]
mov eax, dword ptr [esp+8]
mov dword ptr [esp+4], eax
mov eax, dword ptr [esp+0x0c]
mov dword ptr [esp+8], eax
mov eax, dword ptr [esp+0x10]
mov dword ptr [esp+0xc], eax
mov dword ptr [esp+0x10], ebx
cmp esi, 0x14
jnz L006
mov eax, 0xB1D7E129
add dword ptr [esp+0xc], eax
mov eax, 0x7FC6D814;
add dword ptr [esp+4], eax
mov eax, dword ptr [esp+4]
mov PassWord[0], eax
mov eax, dword ptr [esp+8]
mov PassWord[0] + 4, eax
mov eax, dword ptr [esp+0x0c]
mov PassWord[0] + 8, eax
mov eax, dword ptr [esp+0x10]
mov PassWord[0] + 0x0c, eax
add esp, 20
pop ebp
}
}
;reverse 之后的即为逆向算法,最终的注册机代码如下:
int PassWord[4] = {0};
BYTE data[] =
{
0xA9, 0x8E, 0xA2, 0x84, 0x5B, 0x08, 0x78, 0x5F, 0xE6, 0xD9, 0x9E, 0x1A, 0x69, 0xD0, 0xBC, 0x4D,
0xCE, 0xEA, 0xA1, 0xD3, 0xEF, 0x63, 0x2D, 0x4A, 0x20, 0x0A, 0x4E, 0xCF, 0xAF, 0xFC, 0xB2, 0xA6,
0x88, 0xA1, 0xB0, 0xC9, 0xA3, 0xB9, 0xC3, 0xE1, 0x7B, 0xBB, 0x96, 0x8B, 0x2F, 0x4F, 0xC4, 0xE6,
0x60, 0x7B, 0xCE, 0x8A, 0x11, 0xB4, 0x11, 0x4F, 0xC3, 0xB8, 0x26, 0x72, 0x25, 0x06, 0x35, 0xB1,
0x33, 0x61, 0x41, 0x00, 0x64, 0xD4, 0x4E, 0xD5, 0x9A, 0x42, 0x43, 0xDD, 0x7B, 0xD3, 0x25, 0xF7,
0x8F, 0x38, 0x85, 0x67, 0xDA, 0x41, 0xFB, 0x84, 0xA7, 0x15, 0x5A, 0x62, 0x7A, 0x6F, 0x14, 0x99,
0x36, 0x46, 0x90, 0x90, 0x23, 0xAC, 0x1C, 0x1B, 0x46, 0x81, 0x22, 0xC6, 0x7D, 0xE9, 0x0B, 0x6B,
0x37, 0x67, 0x5B, 0x4B, 0x4C, 0x69, 0xC1, 0x7D, 0xD4, 0x2C, 0x34, 0x1B, 0x6E, 0xC3, 0x17, 0xFD,
0xEF, 0x04, 0x55, 0x86, 0x6C, 0x31, 0xE5, 0x36, 0x3A, 0xA5, 0x63, 0x62, 0x13, 0xA3, 0xDE, 0x73,
0xFA, 0x9A, 0x6E, 0x28, 0x77, 0xF2, 0x69, 0xD3, 0x5C, 0x0E, 0xA4, 0x8D, 0x33, 0xE9, 0x9F, 0xEE,
0xB1, 0xEB, 0xA7, 0xC6, 0xE9, 0x2C, 0x91, 0x30, 0x14, 0xD8, 0xC6, 0x7F, 0x29, 0xE1, 0xD7, 0xB1,
};
void main()
{
__asm
{
push ebp
sub esp, 20
mov edi, offset data
mov dword ptr[esp+4], 0x78563412 ;这个值可以随便填
mov dword ptr[esp+8], 0xEFCDAB90 ;这个值ye 可以随便填
mov dword ptr[esp+0x0c], 0x12d762c3
mov dword ptr[esp+0x010], 0x35a6b629
;reverse
mov eax, dword ptr[edi]
add dword ptr[esp + 8], eax
mov eax, dword ptr[edi + 4]
add dword ptr[esp + 0x10], eax
mov esi, 0
L006:
inc esi
mov eax, dword ptr [esp+0x10]
add eax, eax
inc eax
imul dword ptr [esp+0x10]
mov edx, 5
mov ecx, edx
rol eax, cl
mov ebp, eax
mov eax, dword ptr [esp+8]
add eax, eax
inc eax
imul dword ptr [esp+8]
mov edx, 5
mov ecx, edx
rol eax, cl
mov ebx, eax
mov eax, dword ptr [esp+0xc]
xor eax, ebp
mov edx, ebx
mov ecx, edx
rol eax, cl
push eax
mov eax, esi
add eax, eax
push dword ptr [edi+eax*4+0x4]
pop edx
pop eax
add eax, edx
mov dword ptr [esp+0xc], eax
mov eax, dword ptr [esp+4]
xor eax, ebx
mov edx, ebp
mov ecx, edx
rol eax, cl
push eax
mov eax, esi
add eax, eax
push dword ptr [edi+eax*4]
pop edx
pop eax
add eax, edx
mov dword ptr [esp+4], eax
mov ebx, dword ptr [esp+4]
mov eax, dword ptr [esp+8]
mov dword ptr [esp+4], eax
mov eax, dword ptr [esp+0x0c]
mov dword ptr [esp+8], eax
mov eax, dword ptr [esp+0x10]
mov dword ptr [esp+0xc], eax
mov dword ptr [esp+0x10], ebx
cmp esi, 0x14
jnz L006
mov eax, 0xB1D7E129
add dword ptr [esp+0xc], eax
mov eax, 0x7FC6D814;
add dword ptr [esp+4], eax
mov eax, dword ptr [esp+4]
mov PassWord[0], eax
mov eax, dword ptr [esp+8]
mov PassWord[0] + 4, eax
mov eax, dword ptr [esp+0x0c]
mov PassWord[0] + 8, eax
mov eax, dword ptr [esp+0x10]
mov PassWord[0] + 0x0c, eax
add esp, 20
pop ebp
}
//运算得到的注册码为A282E03E56BB032CC418D93126F525C9
}
后记:前一段时间把优化大师暴力破解出来后,总觉得应该把它逆向出来才算是真本事。终于下定决心搞一把。每天利用下班吃完饭以后的时间搞,其实每天可能也就一两个小时的时间,第二天再接着搞,周末的时间多一些。有两天(不是连续的两天)发狠了,搞到快半夜两点了。第二天白天感觉还好,就是晚上就巨困,挺早就休息了。不过总体感觉是半夜的时候周遭比较安静,心可以静下来想问题。困难在于第二天要7点多起来上班,所以不能总这样。