栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

豆瓣app参数sig分析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

豆瓣app参数sig分析

今天我们要分析的app 是豆瓣, 版本号7.18.0,下载链接小伙伴们可以去各大应用商定自行下载。怕自己忘,赶紧记录下分析流程,是作为一个逆向分析的很好案例。
参考链接:

  1. https://blog.csdn.net/weixin_43582101/article/details/121670287
  2. https://blog.csdn.net/qq_23594799/article/details/108446352
1.抓包找参数

如上图所示,通过charles抓包,找接口,然后找到我们最终要研究的参数 _sig,
其他接口比如udid 猜测是用户uid是固定值,apikey ,device_id和apple应该代表的就是当前设备参数信息,直接固定就能用(ps:没有大批量测试,只是猜测,不是研究的重点,请忽略。)

2.反编译apk

找到加密参数_sig,接下来就是反编译apk,看看里面的加密逻辑到底是咋写的,这时候拿出我们的大宝贝jadx,有不会的同学可自行百度下如何使用。然后把豆瓣app拖进到jadx中,一会就会反编译好。

在这里我们直接搜索 “_sig” 关键字,还好 还好,找到的相似代码不是很多,来我们一个一个的看 ,这里觉得 builder.add("_sig", (String) a2.first);很可疑,点进去看看。

跳转进去以后,可以看到 "_sig"参数 是 a2.first 的方法返回来的,具体是干嘛目前不知道,不过不要紧,继续跟进发现 a2 是Pair a2 = ApiSignatureHelper.a(request);这个方法声明实例化的一个对象(ps:java学的不好,表述可能不准)。然后点进去看看ApiSignatureHelper这个类具体是咋实现的。

然后就来到这里了,可以看到ApiSignatureHelper类的下面的a方法,就是我们今天要搞的加密地方。

整个加密代码如下,然后我们先静态分析一下java代码,一会再用frida动态分析一波验证下我们的猜想。

3.分析加密逻辑

首先看到a方法传入三个参数str,str2 和 str3,然后定义一个变量decode 具体干嘛的不知道, 之后定义一个str4,这是一个AES加密的秘钥key(很重要,后来才知道的),然后用StringBuilder类创建一个sb对象 ,你可以理解为用python 定义一个字符串 对象,再然后 定义一个encodedPath 这个东西就是请求url的path(后来动态分析以后才知道的),同时还把url路径path 给url 编码了,然后又拼接了一个StringPool.AMPERSAND 这是啥东西 点进去看看


发现是一个&符号,最后是拼接一个10位时间戳currentTimeMillis,最后把拼接好的字符串sb,最后调用HMACHash1.a()该方法,并把str4和sb作为参数传进去,最后得到加密的结果。那好,我们再点进去看看HMACHash1.a()方法是咋写的,继续往下走。

public class ApiSignatureHelper {
    static Pair a(Request request) {
        if (request == null) {
            return null;
        }
        String header = request.header(com.douban.push.internal.api.Request.HEADER_AUTHORIZATION);
        if (!TextUtils.isEmpty(header)) {
            header = header.substring(7);
        }
        return a(request.url().toString(), request.method(), header);
    }

    public static Pair a(String str, String str2, String str3) {
        String decode;
        if (TextUtils.isEmpty(str)) {
            return null;
        }
        String str4 = FrodoApi.a().e.b;
        if (TextUtils.isEmpty(str4)) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        sb.append(str2);
        String encodedPath = HttpUrl.parse(str).encodedPath();
        if (encodedPath == null || (decode = Uri.decode(encodedPath)) == null) {
            return null;
        }
        if (decode.endsWith("/")) {
            decode = decode.substring(0, decode.length() - 1);
        }
        sb.append(StringPool.AMPERSAND);
        sb.append(Uri.encode(decode));
        if (!TextUtils.isEmpty(str3)) {
            sb.append(StringPool.AMPERSAND);
            sb.append(str3);
        }
        long currentTimeMillis = System.currentTimeMillis() / 1000;
        sb.append(StringPool.AMPERSAND);
        sb.append(currentTimeMillis);
        return new Pair<>(HMACHash1.a(str4, sb.toString()), String.valueOf(currentTimeMillis));
    }
}

然后我们就来到了这里,根据关键词 HMACHash1 和base64
,可以大胆的猜测下这是hmac和base64加密算法,恭喜你猜对了。要是对hmac不熟悉的看看这篇文章:https://www.liaoxuefeng.com/wiki/1016959663602400/1183198304823296

public class HMACHash1 {
    public static final String a(String str, String str2) {
        try {
            SecretKeySpec secretKeySpec = new SecretKeySpec(str.getBytes(), LiveHelper.HMAC_SHA1);
            Mac instance = Mac.getInstance(LiveHelper.HMAC_SHA1);
            instance.init(secretKeySpec);
            return base64.encodeToString(instance.doFinal(str2.getBytes()), 2);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

静态分析的差不多了,接下来用我们的frida动态调试一下,看看实际的效果是什么样子的。

4.frida调试一下:

首先启动frida服务,把js注入到进程里面 执行一下命令:

frida -U com.douban.frodo -l hook_douban.js
Java.perform(
    function(){
            var apisig = Java.use("com.douban.frodo.network.ApiSignatureHelper");

            apisig.a.overload('java.lang.String', 'java.lang.String', 'java.lang.String').implementation = function (a1,a2, a3){
                console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓豆瓣hook--sig 开始↓↓↓↓↓↓↓↓↓↓↓↓↓");
                console.log("apisig传入参数1:", a1);
                console.log("apisig传入参数2:", a3);
                console.log("apisig传入参数3:", a3);
                var sig_res = apisig.a(a1, a2, a3)
                console.log("apisig加密result:" + sig_res);
                console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑豆瓣hook--sig 结束↑↑↑↑↑↑↑↑↑↑↑↑↑");
                return sig_res;
            }

            apisig.a.overload('okhttp3.Request').implementation = function (a0){
                console.log("apisig传入参数0:", a0);
                var sig_res1 = apisig.a(a0)
                console.log("apisig重载加密result:" + sig_res1);
                return sig_res1;
            }

            var HMACHash1 = Java.use("com.douban.frodo.utils.crypto.HMACHash1");
            HMACHash1.a.overload('java.lang.String', 'java.lang.String').implementation = function (a1,a2) {
                console.log("HMACHash1传入参数1:", a1);
                console.log("HMACHash1传入参数2:", a2);
                var res = HMACHash1.a(a1,a2);
                console.log("HMACHash加密result:" + res);
                return res;
            }

    }
)

动态运行的效果如下:

详细分析的已经差不多了,总结下就是把get请求+请求url的path+时间戳作为sb和str4作为hmac加密的参数,计算出来一个值,再然后base64加密一下,就得到最终加密参数_sig。
最后 用python还原一波,看看拿到的数据。

具体代码就不公布了,有兴趣的可以自己尝试分析一下。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/671240.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号