吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6944|回复: 5
收起左侧

[原创] [算法分析] XorRanger's KeygenME #5

[复制链接]
currwin 发表于 2014-6-2 10:21
本帖最后由 currwin 于 2014-6-2 14:59 编辑

【文章作者】:currwin[F8LEFT]
【软件名称】:XorRanger's KeygenME #5
【下载地址】:因为是从外国网站上面趴下来的。直接发百度盘吧:链接: http://pan.baidu.com/s/1pJx4mFp 密码: mk25
【加密方式】:PEcompact ver.2.78a ~ 3.0.3.9  - www.bitsum.com ( aPlib/Lzma )
【使用工具】:IDA、OD

        蛋疼,IDA,OD都不会用,结果在奇怪的地方浪费了很多时间。小菜鸟写得不好希望大家不要嫌弃。因为这个KM本身并不难,柿子还得挑软的捏,难一点的KM都玩不动了 。小菜鸟玩玩简单的KM,练习一下软件的使用而已。写得不好的地方,还望各位大大能赐教。
脱壳部分:
      没有什么好说的了,PEcompact本身就不难脱,单步也好,什么也好,反正很快就会到达OEP的了。
用IDA结合OD分析到的具体KeygenMe流程是:
①判断输入的SerialKey的长度是否等于12,不是则失败。
②对输入的Name进行处理得到GlobalKey。这里有一个陷阱,如果输入的Name不合法,不会马上提示错误,而是继续执行函数,但是到后面与GlobalKey比较的地方就会过不去的。
        Name的要求是:
        ①长度大于12,并且参与运算的只有前12个字符。
        ②由数字1~9组成。
.结合前面运算得到的GlobalKey,对SerialKey进行加密。                  
   如果加密运算的结果等于0x0F78ECDE ,便会成功。

函数分析部分:
下面是按钮事件的判断部分:
[Asm] 纯文本查看 复制代码
; int __cdecl CheckIt()
.text:005B5138 CheckIt         proc near
.text:005B5138
.text:005B5138 PassW_10        = dword ptr -64h
.text:005B5138 Pass[0]         = dword ptr -60h
.text:005B5138 PassW_9         = dword ptr -5Ch
.text:005B5138 Pass[2]         = dword ptr -58h
.text:005B5138 PassW_8         = dword ptr -54h
.text:005B5138 Pass[4]         = dword ptr -50h
.text:005B5138 PassW_7         = dword ptr -4Ch
.text:005B5138 Pass[10]        = dword ptr -48h
.text:005B5138 PassW_6         = dword ptr -44h
.text:005B5138 Pass[8]         = dword ptr -40h
.text:005B5138 PassW_5         = dword ptr -3Ch
.text:005B5138 Pass[6]         = dword ptr -38h
.text:005B5138 PassW_4         = dword ptr -34h
.text:005B5138 Pass[5]         = dword ptr -30h
.text:005B5138 PassW_3         = dword ptr -2Ch
.text:005B5138 Pass[3]         = dword ptr -28h
.text:005B5138 PassW_2         = dword ptr -24h
.text:005B5138 Pass[1]         = dword ptr -20h
.text:005B5138 NameW           = dword ptr -1Ch
.text:005B5138 PassW_1         = dword ptr -18h
.text:005B5138 var_14          = dword ptr -14h
.text:005B5138 iPassLen        = dword ptr -10h
.text:005B5138 var_C           = dword ptr -0Ch
.text:005B5138 var_8           = dword ptr -8
.text:005B5138 var_4           = dword ptr -4
.text:005B5138
.text:005B5138                 push    ebp
.text:005B5139                 mov     ebp, esp
.text:005B513B                 mov     ecx, 0Ch
.text:005B5140
.text:005B5140 loc_5B5140:                             ; CODE XREF: CheckIt+Dj
.text:005B5140                 push    0
.text:005B5142                 push    0
.text:005B5144                 dec     ecx
.text:005B5145                 jnz     short loc_5B5140
.text:005B5147                 push    ecx
.text:005B5148                 mov     [ebp+var_14], edx
.text:005B514B                 mov     [ebp+var_4], eax
.text:005B514E                 xor     eax, eax
.text:005B5150                 push    ebp
.text:005B5151                 push    offset loc_5B5405 ; buffer
.text:005B5156                 push    dword ptr fs:[eax] ; buffer
.text:005B5159                 mov     fs:[eax], esp
.text:005B515C                 lea     edx, [ebp+PassW_1] ; PassW_i 均表示这里是用来存储Pass的
.text:005B515F                 mov     eax, [ebp+var_4]
.text:005B5162                 mov     eax, [eax+3B0h] ; 3B0为PassWord的Hwnd
.text:005B5168                 call    WGetDlgItemText ; 取Serial的值
.text:005B516D                 mov     eax, [ebp+PassW_1]
.text:005B5170                 mov     [ebp+var_C], eax
.text:005B5173                 mov     eax, [ebp+var_C]
.text:005B5176                 mov     [ebp+iPassLen], eax
.text:005B5179                 cmp     [ebp+iPassLen], 0
.text:005B517D                 jz      short loc_5B518A ; 密码的长度为0xC
.text:005B517F                 mov     eax, [ebp+iPassLen]
.text:005B5182                 sub     eax, 4          ; String的结构为
.text:005B5182                                         ; int iLen
.text:005B5182                                         ; wchar* buffer
.text:005B5185                 mov     eax, [eax]      ; 这里是取长度
.text:005B5187                 mov     [ebp+iPassLen], eax
.text:005B518A
.text:005B518A loc_5B518A:                             ; CODE XREF: CheckIt+45j
.text:005B518A                 cmp     [ebp+iPassLen], 0Ch ; 密码的长度为0xC
.text:005B518E                 jnz     loc_5B535A
.text:005B5194                 lea     edx, [ebp+NameW]
.text:005B5197                 mov     eax, [ebp+var_4]
.text:005B519A                 mov     eax, [eax+3A8h] ; 3A8为Name的hwnd
.text:005B51A0                 call    WGetDlgItemText
.text:005B51A5                 mov     eax, [ebp+NameW]
.text:005B51A8                 call    VerifyName_1    ; 利用Name来对Grobal_Key进行赋值
.text:005B51AD                 lea     edx, [ebp+PassW_2]
.text:005B51B0                 mov     eax, [ebp+var_4]
.text:005B51B3                 mov     eax, [eax+3B0h]
.text:005B51B9                 call    WGetDlgItemText
.text:005B51BE                 mov     eax, [ebp+PassW_2]
.text:005B51C1                 mov     dx, [eax+2]
.text:005B51C5                 lea     eax, [ebp+Pass[1]] ; Pass[i]表示该内存用来存储第i个密码
.text:005B51C8                 call    NewChar__       ; 新建空间来保存传递进入的Char
.text:005B51CD                 mov     eax, [ebp+Pass[1]]
.text:005B51D0                 mov     edx, GlobalKey_0_ ; 比较Pass[1]与GlobalKey[0]是否相等
.text:005B51D6                 call    CmpDword
.text:005B51DB                 jnz     loc_5B535A
.text:005B51E1                 lea     edx, [ebp+PassW_3]
.text:005B51E4                 mov     eax, [ebp+var_4]
.text:005B51E7                 mov     eax, [eax+3B0h]
.text:005B51ED                 call    WGetDlgItemText
.text:005B51F2                 mov     eax, [ebp+PassW_3]
.text:005B51F5                 mov     dx, [eax+6]
.text:005B51F9                 lea     eax, [ebp+Pass[3]]
.text:005B51FC                 call    NewChar__       ; BDS 2005-2007 and Delphi6-7 Visual Component Library
.text:005B5201                 mov     eax, [ebp+Pass[3]]
.text:005B5204                 mov     edx, GlobalKey_1_
.text:005B520A                 call    CmpDword        ; 比较Pass[3]与GlobalKey[1]是否相等
.text:005B520F                 jnz     loc_5B535A
.text:005B5215                 lea     edx, [ebp+PassW_4]
.text:005B5218                 mov     eax, [ebp+var_4]
.text:005B521B                 mov     eax, [eax+3B0h]
.text:005B5221                 call    WGetDlgItemText
.text:005B5226                 mov     eax, [ebp+PassW_4]
.text:005B5229                 mov     dx, [eax+0Ah]
.text:005B522D                 lea     eax, [ebp+Pass[5]]
.text:005B5230                 call    NewChar__       ; BDS 2005-2007 and Delphi6-7 Visual Component Library
.text:005B5235                 mov     eax, [ebp+Pass[5]]
.text:005B5238                 mov     edx, GlobalKey_2_
.text:005B523E                 call    CmpDword        ; 比较Pass[5]与GlobalKey[2]是否相等
.text:005B5243                 jnz     loc_5B535A
.text:005B5249                 lea     edx, [ebp+PassW_5]
.text:005B524C                 mov     eax, [ebp+var_4]
.text:005B524F                 mov     eax, [eax+3B0h]
.text:005B5255                 call    WGetDlgItemText
.text:005B525A                 mov     eax, [ebp+PassW_5]
.text:005B525D                 mov     dx, [eax+0Ch]
.text:005B5261                 lea     eax, [ebp+Pass[6]]
.text:005B5264                 call    NewChar__       ; BDS 2005-2007 and Delphi6-7 Visual Component Library
.text:005B5269                 mov     eax, [ebp+Pass[6]]
.text:005B526C                 call    CharToHex       ; 把输入的字符直接转换为16进制,如数字 9 变成 内存中:09 00 00 00
.text:005B5271                 push    eax             ; buffer
.text:005B5272                 lea     edx, [ebp+PassW_6]
.text:005B5275                 mov     eax, [ebp+var_4]
.text:005B5278                 mov     eax, [eax+3B0h]
.text:005B527E                 call    WGetDlgItemText
.text:005B5283                 mov     eax, [ebp+PassW_6]
.text:005B5286                 mov     dx, [eax+10h]
.text:005B528A                 lea     eax, [ebp+Pass[8]]
.text:005B528D                 call    NewChar__       ; BDS 2005-2007 and Delphi6-7 Visual Component Library
.text:005B5292                 mov     eax, [ebp+Pass[8]]
.text:005B5295                 call    CharToHex
.text:005B529A                 push    eax             ; buffer
.text:005B529B                 lea     edx, [ebp+PassW_7]
.text:005B529E                 mov     eax, [ebp+var_4]
.text:005B52A1                 mov     eax, [eax+3B0h]
.text:005B52A7                 call    WGetDlgItemText
.text:005B52AC                 mov     eax, [ebp+PassW_7]
.text:005B52AF                 mov     dx, [eax+14h]
.text:005B52B3                 lea     eax, [ebp+Pass[10]]
.text:005B52B6                 call    NewChar__       ; BDS 2005-2007 and Delphi6-7 Visual Component Library
.text:005B52BB                 mov     eax, [ebp+Pass[10]]
.text:005B52BE                 call    CharToHex
.text:005B52C3                 push    eax             ; buffer
.text:005B52C4                 lea     edx, [ebp+PassW_8]
.text:005B52C7                 mov     eax, [ebp+var_4]
.text:005B52CA                 mov     eax, [eax+3B0h]
.text:005B52D0                 call    WGetDlgItemText
.text:005B52D5                 mov     eax, [ebp+PassW_8]
.text:005B52D8                 mov     dx, [eax+8]
.text:005B52DC                 lea     eax, [ebp+Pass[4]]
.text:005B52DF                 call    NewChar__       ; BDS 2005-2007 and Delphi6-7 Visual Component Library
.text:005B52E4                 mov     eax, [ebp+Pass[4]]
.text:005B52E7                 call    CharToHex
.text:005B52EC                 push    eax             ; buffer
.text:005B52ED                 lea     edx, [ebp+PassW_9]
.text:005B52F0                 mov     eax, [ebp+var_4]
.text:005B52F3                 mov     eax, [eax+3B0h]
.text:005B52F9                 call    WGetDlgItemText
.text:005B52FE                 mov     eax, [ebp+PassW_9]
.text:005B5301                 mov     dx, [eax+4]
.text:005B5305                 lea     eax, [ebp+Pass[2]]
.text:005B5308                 call    NewChar__       ; BDS 2005-2007 and Delphi6-7 Visual Component Library
.text:005B530D                 mov     eax, [ebp+Pass[2]]
.text:005B5310                 call    CharToHex
.text:005B5315                 push    eax             ; hwnd
.text:005B5316                 lea     edx, [ebp+PassW_10]
.text:005B5319                 mov     eax, [ebp+var_4]
.text:005B531C                 mov     eax, [eax+3B0h]
.text:005B5322                 call    WGetDlgItemText
.text:005B5327                 mov     eax, [ebp+PassW_10]
.text:005B532A                 mov     dx, [eax]
.text:005B532D                 lea     eax, [ebp+Pass[0]]
.text:005B5330                 call    NewChar__       ; BDS 2005-2007 and Delphi6-7 Visual Component Library
.text:005B5335                 mov     eax, [ebp+Pass[0]]
.text:005B5338                 call    CharToHex
.text:005B533D                 pop     edx
.text:005B533E                 pop     ecx               ;主要的处理函数。。。。。
.text:005B533F                 call    DealKey         ; DealKey(P[0],P[2],P[4],P[6],P[8],P[10])
.text:005B5344                 mov     [ebp+var_8], eax ; return F78ECDE,success
.text:005B5347                 cmp     [ebp+var_8], 0F78ECDEh
.text:005B534E                 jnz     short loc_5B535A
.text:005B5350                 mov     eax, offset aSuperbJobNowPl ; "Superb Job \r\nNow Please Write a Keygen "...


        中间的一大段都是可以忽略的,他们的作用都是读取SerialKey,然后取SerialKey中的第i个数,转换为DWORD的值,最重要的是三个函数的使用
         VerifyName_1(wchar* Name);
        CmpDowrd(DWORD *Pass, DWORD *GlobalKey);
        DealKey(P[0],P[2],P[4],P[6],P[8],P[10]);
        好看一点的代码就要靠IDA的插件来搞起了。
[C++] 纯文本查看 复制代码
int __cdecl CheckIt()
{
  int v0; // eax@0
  int v1; // edx@0
  int v2; // edx@4
  char v3; // zf@4
  int v4; // edx@5
  int v5; // edx@6
  int v6; // edx@7
  int v7; // ST10_4@7
  int v8; // edx@7
  int v9; // ST0C_4@7
  int v10; // edx@7
  int v11; // ST08_4@7
  int v12; // edx@7
  int v13; // ST04_4@7
  int v14; // edx@7
  int v15; // ST00_4@7
  int v16; // edx@7
  int v17; // eax@7
  unsigned int v19; // [sp-Ch] [bp-70h]@1
  WCHAR *v20; // [sp-8h] [bp-6Ch]@1
  int (*v21)(); // [sp-4h] [bp-68h]@1
  int PassW_10; // [sp+0h] [bp-64h]@7
  int Pass[0]; // [sp+4h] [bp-60h]@7
  int PassW_9; // [sp+8h] [bp-5Ch]@7
  int Pass[2]; // [sp+Ch] [bp-58h]@7
  int PassW_8; // [sp+10h] [bp-54h]@7
  int Pass[4]; // [sp+14h] [bp-50h]@7
  int PassW_7; // [sp+18h] [bp-4Ch]@7
  int Pass[10]; // [sp+1Ch] [bp-48h]@7
  int PassW_6; // [sp+20h] [bp-44h]@7
  int Pass[8]; // [sp+24h] [bp-40h]@7
  int PassW_5; // [sp+28h] [bp-3Ch]@7
  int Pass[6]; // [sp+2Ch] [bp-38h]@7
  int PassW_4; // [sp+30h] [bp-34h]@6
  int Pass[5]; // [sp+34h] [bp-30h]@6
  int PassW_3; // [sp+38h] [bp-2Ch]@5
  int Pass[3]; // [sp+3Ch] [bp-28h]@5
  int PassW_2; // [sp+40h] [bp-24h]@4
  int Pass[1]; // [sp+44h] [bp-20h]@4
  WCHAR *NameW; // [sp+48h] [bp-1Ch]@4
  int PassW_1; // [sp+4Ch] [bp-18h]@1
  int v42; // [sp+50h] [bp-14h]@1
  int iPassLen; // [sp+54h] [bp-10h]@1
  int v44; // [sp+58h] [bp-Ch]@1
  int v45; // [sp+5Ch] [bp-8h]@7
  int v46; // [sp+60h] [bp-4h]@1
  int v47; // [sp+64h] [bp+0h]@1

  v42 = v1;
  v46 = v0;
  v21 = (int (*)())&v47;
  v20 = &loc_5B5405;
  v19 = __readfsdword(0);
  __writefsdword(0, (unsigned int)&v19);
  WGetDlgItemText();
  v44 = PassW_1;
  iPassLen = PassW_1;
  if ( PassW_1 )
    iPassLen = *(_DWORD *)(iPassLen - 4);       // 获取密码长度
  if ( iPassLen == 12 )                               //密码长度等于12时继续
  {
    WGetDlgItemText();                          // 取用户名
    VerifyName_1(NameW);                        // 利用用户名生成GlobalKey[3]
    WGetDlgItemText();                          // 取密码
    LOWORD(v2) = *(_WORD *)(PassW_2 + 2);       // 取密码第 2 / 2 = 1个
    NewChar__(&Pass[1], v2);                    // 转化为新的wchar
    CmpDword(Pass[1], GlobalKey_0_);            // 与GlobalKey[0]比较
    if ( v3 )
    {
      WGetDlgItemText();                        // 取密码,下面都是不断的取密码
      LOWORD(v4) = *(_WORD *)(PassW_3 + 6);
      NewChar__(&Pass[3], v4);
      CmpDword(Pass[3], GlobalKey_1_);          // 比较P[3] 与 GlobalKey[1]
      if ( v3 )
      {
        WGetDlgItemText();
        LOWORD(v5) = *(_WORD *)(PassW_4 + 10);
        NewChar__(&Pass[5], v5);
        CmpDword(Pass[5], GlobalKey_2_);
        if ( v3 )
        {
          WGetDlgItemText();                    // 不断的取serialKey
          LOWORD(v6) = *(_WORD *)(PassW_5 + 12);// 然后取Key[i/2]相应的数据
          NewChar__(&Pass[6], v6);              // 转换为Hex的值
          v7 = CharToHex();
          WGetDlgItemText();
          LOWORD(v8) = *(_WORD *)(PassW_6 + 16);
          NewChar__(&Pass[8], v8);
          v9 = CharToHex();
          WGetDlgItemText();
          LOWORD(v10) = *(_WORD *)(PassW_7 + 20);
          NewChar__(&Pass[10], v10);
          v11 = CharToHex();
          WGetDlgItemText();
          LOWORD(v12) = *(_WORD *)(PassW_8 + 8);
          NewChar__(&Pass[4], v12);
          v13 = CharToHex();
          WGetDlgItemText();
          LOWORD(v14) = *(_WORD *)(PassW_9 + 4);
          NewChar__(&Pass[2], v14);
          v15 = CharToHex();
          WGetDlgItemText();
          LOWORD(v16) = *(_WORD *)PassW_10;
          NewChar__(&Pass[0], v16);
          v17 = CharToHex();
          v45 = DealKey(v17, v15, v13, v7, v9, v11);            //[/i][i]DealKey(P[0],P[2],P[4],P[6],P[8],P[10]);[/i][i]
          if ( v45 == 259583198 )               // 结果等于这个就成功了
            Dialogs::ShowMessage(L"Superb Job \r\nNow Please Write a Keygen and Tutorial");
        }
      }
    }
  }
 ...                                                      //此处省略一大堆delete的代码
  return sub_40930C(&NameW, 2);
}

         因为CmpDword里面使用到了GlobalKey,所以我们需要知道VerifyName_1到底做了些什么。可惜的是这个函数并不重要啊,就直接贴C代码了
[C++] 纯文本查看 复制代码
int __fastcall VerifyName_1(WCHAR *a1)
{
  unsigned int v2; // [sp-Ch] [bp-18h]@1
  WCHAR *v3; // [sp-8h] [bp-14h]@1
  int (*v4)(); // [sp-4h] [bp-10h]@1
  WCHAR *v5; // [sp+0h] [bp-Ch]@4
  WCHAR *INameLen; // [sp+4h] [bp-8h]@1
  WCHAR *v7; // [sp+8h] [bp-4h]@1
  int v8; // [sp+Ch] [bp+0h]@1

  v7 = a1;
  System::__linkproc___LStrAddRef(0);
  v4 = (int (*)())&v8;
  v3 = &loc_5B512A;
  v2 = __readfsdword(0);
  __writefsdword(0, (unsigned int)&v2);
  INameLen = v7;
  if ( v7 )
    INameLen = (WCHAR *)*((_DWORD *)INameLen - 1);
  if ( (signed int)INameLen >= 12 )             // 用户名长度要大于12,实际上,只有前12个会参加计算
  {
    WGetDlgItemText();                          // 再次取用户名
    VerifyName_2(v5);                           // 进行第二次验证
  }
  __writefsdword(0, v2);
  v4 = loc_5B5131;
  Delete(&v5);
  return Delete(&v7);
}

       函数作用,判断用户名是否大于12个,是的话,传递给VerifyName_2进行下一轮判断。      接着来看VerifyName_2到底做了些什么吧,同样的,直接贴C++代码
[C++] 纯文本查看 复制代码
int __fastcall VerifyName_2(WCHAR *a1)
{
  WCHAR v1; // ax@5
  unsigned __int8 v2; // cf@5
  int v3; // edx@8
  int v4; // edx@9
  int v5; // ST2C_4@9
  int v6; // edx@9
  int v7; // ST28_4@9
  int v8; // edx@9
  int v9; // ST24_4@9
  int v10; // edx@9
  int v11; // ST20_4@9
  int v12; // edx@9
  int v13; // ST1C_4@9
  int v14; // edx@9
  int v15; // ST18_4@9
  int v16; // edx@9
  int v17; // ST14_4@9
  int v18; // edx@9
  int v19; // ST10_4@9
  int v20; // edx@9
  int v21; // ST0C_4@9
  int v22; // edx@9
  int v23; // ST04_4@9
  int v24; // edx@9
  int v25; // ST00_4@9
  int v26; // edx@9
  int v27; // eax@9
  unsigned int v29; // [sp-Ch] [bp-60h]@1
  int (*v30)(); // [sp-8h] [bp-5Ch]@1
  int (*v31)(); // [sp-4h] [bp-58h]@1
  int v32; // [sp+0h] [bp-54h]@1
  int v33; // [sp+4h] [bp-50h]@9
  int v34; // [sp+8h] [bp-4Ch]@9
  int v35; // [sp+Ch] [bp-48h]@9
  int v36; // [sp+10h] [bp-44h]@9
  int v37; // [sp+14h] [bp-40h]@9
  int v38; // [sp+18h] [bp-3Ch]@9
  int v39; // [sp+1Ch] [bp-38h]@9
  int v40; // [sp+20h] [bp-34h]@9
  int v41; // [sp+24h] [bp-30h]@9
  int v42; // [sp+28h] [bp-2Ch]@9
  int v43; // [sp+2Ch] [bp-28h]@9
  char v44; // [sp+30h] [bp-24h]@9
  int v45; // [sp+34h] [bp-20h]@8
  unsigned __int8 v46; // [sp+3Bh] [bp-19h]@7
  int *v47; // [sp+3Ch] [bp-18h]@5
  WCHAR *iNameLen; // [sp+40h] [bp-14h]@1
  WCHAR *v49; // [sp+44h] [bp-10h]@4
  int v50; // [sp+48h] [bp-Ch]@1
  int i; // [sp+4Ch] [bp-8h]@4
  WCHAR *v52; // [sp+50h] [bp-4h]@1
  int v53; // [sp+54h] [bp+0h]@1

  v52 = a1;
  System::__linkproc___LStrAddRef(v32);
  v31 = (int (*)())&v53;
  v30 = loc_5B5085;
  v29 = __readfsdword(0);
  __writefsdword(0, (unsigned int)&v29);
  Delete(&v50);
  iNameLen = v52;
  if ( v52 )
    iNameLen = (WCHAR *)*((_DWORD *)iNameLen - 1);// 取用户名长度
  if ( (signed int)iNameLen <= 0 )
  {
LABEL_9:                                        // 这里IDA卖萌了,反正先看下面的就对了
    HIWORD(v4) = HIWORD(v50);
    LOWORD(v4) = *(_WORD *)(v50 + 6);
    NewChar__(&v43, v4);
    v5 = CharToHex();                           // 把对应的用户名转换为Hex入堆栈
    HIWORD(v6) = HIWORD(v50);                   // 比如说数字9,就入堆栈 00000009
    LOWORD(v6) = *(_WORD *)(v50 + 8);
    NewChar__(&v42, v6);
    v7 = CharToHex();
    HIWORD(v8) = HIWORD(v50);
    LOWORD(v8) = *(_WORD *)(v50 + 10);
    NewChar__(&v41, v8);
    v9 = CharToHex();
    HIWORD(v10) = HIWORD(v50);
    LOWORD(v10) = *(_WORD *)(v50 + 12);
    NewChar__(&v40, v10);
    v11 = CharToHex();
    HIWORD(v12) = HIWORD(v50);
    LOWORD(v12) = *(_WORD *)(v50 + 14);
    NewChar__(&v39, v12);
    v13 = CharToHex();
    HIWORD(v14) = HIWORD(v50);
    LOWORD(v14) = *(_WORD *)(v50 + 16);
    NewChar__(&v38, v14);
    v15 = CharToHex();
    HIWORD(v16) = HIWORD(v50);
    LOWORD(v16) = *(_WORD *)(v50 + 18);
    NewChar__(&v37, v16);
    v17 = CharToHex();
    HIWORD(v18) = HIWORD(v50);
    LOWORD(v18) = *(_WORD *)(v50 + 20);
    NewChar__(&v36, v18);
    v19 = CharToHex();
    HIWORD(v20) = HIWORD(v50);
    LOWORD(v20) = *(_WORD *)(v50 + 22);
    NewChar__(&v35, v20);
    v21 = CharToHex();
    HIWORD(v22) = HIWORD(v50);
    LOWORD(v22) = *(_WORD *)(v50 + 4);
    NewChar__(&v34, v22);
    v23 = CharToHex();
    HIWORD(v24) = HIWORD(v50);
    LOWORD(v24) = *(_WORD *)(v50 + 2);
    NewChar__(&v33, v24);
    v25 = CharToHex();
    HIWORD(v26) = HIWORD(v50);
    LOWORD(v26) = *(_WORD *)v50;
    NewChar__(&v32, v26);
    v27 = CharToHex();
    DealName(v27, v25, v23, v5, v7, v9, v11, v13, v15, v17, v19, v21, (signed int)&v44);// DealName(N1,N2,N3,N4,N5,N6,N7,N8,N9,N10,N11,N12)
  }
  else
  {
    v49 = iNameLen;
    i = 1;
    while ( 1 )
    {
      v47 = &dword_5B5090;                      // dword_5B5090 = 00000000 0000FE03
      v1 = v52[i - 1];
      v2 = v1 < 0xFFu;
      if ( v1 <= 0xFFu )
        v2 = _bittest((signed __int32 *)&dword_5B5090, (unsigned __int8)v1);// 这个函数第一次见到,弄到我在这里卡住了。
      v46 = v2;                                 // 对应的汇编代码为BT XX,XX
      if ( !v2 )                                // 反正在这里的作用就是验证用户名是否为数字0~9
        break;
      HIWORD(v3) = HIWORD(v52);
      LOWORD(v3) = v52[i - 1];
      NewChar__(&v45, v3);
      sub_409FEC(&v50, v45);                    // 符合要求的用户名将使用一个新的空间保存
      ++i;
      v49 = (WCHAR *)((char *)v49 - 1);         // 继续循环,v46为循环次数
      if ( !v49 )
        goto LABEL_9;                           // 对每一个名字都进行了处理后。。。跳转
    }
  }
  __writefsdword(0, v29);
  v31 = loc_5B508C;
  sub_40930C(&v32, 12);
  sub_40B394(&v44, off_5B4824);
  Delete(&v45);
  Delete(&v50);
  return Delete(&v52);
}


        这个函数做的东西好像多了一点了,判断Name里面的每一个数据,是否在 1~9 之间,是的话,就转换对应的Hex数值,最后才调用到DealName来对名字进行处理。所以说,怎么搞得这么麻烦。
        接着看DealName这一个函数,虽然想同时贴汇编代码的,不过实在是太长太难看了,所以唯有贴C代码了。反正IDA这么强大,不用一下可是对不起自己啊。F5.

[C++] 纯文本查看 复制代码
int __fastcall DealName(int a1, int a2, signed __int32 a3, signed int a13, signed int a12, signed int a11, signed int a10, signed int a9, signed int a8, signed int a7, signed int a6, signed int a5, int a4)
{
  int v13; // eax@1
  int v14; // eax@4
  int v15; // eax@7
  int v16; // eax@10
  int v17; // eax@13
  int v18; // eax@16
  double *v19; // eax@19
  double *v20; // edx@19
  double *v21; // eax@19
  double *v22; // edx@19
  double *v23; // eax@19
  double *v24; // edx@19
  long double v25; // fst7@19
  long double v26; // fst7@19
  long double v27; // fst7@19
  unsigned int v29; // [sp-Ch] [bp-78h]@1
  int (__stdcall *v30)(int, int, int, int, int, int, int, int, int, int); // [sp-8h] [bp-74h]@1
  int (__stdcall *v31)(int, int, int, int, int, int, int, int, int, int); // [sp-4h] [bp-70h]@1
  int v32; // [sp+4h] [bp-68h]@19
  int v33; // [sp+8h] [bp-64h]@19
  int v34; // [sp+Ch] [bp-60h]@19
  double *v35; // [sp+10h] [bp-5Ch]@19
  int LoopTime; // [sp+14h] [bp-58h]@2
  int v37; // [sp+18h] [bp-54h]@1
  int v38; // [sp+1Ch] [bp-50h]@1
  int v39; // [sp+20h] [bp-4Ch]@1
  int v40; // [sp+24h] [bp-48h]@19
  double *D9ABC; // [sp+28h] [bp-44h]@1
  double *D5678; // [sp+2Ch] [bp-40h]@1
  double *D1234; // [sp+30h] [bp-3Ch]@1
  double v44; // [sp+34h] [bp-38h]@4
  double v45; // [sp+3Ch] [bp-30h]@4
  double v46; // [sp+44h] [bp-28h]@10
  double v47; // [sp+4Ch] [bp-20h]@1
  int i; // [sp+58h] [bp-14h]@1
  int v49; // [sp+5Ch] [bp-10h]@2
  signed __int32 v50; // [sp+60h] [bp-Ch]@1
  int v51; // [sp+64h] [bp-8h]@1
  int v52; // [sp+68h] [bp-4h]@1
  int v53; // [sp+6Ch] [bp+0h]@1

  v50 = _InterlockedExchange((signed __int32 *)&v52, a3);
  v51 = a2;
  v52 = a1;
  v31 = (int (__stdcall *)(int, int, int, int, int, int, int, int, int, int))&v53;
  v30 = loc_5B4E54;
  v29 = __readfsdword(0);
  __writefsdword(0, (unsigned int)&v29);
  sub_40B394(&v39, off_5B54D8);
  System::__linkproc___DynArraySetLength(4);    // 这里把Name按4个分组,共分成3个组 (double[4]型)
  *(double *)v39 = (long double)v52;                    //D1234[4]存储用户名的第1,2 ,3,4个数据的Hex值
  *(double *)(v39 + 8) = (long double)v51;           //D5678[4]存储用户名的第5,6,7,8个数据的Hex值
  *(double *)(v39 + 16) = (long double)v50;        //D9ABC[4]存储用户名的第9,A,B,C个数据的Hex值
  *(double *)(v39 + 24) = (long double)a4;          //这样说可能还是有一点不太清楚,反正你当作你输入的每一个字符都转换为了Double的值就是了
  System::__linkproc___DynArrayAsg(&D1234, v39, off_5B54D8);
  sub_40B394(&v38, off_5B54FC);
  System::__linkproc___DynArraySetLength(4);
  *(double *)v38 = (long double)a5;
  *(double *)(v38 + 8) = (long double)a6;
  *(double *)(v38 + 16) = (long double)a7;
  *(double *)(v38 + 24) = (long double)a8;
  System::__linkproc___DynArrayAsg(&D5678, v38, off_5B54FC);
  sub_40B394(&v37, off_5B5520);
  System::__linkproc___DynArraySetLength(4);
  *(double *)v37 = (long double)a9;
  *(double *)(v37 + 8) = (long double)a10;
  *(double *)(v37 + 16) = (long double)a11;
  *(double *)(v37 + 24) = (long double)a12;
  System::__linkproc___DynArrayAsg(&D9ABC, v37, off_5B5520);
  i = 0;
  *(_QWORD *)&v47 = *(_QWORD *)D1234;           // D1234[0]
  v13 = GetNumber(D1234);                       // 获取数组的个数-1,总是返回3
  if ( v13 >= 0 )
  {
    LoopTime = v13 + 1;                         // +1取回循环的总次数,为4次
    v49 = 0;
    do
    {
      D1234[i] = D1234[i] / v47;                // D1234[i] = D1234[i] / D1234[0]
      ++i;
      ++v49;
      --LoopTime;
    }
    while ( LoopTime );
  }
  i = 0;
  *(_QWORD *)&v45 = *(_QWORD *)D5678;           // D5678[0]
  *(_QWORD *)&v44 = *(_QWORD *)D9ABC;           // D9ABC[0]
  v14 = GetNumber(D5678);
  if ( v14 >= 0 )
  {
    LoopTime = v14 + 1;
    v49 = 0;
    do
    {
      D5678[i] = D5678[i] - v45 * D1234[i];     // D5678[i] = D5678[i] - D5678[0] * D1234[i]
      D9ABC[i] = D9ABC[i] - v44 * D1234[i];     // D9ABC[i] = D9ABC[i] - D9ABC[0] * D1234[i]
      ++i;
      ++v49;
      --LoopTime;
    }
    while ( LoopTime );
  }
  i = 0;
  *(_QWORD *)&v47 = *((_QWORD *)D5678 + 1);     // D5678[1]
  v15 = GetNumber(D5678);
  if ( v15 >= 0 )
  {
    LoopTime = v15 + 1;
    v49 = 0;
    do
    {
      D5678[i] = D5678[i] / v47;                // D5678[i] = D5678[i] / D5678[1]
      ++i;
      ++v49;
      --LoopTime;
    }
    while ( LoopTime );
  }
  i = 0;
  *(_QWORD *)&v46 = *((_QWORD *)D1234 + 1);     // D1234[1]
  *(_QWORD *)&v44 = *((_QWORD *)D9ABC + 1);     // D9ABC[1]
  v16 = GetNumber(D5678);
  if ( v16 >= 0 )
  {
    LoopTime = v16 + 1;
    v49 = 0;
    do
    {
      D1234[i] = D1234[i] - v46 * D5678[i];     // D1234[i] = D1234[i] - D1234[1] * D5678[i]
      D9ABC[i] = D9ABC[i] - v44 * D5678[i];     // D9ABC[i] = D9ABC[i] - D9ABC[1] * D5678[i]
      ++i;
      ++v49;
      --LoopTime;
    }
    while ( LoopTime );
  }
  i = 0;
  *(_QWORD *)&v47 = *((_QWORD *)D9ABC + 2);     // D9ABC[2]
  v17 = GetNumber(D9ABC);
  if ( v17 >= 0 )
  {
    LoopTime = v17 + 1;
    v49 = 0;
    do
    {
      D9ABC[i] = D9ABC[i] / v47;                // D9ABC[i] = D9ABC[i] / D9ABC[2]
      ++i;
      ++v49;
      --LoopTime;
    }
    while ( LoopTime );
  }
  i = 0;
  *(_QWORD *)&v46 = *((_QWORD *)D1234 + 2);     // D1234[2]
  *(_QWORD *)&v45 = *((_QWORD *)D5678 + 2);     // D5678[2]
  v18 = GetNumber(D9ABC);
  if ( v18 >= 0 )
  {
    LoopTime = v18 + 1;
    v49 = 0;
    do
    {
      D1234[i] = D1234[i] - v46 * D9ABC[i];     // D1234[i] = D1234[i] - D1234[2] * D9ABC[i]
      D5678[i] = D5678[i] - v45 * D9ABC[i];     // D5678[i] = D5678[i] - D5678[2] * D9ABC[i]
      ++i;
      ++v49;
      --LoopTime;
    }
    while ( LoopTime );
  }
  sub_40B394(&v35, off_5B5544);
  System::__linkproc___DynArraySetLength(3);
  v19 = v35;
  v20 = D1234;
  *(_DWORD *)v35 = *((_DWORD *)D1234 + 6);      // V35[0] = D1234[3]
  *((_DWORD *)v19 + 1) = *((_DWORD *)v20 + 7);
  v21 = v35;
  v22 = D5678;
  *((_DWORD *)v35 + 2) = *((_DWORD *)D5678 + 6);// V35[1] = D5678[3]
  *((_DWORD *)v21 + 3) = *((_DWORD *)v22 + 7);
  v23 = v35;
  v24 = D9ABC;
  *((_DWORD *)v35 + 4) = *((_DWORD *)D9ABC + 6);// V35[2] = D9ABC[3]
  *((_DWORD *)v23 + 5) = *((_DWORD *)v24 + 7);
  System::__linkproc___DynArrayAsg(&v40, v35, off_5B5544);// 把v35里面的值全部送给v40
  v25 = fabs(*(double *)v40);                   // 取绝对值
  dword_5C9344 = System::__linkproc___ROUND(v25);// 四舍五入
  v26 = fabs(*(double *)(v40 + 8));
  dword_5C9348 = System::__linkproc___ROUND(v26);
  v27 = fabs(*(double *)(v40 + 16));
  dword_5C934C = System::__linkproc___ROUND(v27);
  DwordToString(dword_5C9344, &v34);
  sub_40A1B4(&GlobalKey_0_);                    // GlobalKey[0] = ROUND(fabs(D1234[3])) + '0'
  DwordToString(dword_5C9348, &v33);
  sub_40A1B4(&GlobalKey_1_);                    // GlobalKey[1] = ROUND(fabs(D5678[3])) + '0'
  DwordToString(dword_5C934C, &v32);
  sub_40A1B4(&GlobalKey_2_);                    // GlobalKey[2] = ROUND(fabs(D9ABC[3])) + '0'
  __writefsdword(0, v29);
  v31 = loc_5B4E5E;
  sub_40930C(&v32, 3);
  sub_40B394(&v35, off_5B5544);
  sub_40B394(&v37, off_5B5520);
  sub_40B394(&v38, off_5B54FC);
  sub_40B394(&v39, off_5B54D8);
  sub_40B394(&v40, off_5B5544);
  sub_40B394(&D9ABC, off_5B5520);
  sub_40B394(&D5678, off_5B54FC);
  return sub_40B394(&D1234, off_5B54D8);
}

         代码可是非常的清晰啊,我也不想再多讲解什么了,注意了,这里在函数头和函数为都使用了一些非常奇怪的函数,反正我是第一次见,在网上也找不到什么资料,不过不太重要,作用大致都可以从名字中猜测出来了,所以不需要害怕的。哈哈。
        利用Name生成GlobalKey后,便是比较几个数据:
        P[1] 与 GlobalKey[0] , P[3] 与 GlobalKey[1], P[5] 与 GlobalKey[2]
        只有他们都相等的话才会进入到DealKey这个函数中去。
        并且,DealKey这个函数并没有用到P[1],P[3],P[5]的值,所以这里已经可以确定SerialKey的其中3个值了。

        接下来看DealKey函数:

[Asm] 纯文本查看 复制代码
int __fastcall DealKey(int a1, int a2, int a3, int P10, int P8, int P6)
.text:005B4854 DealKey         proc near               ; CODE XREF: CheckIt+207p
.text:005B4854
.text:005B4854 var_20          = dword ptr -20h
.text:005B4854 var_1C          = dword ptr -1Ch
.text:005B4854 K2              = dword ptr -18h
.text:005B4854 K1              = dword ptr -14h
.text:005B4854 result          = dword ptr -10h
.text:005B4854 P4              = dword ptr -0Ch
.text:005B4854 P2              = dword ptr -8
.text:005B4854 P0              = dword ptr -4
.text:005B4854 P10             = dword ptr  8
.text:005B4854 P8              = dword ptr  0Ch
.text:005B4854 P6              = dword ptr  10h
.text:005B4854
.text:005B4854                 push    ebp
.text:005B4855                 mov     ebp, esp
.text:005B4857                 add     esp, 0FFFFFFE0h
.text:005B485A                 push    ebx
.text:005B485B                 xor     ebx, ebx
.text:005B485D                 mov     [ebp+var_1C], ebx
.text:005B4860                 mov     [ebp+var_20], ebx
.text:005B4863                 mov     [ebp+P4], ecx
.text:005B4866                 mov     [ebp+P2], edx
.text:005B4869                 mov     [ebp+P0], eax
.text:005B486C                 xor     eax, eax
.text:005B486E                 push    ebp
.text:005B486F                 push    offset loc_5B48FB
.text:005B4874                 push    dword ptr fs:[eax]
.text:005B4877                 mov     fs:[eax], esp   ; 把esp指针送入堆栈
.text:005B487A                 mov     [ebp+K1], 2413h ; K1 = 0x2414
.text:005B4881                 lea     edx, [ebp+var_20]
.text:005B4884                 mov     eax, [ebp+K1]
.text:005B4887                 call    DwordToString
.text:005B488C                 mov     eax, [ebp+var_20]
.text:005B488F                 lea     edx, [ebp+var_1C]
.text:005B4892                 call    @Strutils@ReverseString$qqrx17System@AnsiString ; 反转string
.text:005B4897                 mov     eax, [ebp+var_1C]
.text:005B489A                 call    CharToHex
.text:005B489F                 mov     [ebp+K2], eax   ; K2 = 0x14D1
.text:005B48A2                 mov     eax, [ebp+P2]
.text:005B48A5                 imul    [ebp+P10]
.text:005B48A8                 imul    [ebp+P8]        ; temp_1 = P2 * P10 * P8
.text:005B48AB                 push    eax
.text:005B48AC                 mov     eax, [ebp+P0]
.text:005B48AF                 pop     edx
.text:005B48B0                 mov     ecx, edx
.text:005B48B2                 cdq
.text:005B48B3                 idiv    ecx             ; P0 % temp_1
.text:005B48B5                 mov     eax, [ebp+P0]
.text:005B48B8                 add     eax, [ebp+K1]
.text:005B48BB                 xor     eax, [ebp+P4]   ; temp_2 = P4 ^ (P0 + K1)
.text:005B48BE                 imul    edx, eax        ; temp_3 = temp_1 * temp_2
.text:005B48C1                 mov     eax, [ebp+P0]
.text:005B48C4                 add     eax, [ebp+P4]   ; temp_4 = P0 + P4
.text:005B48C7                 mov     ecx, [ebp+P2]
.text:005B48CA                 imul    ecx, [ebp+P6]
.text:005B48CE                 imul    eax, ecx
.text:005B48D1                 xor     eax, [ebp+K2]   ; temp_5 = K2 ^ P2 * P6 * temp_1
.text:005B48D4                 imul    edx, eax
.text:005B48D7                 sub     edx, 1939h      ; temp_6 = temp_3 * temp_5 - 0x1939
.text:005B48DD                 mov     [ebp+result], edx
.text:005B48E0                 xor     eax, eax
.text:005B48E2                 pop     edx
.text:005B48E3                 pop     ecx
.text:005B48E4                 pop     ecx
.text:005B48E5                 mov     fs:[eax], edx
.text:005B48E8                 push    offset loc_5B4902
.text:005B48ED
.text:005B48ED loc_5B48ED:                             ; CODE XREF: DealKey+ACj
.text:005B48ED                 lea     eax, [ebp+var_20]
.text:005B48F0                 mov     edx, 2
.text:005B48F5                 call    sub_40930C
.text:005B48FA                 retn

         

           幸好其中作为主体的运算部分不算长, 相应的注释也是有的了。看着注释应该是不难理解算法的。

[C++] 纯文本查看 复制代码
int __fastcall DealKey(int a1, int a2, int a3, int P10, int P8, int P6)
{
  int K[2]; // eax@1
  unsigned int v8; // [sp-Ch] [bp-30h]@1
  int (__stdcall *v9)(int, int, int); // [sp-8h] [bp-2Ch]@1
  int (__stdcall *v10)(int, int, int); // [sp-4h] [bp-28h]@1
  int v11; // [sp+4h] [bp-20h]@1
  int v12; // [sp+8h] [bp-1Ch]@1
  int K2; // [sp+Ch] [bp-18h]@1
  int K1; // [sp+10h] [bp-14h]@1
  int result; // [sp+14h] [bp-10h]@1
  int P4; // [sp+18h] [bp-Ch]@1
  int P2; // [sp+1Ch] [bp-8h]@1
  int P0; // [sp+20h] [bp-4h]@1
  int v19; // [sp+24h] [bp+0h]@1

  v12 = 0;                                      // 下面,以P[i]代表是密码的第i个字符
  v11 = 0;
  P4 = a3;
  P2 = a2;
  P0 = a1;
  v10 = (int (__stdcall *)(int, int, int))&v19;
  v9 = loc_5B48FB;
  v8 = __readfsdword(0);
  __writefsdword(0, (unsigned int)&v8);
  K1 = 9235;
  DwordToString(9235, &v11);                    // 把9235转换为字符窜
  Strutils::ReverseString(v11, &v12);           // 把字符窜头尾对调
  K[2] = CharToHex();                           // 转换回为DWORD
  K2 = K[2];                                    // 最终结果为5329
  result = (K[2] ^ P6 * P2 * (P4 + P0)) * (P4 ^ (K1 + P0)) * P0 % (P8 * P10 * P2) - 6457;// 主要的加密地方,一句代码就搞定了。。。。真心的不难
  __writefsdword(0, v8);
  v10 = loc_5B4902;
  return sub_40930C(&v11, 2);
}


        实际上,在逆向的开始,是不太可能马上就知道GlobalKey是怎么生成的,不过因为是IDA嘛,各种奇怪的功能都有,在这里附上一张图,
调用图.jpg
       这一张图充分的说明了GlobalKey由哪一些函数调用到了。说实话,这个功能非常的好用。果然IDA是神器啊。

       好吧,废话少说,知道了这些,就可以着手写Keygen了,实际上写Keygen就相当于把它的加密代码重新写了一遍啊蛋疼得很。

keygen.cpp:
[C++] 纯文本查看 复制代码
#include <iostream>
using namespace std;

#define rand10 (rand() % 10)

char Global_Array[3];

bool IsAuthKeyEffect(char a[]);
void SetGlobalKey(char AuthKey[]);
void SetSerialKey(char SerialKey[]);

int main()
{
        char AuthKey[20];
        char SerialKey[13];

        cout<<"*********************************************************************"<<endl
                <<"*                 KeyGen For XorRanger's KeygenME #5                *"<<endl
                <<"*                                               by F8LEFT           *"<<endl
                <<"*                                               2014.6.1            *"<<endl
                <<"*********************************************************************"<<endl;

        while(1) {
                cout<<"Please input your AuthKey: (1~9,Length: more than 12 character)"<<endl;
                cin>>AuthKey;
                if(strlen(AuthKey) >= 12) {
                        if(IsAuthKeyEffect(AuthKey)) {
                                break;
                        }
                        else {
                                cout<<"Error! Only 1 to 9 is accepted for the AuthKey"<<endl;
                        }
                } else {
                        cout<<"Error! AuthKey must to be 12 characters long (or longer)"<<endl;
                }
        }

        SetGlobalKey(AuthKey);
        SetSerialKey(SerialKey);
        
        cout<<"Your serialKey is:"<<endl
                <<SerialKey<<endl
                <<"Now please enjoy it"<<endl;
        system("pause");
        return 0;
}

bool IsAuthKeyEffect(char a[])                                                        //Only '1' to '9' is accepted
{
        bool flag = 1;
        for(int i = 0; i < 12; i++) {
                if(a[i] <= '0' || a[i] > '9') {  
                        flag = 0;
                        break;
                }
        }
        return flag;
}

void SetGlobalKey(char AuthKey[])
{
        double Group_1[4], Group_2[4], Group_3[4], temp_1, temp_2, temp_3;
        int i;
        for(i = 0; i < 4; i++) {                                                //Change AuthKey To Double
                Group_1[i] = AuthKey[i] - '0';
                Group_2[i] = AuthKey[i + 4] - '0';
                Group_3[i] = AuthKey[i + 8] - '0';
        }
                                                                                                        //Started to Encrypt the AuthKey
        temp_1 = Group_1[0];
        temp_2 = Group_2[0];
        temp_3 = Group_3[0];
        for(i = 0; i < 4; i++) {
                Group_1[i] = Group_1[i]/temp_1;
        }
        for(i = 0; i < 4; i++) {
                Group_2[i] = Group_2[i] - temp_2*Group_1[i];
                Group_3[i] = Group_3[i] - temp_3*Group_1[i];
        }

        temp_1 = Group_1[1];
        temp_2 = Group_2[1];
        temp_3 = Group_3[1];
        for(i = 0; i < 4; i++) {
                Group_2[i] = Group_2[i]/temp_2;
        }
        for(i = 0;i < 4; i++) {
                Group_1[i] = Group_1[i] - temp_1*Group_2[i];
                Group_3[i] = Group_3[i] - temp_3*Group_2[i];
        }

        temp_1 = Group_1[2];
        temp_2 = Group_2[2];
        temp_3 = Group_3[2];
        for(i = 0;i < 4; i++) {
                Group_3[i] = Group_3[i]/temp_3;
        }
        for(i = 0;i < 4; i++) {
                Group_1[i] = Group_1[i] - temp_1*Group_3[i];
                Group_2[i] = Group_2[i] - temp_2*Group_3[i];
        }
        
        Global_Array[0] = (int)(fabs(Group_1[3]) + 0.5) + '0';
        Global_Array[1] = (int)(fabs(Group_2[3]) + 0.5) + '0';
        Global_Array[2] = (int)(fabs(Group_3[3]) + 0.5) + '0';
}

bool CheckSerialKey(char SerialKey[])
{
        static int result;
        static int p[12];
        static int K1 = 0x2413;                
        static int K2 = 0x14D1;                                

        p[0] = SerialKey[0];
        p[2] = SerialKey[2];
        p[4] = SerialKey[4];
        p[6] = SerialKey[6];
        p[8] = SerialKey[8];
        p[10]= SerialKey[10];

        if(!(p[8] && p[10] && p[2]))                        //When one of them is zero, return false
                return false;

        result = (K2 ^ p[6] * p[2] * (p[4] + p[0])) *
                ((p[4] ^ (K1 + p[0])) * (p[0] % (p[8] * p[10] * p[2]))) - 0x1939;

        /*
        ps1: 
        0x1600 > (K2 ^ p[6] * p[2] * (p[4] + p[0])) > 0x1000(u)  
        and
        0x2500 > (p[4] ^ (K1 + p[0]) > 0x2400
        what's more 
        9 >= (p[0] % (p[8] * p[10] * p[2])) >= 0
        so
        (0xF78ECDE / 0x1600 / 0x2500) < 5 <= p[0] < 0xF78ECDE / 0x1000 / 0x2400

        ps2:
        In fact,p[0] = 5 is the best number to choose;
        */
        if(result == 0x0F78ECDE)
                return true;        
        return false;
}

void SetSerialKey(char SerialKey[])
{
        int i;
        for(i = 0; i < 12; i++)
                SerialKey[i] = 0;        
        
        SerialKey[0] = 5;                                                        //must to be 5
        srand(0);
        while(1) {                
                SerialKey[2] = rand10;
                SerialKey[4] = rand10;
                SerialKey[6] = rand10;
                SerialKey[8] = rand10;
                SerialKey[10]= rand10;
                if(CheckSerialKey(SerialKey))
                        break;
        }

        SerialKey[7] = rand10;
        SerialKey[9] = rand10;
        SerialKey[11]= rand10;

        for(i = 0; i < 12; i++)
                SerialKey[i] = SerialKey[i] + '0';

        SerialKey[1] = Global_Array[0];
        SerialKey[3] = Global_Array[1];
        SerialKey[5] = Global_Array[2];

        SerialKey[12]= 0;
}

KeyGen下载:链接: http://pan.baidu.com/s/1jGLvaom 密码: hydi
          最后总结一下吧,个人觉得这个KM做得不好的一点就是AuthKey与SerialKey的关联不大,它对用户名的计算在最后就没有参加到dealKey中去,这样,只要有了一个正确的Key,就可以很简单的模拟出其他的一堆key出来,这样乐趣就少多了。无论如何,这个KM还是挺有趣的,有兴趣的大家可以玩一下。哈哈。
PS:  第一次玩KM啊,第一次用IDA啊,两个都不会玩啊,怎么破?自己看着写出来的代码都感到混乱了,求大大支招啊。端午节到了,赶紧潜水了啊。
PS2:软件的参数传递里面使用到了EAX,ECX,EDX哦,分析起来真是难死了,看来下次还是找一个VC的KeygenMe玩了。
PS3:本来想写好在儿童节发的啊,没想到真的写好了的时候已经到了端午节了啊。
      今天有没有粽子收啊粽子。
放一份到论坛上面备份:













XorRanger\\'s KeygenME #5.rar

473.02 KB, 下载次数: 7, 下载积分: 吾爱币 -1 CB

KeyGenMe

Keygen for XorRanger\\'s KeygenME #5.zip

66.43 KB, 下载次数: 8, 下载积分: 吾爱币 -1 CB

KeyGen

免费评分

参与人数 2热心值 +2 收起 理由
Shark恒 + 1 端午快乐~
Passerby + 1 端午节奉上热心

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Passerby 发表于 2014-6-2 10:34
粽子都没吃上,感谢楼主的分析,算法一直都是我的硬伤
Some 发表于 2014-6-2 10:38
 楼主| currwin 发表于 2014-6-2 10:40
Passerby 发表于 2014-6-2 10:34
粽子都没吃上,感谢楼主的分析,算法一直都是我的硬伤

也是我的硬伤不过不玩算法的话就一直成为不了大牛
Avenshy 发表于 2014-6-2 13:56
啧啧!对于注册码分析之类的是我的软肋啊!特别是注册机什么的及就更不会了!
lao_jin 发表于 2014-6-2 15:01
虽然很详细我这个入门尚浅的学童表示吃不消。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-18 03:43

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表