吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6948|回复: 4
收起左侧

[原创] [反汇编练习] 160个CrackMe之047(DueList.2.exe)算法分析及注册机编写

[复制链接]
pk8900 发表于 2017-12-15 13:19
本帖最后由 pk8900 于 2017-12-15 13:22 编辑

   
   昨天晚上,继续研究 了【适合破解新手的160个crackme练手】,本文内容为第47个CrackMe: DueList.2.exe,论坛里搜索了一下关于这个CrackMe的帖子,没找到,所以写了这篇帖子,分享一下我的分析过程及注册机编写方法。
【crackme简介】
       下载地址:http://pan.baidu.com/share/link?shareid=541269&uk=4146939145
       MASM32 / TASM32编写,无壳,是一个Keyfile验证方式,打开后只有一个提示框,大意是说:你的试用时间已到期,请把KEY文件放到目录下进行注册。
      分析工具:X64dbg,OD
      这个CRACKME和034有些像,可以参照帖子:https://www.52pojie.cn/thread-673404-1-1.html
【crackme截图】
Image 1.png
【算法分析过程】
关键代码位置如下:
[Asm] 纯文本查看 复制代码
00401057   .  A3 AF214000   mov dword ptr ds:[0x4021AF],eax          ; |kernel32.BaseThreadInitThunk
0040105C   .  6A 00         push 0x0                                 ; |/hTemplateFile = NULL
0040105E   .  68 6F214000   push DueList_.0040216F                   ; ||Attributes = READONLY|HIDDEN|SYSTEM|ARCHIVE|TEMPORARY|402048
00401063   .  6A 03         push 0x3                                 ; ||Mode = OPEN_EXISTING
00401065   .  6A 00         push 0x0                                 ; ||pSecurity = NULL
00401067   .  6A 03         push 0x3                                 ; ||ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
00401069   .  68 000000C0   push 0xC0000000                          ; ||Access = GENERIC_READ|GENERIC_WRITE
0040106E   .  68 79204000   push DueList_.00402079                   ; ||FileName = "due-cm2.dat"
00401073   .  E8 0B020000   call <jmp.&KERNEL32.CreateFileA>         ; |\CreateFileA
00401078   .  83F8 FF       cmp eax,-0x1                             ; |
0040107B   .  75 1D         jnz short DueList_.0040109A              ; |
0040107D   .  6A 00         push 0x0                                 ; |/Style = MB_OK|MB_APPLMODAL
0040107F   .  68 01204000   push DueList_.00402001                   ; ||Title = "Duelist's Crackme #2"
00401084   .  68 17204000   push DueList_.00402017                   ; ||Text = "Your time-trial has ended... Please register and copy the keyfile sent to you to this directory!"
00401089   .  6A 00         push 0x0                                 ; ||hOwner = NULL
0040108B   .  E8 D7020000   call <jmp.&USER32.MessageBoxA>           ; |\MessageBoxA
00401090   .  E8 24020000   call <jmp.&KERNEL32.ExitProcess>         ; \ExitProcess
00401095   .  E9 28010000   jmp DueList_.004011C2
0040109A   >  6A 00         push 0x0                                 ; /pOverlapped = NULL
0040109C   .  68 73214000   push DueList_.00402173                   ; |pBytesRead = DueList_.00402173
004010A1   .  6A 46         push 0x46                                ; |BytesToRead = 46 (70.)
004010A3   .  68 1A214000   push DueList_.0040211A                   ; |Buffer = DueList_.0040211A
004010A8   .  50            push eax                                 ; |hFile = 75753358
004010A9   .  E8 2F020000   call <jmp.&KERNEL32.ReadFile>            ; \ReadFile
004010AE   .  85C0          test eax,eax                             ;  kernel32.BaseThreadInitThunk
004010B0   .  75 02         jnz short DueList_.004010B4
004010B2   .  EB 43         jmp short DueList_.004010F7
004010B4   >  33DB          xor ebx,ebx
004010B6   .  33F6          xor esi,esi
004010B8   .  833D 73214000>cmp dword ptr ds:[0x402173],0x12         ;  读取长度小于 0x12 失败
004010BF   .  7C 36         jl short DueList_.004010F7
004010C1   >  8A83 1A214000 mov al,byte ptr ds:[ebx+0x40211A]           ;第一段代码
004010C7   .  3C 00         cmp al,0x0                               ;  key[N]为零结循环
004010C9   .  74 08         je short DueList_.004010D3
004010CB   .  3C 01         cmp al,0x1
004010CD   .  75 01         jnz short DueList_.004010D0              ;  key[N]等于0x01则累加ESI计数
004010CF   .  46            inc esi
004010D0   >  43            inc ebx
004010D1   .^ EB EE         jmp short DueList_.004010C1
004010D3   >  83FE 02       cmp esi,0x2                              ;  第一条件:至少有两个0x01
004010D6   .  7C 1F         jl short DueList_.004010F7

以上代码部分分析结果如下:
       1、CreateFileA参数Mode = OPEN_EXISTING,打开已存在的文件,若文件不存在,函数返回-1,是用来验证Key文件是否存在的。
       2、ReadFile函数读取文件内容,参数pBytesRead = Cruehead.004021A0是读取文件返回的字节数,接下来一句代码cmp dword ptr ds:[0x402173],0x12,如果读取的字节数少于0x12(18)个,则跳至失败处,BytesToRead = 46 (70.),预读取字节为70个
       3、FileName = "due-cm2.dat",所以我们在CrackMe目录下新建一个文件due-cm2.dat,并写入18个字节以上的数据,内容随意。
      再次载入程序,在ReadFile后代码下断点,进行分析。读入的字节我们分别用Key[0]~Key[n]来表示,第一段循环代码,从Key[0]开始,一直遇到\0空字符结束,统计出Key[0]~Key[n]中0x01字节的个数,最少应为2个,少于2个则跳至KEY文件无效提示。
[Asm] 纯文本查看 复制代码
004010DA   .  33DB          xor ebx,ebx                              ;  第二段代码循环
004010DC   >  8A83 1A214000 mov al,byte ptr ds:[ebx+0x40211A]
004010E2   .  3C 00         cmp al,0x0
004010E4   .  74 09         je short DueList_.004010EF
004010E6   .  3C 01         cmp al,0x1
004010E8   .  74 05         je short DueList_.004010EF
004010EA   .  03F0          add esi,eax                              ;  kernel32.BaseThreadInitThunk
004010EC   .  43            inc ebx
004010ED   .^ EB ED         jmp short DueList_.004010DC
004010EF   >  81FE D5010000 cmp esi,0x1D5                            ;  第一个01前,累加值为0x1D5
004010F5   .  74 1D         je short DueList_.00401114

  上面的第二段代码循环是:
  从Key[0]开始,一直到第一个0x01字节,累加各字节值为0x1D5,不含0x01字节,则成功。
[Asm] 纯文本查看 复制代码
00401114   > \33F6          xor esi,esi                              ;  第三段代码
00401116   >  43            inc ebx
00401117   .  8A83 1A214000 mov al,byte ptr ds:[ebx+0x40211A]
0040111D   .  3C 00         cmp al,0x0
0040111F   .  74 18         je short DueList_.00401139
00401121   .  3C 01         cmp al,0x1
00401123   .  74 14         je short DueList_.00401139
00401125   .  83FE 0F       cmp esi,0xF                              ;  >=0xF个字符结束
00401128   .  73 0F         jnb short DueList_.00401139
0040112A   .  3286 1A214000 xor al,byte ptr ds:[esi+0x40211A]        ;  与第一字答异或,依次存入402160地址
00401130   .  8986 60214000 mov dword ptr ds:[esi+0x402160],eax      ;  kernel32.BaseThreadInitThunk
00401136   .  46            inc esi
00401137   .^ EB DD         jmp short DueList_.00401116
00401139   >  43            inc ebx                                  ;  遇到01或到第0xf个字符结束
0040113A   .  33F6          xor esi,esi

上面的第三段代码循环是:
从第一个0x01字节后的字节开始,分别与Key[0]~Key[N]异或,异或结果存入402160地址,一直到第二个0x01字节或到Key[15]结束,同样不含最后的那个字节,402160地址异或后的字节将成为最终注册成功显示的用户名。
[Asm] 纯文本查看 复制代码
0040113A   .  33F6          xor esi,esi                              ;  第四部分循环代码
0040113C   >  8A83 1A214000 mov al,byte ptr ds:[ebx+0x40211A]
00401142   .  3C 00         cmp al,0x0
00401144   .  74 09         je short DueList_.0040114F
00401146   .  3C 01         cmp al,0x1
00401148   .^ 74 F2         je short DueList_.0040113C
0040114A   .  03F0          add esi,eax                              ;  kernel32.BaseThreadInitThunk
0040114C   .  43            inc ebx
0040114D   .^ EB ED         jmp short DueList_.0040113C
0040114F   >  81FE B2010000 cmp esi,0x1B2                            ;  到00字符前累加值为0x1B2,不累加0x01
00401155   .^ 75 A0         jnz short DueList_.004010F7

上面的第四段代码循环是:累加第三部分之后的字节值,一直到0x00字节,其中的0x01字节不累加在内,若累加值为0x1B2则成功验证完成,在文本框内显示402160地址的用户名,上面有已注册的英文提示。
【注册机编写】
第一个0x01前的累加值为:1D5,所以前三个字节可以为0xEA,0xEB,0x01,这样从第四个开始可以留给用户使用,一直到第16个,所以能注册的用户长度最长为13个字符。
用户名部分将想要注册显示的用户名依次序从Key[0]开始异或,存入文件中。后面的部分就比较简单了,长度不限,只要到空字符之前的累加值为0x1B2,并写入第二个0x01就行。
C++代码如下:
[C++] 纯文本查看 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include <windows.h>
using namespace std;
int main()
{
        char * path = "E:\\crackme\\due-cm2.dat";
        FILE * keyfile;
        char * youkey = new char[40];         //输入用户名
        memset(youkey, 0, 40);
        unsigned char * writekey = new unsigned char[40];
        memset(writekey, 0, 40);             //存入文件的内容
        cout << "Enter your name:";
        gets(youkey);
        if (strlen(youkey) >= 8)
                cout << "用户名最多支持13位,其余部分将被截断!" << endl;
        int now = 0;
        
        writekey[0] = 0xEA;
        writekey[1] = 0xEB;
        writekey[2] = 0x01;
        for (unsigned int x = 0; x < 13 && x<strlen(youkey); x++)
        {
                writekey[x+3] = youkey[x]^writekey[x];
        }
        if (strlen(youkey) >= 13)
                now = 16;
        else
                now = strlen(youkey) + 3;

        writekey[now] = 0x01;
        writekey[now+1] = 0xD9;
        writekey[now+2] = 0xD9;
        errno_t err = fopen_s(&keyfile, path, "w+b");
        if (err != 0)
        {
                cout << "file open or create failed!" << endl;
                system("pause");
                return -1;
        }
        rewind(keyfile);
        fwrite(writekey, sizeof(byte), 40, keyfile);
        fclose(keyfile);
        cout << "write file over!" << endl;
        delete[] youkey;
        delete[] writekey;
        system("pause");
        return 1;
}

附注册成功后截图:
Image 2.png
说明:后来想了一下,上面的注册机中异或后的用户名字符部分有可能含有0x01字符,这部分未加入判断,失败也是有概率的。
分析的对不对,欢迎大家回贴交流。

免费评分

参与人数 6威望 +1 吾爱币 +15 热心值 +6 收起 理由
liuchang2017 + 1 + 1 已答复!
ziye + 1 + 1 谢谢@Thanks!
Hmily + 1 + 10 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
朱朱你堕落了 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
WYWZ + 1 + 1 用心讨论,共获提升!
shanhuyi + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

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

13025796343 发表于 2017-12-15 13:35
支持一下下
shanhuyi 发表于 2017-12-15 14:09
异客CO 发表于 2018-12-17 21:54
zyj66 发表于 2018-12-18 10:31
谢谢分享,注册机不容易编写
zq7695zq 发表于 2018-12-18 16:53
请问这个crackme合集在哪里可以下载??
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-12-22 15:45

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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