pk8900 发表于 2017-12-1 23:50

[反汇编练习] 160个CrackMe之023(Chafe.1)分析思路及注册机

本帖最后由 pk8900 于 2017-12-4 10:12 编辑

    今天是星期五,工作之余,继续研究 【适合破解新手的160个crackme练手】,本文内容为第23个CrackMe: Chafe.1.exe
    经过一下午的分析(中间有两次都想放弃了)终于将算法分析出来,并写了一个注册机,搜索了一下关于这个Crackme的帖子,有两篇,都没有分析出具体算法,就决定发这个帖子,以供论坛里和我一样的新手查阅和对照。
【crackme简介】
       下载地址:http://pan.baidu.com/share/link?shareid=541269&uk=4146939145
       MASM32 / TASM32编写,无壳,是一个用户名+序列号验证方式,界面第三个文本框。显示:Your serial is not valid.估计成功后会显示在这里。无按钮事件,应该是GETXXXXTEXT等方式获取输入。看来作者是个汇编高手,作者说明爆破不算,应找出算法或做出注册机,但看了160CrackMe后面标的一颗星,估计不会太难,谁想到却让我花了一下午的时间。
【crackme截图】



【初步分析】


   用X64DBG打开CrackMe,搜索字串,找到失败标志:Your serial is not valid.及成功标志:"YES! You found your serial!!",双击到代码处。可清晰看到跳到成功的路线,有、 两个变量地址(全局变量,局部变量一般为EBP-XX),就简称166和167吧,成功的条件是167=0x10,往上看167=166,也就是166=10成功,看来还得往前逆,这一调用00401294 | E8 BA 01 00 00 | call <chafe.1.sub_401453>,回车跟进,代码如下:



【逆-1步】
   如上图,共有三段简短的代码,在00401294处下断,运行的流程会从第一段跳到第三段,这是到分析完也没弄明白的地方,段中有句代码:lea esp, dword ptr ds:[<&sub_40146F>], 40146F是第二段首地址,但却RET到了第三段0040149C,第二段没被执行。这段代码让我迷惑了好久,第三段跟了数遍,才弄明白,具体分析如下:




代码流程是166=0x0C,如果 188+0x9112478==0 则执行 166+4,166正好是0x10,满足注册成功条件,否则166=0,条件不满足。这里可以看到188是一个:39BD0B38(十进968690488),也就是如果这时188的值是 负(0x9112478)十进制(-152118392),那就注册成功了。
这里给大家说个小窍门,就是X64dgb的监视功能,类似于VS或VB等软件的功能,可以把你要监控的地址加入到监视列表里(上图底部),中断的时候你就可以一眼看到所有的值,尤其是监控全局变量,本程序就是。
因第二段代码没有被执行,而代码里有句引人注意的地方:00401483 | E8 64 00 00 00      | call <chafe.1.GetDlgItemInt>,于是就在这句代码下断,取消其它断点。



【逆-2步】
      如上图所示,断下后,单步F8,发现函数返回值EAX就是我们刚输入的序列号00BC614E(12345678),被存入188这个关键地址中。这时我发现在第三段代码188地址里是:39BD0B38(十进968690488),这说明我们输入的序列号被计算修改了,也许看到这里大家都会想到对188地址下内存写入断点,OD中可以这样,但X64DBG中却不行,这里对内存下断会中断整个内存代码页,具体原因我也没看太懂,英文的文档,好像是实现不了这一中断。但我们可以查找对188地址的引用。通过对引用代码的查看,找到了如下位置,也就是程序的关键算法位置。



↑↑引用列表↑↑
【逆-3步】
   


如上图所示,18C地址中存放的是我们输入的用户名,被EDI引用,168地址是一个计数器,用EDI+168计数器进行偏移,168计数器初始为0,EDI加完后,计数器累加1,然后取出188地址中我们输入序列号(数字格式,输入非数字会变为0)放入EAX,eax加1后与edi(相当于取用户名计数器指针位置4字节)异或运算,结果存入188地址,一直到计数器累加至0x10退出循环,此时188地址中的数值就决定了是否能注册通过,上面我们分析如果188地址==负(0x9112478)十进制(-152118392),就行,我后来在论坛里看了一个帖子说这地址想为负数,就得用户名满足什么条件,实际这想法是错误的,内存数据里是不分正负数的,可以是有符号负数,也可以是无符号正数,也就是说188=F6EEDB88 (4142848904)即可,分析到这里已经完成,接下来就是注册机的问题,因为异或操作是可逆的,我们可以用F6EEDB88 反向从用户名字符尾部住前异或并减1,得出正确的序列号。说到这,程序还有一段通过GetWindowText获取我们的用户名并把字符后部0x14字节置0的代码,大家可以找到并分析。我就不贴上来了。

【注册机】
下面把注册机代码贴上(C++):
#include<iostream>
using namespace std;

char * name;
unsigned long serial = 0xF6EEDB88;

void main()
{
      unsigned long * p;
      name = new char;
      memset(name, 0, strlen(name));
      cout << "enter name:";
      gets_s(name, strlen(name)-1);
      for (int x = 0x10-1; x >= 0; x--)
      {
                p =(unsigned long *) &name;
                serial = serial ^ *p;
                serial--;
      }
      cout <<"serial is:" <<serial<< endl;
system("pause");
}
附一组测试Key: name:52pojie.cn   serial:3702830035
时间马上到零点了,写贴和排版的时间花了近2小时,哈哈,希望大家能看懂,看完后能有所收获,有错误之处还请指正。

梁上燕 发表于 2018-2-2 23:00

pk8900 发表于 2018-2-2 17:30
用户名和序列号都输好了再下断,下断后会直接断下来。

谢谢楼主{:1_919:}
本菜鸟只会追明码,刚刚看到那个程序还想追明码,试了好几次发现并不是和明码比较的:'(weeqw
谢谢楼主的攻略了,不然还在纠结明码在哪

wenwen520 发表于 2019-4-15 22:15

https://www.52pojie.cn/forum.php?mod=redirect&goto=findpost&ptid=670504&pid=20048588
我现在跟你的结果是一样的,其实retn后进去的就是序列号的算法程序,和楼主逆向3部分的代码一样,代码2那部分我觉得可以不用看

都同学 发表于 2017-12-2 00:26

学习一波,楼主辛苦了

抢我所爱的你 发表于 2017-12-2 00:28

我是沙发吗?

13613706220 发表于 2017-12-2 04:32

感谢分享 懂了一点 刚接触

努力的小七 发表于 2017-12-2 10:10

过来学习一下

身外事 发表于 2017-12-2 14:28

学习了,特别是这种一步一步算法破解谢谢分享,新手受够了关键跳nop或者jmp

半夏未夏 发表于 2017-12-3 13:35

谢谢楼主

zhousilai 发表于 2017-12-3 15:54

请问LZ是什么调试器?能分享?

aieva 发表于 2017-12-3 16:11

谢谢楼主

pk8900 发表于 2017-12-3 16:53

zhousilai 发表于 2017-12-3 15:54
请问LZ是什么调试器?能分享?

X64DBG,开源的,现在一直在更新。官网可自由下载。 https://x64dbg.com/
页: [1] 2 3
查看完整版本: [反汇编练习] 160个CrackMe之023(Chafe.1)分析思路及注册机