【文章标题】: 一个CrackMe的分析
【文章作者】: qianyicy
【作者主页】: 8600606.ys168.com
【下载地址】: 己上传
【加壳方式】: 无壳
【保护方式】: crc检校
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
首先感谢风间仁兄弟,破解这个CM,他帮了我的大忙,呵呵,
刚拿到这个CM,说实在话,由于接触破解的时间不怎么长,对这个CM一点头绪都没,一设断点就自动退出,没办法,来论坛
求助,刚刚好碰上风间仁,他说这个有crc检校,于是,又猛攻了几天的CRC检校,才明白了一点,下面言归正传.
用ollydbg载入,由于他有crc检校,我们在ReadFile这个函数上下断f9运行,断在了下面:
00401819 |. 6A 00 push 0 ; /pOverlapped = NULL
0040181B |. 52 push edx ; |pBytesRead
0040181C |. 56 push esi ; |BytesToRead
0040181D |. 57 push edi ; |Buffer
0040181E |. 53 push ebx ; |hFile
0040181F |. FF15 0C304000 call dword ptr ds:[<&KERNEL32.ReadFi>; \ReadFile
00401825 |. 53 push ebx ; /hObject
00401826 |. FF15 08304000 call dword ptr ds:[<&KERNEL32.CloseH>; \CloseHandle
0040182C |. 8A47 3C mov al,byte ptr ds:[edi+3C]
0040182F |. 884424 10 mov byte ptr ss:[esp+10],al
00401833 |. 8B4424 10 mov eax,dword ptr ss:[esp+10]
00401837 |. 25 FF000000 and eax,0FF
0040183C |. 2BF0 sub esi,eax
0040183E |. 8D0C38 lea ecx,dword ptr ds:[eax+edi]
00401841 |. 56 push esi ; /Arg2
00401842 |. 51 push ecx ; |Arg1
00401843 |. 8B79 FC mov edi,dword ptr ds:[ecx-4] ; |
00401846 |. 8BCD mov ecx,ebp ; |
00401848 |. E8 23000000 call CrackMe(.00401870 ; \CrackMe(.00401870
0040184D |. 33C9 xor ecx,ecx
0040184F |. 3BC7 cmp eax,edi
00401851 |. 5F pop edi
00401852 |. 5E pop esi
00401853 |. 0F94C1 sete cl
00401856 |. 5D pop ebp
F8跟踪几步后,可以确定cmp eax,edi为关键,只要eax=edi,crc检校便通过,我们只要改为cmp eax,eax,就OK了,
改完后,F9继续运行,断在了下面:
00401AA1 |. 6A 00 push 0 ; /pOverlapped = NULL
00401AA3 |. 52 push edx ; |pBytesRead
00401AA4 |. 53 push ebx ; |BytesToRead
00401AA5 |. 56 push esi ; |Buffer
00401AA6 |. 57 push edi ; |hFile
00401AA7 |. FF15 0C304000 call dword ptr ds:[<&KERNEL32.ReadFi>; \ReadFile
00401AAD |. 57 push edi ; /hObject
00401AAE |. FF15 08304000 call dword ptr ds:[<&KERNEL32.CloseH>; \CloseHandle
00401AB4 |. 8BBE 00600000 mov edi,dword ptr ds:[esi+6000]
00401ABA |. 56 push esi ; /block
00401ABB |. E8 38010000 call <jmp.&MFC42.#825> ; \free
00401AC0 |. 83C4 04 add esp,4
00401AC3 |. 8BCD mov ecx,ebp
00401AC5 |. 68 42100000 push 1042 ; /Arg2 = 00001042
00401ACA |. 68 00104000 push CrackMe(.00401000 ; |Arg1 = 00401000
00401ACF |. E8 9CFDFFFF call CrackMe(.00401870 ; \CrackMe(.00401870
00401AD4 |. 33C9 xor ecx,ecx
00401AD6 |. 3BF8 cmp edi,eax
00401AD8 |. 5E pop esi
00401AD9 |. 5F pop edi
00401ADA |. 0F94C1 sete cl
00401ADD |. 5D pop ebp
同样F8跟踪几步后,可以确定cmp edi,eax为关键,只要eax=edi,crc检校便通过,我们只要改为cmp edi,edi,就OK了,
把改后的程序保存为新文件,再次载入,这下,我们可以下断点了,
F9运行程序,我们先用mfcspy检测下,看有什么可用信息,
message map=004032F8(CrackMe(去crc检校).exe+0032F8)
msg map entries at 00403300(CrackMe(去crc检校).exe+003300)
OnMsg:WM_PAINT(000f),func=00401370(CrackMe(去crc检校).exe+001370)
OnMsg:WM_QUERYDRAGICON(0037),func=00401430(CrackMe(去crc检校).exe+001430)
OnCommand: notifycode=0000 id=03e8,func=00401440(CrackMe(去crc检校).exe+001440)
OnMsg:WM_TIMER(0113),func=00401A10(CrackMe(去crc检校).exe+001A10)
OnMsg:WM_CLOSE(0010),func=00401350(CrackMe(去crc检校).exe+001350)
OnCommand: notifycode=0000 id=03e8,func=00401440(CrackMe(去crc检校).exe+001440)
OK,我们在00401440处下断,填入注册码,注册名,按OK,断下来了:
F8一直走:
0040154B . 8B46 64 mov eax,dword ptr ds:[esi+64]
0040154E . 8B2D D4314000 mov ebp,dword ptr ds:[<&MSVCRT._mbsc>; msvcrt._mbscmp
00401554 . 68 EC404000 push CrackMe(.004040EC ; /s2 = ""
00401559 . 50 push eax ; |s1
0040155A . FFD5 call ebp ; \_mbscmp
0040155C . 83C4 08 add esp,8
0040155F . 85C0 test eax,eax
00401561 . 74 7A je short CrackMe(.004015DD
00401563 . 8B46 60 mov eax,dword ptr ds:[esi+60]
00401566 . 8D5E 60 lea ebx,dword ptr ds:[esi+60]
00401569 . 68 EC404000 push CrackMe(.004040EC
0040156E . 50 push eax
0040156F . FFD5 call ebp
00401571 . 83C4 08 add esp,8
00401574 . 85C0 test eax,eax
00401576 . 74 65 je short CrackMe(.004015DD ; 以上为判断注册码和注册名是否为0为0就跳
00401578 . 8B4E 64 mov ecx,dword ptr ds:[esi+64]
0040157B . 33C0 xor eax,eax
0040157D > 0FBE1401 movsx edx,byte ptr ds:[ecx+eax] ; 内存中预存0D F0 AD BA 0D F0 AD BA 0D
00401581 . 81F2 AA000000 xor edx,0AA ; 注册码不足9位时,在注册码后+00,再用相应的数据补足9位
00401587 . 03FA add edi,edx ; 每一位与0xAA异或后,把结果相加,记为X
00401589 . 40 inc eax
0040158A . 83F8 09 cmp eax,9
0040158D .^ 7C EE jl short CrackMe(.0040157D
0040158F . 57 push edi
00401590 . 51 push ecx
00401591 . 8BCC mov ecx,esp
00401593 . 896424 1C mov dword ptr ss:[esp+1C],esp
00401597 . 53 push ebx
00401598 . E8 81070000 call <jmp.&MFC42.#535>
0040159D . 8BCE mov ecx,esi ; |
0040159F . E8 8C030000 call CrackMe(.00401930 ; \关键跳转,F7跟进
F8继续,来到:
00401989 |> /0FBE1C10 /movsx ebx,byte ptr ds:[eax+edx]
0040198D |. |03F3 |add esi,ebx
0040198F |. |40 |inc eax
00401990 |. |3BC1 |cmp eax,ecx
00401992 |.^\7C F5 \jl short CrackMe(.00401989 ; 以上循环求注册名ascii码的和记为Y
00401994 |> 33C9 xor ecx,ecx
00401996 |> 0FBE440C 0C /movsx eax,byte ptr ss:[esp+ecx+C] ; 关键字符:KEY-KANON
0040199B |. 0FAFC6 |imul eax,esi ; Y与关键字符的第一个字符相乘,记为a
0040199E |. 99 |cdq ; 符号扩展
0040199F |. BB 1A000000 |mov ebx,1A ; EBX=1A
004019A4 |. F7FB |idiv ebx ; a/ebx
004019A6 |. 83C2 61 |add edx,61 ; 余数+61,结果记为b
004019A9 |. 81F2 AA000000 |xor edx,0AA ; b与AA异或,结果记为c
004019AF |. 03FA |add edi,edx ; EDI=EDI+c,把EDI最终结果记为Z
004019B1 |. 41 |inc ecx ; 计数器+1
004019B2 |. 83F9 09 |cmp ecx,9 ; 字符是否读取完,
004019B5 |.^ 7C DF \jl short CrackMe(.00401996
004019B7 |. 8B4424 2C mov eax,dword ptr ss:[esp+2C]
004019BB |. C74424 20 FFFFFF>mov dword ptr ss:[esp+20],-1
004019C3 |. 3BF8 cmp edi,eax ; 比较X是否和Z相等,如果相等,则注册成功把他改为
cmp edi,edi,则爆破成功.
到此,此CM己经破解,下面附上C语言注册机原码,
main()
{
long x=0,y;
int a,b,c=0,i;
char aa[]="KEY-KANON",name[20];
printf("name:");
gets(name);
for(i = 0; i < 20; i++){
if(name[i] == '\0')
break;
x = x+name[i];
}
for(i = 0; i < 9; i++){
y=((x*aa[i])%26+97)^170;
c=c+y;
}
a=c/9;
b=c/9+c%9;
for (i = 32; i < 126; i++){
if ((i^170) == a)
a=i;
if ((i^170) == b)
b=i;
}
clrscr();
printf("Your name is:\t\t\t");
puts(name);
printf("\n");
printf("The Registration code is:\t");
printf("%c%c%c%c%c%c%c%c%c\n",a,a,a,a,a,a,a,a,b);
getch();
}
--------------------------------------------------------------------------------
【经验总结】
再次感谢风间仁兄弟,这个CM同一个用户名,应该有很多种注册码,我写的应该是最傻瓜的一种注册方式吧,
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课