js逆向实战-酷我榜单Secret逆向及歌曲下载


声明

本文章中所有内容仅供学习交流使用,不用于其他任何目的,严禁用于商业用途和非法用途,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请联系作者立即删除!

前言

年底了,最近工作比较忙,可能没多少时间写博客。今天就来一个简单的吧,目的还是多练习。

目标

地址:https://www.kuwo.cn/rankList
下载酷我某个榜单的歌曲
榜单搜索url
http://www.kuwo.cn/api/www/bang/bang/musicList?bangId=93&pn=1&rn=20&httpsStatus=1&reqId=170c7780-4af5-11ee-bbce-3768c1e6ad77&plat=web_www&from=
bangId: 93 榜单id
pn: 1 页码
rn: 20 行数

思路

1.观察请求,目前观察到的可能需要逆向的东西有三个
在这里插入图片描述
在这里插入图片描述

一个是请求里的reqId
一个是request headers里的Secret
一个是cookie

2.先完全回放模拟一下请求,查看是否能正常获取数据
3.如果第一步可以,那么去掉关键参数,查看请求是否能通过
如果不能通过说明该参数就是逆向的关键

步骤

1.经测试发现,cookie和Secret必不可少
cookie中最重要的是
Hm_Iuvt_cdb524f42f0cer9b268e4v7y734w5esq24=xxxx
2. 这个cookie的值只是简单的通过response header的set-cookie传递的 所以直接用requests.session就可以保留了
下面跟栈查看Secret的值如何生成
先搜索一下Secret
在这里插入图片描述
很简单就看到了其来自h(l,f)函数,其中f是固定值,而l = Object(d.c)(f)
跟踪可以发现其实就是v()函数
在这里插入图片描述

由此可以看出 l 的值其实就是cookie中“Hm_Iuvt_cdb524f42f0cer9b268e4v7y734w5esq24”键对应的值 进行了unescape
那其实我们直接给传过来值就可以了
主要生成逻辑还是h函数
逻辑很简单但是也没必要用py再去实现一边,直接把h函数拷出来即可

function h(t, e) {
    if (null == e || e.length <= 0)
        return console.log("Please enter a password with which to encrypt the message."),
            null;
    for (var n = "", i = 0; i < e.length; i++)
        n += e.charCodeAt(i).toString();
    var r = Math.floor(n.length / 5)
        , o = parseInt(n.charAt(r) + n.charAt(2 * r) + n.charAt(3 * r) + n.charAt(4 * r) + n.charAt(5 * r))
        , l = Math.ceil(e.length / 2)
        , c = Math.pow(2, 31) - 1;
    if (o < 2)
        return console.log("Algorithm cannot find a suitable hash. Please choose a different password. \nPossible considerations are to choose a more complex or longer password."),
            null;
    var d = Math.round(1e9 * Math.random()) % 1e8;
    for (n += d; n.length > 10; )
        n = (parseInt(n.substring(0, 10)) + parseInt(n.substring(10, n.length))).toString();
    n = (o * n + l) % c;
    var h = ""
        , f = "";
    for (i = 0; i < t.length; i++)
        f += (h = parseInt(t.charCodeAt(i) ^ Math.floor(n / c * 255))) < 16 ? "0" + h.toString(16) : h.toString(16),
            n = (o * n + l) % c;
    for (d = d.toString(16); d.length < 8; )
        d = "0" + d;
    return f += d
}


function getSecret(l){
    l = unescape(l)
    se = h(l,f)
    return se
}

}
再去python中用execjs模块执行即可

import subprocess
subprocess.Popen = partial(subprocess.Popen, encoding='utf-8')
import execjs

def get_secret(s):
    with open('getSe.js','r',encoding='utf-8') as jj:
        js_str = jj.read()

    js_exe = execjs.compile(js_str)
    return js_exe.call('getSecret',s)

其实到此为止 逆向出这个Secret值接口就能请求成功了
如下请求了一下获取榜单的接口
在这里插入图片描述

3.逆向一下reqId
直接搜一下reqId

在这里插入图片描述
可以看到它有两个地方
在这里插入图片描述
在这里插入图片描述
这里的reqId的值分别等于r和n,但是这里的r和n的逻辑都指向下面这个逻辑
c()()
往上翻代码可以看到
在这里插入图片描述
也就是说

l = n(109)
c = n.n(l)
reqId = c()()

所以这里的关键参数就是l,l是n(109)生成的,这里的n就是webpack整出来的
查看这个js文件的开头
在这里插入图片描述

并没有看到分发器,这明显是多文件webpack打包了
那么我们在l=n(109)这里打断点跟踪一下
在这里插入图片描述
这样就跟踪到分发器了。

开始抠代码
先把这个分发器抠下来,其他的都不要
因为函数里用到了t,给定义一个空的t

var t = {};
function d(n) {
        if (t[n])
            return t[n].exports;
        var r = t[n] = {
            i: n,
            l: !1,
            exports: {}
        };
        return e[n].call(r.exports, r, r.exports, d),
        r.l = !0,
        r.exports
    }

给他搞成webpack单文件的形式
!function(e){分发器}([函数列表或者大对象])

!function (e) {
    var t = {};
    function d(n) {
        if (t[n])
            return t[n].exports;
        var r = t[n] = {
            i: n,
            l: !1,
            exports: {}
        };
        return e[n].call(r.exports, r, r.exports, d),
            r.l = !0,
            r.exports
    }
}([])

下面就是看用到什么函数就补什么函数到函数列表里了
显示l=n(109),那么先把109拷过来
**注意:**这里最好是在模块分发器里找 109 对应的代码像下图这样,如果将断点打在 l 的位置单步进去可能会出现偏差
单步跟踪执行到分发器的return位置,然后控制台输入e[109]回车,再点击函数跳转到具体的位置
在这里插入图片描述
在这里插入图片描述
因为我们不打算把整个函数列表都拷过去,所以不可能根据索引去寻找了,因此我们将109当成key,具体函数作为值,组成对象,当作分发器的入参
可以看到109里边还用到了204,205,重复刚才的操作把这两个也加进去
在这里插入图片描述
这个时候就得到了所有用到的代码,接下来就是需要在外部得到这个模块分发器运行起来的结果
为啥需要这么做?
完成上面的操作后,我们得到的是一个自执行的函数,也就是说我们一运行代码他就会自动执行了。
函数执行结束我们要的方法的列表的就没了,所以就需要把这个函数列表导出到一个全局变量里,然后在这个全局变量里面调用对应的方法完成reqId的生成
所以我们在外面定义一个全局变量 var abc;
在自执行的方法里把d方法赋值给abc
在这里插入图片描述
最后按照网站上的调用逻辑调用下就可以了
在这里插入图片描述
获取reqId的完整代码

var abc;
!function (e) {
    var t = {};
    function d(n) {
        if (t[n])
            return t[n].exports;
        var r = t[n] = {
            i: n,
            l: !1,
            exports: {}
        };
        return e[n].call(r.exports, r, r.exports, d),
            r.l = !0,
            r.exports
    }
    abc = d;
}({
    "109":function(t, e, n) {
        var r, o, l = n("204"), c = n("205"), d = 0, h = 0;
        t.exports = function(t, e, n) {
            var i = e && n || 0
                , b = e || []
                , f = (t = t || {}).node || r
                , v = void 0 !== t.clockseq ? t.clockseq : o;
            if (null == f || null == v) {
                var m = l();
                null == f && (f = r = [1 | m[0], m[1], m[2], m[3], m[4], m[5]]),
                null == v && (v = o = 16383 & (m[6] << 8 | m[7]))
            }
            var y = void 0 !== t.msecs ? t.msecs : (new Date).getTime()
                , w = void 0 !== t.nsecs ? t.nsecs : h + 1
                , dt = y - d + (w - h) / 1e4;
            if (dt < 0 && void 0 === t.clockseq && (v = v + 1 & 16383),
            (dt < 0 || y > d) && void 0 === t.nsecs && (w = 0),
            w >= 1e4)
                throw new Error("uuid.v1(): Can't create more than 10M uuids/sec");
            d = y,
                h = w,
                o = v;
            var x = (1e4 * (268435455 & (y += 122192928e5)) + w) % 4294967296;
            b[i++] = x >>> 24 & 255,
                b[i++] = x >>> 16 & 255,
                b[i++] = x >>> 8 & 255,
                b[i++] = 255 & x;
            var _ = y / 4294967296 * 1e4 & 268435455;
            b[i++] = _ >>> 8 & 255,
                b[i++] = 255 & _,
                b[i++] = _ >>> 24 & 15 | 16,
                b[i++] = _ >>> 16 & 255,
                b[i++] = v >>> 8 | 128,
                b[i++] = 255 & v;
            for (var A = 0; A < 6; ++A)
                b[i + A] = f[A];
            return e || c(b)
        }
    },
    "204":function(t, e) {
        var n = "undefined" != typeof crypto && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || "undefined" != typeof msCrypto && "function" == typeof window.msCrypto.getRandomValues && msCrypto.getRandomValues.bind(msCrypto);
        if (n) {
            var r = new Uint8Array(16);
            t.exports = function() {
                return n(r),
                    r
            }
        } else {
            var o = new Array(16);
            t.exports = function() {
                for (var t, i = 0; i < 16; i++)
                    0 == (3 & i) && (t = 4294967296 * Math.random()),
                        o[i] = t >>> ((3 & i) << 3) & 255;
                return o
            }
        }
    }
    , "205":function(t, e) {
        for (var n = [], i = 0; i < 256; ++i)
            n[i] = (i + 256).toString(16).substr(1);
        t.exports = function(t, e) {
            var i = e || 0
                , r = n;
            return [r[t[i++]], r[t[i++]], r[t[i++]], r[t[i++]], "-", r[t[i++]], r[t[i++]], "-", r[t[i++]], r[t[i++]], "-", r[t[i++]], r[t[i++]], "-", r[t[i++]], r[t[i++]], r[t[i++]], r[t[i++]], r[t[i++]], r[t[i++]]].join("")
        }
    }
})

function getReqId(){
    l = abc("109");
    reqId = l();
    return reqId;
}

console.log(getReqId())

下载某个排行榜中的免费歌曲

查看榜单接口返回的内容
在这里插入图片描述
当isListenFee是false时,说明这个歌曲可以免费听,也就是说我们可以正常下载。
然后我们把isListenFee是false的歌曲的name和rid都取出来
然后请求链接

https://www.kuwo.cn/api/v1/www/music/playUrl?mid=7214806&type=music&httpsStatus=1&reqId=31b07911-9901-11ee-82f6-fbf623c68861&plat=web_www&from=

把链接中的mid=xxxx换成我们解析出来的rid的值
发送请求后,拿到返回的url
在这里插入图片描述

再请求这个url即可下载歌曲
这里就不贴代码了,都是很简单的请求,大家可以自己尝试。

总结

总体来说,酷我榜单下载歌曲还是比较简单的,适合初学者来练手。

  • 14
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值