【原创】某软件算法分析

Eddy 发布于2009-12-10 16:4:54 分类: 技术心得 已浏览loading 网友评论0条 我要评论

用PEID先查下壳,Microsoft Visual C++ 6.0,无壳。省了很多体力^_

OD载入,ALT+E,发现有C:\WINDOWS\system32\mfc42.dll。说明是MFC的程序……

运行程序,输入Serial:XXXX-XXXX-XXXX-XXXX
Options:XXXX-XXXX-XXXX-XXXX
Name:Eddy
Organization:CUMT
点击注册,生成申请码(Request):1D84-E6CA-2A34-CC7B

然后任意输入假的激活码(Activation):1111-2222-3333-4444

程序的激活按钮是灰色的,无法进行验证,说明在输入过程中程序已经在验证激活码。分析到最好我才知道其实在这个过程中激活码程序已经计算出来了……

先分析程序如何验证是否激活Activate按钮,分析发现,程序是用下面这个call来判断激活码格式是否合法,以此决定是否激活Activate按钮

10015301 E8 6A00FFFF call Adjudica.NRegistrationModule::CRegFormatter::checkCode>; 检查激活码格式的合法性(调用这个函数的地方很多,在此我只说这个)


跟进10015301处的call:
10005370 > 8B4424 08 mov eax,dword ptr ss:[esp+8] ; 前8位
10005374 8B4C24 04 mov ecx,dword ptr ss:[esp+4] ; 后8位
10005378 50 push eax
10005379 51 push ecx
1000537A E8 41CDFFFF call Adjudica.100020C0
1000537F 83C4 08 add esp,8
10005382 C3 retn

跟进1000537A处的call:
100020C0 8B4424 04 mov eax,dword ptr ss:[esp+4] ; 后8位
100020C4 8B5424 08 mov edx,dword ptr ss:[esp+8] ; 前8位
100020C8 85C0 test eax,eax
100020CA 75 07 jnz short Adjudica.100020D3
100020CC 85D2 test edx,edx
100020CE 75 03 jnz short Adjudica.100020D3
100020D0 32C0 xor al,al
100020D2 C3 retn
100020D3 8BC8 mov ecx,eax
100020D5 24 00 and al,0
100020D7 895424 08 mov dword ptr ss:[esp+8],edx
100020DB 81E1 FF000000 and ecx,0FF
100020E1 894424 04 mov dword ptr ss:[esp+4],eax
100020E5 32D2 xor dl,dl
100020E7 53 push ebx
100020E8 33C0 xor eax,eax
100020EA 8A5C04 08 mov bl,byte ptr ss:[esp+eax+8] ; -----循环
100020EE 02D3 add dl,bl ; |
100020F0 40 inc eax ; |
100020F1 83F8 08 cmp eax,8 ; |
100020F4 ^ 7C F4 jl short Adjudica.100020EA ; -----分析下可知:假码前8位和的低2位==最后两位则格式合法
100020F6 885424 08 mov byte ptr ss:[esp+8],dl
100020FA 8B4424 08 mov eax,dword ptr ss:[esp+8]
100020FE 25 FF000000 and eax,0FF
10002103 33D2 xor edx,edx
10002105 3BC1 cmp eax,ecx
10002107 5B pop ebx
10002108 0F94C2 sete dl
1000210B 8AC2 mov al,dl
1000210D C3 retn

根据上面的分析结果,我构造了一个格式合法的激活码:XXXX-XXXX-XXXX-XXXX

这样输入激活码,就可以点击Activate按钮进入激活例程。找下按钮事件,发现验证在下:

10015270 55 push ebp ; 验证开始
10015271 8BEC mov ebp,esp
10015273 6A FF push -1
10015275 68 CC3E0510 push Adjudica.10053ECC
1001527A 64:A1 00000000 mov eax,dword ptr fs:[0]
10015280 50 push eax
10015281 64:8925 0000000>mov dword ptr fs:[0],esp
10015288 51 push ecx
10015289 B8 B0100000 mov eax,10B0
1001528E E8 5DB80300 call Adjudica.10050AF0
10015293 53 push ebx
10015294 56 push esi
10015295 57 push edi
10015296 8BF1 mov esi,ecx
10015298 8965 F0 mov dword ptr ss:[ebp-10],esp
1001529B 8975 C8 mov dword ptr ss:[ebp-38],esi
1001529E E8 42B40300 call Adjudica.100506E5
100152A3 50 push eax
100152A4 8D4D BC lea ecx,dword ptr ss:[ebp-44]
100152A7 E8 CEB00300 call <jmp.&MFC42.#6467>
100152AC 8B4E 6C mov ecx,dword ptr ds:[esi+6C]
100152AF C745 FC 0000000>mov dword ptr ss:[ebp-4],0
100152B6 8B01 mov eax,dword ptr ds:[ecx]
100152B8 FF10 call dword ptr ds:[eax]
100152BA 84C0 test al,al
100152BC 0F84 AA010000 je Adjudica.1001546C
100152C2 8B4E 6C mov ecx,dword ptr ds:[esi+6C]
100152C5 8B11 mov edx,dword ptr ds:[ecx]
100152C7 FF52 04 call dword ptr ds:[edx+4] ; 判断是否已经激活
100152CA 84C0 test al,al
100152CC 74 0E je short Adjudica.100152DC
100152CE 6A 01 push 1
100152D0 8BCE mov ecx,esi
100152D2 E8 E7B10300 call <jmp.&MFC42.#2645>
100152D7 E9 8C040000 jmp Adjudica.10015768
100152DC 8B8E 80000000 mov ecx,dword ptr ds:[esi+80] ; 假码出现
100152E2 8D86 80000000 lea eax,dword ptr ds:[esi+80]
100152E8 8B51 F8 mov edx,dword ptr ds:[ecx-8]
100152EB 85D2 test edx,edx
100152ED 0F84 75040000 je Adjudica.10015768
100152F3 6A 00 push 0
100152F5 50 push eax
100152F6 E8 3500FFFF call Adjudica.NRegistrationModule::CRegFormatter::string2Co>
100152FB 8BDA mov ebx,edx
100152FD 8BF8 mov edi,eax
100152FF 53 push ebx
10015300 57 push edi
10015301 E8 6A00FFFF call Adjudica.NRegistrationModule::CRegFormatter::checkCode>; 检查激活码格式的合法性
10015306 83C4 10 add esp,10
10015309 84C0 test al,al
1001530B 0F84 E9000000 je Adjudica.100153FA ;
10015311 8B4E 6C mov ecx,dword ptr ds:[esi+6C]
10015314 53 push ebx ; 前8位
10015315 57 push edi ; 后8位
10015316 8B11 mov edx,dword ptr ds:[ecx]
10015318 FF52 34 call dword ptr ds:[edx+34] ; 关键call al!=0
1001531B 6A 01 push 1
1001531D 8BCE mov ecx,esi
1001531F 8AD8 mov bl,al
10015321 E8 92B10300 call <jmp.&MFC42.#6334> ; CWnd::UpdateData(int)
10015326 84DB test bl,bl
10015328 75 4C jnz short Adjudica.10015376 ; 跳走则出现激活成功的对话框
1001532A 8D45 E8 lea eax,dword ptr ss:[ebp-18]
1001532D 6A 0B push 0B
1001532F 50 push eax
10015330 E8 DBC4FFFF call Adjudica.10011810
10015335 8B38 mov edi,dword ptr ds:[eax]
10015337 8D4D EC lea ecx,dword ptr ss:[ebp-14]
1001533A 6A 08 push 8
1001533C 51 push ecx
1001533D C645 FC 01 mov byte ptr ss:[ebp-4],1
10015341 E8 CAC4FFFF call Adjudica.10011810
10015346 83C4 10 add esp,10
10015349 8B00 mov eax,dword ptr ds:[eax]
1001534B 6A 30 push 30
1001534D 57 push edi
1001534E 50 push eax
1001534F 8BCE mov ecx,esi
10015351 C645 FC 02 mov byte ptr ss:[ebp-4],2
10015355 E8 28B10300 call <jmp.&MFC42.#4224>
1001535A 8D4D EC lea ecx,dword ptr ss:[ebp-14]
1001535D C645 FC 01 mov byte ptr ss:[ebp-4],1
10015361 E8 D2AF0300 call <jmp.&MFC42.#800>
10015366 8D4D E8 lea ecx,dword ptr ss:[ebp-18]
10015369 885D FC mov byte ptr ss:[ebp-4],bl
1001536C E8 C7AF0300 call <jmp.&MFC42.#800>
10015371 E9 F2030000 jmp Adjudica.10015768
10015376 68 BB360000 push 36BB
1001537B 8BCE mov ecx,esi
1001537D E8 EEB00300 call <jmp.&MFC42.#3092> ; CWnd::GetDlgItem(int)
10015382 85C0 test eax,eax
10015384 74 09 je short Adjudica.1001538F
10015386 6A 00 push 0
10015388 8BC8 mov ecx,eax
1001538A E8 11B10300 call <jmp.&MFC42.#2642> ; CWnd::EnableWindow(int)

进入10015318处的call:
这里面的代码就不是一般的多了,那是相当多。我的策略就是先单步走下,眼睛一定盯着OD的4个窗口,找找感觉^_
我帖出一些关键地方
1000F3E9 56 push esi ; 压入Serial前8位
1000F3EA 57 push edi ; 压入Serial后8位
1000F3EB 8BCD mov ecx,ebp
1000F3ED E8 3E000000 call Adjudica.NRegistrationModule::CRegistrationModule::ScrambleCode ;绕了几大圈你最终会发现这就是生成激活码的关键
1000F3F2 8BF0 mov esi,eax ; 保存下计算结果
1000F3F4 8B4424 38 mov eax,dword ptr ss:[esp+38]
1000F3F8 53 push ebx ; 压入申请码前8位
1000F3F9 50 push eax ; 压入申请码后8位
1000F3FA 8BCD mov ecx,ebp
1000F3FC 8BFA mov edi,edx ; 保存下计算结果
1000F3FE E8 2D000000 call Adjudica.NRegistrationModule::CRegistrationModule::ScrambleCode
1000F403 03C6 add eax,esi ; 返回结果与上面的结果相加
1000F405 13D7 adc edx,edi ; 返回结果与上面的结果相加
1000F407 52 push edx
1000F408 50 push eax
1000F409 E8 425FFFFF call Adjudica.NRegistrationModule::CRegFormatter::addChecksumToCode ; 把eax和edx中的结果连起来就是激活码
1000F40E 8B4C24 28 mov ecx,dword ptr ss:[esp+28]
1000F412 83C4 08 add esp,8
1000F415 64:890D 0000000>mov dword ptr fs:[0],ecx
1000F41C 5F pop edi
1000F41D 5E pop esi
1000F41E 5D pop ebp
1000F41F 5B pop ebx
1000F420 83C4 1C add esp,1C
1000F423 C2 1000 retn 10

那我们就跑到关键东东里面看看(以下的多少位是指Serial,不包含“-”):
1000F4D6 8B4424 13 mov eax,dword ptr ss:[esp+13]
1000F4DA 8BCE mov ecx,esi
1000F4DC 50 push eax ; 3-10位
1000F4DD E8 CE010000 call Adjudica.NRegistrationModule::CRegistrationModule::FlipBits
1000F4E2 8B4C24 11 mov ecx,dword ptr ss:[esp+11] ; 7-14位
1000F4E6 884424 04 mov byte ptr ss:[esp+4],al ; 结果保存
1000F4EA 51 push ecx
1000F4EB 8BCE mov ecx,esi
1000F4ED E8 BE010000 call Adjudica.NRegistrationModule::CRegistrationModule::FlipBits
1000F4F2 8B5424 15 mov edx,dword ptr ss:[esp+15] ; 00+1-6位
1000F4F6 8BCE mov ecx,esi
1000F4F8 52 push edx
1000F4F9 884424 09 mov byte ptr ss:[esp+9],al ; 结果保存
1000F4FD E8 AE010000 call Adjudica.NRegistrationModule::CRegistrationModule::FlipBits
1000F502 884424 06 mov byte ptr ss:[esp+6],al ; 结果保存
1000F506 8B4424 16 mov eax,dword ptr ss:[esp+16] ; 0000+1-4
1000F50A 50 push eax
1000F50B 8BCE mov ecx,esi
1000F50D E8 9E010000 call Adjudica.NRegistrationModule::CRegistrationModule::FlipBits
1000F512 8B4C24 12 mov ecx,dword ptr ss:[esp+12] ; 5-12
1000F516 884424 07 mov byte ptr ss:[esp+7],al ; 保存
1000F51A 51 push ecx
1000F51B 8BCE mov ecx,esi
1000F51D E8 8E010000 call Adjudica.NRegistrationModule::CRegistrationModule::FlipBits
1000F522 8B5424 14 mov edx,dword ptr ss:[esp+14] ; 1-8
1000F526 8BCE mov ecx,esi
1000F528 52 push edx
1000F529 884424 0C mov byte ptr ss:[esp+C],al ; 保存
1000F52D E8 7E010000 call Adjudica.NRegistrationModule::CRegistrationModule::FlipBits
1000F532 884424 09 mov byte ptr ss:[esp+9],al ; 保存
1000F536 8B4424 17 mov eax,dword ptr ss:[esp+17] ; 000000+1-2
1000F53A 50 push eax
1000F53B 8BCE mov ecx,esi
1000F53D E8 6E010000 call Adjudica.NRegistrationModule::CRegistrationModule::FlipBits
1000F542 8B4C24 10 mov ecx,dword ptr ss:[esp+10]
1000F546 884424 0A mov byte ptr ss:[esp+A],al ; 保存
1000F54A 51 push ecx ; 9-16
1000F54B E9 EC000000 jmp Adjudica.1000F63C
1000F550 8B5424 13 mov edx,dword ptr ss:[esp+13]
1000F554 8BCE mov ecx,esi
1000F556 52 push edx
1000F557 E8 54010000 call Adjudica.NRegistrationModule::CRegistrationModule::FlipBits
1000F55C 884424 04 mov byte ptr ss:[esp+4],al
1000F560 8B4424 11 mov eax,dword ptr ss:[esp+11]
1000F564 50 push eax
1000F565 8BCE mov ecx,esi
1000F567 E8 44010000 call Adjudica.NRegistrationModule::CRegistrationModule::FlipBits
1000F56C 8B4C24 14 mov ecx,dword ptr ss:[esp+14]
1000F570 884424 05 mov byte ptr ss:[esp+5],al
1000F574 51 push ecx
1000F575 8BCE mov ecx,esi
1000F577 E8 34010000 call Adjudica.NRegistrationModule::CRegistrationModule::FlipBits
1000F57C 8B5424 16 mov edx,dword ptr ss:[esp+16]
1000F580 8BCE mov ecx,esi
1000F582 52 push edx
1000F583 884424 0A mov byte ptr ss:[esp+A],al
1000F587 E8 24010000 call Adjudica.NRegistrationModule::CRegistrationModule::FlipBits
1000F58C 884424 07 mov byte ptr ss:[esp+7],al
1000F590 8B4424 12 mov eax,dword ptr ss:[esp+12]
1000F594 50 push eax
1000F595 8BCE mov ecx,esi
1000F597 E8 14010000 call Adjudica.NRegistrationModule::CRegistrationModule::FlipBits
1000F59C 8B4C24 15 mov ecx,dword ptr ss:[esp+15]
1000F5A0 884424 08 mov byte ptr ss:[esp+8],al
1000F5A4 51 push ecx
1000F5A5 8BCE mov ecx,esi
1000F5A7 E8 04010000 call Adjudica.NRegistrationModule::CRegistrationModule::FlipBits
1000F5AC 8B5424 17 mov edx,dword ptr ss:[esp+17]
1000F5B0 8BCE mov ecx,esi
1000F5B2 52 push edx
1000F5B3 884424 0D mov byte ptr ss:[esp+D],al
1000F5B7 E8 F4000000 call Adjudica.NRegistrationModule::CRegistrationModule::FlipBits
1000F5BC 884424 0A mov byte ptr ss:[esp+A],al
1000F5C0 8B4424 10 mov eax,dword ptr ss:[esp+10]
1000F5C4 50 push eax
1000F5C5 EB 75 jmp short Adjudica.1000F63C 一共进行8次计算,后面的我就没帖了

1000F63C 8BCE mov ecx,esi
1000F63E E8 6D000000 call Adjudica.NRegistrationModule::CRegistrationModule::FlipBits
1000F643 884424 0B mov byte ptr ss:[esp+B],al ; 保存
1000F647 8B4424 04 mov eax,dword ptr ss:[esp+4] ; 最终结果
1000F64B 8B5424 08 mov edx,dword ptr ss:[esp+8] ; 最终结果
1000F64F 5E pop esi
1000F650 83C4 08 add esp,8
1000F653 C2 0800 retn 8

发现频繁调用call Adjudica.NRegistrationModule::CRegistrationModule::FlipBits这个函数,进去看看:
10001DA0 8A4C24 04 mov cl,byte ptr ss:[esp+4]
10001DA4 8AC1 mov al,cl
10001DA6 8AD1 mov dl,cl
10001DA8 24 01 and al,1
10001DAA 80E2 02 and dl,2
10001DAD C0E0 02 shl al,2
10001DB0 02C2 add al,dl
10001DB2 8AD1 mov dl,cl
10001DB4 C0E0 02 shl al,2
10001DB7 80E2 04 and dl,4
10001DBA 02C2 add al,dl
10001DBC 8AD1 mov dl,cl
10001DBE C0E0 02 shl al,2
10001DC1 80E2 08 and dl,8
10001DC4 02C2 add al,dl
10001DC6 8AD1 mov dl,cl
10001DC8 D0EA shr dl,1
10001DCA D0E0 shl al,1
10001DCC 80E2 08 and dl,8
10001DCF 02C2 add al,dl
10001DD1 8AD1 mov dl,cl
10001DD3 C0EA 05 shr dl,5
10001DD6 80E2 02 and dl,2
10001DD9 02C2 add al,dl
10001DDB 8AD1 mov dl,cl
10001DDD C0EA 03 shr dl,3
10001DE0 80E2 04 and dl,4
10001DE3 02C2 add al,dl
10001DE5 C0E9 07 shr cl,7
10001DE8 02C1 add al,cl
10001DEA C3 retn

一堆转换,慢慢分析吧^_
我比较懒哈,拖到IDA里面,F5一下出来了,如下:
char __cdecl text_10001DA0(unsigned int8 a1)
{
return (a1 >> 7)
+ ((a1 >> 3) & 4)
+ ((a1 >> 5) & 2)
+ ((a1 >> 1) & 8)
+ 2 * ((a1 & 8) + 4 * ((a1 & 4) + 4 * ((a1 & 2) + 4 * (a1 & 1))));
}

最后算出激活码是:2A3E-2018-A167-963E

算法基本上出来了,我就不总结了……

OK!谢谢观看^_

PS:此文不要转载,Thanks!

已经有(0)位网友发表了评论,你也评一评吧!
原创文章如转载,请注明:转载自Eddy Blog
原文地址:http://www.rrgod.com/technique/210.html     欢迎订阅Eddy Blog

记住我的信息,下次不用再输入 欢迎给Eddy Blog留言