[反汇编练习] 160个CrackMe之002。
本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将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,保存下来。运行程序,崩溃,缺少msvbvm50.dll,程序无法运行。没办法,上网上搜索一个,放到程序同一级目录,再次运行,OK。程序界面如下:
这是一个标准的Name/Serial注册码方式,二话不说,来个伪码测试:
Name: 111222 Serial: 3334444
点击OK,弹出了一个错误对话框,You Get Wrong,Try again!
3、思路分析和破解流程:
首先,按照经验,有对话框提示的程序可以通过堆栈查找调用的位置。方法如下:输入伪码,点击OK,弹出错误对话框,此时不要关闭这个对话框,切换到OD,点击暂停程序,然后Ctrl+K到堆栈视图,如下:
到了这里基本蒙圈了,竟然不是一般的C/C++代码,看看后面的Called from大部分来自msvbvm50,user32,根据名称百度一下,发现是使用VB的模块写的。再查看红色部分,发现表面上和对话框相关的只有msvbvm50.rtcmsgbox和user32.MessageBoxIndirectA,最主要的是msvbvm50.rtcMsgBox的调用来自AfKayas_.0040261C,所以我们基本可以断定rtcMsgBox是Vb中弹出对话框相关的东西,不要犹豫,选中它,右键->show call。
004025E3 . /EB 56 jmp short 0040263B 004025E5 > |68 C81B4000 push 00401BC8 ; UNICODE "You Get Wrong" 004025EA . |68 9C1B4000 push 00401B9C ; ASCII " " 004025EF . |FFD7 call edi 004025F1 . |8BD0 mov edx,eax 004025F3 . |8D4D E8 lea ecx,dword ptr ss:[ebp-0x18] 004025F6 . |FFD3 call ebx 004025F8 . |50 push eax 004025F9 . |68 E81B4000 push 00401BE8 ; UNICODE "Try Again" 004025FE . |FFD7 call edi 00402600 . |8945 CC mov dword ptr ss:[ebp-0x34],eax 00402603 . |8D45 94 lea eax,dword ptr ss:[ebp-0x6C] 00402606 . |8D4D A4 lea ecx,dword ptr ss:[ebp-0x5C] 00402609 . |50 push eax 0040260A . |8D55 B4 lea edx,dword ptr ss:[ebp-0x4C] 0040260D . |51 push ecx 0040260E . |52 push edx 0040260F . |8D45 C4 lea eax,dword ptr ss:[ebp-0x3C] 00402612 . |6A 00 push 0x0 00402614 . |50 push eax 00402615 . |C745 C4 08000>mov dword ptr ss:[ebp-0x3C],0x8 0040261C . |FF15 10414000 call dword ptr ds:[<&MSVBVM50.#595>] ; msvbvm50.rtcMsgBox
将代码稍微向上查看,发现最近的地方就有“Try again”和“You get wrong”的提示,我们基本就可以断定就是这里了。继续向上,看看判断的逻辑部分在哪里:
00402569 . 83C4 0C add esp,0xC 0040256C . B9 04000280 mov ecx,0x80020004 00402571 . B8 0A000000 mov eax,0xA 00402576 . 894D 9C mov dword ptr ss:[ebp-0x64],ecx 00402579 . 66:85F6 test si,si 0040257C . 8945 94 mov dword ptr ss:[ebp-0x6C],eax 0040257F . 894D AC mov dword ptr ss:[ebp-0x54],ecx 00402582 . 8945 A4 mov dword ptr ss:[ebp-0x5C],eax 00402585 . 894D BC mov dword ptr ss:[ebp-0x44],ecx 00402588 . 8945 B4 mov dword ptr ss:[ebp-0x4C],eax 0040258B . 74 58 je short 004025E5 ; 判断应该是这里吧? 0040258D . 68 801B4000 push 00401B80 ; UNICODE "You Get It" 00402592 . 68 9C1B4000 push 00401B9C ; ASCII " " 00402597 . FFD7 call edi 00402599 . 8BD0 mov edx,eax 0040259B . 8D4D E8 lea ecx,dword ptr ss:[ebp-0x18] 0040259E . FFD3 call ebx 004025A0 . 50 push eax 004025A1 . 68 A81B4000 push 00401BA8 ; UNICODE "KeyGen It Now" 004025A6 . FFD7 call edi 004025A8 . 8D4D 94 lea ecx,dword ptr ss:[ebp-0x6C] 004025AB . 8945 CC mov dword ptr ss:[ebp-0x34],eax 004025AE . 8D55 A4 lea edx,dword ptr ss:[ebp-0x5C] 004025B1 . 51 push ecx 004025B2 . 8D45 B4 lea eax,dword ptr ss:[ebp-0x4C] 004025B5 . 52 push edx 004025B6 . 50 push eax 004025B7 . 8D4D C4 lea ecx,dword ptr ss:[ebp-0x3C] 004025BA . 6A 00 push 0x0 004025BC . 51 push ecx 004025BD . C745 C4 08000>mov dword ptr ss:[ebp-0x3C],0x8 004025C4 . FF15 10414000 call dword ptr ds:[<&MSVBVM50.#595>] ; msvbvm50.rtcMsgBox 004025CA . 8D4D E8 lea ecx,dword ptr ss:[ebp-0x18] 004025CD . FF15 80414000 call dword ptr ds:[<&MSVBVM50.__vbaFreeS>; msvbvm50.__vbaFreeStr 004025D3 . 8D55 94 lea edx,dword ptr ss:[ebp-0x6C] 004025D6 . 8D45 A4 lea eax,dword ptr ss:[ebp-0x5C] 004025D9 . 52 push edx 004025DA . 8D4D B4 lea ecx,dword ptr ss:[ebp-0x4C] 004025DD . 50 push eax 004025DE . 8D55 C4 lea edx,dword ptr ss:[ebp-0x3C] 004025E1 . 51 push ecx 004025E2 . 52 push edx 004025E3 . EB 56 jmp short 0040263B 004025E5 > 68 C81B4000 push 00401BC8 ; UNICODE "You Get Wrong" 004025EA . 68 9C1B4000 push 00401B9C ; ASCII " " 004025EF . FFD7 call edi 004025F1 . 8BD0 mov edx,eax 004025F3 . 8D4D E8 lea ecx,dword ptr ss:[ebp-0x18] 004025F6 . FFD3 call ebx 004025F8 . 50 push eax 004025F9 . 68 E81B4000 push 00401BE8 ; UNICODE "Try Again" 004025FE . FFD7 call edi
很简单吧?直接在”You get it ”的旁边就有一个JE跳转,在OD查看发现如果跳转实现就提示错误,不实现就提示正确,爆破开始啦!选中je那一行,右键->Binary->Fill with NOPs. 这时在程序里随意输入试试,哈哈,爆破成功!
4、注册机探索:
由于我们在跳转附近没有发现任何类注册码的东西,所以,我们需要将这里块的内容F8跟踪一下,大概地看看那些地方可能和注册码相关。我们向上查找,在这段程序的开头(即找到最近的那个retn,下面开头一般是push ebp等)下断点:
00402310 > 55 push ebp // 程序段头
单步F8跟踪,将重要信息添加注释,特别是和Name/Serial相关的东西,分析后代码如下:
00402403 . FF15 04414000 call dword ptr ds:[<&MSVBVM50.__vbaHresultChec>; MSVBVM50.__vbaHresultCheckObj 00402409 > 8B95 50FFFFFF mov edx,dword ptr ss:[ebp-0xB0] 0040240F . 8B45 E4 mov eax,dword ptr ss:[ebp-0x1C] 00402412 . 50 push eax ; //eax=111222,name 00402413 . 8B1A mov ebx,dword ptr ds:[edx] 00402415 . FF15 E4404000 call dword ptr ds:[<&MSVBVM50.__vbaLenBstr>] ; MSVBVM50.__vbaLenBstr 0040241B . 8BF8 mov edi,eax ; edi=6 0040241D . 8B4D E8 mov ecx,dword ptr ss:[ebp-0x18] ; ecx=1111222地址 00402420 . 69FF FB7C0100 imul edi,edi,0x17CFB ; // 乘法,edi*0x17CFB 00402426 . 51 push ecx 00402427 . 0F80 91020000 jo 004026BE 0040242D . FF15 F8404000 call dword ptr ds:[<&MSVBVM50.#516>] ; MSVBVM50.rtcAnsiValueBstr 00402433 . 0FBFD0 movsx edx,ax 00402436 . 03FA add edi,edx ; // edi=edi+edx(0x31) 00402438 . 0F80 80020000 jo 004026BE 0040243E . 57 push edi 0040243F . FF15 E0404000 call dword ptr ds:[<&MSVBVM50.__vbaStrI4>] ; MSVBVM50.__vbaStrI4 00402445 . 8BD0 mov edx,eax ; // eax=585235 00402447 . 8D4D E0 lea ecx,dword ptr ss:[ebp-0x20] 0040244A . FF15 70414000 call dword ptr ds:[<&MSVBVM50.__vbaStrMove>] ; MSVBVM50.__vbaStrMove 00402450 . 8BBD 50FFFFFF mov edi,dword ptr ss:[ebp-0xB0] 00402456 . 50 push eax ; // 585235 00402457 . 57 push edi ; // 0091B51C 00402458 . FF93 A4000000 call dword ptr ds:[ebx+0xA4] 0040245E . 85C0 test eax,eax ; // ==0 00402460 . 7D 12 jge short 00402474 00402462 . 68 A4000000 push 0xA4 00402467 . 68 5C1B4000 push 00401B5C 0040246C . 57 push edi 0040246D . 50 push eax 0040246E . FF15 04414000 call dword ptr ds:[<&MSVBVM50.__vbaHresultChec>; MSVBVM50.__vbaHresultCheckObj 00402474 > 8D45 E0 lea eax,dword ptr ss:[ebp-0x20] 00402477 . 8D4D E4 lea ecx,dword ptr ss:[ebp-0x1C] 0040247A . 50 push eax 0040247B . 8D55 E8 lea edx,dword ptr ss:[ebp-0x18] 0040247E . 51 push ecx 0040247F . 52 push edx 00402480 . 6A 03 push 0x3 00402482 . FF15 5C414000 call dword ptr ds:[<&MSVBVM50.__vbaFreeStrList>; MSVBVM50.__vbaFreeStrList 00402488 . 83C4 10 add esp,0x10 0040248B . 8D45 D4 lea eax,dword ptr ss:[ebp-0x2C] 0040248E . 8D4D D8 lea ecx,dword ptr ss:[ebp-0x28] 00402491 . 8D55 DC lea edx,dword ptr ss:[ebp-0x24] 00402494 . 50 push eax 00402495 . 51 push ecx 00402496 . 52 push edx 00402497 . 6A 03 push 0x3 00402499 . FF15 F4404000 call dword ptr ds:[<&MSVBVM50.__vbaFreeObjList>; MSVBVM50.__vbaFreeObjList 0040249F . 8B06 mov eax,dword ptr ds:[esi] 004024A1 . 83C4 10 add esp,0x10 004024A4 . 56 push esi 004024A5 . FF90 04030000 call dword ptr ds:[eax+0x304] 004024AB . 8B1D 0C414000 mov ebx,dword ptr ds:[<&MSVBVM50.__vbaObjSet>] ; MSVBVM50.__vbaObjSet 004024B1 . 50 push eax 004024B2 . 8D45 DC lea eax,dword ptr ss:[ebp-0x24] 004024B5 . 50 push eax 004024B6 . FFD3 call ebx ; <&MSVBVM50.__vbaObjSet> 004024B8 . 8BF8 mov edi,eax 004024BA . 8D55 E8 lea edx,dword ptr ss:[ebp-0x18] 004024BD . 52 push edx 004024BE . 57 push edi 004024BF . 8B0F mov ecx,dword ptr ds:[edi] 004024C1 . FF91 A0000000 call dword ptr ds:[ecx+0xA0] 004024C7 . 85C0 test eax,eax ; eax=0,zf=1 004024C9 . 7D 12 jge short 004024DD 004024CB . 68 A0000000 push 0xA0 004024D0 . 68 5C1B4000 push 00401B5C 004024D5 . 57 push edi 004024D6 . 50 push eax 004024D7 . FF15 04414000 call dword ptr ds:[<&MSVBVM50.__vbaHresultChec>; MSVBVM50.__vbaHresultCheckObj 004024DD > 56 push esi 004024DE . FF95 40FFFFFF call dword ptr ss:[ebp-0xC0] 004024E4 . 50 push eax 004024E5 . 8D45 D8 lea eax,dword ptr ss:[ebp-0x28] 004024E8 . 50 push eax 004024E9 . FFD3 call ebx 004024EB . 8BF0 mov esi,eax 004024ED . 8D55 E4 lea edx,dword ptr ss:[ebp-0x1C] 004024F0 . 52 push edx 004024F1 . 56 push esi 004024F2 . 8B0E mov ecx,dword ptr ds:[esi] 004024F4 . FF91 A0000000 call dword ptr ds:[ecx+0xA0] 004024FA . 85C0 test eax,eax ; eax=0 004024FC . 7D 12 jge short 00402510 004024FE . 68 A0000000 push 0xA0 00402503 . 68 5C1B4000 push 00401B5C 00402508 . 56 push esi 00402509 . 50 push eax 0040250A . FF15 04414000 call dword ptr ds:[<&MSVBVM50.__vbaHresultChec>; MSVBVM50.__vbaHresultCheckObj 00402510 > 8B45 E8 mov eax,dword ptr ss:[ebp-0x18] ; eax=3334444 00402513 . 8B4D E4 mov ecx,dword ptr ss:[ebp-0x1C] ; ecx=585235 00402516 . 8B3D 00414000 mov edi,dword ptr ds:[<&MSVBVM50.__vbaStrCat>] ; MSVBVM50.__vbaStrCat 0040251C . 50 push eax ; eax=3334444 0040251D . 68 701B4000 push 00401B70 ; UNICODE "AKA-" 00402522 . 51 push ecx ; ecx=585235 00402523 . FFD7 call edi ; <&MSVBVM50.__vbaStrCat> 00402525 . 8B1D 70414000 mov ebx,dword ptr ds:[<&MSVBVM50.__vbaStrMove>>; MSVBVM50.__vbaStrMove 0040252B . 8BD0 mov edx,eax ; edx=eax=AKA-585235 0040252D . 8D4D E0 lea ecx,dword ptr ss:[ebp-0x20] 00402530 . FFD3 call ebx ; <&MSVBVM50.__vbaStrMove> 00402532 . 50 push eax 00402533 . FF15 28414000 call dword ptr ds:[<&MSVBVM50.__vbaStrCmp>] ; MSVBVM50.__vbaStrCmp 00402539 . 8BF0 mov esi,eax ; eax=-1 0040253B . 8D55 E0 lea edx,dword ptr ss:[ebp-0x20] 0040253E . F7DE neg esi ; 取补 00402540 . 8D45 E8 lea eax,dword ptr ss:[ebp-0x18] 00402543 . 52 push edx 00402544 . 1BF6 sbb esi,esi 00402546 . 8D4D E4 lea ecx,dword ptr ss:[ebp-0x1C] 00402549 . 50 push eax 0040254A . 46 inc esi 0040254B . 51 push ecx 0040254C . 6A 03 push 0x3 0040254E . F7DE neg esi 00402550 . FF15 5C414000 call dword ptr ds:[<&MSVBVM50.__vbaFreeStrList>; MSVBVM50.__vbaFreeStrList 00402556 . 83C4 10 add esp,0x10 00402559 . 8D55 D8 lea edx,dword ptr ss:[ebp-0x28] 0040255C . 8D45 DC lea eax,dword ptr ss:[ebp-0x24] 0040255F . 52 push edx 00402560 . 50 push eax 00402561 . 6A 02 push 0x2 00402563 . FF15 F4404000 call dword ptr ds:[<&MSVBVM50.__vbaFreeObjList>; MSVBVM50.__vbaFreeObjList 00402569 . 83C4 0C add esp,0xC 0040256C . B9 04000280 mov ecx,0x80020004 00402571 . B8 0A000000 mov eax,0xA 00402576 . 894D 9C mov dword ptr ss:[ebp-0x64],ecx 00402579 . 66:85F6 test si,si ; esi=0,ZF=1 0040257C . 8945 94 mov dword ptr ss:[ebp-0x6C],eax 0040257F . 894D AC mov dword ptr ss:[ebp-0x54],ecx 00402582 . 8945 A4 mov dword ptr ss:[ebp-0x5C],eax 00402585 . 894D BC mov dword ptr ss:[ebp-0x44],ecx 00402588 . 8945 B4 mov dword ptr ss:[ebp-0x4C],eax 0040258B 74 58 je short 004025E5 ; // 爆破关键跳,NOP 0040258D . 68 801B4000 push 00401B80 ; UNICODE "You Get It" 00402592 . 68 9C1B4000 push 00401B9C ; ASCII " " 00402597 . FFD7 call edi
其实代码很简单,经过一遍跟踪,基本都出来了,重点分析部分如下:
00402412 . 50 push eax ; //eax=111222,name 00402413 . 8B1A mov ebx,dword ptr ds:[edx] 00402415 . FF15 E4404000 call dword ptr ds:[<&MSVBVM50.__vbaLenBstr>] ; MSVBVM50.__vbaLenBstr 0040241B . 8BF8 mov edi,eax ; edi=6 0040241D . 8B4D E8 mov ecx,dword ptr ss:[ebp-0x18] ; ecx=1111222地址 00402420 . 69FF FB7C0100 imul edi,edi,0x17CFB ; // 乘法,edi*0x17CFB 00402426 . 51 push ecx 00402427 . 0F80 91020000 jo 004026BE 0040242D . FF15 F8404000 call dword ptr ds:[<&MSVBVM50.#516>] ; MSVBVM50.rtcAnsiValueBstr 00402433 . 0FBFD0 movsx edx,ax 00402436 . 03FA add edi,edx ; // edi=edi+edx(0x31) 00402438 . 0F80 80020000 jo 004026BE 0040243E . 57 push edi 0040243F . FF15 E0404000 call dword ptr ds:[<&MSVBVM50.__vbaStrI4>] ; MSVBVM50.__vbaStrI4 00402445 . 8BD0 mov edx,eax ; // eax=585235
首先,eax为Name的地址,经过__vbaLenBstr计算的长度赋值给edi,然后edi=edi*0x17CFB,接着edi=edi+edx,而edx为Name字符串第一个字符Ansi的值,最后进过__vbaStrI4将edi的整数值转换为十进制字符串585235。
然后向下跟踪和字符串585235相关的东西:
00402510 > 8B45 E8 mov eax,dword ptr ss:[ebp-0x18] ; eax=3334444 00402513 . 8B4D E4 mov ecx,dword ptr ss:[ebp-0x1C] ; ecx=585235 00402516 . 8B3D 00414000 mov edi,dword ptr ds:[<&MSVBVM50.__vbaStrCat>] ; MSVBVM50.__vbaStrCat 0040251C . 50 push eax ; eax=3334444 0040251D . 68 701B4000 push 00401B70 ; UNICODE "AKA-" 00402522 . 51 push ecx ; ecx=585235 00402523 . FFD7 call edi ; <&MSVBVM50.__vbaStrCat> 00402525 . 8B1D 70414000 mov ebx,dword ptr ds:[<&MSVBVM50.__vbaStrMove>>; MSVBVM50.__vbaStrMove 0040252B . 8BD0 mov edx,eax ; edx=eax=AKA-585235 0040252D . 8D4D E0 lea ecx,dword ptr ss:[ebp-0x20] 00402530 . FFD3 call ebx ; <&MSVBVM50.__vbaStrMove> 00402532 . 50 push eax 00402533 . FF15 28414000 call dword ptr ds:[<&MSVBVM50.__vbaStrCmp>] ; MSVBVM50.__vbaStrCmp 00402539 . 8BF0 mov esi,eax ; eax=-1
这段代码中将585235通过__vbaStrCat与”AKA-”连接到一起组成字符串”AKA-585235”,然后通过__vbaStrCmp函数与我们的Serial比较结果,最后返回值放到eax中,通过返回值确定是否正确。将这里的分析与上一块合到一起,很容易就可以得出最终的注册码。
小结一下:先取出注册码的长度len, 然后取出注册码第一个字符的ANSI值cName, 让后计算len*0x17CFB+cName,将计算的值转换为10进制文本,前面加上”AKA-”组成最后的注册码。
C/CPP代码如下:
// CrackMe160.cpp : 定义控制台应用程序的入口点。 // 002 #include "stdafx.h" #include <stdio.h> #include "iostream" char buff[100] = {0}; int _tmain(int argc, _TCHAR* argv[]) { printf("160CrackMe-002 Name/Serial "); printf("Name:"); gets_s(buff,100); int nLen = strlen(buff); if ( nLen > 0 ) { int nRet = nLen * 0x17CFB; nRet += buff[0]; printf("AKA-%d ",nRet); }else{ printf("Input error! "); } system("pause"); return 0; }