【安卓逆向】某美颜app sig参数分析

之前转载过该app的文章,今天翻版重新整理下,版本号:576O5Zu+56eA56eAYXBwIHY5MDgw (base64 解码)。

上来先抓个包:

在这里插入图片描述

jadx搜索关键词 "sigTime",然后定位到这里

在这里插入图片描述

看这行代码 cVar.addForm(INoCaptchaComponent.sig, generatorSig.sig); ,看下INoCaptchaComponent.sig 其实就是 "sig",感觉是这里大差不差。

在这里插入图片描述

sig 是由 generatorSig.sig 计算出来的,跟进去。

在这里插入图片描述

这里是定义了一个 静态 SigEntity,看下大概的功能就是做下参数拼接,底部是调用nativeGeneratorSigOld(str, bArr, str2) 方法,继续跟进去。

在这里插入图片描述

这里最终是调用了public static native SigEntity nativeGeneratorSigOld(String str, byte[][] bArr, String str2) 方法,是一个native方法,用到的so是release_sig

用ida pro 打开这个so 看看,继续跟进。

先看看导出表

在这里插入图片描述

搜索"java_",可以看到java层注册的函数名,没错是个静态注册的,而且没有什么混淆。

在这里插入图片描述

先看 Java_com_meitu_secret_SigEntity_nativeGeneratorSig 函数

在这里插入图片描述

先看下 v10 = ValidateKey::getValidateResult() 大概就是检验是否合规的key

在这里插入图片描述

进来这里调用了 JavaHelper::getAndroidAPKKeyHash 函数,看起来像是校验 apk 签名

然后再看下 GeneratorSIG 函数,看字段命名 就像是,瞎猜的。

在这里插入图片描述

刚开始掉用了一个 GetSecretKey 函数,获取 key,接着是拼接一些不明的字符串,最后调用了 MD5_Calculate 计算函数。

着重分析下这个
这个MD5_Calculate 函数 重要的是由三部分组成 MD5_InitMD5_UpdateMD5_Final

在这里插入图片描述

init 这里 全都是MD5标准的常量

在这里插入图片描述

最核心的加密都是在MD5_Update里面。

在这里插入图片描述
静态分析到此结束,开始上 frida 动态调试下。

先hook下 com.meitu.secret.SigEntity_Z13MD5_CalculatePKcjPc函数看看。

hook js 代码:

setImmediate(function () {
    if (Java.available) {
        Java.perform(function () {
            var SigEntity = Java.use("com.meitu.secret.SigEntity");

            // SigEntity.generatorSig.overload('java.lang.String', '[Ljava.lang.String;', 'java.lang.String').implementation = function (data1, data2, data3) {
            //     console.log("↓↓↓↓↓↓↓↓↓↓↓↓传递3个参数↓↓↓↓↓↓↓↓↓↓↓↓");
            //     console.log("SigEntityA-参数1:" + data1);
            //     console.log("SigEntityA-参数2:" + data2);
            //     console.log("SigEntityA-参数3:" + data2);
            //     var res1 = this.generatorSig(data1, data2, data3);
            //     console.log("SigEntityA-结果:" + res1.sig.value);
            //     console.log("↑↑↑↑↑↑↑↑↑↑↑↑传递3个参数↑↑↑↑↑↑↑↑↑↑↑↑");
            //     return res1;
            // };

            SigEntity.generatorSig.overload('java.lang.String', '[Ljava.lang.String;', 'java.lang.String', 'java.lang.Object').implementation = function (data1, data2, data3, data4) {
                console.log("↓↓↓↓↓↓↓↓↓↓↓↓传递四个参数↓↓↓↓↓↓↓↓↓↓↓↓");
                console.log("SigEntityB-参数1:" + data1);
                console.log("SigEntityB-参数2:" + data2);
                console.log("SigEntityB-参数3:" + data3);
                console.log("SigEntityB-参数4:" + data4);
                var res2 = this.generatorSig(data1, data2, data3, data4);
                console.log("SigEntityB-结果:" + res2.sig.value);
                console.log("↑↑↑↑↑↑↑↑↑↑↑↑传递四个参数↑↑↑↑↑↑↑↑↑↑↑↑");
                return res2
            };

            SigEntity.generatorSigWithFinal.implementation = function (data1, data2, data3, data4) {
                console.log('generatorSigWithFinal', data1, data2, data3, data4);
                var result = this.generatorSigWithFinal(data1, data2, data3, data4);
                console.log("generatorSigWithFinal", result.sig.value, result.sigTime.value, result.sigVersion.value);
                return result;
            };

            var MD5_Calculate = Module.findExportByName("librelease_sig.so", "_Z13MD5_CalculatePKcjPc");
            if (MD5_Calculate !== null) {
                Interceptor.attach(MD5_Calculate, {
                    onEnter: function (args) {
                        console.log("so层入参-参数:\n", args[0], args[1].toInt32(), args[2]);
                        // var byteArray = args[0].readByteArray(args[1].toInt32());
                        // console.log("so层入参-byteArray:\n", byteArray);


                        var bufferData = Memory.readByteArray(args[0], args[1].toInt32());
                        console.log("so层入参-byteArray:\n", bufferData);

                        // var hexdata = hexdump(byteArray, {
                        //     ansi: true,
                        //     length: args[1].toInt32()
                        // });
                        // console.log("打印16进制数据-hexdata:\n", hexdata);
                        this.retbuff = args[2];
                        // console.log("打印retbuff-hexdata:", this.retbuff);
                    },
                    onLeave: function (args) {
                        var ret = this.retbuff.readCString();
                        console.log("so层加密", ret);
                        // console.log("so层加密args", args);
                    }
                });
            }


        });
    }
});

打印下看看

在这里插入图片描述

MD5_Calculate 方法的入参参数2 用hexdump转换成正常的字符串,在md5加密下,是cb67c671be0f0de69cfa310007eb146c,果然和hook出来的so层加密是一样的。

在这里插入图片描述

但是会发现 so层加密 cb67c671be0f0de69cfa310007eb146cSigEntityB-结果:bc766c17ebf0d06ec9af130070be41c6 值不一样,仔细对比会发现他们是相邻的两个字符互换得来。

_Z13MD5_CalculatePKcjPc 函数的入参参数 和抓包拿到的请求参数对比,我们会发现,它其实是把get请求后面的参数,先排序,然后再拼接,在拼接的过程中各拼接了2个盐值(xxxxxx 手动马赛克),最后MD5计算出来的。

最后 最后当然是 python 算法还原了。

看看效果:

在这里插入图片描述

水文一篇,再接再续。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值