吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 24984|回复: 77
收起左侧

[原创] [反汇编练习] 160个CrackMe之024(Chafe.2)异或加密推理及注册机编写

[复制链接]
pk8900 发表于 2017-12-4 16:23
本帖最后由 pk8900 于 2017-12-10 17:30 编辑

  
      周末,继续研究 【适合破解新手的160个crackme练手】,本文内容为第24个CrackMe: Chafe.2.exe ,收获不少。
  这个和第23个是一个作者所写,有了分析第23个Crackme的经验(帖子:https://www.52pojie.cn/thread-670504-1-1.html),一点也不敢轻视,分析过程很顺利,但到了编写注册步骤就用的时间多了,主要是C++刚学的原因,加上我把VS2010换了2013,总会出一些莫名的错误及警告,昨晚才完成了注册机的编写,今天有时间,就发贴把我分析的过程和注册机编写和大家一起分享。
    之前论坛里有一篇关于这个CrackME的帖子,我写完注册机后搜索论坛的帖子对照了一下,帖子地址:https://www.52pojie.cn/thread-601284-1-1.html,过程写的比较细,但也有未尽之处,大家可以一并参考。
【crackme简介】
       下载地址:http://pan.baidu.com/share/link?shareid=541269&uk=4146939145
       MASM32 / TASM32编写,无壳,是一个用户名+序列号验证方式,界面第三个文本框。显示:Your serial is not valid.成功后会显示成功字样。
      分析工具:X64dbg
【crackme截图】

Image 1.png

【算法分析过程】
  有了分析chafe.1的经验,这个很快就找到了关键算法部分,代码很简短,算法部分下面跟着就是判断及提示成功或失败的信息。通过找到API调用,<user32.GetDlgItemInt>、<user32.GetWindowTextA>分别用来获取输入的用户名及注册码。
[Asm] 纯文本查看 复制代码
0040127B | FF 35 50 31 40 00     | push dword ptr ds:[403150]          |
00401281 | E8 BC 01 00 00        | call <chafe.2.GetDlgItemInt>        | 获取序列号
00401286 | 83 7D FC 00           | cmp dword ptr ss:[ebp-4], 0         |
0040128A | 74 5F                 | je chafe.2.4012EB                   |
0040128C | 50                    | push eax                            |
0040128D | 6A 14                 | push 14                             |
0040128F | 68 6C 31 40 00        | push chafe.2.40316C                 |
00401294 | FF 35 54 31 40 00     | push dword ptr ds:[403154]          |
0040129A | E8 AF 01 00 00        | call <chafe.2.GetWindowTextA>       | 获取用户名
0040129F | 85 C0                 | test eax, eax                       |
004012A1 | 74 48                 | je chafe.2.4012EB                   |
004012A3 | A1 0B 30 40 00        | mov eax, dword ptr ds:[40300B]      | 0040300B:"CTEX"
004012A8 | BB 6C 31 40 00        | mov ebx, chafe.2.40316C             | 用户名:40316C:"pk8900"
004012AD | 03 03                 | add eax, dword ptr ds:[ebx]         | 用户名前四字节+CTEX
004012AF | 43                    | inc ebx                             |
004012B0 | 81 FB 7C 31 40 00     | cmp ebx, chafe.2.40317C             |
004012B6 | 75 F5                 | jne chafe.2.4012AD                  | 循环加到末尾 eax
004012B8 | 5B                    | pop ebx                             | ebx 12345678 假码
004012B9 | 03 C3                 | add eax, ebx                        | 再加上序列号
004012BB | 31 05 D9 12 40 00     | xor dword ptr ds:[4012D9], eax      | 与 "TEX"  异或,改变004012D9
004012C1 | C1 E8 10              | shr eax, 10                         | EAX 右移位 0x10,相当于取高位
004012C4 | 66 29 05 D9 12 40 00  | sub word ptr ds:[4012D9], ax        | 4012D9 减去取的高位
004012CB | BE EC 11 40 00        | mov esi, chafe.2.4011EC             | ??压入取异或代码首地址
004012D0 | B9 3E 00 00 00        | mov ecx, 3E                         | 次数为:  0x3E
004012D5 | 33 DB                 | xor ebx, ebx                        | 清空EBX (ebx用于累计异或结果)
004012D7 | EB 04                 | jmp chafe.2.4012DD                  |
004012D9 | 54                    | db 54                               | ‘四字节为关键异或位置,跟据用户名及序列号变动
004012DA | 45                    | db 45                               | 原始代码:54 45 58 00 即“TEX”
004012DB | 58                    | db 58                               |
004012DC | 00                    | db 0                                |
004012DD | AD                    | lodsd                               | 取得双字节
004012DE | 33 D8                 | xor ebx, eax                        | ebx与其异或
004012E0 | 49                    | dec ecx                             |
004012E1 | 75 FA                 | jne chafe.2.4012DD                  | 循环判断 3E递减为0
004012E3 | 81 FB FB CF FC AF     | cmp ebx, AFFCCFFB                   | 关键比较,条件:EBX==0xAFFCCFFB
004012E9 | 74 EE                 | je chafe.2.4012D9                   |
004012EB | 68 59 30 40 00        | push chafe.2.403059                 | 403059:"Your serial is not valid."
004012F0 | FF 35 5C 31 40 00     | push dword ptr ds:[40315C]          |
004012F6 | E8 7D 01 00 00        | call <chafe.2.SetWindowTextA>       |
004012FB | 33 C0                 | xor eax, eax                        |
004012FD | C9                    | leave                               |
004012FE | C2 10 00              | ret 10                              |
00401301 | 68 73 30 40 00        | push chafe.2.403073                 | 403073:"YES! You found your serial!!"
00401306 | FF 35 5C 31 40 00     | push dword ptr ds:[40315C]          |
0040130C | E8 67 01 00 00        | call <chafe.2.SetWindowTextA>       |
00401311 | 33 C0                 | xor eax, eax                        |
00401313 | C9                    | leave                               |
00401314 | C2 10 00              | ret 10                              |


       通过对以上代码下断并分析,程序的注册验证流程为:
  0x01:GetDlgItemInt函数获取序列号,存于堆栈中
  0x02:GetWindowTextA函数获取用户名,存于40316C
  0x03:对用户名和序列号进行累加:初始值为:"CTEX"字节值:0x58455443,从用户名字串取字节值,每次偏移一个字节,取双字值进行累加,不论用户名实际长度,一直到40317C,也就是0x10(16)个,用户名变量空间是0x14(20)个。加完用户名后,出栈序列号,并与之累加(结果在EAX中)。

  0x04:累加值EAX与关键较验数据[4012D9]异或,写入[4012D9],然后取EAX高位WORD值,加到[4012D9]里,到此[4012D9]被改动了2次。
  0x05:将EBX清空,然后从内存地址[4011EC]开始,第次读入四个字节与EBX异或,EBX累加异或值,一直至内存地址[4012E4],这段正好是关键算法部分,也就是至代码004012E9  |  74 EE   |  je chafe.2.4012D9之前的这一段,所以进行异或累加过程中不能在范围内下F2断点,调试器会更换中断地址首字节为CC,这将有可能改变真正异或的结果,断点可以选在:004012E9,或下硬件执行断点调试(我也是上了当后才想明白的)。
  0x06:将异或结果与固定值:0xAFFCCFFB比较,相同的话跳至关键检验字节,再跳到注册成功。
  算法部分已分析明白,接下来就是想法做出注册机。
【制作注册机过程】
  【难点】通过分析,最后比较的字符串来自对程序248字节的代码进行异或运算,得出异或和,与固定的字符进行对比,其中[4012D9]地址4字节是根据用户名和序列号进行一系列累加,异或,高低加至低位的运算得出,也就是说用户名或序列号每变动任意一个字符都会影响最终写入[4012D9]的值。还是给大家画个流程图吧,要不还真解释不清楚。
Image 2.png
【第一步】
  通过流程图,我们可以看出,只要[4012D9]地址被写入的值对,最终异或结果就会等于0xAFFCCFFB,正确是流程是EBX最初为0,分别与4011EC开始的0x3E个地址求异或和,也包括[4012D9]地址,最终等于0xAFFCCFFB,因为异或的可逆性,可以用0xAFFCCFFB分别与以上地址求异或和,去除[4012D9]地址,或将[4012D9]地址置0,得出的结果就应该是[4012D9]地址正确的值,经计算 实际应为0x585426EB)这样我们的第一步完成了。
第二步:跟据程序写入[4012D9]值的过程,推算出写之前EAX的值。
【第二步】
  根据流程是:eax与[4012D9]"TEX"0x00584554异或,后将EAX的高位加到[4012D9]低位上,这部分是难点,我们可以先从高位推起,因为异或是按位操作,低位异或结果不会影响高位的,所以反推高位:0x585426EB取出高位:0x5854 与 对应的"TEX"0x00584554的高位0x0058异或,得出之前EAX高位是0x580C,接下来推算低位:取出26EB,应该加高位即0x580C,再和"TEX"0x00584554的低位异或,即算出EAX的低位,即(3BA3)。此时连接高低位:0x580C3BA3就是EAX的值了。
【第三步】
  第三步相对简单了,从EAX中减去固定字串"CTEX"(0x58455443)与用户名移位累加的值,剩下的就是序列号的值了(此部分可以参照CrackME 023,异或改为累加)。
根据结果,用C++做注册机完整代码如下:

[C++] 纯文本查看 复制代码
#include<iostream>

using namespace std;

unsigned char * buff;    //字符串缓冲区
unsigned long key;  //保存代码校验部分可以通过的值
unsigned long  nameValue; 
unsigned long keyHight; //高位
unsigned long keyLow;
char * youname; //用户名
unsigned long serial_No;  //序列号
unsigned char data[0x3E*4+1] = { 0x55, 0x8B, 0xEC, 0x83, 0xC4, 0xFC, 0x8B, 0x45, 0x0C, 0x83, 0xF8, 0x10, 0x75, 0x0D, 0x6A, 0x00, 0xE8, 0x6B, 0x02, 0x00, 0x00, 0x33, 0xC0, 0xC9,
0xC2, 0x10, 0x00, 0x83, 0xF8, 0x0F, 0x75, 0x0E, 0x8B, 0x45, 0x08, 0xE8, 0x18, 0x01, 0x00, 0x00, 0x33, 0xC0, 0xC9, 0xC2, 0x10, 0x00, 0x83, 0xF8,
0x01, 0x75, 0x06, 0x33, 0xC0, 0xC9, 0xC2, 0x10, 0x00, 0x3D, 0x11, 0x01, 0x00, 0x00, 0x0F, 0x85, 0xE7, 0x00, 0x00, 0x00, 0x8B, 0x45, 0x14, 0x3B,
0x05, 0x60, 0x31, 0x40, 0x00, 0x75, 0x1A, 0x6A, 0x00, 0x68, 0x96, 0x30, 0x40, 0x00, 0x68, 0xA7, 0x30, 0x40, 0x00, 0xFF, 0x75, 0x08, 0xE8, 0x17,
0x02, 0x00, 0x00, 0x33, 0xC0, 0xC9, 0xC2, 0x10, 0x00, 0x3B, 0x05, 0x58, 0x31, 0x40, 0x00, 0x74, 0x0C, 0x3B, 0x05, 0x54, 0x31, 0x40, 0x00, 0x0F,
0x85, 0xAE, 0x00, 0x00, 0x00, 0xC7, 0x05, 0xD9, 0x12, 0x40, 0x00, 0x54, 0x45, 0x58, 0x00, 0x6A, 0x00, 0x8D, 0x45, 0xFC, 0x50, 0x6A, 0x64, 0xFF,
0x35, 0x50, 0x31, 0x40, 0x00, 0xE8, 0xBC, 0x01, 0x00, 0x00, 0x83, 0x7D, 0xFC, 0x00, 0x74, 0x5F, 0x50, 0x6A, 0x14, 0x68, 0x6C, 0x31, 0x40, 0x00,
0xFF, 0x35, 0x54, 0x31, 0x40, 0x00, 0xE8, 0xAF, 0x01, 0x00, 0x00, 0x85, 0xC0, 0x74, 0x48, 0xA1, 0x0B, 0x30, 0x40, 0x00, 0xBB, 0x6C, 0x31, 0x40,
0x00, 0x03, 0x03, 0x43, 0x81, 0xFB, 0x7C, 0x31, 0x40, 0x00, 0x75, 0xF5, 0x5B, 0x03, 0xC3, 0x31, 0x05, 0xD9, 0x12, 0x40, 0x00, 0xC1, 0xE8, 0x10,
0x66, 0x29, 0x05, 0xD9, 0x12, 0x40, 0x00, 0xBE, 0xEC, 0x11, 0x40, 0x00, 0xB9, 0x3E, 0x00, 0x00, 0x00, 0x33, 0xDB, 0xEB, 0x04, 0x00, 0x00, 0x00,
0x00, 0xAD, 0x33, 0xD8, 0x49, 0x75, 0xFA, 0x81,0 };


void main024_1()
{
        key = 0xAFFCCFFB; //初始化为最终判断值  0xAFFCCFFB
        buff = data;
        serial_No = 0;
        youname = new char[250];
        memset(youname, 0, 250);
        for (int x = 0; x < 0x3E * 4; x += 4)  //循环读入代码并与最终校验值异或累计
        {
                key = key ^ *(unsigned long *)&buff[x];
                //cout << 0x3E - x / 4 << " key is:" << hex << key << "    (" << *(unsigned long *)&buff[x] << ")" << endl;
        }
        key = (key << 24) + (key >> 8); //调整字节顺序
        cout << "最终校验值:" << hex << key << endl;
        cout << "enter name:";
        gets(youname);
        nameValue = 0x58455443;      // 计算name值累加          0x58455443;//"CTEX";
        unsigned long *t1=0; 
        for (int x =0 ; x < 0x10; x++)
        {
                t1 = (unsigned long *)&youname[x];
                nameValue = nameValue + *t1;
        }
        keyHight = key >> 16;      //取出高位
        keyLow = key & 0x0000ffff;  //取出低位
        keyLow = keyLow +( keyHight^0x58);
        key = (keyHight << 16) + keyLow;
        key = key ^ 0x584554;                        //584554("CTE")
        serial_No = key - (nameValue);
        
        cout << "you key is:" << dec << serial_No << endl;
        buff = NULL;
        if (youname != NULL)
                delete[] youname;
        youname = NULL;
        system("pause");


  通过算法分析过程,可以发现EAX那个0x580C3BA3是固定值,因此注册机可以精简为如下代码:
[C++] 纯文本查看 复制代码
#include<iostream>
using namespace std;
unsigned long key;  //保存代码校验部分可以通过的值
unsigned long  nameValue;
char * youname; //用户名
unsigned long serial_No;  //序列号

void main()
{
        key = 0x580C3BA3; //初始化为最终判断值  0xAFFCCFFB
        serial_No = 0;
        youname = new char[250];
        memset(youname, 0, 250);
        cout << "enter name:";
        gets(youname);
        nameValue = 0x58455443;      // 计算name值累加          0x58455443;//"CTEX";
        unsigned long *t1 = 0;
        for (int x = 0; x < 0x10; x++)
        {
                t1 = (unsigned long *)&youname[x];
                nameValue = nameValue + *t1;
        }
        serial_No = key - (nameValue);
        cout << "you key is:" << dec << serial_No << endl;
        system("pause");
}

  提供一组KEY,name:52pojie.cn  serial:1454218211
  整个分析及注册机编写流程这是这样了,也不知道大家能不能看明白,也不确定自己分析的准不准确,反正注册机算出的序列号是能用的。CrackMe有个小BUG,第一次输个长用户名,第二次输短的,只会在第一次输入的地址前部改写,不会清0后边的,所以这种情况判断的结果就未知了。

  欢迎大家回贴交流,共同探讨。让我们共同从新手成为高手,也有可以和大牛一拼的实力。

免费评分

参与人数 36吾爱币 +31 热心值 +31 收起 理由
52lxw + 1 热心回复!
laike0 + 1 谢谢@Thanks!
netle8 + 1 热心回复!
liuchang2017 + 1 + 1 已答复!
buddama + 1 + 1 我很赞同!
wuaipojiee + 1 + 1 我很赞同!
milkwolf + 1 + 1 用心讨论,共获提升!
2864095098 + 1 + 1 热心回复!
drw168 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
没有如果儿 + 1 + 1 用心讨论,共获提升!
不知道叫什么好 + 1 + 1 谢谢@Thanks!
王亦棋 + 1 + 1 热心回复!
zhh4827 + 1 + 1 谢谢@Thanks!
独行风云 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
woshitxm + 1 热心回复!
patchouli + 1 谢谢@Thanks!
科技成就生活 + 1 + 1 用心讨论,共获提升!
ziye + 1 + 1 谢谢@Thanks!
笙若 + 1 谢谢@Thanks!
174888 + 1 + 1 谢谢@Thanks!
沉浸故里南 + 1 膜拜
a5606495 + 1 + 1 谢谢@Thanks!
xiaofengzi + 1 + 1 热心回复!
zhiyi1120 + 1 + 1 用心讨论,共获提升!
v_link + 1 + 1 谢谢@Thanks!
sunnylds7 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
kikyoulin + 1 + 1 先赞后马,明天考完试来看!
jin925 + 1 + 1 向你学习,有时间也把那个系列学习了
yufan1123 + 1 + 1 谢谢@Thanks!
kilkilo502 + 1 谢谢@Thanks!
红枫 + 1 谢谢@Thanks!
22222 + 1 用心讨论,共获提升!
xiaolei0517 + 1 + 1 用心讨论,共获提升!
无瑕黑心肠 + 1 + 1 用心讨论,共获提升!
WYWZ + 1 + 1 用心讨论,共获提升!
朱朱你堕落了 + 1 + 1 望你早日与大牛比肩!

查看全部评分

本帖被以下淘专辑推荐:

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

wssbly 发表于 2019-1-14 00:16
大神你好,我有一个问题,比较难以表述:第二块儿算法那里,不是62次异或嘛;第60和61次是第一块算法那里计算好后填充到0x004012D9位置的值,这块值我做出来不是0x585426EB,是0x581D26EB,关键是这样用OD调试时还调对了?但是真的单独打开程序明显没通过验证,我是哪里错了,为什么我算出来是1D不是54?
2.PNG
上图的EB261D58,EB26是无条件跳转都一样,但是调试时我这里要是1D58最后异或才能得出AFFCCFFB,5458反而不行。
2.PNG
但是单独打开这样输入验证不通过,应该就是这个“1D”不对,但调试就是对的。
3.PNG
感觉缺了什么,求教大神!
还有,我不是算异或和,我是先靠程序自己运行的,然后列等式:
0xEB13FCEE xor 0x xxxxxx04 = (0xAFFCCFFB xor 0x81FA7549)xor 0xD833ADxx   最后得0x1D26EB04和0xD833AD58,是不是这样算是错误的?为什么错误?



 楼主| pk8900 发表于 2019-4-16 19:19
wenwen520 发表于 2019-4-16 00:33
我不是很明白你写的这个注册机里面0x580C3BA3 这个值怎么来的,还有在跳转前进行cmp 0xAFFCCFFB之前进行了3 ...

004012A3 | A1 0B 30 40 00        | mov eax, dword ptr ds:[40300B]      | 0040300B:"CTEX"
ptr ds:[40300B] 中的值 dword ptr [0040300B "CTEX"]=58455443,这个是固定的值

“还有在跳转前进行cmp 0xAFFCCFFB之前进行了3E次的异或,但是从你的注册机代码中并没有体现出这块的代码”
看注册机1就有异或操作,注册机2因为这样异或只会产生一个固定值,所以可以精简了。
Cubo 发表于 2017-12-4 16:51
Hmily 发表于 2017-12-4 16:56
pk8900和whyida最近一直在给大家带来科普各种crackme知识文章,先给pk8900一个精华鼓励,感谢你们的分享期待以后有更多分析。
 楼主| pk8900 发表于 2017-12-4 17:05
Hmily 发表于 2017-12-4 16:56
pk8900和whyida最近一直在给大家带来科普各种crackme知识文章,先给pk8900一个精华鼓励,感谢你们的分享期 ...

把自己分析过程写下来,能加深学到的内容,同时又能和大家分享,何乐不为。
卡卡纠结 发表于 2017-12-4 18:02
超级给力啊
6767 发表于 2017-12-4 18:11
围观围观
都同学 发表于 2017-12-4 20:14
感谢楼主、
lipinghao 发表于 2017-12-4 21:55
楼主能干掉 TMPGEnc Video Mastering Works 6 这个就好了!
GANDALF111 发表于 2017-12-5 07:06
最近也在学习破解,但是第一个crackme就遇到了点小麻烦,需要不断学习才行啊,感谢楼主分享破解过程,很精彩。
iloveu 发表于 2017-12-5 10:14
学习一下,谢谢
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

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

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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