有趣的Crackme分析分享01-snake
2022-9-3 00:0:31 Author: web安全工具库(查看原文) 阅读量:18 收藏

前言

曾经试图挑战160个cm练习,但是很快又放弃了,这次重新归来,由于很多cm很重复没啥意思,所以就挑着有趣的或者有价值的来论坛发帖跟大家分享分享(当然,也会有其他来源的cm)

对于其他的cm分析,有兴趣的童鞋可以去我的博客上逛逛

本文的cm来自新160个crackme练习中的第60个,以静态分析为主,动态分析可以看b站up主的分析视频

信息收集

运行情况:

查壳与脱壳:

调试分析

Check按钮事件

老样子,IDA打开,找到Check按钮的事件分支:

首先是获取Name和Serial,为空会提示

然后一个call验证Serial合法性,不行就弹窗提示

这个call的内容如下:判断内容要由数字和大写字母组成

再往下就是三个call和弹窗提示验证是否成功了:

验证过程--第1个Call

验证过程主要是3个call

首先是第一个call:

内容较少,简单来说就是填充数组

填充16个FF,然后填充16*16个00,然后再填充16个FF

验证过程--第2个Call

第2个Call内容多点

首先是对输入的Name进行处理,累加每一个字符,得到一个累加值,保存到dl

接下来生成CC,通过累加值dl和取出来的字节进行异或,得到数组索引,该位置是0就往该位置填充CC,计数CC的数量

累加值异或字节,然后用过的累加值再减去字节值,来使得CC随机分布,但最终取决于输入的Name

再往下就是填充DD,总共填充一个,接着用刚刚填充CC的位置计算方法进行

再往后就是填充99:

直接用计算到最后的dl作为索引进行,如果是00,就填充为99,否则就往前挪一格再次判断,最后保存99的地址

使用字符串selph生成一个地图看看:

验证过程--第3个Call

到这里已经很明显的感觉到了,16*16的地图,生成了很多CC,然后有一个DD,一个99,再加上程序名snake,这就是一个贪吃蛇啊

第一个call开辟空间,第二个call布置场地,第三个call理所应当就是开始游戏了!

首先获取当前位置和序列号,通过序列号的输入来进行移动

首先是判断输入是否是数字,是数字则直接进行移动,这里的移动是通过加减数组的索引进行的

判断方式是这样进行的:取数字的后两位:

  • 00:向下一格

  • 01:向上一格

  • 10:向左一格

  • 11:向右一格

如果数字不只是后两位有值,则执行完用前两位再次走一遍判断,比如9,就是1001,就是上左移动一格,如果输入的是大写字母的话,也是类似的,具体可见反汇编这一段的计算过程

计算完移动方向之后,该进行移动判断了:

如果下一个位置是0,或者CC,都跳转去执行,如果是99则返回0失败,如果是DD且没吃完CC,也返回0失败,如果是CC吃完了,就是返回1成功

首先看如果下一个位置是00怎么处理:

调用一个call,就是走格子用的,然后判断是否有高2位,有的话再按高2位走一遍,没有的话,获取下一个字符进入下一个循环

接下来看看这个走格子的call:

首先是获取当前格子的新位置,起始位置,把新位置写入99,把当前位置写入00

然后edi+4进行判断,edi里装的是个数组,数组成员是当前蛇的身子的位置,当长度大于1的时候,edi+4就是第二个位置,有值的时候,把刚刚写入0的位置作为新位置,把身子的位置作为当前位置,再次进行相同的操作

视觉效果就是,身子跟着头一起移动了

回到刚刚的循环里,如果移动遇到了CC则再次执行这个移动的函数,同时给count计数-1,这个count变量保存的是当前场上CC的数量

然后把这个函数清零的位置变成99,也就是让蛇身子最后一个位置本来清零了,结果又填充回99,同时把新的位置加入到身子数组里

到这里,整个程序的逻辑分析完整了,就是贪吃蛇,吃完所有CC走到DD即可验证通过

注册机

注册码生成算法:

 复制代码 隐藏代码
#include <iostream>#include <setjmp.h>using namespace std;uint8_t areas[18][16] = {0};uint8_t countCC = 0;uint8_t snake[10][2] = {0};uint8_t pos[10][2] = { 0 };void GenerateAreas(string str) {
    // 场地生成    memset(&areas[0], 0xFF, 0x10);
    memset(&areas[1], 0, 0x100);
    memset(&areas[17], 0xFF, 0x10);

    // 填充CC    uint8_t* areasBegin = (uint8_t*)&areas[1];
    uint8_t sum = 0;
    uint8_t tmp = 0;
    for (auto var : str) sum += var;
    for (auto var : str) {
        tmp = var ^ sum;
        sum -= tmp;
        *(areasBegin + tmp) = 0xCC;
        // 保存坐标        pos[countCC][0] = tmp / 16;
        pos[countCC][1] = tmp % 16;
        countCC++;
    }

    // 填充DD    sum ^= tmp;
    for (; *(areasBegin + (tmp -= sum)) == 0xCC; sum--);
    *(areasBegin + tmp) = 0xDD;
    pos[countCC][0] = tmp / 16;
    pos[countCC][1] = tmp % 16;;

    // 填充99    tmp = sum;
    for (; *(areasBegin + tmp) == 0xCC || *(areasBegin + tmp) == 0xDD; tmp--);
    *(areasBegin + tmp) = 0x99;
    snake[0][0] = tmp / 16;
    snake[0][1] = tmp % 16;
    countCC++;
}int main(){
    GenerateAreas("selph");

    // 生成注册码:长度短的情况下,不用考虑自己咬到自己    uint8_t x = snake[0][0];
    uint8_t y = snake[0][1];
    for (int i = 0; i<countCC; i++) {
        uint8_t xCC = pos[i][0];
        uint8_t yCC = pos[i][1];
        if (yCC - y >= 0) for (int i = 0; i < yCC - y; i++)cout << "3";
        else for (int i = 0; i < y - yCC; i++)cout << "2";

        if (xCC - x >= 0) for (int i = 0; i < xCC - x; i++)cout << "0";
        else for (int i = 0; i < x - xCC; i++)cout << "1";

        x = xCC;
        y = yCC;
    }
}

效果:

 复制代码 隐藏代码
selph33333333333333311222222200000031111333111111222200000000000

总结

有趣的验证方式,通过输入的用户名生成贪吃蛇地图,通过密码来进行移动,吃完豆子CC,走到终点DD算验证通过,很有趣的一次逆向体验

该内容转载自网络,更多内容请点击“阅读原文”


文章来源: http://mp.weixin.qq.com/s?__biz=MzI4MDQ5MjY1Mg==&mid=2247504200&idx=2&sn=5019364790b9713198973d0464c306cf&chksm=ebb53e4bdcc2b75d493785082933abf7624952bfbedaad922cb79662ff36ea5c37822b6a8cca#rd
如有侵权请联系:admin#unsafe.sh