目 录CONTENT

文章目录

JS逆向案例001:返回参数解密

克林空间
2024-02-03 / 0 评论 / 0 点赞 / 105 阅读 / 0 字 / 正在检测是否收录...
温馨提示:
本文最后更新于2024-02-03,若内容或图片失效,请留言反馈。 部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

📌免责声明:本文章涉及到的代码仅供学习交流使用,不得用于任何商业用途,数据来源于互联网公开内容,没有获取任何私有和非公开权限的信息(个人信息等)。由此引发的任何法律纠纷与本人无关。禁止将本文技术或者本文所关联的Github项目源码用于任何除学习外的目的。

以影视综Rank为例,学习返回参数解密的方法,分析如何提取某乐指数网站数据。

分析页面

打开页面后有剧集榜、电影榜、综艺榜三个页签,每个面签的加密逻辑相同,这里使用剧集榜做为样例。
打开开发者工具,刷新页面,可以在Fetch/XHR里看到如图请求。

lrj4o

这个请求的头部和载荷里分别有uuid和sign两个参数需要模拟。

uc4yd
ia9b3
查看响应数据,可以发现返回的是经过加密后的密文。
p7ley

剧集榜参数特性:
r3vs9
电影榜参数特征:
w328k
综艺榜参数特征:
f0xoo
由此可以看出,“影视综Rank”里,三个页签接口分别对应“无参数”、“movielist”和“varietylist”,并且都设置了相对固定的sign值,理论上可以直接使用,不用进一步分析sign值生成JS。不过出于兴趣,还是看看这个是怎么生成的,:P
5i3vh

解密

Sign生成

通过搜索,初步定位到上图t.sign是参数生成的地方,在控制台中确认后,确定目标就是_t.getSign(t).toString()
8uwor
其中t就是channel参数。
g6ih3
看加密后的结果是长度32的16进制字符串,符合MD5特征,但是用标准MD5算法测试相同的参数,发现生成的字符并不一样。所以这里的算法或者输入参数并不是简单的处理,需要进一步分析JS实现。
xo5wo
通过查看代码,发现参数传入后,进行了字符串拼接,导致实际进行MD5计算的参数并不一样。可以看出实际加密的字符串是“channel_movielist_iIndex”这三个字符串的拼接。这里对Vie()方法测试后,是标准的MD5分组加密结果,调用toString()方法后,得到的值和标准MD5算法一致。所以这里用的就是标准MD5算法。
到此,便可以将网页中的JS代码复制过来,在本地封装成JS脚本自己生成sing参数了。JS 代码如下:

const CryptoJS = require("crypto-js")  
  
function getSign(e) {  
    delete e.sign;  
    for (var t = [], n = Object.keys(e).sort(), r = 0; r < n.length; r++) {  
        var i = n[r]  
            , a = e[i];  
        t.push(i),  
            t.push(a)  
    }    t.push("iIndex");  
    var s = t.join("_")  
        , c = CryptoJS.MD5(s);  
    return c  
}

调用的Python代码如下:

import execjs  
  
  
def get_sign(channel):  
    with open("Sign.js", "r", encoding="utf-8") as f:  
        js_file = f.read()  
    js = execjs.compile(js_file)  
    return js.call('getSign', channel)  
  
  
if __name__ == '__main__':  
    channel = {  
        "channel": "movielist"  
    }  
    print(get_sign(channel))

输出结果为5f3cce6a40c09a221b21104cc98436a3,与之前抓包的结果一致。

返回值解密

对于返回值加密的搜索方法:

  1. 搜索json.parse(关键字
  2. 搜索decrypt关键字
  3. 搜索拦截器
  4. 下断点到类似.then的回调方法
    这里先使用搜索json.parse,搜索结果很多,需要缩小范围。
    qopqw
    查看启动器寻找线索,但并没有能“望文知义”的地方,只能确定调用的内容都在index.28827ebe.js文件中,那么搜索结果里可以先把其它文件放在一边,从这个文件入手。
    ww8lv
    对28827文件里的搜索结果中,可能性大的地方进行断点确认后,初步确定了下图两个位置入口。
    可能位置1:经过查看输入和输出,发现并没有解密活动,所以不是该位置。
    tfd08
    可能位置2:查看输入和输出,由密文转换成了明文,所以该方法是目标位置。
    i0oqb

这里也可以使用拦截器的方法进行定位。搜索拦截器关键字interceptors,找到28827文件相关的位置,查看有关response的条目。
gku9g
然后在该文件中搜索interceptors.response关键字,发现有3位可疑位置,分别打上断点,刷新页面后,在每个断点查看对应的输入输出参数,定位到如下位置有解密功能,于是确定这里为解密方法。
v0h9d
现在开始分析_t.dataFilter(e.data)代码,明确解密算法。跳转到该方法实现位置,发现就是之前搜索到的“可能位置2“。
根据方法和参数信息,可以初步判断Zie是对称加密算法,因为它有iv参数。
而加密算法里有CryptoJS.enc.Utf8同时有parse()stringify()方法,代入验证后确认,那么Zie就是CryptoJS.AES。根据这些分析,可以将这部分代码在本地改写为:


var CryptoJS = require('crypto-js')  
  
//encrypt_data为响应中的加密数据,lastFetchTime是响应中返回的时间戳  
function get_decrypt_data(encrypt_data, lastFetchTime) {  
  var i = CryptoJS.enc.Utf8.parse(lastFetchTime + "000")  
    , a = CryptoJS.enc.Utf8.parse(lastFetchTime + "000")  
    , s = CryptoJS.AES.decrypt(encrypt_data.toString(), i, {  
      iv: a  
    })  
    , l = s.toString(CryptoJS.enc.Utf8);  
  return JSON.parse(l)  
}
  

通过在Python中调用这个脚本即可完成解码。

这种方法比较依赖经验判断,还有另外一种不需要经验的简单粗暴方法:
就是查看这个js文件后,可以发现dataFilter()方法是独立赋给_t这个对象的,那么就可以直接调用。首先直接把index_28827ebe.js文件全部复制到本地,去掉不相关或者报错的代码后,直接把_t.dataFilter()方法封装成Python中可调用的方法使用即可。这种方法因为这个js文件代码有几万行,所以会导致电脑突然变慢,酌情使用:P。
vixoj

获得了解密方法,就可以通过爬虫自动抓取数据信息了。

0

评论区