lingyin 发表于 2019-1-1 18:43

160个crackme 之 039 算法分析

作为一个非计算机专业的学生,我最讨厌的就是期末考试的最后几周了,虽然在复习着课本,但脑子里不自觉的就转到计算机上了。好吧,我保证,这是我在1月16号寒假之前的最后一篇帖子了。{:5_187:}

今天这个crackme的算法,发费了我快一个下午的时间,中途遇见了几个不懂的汇编指令,然后就百度,分析。程序中有一个das指令,其实就是他浪费了我绝大多数的时间。最后还是通过分析大佬的一篇关于此crackme的逆向帖子,才稍微搞懂了这个程序。大佬的帖子我放在附件了,就不在这贴出来了。好,接下来看看这个craceme吧。

这个程序,加了一个APSpack的壳,通过脱壳软件就可以脱掉。



我们输入了用户名和注册码之后,Register按钮还是处于禁止状态,这说明,该程序是不断的获取我们的输入,知道输入的注册码正确才会变成激活的状态。
没有错误的字符串提示,我的思路就是,通过查找获取输入字符串的函数,去到关键的代码处。

Ctrl + N (查找当前模块中的名称(标签)),可以看到,GetDlgItemTextA函数:



回车,双击,来到它的调用处:



看到了,两个调用,那就可以肯定了,分别是获取用户名和获取注册码。
往下看,还可以看到一个EnableWindow函数,我猜,就是激活和禁止Register的函数。这个函数,之前没碰到过,所以去查了MSDN:



EnableWindow接收两个函数,hWnd:需要禁止或激活的窗口句柄。
                                           bEnable:True代表激活False代表禁止



此处的bEnable以eax的方式传递,push eax 的上方有一个call,我又猜想{:5_125:}:call处的函数是主要的算法函数,如果注册码对了,通过eax返回TRUE,否则返回FALSE。然后将eax的内容传给EnableWindow.
我的猜想对不对呢?实验一下不就知道了。进入call 004012F3:
眼睛一扫,发现大部分的数学运算指令,哼,这就是算法的核心了。我先用爆破的方式 来逆向这个小东西。

进入函数,直接给eax赋值为1,然后返回:


保存文件,打开,随便输入几个字符,可以看到Regester已经被激活了:



底下的图片也变成了CRACKED!

算法部分:

我学习逆向的时候,看大佬们的帖子,他们都是将分析的过程,以注释的方式写在od里,我呢,也跟大佬们一样,这样,以后看汇编代码的时候,也可以快速的回忆起当时的思路。


004012F3/$90            nop
004012F4      8B0D 89234000 mov   ecx, dword ptr              ;len 用户名
004012FA      85C9          test    ecx, ecx
004012FC|.74 71         je      short 0040136F                      ;长度为0 注册按钮禁用
004012FE|.49            dec   ecx                                 ;len - 1
004012FF|.8BF1          mov   esi, ecx
00401301|.BF 53234000   mov   edi, 00402353                     ;ASCII "lingyin"
00401306|.BB 4E4D4144   mov   ebx, 44414D4E                     ;tmp = 0x44414d4e
0040130B|.33D2          xor   edx, edx                            ;sum = 0
0040130D|.8BCA          mov   ecx, edx                            ;i = 0
0040130F|>33C0          /xor   eax, eax
00401311|.8A040F      |mov   al, byte ptr
00401314|.03D0          |add   edx, eax                           ;sum += name
00401316|.D1CB          |ror   ebx, 1                           ;ror tmp 1
00401318|.D3CB          |ror   ebx, cl                            ;ror tmp i
0040131A|.33DA          |xor   ebx, edx                           ;tmp = tmp ^ sum
0040131C|.3BCE          |cmp   ecx, esi                           ;是否遍历完毕
0040131E|.74 03         |je      short 00401323
00401320|.41            |inc   ecx                              ;i++
00401321|.^ EB EC         \jmp   short 0040130F
00401323|>81CB 10101010 or      ebx, 10101010                     ;tmp | 0x10101010
00401329|.87DA          xchg    edx, ebx                            ;sum 和 tmp 值的交换
0040132B|.BF 21234000   mov   edi, 00402321                     ;指向注册码
00401330|.8B0D 8D234000 mov   ecx, dword ptr
00401336|.83F9 08       cmp   ecx, 8                              ;注册码的长度 = 8
00401339|.75 34         jnz   short 0040136F
0040133B|.33C9          xor   ecx, ecx                            ;j = 0
0040133D|>33C0          /xor   eax, eax
0040133F|.C1C2 08       |rol   edx, 8                           ;edx = tmp   rol tmp 8
00401342|.8AC2          |mov   al, dl                           ;var_1 = tmp的低八位
00401344|.8AD8          |mov   bl, al                           ;var_2 = var_1
00401346|.24 0F         |and   al, 0F                           ;var_1 = var_1 & 0xf
00401348|.C0EB 04       |shr   bl, 4                              ;shr var_2 4
0040134B|.80E3 0F       |and   bl, 0F                           ;var_2 = var_2 & 0xf
0040134E|.3C 0A         |cmp   al, 0A
00401350|.1C 69         |sbb   al, 69                           ;var_1 = var_1 - 0x69 - CF
00401352|.2F            |das
00401353|.38444F 01   |cmp   byte ptr , al
00401357|.75 16         |jnz   short 0040136F
00401359|.8AC3          |mov   al, bl                           ;var_1 = var_2
0040135B|.3C 0A         |cmp   al, 0A
0040135D|.1C 69         |sbb   al, 69                           ;var_1 = var_1 - 0x69
0040135F|.2F            |das
00401360|.38044F      |cmp   byte ptr , al
00401363|.75 0A         |jnz   short 0040136F
00401365|.41            |inc   ecx
00401366|.83F9 04       |cmp   ecx, 4
00401369|.^ 75 D2         \jnz   short 0040133D
0040136B|.33C0          xor   eax, eax                            ;成功
0040136D|.40            inc   eax
0040136E|.C3            retn
0040136F|>33C0          xor   eax, eax                            ;失败
00401371\.C3            retn



das指令,我不会,百度了一下,发现还是不怎么明白{:5_187:}。
上面那段指令,var_1 和var_2 那一段,我真的是思考了很久,最后,算了,还是去Search吧。Search后,我知道了,下面那段代码是将经处理后的用户名的16进制直接转换为ascii字符的形式。。。。。。。。。。。。。

{:5_192:}

好吧,以我现在的能力,还看不懂这段代码,不管了,知道意思就好了,最后,写一个注册机:

#include<stdio.h>
#include<string.h>

//循环右移宏定义
#define ROTATE_RIGHT(x,n) (((x) >> (n)) | ((x) << (32 - (n))))


//用户名处理算法
void F_Name()
{
        unsigned long tmp = 0x44414D4E;
        char name;
        unsigned long sum = 0;
        int len;
        int i;
        printf("请输入用户名:\n");
        scanf("%s",name);
        len = strlen(name);
        for(i = 0;i < len;i++)
        {
                sum += name;
                tmp = ROTATE_RIGHT(tmp,1);
                tmp = ROTATE_RIGHT(tmp,i);
                tmp = tmp ^ sum;
        }
        tmp = tmp | 0x10101010;
        printf("%X\n",tmp);
}

int main()
{
        F_Name();
        getchar();
        return 0;
}



既然是将16进制转换为ascii的形式,再与输入的注册码进行对比,那么,我们将处理后的用户名以16进制的格式输出,得到的字符,不就是我们的注册码吗。



输入:xuepojie    注册码是:7573FA1F
但是,下面的图片还没有显示cracked,算了,不管了,反正我主要是研究算法。
唉,功力还是太低,等考完试,继续修炼。


Shark恒 发表于 2019-1-1 19:24

非常棒~~赞!

lingyin 发表于 2019-1-1 20:06

Shark恒 发表于 2019-1-1 19:24
非常棒~~赞!

谢谢鼓励,元旦三天在电脑前做了30多个小时,不行了,脖子疼,等考完试在刚{:5_188:}

turbojet 发表于 2019-3-31 16:01

THANKS for sharing

ghostxu 发表于 2022-1-15 07:00

大神,请收下我的膝盖

king51999 发表于 2022-1-15 07:16

膜拜大神!!

kalove 发表于 2022-1-15 10:10

支持~谢谢大神的分享~

毫无头绪 发表于 2022-1-15 12:14


学习一下大神

PDWORD 发表于 2022-1-15 19:06



学习一下大神

xujinwen 发表于 2022-1-16 03:00

谢谢楼主分享
页: [1] 2 3
查看完整版本: 160个crackme 之 039 算法分析