[反汇编练习] 160个CrackMe之003。
本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注册机的东西。
其中,文章中按照如下逻辑编排(解决如下问题):
1、使用什么环境和工具
2、程序分析
3、思路分析和破解流程
4、注册机的探索
1、工具和环境:
WinXP SP3 + 52Pojie六周年纪念版OD + PEID + 汇编金手指。
160个CrackMe的打包文件。
下载地址: http://pan.baidu.com/s/1xUWOY 密码: jbnq
注:
1、Win7系统对于模块和程序开启了随机初始地址的功能,会给分析带来很大的负担,所以不建议使用Win7进行分析。
2、以上工具都是在52PoJie论坛下的原版程序,NOD32不报毒,个人承诺绝对不会进行任何和木马病毒相关内容。
2、程序分析:
想要破解一个程序,必须先了解这个程序。所以,在破解过程中,对最初程序的分析很重要,他可以帮助我们理解作者的目的和意图,特别是对于注册码的处理细节,从而方便我们反向跟踪和推导。
和上一节一样,打开CHM,选择第二个Afkayas,保存下来。运行程序,程序界面如下:
这是一个标准的Name/Serial注册码方式,二话不说,来个伪码测试:
Name: 3333 Serial: 44445555
点击OK,弹出了一个错误对话框,You Get Wrong,Try again!
3、思路分析和破解流程:
首先,将程序从OD打开,这次的程序会提示可能有压缩内容,SO,我们不得不使用PEID看看是否有壳,PEID查看情况如下:
有压缩内容,但是没有壳,很好,放心地使用OD打开,直接点是。
按照经验,有对话框提示的程序可以通过堆栈查找调用的位置。方法如下:输入伪码,点击OK,弹出错误对话框,此时不要关闭这个对话框,切换到OD,点击暂停程序,然后Ctrl+K到堆栈视图,如下:
更具体的分析就不说了,参看002,直接最后一个rtcMsgBox,右键->show call。
vba相关函数请参考这篇文章。
将代码直接向上翻看,找到了关键的跳转,JE,代码如下:
00408665 . 66:85F6 test si,si 00408668 . 8945 94 mov dword ptr ss:[ebp-0x6C],eax 0040866B . 894D AC mov dword ptr ss:[ebp-0x54],ecx 0040866E . 8945 A4 mov dword ptr ss:[ebp-0x5C],eax 00408671 . 894D BC mov dword ptr ss:[ebp-0x44],ecx 00408674 . 8945 B4 mov dword ptr ss:[ebp-0x4C],eax 00408677 74 62 je short 004086DB ; // 爆破的关键 00408679 . 8B35 14B14000 mov esi,dword ptr ds:[<&MSVBVM50.__vbaSt>; msvbvm50.__vbaStrCat 0040867F . 68 C06F4000 push 00406FC0 ; UNICODE "You Get It" 00408684 . 68 DC6F4000 push 00406FDC ; ASCII " " 00408689 . FFD6 call esi ; <&MSVBVM50.__vbaStrCat> 0040868B . 8BD0 mov edx,eax 0040868D . 8D4D E8 lea ecx,dword ptr ss:[ebp-0x18] 00408690 . FF15 94B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrMo>; msvbvm50.__vbaStrMove 00408696 . 50 push eax 00408697 . 68 E86F4000 push 00406FE8 ; UNICODE "KeyGen It Now" 0040869C . FFD6 call esi 0040869E . 8945 CC mov dword ptr ss:[ebp-0x34],eax 004086A1 . 8D45 94 lea eax,dword ptr ss:[ebp-0x6C] 004086A4 . 8D4D A4 lea ecx,dword ptr ss:[ebp-0x5C] 004086A7 . 50 push eax 004086A8 . 8D55 B4 lea edx,dword ptr ss:[ebp-0x4C] 004086AB . 51 push ecx 004086AC . 52 push edx 004086AD . 8D45 C4 lea eax,dword ptr ss:[ebp-0x3C] 004086B0 . 6A 00 push 0x0 004086B2 . 50 push eax 004086B3 . C745 C4 08000>mov dword ptr ss:[ebp-0x3C],0x8 004086BA . FF15 24B14000 call dword ptr ds:[<&MSVBVM50.#595>] ; msvbvm50.rtcMsgBox 004086C0 . 8D4D E8 lea ecx,dword ptr ss:[ebp-0x18] 004086C3 . FF15 A8B14000 call dword ptr ds:[<&MSVBVM50.__vbaFreeS>; msvbvm50.__vbaFreeStr 004086C9 . 8D4D 94 lea ecx,dword ptr ss:[ebp-0x6C] 004086CC . 8D55 A4 lea edx,dword ptr ss:[ebp-0x5C] 004086CF . 51 push ecx 004086D0 . 8D45 B4 lea eax,dword ptr ss:[ebp-0x4C] 004086D3 . 52 push edx 004086D4 . 8D4D C4 lea ecx,dword ptr ss:[ebp-0x3C] 004086D7 . 50 push eax 004086D8 . 51 push ecx 004086D9 . EB 60 jmp short 0040873B 004086DB > 8B35 14B14000 mov esi,dword ptr ds:[<&MSVBVM50.__vbaSt>; msvbvm50.__vbaStrCat 004086E1 . 68 08704000 push 00407008 ; UNICODE "You Get Wrong" 004086E6 . 68 DC6F4000 push 00406FDC ; ASCII " " 004086EB . FFD6 call esi ; <&MSVBVM50.__vbaStrCat> 004086ED . 8BD0 mov edx,eax 004086EF . 8D4D E8 lea ecx,dword ptr ss:[ebp-0x18] 004086F2 . FF15 94B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrMo>; msvbvm50.__vbaStrMove 004086F8 . 50 push eax 004086F9 . 68 28704000 push 00407028 ; UNICODE "Try Again" 004086FE . FFD6 call esi 00408700 . 8945 CC mov dword ptr ss:[ebp-0x34],eax 00408703 . 8D55 94 lea edx,dword ptr ss:[ebp-0x6C] 00408706 . 8D45 A4 lea eax,dword ptr ss:[ebp-0x5C] 00408709 . 52 push edx 0040870A . 8D4D B4 lea ecx,dword ptr ss:[ebp-0x4C] 0040870D . 50 push eax 0040870E . 51 push ecx 0040870F . 8D55 C4 lea edx,dword ptr ss:[ebp-0x3C] 00408712 . 6A 00 push 0x0 00408714 . 52 push edx 00408715 . C745 C4 08000>mov dword ptr ss:[ebp-0x3C],0x8 0040871C . FF15 24B14000 call dword ptr ds:[<&MSVBVM50.#595>] ; msvbvm50.rtcMsgBox
爆破就不用说了,直接选中JE语句,右键->Binary->Fill with NOPs. 试一试,OK,爆破成功。
4、注册机的探索:
这个程序和002基本一样的,在跳转附近无任何和Name/Serial相关的内容,所以,向上找到这段代码的开头,下断,一路F8记录重要信息。
PS:由于这个代码太长,只将重要片段拿出来。查找开头时不要急,代码真的很长。需要特别注意和Name/Serial相关的部分。
开头下断位置:
004080F0 > 55 push ebp 004080F1 . 8BEC mov ebp,esp 004080F3 . 83EC 0C sub esp,0xC 004080F6 . 68 56104000 push <jmp.&MSVBVM50.__vbaExceptHandler> ; SE handler installation 004080FB . 64:A1 0000000>mov eax,dword ptr fs:[0]
获取Name的位置:
004081E3 . FF15 18B14000 call dword ptr ds:[<&MSVBVM50.__vbaHresu>; msvbvm50.__vbaHresultCheckObj 004081E9 > 8B95 50FFFFFF mov edx,dword ptr ss:[ebp-0xB0] 004081EF . 8B45 E4 mov eax,dword ptr ss:[ebp-0x1C] 004081F2 . 50 push eax ; // eax=3333地址 004081F3 . 8B1A mov ebx,dword ptr ds:[edx] 004081F5 . FF15 F8B04000 call dword ptr ds:[<&MSVBVM50.__vbaLenBs>; msvbvm50.__vbaLenBstr 004081FB . 8BF8 mov edi,eax ; // eax=4 004081FD . 8B4D E8 mov ecx,dword ptr ss:[ebp-0x18] 00408200 . 69FF 385B0100 imul edi,edi,0x15B38 ; // edi=edi*0x15B38 00408206 . 51 push ecx 00408207 . 0F80 B7050000 jo 004087C4 0040820D . FF15 0CB14000 call dword ptr ds:[<&MSVBVM50.#516>] ; msvbvm50.rtcAnsiValueBstr 00408213 . 0FBFD0 movsx edx,ax ; // edx = 第一个字符的ANSI 00408216 . 03FA add edi,edx ; // edi=edi+edx 00408218 . 0F80 A6050000 jo 004087C4 0040821E . 57 push edi 0040821F . FF15 F4B04000 call dword ptr ds:[<&MSVBVM50.__vbaStrI4>; msvbvm50.__vbaStrI4 00408225 . 8BD0 mov edx,eax ; // eax = 355603 文本 00408227 . 8D4D E0 lea ecx,dword ptr ss:[ebp-0x20] 0040822A . FF15 94B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrMo>; msvbvm50.__vbaStrMove 00408230 . 8BBD 50FFFFFF mov edi,dword ptr ss:[ebp-0xB0] 00408236 . 50 push eax ; eax=355603 00408237 . 57 push edi ; edi=0091C5B4 00408238 . FF93 A4000000 call dword ptr ds:[ebx+0xA4] 0040823E . 85C0 test eax,eax ; // eax=0 00408240 . 7D 12 jge short 00408254
第一次计算(浮点数):
004082D7 . FF15 18B14000 call dword ptr ds:[<&MSVBVM50.__vbaHresu>; msvbvm50.__vbaHresultCheckObj 004082DD > 8B8D 58FFFFFF mov ecx,dword ptr ss:[ebp-0xA8] 004082E3 . 8B55 E8 mov edx,dword ptr ss:[ebp-0x18] 004082E6 . 52 push edx ; // edx=355603 004082E7 . 8B19 mov ebx,dword ptr ds:[ecx] 004082E9 . FF15 74B14000 call dword ptr ds:[<&MSVBVM50.__vbaR8Str>; msvbvm50.__vbaR8Str 004082EF . D905 08104000 fld dword ptr ds:[0x401008] ; // 10.0 004082F5 . 833D 00904000>cmp dword ptr ds:[0x409000],0x0 004082FC . 75 08 jnz short 00408306 004082FE . D835 0C104000 fdiv dword ptr ds:[0x40100C] ; // 5.0, 做除法==2。0 00408304 . EB 0B jmp short 00408311 00408306 > FF35 0C104000 push dword ptr ds:[0x40100C] 0040830C . E8 578DFFFF call <jmp.&MSVBVM50._adj_fdiv_m32> 00408311 > 83EC 08 sub esp,0x8 00408314 . DFE0 fstsw ax ; // 将值给eax=3100 00408316 . A8 0D test al,0xD 00408318 . 0F85 A1040000 jnz 004087BF 0040831E . DEC1 faddp st(1),st ; // 加法,355603 + 2 00408320 . DFE0 fstsw ax 00408322 . A8 0D test al,0xD 00408324 . 0F85 95040000 jnz 004087BF 0040832A . DD1C24 fstp qword ptr ss:[esp] 0040832D . FF15 48B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrR8>; msvbvm50.__vbaStrR8 00408333 . 8BD0 mov edx,eax ; // eax = 355605 字符串 00408335 . 8D4D E4 lea ecx,dword ptr ss:[ebp-0x1C] 00408338 . FF15 94B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrMo>; msvbvm50.__vbaStrMove 0040833E . 899D 34FFFFFF mov dword ptr ss:[ebp-0xCC],ebx 00408344 . 8B9D 58FFFFFF mov ebx,dword ptr ss:[ebp-0xA8] 0040834A . 50 push eax 0040834B . 8B85 34FFFFFF mov eax,dword ptr ss:[ebp-0xCC] ; // 355605 00408351 . 53 push ebx 00408352 . FF90 A4000000 call dword ptr ds:[eax+0xA4] 00408358 . 85C0 test eax,eax ; // eax=0,ecx=" " 0040835A . 7D 12 jge short 0040836E
第二次计算(浮点数):
004083E3 . FF15 18B14000 call dword ptr ds:[<&MSVBVM50.__vbaHresu>; msvbvm50.__vbaHresultCheckObj 004083E9 > 8B8D 58FFFFFF mov ecx,dword ptr ss:[ebp-0xA8] 004083EF . 8B55 E8 mov edx,dword ptr ss:[ebp-0x18] ; // 355605 004083F2 . 52 push edx 004083F3 . 8B19 mov ebx,dword ptr ds:[ecx] 004083F5 . FF15 74B14000 call dword ptr ds:[<&MSVBVM50.__vbaR8Str>; msvbvm50.__vbaR8Str 004083FB . DC0D 10104000 fmul qword ptr ds:[0x401010] ; // 355605 * 3 = 1066815.0 00408401 . 83EC 08 sub esp,0x8 00408404 . DC25 18104000 fsub qword ptr ds:[0x401018] ; // 1066815 - 2 = 1066813 0040840A . DFE0 fstsw ax ; // ax = 3900 0040840C . A8 0D test al,0xD 0040840E . 0F85 AB030000 jnz 004087BF 00408414 . DD1C24 fstp qword ptr ss:[esp] 00408417 . FF15 48B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrR8>; msvbvm50.__vbaStrR8 0040841D . 8BD0 mov edx,eax ; // eax=1600133 0040841F . 8D4D E4 lea ecx,dword ptr ss:[ebp-0x1C] 00408422 . FF15 94B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrMo>; msvbvm50.__vbaStrMove 00408428 . 899D 2CFFFFFF mov dword ptr ss:[ebp-0xD4],ebx 0040842E . 8B9D 58FFFFFF mov ebx,dword ptr ss:[ebp-0xA8] 00408434 . 50 push eax ; 1066813 00408435 . 8B85 2CFFFFFF mov eax,dword ptr ss:[ebp-0xD4] 0040843B . 53 push ebx 0040843C . FF90 A4000000 call dword ptr ds:[eax+0xA4] 00408442 . 85C0 test eax,eax 00408444 . 7D 12 jge short 00408458
第三次计算(浮点数):
004084CD . FF15 18B14000 call dword ptr ds:[<&MSVBVM50.__vbaHresu>; msvbvm50.__vbaHresultCheckObj 004084D3 > 8B8D 58FFFFFF mov ecx,dword ptr ss:[ebp-0xA8] 004084D9 . 8B55 E8 mov edx,dword ptr ss:[ebp-0x18] 004084DC . 52 push edx 004084DD . 8B19 mov ebx,dword ptr ds:[ecx] 004084DF . FF15 74B14000 call dword ptr ds:[<&MSVBVM50.__vbaR8Str>; msvbvm50.__vbaR8Str 004084E5 . DC25 20104000 fsub qword ptr ds:[0x401020] ; // 1066813.0 - (-15.0) = 1066828 004084EB . 83EC 08 sub esp,0x8 004084EE . DFE0 fstsw ax 004084F0 . A8 0D test al,0xD 004084F2 . 0F85 C7020000 jnz 004087BF 004084F8 . DD1C24 fstp qword ptr ss:[esp] 004084FB . FF15 48B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrR8>; msvbvm50.__vbaStrR8 00408501 . 8BD0 mov edx,eax ; // 1066828 00408503 . 8D4D E4 lea ecx,dword ptr ss:[ebp-0x1C] 00408506 . FF15 94B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrMo>; msvbvm50.__vbaStrMove
我们的Serial出现了:
004085C8 . FF15 18B14000 call dword ptr ds:[<&MSVBVM50.__vbaHresu>; msvbvm50.__vbaHresultCheckObj 004085CE > 8B45 E8 mov eax,dword ptr ss:[ebp-0x18] 004085D1 . 50 push eax ; // 获取Serial 004085D2 . FF15 74B14000 call dword ptr ds:[<&MSVBVM50.__vbaR8Str>; msvbvm50.__vbaR8Str 004085D8 . 8B4D E4 mov ecx,dword ptr ss:[ebp-0x1C] ; // 1066828 004085DB . DD9D 1CFFFFFF fstp qword ptr ss:[ebp-0xE4] 004085E1 . 51 push ecx 004085E2 . FF15 74B14000 call dword ptr ds:[<&MSVBVM50.__vbaR8Str>; msvbvm50.__vbaR8Str 004085E8 . 833D 00904000>cmp dword ptr ds:[0x409000],0x0 004085EF . 75 08 jnz short 004085F9 004085F1 . DCBD 1CFFFFFF fdivr qword ptr ss:[ebp-0xE4] ; // 做除法 004085F7 . EB 11 jmp short 0040860A 004085F9 > FFB5 20FFFFFF push dword ptr ss:[ebp-0xE0] 004085FF . FFB5 1CFFFFFF push dword ptr ss:[ebp-0xE4] 00408605 . E8 888AFFFF call <jmp.&MSVBVM50._adj_fdivr_m64> 0040860A > DFE0 fstsw ax ; // 把结果送入ax 0040860C . A8 0D test al,0xD 0040860E . 0F85 AB010000 jnz 004087BF 00408614 . FF15 34B14000 call dword ptr ds:[<&MSVBVM50.__vbaFpR8>>; msvbvm50.__vbaFpR8 0040861A . DC1D 28104000 fcomp qword ptr ds:[0x401028] 00408620 . DFE0 fstsw ax ; //ax=20 00408622 . F6C4 40 test ah,0x40 ; // ah=40 00408625 . 74 07 je short 0040862E
后面做的除法运算和取反,为了处理esi的值,然后做为JE的条件。我们到这里其实就可以试试算出来的字符串“1066828”是否是正确的?哈哈,他肯定是的啦!
00408665 . 66:85F6 test si,si 00408668 . 8945 94 mov dword ptr ss:[ebp-0x6C],eax 0040866B . 894D AC mov dword ptr ss:[ebp-0x54],ecx 0040866E . 8945 A4 mov dword ptr ss:[ebp-0x5C],eax 00408671 . 894D BC mov dword ptr ss:[ebp-0x44],ecx 00408674 . 8945 B4 mov dword ptr ss:[ebp-0x4C],eax 00408677 74 62 je short 004086DB ; // 爆破的关键 00408679 . 8B35 14B14000 mov esi,dword ptr ds:[<&MSVBVM50.__vbaSt>; msvbvm50.__vbaStrCat 0040867F . 68 C06F4000 push 00406FC0 ; UNICODE "You Get It" 00408684 . 68 DC6F4000 push 00406FDC ; ASCII " " 00408689 . FFD6 call esi ; <&MSVBVM50.__vbaStrCat>
至此,序列号的生成过程已经分析完毕。过程中设计到的常量都是使用[0040100A]等固定地址得到的固定值,不用理会,我们可以直接使用。
小结一下:先计算出Name的长度nLen,然后edi=edi*0x15B38+cName, cName是Name第一个字符的ANSI码。然后,计算浮点数10.0/5.0=2.0, edi转换为浮点数,加上2.0,然后结果再乘以3.0,然后减去2,然后再减去-15,得到的值转换为文本,即为正确的序列号。
C/CPP代码:
// CrackMe160.cpp : 定义控制台应用程序的入口点。 // 003 #include "stdafx.h" #include <stdio.h> #include "iostream" char buff[100] = {0}; int _tmain(int argc, _TCHAR* argv[]) { printf("160CrackMe-003 Name/Serial "); printf("Name:"); gets_s(buff,100); int nLen = strlen(buff); if ( nLen > 0 ) { int nRet = nLen * 0x15B38; nRet += buff[0]; double dRet = (double)nRet; dRet += (10.0/5.0); dRet *= 3.0; dRet -= 2; dRet -= -15; printf("Serial:%d ",(int)dRet); }else{ printf("Input error! "); } system("pause"); return 0; }