首页
论坛
课程
招聘
[调试逆向] [原创][原创]160个CrackMe学习之001
2020-9-16 13:25 1239

[调试逆向] [原创][原创]160个CrackMe学习之001

2020-9-16 13:25
1239

前言

160个CrackMe 是新手学习逆向破解的CrackMe系列,我尝试一步步将160个CrackMe破解,帖子记录学习过程。

由于百度云现在分享不了这160个crackmed程序,说什么有敏感内容,如果需要,回复邮箱,我邮箱发过来。

这是我在看雪的第一个帖,若有错误,还望指正谢谢。

0x1.工具和环境

WinXP SP3 + 52专用OD + PEID

由于win7系统对于程序开启了地址随机化,会给分析带来不必要的麻烦,所以我的分析环境是WinXP SP3


0x2.程序分析

想要分析一个程序,首先,需要运行一下程序,这一步很重要,它帮助我们理解作者的意图以及为我们提供一些有用的信息,比如字符串,弹窗等等。

运行程序,发现程序的注册分为两种方式,一种是Serial/Name,用户需要输入用户名和注册码,另外一种是Serial,用户只需输入一个注册码。


方式二:

我们随便选一种方式,就比如选只要求用户输入注册码的看似稍简单的第二种方式:

随便输入一个注册码:999

点击Check it Baby! 

弹出一个对话框提示:Try Again!

现在我们将其拖入exeinfo查壳,无壳,程序由Delphi写的。然后拖入ollydbg查看,搜索字符串Try Again!

这里面搜索出来两个Try Again!字符串,我们先查看第一个(我们的运气比较好,第一个Try Again!字符串就是我们要找的,第二种方式的Try Again!的字符串)

那么我们可以推测,第二个Try Again!字符串将会出现在第一种方式的报错当中



可以看到此处就是第二种注册方式的代码领空,这里面有注册成功后的congratz!和注册失败的Try Again!而且,这上面只有一个跳转,也就是jnz

我们若是把jnznop掉,程序便可以直接走到注册成功的提示信息congratulatz!处,也出现了注册成功的提示信息,这样我们便实现了对程序的爆破。


同时,我们注意到栈当中有个字符串,Hello Dude!我们没有理由不怀疑,这就是注册码,拿来尝试一下,果不其然,这就是注册码,而且是不变的。


方式一:

现在我们来看看第一种方式如何破解这个程序。随便输入:

Name:99999
Serial:11111

点击Check it Baby! 弹出一个对话框:Sorry,The Serial is incorrect!

现在我们还是在od里面看看这个程序,搜索字符串 Sorry,The Serial is incorrect!我们可以看到程序当中有两个Sorry,The Serial is incorrect!字符串,


我们先去第一个字符串的代码领空看看:



我们将断点设在42FA4D然后单步运行程序,在42FA57时,EAX的值是5,也就是说,函数的返回值为5,然后再与4比较大小,5>4,jge跳转实现

这个地方的字符串并没有输出!刚才输出的是第二个Sorry,The Serial is incorrect!字符串。奇怪,现在也不知道为什么,继续向下面单步运行。


在下面我们可以看到堆栈出现奇怪的字符串CW-4674-CRACKED,并且也出现了我们的Name:99999。我们完全有理由怀疑这个由CW-

4674-CRACKED拼接而成的字符串CW-4674-CRACKED是注册码,并且4674是被运算出来的!!!尝试一下,我们的猜测完全正确

而且下面有个可疑的跳转,这个跳转跳过congratz!成功跳到输出第二个Sorry,The Serial is incorrect!字符串。

显然,42A170就是MessageBoxA函数了。



我们将这个jnznop掉,就可以将这个程序爆破了。

但是!不找出注册算法,我们不能称之为将这个程序破解了。而且我们之前还遗留了一个问题,在地址42FA57处,EAX的值是5,

这个5是什么意思?第一个Sorry,The Serial is incorrect!字符串。在什么情况下输出,有朋友可能会怀疑第二种注册方式会输出,

但是我们已经将第二种方式摸透了,并不会输出这个字符串,那么这个字符串看肯定就是在第一种注册方式当中输出的,

但是我们不知道什么情况下会触发输出这个字符串的判断机制。

找到注册算法

上面是爆破,下面我们来找注册算法,并且尝试解决我们之前的疑问。

重新运行这个程序,还是在将断点设在42FA4D然后单步运行程序,这次我们输入:

Name:111
Serial:222


我们一步一步看,好巧不巧,在函数406903处,我们的Name字符串被传入了函数,然后返回3,上一次我们输入99999返回的值是5,那么现在这个

函数的功能确定了:就是判断Name字符串的长度,如果字符串长度<4,那么对不起,弹出错误提示弹窗,我们之前推断的42A170应该是MessageBoxA

函数了。于是我们的之前的疑惑便解决了,现在安安心心找注册算法:

我们重新输入:

Name:99999
Serial:11111

然后依然下断在42FA4D然后单步运行:程序的注册算法肯定在jmp下面的某个函数当中,或者就在下面的代码


0042FA79  |>   \8D55 F0           lea edx,[local.4]
0042FA7C  |.  8B83 DC010000         mov eax,dword ptr ds:[ebx+0x1DC]
0042FA82  |.  E8 D1AFFEFF          call Acid_bur.0041AA58
0042FA87  |.  8B45 F0            mov eax,[local.4]                     ;  EAX=99999的地址
0042FA8A  |.  0FB600             movzx eax,byte ptr ds:[eax]              ;  取出第一个字节9=0x39
0042FA8D  |.  F72D 50174300         imul dword ptr ds:[0x431750]               ;  *0x29
0042FA93  |.  A3 50174300          mov dword ptr ds:[0x431750],eax            ;  eax=0x921=0x29*0x39
0042FA98  |.  A1 50174300          mov eax,dword ptr ds:[0x431750]
0042FA9D  |.  0105 50174300          add dword ptr ds:[0x431750],eax              ;  加一倍
0042FAA3  |.  8D45 FC            lea eax,[local.1]
0042FAA6  |.  BA ACFB4200          mov edx,Acid_bur.0042FBAC                 ;  CW
0042FAAB  |.  E8 583CFDFF          call Acid_bur.00403708
0042FAB0  |.  8D45 F8            lea eax,[local.2]
0042FAB3  |.  BA B8FB4200          mov edx,Acid_bur.0042FBB8                 ;  CRACKED
0042FAB8  |.  E8 4B3CFDFF          call Acid_bur.00403708
0042FABD  |.  FF75 FC            push [local.1]                      ;  Acid_bur.0042FBAC
0042FAC0  |.  68 C8FB4200          push Acid_bur.0042FBC8                  ;  -
0042FAC5  |.  8D55 E8            lea edx,[local.6]                     ;  UNICODE "-"
0042FAC8  |.  A1 50174300          mov eax,dword ptr ds:[0x431750]
0042FACD  |.  E8 466CFDFF          call Acid_bur.00406718
0042FAD2  |.  FF75 E8            push [local.6]                      ;  注册码中间部分4674
0042FAD5  |.  68 C8FB4200          push Acid_bur.0042FBC8                  ;  UNICODE "-"
0042FADA  |.  FF75 F8            push [local.2]                        ;  Acid_bur.0042FBB8
0042FADD  |.  8D45 F4            lea eax,[local.3]
0042FAE0  |.  BA 05000000          mov edx,0x5
0042FAE5  |.  E8 C23EFDFF          call Acid_bur.004039AC
0042FAEA  |.  8D55 F0            lea edx,[local.4]                     ;  edx=0012F998 = 11111
0042FAED  |.  8B83 E0010000         mov eax,dword ptr ds:[ebx+0x1E0]              ;  eax=00A85E4C
0042FAF3  |.  E8 60AFFEFF          call Acid_bur.0041AA58
0042FAF8  |.  8B55 F0            mov edx,[local.4]
0042FAFB  |.  8B45 F4            mov eax,[local.3]
0042FAFE  |.  E8 F93EFDFF          call Acid_bur.004039FC                   ;  出现CW-4674-CRACKED 字符串拼接函数
0042FB03  |.  75 1A             jnz short Acid_bur.0042FB1F               ;  这个跳转很可疑
0042FB05  |.  6A 00             push 0x0
0042FB07  |.  B9 CCFB4200          mov ecx,Acid_bur.0042FBCC                ;  Congratz !!
0042FB0C  |.  BA D8FB4200          mov edx,Acid_bur.0042FBD8                ;  Good job dude =)
0042FB11  |.  A1 480A4300          mov eax,dword ptr ds:[0x430A48]
0042FB16  |.  8B00              mov eax,dword ptr ds:[eax]
0042FB18  |.  E8 53A6FFFF          call Acid_bur.0042A170
0042FB1D  |.  EB 18             jmp short Acid_bur.0042FB37
0042FB1F  |>  6A 00             push 0x0
0042FB21  |.  B9 74FB4200          mov ecx,Acid_bur.0042FB74                ;  Try Again!
0042FB26  |.  BA 80FB4200          mov edx,Acid_bur.0042FB80                ;  Sorry , The serial is incorect !
0042FB2B  |.  A1 480A4300          mov eax,dword ptr ds:[0x430A48]
0042FB30  |.  8B00              mov eax,dword ptr ds:[eax]
0042FB32  |.  E8 39A6FFFF          call Acid_bur.0042A170

分析了一下了这段代码,我们有可以清楚的看到注册码是如何生成的:

取Name第一个字母对应的ASNI数字,比如说99999中第一个字符9对应数字0x39,然后用它乘以0x29,结果再x2,将16进制数字转为10进制的字符串便是4674,然后再在前加上”CW-”,后加上”-CRACKED”,就组成了用户名对应的注册码。


写出注册机


#include <iostream>
  
int _tmain(int argc, _TCHAR* argv[])ch
{
    printf("Input Name:\n");
    // 取第一个字符值h
    int ch = getchar();
    if ( ch > 0x21) // 只处理可见字符
    {
        ch *= 0x29; // 乘法
        ch *= 2; // 自增一倍
        printf("Serial: CW-%4d-CRACKED\n",ch);
    }
    else
    {
        printf("error!\r\n");
    }
    system("pause");
    return 0;
}


直接搜索字符串,这只是我处理这个程序的思路,当然也有其他更好的思路来处理这个程序,

看到弹窗可以下MessageBox断点,然后再一个一个排查,也可以到达程序领空
看到个老哥的方法,觉得挺不错的:直接运行程序,最后不点击确定,然后再在od里面将程序暂停,alt+k查看堆栈调用,由于有弹窗,我们肯定是可以在堆栈调用里面看到MessageBox函数调用的,然后右键查看调用,然后再在调用函数的领空查看返回的地址,我们便可以到达目标代码领空。这种方法适合于搜索不到字符串的情况。


[看雪官方]《安卓高级研修班》线下班,网课(12月)班开始同步招生!!

最后于 2020-9-16 17:11 被VEhl编辑 ,原因:
收藏
点赞2
打赏
分享
最新回复 (9)
雪    币: 220
活跃值: 活跃值 (33)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
拍手笑沙鸥 活跃值 2020-9-16 13:33
2
0
感谢分享
雪    币: 57
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
叨大喵 活跃值 2020-9-16 13:44
3
0
很基础的学习贴
雪    币: 10088
活跃值: 活跃值 (151)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Sheawzb 活跃值 2020-9-16 15:07
4
0
兄弟 求一份160个的程序合集 感谢! wangzib2@sina.com
雪    币: 3683
活跃值: 活跃值 (154)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
千音丶 活跃值 2020-9-17 15:39
5
1
加油,我只破解到80几个就没弄了,可以参考一下我的笔记http://note.youdao.com/s/3VUpAVqk
雪    币: 214
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
000lbh 活跃值 2020-10-6 21:36
6
0
笔记爆了
雪    币: 209
活跃值: 活跃值 (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
蓑衣孤客 活跃值 2020-10-8 21:11
7
0
mondayice123@163.com,非常感谢
雪    币: 209
活跃值: 活跃值 (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
蓑衣孤客 活跃值 2020-10-8 21:12
8
0
千音丶 加油,我只破解到80几个就没弄了,可以参考一下我的笔记http://note.youdao.com/s/3VUpAVqk
笔记屏蔽了
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
0xSky 活跃值 2020-10-23 16:49
9
0
skysilently@qq.com萌新求程序集合,非常感谢
雪    币: 63
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
居客 活跃值 2天前
10
0
学习了,感谢
游客
登录 | 注册 方可回帖
返回