[反汇编练习] 160个CrackMe之029
[反汇编练习] 160个CrackMe之029.本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注册机的东西。其中,文章中按照如下逻辑编排(解决如下问题):1、使用什么环境和工具2、程序分析3、思路分析和破解流程4、注册机的探索----------------------------------提醒各位看客: 如果文章中的逻辑看不明白,那你一定是没有亲手操刀!OD中的跳转提示很强大,只要你跟踪了,不用怎么看代码就理解了!----------------------------------1、工具和环境:WinXP SP3 + 52Pojie六周年纪念版OD + PEID + 汇编金手指。160个CrackMe的打包文件。下载地址: http://pan.baidu.com/s/1xUWOY 密码: jbnq注:1、Win7系统对于模块和程序开启了随机初始地址的功能,会给分析带来很大的负担,所以不建议使用Win7进行分析。2、以上工具都是在52PoJie论坛下的原版程序,NOD32不报毒,个人承诺绝对不会进行任何和木马病毒相关内容。http://images.cnitblog.com/blog/573547/201406/192147191763366.png2、程序分析:想要破解一个程序,必须先了解这个程序。所以,在破解过程中,对最初程序的分析很重要,他可以帮助我们理解作者的目的和意图,特别是对于注册码的处理细节,从而方便我们反向跟踪和推导。和上一节一样,打开CHM,选择第29个CoSH.2.exe,保存下来。运行程序,程序界面如下:点击上面的Check按钮,弹出了信息框,很好。注意的是,点击确定按钮后,程序直接退出了。PEID:Microsoft Visual C++ 6.0哈哈哈,VC++的,我最喜欢了! 3、思路分析和破解流程没有信息框,我们可以试试查找文本的办法。1、打开OD,将exe拖到OD窗口中,等程序暂停后,直接点击运行按钮(F9),不用理会。2、随意输入伪码:BBDXF 123123。点击CHECK按钮,弹出信息框,不要关闭,回到OD。3、Ctrl+K查看堆栈信息:和之前的一样,找到Messagebox的下一个调用处,右键->Show call。4、在反汇编窗口查看代码信息:004015C1|.EB 16 jmp short 004015D9 ;// 关键跳转?没有判断,肯定不是的004015C3|>6A 00 push 0x0
004015C5|.68 6C304000 push 0040306C ;ASCII "ERROR"
004015CA|.68 40304000 push 00403040 ;ASCII "One of the Details you entered was wrong"
004015CF|.8B4D E0 mov ecx,
004015D2|.E8 BB020000 call <jmp.&MFC42.#4224> ;// 返回到这里
附近的几个随意看看,没有找到关键跳转,哎,全部都看看吧:
004014B0/.55 push ebp
004014B1|.8BEC mov ebp,esp
004014B3|.6A FF push -0x1
004014B5|.68 C21B4000 push 00401BC2 ;SE handler installation
004014BA|.64:A1 0000000>mov eax,dword ptr fs:
004014C0|.50 push eax
004014C1|.64:8925 00000>mov dword ptr fs:,esp
004014C8|.83EC 14 sub esp,0x14
004014CB|.53 push ebx
004014CC|.56 push esi
004014CD|.57 push edi
004014CE|.894D E0 mov ,ecx
004014D1|.8D4D E4 lea ecx,
004014D4|.E8 83030000 call <jmp.&MFC42.#540>
004014D9|.C745 FC 00000>mov ,0x0
004014E0|.8D4D F0 lea ecx,
004014E3|.E8 74030000 call <jmp.&MFC42.#540>
004014E8|.C645 FC 01 mov byte ptr ss:,0x1
004014EC|.8B4D E0 mov ecx,
004014EF|.81C1 A0000000 add ecx,0xA0
004014F5|.E8 AA030000 call <jmp.&MFC42.#3876> ;// 猜测是获取文本长度
004014FA|.8945 EC mov ,eax ;// eax = 5
004014FD|.837D EC 05 cmp ,0x5 ;// 文本长度大于5
00401501 7F 05 jg short 00401508 ;// 这个才是关键跳转
00401503 E9 BB000000 jmp 004015C3 ;// 直接跳到失败
00401508|>8B4D E0 mov ecx,
0040150B|.83C1 60 add ecx,0x60
0040150E|.E8 91030000 call <jmp.&MFC42.#3876>
00401513|.8945 E8 mov ,eax
00401516|.837D E8 05 cmp ,0x5
0040151A|.7F 05 jg short 00401521
0040151C|.E9 A2000000 jmp 004015C3
00401521|>8B45 E0 mov eax,
00401524|.05 E0000000 add eax,0xE0
00401529|.50 push eax
0040152A|.8B4D E0 mov ecx,
0040152D|.81C1 A0000000 add ecx,0xA0
00401533|.E8 66030000 call <jmp.&MFC42.#3874>
00401538|.8B4D E0 mov ecx,
0040153B|.81C1 E4000000 add ecx,0xE4
00401541|.51 push ecx
00401542|.8B4D E0 mov ecx,
00401545|.83C1 60 add ecx,0x60
00401548|.E8 51030000 call <jmp.&MFC42.#3874>
0040154D|.8B55 E0 mov edx,
00401550|.81C2 E0000000 add edx,0xE0
00401556|.52 push edx
00401557|.8D4D E4 lea ecx,
0040155A|.E8 39030000 call <jmp.&MFC42.#858>
0040155F|.8B45 E0 mov eax,
00401562|.05 E4000000 add eax,0xE4
00401567|.50 push eax
00401568|.8D4D F0 lea ecx,
0040156B|.E8 28030000 call <jmp.&MFC42.#858>
00401570|.33C0 xor eax,eax ;// eax = 0
00401572|.33DB xor ebx,ebx ;// ebx = 0
00401574|.33C9 xor ecx,ecx ;// ecx = 0
00401576|.B9 01000000 mov ecx,0x1 ;// ecx = 1
0040157B|.33D2 xor edx,edx ;// edx = 0
0040157D|.8B45 E4 mov eax, ;// "bbdxf1"
00401580|>8A18 /mov bl,byte ptr ds:
00401582|.32D9 |xor bl,cl
00401584|.8818 |mov byte ptr ds:,bl
00401586|.41 |inc ecx ;// ecx++
00401587|.40 |inc eax ;// eax++, 字符串向右一个
00401588|.8038 00 |cmp byte ptr ds:,0x0
0040158B|.^ 75 F3 \jnz short 00401580 ;// 得到字符串 "c`g|c7"
0040158D|.33C0 xor eax,eax ;0
0040158F|.33DB xor ebx,ebx ;0
00401591|.33C9 xor ecx,ecx ;0
00401593|.B9 0A000000 mov ecx,0xA ;0x0A
00401598|.33D2 xor edx,edx ;0
0040159A|.8B45 F0 mov eax, ;// "123123"
0040159D|>8A18 /mov bl,byte ptr ds:
0040159F|.32D9 |xor bl,cl
004015A1|.8818 |mov byte ptr ds:,bl
004015A3|.41 |inc ecx
004015A4|.40 |inc eax
004015A5|.8038 00 |cmp byte ptr ds:,0x0 ;// 得到字符串 ";9?<<<"
004015A8|.^ 75 F3 \jnz short 0040159D
004015AA|.8B45 E4 mov eax, ;ASCII "c`g|c7"
004015AD|.8B55 F0 mov edx, ;ASCII ";9?<<<"
004015B0|>33C9 /xor ecx,ecx ;0
004015B2|.8A18 |mov bl,byte ptr ds:
004015B4|.8A0A |mov cl,byte ptr ds:
004015B6|.3AD9 |cmp bl,cl ;// 循环比较字符串的每一个字符
004015B8|.75 09 |jnz short 004015C3 ;// 有一个不相等则失败
004015BA|.40 |inc eax
004015BB|.42 |inc edx
004015BC|.8038 00 |cmp byte ptr ds:,0x0
004015BF|.^ 75 EF \jnz short 004015B0
004015C1|.EB 16 jmp short 004015D9 ;// 关键跳转?没有判断,肯定不是的
004015C3|>6A 00 push 0x0
004015C5|.68 6C304000 push 0040306C ;ASCII "ERROR"
004015CA|.68 40304000 push 00403040 ;ASCII "One of the Details you entered was wrong"
004015CF|.8B4D E0 mov ecx,
004015D2|.E8 BB020000 call <jmp.&MFC42.#4224> ;// 返回到这里
004015D7|.EB 14 jmp short 004015ED
004015D9|>6A 00 push 0x0
004015DB|.68 34304000 push 00403034 ;ASCII "YOU DID IT"
004015E0|.68 20304000 push 00403020 ;ASCII "Well done,Cracker"
004015E5|.8B4D E0 mov ecx,
004015E8|.E8 A5020000 call <jmp.&MFC42.#4224>
004015ED|>6A 64 push 0x64 ; /Timeout = 100. ms
004015EF|.FF15 00204000 call dword ptr ds:[<&KERNEL32.Sleep>] ; \Sleep
004015F5|.C645 FC 00 mov byte ptr ss:,0x0
004015F9|.8D4D F0 lea ecx,
004015FC|.E8 65010000 call <jmp.&MFC42.#800>
00401601|.C745 FC FFFFF>mov ,-0x1
00401608|.8D4D E4 lea ecx,
0040160B|.E8 56010000 call <jmp.&MFC42.#800>
00401610|.8B4D F4 mov ecx,
00401613|.64:890D 00000>mov dword ptr fs:,ecx
0040161A|.5F pop edi
0040161B|.5E pop esi
0040161C|.5B pop ebx
0040161D|.8BE5 mov esp,ebp
0040161F|.5D pop ebp
00401620\.C3 retn
这个流程已经很简单了,爆破似乎都没什么必要了!比如:00401501 7F 05 jg short 00401508 原本用来判断字符串长度的跳转就可以,我们直接修改为jmp 004015D9.哈哈!!4、注册机的探索算法其实很简单,核心内容为:00401570|.33C0 xor eax,eax ;// eax = 0
00401572|.33DB xor ebx,ebx ;// ebx = 0
00401574|.33C9 xor ecx,ecx ;// ecx = 0
00401576|.B9 01000000 mov ecx,0x1 ;// ecx = 1
0040157B|.33D2 xor edx,edx ;// edx = 0
0040157D|.8B45 E4 mov eax, ;// "bbdxf1"
00401580|>8A18 /mov bl,byte ptr ds:
00401582|.32D9 |xor bl,cl
00401584|.8818 |mov byte ptr ds:,bl
00401586|.41 |inc ecx ;// ecx++
00401587|.40 |inc eax ;// eax++, 字符串向右一个
00401588|.8038 00 |cmp byte ptr ds:,0x0
0040158B|.^ 75 F3 \jnz short 00401580 ;// 得到字符串 "c`g|c7"
就是将Name的每一个字符都与ecx异或,ecx从1每次递增1,最后得到的字符串1。然后再对Serial做类似的处理得到字符串2,最后将字符串1和2比较,如果相等,则通过。总体来讲就是两个大于5个字符的字符串,通过只有一个常量不同的算法,得到的字符串相等。这…..C/CPP算法模拟:// 用户名算法模拟
char* pName = "bbdxf1";
char pOut = {0};
for(int i=0;i<strlen(pName);i++)
{
pOut = pName ^ (i+1);
}
printf("%s\r\n",pOut);
// 注册码算法模拟
char* pKey = "123123";
char pOut = {0};
for(int i=0;i<strlen(pKey);i++)
{
pOut = pKey ^ (i+0x0A);
}
printf("%s\r\n",pOut);
好吧,算法出来了,但是我们不可能凭空想到一个字符串能够完成这样的结果。所以,只有反算法了!算法是通过异或得到【密文】比较相等,我们可以反过来,指定一个密文,分别反出来两个【原文】,即CPP算法中的Name和Key内容相同,输出的两个非别为Name和Key即可。// CrackMeDemo.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "iostream"
int _tmain(int argc, _TCHAR* argv[])
{
// 用户名算法模拟
char* pName = "bbdxf1";
printf("%s\r\n",pName);
char pOut = {0};
for(int i=0;i<strlen(pName);i++)
{
pOut = pName ^ (i+1);
}
printf("Name:%s\r\n",pOut);
// 注册码算法模拟
char* pKey = pName;
for(int i=0;i<strlen(pKey);i++)
{
pOut = pKey ^ (i+0x0A);
}
printf("key:%s\r\n",pOut);
system("pause");
return 0;
}
BY笨笨D幸福
羞愧啊,已经欠了好几篇了!其实,程序已经研究好了,就是没时间组织文章!人生啊! 有料,学学 本帖最后由 44018723 于 2014-7-8 22:39 编辑
bao宝明 发表于 2014-7-8 22:08
为什么是改修改为jmp 004015D9.呢,求解
004015D9|>6A 00 push 0x0
004015DB|.68 34304000 push 00403034 ;ASCII "YOU DID IT"
004015E0|.68 20304000 push 00403020 ;ASCII "Well done,Cracker"
004015E5|.8B4D E0 mov ecx,
004015E8|.E8 A5020000 call <jmp.&MFC42.#4224>
因为这个是正确的处理部分啊!这个地址是分析代码分析出来的,前面有好几个想要爆破也需要这样自己分析的! 看不懂,学习下 没什么事做,又分析了一个。 这个就是函数名不显示出来,只能自己猜意思有点郁闷。
页:
[1]
2