【文章作者】: moonife
【读者对象】:刚入门:有C,asm的一些基础,至少了解windows编程,掌握常用破解工具的基本操作(ps:我认为既然把文章贴出来了,目的就是希望读者有所得,不会是拿出来秀一下,所以最好有个比较客观的读者对象定位,节约读者时间,仅是个人观点)
【文章难度】:2/10(我自己定义的)
【作者邮箱】: moonife@163.com
【作者QQ号】: 765496322
【软件名称】: codefantasy CrackMe2.exe
【软件大小】: 48.5KB
【下载地址】: 自己搜索(我是在光盘中找到的,还没有上传权限,努力吧!)
【加壳方式】: 无壳
【保护方式】: 注册名+序列号+明码比较
【编写语言】: Borland Delphi 6.0 - 7.0
【使用工具】: ollydbg+peid + Microsoft Visual C++ 6.0
【操作平台】: xp-sp3
【软件介绍】: 一个简单的creakme,入门学习用!
【作者说明】: 这是我写的第一个creakme分析文章,也是我第一次在看雪发表文章,在这里我还想谈一下我的感受,还请多多忍耐了!我接触这个加密与解密差不多有一年了吧,但都仅仅只是停留在了解这么一个层次上,没有发生过什么亲密接触了。真正开始学是近一两个月的事,但我以前有学过c,asm的一些知识,但都是浅薄的一点了,感觉人还是浮躁了一点.今年一月份买了kanxue大哥以及诸位大虾的出的《加密与解密》,用春晚老毕的话说是:内容很不错,写得很不错!不过对我来说是有点难了!春节放假回去鼓捣了一阵,今天终于写了第一篇破文,我的心情是从多云转晴了!不说了,不说了,什么时候把感想重写一篇把,还扯不完了还,都快跑偏了!最后我要感谢pediy,感谢cctv,mtv............还是F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7.....................实际~@~
------------------------------------------------------分析过程------------------------------------------------------------
一 收集信息:PEID查壳, Borland Delphi 6.0 - 7.0,无壳
二 踩点:运行程序,填写注册资料:name:moonife,serial:ggggggggggggg,注册,没反应,没有错误提示,也就是说不能简单的用MessageBox设断和查找错误提示字符串快速定位关键注册算法,但是我们可以查找注册成功提示信息,如果它没有经过特殊处理的话
三 动态调试分析:ollydbg载入,思考:我们可以采取什么方法快速定位关键注册代码呢?针对这个Creakme可以用以下几个方法:A 查找注册成功提升信息来定位(用 ultra reference string 插件);B Ctrl+N看输入表,有熟悉的GetDlgItemTextA,就可以bp GetDlgItemTextA 了 或 find references to import; C 如果上述两个方法还不行的话,我们就下WM_LBUTTONUP消息断点;D 还有其他许多方法,只是目前我也不会了,我在这里就当抛砖引玉了,还请诸位大虾赐教了!这个程序用以上任一方法都可以,建议每个都试一下,当做练习。
-----------------定位到的关键代码:
00408D8C |> \68 FF000000 push 0FF ; /Count = FF (255.); Case 3EA of switch 00408D6B
00408D91 |. 68 A0A24000 push 0040A2A0 ; |Buffer = codefant.0040A2A0
00408D96 |. 68 F2030000 push 3F2 ; |ControlID = 3F2 (1010.)
00408D9B |. 8B45 08 mov eax, dword ptr [ebp+8] ; |
00408D9E |. 50 push eax ; |hWnd
00408D9F |. E8 90B9FFFF call <jmp.&user32.GetDlgItemTextA> ; \GetDlgItemTextA
00408DA4 |. 8D45 B4 lea eax, dword ptr [ebp-4C]
00408DA7 |. BA A0A24000 mov edx, 0040A2A0 ; ASCII "moonife"
00408DAC |. B9 FF000000 mov ecx, 0FF
00408DB1 |. E8 BAAAFFFF call 00403870
00408DB6 |. 837D B4 00 cmp dword ptr [ebp-4C], 0
00408DBA |. 0F84 9E000000 je 00408E5E
00408DC0 |. 68 FF000000 push 0FF ; /Count = FF (255.)
00408DC5 |. 68 A0A34000 push 0040A3A0 ; |Buffer = codefant.0040A3A0
00408DCA |. 68 F3030000 push 3F3 ; |ControlID = 3F3 (1011.)
00408DCF |. 8B45 08 mov eax, dword ptr [ebp+8] ; |
00408DD2 |. 50 push eax ; |hWnd
00408DD3 |. E8 5CB9FFFF call <jmp.&user32.GetDlgItemTextA> ; \GetDlgItemTextA
00408DD8 |. 8D45 AC lea eax, dword ptr [ebp-54]
00408DDB |. BA A0A24000 mov edx, 0040A2A0 ; ASCII "moonife"
00408DE0 |. B9 FF000000 mov ecx, 0FF
00408DE5 |. E8 86AAFFFF call 00403870
00408DEA |. 8B45 AC mov eax, dword ptr [ebp-54] ; eax指向用户名
00408DED |. 8D55 B0 lea edx, dword ptr [ebp-50] ; 真注册码存放地址
00408DF0 |. E8 BFFCFFFF call 00408AB4 ; 计算真注册码的算法call,F7跟进去
-----------------注册码关键算法分析开始(部分省略):
00408B01 |> /8B4D F4 /mov ecx, dword ptr [ebp-C] ; 1:ecx=2 2:ecx=4
00408B04 |. |8A4437 FF |mov al, byte ptr [edi+esi-1] ; 从用户名的第一个字符开始取并进行计算
00408B08 |. |24 C0 |and al, 0C0 ; al=al&0xc0
00408B0A |. |25 FF000000 |and eax, 0FF ; eax不变
00408B0F |. |D3E8 |shr eax, cl ; eax右移动2位
00408B11 |. |0845 F3 |or byte ptr [ebp-D], al ; 1:【ebp-d】=0012fa5f=10 2:10or4=14
00408B14 |. |8345 F4 02 |add dword ptr [ebp-C], 2 ; 【ebp-c】=0012fa60=4 2:6
00408B18 |. |8D45 F8 |lea eax, dword ptr [ebp-8] ; eax=0012fa64 ecx=2 edx=0 si=1
00408B1B |. |E8 58AFFFFF |call 00403A78 ; 可能是取eax=*(eax)ecx=0 edx=eax=00900954
00408B20 |8A5437 FF mov dl, byte ptr [edi+esi-1] ; 取用户名的第一个字符(dl)=g edx=00900967 ‘g’=67
00408B24 |. |80E2 3F |and dl, 3F ; edx=00900927
00408B27 |. |81E2 FF000000 |and edx, 0FF ; edx=00000027
00408B2D |. |8B0D 98A24000 |mov ecx, dword ptr [40A298] ; 计算用户名关键字符串ASCII ;指向字符串 "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz~#%&*+-"
00408B33 |. |8A1411 |mov dl, byte ptr [ecx+edx] ; edx=00000068
00408B36 |. |885418 FF |mov byte ptr [eax+ebx-1], dl ; dl=68 ('h') ds:【00900955】=68
00408B3A |. |46 |inc esi ; esi=sei+1=2
00408B3B |. |43 |inc ebx ; ebx=ebx+1=3
00408B3C |. |83FB 04 |cmp ebx, 4 ; ebx<=4 所以跳转 计算出三位后开始跳转
00408B3F |. |7E 36 |jle short 00408B77
00408B41 |. |8D45 F8 |lea eax, dword ptr [ebp-8] ; *(eax)=放计算出来的注册码的地址(10090054+1)
00408B44 |. |E8 2FAFFFFF |call 00403A78 ; 可能是取eax=*(eax)ecx=0 edx=eax=00900954
00408B49 |. |33D2 |xor edx, edx ; edx=0
00408B4B |. |8A55 F3 |mov dl, byte ptr [ebp-D] ; dl=15 计算第一个字符的关键
00408B4E |. |8B0D 98A24000 |mov ecx, dword ptr [40A298] ; CrackMe2.00407FE0
00408B54 |. |8A1411 |mov dl, byte ptr [ecx+edx] ; dl=(00407fe0+edx)=50 'p'
00408B57 |. |8810 |mov byte ptr [eax], dl ; 注册码的第一个字符
00408B59 |. |C645 F3 00 |mov byte ptr [ebp-D], 0 ; 重置【ebp-d】为0
00408B5D |. |BB 02000000 |mov ebx, 2 ; ebx=2
00408B62 |. |C745 F4 02000>|mov dword ptr [ebp-C], 2 ; 重置【ebp-c】为2
00408B69 |. |8B45 FC |mov eax, dword ptr [ebp-4] ; eax=0012fa8c
00408B6C |. |8B55 F8 |mov edx, dword ptr [ebp-8] ; 计算出来注册码的前四个字符
00408B6F |. |E8 30ADFFFF |call 004038A4 ; ecx=2 edx=0
00408B74 |. |8B45 FC |mov eax, dword ptr [ebp-4]
00408B77 |> |8BC7 mov eax, edi ; eax=edi=00900934=输入的用户名
00408B79 |. |E8 1EADFFFF |call 0040389C ; 返回输入的用户名的字符个数
00408B7E |. |3BF0 |cmp esi, eax ; esi=2 eax=0x13
00408B80 |.^\0F8E 7BFFFFFF \jle 00408B01
00408B86 |. 83FB 02 cmp ebx, 2
00408B89 |. 74 52 je short 00408BDD
00408B8B |. 8D45 F8 lea eax, dword ptr [ebp-8]
00408B8E |. E8 E5AEFFFF call 00403A78
00408B93 |. C64418 FF 2E mov byte ptr [eax+ebx-1], 2E ; 最后一位用’.’填充
00408B98 |. 8D45 F8 lea eax, dword ptr [ebp-8]
00408B9B |. E8 D8AEFFFF call 00403A78
00408BA0 |. 33D2 xor edx, edx
00408BA2 |. 8A55 F3 mov dl, byte ptr [ebp-D]
00408BA5 |. 8B0D 98A24000 mov ecx, dword ptr [40A298] ; CrackMe2.00407FE0
00408BAB |. 8A1411 mov dl, byte ptr [ecx+edx]
00408BAE |. 8810 mov byte ptr [eax], dl
00408BB0 |. 8B45 FC mov eax, dword ptr [ebp-4]
00408BB3 |. 8B55 F8 mov edx, dword ptr [ebp-8]
00408BB6 |. E8 E9ACFFFF call 004038A4
00408BBB |. 8B45 FC mov eax, dword ptr [ebp-4]
00408BBE |. 8B45 FC mov eax, dword ptr [ebp-4]
00408BC1 |. 8B00 mov eax, dword ptr [eax]
-----------------------注册码关键算法分析结束
00408DF5 |. 8B45 B0 mov eax, dword ptr [ebp-50] ; 此时eax指向计算出来的serial,也可以做内存注册机
00408DF8 |. 50 push eax
00408DF9 |. 8D45 A8 lea eax, dword ptr [ebp-58]
00408DFC |. BA A0A34000 mov edx, 0040A3A0 ; ASCII "gggggggggggg"
00408E01 |. B9 FF000000 mov ecx, 0FF
00408E06 |. E8 65AAFFFF call 00403870
00408E0B |. 8B55 A8 mov edx, dword ptr [ebp-58]
00408E0E |. 58 pop eax
00408E0F |. E8 60ABFFFF call 00403974 ; 比较注册码是否相等
00408E14 |. 75 48 jnz short 00408E5E ; 关键比较 这里可以nop掉或取反实现爆破
00408E16 |. 6A 40 push 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00408E18 |. 68 5C8F4000 push 00408F5C ; |注册提示
00408E1D |. 68 688F4000 push 00408F68 ; |恭喜您,注册码正确!
00408E22 |. 8B45 08 mov eax, dword ptr [ebp+8] ; |
00408E25 |. 50 push eax ; |hOwner
00408E26 |. E8 41B9FFFF call <jmp.&user32.MessageBoxA> ; \MessageBoxA
-----------------------代码分析结束
四 总结:这个creakme注册过程思路清晰,计算serial的算法也比较简单,具体请看keygen源码
五 浅薄的经验分享:当我们定位到关键代码处的时候,一般摆在我们目前很多个Call,但是关键的call一般就那么两三个,切不要一路F7下去,那样往往会迷路的!这时我们可以先F8路过,路过前注意前两三行代码的执行,看或猜传什么参数进去了,路过后看寄存器的值有何变化或如果参数是指针,地址,堆栈的话看这些地址上的数据有何变化,然后我们就可以判定或猜出这个call是干嘛的了,接下来就不说了,靠你自己尽情的发挥了,good luck!
---------------------------------------------------keygen_C源码-----------------------------------------------------------
//kengen for codefantasy CrackMe
//用dbp_d等这样的变量是因为可以较快的照原算法写出注册机,
//对于我们初学者它还是个不错的想法了,有时间再优化
#include<stdio.h>
#include<string.h>
int main()
{
char key_word[]="23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz~#%&*+-";
char in_name[50]="";
char serial[50]="";
int ebp_d=0,ecx=2,eax=0,edx=0,esi=1,ebx=2,name_length=0,base=0;
printf("please input you name:");
scanf("%s",in_name);
name_length=strlen(in_name);
while(esi<=name_length)
{
ebx=2,ecx=2,ebp_d=0;
for(;ebx<=4 && esi<=name_length;ebx++,esi++)
{
eax=in_name[esi-1];
eax=(eax&0xC0&0xFF)>>ecx;
ebp_d=ebp_d|eax;
ecx+=2;
edx=in_name[esi-1];
edx=edx&0x3F&0xff;
edx=key_word[edx];
serial[base+ebx-1]=(char)edx;
}
serial[base]=key_word[ebp_d];
base+=4;
}
printf("The serial is:%s.\n",serial);//最后的点’.’直接输出
return 0;
}
-----------------------------------------------------------The end 2009-2-24 10:53:26-------------------------------------------------------------
ps:终于有上传权限了,我把creakme传上来,好给需要的做练习!
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课