Tiger's Crackme

今天一早起来将以前的分析,注释全部删掉,重新分析这个CM,总结出来一些东西,当瞥见网上关于此CM的一篇破文的某一部分时,突然有了思路,再看下去,果然是这样。。
上一次发了一篇不太全的分析,这次来收尾,总结了一下网上关于这个CM的破文和自己跟出来的东西。

在分析之前,先看看CrackMe的模样:


Same old same old,Name+Serial

第一步:反汇编算法分析
Button1的汇编代码:

004501DD      55            push    ebp

004501DE  |.  68 4F034500   push    0045034F

004501E3  |.  64:FF30       push    dword ptr fs:[eax]

004501E6  |.  64:8920       mov     dword ptr fs:[eax], esp

004501E9  |.  8D55 FC       lea     edx, dword ptr [ebp-4]

004501EC  |.  8B83 FC020000 mov     eax, dword ptr [ebx+2FC]

004501F2  |.  E8 25F2FDFF   call    0042F41C

004501F7  |.  8D55 F8       lea     edx, dword ptr [ebp-8]

004501FA  |.  8B83 00030000 mov     eax, dword ptr [ebx+300]

00450200  |.  E8 17F2FDFF   call    0042F41C

00450205  |.  8D45 F4       lea     eax, dword ptr [ebp-C]

00450208  |.  BA 68034500   mov     edx, 00450368                    ;  i am bin laden

0045020D  |.  E8 963CFBFF   call    00403EA8

00450212  |.  8D45 F0       lea     eax, dword ptr [ebp-10]

00450215  |.  BA 80034500   mov     edx, 00450380                    ;  i am yi zhi lao hu

0045021A  |.  E8 893CFBFF   call    00403EA8

0045021F  |.  8B45 FC       mov     eax, dword ptr [ebp-4]

00450222  |.  E8 A93EFBFF   call    004040D0

00450227  |.  83F8 0A       cmp     eax, 0A

0045022A  |.  0F8C FC000000 jl      0045032C

00450230  |.  8B45 FC       mov     eax, dword ptr [ebp-4]

00450233  |.  E8 983EFBFF   call    004040D0

00450238  |.  83F8 10       cmp     eax, 10

0045023B  |.  0F8F EB000000 jg      0045032C                         ;  用户名长度在10到16之间

00450241  |.  8B45 F8       mov     eax, dword ptr [ebp-8]

00450244  |.  E8 873EFBFF   call    004040D0

00450249  |.  83F8 11       cmp     eax, 11

0045024C  |.  0F8C DA000000 jl      0045032C

00450252  |.  8B45 F8       mov     eax, dword ptr [ebp-8]

00450255  |.  E8 763EFBFF   call    004040D0

0045025A  |.  83F8 16       cmp     eax, 16

0045025D  |.  0F8F C9000000 jg      0045032C                         ;  密码长度在17到22之间

00450263  |.  8D45 FC       lea     eax, dword ptr [ebp-4]

00450266  |.  8B55 F4       mov     edx, dword ptr [ebp-C]

00450269  |.  E8 6A3EFBFF   call    004040D8                         ;  合并 UsrBin=用户名+szBin

0045026E  |.  BB 64000000   mov     ebx, 64

00450273  |.  8D45 88       lea     eax, dword ptr [ebp-78]

00450276  |>  C600 2E       /mov     byte ptr [eax], 2E

00450279  |.  40            |inc     eax

0045027A  |.  4B            |dec     ebx

0045027B  |.^ 75 F9         \jnz     short 00450276                  ;  初始化12F5B4到12F617为0x2E

0045027D  |.  8B45 FC       mov     eax, dword ptr [ebp-4]

00450280  |.  E8 4B3EFBFF   call    004040D0

00450285  |.  8BF8          mov     edi, eax

00450287  |.  85FF          test    edi, edi

00450289  |.  7E 47         jle     short 004502D2

0045028B  |.  BB 01000000   mov     ebx, 1                           ;  i=1

00450290  |>  8B45 F0       /mov     eax, dword ptr [ebp-10]

00450293  |.  E8 383EFBFF   |call    004040D0

00450298  |.  8BF0          |mov     esi, eax

0045029A  |.  85F6          |test    esi, esi

0045029C  |.  7E 30         |jle     short 004502CE

0045029E  |.  B9 01000000   |mov     ecx, 1                          ;  j=1

004502A3  |>  8B45 FC       |/mov     eax, dword ptr [ebp-4]

004502A6  |.  0FB64418 FF   ||movzx   eax, byte ptr [eax+ebx-1]

004502AB  |.  8B55 F8       ||mov     edx, dword ptr [ebp-8]

004502AE  |.  0FB6540A FF   ||movzx   edx, byte ptr [edx+ecx-1]

004502B3  |.  F7EA          ||imul    edx

004502B5  |.  51            ||push    ecx

004502B6  |.  B9 1A000000   ||mov     ecx, 1A

004502BB  |.  33D2          ||xor     edx, edx

004502BD  |.  F7F1          ||div     ecx

004502BF  |.  59            ||pop     ecx

004502C0  |.  83C2 41       ||add     edx, 41

004502C3  |.  8D0419        ||lea     eax, dword ptr [ecx+ebx]

004502C6  |.  885405 87     ||mov     byte ptr [ebp+eax-79], dl      ;  String[i+j]=UsrBin[i]*Code[j]%26+65

004502CA  |.  41            ||inc     ecx

004502CB  |.  4E            ||dec     esi

004502CC  |.^ 75 D5         |\jnz     short 004502A3                 ;  j<=18

004502CE  |>  43            |inc     ebx

004502CF  |.  4F            |dec     edi

004502D0  |.^ 75 BE         \jnz     short 00450290                  ;  i<=24

004502D2  |>  8D45 EC       lea     eax, dword ptr [ebp-14]

004502D5  |.  E8 363BFBFF   call    00403E10

004502DA  |.  8B45 F8       mov     eax, dword ptr [ebp-8]

004502DD  |.  E8 EE3DFBFF   call    004040D0

004502E2  |.  8BF8          mov     edi, eax

004502E4  |.  85FF          test    edi, edi

004502E6  |.  7E 1F         jle     short 00450307

004502E8  |.  8D5D 8E       lea     ebx, dword ptr [ebp-72]

004502EB  |>  8D45 84       /lea     eax, dword ptr [ebp-7C]

004502EE  |.  8A13          |mov     dl, byte ptr [ebx]

004502F0  |.  E8 033DFBFF   |call    00403FF8

004502F5  |.  8B55 84       |mov     edx, dword ptr [ebp-7C]

004502F8  |.  8D45 EC       |lea     eax, dword ptr [ebp-14]

004502FB  |.  8B4D EC       |mov     ecx, dword ptr [ebp-14]

004502FE  |.  E8 193EFBFF   |call    0040411C

00450303  |.  43            |inc     ebx

00450304  |.  4F            |dec     edi

00450305  |.^ 75 E4         \jnz     short 004502EB                  ;  String+6"之后的len(code)个位的字符串倒置作为密码

00450307  |>  8B45 EC       mov     eax, dword ptr [ebp-14]

0045030A  |.  8B55 F8       mov     edx, dword ptr [ebp-8]

0045030D  |.  E8 0A3FFBFF   call    0040421C

00450312  |.  75 18         jnz     short 0045032C

00450314  |.  6A 40         push    40

00450316  |.  B9 94034500   mov     ecx, 00450394                    ;  恭喜你

0045031B  |.  BA 9C034500   mov     edx, 0045039C                    ;  注册成功!请联系我!qq:609841314

00450320  |.  A1 04204500   mov     eax, dword ptr [452004]

00450325  |.  8B00          mov     eax, dword ptr [eax]

00450327  |.  E8 48E9FFFF   call    0044EC74

0045032C  |>  33C0          xor     eax, eax

0045032E  |.  5A            pop     edx

0045032F  |.  59            pop     ecx

00450330  |.  59            pop     ecx

第二步:用C语言还原算法
虽然最后一步的还原不是太地道,不过算出来就是了

#include <stdio.h>

#include <string.h>

//从网上找了两个字符串操作函数稍微改动一了下************************

/*从字符串的左边截取n个字符*/

void GetLeftStr(char *dst,char *src, int n)

{

    char*p = src;

    intlen = strlen(src);

    if(n>len)n = len;

    while(n--)*(dst++) = *(p++);

    *(dst++)='\0';

    return;

}

/*把字符串反过来*/

void reverse(char s[])

{  

 intc,j,i;

 for(i=0,j=strlen(s)-1;i<j;i++,j--)//完成倒置功能,不包括字符串结束符'/0'

 {

  c=s[i];

  s[i]=s[j];

  s[j]=c;

 }

}

 

int main()

{

  char szBen[]="i am Bin Laden";

  char user[50]="";

  int UsrLen=0;

  int i=0,j,code1=0,code2=0,code12=0,code22=0,k=0,pass1=0,pass2=0;

  int i2,j2,k2,ijkSignal=0;

  char code[50]="";

  char Pass[50]="";

  char LeftStr[50]="";

  char LeftStr2[50]="";

  int CodeLen=0;

  int count=1;

  memset(user,0,50);

  memset(code,0,50);

  memset(Pass,0,50);

  memset(LeftStr,0,50);

 

  //因为怕调试麻烦,所以我就不用scanf,而是直接设置用户和密码了

  strcpy(user,"abcdefghij");

  strcpy(code,"12klmnopqrstuvwxyz");

 

  UsrLen=strlen(user);

  if(UsrLen<0x0A|| UsrLen>0x10)

      goto end;

 

  CodeLen=strlen(code);

  if(CodeLen<0x0A|| CodeLen>0x16)

      goto end;

  strcat(user,szBen);

  UsrLen=strlen(user);

  //计算第一部分

  for(i=0;i<UsrLen;i++)

     for(j=0;j<18;j++)

     {

      Pass[i+j]=(user[i]*code[j])%26+65;            //这里是重点***这里是重点

     }

  //计算第二部分

 GetLeftStr(LeftStr,Pass,CodeLen+5);

  reverse(LeftStr);

 GetLeftStr(LeftStr2,LeftStr,CodeLen);

  printf("\nMiddleString:%s\n",LeftStr2);

end:

  return0;       

}  

第三步:研究其规律并根据规律写注册机
根据在VC调试第二步中的代码,发现“计算第一部分”中生成的字符,不全是第一次被设置成一个值之后,以后就会是这个值。
换句话说Pass[1]在i=0,j=1的时候被设置成了x,但是Pass[1]的最终取值取决于它在双重循环中最后被赋值的那个操作。
根据调试得知它最后被赋值是在i=1,j=0的时候。
很奇妙地,Pass[2]最后被赋值是在i=2,j=0的时候(看出规律了?)
现在我们把C语言还原出来的算法中重点的一句拿出来看看
Pass[i+j]=(user[i]*code[j])%26+65;            //这里是重点***这里是重点 
从上面研究出来的规律我们可以看出,要使得算出来的Pass中的某个元素为最终的模样,j必须为0,也就是说我们完全可以把这条语句替换为
Pass[i]=(user[i]*code[0])%26+65;            //这里是重点***这里是重点  

现在我们要做的事情就是求出code[0]了
在求出code[0]之前,我们首先看看第一步分析汇编算法时,在“成功信息”弹出来之前有"
将String+6"之后的len(code)个位的字符串倒置作为密码"的操作,从这个操作我们看出
1 用user[0],user[1],user[2],user[3],user[4]算出来的Pass对应的字符跟最终的密码没半毛线关系
2 用user[5]算出来的Pass中对应的字符实际上就是算出来的Key的最后一位(也就是说从i=5开始,第一次算出来的Pass字符是最后一个序列号字符,同理:i=6时算出来的Pass字符是序列号倒数第二个字符)
举个例,当输入的密码为18位的时候
Pass[17]=name[5]*code[0]%26+65
Pass[16]=name[6]*code[0]%26+65
Pass[15]=name[7]*code[0]%26+65
Pass[14]=name[8]*code[0]%26+65
Pass[13]=name[9]*code[0]%26+65
Pass[12]=name[10]*code[0]%26+65
Pass[11]=name[11]*code[0]%26+65
Pass[10]=name[12]*code[0]%26+65
Pass[9]=name[13]*code[0]%26+65
Pass[8]=name[14]*code[0]%26+65
Pass[7]=name[15]*code[0]%26+65
Pass[6]=name[16]*code[0]%26+65
Pass[5]=name[17]*code[0]%26+65
Pass[4]=name[18]*code[0]%26+65
Pass[3]=name[19]*code[0]%26+65
Pass[2]=name[20]*code[0]%26+65
Pass[1]=name[21]*code[0]%26+65
Pass[0]=name[22]*code[0]%26+65
了解这些知识之后我们来算code[0]
 我们应用上面举的例子中的最后一条来算code[0],代码如下
    for(code[0]=65; code[0]<91; code[0]++)
    if(code[0]==name[22]*code[0]%26+65)
      break;
现在既然求出code[0]了, 那么根据表达式
Pass[i]=(user[i]*code[0])%26+65; 
其他位的序列号也可以算出来了
for(int i=1;i<=LenOfCode;i++)
    Pass[i]=user[i+4]*code[0]%26+65


CraclkMe源码(因为这个exe链接失效了,所以我找到了作者发的源码重新编译一遍

procedure TForm1.Button1Click(Sender: TObject);
var
   name,code,laden,tiger,str:string;
   i,j:integer;
   part:array[1..100]of char;
begin
     name:=edit1.Text;
     code:=edit2.Text;
     laden:='i am Bin Laden';
     tiger:='i am yi zhi lao hu';
     if (length(name)<10) or (length(name)>16) then
         exit;
     if (length(code)<17) or (length(code)>22) then
         exit;
     name:=name+laden;
     for i:=1 to 100 do
         part[i]:='.';
     for i:=1  to length(name) do
        for j:=1 to length(tiger) do
            part[i+j]:=chr(((ord(name[i])*ord(code[j]))mod 26)+65);
     str:='';
     for i:=1 to length(code) do
         str:=part[i+6]+str;
     if str=code then
       Application.MessageBox('注册成功!请联系我!QQ:609841314','恭喜你',MB_ICONINFORMATION+MB_OK);
end;


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值