Android CrackMe[2]:Base64算法逆向

这好像是之前腾讯某次安全挑战赛中的一道CrackMe。运行如下:


Android CrackMe[2]:Base64算法逆向_第1张图片
image.png

应该是根据输入的Name,来计算Code。
不多说,先拖到JEB看下。

MainActivity的相关代码如下:


Android CrackMe[2]:Base64算法逆向_第2张图片
image.png

还看到了一个native方法,很明显校验是在该函数中完成的。


image.png

再看下Check按钮的监听类,


Android CrackMe[2]:Base64算法逆向_第3张图片
image.png

可以看到,名字要在 [6,20]这个区间,且native方法 NativeCheckRegister()要返回1,才算正确。

用IDA打开so库,找到对应的jni函数,并将相关变量类型,变量名以及函数名重新命名后,如下:


Android CrackMe[2]:Base64算法逆向_第4张图片
image.png

如上图,verify这个函数会对输入的name和password进行校验,进入该函数,关键代码如下:


Android CrackMe[2]:Base64算法逆向_第5张图片
image.png

verifyPassLen和passBase64Decode这两个函数名都是我经过分析后重命名的,还有一些变量名也是如此,比如 name经过处理后的fName,password经过处理后的fPass。

如上图,从结果出发,因为要返回1才行。要进入到最后的 if 分支语句块才行。所以就有如下的等式:

   fPass[4] + fName[0] == fPass[2]
   fPass[4] + fName[0] + fName[1] == 2 * fPass[4]
   fName[2] + fPass[3] == fPass[0]
   fName[2] + fPass[3] + fName[3] == 2 * fPass[3]
   fName[4] + fPass[1] - 3 * fName[2] == 0

从而有:

fPass[0] = 2 * fName[2] + fName[3]
fPass[1] = 3 * fName[2] - fName[4]
fPass[2] = 2 * fName[0] + fName[1]
fPass[3] = fName[2] + fName[3]
fPass[4] = fName[0] + fName[1]

再结合代码,可以得出下面的解题思路:

name -> fName -> fPass -> password

这里的关键点是:如何由fPass得到输入的password。
那就需要分析一下verifyPassLen() 和 passBase64Decode() 这两个函数了。

首先进入第一个校验函数verifyPassLen:


Android CrackMe[2]:Base64算法逆向_第6张图片
image.png

可以看到,它是通过某种方式来得到一个与password的长度相关的整数值,并将这个整数值返回。这里值得注意的是获取该整数值的方式,它是通过查表的方式去遍历。看一下这个表的数据都是什么,因为这里查表的索引范围是0-255,所以只要将256个字节抽出来就好,如图:


Android CrackMe[2]:Base64算法逆向_第7张图片
image.png

结合这张表,再看一下verifyPassLen()函数中的那个循环的条件为 <= 0x3F(即十进制的63)。从这个特征就可以猜测,是不是用到了Base64算法了,因为Base64的解码算法所用到的转换表就是这样的。

再继续看一下passBase64Decode()函数:


Android CrackMe[2]:Base64算法逆向_第8张图片
image.png

显然,这就是一个Base64解码的实现函数,如果不了解Base64编码和解码的童鞋,可以参考这两个链接:

  • https://baike.baidu.com/item/base64
  • http://www.ruanyifeng.com/blog/2008/06/base64.html

因此,fPass是将输入的password经过Base64解码后得到的。换言之,输入的password其实是一个经过Base64编码后的字符串。

那么到这里,根据前面提到的解题思路,就可以写出KeyGen了,代码如下:

/*
分析:

由:
   fPass[4] + fName[0] == fPass[2]
   fPass[4] + fName[0] + fName[1] == 2 * fPass[4]
   fName[2] + fPass[3] == fPass[0]
   fName[2] + fPass[3] + fName[3] == 2 * fPass[3]
   fName[4] + fPass[1] - 3 * fName[2] == 0

可得:
    fPass[0] = 2 * fName[2] + fName[3]
    fPass[1] = 3 * fName[2] - fName[4]
    fPass[2] = 2 * fName[0] + fName[1]
    fPass[3] = fName[2] + fName[3]
    fPass[4] = fName[0] + fName[1]

解题思路: name -> fName -> fPass -> pass

*/


#include 
#include 
#include 
#include "base64.h"

typedef int _DWORD;

int main(void)
{
    char name[32] = {0}; 
    int nameLen;
    
    printf("Please input name: ");
    scanf("%s", name);  
    
    nameLen = strlen(name);
    if (nameLen < 6 || nameLen > 20) {
        fprintf(stderr, "Name too short(<6) or too long(>20)!\n");
        exit(EXIT_FAILURE);
    }

    int fName[5] = {0};
    int fPass[5] = {0};
    char s[20] = {0};
    
    int i = 0;
    char *v6;
    int v7;
    
    //1. name -> fName
    do {
        v6 = &s[i];
        v7 = name[i % nameLen] * (i + 20160126) * nameLen;
        ++i;
        *(_DWORD *)v6 += v7;
        // printf("s[%d]=%d\n", i, s[i]);
    } while (i != 16);
    
    int j = 0;
    do {
        fName[j] = *(_DWORD*)&s[j * 4] / 10;
        ++j;
    } while (j != 5);
    
    //2. fName -> fPass
    fPass[0] = 2 * fName[2] + fName[3];
    fPass[1] = 3 * fName[2] - fName[4];
    fPass[2] = 2 * fName[0] + fName[1];
    fPass[3] = fName[2] + fName[3];
    fPass[4] = fName[0] + fName[1];
    
    //3. fPass -> pass
    char pass[128] = {0};
    base64_encode((char*)fPass, pass, 20);
    
    printf("pass=%s\n", pass);
    
}

测试如下:


image.png
Android CrackMe[2]:Base64算法逆向_第9张图片
image.png

相关文件下载:
链接:https://pan.baidu.com/s/1VYP4o20Uibq3nOCBvhIZSQ 密码:sv7i

你可能感兴趣的:(Android CrackMe[2]:Base64算法逆向)