pk8900 发表于 2018-3-10 12:08

[反汇编练习] 160个CrackMe之154(The_q.2)算法分析及注册机编写

本帖最后由 pk8900 于 2018-3-10 12:15 编辑

    经过半年多的断断续续的研究 【适合破解新手的160个crackme练手】已经进行到第154个,还有几个就要进行完了,今天把这个Crackme的算法分析写一下,因为论坛里没有搜索到详细分析的帖子。
【crackme简介】
       下载地址1:https://pan.baidu.com/s/1cySNkj9uENG_ppK80BmjUQ 密码:8d77
      MASM32 / TASM32编写,无壳,点击help菜单下Register,是一个Name+Code验证方式,界面两个文本框,OK按钮和Cancel按钮。【初试】在Crackme中输入任意用户名和序列号,点OK按钮,没有反应,估计只能正确时才会有提示。
      分析工具:IDA + X64dbg,注册机编写:VS2013
【crackme截图】

【算法分析过程】
X64dbg中载入,搜索字符串,发现:"         C00L !! U found a correct Serial ! =)\n\r Tell Me how by e-mail to : Phrozen_q@cyberdude.com ",转到代码位置,发现如下代码:
004012C9 | E8 52 01 00 00               | call <the_q..GetDlgItem>                           |
004012CE | 68 A9 21 40 00               | push the_q..4021A9                                 |
004012D3 | 6A 28                        | push 0x28                                          |
004012D5 | 6A 0D                        | push 0xD                                             |
004012D7 | 50                           | push eax                                             |
004012D8 | E8 73 01 00 00               | call <the_q..SendMessageA>                           |
004012DD | A2 D1 21 40 00               | mov byte ptr ds:, al                     |
004012E2 | 3C 00                        | cmp al, 0x0                                          |
004012E4 | 74 67                        | je the_q..40134D                                     |
004012E6 | 90                           | nop                                                |
004012E7 | 90                           | nop                                                |
004012E8 | 90                           | nop                                                |
004012E9 | 90                           | nop                                                |
004012EA | 3C 08                        | cmp al, 0x8                                          |
004012EC | 73 09                        | jae the_q..4012F7                                    |
004012EE | 90                           | nop                                                |
004012EF | 90                           | nop                                                |
004012F0 | 90                           | nop                                                |
004012F1 | 90                           | nop                                                |
004012F2 | E8 5F 00 00 00               | call <the_q..sub_401356>                           |
004012F7 | 6A 00                        | push 0x0                                             |
004012F9 | 6A 00                        | push 0x0                                             |
004012FB | 6A 66                        | push 0x66                                          |
004012FD | FF 75 08                     | push dword ptr ss:                        |
00401300 | E8 21 01 00 00               | call <the_q..GetDlgItemInt>                        |
00401305 | A3 D2 21 40 00               | mov dword ptr ds:, eax                     |
0040130A | 3C 00                        | cmp al, 0x0                                          |
0040130C | 74 3F                        | je the_q..40134D                                     |
0040130E | 90                           | nop                                                |
0040130F | 90                           | nop                                                |
00401310 | 90                           | nop                                                |
00401311 | 90                           | nop                                                |
00401312 | E8 5E 00 00 00               | call <the_q..sub_401375>                           |
00401317 | E8 A5 00 00 00               | call <the_q..sub_4013C1>                           |
0040131C | 85 C0                        | test eax, eax                                        |
0040131E | 74 2D                        | je the_q..40134D                                     |
00401320 | 90                           | nop                                                |
00401321 | 90                           | nop                                                |
00401322 | 90                           | nop                                                |
00401323 | 90                           | nop                                                |
00401324 | 6A 00                        | push 0x0                                             |
00401326 | 68 9F 21 40 00               | push the_q..40219F                                 | 40219F:"Correct !"
0040132B | 68 3A 21 40 00               | push the_q..40213A                                 | 40213A:"         C00L !! U found a correct Serial ! =)\n\r Tell Me how by e-mail to : Phrozen_q@cyberdude.com "
00401330 | FF 75 08                     | push dword ptr ss:                        |
00401333 | E8 06 01 00 00               | call <the_q..MessageBoxA>                            |
程序调用:GetDlgItem和SendMessageA获取Name框文本内容,调用GetDlgItemInt获取Code框输入的数值,输入任意Name和Code后,进行跟踪,发现在上段代码中:
       一、sub_401356子程序对输入的Name长度小于8的话,则在用户名后追加字符0,1,2......到Name长度为8终止。
       二、sub_401375子程序对输入的Name进行加密操作处理,流程为:第一字符累加第8字符,第二字符累加第7字符,第三字符累加第6字符,第4字符累加第5字符,然后用累加完的1-4字符复制到5-8字符,最后将1-8字符分别与"PhroZenQ"字符异或,加密过程完成。
voidsub_401375( char * yourname)
{
      for (int x = 0; x < 4; x++)
      {
                yourname += yourname;
      }
      for (int x = 4; x < 8; x++)
      {
                yourname = yourname;
      }
      char * s1 = "PhroZenQ";
      for (int x = 0; x < 8; x++)
      {
                yourname ^= s1;
      }
}
      三、sub_4013C1是验证子程序,验证流程如下图:

通过上图验证流程,进行注册机的反推,将Name值加密后分组,应使P1和P2的值相等,P2的值是由Key1循环右移P1的低8位值得来,也就是说P2的值(Key1循环右移X次后),值等于P1,即P2的低8位值一定是X,否则无法实现P1=P2,通过比较X的值,匹配后再进一步算出Code,如果从00-0FF都匹配不上,则该Name无法成功算出Code。
       根据分析结果,注册机实现如下:
#include<iostream>
using namespace std;
voidsub_401375( char * yourname)//用户名加密处理
{
      for (int x = 0; x < 4; x++)
      {
                yourname += yourname;
      }
      for (int x = 4; x < 8; x++)
      {
                yourname = yourname;
      }
      char * s1 = "PhroZenQ";
      for (int x = 0; x < 8; x++)
      {
                yourname ^= s1;
      }
}
long ror(unsigned long a1, int x1)//循环右移x1次
{
      unsigned long ret = a1;
      long a2 = 0;
      for (int x = 0; x < x1; x++)
      {
                a2 = (ret & 1) << 31;
                ret = ((ret & 1) << 31) | (ret >> 1);
      }
      return ret;
}
long rol(unsigned long a1, int x1)//循环左移x1次
{
      unsigned long ret = a1;
      for (int x = 0; x < x1; x++)
      {
                ret = ((ret & 0x80000000) >>31) + (ret << 1);
      }
      return ret;
}
void main()
{
      char * Enter_yourname = new char;
      memset(Enter_yourname, 0, 260);
      cout << "Enter your name:";
      gets_s(Enter_yourname, 260);
      char s1 = 0x30;

      int a;
      while (strlen(Enter_yourname) < 8)
      {
                a = strlen(Enter_yourname);
                Enter_yourname = s1;
                Enter_yourname = 0;
                s1++;
      }
      cout << Enter_yourname << endl;
      sub_401375(Enter_yourname);
    // cout << "Enter your serial:";//原程序流程部分
      unsigned long serial;
      //cin >> serial;//原程序流程部分
      unsigned long * key1 = (unsigned long *)&Enter_yourname;
      unsigned long * key2 = (unsigned long *)&Enter_yourname;
      // unsigned long k1 = rol(serial, Enter_yourname & 0xFF) ^ *key2;//原程序流程部分
      // unsigned long k2 = ror(*key1, k1 & 0xff);//原程序流程部分
      //cout << hex << uppercase << k1 << "    " << k2 << endl;//原程序流程部分
      unsigned long tmp=0,tmp1=0;
      unsigned long the_key = 0;
      for (int x = 0; x <= 255; x++)
      {
                tmp = ror(*key1, x);
                if ((tmp & 0xFF) == x)    //判断低8位值是否等于X,若相等则进一步反推,得出CODE值
                {
                        tmp ^= *key2;
                        the_key = ror(tmp, Enter_yourname & 0xFF);
                        break;
                }
      }
      if (the_key != 0)
                cout << "your serial is:" << the_key << endl;
      else
                cout << "not found serial!" << endl;
cout<<"auto head...hello!"<<endl;
system("pause");
}
通过注册机测试,并不是所有的name都能得到CODE,能通过的用户名有:PhroZenQ,P......
52pojie,52pojie.cn,O等
提供两组测试:name:52pojie.cnCode:3679130504       name:PhroZenQ    Code:3793889001
注册成功截图如下:

程序Name长度有效位数为9位,多余部分不参与加密与验证。
整个分析过程完成,如有不对的地方还请路过的大神指正。

flyyi 发表于 2018-3-10 12:27

感谢大佬

kk1212 发表于 2018-3-10 12:29

反汇编练习资料丰富学习完这些基本上就上路了

wgz001 发表于 2018-3-10 13:44

这个我服 {:1_932:}

cnshr00t 发表于 2018-3-10 13:59

谢谢分享

NoDocCat 发表于 2018-3-10 14:00

谢谢楼主

无书。 发表于 2018-3-10 14:15

多谢,学习了,最近也在学破解

胖子哦 发表于 2018-3-10 14:25


多谢,学习了,最近也在学破解

夜曲 发表于 2018-3-10 14:33

多谢,先收藏一下。

刘留留 发表于 2018-3-11 02:17

正在学习中,谢谢分享
页: [1] 2
查看完整版本: [反汇编练习] 160个CrackMe之154(The_q.2)算法分析及注册机编写