Android逆向学习笔记---逆向腾讯2016游戏安全挑战赛Tencent2016A.apk

首先,用jeb将apk逆向,发现程序是通过NativeCheckRegister(String arg1)函数来判断输入
JEB逆向
进一步看这个函数:
native定义:

调用本地native 函数,而这类函数一般存在apk的lib目录里面的.so文件当中。
使用IDA6.6 导出so文件找到NativeCheckRegister(String arg1)函数

这里写图片描述
看方框里面的sub_1634()函数
这里写图片描述
这个程序的功能是根据传入的Name字符串,然后生成一个Code,与输入的code 对比。
这里写图片描述
首先 ,分析上面一段算法。转换成Java代码:

for (; i < 16; i++, j = i % name.length) {
     nameCrypt[i] = ((name[j] * (20160126 + i) * name.length) + tmp) & 0x0ff;
     tmp = (((name[j] * (20160126 + i) * name.length) + tmp) >> 8) & 0x0ffffffff;
}
这里主要功能是把输入的name进行一个加密转换;

这里有几点值得注意的v11 是char类型,占用1个字节,所以后面要和 0x0ff相与 保留后两个字节,v6强制类型转换成dword类型,占用8个字节,因此结果和0x0ffffffff相与。
再看这个:
这里写图片描述

for (i = 0; i < 5; i++) {
            nameCrypt2[i] = nameCrypt[i * 4 + 3];
            nameCrypt2[i] = nameCrypt2[i] << 8 | nameCrypt[i * 4 + 2];
            nameCrypt2[i] = nameCrypt2[i] << 8 | nameCrypt[i * 4 + 1];
            nameCrypt2[i] = nameCrypt2[i] << 8 | nameCrypt[i * 4];
            nameCrypt2[i] = nameCrypt2[i] / 10;
}
进一步对转换过的nameCrypt转换(有点绕)

同道理也是字节位运算,V10是int类型,V15转换成dword类型,所以先算出来的字节往左移8位作高位字节,后八位作低位。

然后这边是sub_1498()函数,这个函数主要将输入的Code字符串Code进行验证:

这里写图片描述
这里写图片描述
根据上面的伪代码,用java代码表示:

public String getCode() {
        StringBuilder str = new StringBuilder();

        codeCrypt[3] = nameCrypt2[2] + nameCrypt2[3];
        codeCrypt[0] = codeCrypt[3] + nameCrypt2[2];

        codeCrypt[1] = 3 * nameCrypt2[2] - nameCrypt2[4];

        codeCrypt[4] = nameCrypt2[0] + nameCrypt2[1];
        codeCrypt[2] = codeCrypt[4] + nameCrypt2[0];


        for (int i = 0; i < 5; i++) {
            codeCrypt2[i * 4    ] = (byte) (codeCrypt[i] & 0x0ff);
            codeCrypt2[i * 4 + 1] = (byte) ((codeCrypt[i] >> 8) & 0x0ff);
            codeCrypt2[i * 4 + 2] = (byte) ((codeCrypt[i] >> 16) & 0x0ff);
            codeCrypt2[i * 4 + 3] = (byte) ((codeCrypt[i] >> 24) & 0x0ff);
        }

        for (int i = 0; i <= 6; i++) {
            byte tmp = 0;

            if (i == 6) {
                tmp = (byte) ((codeCrypt2[i * 3] & 0x0ff) >> 2);
                str.append((char) lookupTableRev(tmp));
                tmp = (byte) (((codeCrypt2[i * 3] & 0x03) << 4) | ((codeCrypt2[i * 3 + 1] >> 4)) & 0x0f);
                str.append((char) lookupTableRev(tmp));
                tmp = (byte) (((codeCrypt2[i * 3 + 1] & 0xf) << 2) | ((codeCrypt2[i * 3 + 2] & 0x0ff) >> 6));
                str.append((char) lookupTableRev(tmp));
            } else {
                tmp = (byte) ((codeCrypt2[i * 3] & 0x0ff) >> 2);
                str.append((char) lookupTableRev(tmp));
                tmp = (byte) (((codeCrypt2[i * 3] & 0x03) << 4) | ((codeCrypt2[i * 3 + 1] >> 4)) & 0x0f);
                str.append((char) lookupTableRev(tmp));
                tmp = (byte) (((codeCrypt2[i * 3 + 1] & 0xf) << 2) | ((codeCrypt2[i * 3 + 2] & 0x0ff) >> 6));
                str.append((char) lookupTableRev(tmp));
                tmp = (byte) (codeCrypt2[i * 3 + 2] & 0x3f);
                str.append((char) lookupTableRev(tmp));
            }
        }
        return str.toString();
    }

这里写图片描述

上面的a456789[] 在汇编下是这么一个字符串,

这里写图片描述
转换成java代码:

private int lookupTableRev(byte content) {
        for (int i = 0; i < 256; i++) {
            if (table[i] == content) {
                return i;
            } else {
                continue;
            }
        }
        return -1;
    }
查表,使经过转换的code根据其在表中的位置得到0xff内的可见字符。

结果有:
这里写图片描述

总结一下代码的验证流程:

用户输入的name和code;
首先对输入的name进行一系列加密处理,然后根据加密后的nameCrypt,生成codeCrypt加密后的code,最后根据表得到相应字符串值,然后输出比较。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值