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
非常棒~~赞!
谢谢鼓励,元旦三天在电脑前做了30多个小时,不行了,脖子疼,等考完试在刚{:5_188:} THANKS for sharing 大神,请收下我的膝盖 膜拜大神!! 支持~谢谢大神的分享~
学习一下大神
学习一下大神 谢谢楼主分享