首页
社区
课程
招聘
[移CrackMe论坛]一个简单crackme的详细算法分析(高手莫入)
发表于: 2005-1-27 11:41 10425

[移CrackMe论坛]一个简单crackme的详细算法分析(高手莫入)

2005-1-27 11:41
10425

这是一个crackme破解练习 

算法简单  适合初学!

附件:Splish.rar

呵呵  我也是初学者  也是从爆破刚刚走出来(也许还没有^_^,但我想走出来)!
----------------------------------------------------------------------
我非常讨厌这些密密麻麻的汇编代码就象魔鬼字符  一点意思都没有!  我看破解文章时也是检  中文多的看  !没办法  太菜了
----------------------------------------------------------------------
非常感谢看雪里的同仁们为了照顾我们这些菜鸟  不顾辛劳  写的一篇篇好文并整理收集! 可想而知你们不顾辛劳  不计报酬  花费了多少时间!
----------------------------------------------------------------------
特别是看雪学院里的同仁们,本站作为中国破解界最早 最有威望 最有技术含量对中国破解影响最深的破解交流平台  在经历了几年的风风雨雨  付出了大量的心血   由于破解技术的特殊性   总有一些人不厌其烦的攻击  遭受各方面的压力也越来越大  着实让人担心!前几天买了看雪学院的加密与解密第二版看的爽透了!
----------------------------------------------------------------------
^_^值此新春佳节到来之际  真诚祝愿看雪学院越来越好  祝愿看雪学院里的同仁们新年快乐  心想事成!
以此文感谢那么多破文的作者!  没有你们也没有我的这篇文章!
----------------------------------------------------------------------
一个破解练习  比较早了   可能也有人写过  !  不过肯定没我细吧!  建议如果初学一定要看懂算法!如果有错误一定要指出!
断点下在 GetWindowTextA ( bp GetWindowTextA )  建议初学者在跟踪算法时  把自己输入的用户名的ASC先看一下有一个印象
还需要知道 你注册码和用户名输入了多少位(ASC码)
----------------------------------------------------------------------
004015E4  /$  55            PUSH EBP
004015E5  |.  8BEC          MOV EBP,ESP
004015E7  |.  6A 20         PUSH 20                                  ; /Count = 20 (32.)
004015E9  |.  68 42324000   PUSH Splish.00403242                     ; |Buffer = Splish.00403242
004015EE  |.  FF75 0C       PUSH DWORD PTR SS:[EBP+C]                ; |hWnd
004015F1  |.  E8 34010000   CALL <JMP.&USER32.GetWindowTextA>        ; \GetWindowTextA
004015F6  |.  85C0          TEST EAX,EAX
004015F8  |.  0F84 95000000 JE Splish.00401693                       ;  测试是否输入了用户名
004015FE  |.  A3 67344000   MOV DWORD PTR DS:[403467],EAX
00401603  |.  6A 0B         PUSH 0B                                  ; /Count = B (11.)
00401605  |.  68 36324000   PUSH Splish.00403236                     ; |Buffer = Splish.00403236
0040160A  |.  FF75 08       PUSH DWORD PTR SS:[EBP+8]                ; |hWnd
0040160D  |.  E8 18010000   CALL <JMP.&USER32.GetWindowTextA>        ; \GetWindowTextA
00401612  |.  85C0          TEST EAX,EAX
00401614  |.  74 68         JE SHORT Splish.0040167E                 ;  测试是否输入了注册码
00401616  |.  A3 63344000   MOV DWORD PTR DS:[403463],EAX            ;  eax为用户名位数送内存403463处  下面循环用
0040161B  |.  33C9          XOR ECX,ECX                              ;  ecx 清零下面要用
0040161D  |.  33DB          XOR EBX,EBX                              ;  同上
0040161F  |.  33D2          XOR EDX,EDX                              ;  同上
00401621  |.  8D35 36324000 LEA ESI,DWORD PTR DS:[403236]            ;  把内存地址为403236里的值送入esi  可以在命令行输入d 403236查看
00401627  |.  8D3D 58324000 LEA EDI,DWORD PTR DS:[403258]            ;  同上
0040162D  |.  B9 0A000000   MOV ECX,0A                               ;  把0A 送ecx
00401632  |>  0FBE041E      /MOVSX EAX,BYTE PTR DS:[ESI+EBX]         ;  循环入口  依次取用户名ASC码
00401636  |.  99            |CDQ                                     ;  字符扩展
00401637  |.  F7F9          |IDIV ECX                                ;  取用户名ASC码除以0A余数送EDX(ecx为常数0A)
00401639  |.  33D3          |XOR EDX,EBX                             ;  当前计算位数与(ASC码除以0A的余数EDX)异或
0040163B  |.  83C2 02       |ADD EDX,2                               ;  当前计算位数与(ASC码除以0A的余数EDX)异或+2
0040163E  |.  80FA 0A       |CMP DL,0A                               ;  当前计算位数与(ASC码除以0A的余数EDX)异或+2与0a比较
00401641  |.  7C 03         |JL SHORT Splish.00401646                ;  这里插一句  本例中所有除运算  商,作者没用!
00401643  |.  80EA 0A       |SUB DL,0A                               ;  当前计算位数与(ASC码除以0A的余数EDX)异或+2与0a比较大于0a就-0A
00401646  |>  88141F        |MOV BYTE PTR DS:[EDI+EBX],DL            ;  当前计算位数与(ASC码除以0A的余数EDX)异或+2与0a比较大于就-0A 把值送入edi+ebx
00401649  |.  43            |INC EBX                                 ;  取下一位!
0040164A  |.  3B1D 63344000 |CMP EBX,DWORD PTR DS:[403463]           ;  比较取完没
00401650  |.^ 75 E0         \JNZ SHORT Splish.00401632               ;  没取完向上继续  循环出口
00401652  |.  33C9          XOR ECX,ECX                              ;  ecx 清零下面用
00401654  |.  33DB          XOR EBX,EBX                              ;  同上  清零
00401656  |.  33D2          XOR EDX,EDX                              ;  同上  清零
00401658  |.  8D35 42324000 LEA ESI,DWORD PTR DS:[403242]            ;  参照上面  类似指令!
0040165E  |.  8D3D 4D324000 LEA EDI,DWORD PTR DS:[40324D]            ;  参照上面  类似指令!
00401664  |.  B9 0A000000   MOV ECX,0A                               ;  把0A 送ecx
00401669  |>  0FBE041E      /MOVSX EAX,BYTE PTR DS:[ESI+EBX]         ;  循环入口  取当前注册码ASC码
0040166D  |.  99            |CDQ                                     ;  字符扩展
0040166E  |.  F7F9          |IDIV ECX                                ;  你应该知道这是除法运算了吧! 罗嗦一句  eax/ecx商eax 余edx
00401670  |.  88141F        |MOV BYTE PTR DS:[EDI+EBX],DL            ;  循环内容  当前注册码ASC码除0A的余数给EDX+EBX    循环结果  也放EDX+EBX这里了! 在下面比较时一个一个取出来比较
00401673  |.  43            |INC EBX                                 ;  ebx加一
00401674  |.  3B1D 67344000 |CMP EBX,DWORD PTR DS:[403467]           ;  比较是否取完
0040167A  |.^ 75 ED         \JNZ SHORT Splish.00401669               ;  循环出口   结束时  就不往上条跳了
0040167C  |.  EB 2A         JMP SHORT Splish.004016A8
0040167E  |>  6A 00         PUSH 0                                   ; /Style = MB_OK|MB_APPLMODAL
00401680  |.  68 0A304000   PUSH Splish.0040300A                     ; |Title = "Splish, Splash"
00401685  |.  68 A0304000   PUSH Splish.004030A0                     ; |Text = "Please enter your name."
0040168A  |.  6A 00         PUSH 0                                   ; |hOwner = NULL
0040168C  |.  E8 B7000000   CALL <JMP.&USER32.MessageBoxA>           ; \MessageBoxA
00401691  |.  EB 62         JMP SHORT Splish.004016F5
00401693  |>  6A 00         PUSH 0                                   ; /Style = MB_OK|MB_APPLMODAL
00401695  |.  68 0A304000   PUSH Splish.0040300A                     ; |Title = "Splish, Splash"
0040169A  |.  68 B8304000   PUSH Splish.004030B8                     ; |Text = "Please enter your serial number."
0040169F  |.  6A 00         PUSH 0                                   ; |hOwner = NULL
004016A1  |.  E8 A2000000   CALL <JMP.&USER32.MessageBoxA>           ; \MessageBoxA
004016A6  |.  EB 4D         JMP SHORT Splish.004016F5
004016A8  |>  8D35 4D324000 LEA ESI,DWORD PTR DS:[40324D]            ;  把内存地址为40324d里的值送入esi  可以在命令行输入d 40324d查看
004016AE  |.  8D3D 58324000 LEA EDI,DWORD PTR DS:[403258]            ;  同上
004016B4  |.  33DB          XOR EBX,EBX                              ;    EBX 清零
004016B6  |>  3B1D 63344000 /CMP EBX,DWORD PTR DS:[403463]           ;  此为以上计算出的两码依次比较--循环开始处  从以上循环可知此验证为f(用户名)=f(注册码)
004016BC  |.  74 0F         |JE SHORT Splish.004016CD                ;  全部正确就跳转  爆破点
004016BE  |.  0FBE041F      |MOVSX EAX,BYTE PTR DS:[EDI+EBX]         ;  edi+ebx是由上面循环用户名所得值  传一个字节给eax
004016C2  |.  0FBE0C1E      |MOVSX ECX,BYTE PTR DS:[ESI+EBX]         ;  esi+ebx是由上面循环注册码所得  传一个字节给ecx
004016C6  |.  3BC1          |CMP EAX,ECX                             ;  比较
004016C8  |.  75 18         |JNZ SHORT Splish.004016E2               ;  错误就跳
004016CA  |.  43            |INC EBX                                 ;  把ebx加1
004016CB  |.^ EB E9         \JMP SHORT Splish.004016B6               ;  继续循环
004016CD  |> \6A 00         PUSH 0                                   ; /Style = MB_OK|MB_APPLMODAL
004016CF  |.  68 0A304000   PUSH Splish.0040300A                     ; |Title = "Splish, Splash"
004016D4  |.  68 42304000   PUSH Splish.00403042                     ; |Text = "Good job, now keygen it."
004016D9  |.  6A 00         PUSH 0                                   ; |hOwner = NULL
004016DB  |.  E8 68000000   CALL <JMP.&USER32.MessageBoxA>           ; \MessageBoxA
004016E0  |.  EB 13         JMP SHORT Splish.004016F5
004016E2  |>  6A 00         PUSH 0                                   ; /Style = MB_OK|MB_APPLMODAL
004016E4  |.  68 0A304000   PUSH Splish.0040300A                     ; |Title = "Splish, Splash"
004016E9  |.  68 67304000   PUSH Splish.00403067                     ; |Text = "Sorry, please try again."
004016EE  |.  6A 00         PUSH 0                                   ; |hOwner = NULL
004016F0  |.  E8 53000000   CALL <JMP.&USER32.MessageBoxA>           ; \MessageBoxA
004016F5  |>  C9            LEAVE
004016F6  \.  C2 0800       RETN 8

004016BC  |.  74 0F         |JE SHORT Splish.004016CD                ;  全部正确就跳转  爆破点
改为
004016BC     /EB 0F         JMP SHORT Splish.004016CD                ;  全部正确就跳转  爆破点

算法总结:

-----------------------------------------------------------------------------------
程序开始:

注册名循环开始  取完没?

[(当前计算位数)与(当前用户名ASC码除以0A的余数EDX)异或]+2与0a比较大于就-0A

下一位

继续循环

注册码循环开始  取完没?

当前注册码ASC码除0A的余数

下一位

继续循环

以上两数相等吗?  相等-》"Good job, now keygen it."    不相等->"Sorry, please try again."

程序结束!

f(用户名)=f(注册码)

----------------------------------------------------------------------
好晕在单位写的  没有五笔  拼音打字不熟好累呀!
希望你能看懂  我会再写的  如果你不认为这篇文章浪费了你的时间的话!
----------------------------------------------------------------------
欢迎交流QQ:36002700    加入请注明:kanxue  E-maill:yjjh@163.com   
个人主页:http://pypoje.com


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 7
支持
分享
最新回复 (17)
雪    币: 265
活跃值: (430)
能力值: ( LV9,RANK:370 )
在线值:
发帖
回帖
粉丝
2
恭喜“天涯”第一篇文章入选精华。
2005-1-27 11:53
0
雪    币: 169
活跃值: (245)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
3
谢谢支持!  
2005-1-27 12:28
0
雪    币: 117
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
很好,太详细了。。正是我们所需要的
2005-1-27 14:01
0
雪    币: 209
活跃值: (55)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
大力支持,非常感谢
2005-1-27 14:25
0
雪    币: 260
活跃值: (81)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
恭喜天涯第在看雪上的第一篇精华。
2005-1-27 21:24
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
crackme破解练习
[splash窗口]
自动步过,到
00401021     E8 06000000    CALL Splish.0040102C
处停下了,然后出现splash。所以重来,在此单步进入,
再次自动步过,发现在
00401079     E8 F9030000    CALL Splish.00401477
处停下了,然后出现splash。所以重来,在此单步进入,
发现showwindow等代码,于是判断这个call就是splash
窗口的代码,于是在00401079用nop填充,搞掂。

[硬件序列号]
(内存注册码-明码比较)
在getwindowstexta下断。
硬件序列号输入“vcangle”确定,中断在getwindowstexta。
执行到用户代码,停在
0040136F  |. 8D05 53134000  LEA EAX,DWORD PTR DS:[401353]
单步步过,发现
0040136F  |. 8D05 53134000  LEA EAX,DWORD PTR DS:[401353]
00401375  |. 8D1D 15324000  LEA EBX,DWORD PTR DS:[403215]
eax出现“HardCoded”
ebx出现“vcangle”
然后是一个比较的循环
最后根据循环的结果给出提示信息。
所以判定,HardCoded就是我们要找的硬件序列号。过关。

[用户名和注册码]
在getwindowstexta下断。
用户名输入“vcangle”,注册码输入“12345678”
确定,中断在getwindowstexta。
执行到用户代码,停在
004015F6  |. 85C0           TEST EAX,EAX
这是检查getwindowstexta的返回值,如果成功长度就保存在
DS:[403467],否则跳转到0040167e,提示出错信息。
单步步过,再次出现getwindowstexta,这是取得用户名。
长度保存在DS:[403467],失败则跳到401693提示出错信息。
执行到用户代码。继续单步步过,然后一个类似下面的循环:
bx=0;
byte esi[]="vcangle";
cx=10;
while(1)
{
  ax=esi[bx];
  dx=ax%cx;
  dx^=bx;
  dx+=2;
  if(dx<10)
    goto H;
  dx-=10;
H:edi[bx]=dx;
  bx++;
  if(bx<lenA)continue;
  else break;
}
这是把用户名运算后放到ds:[edi+bx]中。
再往下:
bx=0;
byte esi="12345678";
cx=10;
while(1)
{
  ax=esi[bx];
  dx=ax%cx;
  edi[bx]=dx;
  bx++;
  if(bx<lenB)continue;
  else break;
}
这是把注册码运算后放到ds:[edi+bx]中.
继续单步步过,如果没出错将跳转到4016a8;
然后把注册玛放在esi,用户名放在edi。
再来一个循环:
bx=0;
while(1)
{
  if(lenA==bx)break;
  ax=edi[bx];
  cx=esi[bx];
  if(ax!=cx)goto E;
  bx++;
}
E:
然后是一个用户名和注册码正确的提示信息。
由上可以写出注册机:
(用户名max:=11;注册码max:=32)
void CZcjDlg::OnOK()
{
        char strName[12],strCode[33];
        memset(strName,0,12);
        memset(strCode,0,33);
        GetDlgItemText(IDC_EDIT1,strName,12);
        char buff[12];
        memset(buff,0,12);
        int a,lenA=strlen(strName);
        if(lenA<1)return;
        for(int i=0;i<lenA;i++)
        {
                a=strName[i];
                a=a%10;
                a^=i;
                a+=2;
                if(a>=10)a-=10;
                buff[i]=a;
        }
        for(i=0;i<lenA;i++)buff[i]+=('k'-'k'%10);//其中一组解
        SetDlgItemText(IDC_EDIT2,buff);
}
对取其中一组解的说明:
基数取'k'是为了得到可见的字符;
'k'-'k'%10是为了保证它是整10的数。
buff[i]+=('k'-'k'%10)正是符合了余数为f(用户名)算出的结果。

第一次写此类文章,请指教!
2005-1-28 02:41
0
雪    币: 169
活跃值: (245)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
8
  你写的怎么如此复杂  看着有点晕!
2005-1-28 11:20
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
我昨天晚上花了至少3个小时的心血啊~~~~~~```
我觉得很清晰啊,我只是把它翻译为c语言,没有这样分析我无法写出注册机来。
你说的是注册码分析部分还是注册机实现部分?你有更简单的注册机代码?
2005-1-28 14:13
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
先下来练习练习再说。谢了,我还没入门呢,只是这个网站对我还有不小的诱惑力。呵呵,
2005-1-28 14:46
0
雪    币: 97697
活跃值: (200834)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
11
我支持...
2005-1-29 01:34
0
雪    币: 200
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
支持楼主!
2005-1-29 09:50
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
我用c做的一个注册机,vc编译,dos界面的.也是我所做的第一个注册机.写源码时还需查书呢.呵呵.可能还有bug在里面呢.crackme里面的算法很简单.很快就能搞定.
给人信心鼓励.多谢了.
#include <stdio.h>
#include <string.h>
main()
{
  int len,i,hao;
  char  name[20];
  scanf("%s",name);
  len=strlen(name);
  for (i=0;i<len;i++)
    {
      hao=(name[i]) % 10;
      hao=(hao^i)+2;
      if (hao>=10) hao=hao-10;      
      hao=hao+70;                     //使序列号范围在70-79之间
      printf("%c",hao);
     }
   printf("\n");
   scanf("%c");              //使他在windows下停留,不用跑到dos界面下看
}
2005-10-7 00:25
0
雪    币: 212
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
你们都能写注册机了,我连看都还看不太懂,我还要努力学习赶上你们!!!
2005-10-19 11:10
0
雪    币: 216
活跃值: (70)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
15
支持
2005-10-24 11:58
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
我也想,自己也分析了几个,感觉还不错
可是不敢发表
一是太简单,
二是自己分析的只有自己看得懂,还不会照顾别人的感受
三就是怕别人笑话
呵呵,其实是怕自己丢人。
等这段时间忙完了,咱也弄他个精华帖
大家鼓励一下。


最后,支持一下爱在天涯兄弟,顶
2005-10-26 00:59
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
真详细,谢谢楼主了。
2006-1-26 23:46
0
雪    币: 247
活跃值: (135)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
18
为什么我没下任何断点,我会莫名其妙的被断在系统内存里了,。
而且什么也动不了,要按N下F9才行。
2006-1-27 10:22
0
游客
登录 | 注册 方可回帖
返回
//