新CrackMe160之064 - CR - Game0

第一关:
OD载入程序, 搜索界面看到成功关键字,定位到0040148C, 向上看到了固定串"JPL-168-39", 输入验证提示成功, 接着又提示失败
所以这个固定串并不是真正的答案, 由IDA分析源码可知:

signed int sub_401403()
{
  signed int result; // eax@5
  LPARAM lParam; // [sp+0h] [bp-Ch]@1
  char v2; // [sp+7h] [bp-5h]@2
  char v3; // [sp+Ah] [bp-2h]@3

  if ( SendMessageA(hWnd, 0xDu, 0xCu, (LPARAM)&lParam) <= 3 )  //4位以上
    goto LABEL_11;
  if ( v2 == 32 )
    v3 += 31;
  if ( !sub_401146(&lParam, &word_401436) ) // 字符串对比, &word_401436 = "JPL-168-39"
  {
    MessageBoxA(0, "Congratulation! You pass Level 0!", "CR-Game vXO", 0); //进这里就返回0失败,是个幌子
    return 0;
  }
  if ( sub_401146(&lParam, &word_40149E) ) // &word_40149E = "CR-Game vXO"
LABEL_11:
    result = 0;
  else
    result = 1; //需要到这里,所以word_40149E 这个应该才是关键
  return result;
}

系列号得4位以上, 00401429处判断第8位如果是空格,那第11位就要加0x1F, 所以最终要与"CR-Game vXO"这个比,那正确的系列号就应该是最后一位反过来减去0x1F, 得到"CR-Game vX0"
输入"CR-Game vX0"这个,第一关过了, 这时界面显示 Level 002

第二关:
由上一关最后返回位置可知所有关的入口在004021B5 ~ 0040221C这些判断里, 直接在最开头(004021B5处)下断点, 这样每一关都可以直接停这里再进对应关
第二关的入口是: 004014C7, IDA对应查看源码:

signed int sub_4014C7()
{
  signed int result; // eax@16
  LPARAM lParam; // [sp+6h] [bp-Ah]@1
  char v2; // [sp+Ah] [bp-6h]@6
  char v3; // [sp+Bh] [bp-5h]@7
  char v4; // [sp+Ch] [bp-4h]@8
  char v5; // [sp+Dh] [bp-3h]@9
  char v6; // [sp+Eh] [bp-2h]@10

  if ( SendMessageA(hWnd, 0xDu, 0xAu, (LPARAM)&lParam) <= 8
    || (_BYTE)lParam == 67
    || BYTE1(lParam) != 108
    || BYTE2(lParam) == 71 && BYTE3(lParam) != 118
    || v2 != 101
    || v3 == 50 && v4 != 49
    || v5 != 71
    || v6 != 67
    || (v4 += 59, (_BYTE)lParam != 50)
    || BYTE2(lParam) != 101
    || BYTE3(lParam) != 118
    || v3 != 76
    || v4 != 108 )
    result = 0;
  else
    result = 2;
  return result;
}

这里看不出什么, 只能知道有个判断,还得看OD代码:

004014C7  /$  55            push ebp
004014C8  |.  8BEC          mov ebp,esp
004014CA  |.  83C4 F4       add esp,-0xC
004014CD  |.  53            push ebx                                           ;  CR-Game0.00401FDA
004014CE  |.  8D45 F6       lea eax,dword ptr ss:[ebp-0xA]
004014D1  |.  50            push eax                                           ; /lParam = 0x2
004014D2  |.  6A 0A         push 0xA                                           ; |wParam = 0xA
004014D4  |.  6A 0D         push 0xD                                           ; |Message = WM_GETTEXT
004014D6  |.  FF35 74404000 push dword ptr ds:[0x404074]                       ; |hWnd = 0x143900
004014DC  |.  E8 25180000   call <jmp.&user32.SendMessageA>                    ; \SendMessageA
004014E1  |.  83F8 08       cmp eax,0x8                                        ; 是否<=8, 9位以上
004014E4  |.  7E 60         jle short CR-Game0.00401546
004014E6  |.  8D5D F6       lea ebx,dword ptr ss:[ebp-0xA]
004014E9  |.  803B 43       cmp byte ptr ds:[ebx],0x43                         ; 第1位不能是0x43
004014EC  |.  74 58         je short CR-Game0.00401546        
004014EE  |.  807B 01 6C    cmp byte ptr ds:[ebx+0x1],0x6C                     ; 第2位是0x6C = 'l' (L)
004014F2  |.  75 52         jnz short CR-Game0.00401546
004014F4  |.  807B 02 47    cmp byte ptr ds:[ebx+0x2],0x47                     ; 第3位是0x47 = 'G'
004014F8  |.  75 06         jnz short CR-Game0.00401500
004014FA  |.  807B 03 76    cmp byte ptr ds:[ebx+0x3],0x76                     ; 第4位是0x76 = 'v'
004014FE  |.  75 46         jnz short CR-Game0.00401546
00401500  |>  807B 04 65    cmp byte ptr ds:[ebx+0x4],0x65                     ; 第5位是0x65 = 'e'
00401504  |.  75 40         jnz short CR-Game0.00401546
00401506  |.  807B 05 32    cmp byte ptr ds:[ebx+0x5],0x32                     ; 第6位是0x32 = '2'
0040150A  |.  75 06         jnz short CR-Game0.00401512
0040150C  |.  807B 06 31    cmp byte ptr ds:[ebx+0x6],0x31                     ; 第7位是0x31 = '1'
00401510  |.  75 34         jnz short CR-Game0.00401546
00401512  |>  807B 07 47    cmp byte ptr ds:[ebx+0x7],0x47                     ; 第8位是0x47 = 'G'
00401516  |.  75 2E         jnz short CR-Game0.00401546
00401518  |.  807B 08 43    cmp byte ptr ds:[ebx+0x8],0x43                     ; 第9位是0x43 = 'C'
0040151C  |.  75 28         jnz short CR-Game0.00401546
0040151E  |.  8043 06 3B    add byte ptr ds:[ebx+0x6],0x3B                     ; 第7位+0x3B=0x6C = 'l' (L)
00401522  |.  803B 32       cmp byte ptr ds:[ebx],0x32                         ; 第1位是0x32 = '2'
00401525  |.  75 1F         jnz short CR-Game0.00401546
00401527  |.  807B 02 65    cmp byte ptr ds:[ebx+0x2],0x65                     ; 第3位是0x65 = 'e'
0040152B  |.  75 19         jnz short CR-Game0.00401546
0040152D  |.  807B 03 76    cmp byte ptr ds:[ebx+0x3],0x76                     ; 第4位是0x76 = 'v'
00401531  |.  75 13         jnz short CR-Game0.00401546
00401533  |.  807B 05 4C    cmp byte ptr ds:[ebx+0x5],0x4C                     ; 第6位是0x4C = 'L'
00401537  |.  75 0D         jnz short CR-Game0.00401546
00401539  |.  807B 06 6C    cmp byte ptr ds:[ebx+0x6],0x6C                     ; 第7位是0x6C = 'l' (L)
0040153D  |.  75 07         jnz short CR-Game0.00401546
0040153F  |.  B8 02000000   mov eax,0x2
00401544  |.  EB 02         jmp short CR-Game0.00401548
00401546  |>  33C0          xor eax,eax
00401548  |>  5B            pop ebx                                            ;  CR-Game0.004021CE
00401549  |.  C9            leave
0040154A  \.  C3            retn

00401525 以上可得系列号为: 2lGve21GC, 00401527 ~ 00401539将第3467位换为evLl, 所以最终系列号为: 2leveL1GC (其中第7位还要反减0x3B)

第三关:
同理直接看IDA源码:

signed int sub_40154B()
{
  LRESULT v0; // eax@1
  int i; // ecx@4
  int v2; // ecx@9
  int j; // eax@9
  signed int result; // eax@13
  _BYTE v5[41]; // [sp+7h] [bp-59h]@3   //系列号
  LPARAM lParam; // [sp+30h] [bp-30h]@1 //用户名
  char v7[27]; // [sp+45h] [bp-1Bh]@4   //固定串 QWERTYUIOPASDFGHJKLZXCVBNM

  v0 = SendMessageA(dword_40406C, 0xDu, 0x15u, (LPARAM)&lParam);
  if ( (unsigned int)v0 < 5 || v0 > 20 || SendMessageA(hWnd, 0xDu, 0x29u, (LPARAM)v5) != v0 )
  { //用户名长度需要6~20位
LABEL_14:
    result = 0;
  }
  else
  {
    sub_40118A(v7, "QWERTYUIOPASDFGHJKLZXCVBNM");
    for ( i = 0; *((_BYTE *)&lParam + i); ++i )
    {
      if ( *((_BYTE *)&lParam + i) >= 0x61u )   // 将小写转大写
        *((_BYTE *)&lParam + i) -= 32;
    }
    v2 = 0;
    for ( j = (unsigned __int8)lParam; (_BYTE)j; LOBYTE(j) = *((_BYTE *)&lParam + v2) )
    {
      LOBYTE(j) = j - 65;
      if ( v7[j] != v5[v2] ) // 固定串对应位置的值是否等于系列号
        goto LABEL_14;
      ++v2;
    }
    result = 3;
  }
  return result;
}

由上代码分析可得, 用户名: abcdef => ABCDEF => 对应固定串 QWERTY, 所以系列号就是: QWERTY

第四关:
同理直接看IDA源码:

signed int sub_401602()
{
  LRESULT v0; // eax@1
  LPARAM *v1; // ebx@4
  int v2; // ecx@4
  int i; // eax@4
  signed int result; // eax@26
  _BYTE v5[41]; // [sp+4h] [bp-74h]@3   //系列号
  LPARAM lParam; // [sp+2Dh] [bp-4Bh]@1 //用户名
  char v7[27]; // [sp+42h] [bp-36h]@4   //固定串QWERTYUIOPASDFGHJKLZXCVBNM
  char v8[27]; // [sp+5Dh] [bp-1Bh]@4   //固定串polkiujmnhytgbvfredcxswqaz

  v0 = SendMessageA(dword_40406C, 0xDu, 0x15u, (LPARAM)&lParam); //用户名长度 6 ~ 20
  if ( (unsigned int)v0 < 5 || v0 > 20 || SendMessageA(hWnd, 0xDu, 0x29u, (LPARAM)v5) != 2 * v0 )
  {
LABEL_27:
    result = 0;
  }
  else
  {
    v1 = &lParam;
    sub_40118A(v8, "polkiujmnhytgbvfredcxswqaz");
    sub_40118A(v7, "QWERTYUIOPASDFGHJKLZXCVBNM");
    v2 = 0;
    for ( i = (unsigned __int8)lParam; (_BYTE)i; LOBYTE(i) = *((_BYTE *)&lParam + v2) )
    {
      if ( (unsigned __int8)i < 0x61u || (unsigned __int8)i > 0x7Au )
      {
        if ( (unsigned __int8)i < 0x41u )
          goto LABEL_27;
        if ( (unsigned __int8)i > 0x5Au )
          goto LABEL_27;
        LOBYTE(i) = i - 65; //A~Z之间
        if ( v7[i] != v5[v2] ) //用大写串
          goto LABEL_27;
      }
      else  //如果用户名在a~z之间
      {
        LOBYTE(i) = i - 97;
        if ( v8[i] != v5[v2] ) //用小写串
          goto LABEL_27;
      }
      ++v2;
    } //下面与上面同理,对比系列号后半部分,所以可知系列号长度应=2倍用户名长度
    LOBYTE(i) = lParam;
    while ( (_BYTE)i )
    {
      if ( (unsigned __int8)i < 0x61u || (unsigned __int8)i > 0x7Au )
      {
        if ( (unsigned __int8)i < 0x41u )
          goto LABEL_27;
        if ( (unsigned __int8)i > 0x5Au )
          goto LABEL_27;
        LOBYTE(i) = i - 65; //A~Z
        if ( v8[i] != v5[v2] ) //用小写串 与上面不同处
          goto LABEL_27;
      }
      else
      {
        LOBYTE(i) = i - 97; //a~z
        if ( v7[i] != v5[v2] ) //用大写串 与上面不同处
          goto LABEL_27;
      }
      ++v2;
      v1 = (LPARAM *)((char *)v1 + 1);
      LOBYTE(i) = *(_BYTE *)v1;
    }
    result = 4;
  }
  return result;
}

固定串QWERTYUIOPASDFGHJKLZXCVBNM
固定串polkiujmnhytgbvfredcxswqaz

所以分析完就很明朗了, 用户名: aBcDeF => 系列号: pWlRiYQoEkTu

第五关:
继续看IDA源码:

signed int sub_40172D()
{
  LRESULT v0; // eax@1
  int i; // ecx@4
  int v2; // ecx@9
  char j; // al@9
  int k; // ecx@10
  signed int result; // eax@17
  int v6; // [sp-14h] [bp-8Ch]@10
  _BYTE v7[41]; // [sp+4h] [bp-74h]@3
  LPARAM lParam; // [sp+2Dh] [bp-4Bh]@1 
  char v9[27]; // [sp+42h] [bp-36h]@4
  char v10[27]; // [sp+5Dh] [bp-1Bh]@4

  v0 = SendMessageA(dword_40406C, 0xDu, 0x15u, (LPARAM)&lParam);
  if ( (unsigned int)v0 < 5 || v0 > 20 || SendMessageA(hWnd, 0xDu, 0x29u, (LPARAM)v7) != v0 )
  {
LABEL_18:
    result = 0;
  }
  else
  {
    sub_40118A(v10, "QWERTYUIOPASDFGHJKLZXCVBNM");
    sub_40118A(v9, "pOlKiUjmnhytgbVfredCXSwqaZ");
    for ( i = 0; *((_BYTE *)&lParam + i); ++i )
    {
      if ( *((_BYTE *)&lParam + i) >= 0x61u ) //小写转大写
        *((_BYTE *)&lParam + i) -= 32;
    }
    v2 = 0;
    for ( j = lParam; j; j = *((_BYTE *)&lParam + v6 + 1) )
    {
      v6 = v2;
      for ( k = 0; v10[k] && j != v10[k]; ++k ) //在大写串中找到位置
        ;
      if ( v9[k] != v7[v6] ) //用这个位置在V9串中找到值与系列号对比
        goto LABEL_18;
      v2 = v6 + 1;
    }
    result = 5;
  }
  return result;
}

这个就很明显了, 用户名: QWERTY => 系列号: pOlKiU

第六关:
还是继续直接看IDA源码:

signed int sub_401823()
{
  unsigned int v0; // ecx@5
  unsigned int v1; // ecx@9
  unsigned int v2; // ecx@13
  int i; // ecx@19
  int v4; // ecx@24
  int j; // eax@24
  char v7[32]; // [sp+0h] [bp-80h]@24
  LPARAM v8; // [sp+20h] [bp-60h]@3 //系列号
  char v9; // [sp+24h] [bp-5Ch]@17
  int v10; // [sp+25h] [bp-5Bh]@18
  int v11; // [sp+29h] [bp-57h]@18
  LPARAM v12; // [sp+40h] [bp-40h]@2 //公司名
  LPARAM lParam; // [sp+60h] [bp-20h]@1 //用户名

  if ( (unsigned int)SendMessageA(dword_40406C, 0xDu, 0x20u, (LPARAM)&lParam) < 5 //用户名5位以上
    || (unsigned int)SendMessageA(dword_404070, 0xDu, 0x20u, (LPARAM)&v12) < 1 //公司名不能空
    || (unsigned int)SendMessageA(hWnd, 0xDu, 0x20u, (LPARAM)&v8) < 0xA ) //系列号长度10位以上
    return 0;
  if ( (_BYTE)v8 != 74 ) //J
  {
    v0 = 0;
    do
      ++v0;
    while ( v0 < 0x64 );
    return 0;
  }
  if ( BYTE1(v8) != 105 ) //i
  {
    v1 = 0;
    do
      ++v1;
    while ( v1 < 0xC8 );
    return 0;
  }
  if ( BYTE2(v8) != 80 ) //P
  {
    v2 = 0;
    do
      ++v2;
    while ( v2 < 0x12C );
    return 0;
  }
  if ( (v12 & 6) + (_BYTE)lParam != BYTE3(v8)
    || (lParam & 9) + (_BYTE)v12 != v9
    || v11 != lParam + ((v10 ^ lParam) & 0x9070503) )
    return 0;
  for ( i = 0; *((_BYTE *)&lParam + i); ++i )
  {
    if ( *((_BYTE *)&lParam + i) >= 0x61u )    // 小写转大写
      *((_BYTE *)&lParam + i) -= 32;
  }
  sub_40118A(v7, "JiP4ZAQWSXCDERFVBGTYHNMJUIKLOP");
  v4 = 0;
  for ( j = (unsigned __int8)lParam; (_BYTE)j; LOBYTE(j) = *((_BYTE *)&lParam + v4) )
  {
    LOBYTE(j) = j - 61;
    if ( v7[j] != *((_BYTE *)&v8 + v4 + 13) ) // 系列号与用户名转换后对比, 说明用户名长度与系列号长度也得一样
      return 0;
    ++v4;
  }
  return 6;
}

用户名: abcde
公司名: 1
系列号第1位: 0x4D - 3 = 'J'
系列号第2位: 0x69 = 'i'
系列号第3位: 0x4D + 3 = 'P'
系列号第4位: 0x61 + (0x31 & 6) = 'a'
系列号第5位: ((0x61 & 9) + 0x31) & 0xFF = '2'
系列号第6~9位x: 6~9位 ^ 0x64636261 & 0x9070503 + 0x64636261 == 10~13位 OD测试结果 69:1234那1013则为:abcd
系列号第14~18位: ZAQWS (用户名在固定串对应位置的后4位)
最终:
系列号: JiPa21234abcdZAQWS

第七关:
IDA源码:

signed int sub_401967()
{
  LRESULT v0; // eax@2
  LRESULT v1; // eax@4
  signed int result; // eax@7
  char v3; // [sp+5h] [bp-43h]@2
  LPARAM v4; // [sp+16h] [bp-32h]@2
  LPARAM lParam; // [sp+27h] [bp-21h]@1
  char v6; // [sp+33h] [bp-15h]@6

  if ( SendMessageA(hWnd, 0xDu, 0x21u, (LPARAM)&lParam) != 16  //系列号长度16位
    || (RtlZeroMemory(&v3, 17),
        sub_4012E8(&lParam, &v3),
        v0 = SendMessageA(dword_404070, 0xDu, 0x11u, (LPARAM)&v4),
        (unsigned int)v0 < 1)
    || (unsigned int)v0 > 0x10
    || (v1 = SendMessageA(dword_40406C, 0xDu, 0x21u, (LPARAM)&lParam), (unsigned int)v1 < 1)
    || (unsigned int)v1 > 0x10
    || (sub_4011AE(&lParam, &v4), v6 = 0, sub_401146(&lParam, &v3)) )
    result = 0;
  else
    result = 7;
  return result;
}

代码比较简单,看不出具体算法, 关键在这三个方法 sub_4012E8(base64加密), sub_4011AE(字符串连接), sub_401146(字符串对比)
系列号长度: 16位,
公司名长度: 16位以内,
用户名长度: 16位以内,
算法就是: 系列号 = base64(用户名+公司名)
用户名: abcde
公司名: 12345
系列号: base64("abcde12345") = YWJjZGUxMjM0NQ==
用户名+公司名 的长度需要为10~12位, 加密结果才会是16位

 
 
本节高手录制的视频,点击前往查看

 
 
 
使用的工具连接(工具有点多有点大,可以先下OD,其它的后面慢慢下) 点击前往下载

下面是我的OD的界面布局,我觉得这4个是最常用的界面,其它的我基本上没用到~
OD界面布局

posted @ 2024-12-30 14:28  hankerstudio  阅读(12)  评论(0)    收藏  举报