吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 880|回复: 9
收起左侧

[Web逆向] 记一次简单的JS(ob高级)混淆算法逆向分析

  [复制链接]
chboy 发表于 2025-3-21 16:39
本帖最后由 chboy 于 2025-3-21 16:48 编辑

前言

分析网址:aHR0cHM6Ly93d3cuaXRkb2cuY24v(数据已脱敏)

本次分析的是“网站测速”模块,其他模块的逆向思路是一样的,所以都可仿照本文章的思路进行逆向。

本文章的技术内容其实并不多,主要需要了解JS混淆的几个特征点,知道如何排查JS是用的什么技术进行混淆,再在网上找找脱壳工具,进行解混淆。

快速开始

WS分析

首先,逆向的第一步都是正着走一遍,看看是如何执行的。
image.png

通过F12,我们也可以看见,测速的底层传输逻辑是WS协议。

所以我们看一下WS的消息,如何进行的消息传递:

image.png

通过分析,发现第一次与服务器进行WS连接的时候,向服务器发送了一个数据包;之后,服务端给客户端发送了测速结果:

{"task_id":"202503211422122aa3vh0z2kxxowz4vd","task_token":"9789e2515c589a70"}

那么, 这两个参数是如何生成的?最简单的方法就是跟栈分析,看看创建WS连接的代码是怎么写的:

image.png

点进去后,发现JS被混淆了,怎么办?此时,就需要解混淆。

image.png

看到"0x"开头的,就应该是 通过变量混淆替换、增加冗余无效代码、增加无限debugger反调试功能、增加多层的套娃式if~else代码、以及埋陷阱等混淆成几千行的js代码。很明显,这里的JS是经过变量名混淆替换的ob混淆。

这里有详细讲解ob高级混淆的:

https://blog.csdn.net/weixin_43411585/article/details/123437953

所以,我们这里就直接使用v_jstools进行解混淆。

把上述的JS代码,Ctrl + Actrl + C,到上述工具中:

image.png

此时,出结果了,我们把code放到VS Code里面方便查看和分析:

我们搜索"new"就直接定位到关键连接WS的相关代码。

image.png
我们来依次看看代码做了什么:

   if (error_num < 1) {

​    return error_num++, setTimeout(() => {

​     create_websocket(_0x5d9212, _0x261ac6, _0x347e74);

​    }, 2000), ![];

   } else return $.get("/public/ajax.php?type=error_feedback&task_id=" + _0x261ac6), err_tip("WebSocket服务器连接失败,请重试 !"), ![];

  };

这个代码是日志记录,如果是WS服务器连接失败,此时会GET一个请求,应该是反馈给开发者的日志。

  ws.onopen = function () {

   ws.send("{\"task_id\":\"" + _0x261ac6 + "\",\"task_token\":\"" + md5(_0x261ac6 + "token_20230313000136kwyktxb0tgspm00yo5", 16) + "\"}");

  };

很明显,这个代码就是刚才我提到的两个值,此时我们可以看到task_token是MD5加密算法,task_token是两个字符串(_0x261ac6token_20230313000136kwyktxb0tgspm00yo5)拼接后,进行MD5加密而来。

请注意,MD5加密之后md5(..., 16)16 表示返回16位的十六进制字符串

那么,_0x261ac6这个变量的值是多少呢?很明显,看这个JSON格式,这个变量的值就是task_id

此时,我们搜索下这个_0x261ac6变量看看有没有什么对我们有用的信息,这里通过搜索看到了这个变量是这个函数"create_websocket"的一个传参变量;我们需要用到浏览器的断点大法看这个变量的值是是什么,我们在这个函数的起始位置打个断点:

image.png

通过看断点打出来的信息,也证实了这个变量的值是task_id

那么,知道这个task_idcreate_websocket函数的传参参数,我们全局搜索调用create_websocket函数的相关代码。

image.png

发现了,在这里,点进去看看。

image.png

真相大白了,原来这个函数传递的三个参数就是这三个。

那么,建立WS的三个参数我们都知道了,但是逆向到这里就结束了吗?还没有。

Cookie保护

在发送WS请求和获取task_id的时候,如果大量请求接口,则会触发保护。

触发保护后,需要进行Cookie鉴权,即保护器会生成一个值放入Cookie,接口会校验这个Cookie是否正确,如果不正确会导致type_id无法获取和WS无法连接。

至于解决办法嘛,下期再说~

但如果没有大量请求(一般情况下),是不会触发这个保护器的。

自动化

现在我们做一个自动化Python程序,看看我们的推断是否正确。

写自动化的程序和用到的技术这里就不多赘述了,详情可以看看代码:

import hashlib
import json

import requests
import re
import websockets
import asyncio
# 设置 测速的网址
http_url = "https://www.52pojie.cn"

gbl_taskId = None
gbl_taskToken = None

def get_task_id():
    url = "https://www.itdog.cn/http/"
    # 下面的data里面有一个参数"host_s"建议自己替换下,有点小问题,但是应该也不影响。
    data = f"line=&host={http_url}&host_s={http_url}&check_mode=fast&ipv4=&method=get&referer=&ua=&cookies=&redirect_num=5&dns_server_type=isp&dns_server="
    headers = {
        'upgrade-insecure-requests': '1',
        'origin': 'https://www.itdog.cn',
        'sec-fetch-dest': 'document',
        'sec-fetch-mode': 'navigate',
        'priority': 'u=0, i',
        'referer': 'https://www.itdog.cn/http/',
        'sec-ch-ua': '',
        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
        'sec-ch-ua-mobile': '?0',
        'sec-fetch-site': 'same-origin',
        'cache-control': 'no-cache',
        'sec-ch-ua-platform': '',
        'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36',
        'sec-fetch-user': '?1',
        'content-type': 'application/x-www-form-urlencoded',
        'pragma': 'no-cache',
        # 'cookie': ''
    }
    response = requests.post(url, data=data, headers=headers)
    print(response.text,response.status_code)
    match = re.search(r"var task_id='(.*?)';", response.text)
    if match:
        task_id = match.group(1)
        return True, task_id
    else:
        return False,""

async def connect_and_listen(uri, message_handler=None, extra_headers=None):
    """
    连接到指定的WebSocket URI并监听消息。

    :param uri: WebSocket服务器的URI(例如wss://www.example.com/websockets)
    :param message_handler: 一个可选的回调函数,用于处理接收到的消息
    :param extra_headers: 额外的HTTP头信息,如包含Cookie等
    """
    try:
        async with websockets.connect(uri, extra_headers=extra_headers) as websocket:
            print(f"Connected to {uri}")

            message = {
                "task_id": gbl_taskId,
                "task_token": gbl_taskToken
            }
            # 如果需要发送初始消息给服务器,可以在这里添加
            await websocket.send(json.dumps(message))
            print(json.dumps(message))
            while True:
                message = await websocket.recv()
                # print(f"Received message: {message}")

                # message_handler回调函数,调用它来处理消息
                if message_handler:
                    message_handler(message)

    except websockets.ConnectionClosed:
        print("Connection closed unexpectedly")

def start_websocket_listener(uri, message_handler=None):
    """
    启动WebSocket监听器。
    :param uri: WebSocket服务器的URI
    :param message_handler: 处理接收到消息的回调函数
    """
    extra_headers = {
        # 'cookie': ""
    }
    # 使用asyncio运行异步函数
    asyncio.get_event_loop().run_until_complete(connect_and_listen(uri, message_handler, extra_headers))

def websocket_return_message(message):
    json_obj = json.loads(message)
    print(json_obj)

if __name__ == '__main__':
    # 获取 task_id
    task_flag,task_id = get_task_id()
    if task_flag == False:
        print("获取task_id失败,请检查函数内部调用!")
        exit()
    # 获取 task_token
    task_token_str = "token_20230313000136kwyktxb0tgspm00yo5"
    task_token = hashlib.md5((task_id + task_token_str).encode('utf-8')).hexdigest()[8:24]
    gbl_taskId =  task_id
    gbl_taskToken = task_token
    print(f'{{"task_id":"{gbl_taskId}","task_token":"{gbl_taskToken}"}}')
    start_websocket_listener("wss://www.itdog.cn/websockets",websocket_return_message)

image.png

免费评分

参与人数 4威望 +1 吾爱币 +24 热心值 +4 收起 理由
芽衣 + 3 + 1 用心讨论,共获提升!
Unbalance + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
涛之雨 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
ImpJ + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

ImpJ 发表于 2025-3-21 17:16
快出下期,想知道怎么解决type_id无法获取和WS无法连接
su010 发表于 2025-3-21 17:28
mtmakemoney 发表于 2025-3-21 19:00
HiJo 发表于 2025-3-21 19:39
学习到了,谢谢博主
guotianyun 发表于 2025-3-21 20:07
很详细,认真学习
rtzanywn 发表于 2025-3-21 23:01
学习了。楼主高手。
DDS5205201 发表于 2025-3-21 23:37
感谢分享,帮我解决了困扰很久的小问题
rootbot007 发表于 2025-3-22 10:57
太厉害了吧
PoJieDaWang123 发表于 2025-3-23 13:46
又学到了,讲的好详细
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-4-1 08:41

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表