某CrackMe算法分析

平时看了一些CrackMe,算法都比较简单,这次拿到的这个算法自己觉得还是比较有难度,首先自己分析时并没有完全分析出算法的结论,后来参照答案才得到较完整的分析:

1.OD载入,F9运行,输入序列号,点击Check,弹出MessgaeBox提示错误的序列号,那么我们分别给MessageBoxA和MessageBoxW下断,重新载入OD,任意输入序列号,程序中断在调用MessgaeBoxA的地方,根据栈回溯找到调用MessgaeBox的地方为0x0040188E:

Crtl+G跟随到0x0040188E

定位到关键跳转分支:0x00401871:jnz short 0040189D

以及关键函数:0x401869 call 00401332

给这个函数下断点,可见当函数返回值为-1时,弹出失败的MessageBox

重新载入后,输入序列号,程序中断在0x00401869,F7跟进函数处理:

注意这里会判断输入的数据长度是否正确,当长度不等于43时便直接jnz到0x40157E,然后返回-1,这里为什么是43可以通过手工调试来发现,主要是指令repne scas ****在判断,

当我们输入的字符串等于43时便可以通过判断,继续向下分析:

这里是一个格式化输入,因此推断出正确的序列号格式应该为"XDSEC**-********-********-********-********"

下面的两个函数用来判断前两个字符(即%2s)是否分别在两个指定的字符串中:

设%2s为AB,函数0x00401656判断A是否在“XDSECJQLWARMZ”中,函数0x00401656判断B是否在“VYBFGHIKNOPTU”中,如果不存在跳转到0x0040157E并返回-1。

接下来的函数0x0040163A用来获取字符A在“XDSECJQLWARMZ“中的偏移,比如输入AB分别为”MH“,则函数0x0040163A返回11,然后从该偏移开始(包括偏移)将循环截取后面的字符串并写入内存地址为0x00405018的空间,比如这里会写入”MZXDSECJQLWAR“:

同样,下面也会将以B在字符串”VYBFGHIKNOPTU“中的偏移来循环截取字符串写入内存0x00405026:

接下来将会对后面4组%8s做判断:

这里面有两个函数,分别判断字符串%8s是否在前面截取的字符串中,通过调试,判断出后面四组字符串的输入格式为ABABABAB-ABABABAB-ABABABAB-ABABABAB

接下来是算法的核心部分:

这里总共有四个函数,其中前两个函数用来读取当前字符在指定字符串中的偏移(位置),后面的一个函数0040161A将会根据偏移来判断注册码是否正确,这里关键是对

mov dword ptr[esp+8],00403000的理解,这个位置貌似是一个固定的地址,里面写有一些dword,为了方便查看数据类型,我们用IDA来看看这段数据:

可以看到这段数据是一个数组,进一步分析该函数

可以看出a1是字符在“MZXDSECJQLWAR”中的偏移,a2是字符在“HIKNOPTUVYBFG”中的偏移,然后是计算出在数组00403000中的对应位置,如果是1则返回0。

可以看出00403000是一个13*13的2维数组,在计算出偏移为a1和a2后,会到该数组查询对应[a2][a1]的数据是否为1,注意这里是将a1和a2分别进行了调换。

如下例子:

                  0 1 2 3 4 5 6 7 8 9 10 11 12
                  H I K N O P T U V Y B   F   G
0 M             1 1 1 1 1 0 1 1 1 1  1   1   1
1 Z             1 1 0 0 1 1 1 0 0 0  0   1   1
2 X             0 1 1 1 1 0 1 1 1 1  1   1   1
3 D             1 1 0 0 1 1 1 1 0 1  1   1   1
4 S             1 1 0 0 1 0 1 0 0 1  1   1   1
5 E             1 1 1 1 1 1 1 0 0 1  1   0   0
6 C             1 1 1 1 1 1 1 1 1 1  1   0   0
7 J              0 1 0 1 1 1 1 0 0 0  1   1    1
8 Q             1 1 1 1 0 0 1 1 1 1  1   0    1
9  L             1 0 1 1 1 1 1 1 0 1  1   1    1
10 W           1 0 1 0 0 0 1 1 1 1  1   1    1
11 A            1 1 1 1 1 1 1 1 1 0  1   1    0
12 R            1 1 1 1 1 1 1 0 0 0  0   1    1

最后一个函数0401588用来判断当前字符位置是否由前一个字符位置移动而来。

该函数有四个参数:

参数a1,a2用来保存上一个元素的位置,a3,a4保存当前位置,每次数组元素下移一个位置,比如前面一个是MH(a[0][0]=1 a[0][0]=1),那么目前的就可以是MI(a[0][1]=1 a[1][0]=1),依次类推:XDSECMH-MHZHXHDH-SHSISKSN-ENCNCOCP-CTCUCVCY是随便猜测的一个Key。

posted @ 2013-10-07 23:06  Lamboy  阅读(324)  评论(0编辑  收藏  举报