狗狗音乐登陆协议加密参数逆向分析

android 逆向 31 / 38

前言

样本下载:https://www.wandoujia.com/apps/34221
版本:11.0.4
账号密码登陆接口

charles

请求体里的 pk、t1、t2、t3、key、params 等参数

请求参数里的 signature 签名

java 层分析

通过全局搜索关键词定位到这里 com.kugou.common.useraccount.b.u,下面来一个个分析

data key 参数

key = v8 = com.kugou.common.useraccount.utils.a.a 函数

这里是生成一个 aes key

data pk 参数

pk = h.a(v5.toString(), c.a().b(com.kugou.common.config.a.lq))

v5 是个 json

c.a().b() 函数看不出来是啥,稍后 frida hook 一下

h.a 函数也比较简单,看不出来啥,继续往下

v1.a(arg5) 初始化 rsa 加密对象

再往下是 rsa/ecb/nopadding 加密算法

最后有个简单的数据处理逻辑

data params 参数

params = com.kugou.common.useraccount.utils.a.b()

v9json, v8aes key

先看里面的两个 a.a 函数逻辑

是个 md5 加密,是对 aes key 进行加密

回过头再往下继续分析,是个 aes 加密逻辑

signature 加密后面再分析。先来看看 t1 t2 参数

data t1, t2 参数

t1, t2 = v9_1, v4 点进去分析一下

跟进来调用的是这两个 native 函数

data t3, dfid 参数

这两个参数貌似可以写死

url params signature 参数

这里是一些字符串拼接

最后是 md5 加密

frida hook

function getMapData(mapSet) {
    try {
        var result = {};
        var key_set = mapSet.keySet();
        var it = key_set.iterator();
        while (it.hasNext()) {
            var key_str = it.next().toString();
            result[key_str] = mapSet.get(key_str).toString();
        }
        return result
    } catch (error) {
        return mapSet
    }
}

function getProcessId() {
    var androidProcess = Java.use('android.os.Process');
    return 'processId: ' + androidProcess.myTid() + ' - ';
}

function printLog() {
    var result = '';

    for (var i = 0; i < arguments.length; i++) {
        result += arguments[i] + ' ';
    }

    console.log(getProcessId(), result)
}

function hook() {
    var NativeParams = Java.use('com.kugou.common.player.kugouplayer.NativeParams');

    NativeParams.getToken.implementation = function (a) {
        printLog('NativeParams.getToken.a: ', a);

        var res = this.getToken(a);
        printLog('NativeParams.getToken.res: ', res);

        return res;
    }

    NativeParams.getMachineIdCode.implementation = function (a) {
        printLog('NativeParams.getMachineIdCode.a: ', a);

        var res = this.getMachineIdCode(a);
        printLog('NativeParams.getMachineIdCode.res: ', res);

        return res;
    }

    // hook aes
    var aCls = Java.use('com.kugou.common.useraccount.utils.a');

    aCls.a.overload('java.lang.String', 'java.lang.String', 'java.lang.String', 'java.lang.String').implementation = function (a, b, c, d) {
        printLog('aes.aCls.a.a: ', a);
        printLog('aes.aCls.a.b: ', b);
        printLog('aes.aCls.a.c: ', c);
        printLog('aes.aCls.a.d: ', d);

        var res = this.a(a, b, c, d);
        printLog('aes.aCls.a.res: ', res);

        return res;
    }

    // hook rsa
    var hCls = Java.use('com.kugou.common.useraccount.utils.h');

    hCls.a.overload('java.lang.String', 'java.lang.String').implementation = function (a, b) {
        printLog('rsa.hCls.a.a: ', a);
        printLog('rsa.hCls.a.b: ', b);

        var res = this.a(a, b);
        printLog('rsa.hCls.a.res: ', res);

        return res;
    }

    // hook sig
    var wCls = Java.use('com.kugou.common.network.w');

    wCls.a.overload('java.lang.String', 'java.util.Map', 'java.lang.String').implementation = function (a, b, c) {
        printLog('sig.wCls.a.a: ', a);
        printLog('sig.wCls.a.b: ', JSON.stringify(getMapData(b)));
        printLog('sig.wCls.a.c: ', c);

        var res = this.a(a, b, c);
        printLog('sig.wCls.a.res: ', res);

        return res;
    }
}

function main() {
    Java.perform(function () {
        hook();
    })
}

setImmediate(main);

// frida -UF -l hook.js
// jnitrace -l libj.so com.kugou.android | tee kugouyinyue.log

运行脚本,可以 hook 出一些关键的输入输出。结果博主都是验证过的,全部没问题

so 文件查找

前面的两个 native 函数,静态分析没找到在那个 so 里,咱们使用 frida native trace 一下
使用 yang 神的脚本:https://github.com/lasting-yang/frida_hook_libart

trace 结果保存到文件里,全局搜索一下,在 libj.so 文件里,后面就可以使用 unidbg 跑起来,过程也是十分的顺畅没啥难点

暂无评论
本文作者:
本文链接: https://www.qinless.com/?p=1436
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 qinless 的博客!
100

发表评论

返回顶部