首页
社区
课程
招聘
[原创]czCrackme 09破解及注册源码
发表于: 2007-4-9 10:02 6458

[原创]czCrackme 09破解及注册源码

hud 活跃值
2
2007-4-9 10:02
6458
【文章标题】: czCrackme 09破解及注册源码
【文章作者】: hud
【软件名称】: czCrackme.exe
【软件下载】: 见附件
【软件大小】: 96 KB
【加壳方式】: 无
【保护方式】: 序列号
【编写语言】: MASM32/TASM32
【使用工具】: Ollydbg
【操作平台】: Win32 XP
【作者声明】: 这是一个很旧的Crackme,之所以发出来,基于以下3点:

  1. 练习时找到的旧crackme,中间曾有些疑惑,但网上搜了一下,好像还没人发过破文;
  2. 这个crackme使用了一个API函数的尾地址作为初值,因此在不同的机上可能值不同。还有就是嵌套循环,没理清它的流程时容易迷,其它就没什么特别的地方了;
  3. 我的注册机用的是最笨的穷举,应该会有不用穷举更直接的办法吧,借此抛砖引玉。

【详细过程】:

  下断于GetWindowTextA,输入“pediy”和7654321,F9运行,断下后alt+F9到用户代码:

00401340   |.  6A 4>push 40         ; /Count = 40 (64.)
00401342   |.  68 3>push czCrackm.00403130         ; |Buffer = czCrackm.00403130
00401347   |.  FF35>push dword ptr ds:[4030C3]     ; |hWnd = 0037024A 

(class='Edit',parent=006801CA)
0040134D   |.  E8 A>call <jmp.&USER32.GetWindowTextA> ; \GetWindowTextA
00401352   |.  83F8>cmp eax,4                      ;  Name长度要大于4
00401355   |.  0F8E>jle czCrackm.00401444
0040135B   |.  6A 4>push 40                        ; /Count = 40 (64.)
0040135D   |.  68 7>push czCrackm.00403170         ; |Buffer = czCrackm.00403170
00401362   |.  68 B>push 0BB9                           ; |ControlID = BB9 (3001.)
00401367   |.  FF75>push dword ptr ss:[ebp+8]      ; |hWnd
0040136A   |.  E8 7>call <jmp.&USER32.GetDlgItemTextA>; \GetDlgItemTextA
0040136F   |.  83F8>cmp eax,4                      ;  试练码要大于4

00401372   |. /0F8E>jle czCrackm.00401444       ;  小于4则跳死
00401378   |. |A3 B>mov dword ptr ds:[4030BF],eax
0040137D   |. |FF35>push dword ptr ds:[4030C3]     ; /hWnd = 0037024A 

(class='Edit',parent=006801CA)
00401383   |. |E8 A>call <jmp.&USER32.SetFocus>     ; \SetFocus
00401388   |. |BF 3>mov edi,czCrackm.00403130      ;  ASCII "pediy"
0040138D   |. |BE 3>mov esi,czCrackm.00403130      ;  ASCII "pediy"
00401392   |> |AC   /lods byte ptr ds:[esi]
00401393   |. |0C 0>|or al,0                       ;  此循环确保字符不小于0x20
00401395   |. |74 0>|je short czCrackm.0040139C
00401397   |. |0C 2>|or al,20                      ;  Name[i] or 20,小于则+
00401399   |. |AA   |stos byte ptr es:[edi]     ;  结果放入edi
0040139A   |.^|EB F>\jmp short czCrackm.00401392

0040139C   |> \BF 7>mov edi,czCrackm.00403170      ;  ASCII "7654321"
004013A1   |.  BE 7>mov esi,czCrackm.00403170      ;  ASCII "1654321"
004013A6   |.  8D1D>lea ebx,dword ptr ds:[403130]

下面循环:Name[i] – SN[i],若其中一个长度短于另一个,则取值为0,所得值设为val1:

004013AC   |> /AC /lods byte ptr ds:[esi]
004013AD   |. |0C>|or al,0
004013AF   |. |74>|je short czCrackm.004013BB
004013B1   |. |8A>|mov dl,byte ptr ds:[ebx]
004013B3   |. |2A>|sub dl,al                       ;  Name[i]-SN[i]
004013B5   |. |8A>|mov al,dl
004013B7   |. |AA |stos byte ptr es:[edi]          ;  所得值设为val1
004013B8   |. |43 |inc ebx
004013B9   |.^\EB>\jmp short czCrackm.004013AC

004013BB   |> \8B0D>mov ecx,dword ptr ds:[4030BF]

下面开始一个嵌套循环:

004013C1   |> /80>/or cl,0                         ;  For (i = Len(SN); i>0; --i)
004013C4   |. |74>|je short czCrackm.00401426
004013C6   |. |51 |push ecx
004013C7   |. |68>|push czCrackm.00403170          ;  val1
004013CC   |. |E8>|call czCrackm.00401654          ;  进入,详见下面,得val2
004013D1   |. |F7>|mul ecx                         ;  i * val2
004013D3   |. |68>|push czCrackm.004031B0
004013D8   |. |50 |push eax
004013D9   |. |E8>|call czCrackm.0040169C          ;  化成10进制字符串s
004013DE   |. |BF>|mov edi,czCrackm.004031B0
004013E3   |. |BE>|mov esi,czCrackm.004031B0

下面这个循环中间的小循环取10进制字符串s各位的低1位:
004013E8   |> |AC |/lods byte ptr ds:[esi]         ;  取s各位
004013E9   |. |0C>||or al,0
004013EB   |. |74>||je short czCrackm.004013F3
004013ED   |. |83>||and eax,0F         ;  取s各位低1位
004013F0   |. |AA ||stos byte ptr es:[edi]
004013F1   |.^|EB>|\jmp short czCrackm.004013E8

004013F3   |> |8B>|mov ecx,dword ptr ds:[4030BF] 
004013F9   |. |D1>|shr ecx,1                       ;  试练码长度\2, 设为m
004013FB   |. |BF>|mov edi,czCrackm.004030F0
00401400   |. |BE>|mov esi,czCrackm.004031B0
00401405   |. |8D>|lea ebx,dword ptr ds:[ecx+4031B0]

下面这个循环中的小循环形成最后的比较值v3:
0040140B   |> |80>|/or cl,0                        ;  For i=1 to m
0040140E   |. |74>||je short czCrackm.00401422
00401410   |. |AC ||lods byte ptr ds:[esi]         ;  s[i]
00401411   |. |33>||xor edx,edx
00401413   |. |8A>||mov dl,byte ptr ds:[ebx]       ;  s[i+m]
00401415   |. |02>||add al,dl                      ;  v3[i] = s[i] + s[i+m]
00401417   |. |8A>||mov dl,byte ptr ds:[edi]
00401419   |. |02>||add al,dl
0040141B   |. |24>||and al,0F                      ;  取v3[i]低1位
0040141D   |. |AA ||stos byte ptr es:[edi]
0040141E   |. |49 ||dec ecx
0040141F   |. |43 ||inc ebx
00401420   |.^|EB>|\jmp short czCrackm.0040140B

00401422   |> |59 |pop ecx
00401423   |. |49 |dec ecx
00401424   |.^\EB>\jmp short czCrackm.004013C1     ;  大循环回去

00401426   |>  BE>mov esi,czCrackm.004030F0
0040142B   |.  8B>mov ebx,dword ptr ds:[4030BF]
00401431   |.  8B>mov ecx,ebx
00401433   |.  D1>shr ecx,1

比较的循环,相当于:

for (i=0; i<m; ++i)
    if (v3[i]!=SN长度)
  失败

00401435   |>  8A>/mov al,byte ptr ds:[esi]
00401437   |.  80>|or cl,0
0040143A   |.  74>|je short czCrackm.00401475
0040143C   |.  38>|cmp al,bl
0040143E   |.  75>|jnz short czCrackm.00401444
00401440   |.  46 |inc esi
00401441   |.  49 |dec ecx
00401442   |.^ EB>\jmp short czCrackm.00401435

如果v3从1到m (注册码长度整除2)位都等于SN长度,则成功。

进入004013C4处的Call (得到val2):

00401654   /$  55 push ebp                         ;  外层循环
00401655   |.  8B>mov ebp,esp
00401657   |.  51 push ecx                         ;  nLen
00401658   |.  57 push edi
00401659   |.  52 push edx
0040165A   |.  56 push esi
0040165B   |.  33>xor ecx,ecx
0040165D   |.  8B>mov edi,[arg.1]                  ;  val1,下面得出长度
00401660   |.  FF>push [arg.1]                     ; /String
00401663   |.  E8>call <jmp.&KERNEL32.lstrlenA>; \lstrlenA
00401668   |.  EB>jmp short czCrackm.0040168D

0040166A   |>  >/xor edx,edx                        ;  循环
0040166C   |.  >|mov dl,byte ptr ds:[edi]           ;  val1[i]
0040166E   |.  >|sub dl,30                          ;  val1[i] - 30
00401671   |.  >|mov esi,eax
00401673   |.  >|dec esi                            ;  --i
00401674   |.  >|push eax
00401675   |.  >|mov eax,edx
00401677   |.  >|push ebx
00401678   |.  >|mov ebx,0A         ;  相当于:

for (i=nLen-1; i>0; --1)
   For (j=0; j<i; ++j)
     val1[i] * 10;

0040167D   |.  >|jmp short czCrackm.00401682
0040167F   |>  >|/mul ebx
00401681   |.  >||dec esi
00401682   |>  >| cmp esi,0
00401685   |.^ >|\ja short czCrackm.0040167F
00401687   |.  >|pop ebx
00401688   |.  >|add ecx,eax         ; 累加(初值为函数lstrlenA末尾地址)
0040168A   |.  >|pop eax
0040168B   |.  >|inc edi
0040168C   |.  >|dec eax
0040168D   |>  > or eax,eax
0040168F   |.^ >\jnz short czCrackm.0040166A     ;  内层循环1回去
00401691   |.  >mov eax,ecx
00401693   |.  >pop esi
00401694   |.  >pop edx
00401695   |.  >pop edi
00401696   |.  >pop ecx
00401697   |.  >leave
00401698   \.  >retn 4

/****************************************************************************

算法:

1. Name和注册码要5位以上;
2. Name各位-SN各位取低二位,得val1;
3. 从1到试练码长度循环  for(i=0; i<nSNLen; ++i);
4. val1各位减0x30取低2位*10的i-1次方相加;
3. 再加lstrlen函数的尾地址;
4. 乘以循环变量;
5. 化为10进制字符s;
6. 取s各位字符低1位为val2;
7. 从1至m(试练码长度\2);
8. v2各位+(v2+m)+v3各位,然后取低1位为v3,即:
   v3[i] = ( v2[i] + v2[i+m] + v3[i] ) & 0x0F;
9. 上面v3循环使用,第一次各位为0。
10.如果v3的前(试练码长度\2)位都等于试练码长度则成功;

Name文本框最多只接受11位,SN文本框只接受16位;

******************************************************************************/

【注册机】: 见附件2

【VC++6.0注册源码】:

这里只是自已添加上去的代码,不包括自动生成的,写得很烂,高手见笑了。

#include <math.h>

int nName, nSN;
DWORD add;

DWORD get_add()            // 取得lstrlen函数的地址
{
   HINSTANCE hLib = LoadLibrary ("kernel32.dll");
   FARPROC lfnProc = 0;

   if (hLib)
   {
      lfnProc = (FARPROC) GetProcAddress (hLib, "lstrlenA");
      FreeLibrary (hLib);
   }
   return (DWORD) lfnProc + 0x30;
}

bool check_sn(const CString &name, const CString &sn, 
          CString &hash)  //检验sn是否正确
{
   int i, j, m,
      v1[16], v2[16], v3[16];

   j = nName > nSN ? nName : nSN;

   for (i=0; i<j; ++i)
   {
     v1[i] = i<nName ? name[i] : 0;      //name各位入v1
     v2[i] = i<nSN ? sn[i] : 0;      //sn各位入v2
     v1[i] =  ( v1[i] - v2[i] ) & 0xFF;    //name[i] - sn[i]
     v3[i] = 0;                
   }
   
   m = nSN/2;
   for (i=nSN; i>0; --i)
   {
      DWORD val = add;
      for (j=nSN-1; j>=0; --j)
        val += ( ( v1[nSN-j-1] - 0x30 ) & 0xFF ) * (DWORD) pow(10, j);

     val *= i;

     char s[11];
     sprintf(s, "%lu", val);

     for (j=0; j<m; ++j)
        v3[j] = ( ( s[j] & 0x0F ) + ( s[j+m] & 0x0F ) + v3[j] ) & 0x0F;
   }

   hash.Empty();
   for (i=0; i<m; ++i)
     hash.Insert(i, v3[i] + 0x30);

   for (i=0; i<m; ++i)
     if (v3[i]!=nSN)
           return false;
  
   return true;
}

void CKeygenDlg::OnOK()       //穷举及检测
{
   UpdateData(true);

   nName = m_szName.GetLength();
   if (nName<5)
     return;
   
   add = get_add();

   char      szSet[128] = "0123456789";    //候选字符集
   CString  name;  
   const    int nChar = strlen(szSet);    //候选字符集长度
   long      idx[16];        //注册码下标 
   long      j, i = 0; 
   bool      bNext;

   for (i=0; i<nName; ++i)
     name.Insert(i, m_szName.GetAt(i) | 0x20);
                                 //name各位和0x20作or运算

   for (nSN=5; nSN<17; ++nSN)      // 循环#1
   { 
      for (i=0; i<nSN; ++i)
        idx[i] = 0;

      bNext = true; 

      while (bNext)        // 循环#2
      {
        m_szSN.Empty();
        for (i=0; i<nSN; ++i) 
            m_szSN.Insert(i, szSet[idx[i]]);

        if (check_sn(name, m_szSN, m_szHash))
        {
            UpdateData(false);
            AfxMessageBox("Found!");
            return;
        }
         
        for (j=nSN-1; j>=0; --j)    // 循环#3 下标进位
        { 
            idx[j]++; 

            if (idx[j]!=nChar)
              break; 
            else 
            { 
               idx[j] = 0; 
               if (j==0)
                 bNext = false; 
            } 
        }                    // 循环#3 end
      }                      // 循环#2 end
      ++nSN; 
   }                          // 循环#1 end

   AfxMessageBox("Not found!");
}


一般在1、2分鉮内就能算出注册码,我算出来的注册码全部是7位长,hash值(v3)全部是:777

--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2007年04月09日 8:47:06

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 225
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
VC++6.0注册源码
2011-1-24 15:26
0
游客
登录 | 注册 方可回帖
返回
//