【JS逆向案例】某加速乐cookie逆向分析

声明

本文中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!

本文未经许可禁止转载,禁止任何形式的修改后进行二次传播,若有侵权,请联系作者删除!

逆向目标

网站:aHR0cHM6Ly93d3cubXBzLmdvdi5jbi9pbmRleC5odG1s

加速乐

加速乐的特点是一般有三次请求:

  1. 第一次请求网站返回的状态码是521,响应返回的数据经过了AAEncode混淆
  2. 第二次请求网站返回的状态码也是521,响应返回的数据经过了OB混淆
  3. 第三次请求网站返回的状态码是正常的200,成功访问网页

逆向思路

根据加速乐的特点,思路分为以下三点:

  1. 第一次请求响应头中会返回__jsluid_s参数,响应内容解密后得到第一次__jsl_clearance_s参数
  2. 第二次请求携带上第一次请求得到的cookie值,响应内容解密后得到第二次__jsl_clearance_s参数
  3. 第三次请求携带上最终的cookie,即可成功访问网页

逆向分析

先对目标网站抓个包分析一下,可以看到请求同一个页面发生了三次请求,前两次都是返回521状态码,最后一次是200,符合加速乐特征

第一次请求

点击第一次请求,我们看到服务器给我们返回了cookie参数__jsluid_s,但响应内容无法看到,这时可以使用fiddler抓包工具查看,是一段混淆后的内容

我们把响应内容拿出来,粘贴到notepad++,内容大致是一个经过AAEncode混淆的cookie

<script>document.cookie=('_')+('_')+('j')+('s')+('l')+('_')+('c')+('l')+('e')+('a')+('r')+('a')+('n')+('c')+('e')+('_')+('s')+('=')+(+!+[]+'')+(6+'')+(4+5+'')+(-~(8)+'')+(3+4+'')+(([2]+0>>2)+'')+(2+6+'')+(~~''+'')+((1<<1)+'')+(-~1+'')+('.')+(8+'')+(-~[]+'')+(2+6+'')+('|')+('-')+(-~0+'')+('|')+('K')+('y')+((1<<3)+'')+('Q')+('q')+('Q')+('q')+('l')+('i')+('l')+((2^1)+'')+('V')+((2)*[4]+'')+('p')+(-~{}+'')+('l')+('Q')+('v')+('%')+(0+1+0+1+'')+('B')+('h')+('g')+('T')+('B')+('k')+('r')+('n')+('A')+('%')+(3+'')+('D')+(';')+(' ')+('M')+('a')+('x')+('-')+('a')+('g')+('e')+('=')+(3+'')+(2+4+'')+((+false)+'')+(~~{}+'')+(';')+(' ')+('P')+('a')+('t')+('h')+('=')+('/')+(';')+(' ')+('S')+('a')+('m')+('e')+('S')+('i')+('t')+('e')+('=')+('N')+('o')+('n')+('e')+(';')+(' ')+('S')+('e')+('c')+('u')+('r')+('e');location.href=location.pathname+location.search</script>

直接拿出document.cookie等号后的值控制台输出一下,果然是一段cookie,在Python中可以使用execjs.eval()解混淆(可以使用正则将混淆的cookie提取出来)

第二次请求

点击查看第二次请求,返回的也是一段混淆的

这里我也不知道怎么解混淆,参考了下K哥的教程,提到了两种方法,一种是本地替换,一种是hook,我这里直接就选择了hook方法,使用了编程猫插件

//当前版本hook工具只支持Content-Type为html的自动hook
//下面是一个示例:这个示例演示了hook全局的cookie设置点
(function() {
    //严谨模式 检查所有错误
    'use strict';
    //document 为要hook的对象   这里是hook的cookie
	var cookieTemp = "";
    Object.defineProperty(document, 'cookie', {
		//hook set方法也就是赋值的方法 
		set: function(val) {
        if(val.indexOf("__jsl_clearance_s") != -1){
            debugger;
        }           
				//这样就可以快速给下面这个代码行下断点
				//从而快速定位设置cookie的代码
				console.log('Hook捕获到cookie设置->', val);
				cookieTemp = val;
				return val;
		},
		//hook get方法也就是取值的方法 
		get: function()
		{
			return cookieTemp;
		}
    });
})();

可以看到成功hook到cookie参数__jsl_clearance_s

下面开始跟栈调试,在这里设置了cookie

找到了cookie生成的位置是下面这段代码

var _0x2cb0e1 = _0x293413[_0x5c39('0x4b', 'fbqw') + 'c'](_0x1ab968['tn'] + '=' + _0x1f2023[0x0] + (_0x5c39('0xab', 'FMv#') + _0x5c39('0x75', '%^JY') + '=') + _0x1ab968['vt'], _0x293413[_0x5c39('0x94', 'aZ9(') + 'o']);

将这段代码优化下,发现cookie由_0x1f2023[0x0]生成,继续跟栈调试,找到_0x1f2023[0x0]的生成位置是如下代码

var _0x1f2023 = _0x293413[_0x5c39('0x35', '34sA') + 'R'](_0x47a5cd, _0x1ab968['ct'], _0x1ab968[_0x5c39('0xfe', '7oIp')]);

先将代码本地保存一份到notepad++,因为该js代码是动态变化的,方便我们调试。我们直接在开发者工具新建代码片段进行调试,记得清除cookie再断点调试

经过调试发现,cookie参数由如下代码生成,其关键处是hash函数,当hash函数加密后的数据等于_0x393bf1时,返回cookie参数的值

function _0x47a5cd(_0x393bf1, _0xf58bf1) {
    var _0x15efa8 = {};
    _0x15efa8[_0x5c39('0xae', 'm$PE') + 'S'] = function(_0x555149, _0x3f2144, _0x255dc1) {
        return _0x555149(_0x3f2144, _0x255dc1);
    }
    ;
    _0x15efa8[_0x5c39('0x5a', '#2#0') + 'Z'] = function(_0x9f6fcd, _0x54edcc, _0x37d23d) {
        return _0x293413[_0x5c39('0x5c', '(aB&') + 'h'](_0x9f6fcd, _0x54edcc, _0x37d23d);
    }
    ;
    var _0x283d83 = _0x15efa8;
    if (_0x293413[_0x5c39('0x104', 'swkp') + 'k'] !== _0x293413[_0x5c39('0xd7', '*)&)') + 'k']) {
        a = _0x283d83[_0x5c39('0xf4', '%^JY') + 'S'](AddUnsigned, a, _0x283d83[_0x5c39('0x6b', '2Qrn') + 'Z'](AddUnsigned, AddUnsigned(F(b, c, d), x), ac));
        return _0x283d83[_0x5c39('0x1e', 'fbiV') + 'Z'](AddUnsigned, RotateLeft(a, s), b);
    } else {
        var _0x3c0e1f = _0x1ab968[_0x5c39('0x7e', 'Q#%8') + 's'][_0x5c39('0xfd', 'w[O^') + 'th'];
        for (var _0x14a05f = 0x0; _0x293413[_0x5c39('0x121', '62a0') + 's'](_0x14a05f, _0x3c0e1f); _0x14a05f++) {
            for (var _0x56321d = 0x0; _0x56321d < _0x3c0e1f; _0x56321d++) {
                var _0x1919fd = _0xf58bf1[0x0] + _0x1ab968[_0x5c39('0x129', '72K6') + 's'][_0x5c39('0xbc', '#2#0') + 'tr'](_0x14a05f, 0x1) + _0x1ab968[_0x5c39('0xf2', 'Zw9a') + 's'][_0x5c39('0xf8', '!Y%v') + 'tr'](_0x56321d, 0x1) + _0xf58bf1[0x1];
                if (_0x293413[_0x5c39('0x4e', '%^JY') + 'A'](hash(_0x1919fd), _0x393bf1)) {
                    return [_0x1919fd, _0x293413[_0x5c39('0x72', '7XT8') + 'i'](new Date(), _0x534ce4)];
                }
            }
        }
    }
}

调试这段代码可以发现里面所用参数来自go函数传入,并且hash函数所使用的加密方法是动态变化的,由go["ha"]决定,有三种加密方式md5、sha1、sha256,找个在线网站或者编程猫插件可以验证hash函数是标准的加密方式,直接调用crypto-js库实现算法

go = {
    "bts": ["1699759180.198|0|gI4", "2F4ybqrb3R3XniRZUgcbpvJI%3D"],
    "chars": "IVwNuGnmmWkymG%lYdqCqQ",
    "ct": "6f455c7207ae7bdee69232d4b9df739f",
    "ha": "md5",
    "is": true,
    "tn": "__jsl_clearance_s",
    "vt": "3600",
    "wt": "1500"
}
const CryptoJs = require("crypto-js");

function hash(type, value){
    if(type == "md5"){
        return CryptoJs.MD5(value).toString();
    }
    if(type == "sha1"){
        return CryptoJs.SHA1(value).toString();
    }
    if(type == "sha256"){
        return CryptoJs.SHA256(value).toString();
    }
}

第三次请求

cookie逆向已经完成,直接编写Python代码进行请求,验证是否可用

# @Time    : 2023/11/11 16:18
# @Author  : 车厘子
# @Software: PyCharm
import re
import json
import execjs
import requests
from loguru import logger


url = ''
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36',
}
cookies = {}

def get_first_cookie():
    global cookies
    response = requests.get(url, headers=headers)
    # 获取 cookie 值 __jsluid_s
    cookies.update(response.cookies)
    # 获取第一层响应内容, AAEncode 加密
    AAEncode_text = re.search('document.cookie=(.*?);location', response.text).group(1)
    __jsl_clearance_s = execjs.eval(AAEncode_text).split(";")[0]
    # 获取 cookie 值 __jsl_clearance_s
    cookies["__jsl_clearance_s"] = __jsl_clearance_s.split("=")[1]

def get_second_cookie():
    global cookies
    # 通过携带 __jsluid_s 和 __jsl_clearance_s 值的 cookie 获取第二层响应内容
    response = requests.get(url, headers=headers, cookies=cookies)
    go_params = re.findall(';go\((.*?)\)</script>', response.text)[0]
    go_params = json.loads(go_params)
    return go_params

def get_response_data(go_params):
    global cookies
    __jsl_clearance_s = execjs.compile(open("__jsl_clearance_s.js","r", encoding="utf-8").read()).call("get__jsl_clearance_s",go_params)
    cookies["__jsl_clearance_s"] = __jsl_clearance_s
    response = requests.get(url, headers=headers, cookies=cookies)
    response.encoding = "utf-8"
    logger.success(response.text)

def main():
    get_first_cookie()
    go_params = get_second_cookie()
    get_response_data(go_params)

if __name__ == '__main__':
    main()

验证结果

完美通过!

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
嗨!对于爬虫中的 JavaScript 逆向案例,我可以给你提供一个简单的示例。请注意,这个示例只是为了帮助你理解逆向过程,真实的应用中可能涉及法律和伦理问题,请合法使用爬虫技术。 假设我们要爬取一个网站上的某个页面数据,但是该页面通过 JavaScript 动态生成。我们可以通过分析网页的 JavaScript 代码来逆向工程,获取所需数据。 首先,打开 Chrome 浏览器并进入开发者工具(按 F12 键或右键点击页面并选择“检查”)。然后切换到“网络”选项卡。 接下来,在浏览器地址栏中输入目标网页的 URL 并按下回车,浏览器将开始加载页面。在网络选项卡中,你将看到所有请求和响应的列表。 查找其中一个请求,该请求可能包含我们所需的数据。点击该请求并查看其请求头、响应头和响应体。 在响应体中,你可能会看到一些 JavaScript 代码,这些代码负责生成页面上的内容。你可以仔细阅读该代码,并找到生成目标数据的部分。 如果你发现目标数据是通过 Ajax 请求获取的,你可以查看该 Ajax 请求的 URL 和参数,然后使用 Python 的 requests 库或其他适当的方法模拟该请求,并解析响应获取数据。 如果你发现目标数据是在 JavaScript 代码中直接生成的,你可以尝试分析代码逻辑并编写相应的 Python 代码来模拟该过程。这可能涉及到使用 JavaScript 解释器或库来执行 JavaScript 代码。 需要注意的是,JavaScript 逆向工程是一项复杂的任务,需要对 JavaScript 和网络协议有一定的理解。同时,网站所有者可能会采取一些反爬虫措施来阻止你的行为,所以请务必遵守法律法规和网站的使用规则。 希望这个示例能够帮助你入门 JavaScript 逆向工程。如果你有任何其他问题,欢迎继续提问!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Red sir

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值