[反汇编练习] 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 "\r"
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 "\r"
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 "\r"
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\r\n\r\n");
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\r\n",(int)dRet);
}else{
printf("Input error!\r\n");
}
system("pause");
return 0;
}