• 某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。

  • 相关阅读:
    Spring boot MultipartResolver
    shell 脚本中的当前工作目录等于执行脚本时所在的工作目录
    IDEA Exception in thread "main" java.lang.ClassNotFoundException: com.streamax.servicecore.business.FileManageServApplication
    java学习路线图-----java基础学习路线图(J2SE学习路线图)
    Java基本语法-----java数组(一维数组二维数组)
    Java基本语法-----java二维数组
    Java基本语法-----java函数
    程序员的自我修养-----Java开发的必须知道的几个注意点
    JAVA面向对象-----java面向对象的六大原则
    Java集合-----java集合框架常见问题
  • 原文地址:https://www.cnblogs.com/Lamboy/p/3356316.html
Copyright © 2020-2023  润新知