吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 27731|回复: 75
收起左侧

[原创] [算法分析] C Program KenGenMe

  [复制链接]
〇〇木一 发表于 2014-5-29 22:19
本帖最后由 〇〇木一 于 2014-5-30 09:04 编辑

【文章作者】: 〇〇木一[OoWoodOne]
【软件名称】: C Program KenGenMe  
【下载地址】: http://www.52pojie.cn/thread-261639-1-1.html
【使用工具】: IDA , OD , VC6

分析不出,难受。分析出来了,不发表一下思路也难受。 所以一天时间就没了。
找实习,让我感到未来一片渺茫。大学以来我感觉我都没认真干过什么事,上不上课看心情,总喜欢自己搞一套,到现在绩点也就刚刚毕毕业,还有重修科目在身。找实习也受了不少挫,最后找到了个windows驱动开发的实习岗位,总的来说还算和我胃口。现在就是天天泡图书馆,想想以后要买房子,养老婆...不勤奋不行了。
IDA的使用也是图书馆看的,为了熟悉,我就一直找东西来试试。这个KenGenMe是昨天Blackk大大发的,今天在图书馆试试,结果发现点思路就停不下来了。
下面是正文:

IDA分析KenGenMe的具体流程是:
1.获取输入key,判断key的长度是否为24,不是则失败。
2.对得到的key进行第一步处理,并把处理结果储存在一个全局数组中。
3.对第二步全局数组中的数据进行2次处理,获取数据进行比较验证。

下面是主函数部分:
[Asm] 纯文本查看 复制代码
.text:00410240 ; Attributes: bp-based frame
.text:00410240
.text:00410240 _main_0         proc near               ; CODE XREF: _mainj
.text:00410240
.text:00410240 anonymous_0     = byte ptr -7Ch
.text:00410240 var_70          = byte ptr -70h
.text:00410240 var_30          = dword ptr -30h
.text:00410240 var_2C          = dword ptr -2Ch
.text:00410240 var_28          = dword ptr -28h
.text:00410240 var_24          = dword ptr -24h
.text:00410240 _key_len        = dword ptr -20h
.text:00410240 char_table      = dword ptr -1Ch
.text:00410240 _key_str        = byte ptr -18h
.text:00410240
.text:00410240                 push    ebp
.text:00410241                 mov     ebp, esp
.text:00410243                 sub     esp, 70h
.text:00410246                 push    ebx
.text:00410247                 push    esi
.text:00410248                 push    edi
.text:00410249                 lea     edi, [ebp+var_70]
.text:0041024C                 mov     ecx, 1Ch
.text:00410251                 mov     eax, 0CCCCCCCCh
.text:00410256                 rep stosd               ; ↓获取字符表
.text:00410258                 mov     [ebp+char_table], offset a123456789abcde ; "123456789abcdefghijklmnpqrstuvwxyz"
.text:0041025F                 push    offset asc_426120 ; "***************************************"...
.text:00410264                 call    _printf
.text:00410269                 add     esp, 4
.text:0041026C                 push    offset asc_425A68 ; "\n\n"
.text:00410271                 call    _printf
.text:00410276                 add     esp, 4
.text:00410279                 push    offset aPleaseKeygenMe ; "********                Please KeyGen M"...
.text:0041027E                 call    _printf
.text:00410283                 add     esp, 4
.text:00410286                 push    offset asc_425A68 ; "\n\n"
.text:0041028B                 call    _printf
.text:00410290                 add     esp, 4
.text:00410293                 push    offset aHaveFun_byBlac ; "********             Have Fun.By Blackk"...
.text:00410298                 call    _printf
.text:0041029D                 add     esp, 4
.text:004102A0                 push    offset asc_425A68 ; "\n\n"
.text:004102A5                 call    _printf
.text:004102AA                 add     esp, 4
.text:004102AD                 push    offset asc_426120 ; "***************************************"...
.text:004102B2                 call    _printf
.text:004102B7                 add     esp, 4
.text:004102BA                 push    offset asc_42592C ; "\n"
.text:004102BF                 call    _printf
.text:004102C4                 add     esp, 4
.text:004102C7                 push    offset aPleaseEnterPas ; "Please Enter Password:"
.text:004102CC                 call    _printf
.text:004102D1                 add     esp, 4
.text:004102D4                 lea     eax, [ebp+_key_str]
.text:004102D7                 push    eax             ; ↓获取key
.text:004102D8                 push    offset aS       ; "%s"
.text:004102DD                 call    _scanf
.text:004102E2                 add     esp, 8          ; ↓获取key串长度
.text:004102E5                 lea     ecx, [ebp+_key_str]
.text:004102E8                 push    ecx             ; Str
.text:004102E9                 call    _strlen
.text:004102EE                 add     esp, 4
.text:004102F1                 mov     [ebp+_key_len], eax
.text:004102F4                 cmp     [ebp+_key_len], 18h
.text:004102F8                 jz      loc_4103A6      ; 长度不为24就失败↓
.text:004102FE                 push    offset aBadWork_please ; "Bad Work.Please try again!"
.text:00410303                 call    _printf
.text:00410308                 add     esp, 4
.text:0041030B                 mov     edx, File._cnt
.text:00410311                 sub     edx, 1
.text:00410314                 mov     File._cnt, edx
.text:0041031A                 cmp     File._cnt, 0
.text:00410321                 jl      short loc_410345
.text:00410323                 mov     eax, File._ptr
.text:00410328                 movsx   ecx, byte ptr [eax]
.text:0041032B                 and     ecx, 0FFh
.text:00410331                 mov     [ebp+var_24], ecx
.text:00410334                 mov     edx, File._ptr
.text:0041033A                 add     edx, 1
.text:0041033D                 mov     File._ptr, edx
.text:00410343                 jmp     short loc_410355
.text:00410345 ; ---------------------------------------------------------------------------
.text:00410345
                        .
                        .
                        .
.text:0041038C ; ---------------------------------------------------------------------------
.text:0041038C
.text:0041038C loc_41038C:                             ; CODE XREF: _main_0+129j
.text:0041038C                 push    offset File     ; File
.text:00410391                 call    __filbuf
.text:00410396                 add     esp, 4
.text:00410399                 mov     [ebp+var_28], eax
.text:0041039C
.text:0041039C loc_41039C:                             ; CODE XREF: _main_0+14Aj
.text:0041039C                 push    0               ; Code
.text:0041039E                 call    _exit
.text:004103A3 ; ---------------------------------------------------------------------------
.text:004103A3                 add     esp, 4
.text:004103A6
.text:004103A6 loc_4103A6:                             ; CODE XREF: _main_0+B8j
.text:004103A6                 lea     ecx, [ebp+_key_str]
.text:004103A9                 push    ecx             ; key_str
.text:004103AA                 mov     edx, [ebp+char_table]
.text:004103AD                 push    edx             ; char_table
.text:004103AE                 mov     eax, [ebp+_key_len]
.text:004103B1                 push    eax             ; key_len
.text:004103B2                 call    _DealKey        ; 首先处理key
.text:004103B7                 add     esp, 0Ch
.text:004103BA                 push    offset _GlobalArray_0
.text:004103BF                 movsx   ecx, _GlobalArray_1
.text:004103C6                 push    ecx
.text:004103C7                 call    _VerifyKey      ; 再验证
.text:004103CC                 add     esp, 8
.text:004103CF                 mov     edx, File._cnt
.text:004103D5                 sub     edx, 1
.text:004103D8                 mov     File._cnt, edx
.text:004103DE                 cmp     File._cnt, 0
.text:004103E5                 jl      short loc_410409
.text:004103E7                 mov     eax, File._ptr
.text:004103EC                 movsx   ecx, byte ptr [eax]
.text:004103EF                 and     ecx, 0FFh
.text:004103F5                 mov     [ebp+var_2C], ecx
.text:004103F8                 mov     edx, File._ptr
.text:004103FE                 add     edx, 1
.text:00410401                 mov     File._ptr, edx
.text:00410407                 jmp     short loc_410419
.text:00410409 ; ---------------------------------------------------------------------------
.text:00410409
                        .
                        .
                        .
.text:00410450 ; ---------------------------------------------------------------------------
.text:00410450
.text:00410450 loc_410450:                             ; CODE XREF: _main_0+1EDj
.text:00410450                 push    offset File     ; File
.text:00410455                 call    __filbuf
.text:0041045A                 add     esp, 4
.text:0041045D                 mov     [ebp+var_30], eax
.text:00410460
.text:00410460 loc_410460:                             ; CODE XREF: _main_0+20Ej
.text:00410460                 pop     edi
.text:00410461                 pop     esi
.text:00410462                 pop     ebx
.text:00410463                 add     esp, 70h
.text:00410466                 cmp     ebp, esp
.text:00410468                 call    __chkesp
.text:0041046D                 mov     esp, ebp
.text:0041046F                 pop     ebp
.text:00410470                 retn
.text:00410470 _main_0         endp


搞清楚各种变量并修改后,使用IDAf5功能可以一目了然(几乎和源代码一样)

[C] 纯文本查看 复制代码
int __cdecl main_0()
{
  int v0; // eax@13
  char v2; // [sp+0h] [bp-7Ch]@0
  char v3; // [sp+Ch] [bp-70h]@1
  int v4; // [sp+4Ch] [bp-30h]@13
  int v5; // [sp+50h] [bp-2Ch]@10
  int v6; // [sp+54h] [bp-28h]@6
  int v7; // [sp+58h] [bp-24h]@3
  size_t _key_len; // [sp+5Ch] [bp-20h]@1
  char *char_table; // [sp+60h] [bp-1Ch]@1
  char _key_str[24]; // [sp+64h] [bp-18h]@1

  
  char_table = "123456789abcdefghijklmnpqrstuvwxyz";// 字符表
  printf("**************************************************************");
  printf("\n\n");
  printf("********                Please KeyGen Me.             ********");
  printf("\n\n");
  printf("********             Have Fun.By Blackk[PYG]          ********");
  printf("\n\n");
  printf("**************************************************************");
  printf("\n");
  printf("Please Enter Password:");
  scanf("%s", _key_str);
  _key_len = strlen(_key_str);
  if ( _key_len != 24 )                         // 判断长度
  {
    printf("Bad Work.Please try again!");
        ...
    exit(0);
  }
  DealKey(24, char_table, _key_str);            // 处理函数(key长度,字符表,key)
  VerifyKey(GlobalArray_1[0], GlobalArray_0);   // 验证函数(全局变量1首字符,全局变量2)
        ...
  return _chkesp(1, v0, v2);
}



这里有部分的代码省略了,都是些关于调试或者控制台有关的代码,无关紧要。

要搞清楚算法既验证原理就要逆行而上,先来看看验证部分代码

[Asm] 纯文本查看 复制代码

int __cdecl VerifyKey0(int gArr1Char0, int globalArray0)
.text:004017A0 _VerifyKey0     proc near               ; CODE XREF: _VerifyKeyj
.text:004017A0
.text:004017A0 anonymous_0     = byte ptr -5Ch
.text:004017A0 var_50          = byte ptr -50h
.text:004017A0 Dst             = byte ptr -0Ch
.text:004017A0 changeG1        = word ptr -8
.text:004017A0 var_5           = byte ptr -5
.text:004017A0 var_4           = byte ptr -4
.text:004017A0 gArr1Char0      = dword ptr  8
.text:004017A0 globalArray0    = dword ptr  0Ch
.text:004017A0
.text:004017A0                 push    ebp
.text:004017A1                 mov     ebp, esp
.text:004017A3                 sub     esp, 50h
.text:004017A6                 push    ebx
.text:004017A7                 push    esi
.text:004017A8                 push    edi
.text:004017A9                 lea     edi, [ebp+var_50]
.text:004017AC                 mov     ecx, 14h
.text:004017B1                 mov     eax, 0CCCCCCCCh
.text:004017B6                 rep stosd
.text:004017B8                 mov     [ebp+var_4], 1
.text:004017BC                 mov     eax, [ebp+gArr1Char0] ; 取首字符运算后(changeG1)判断是否符合要求↓
.text:004017BF                 and     eax, 0F0h
.text:004017C4                 sar     eax, 5
.text:004017C7                 mov     [ebp+changeG1], ax
.text:004017CB                 movsx   ecx, [ebp+changeG1]
.text:004017CF                 cmp     ecx, 1
.text:004017D2                 jnz     short loc_4017EB
.text:004017D4                 push    1               ; int
.text:004017D6                 push    0Eh             ; int
.text:004017D8                 mov     edx, [ebp+globalArray0]
.text:004017DB                 push    edx             ; keyStr
.text:004017DC                 push    (offset _GlobalArray_1+1) ; globalArr1pchar1
.text:004017E1                 call    j__DealKey1     ; changeG1为1时,第二次处理函数程序崩溃
.text:004017E6                 add     esp, 10h
.text:004017E9                 jmp     short loc_4017F8
.text:004017EB ; ---------------------------------------------------------------------------
.text:004017EB
.text:004017EB loc_4017EB:                             ; CODE XREF: _VerifyKey0+32j
.text:004017EB                 movsx   eax, [ebp+changeG1]
.text:004017EF                 cmp     eax, 2
.text:004017F2                 jz      short loc_4017F8
.text:004017F4                 mov     [ebp+var_4], 0  ; changeG1不为2时失败
.text:004017F8
.text:004017F8 loc_4017F8:                             ; CODE XREF: _VerifyKey0+49j
.text:004017F8                                         ; _VerifyKey0+52j
.text:004017F8                 movsx   ecx, [ebp+var_4]
.text:004017FC                 test    ecx, ecx
.text:004017FE                 jz      short loc_401873 ; 只用changeG1为2时,才能真正运行到验证
.text:00401800                 push    1               ; int
.text:00401802                 push    0Eh             ; int
.text:00401804                 push    offset keyStr   ; "9QX6K882ISS5M"
.text:00401809                 push    (offset _GlobalArray_1+1) ; globalArr1pchar1
.text:0040180E                 call    j__DealKey1     ; 处理函数2
.text:00401813                 add     esp, 10h
.text:00401816                 push    3               ; Size
.text:00401818                 push    (offset _GlobalArray_1+1) ; Src
.text:0040181D                 lea     edx, [ebp+Dst]
.text:00401820                 push    edx             ; Dst
.text:00401821                 call    _memcpy         ; 最后取值1
.text:00401826                 add     esp, 0Ch
.text:00401829                 push    4               ; Size
.text:0040182B                 push    (offset _GlobalArray_1+0Ah) ; Src
.text:00401830                 lea     eax, [ebp+Dst+3] ; 最后取值2
.text:00401833                 push    eax             ; Dst
.text:00401834                 call    _memcpy
.text:00401839                 add     esp, 0Ch
.text:0040183C                 mov     [ebp+var_5], 0
.text:00401840                 push    offset Str2     ; "FB40"
.text:00401845                 lea     ecx, [ebp+Dst]
.text:00401848                 push    ecx             ; Str1
.text:00401849                 call    _strcmp         ; 比较
.text:0040184E                 add     esp, 8
.text:00401851                 test    eax, eax
.text:00401853                 jnz     short loc_401864
.text:00401855                 push    offset Format   ; "Good Job!"
.text:0040185A                 call    _printf
.text:0040185F                 add     esp, 4
.text:00401862                 jmp     short loc_401871
.text:00401864 ; ---------------------------------------------------------------------------
.text:00401864
.text:00401864 loc_401864:                             ; CODE XREF: _VerifyKey0+B3j
.text:00401864                 push    offset aBadWork_please ; "Bad Work.Please try again!"
.text:00401869                 call    _printf
.text:0040186E                 add     esp, 4
.text:00401871
.text:00401871 loc_401871:                             ; CODE XREF: _VerifyKey0+C2j
.text:00401871                 jmp     short loc_401880
.text:00401873 ; ---------------------------------------------------------------------------
.text:00401873
.text:00401873 loc_401873:                             ; CODE XREF: _VerifyKey0+5Ej
.text:00401873                 push    offset aBadWork_please ; "Bad Work.Please try again!"
.text:00401878                 call    _printf
.text:0040187D                 add     esp, 4
.text:00401880
.text:00401880 loc_401880:                             ; CODE XREF: _VerifyKey0:loc_401871j
.text:00401880                 pop     edi
.text:00401881                 pop     esi
.text:00401882                 pop     ebx
.text:00401883                 add     esp, 50h
.text:00401886                 cmp     ebp, esp
.text:00401888                 call    __chkesp
.text:0040188D                 mov     esp, ebp
.text:0040188F                 pop     ebp
.text:00401890                 retn
.text:00401890 _VerifyKey0     endp

F5之后
[C] 纯文本查看 复制代码
int __cdecl VerifyKey0(int gArr1Char0, int globalArray0)
{
  int v2; // eax@7
  char v4; // [sp+0h] [bp-5Ch]@0
  char v5; // [sp+Ch] [bp-50h]@1
  char Dst[4]; // [sp+50h] [bp-Ch]@6
  __int16 changeG1; // [sp+54h] [bp-8h]@1
  char v8; // [sp+57h] [bp-5h]@6
  char v9; // [sp+58h] [bp-4h]@1

  memset(&v5, -858993460, 0x50u);
  v9 = 1;
  changeG1 = (gArr1Char0 & 0xF0) >> 5;          // changeG1的值必为2,为1时DealKey引入空值报错
  if ( (signed __int16)((gArr1Char0 & 0xF0) >> 5) == 1 )// gArr1Char0的大小必须在0x40-0x5F
  {
    j__DealKey1(&GlobalArray_1[1], (char *)globalArray0, 14, 1);// 陷阱程序崩溃
  }
  else
  {
    if ( changeG1 != 2 )                        // changeG1不为2时失败
      v9 = 0;
  }
  if ( v9 )
  {
    j__DealKey1(&GlobalArray_1[1], "9QX6K882ISS5M", 14, 1);// 第2次处理
    memcpy(Dst, &GlobalArray_1[1], 3u);         // 从全局数组中第2位开始取3个
    memcpy(&Dst[3], &GlobalArray_1[10], 4u);    // 再从第10位开始取4个
    v8 = 0;
    if ( strcmp(Dst, "FB40") )                  // 最后判断是否字串与"FB40"相等
      v2 = printf("Bad Work.Please try again!");
    else
      v2 = printf("Good Job!");
  }
  else
  {
    v2 = printf("Bad Work.Please try again!");
  }
  return _chkesp(1, v2, v4);
}

从上述代码中可以看出GloabalArray_1[0]用来判断是否真正进入验证:
changeG1=(GloabalArray_1[0]&0xF0)>>5;
changeG1必须等于2才能进入真正的验证,所以GloabalArray_1[0]的值的二进制形式必须是[010?????B],其中问号表示未知(1 or 0),也就是GloabalArray_1[0]的范围必须在0x40~0x5F之间。
最后的验证为取GloabalArray_1[1]开始的3个字符,和GloabalArray_1[10]开始的4个字符。但是其实GloabalArray_1[10]之后取得只有前两个字符有用,因为验证最后是与字符串”FB40”比较是否相等所以要使验证通过最后肯定是这样的:
GloabalArray_1[1]==’F’;
GloabalArray_1[2]==’B’;
GloabalArray_1[3]==’4’;
GloabalArray_1[10]==’0’;
GloabalArray_1[11]==’\0’;

再来看一下第二个处理函数,篇幅问题就直接看下F5的结果吧
[C] 纯文本查看 复制代码
int __cdecl DealKey1(char *globalArr1pchar1, char *keyStr, int gaLen, int status)
{
  char v5; // [sp+0h] [bp-64h]@0
  char v6; // [sp+Ch] [bp-58h]@1
  int keyStrLen; // [sp+4Ch] [bp-18h]@1
  int i; // [sp+50h] [bp-14h]@2
  int v9; // [sp+54h] [bp-10h]@6
  int v10; // [sp+58h] [bp-Ch]@6
  unsigned int j; // [sp+5Ch] [bp-8h]@6
  int kslTMP; // [sp+60h] [bp-4h]@1

  memset(&v6, -858993460, 0x58u);
  kslTMP = strlen(keyStr);
  keyStrLen = kslTMP;
  if ( status == 1 )                            // 传进来的status均为1,仅此if范围内代码有用
  {
    kslTMP = 0;
    for ( i = 0; i < gaLen; ++i )
    {
      kslTMP = i;
      globalArr1pchar1 ^= keyStr[i % keyStrLen];// 与传进的keyStr对应下标位置值异或
    }
  }
  if ( status == 2 )                            // 无用
  {
    v9 = 0;
    v10 = 0;
    for ( j = 0; ; ++j )
    {
      kslTMP = j__max0(gaLen, keyStrLen);
      if ( kslTMP <= j )
        break;
      globalArr1pchar1[v9] ^= keyStr[v10++];
      ++v9;
      if ( v9 == gaLen )
        v9 = 0;
      if ( v10 == keyStrLen )
        v10 = 0;
    }
  }
  strcmp(GlobalArray_0, globalArr1pchar1);
  return _chkesp(1, kslTMP, v5);
}


对此函数调用的地方仅仅有两处:
可以看出两处调用第4个参数status均为1

第一处是个陷阱会导致程序崩溃
j__DealKey1(&GlobalArray_1[1], (char *)globalArray0, 14, 1);// 陷阱程序崩溃
他的第二个参数是调用某个全局字串,通过分析可以发现,这个全局数组其实一直会是什么都没有,这就导致处理函数在获取字串长为0
globalArr1pchar1 ^= keyStr[i % keyStrLen];// 与传进的keyStr对应下标位置值异或
keyStrLen0,已0为除数(取余会有除操作)导致系统错误,程序崩溃。

2的调用传入keyStr="9QX6K882ISS5M",
j__DealKey1(&GlobalArray_1[1], "9QX6K882ISS5M", 14, 1);// 2次处理

传进的GlobalArray_1数组中的值是与keyStr对应下标的值进行异或,这样就可以得出:
我把第一次处理key后的全局变量GloabalArray_1[?] 写成<?>(为了方便).
<1> ^ ’9’==’F’;
<2> ^ ‘Q’==’B’;
<3> ^ ‘X’==’4’;
<10> ^ ‘S’==’0’;
<11> ^ ‘S’==’\0’;
计算后再加上方面对GloabalArray_1[0]的分析可以得出:
<0> = 0x40~0x5F (010?????B)
<1> = 0x7F (01111111B)
<2> = 0x13 (00010011B)
<3> = 0x6C (01101100B)
<10> = 0x63 (01100011B)
<11> = 0x53 (01010011B)

有了这些数据接下来就去看一下第一次处理也是最主要的处理key的部分:
标注一些变量后F5能够很清晰的了解算法
[C] 纯文本查看 复制代码
int __cdecl DealKey0(int key_len, char *char_table, char *key_str)
{
  char v4; // [sp+0h] [bp-180h]@0
  char v5; // [sp+Ch] [bp-174h]@1
  int res; // [sp+4Ch] [bp-134h]@14
  char vResult; // [sp+50h] [bp-130h]@11
  int vCmp5; // [sp+54h] [bp-12Ch]@9
  int vCmp8; // [sp+58h] [bp-128h]@11
  int minC58; // [sp+5Ch] [bp-124h]@14
  int _index; // [sp+60h] [bp-120h]@9
  int _gArrIndex; // [sp+64h] [bp-11Ch]@9
  int v13; // [sp+68h] [bp-118h]@14
  int v14; // [sp+6Ch] [bp-114h]@14
  char c; // [sp+70h] [bp-110h]@3
  int i; // [sp+74h] [bp-10Ch]@1
  unsigned int j; // [sp+78h] [bp-108h]@3
  char _arr[256]; // [sp+7Ch] [bp-104h]@6
  size_t char_table_len; // [sp+17Ch] [bp-4h]@4

  memset(&v5, 0xCCCCCCCCu, 0x174u);
  for ( i = 0; i < key_len; ++i )               // 将key转为字符表对应下标
  {
    c = key_str;
    for ( j = 0; ; ++j )
    {
      char_table_len = strlen(char_table);
      if ( char_table_len <= j )
        break;
      if ( char_table[j] == c )
      {
        _arr = j;
        break;
      }
    }
  }
  vCmp5 = 0;
  _index = 0;
  _gArrIndex = 0;
  while ( _index < key_len )
  {
    vCmp8 = 0;
    vResult = 0;
    while ( vCmp8 < 8 && _index < key_len )
    {
      LOBYTE(res) = _arr[_index];
      v14 = 8 - vCmp8;
      v13 = 5 - vCmp5;
      minC58 = min(5 - vCmp5, 8 - vCmp8);
      if ( vCmp5 <= vCmp8 )
        LOBYTE(res) = (_BYTE)res << vCmp8;
      else
        LOBYTE(res) = (signed int)(unsigned __int8)res >> vCmp5;
      vResult |= res;
      vCmp8 += minC58;
      vCmp5 += minC58;
      if ( vCmp5 >= 5 )
      {
        ++_index;
        vCmp5 = 0;
      }
    }
    GlobalArray_1[_gArrIndex++] = vResult;
  }
  GlobalArray_1[_gArrIndex] = 0;
  return _chkesp(1, 5 * key_len / 8, v4);
}

上面就是关键算法的实现部分了,首先它根据输入key将每个字符在字符表中的下标存入_arr[](为了方便我将把_arr[?]直接写成[?],与上面<?>对应),然后再去[?]中的值进行运算,将每个运算结果写入到对应的<?>中。
[?]的值只能是在字符表的范围内,在这里字符表为”123456789abcdefghiklmnpqrstuvwxyz”共34个字符(它里面竟然不包含’o’,简直坑爹,害的我很苦),所以[?]值得范围是0~33(00000000B~00100001B).
这个算法的分析没什么好讲的,因为这已经是源代码了。下面主要看看每个<?>对应的生成方式,每个<?>会用多个[?]来生成。改变一下这段代码就能获取每个<?>的生成方式。
改变后的c代码:
[C] 纯文本查看 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string>
using namespace std;

#define min(x,y) (((x)<(y)) ? (x):(y))

string toStr(int a)
{
        char b[8];
        itoa(a,b,10);
        return b;
}

int main()
{
        printf("\n_arr:<?>\nGloabalArray_1:[?]\n\n");
        int key_len=24;
        int vCmp5 = 0 , vCmp8 = 0;
        int _index = 0;
        int _gArrIndex = 0;
        string vResult;
        int minC58;
        string res;
        while ( _index < key_len )
        {
                vCmp8 = 0;
                vResult = "<";
                vResult += toStr(_gArrIndex);
                vResult += "> = ";
                bool p=false;
                while ( vCmp8 < 8 && _index < key_len )
                {
                        res = "([";
                        res += toStr(_index);
                        res += "]";
                        minC58 = min(5 - vCmp5, 8 - vCmp8);
                        if ( vCmp5 <= vCmp8 )
                                res = res + "<<" + toStr(vCmp8);
                        else
                                res = res + ">>" + toStr(vCmp5);
                        res+=")";
                        if(p)
                                vResult +="|";
                        vResult +=res;
                        p=true;
                        vCmp8 += minC58;
                        vCmp5 += minC58;
                        if ( vCmp5 >= 5 )
                        {
                                ++_index;
                                vCmp5 = 0;
                        }
                }
                _gArrIndex++;
                vResult +="\n";
                printf(vResult.c_str());
        }
        printf("\n");
        system("pause");
        return 0;
}

运行后就能看到每个<?>的生成方式了。
捕获.JPG
其中只有<0>,<1>,<2>,<3>,<10>,<11>是我们需要的

下面就是最主要关键的部分了,根据已知的东西来分析获取key:
第一个有用的[?]的范围:
[?] = (00000000B~00100001B);
先定义[?]为未知
Def  [?] = 00??????B(黄底的部分说明原本是在[?]中的部分,下同
一步步来
①:
<0> = ([0]<<0) | ([1]<<5) )= 010?????B
00??????B| ???00000B = 010?????B
000?????B| 01000000B = 010?????B
所以①可以得出:
[0] = 000?????B , [1] = 00???010B
<1> = ([1]>>3) | ([2]<<2) | ([3]<<7) = 01111111B
00000???B | ??????00B | ?0000000B = 01111111B
00000?11B | 01111?00B | 00000000B = 01111111B
[1] = 00?11010B 要小于00100001B
所以 由②可得:
[1] = 00011010B , [2] = 00011111B , [3] = 00?????0B
<2> = ([3]>>1) | ([4]<<4) = 00010011B
000?????B | ????0000B = 00010011B
000?00111B | 000?0000B = 00010011B
[3] = 00?001110B , 要小于00100001B
所以 由③可得:
[3] = 00000110B , [4] = 00??0001B
<3> = ([4]>>4) | ([5]<<1) | ([6]<<6) = 01101100B
000000??B | 0??????0B | ??000000B = 01101100B
00000000B | 0?101100B | 0?000000B = 01101100B
[5] = 00?10110B,要小于00100001B
所以 有④可得:
[4] = 00000001B , [5] = 00010110B , [6] = 00????01B
<10> = ([16]<<0) | ([17]<<5) = 01100011B
00??????B | ???00000B = 01100011B
00000011B |01100000B = 01100011B
所以 由⑤可得:
[16] = 00000011B , [17] = 00???011B
<11> = ([17] >> 3) | ([18]<<2) | ([19]<<7) =01010011B
00000???B | ??????00B | ?0000000B = 01010011B
00000011B | 0101000B | 00000000B = 01010011B
所以 由⑥可得:
[17] = 0001101?B , [18] = 00010100B , [19] = 00?????0B
最后综上可得:

[0] = 000?????B = (0~31)
[1] = 00011010B= 26
[2] = 00011111B =31
[3] = 00000110B = 6
[4] = 00000001B = 1
[5] = 00010110B = 22
[6] = 00????01B = {1,5,9,13,17,21,25,29,33}
[16] = 00000011B = 3
[17] = 00011011B = 27
[18] = 00010100B = 20
[19] = 00?????0B = {2,4,6,8...30,32}

最后通过对应字符表可得最后key字符串的24位字符的范围:
[C] 纯文本查看 复制代码
charTable = '123456789abcdefghijklnpqrstuvwxyz'; 

key[0] = {'1' ~ 'w'};
key[1] = 's';
key[2] = 'x';
key[3] = '7';
key[4] = '2';
key[5] = 'n';
key[6] = {'2','6','a','e','i','m','r','v','z'};

key[7] ~ key[15] = 任意;

key[16] = '4';
key[17] = 't';
key[18] = 'l';
key[19] = {'1','3','5','7','9','b','d','f','h','j','l','n','q','s','u','w','y'};

key[20] ~ key[24] = 任意;


//这里的任意是charTable中的任意字符(很坑爹的不包含字母'o');


随便测试几个key:
捕获xxxx.JPG

分析完了,明天继续图书馆。

点评

牛..搬个板凳坐着跟楼主学习.  发表于 2014-10-10 08:32

免费评分

参与人数 11热心值 +11 收起 理由
huanqiudiaochaw + 1 很diao!
1006706246 + 1 虽然看不懂,但是还要给分
Cencrack + 1 大神桌面跟我的一样 ! _^_
ieiqp + 1 我很赞同!
wanttobeno + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩.
2314902431 + 1 偶要上班了,给你BB,加油.
yAYa + 1 大牛.
boyving + 1 全部给你了。。大牛。
supercomx + 1 谢谢@Thanks!
Shark恒 + 1 感谢!
黑子网络 + 1 已经处理,感谢您对吾爱破解论坛的支持!

查看全部评分

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

fzx118 发表于 2014-5-30 08:30
谢谢分享  好精的汇编语言呀
轩轩1018 发表于 2014-8-1 17:13
OneTime 发表于 2014-7-29 09:07
ricroon 发表于 2014-7-23 20:48 来自手机
最近也在写一个keygen,代码好多
zzfonline 发表于 2014-7-13 18:30
学这些就要靠大神你的教程了!!大神我失业中求安慰
骑乌龟的帅蜗牛 发表于 2014-7-12 13:48
因为精华来的,可惜小女子看不懂
清少 发表于 2014-7-11 22:18
学习了!
cdTabEnter 发表于 2014-7-8 10:32
思路相当的清楚,学习了
fah 发表于 2014-7-8 01:13
好厉害,谢谢分享。。。
star0angel 发表于 2014-5-29 22:25
这  膜拜大牛啊  虽然看不懂  还是觉得非常厉害
a070458 发表于 2014-5-29 22:49
{:1_931:}学习了!
膜拜
阿富汗2013 发表于 2014-5-29 22:53
        表示在围观
含蕊 发表于 2014-5-29 23:16
支持一下
海盗小K 发表于 2014-5-29 23:22
学习了,非常感谢!
H2o 发表于 2014-5-30 00:47
膜拜会算法的大牛   !!手置了!
bansjs 发表于 2014-5-30 01:03 来自手机
兄弟呀,说的太高深了,看不明白呀
beyond_dongdong 发表于 2014-5-30 01:57
哎 这简直是在看天书  什么时候自己可以这样
zyhewsd 发表于 2014-5-30 06:59
好复杂,初学看不懂
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

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

GMT+8, 2024-3-29 04:11

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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