某h5st逆向分析

news2024/10/7 2:30:44

具体网址经过了base64处理

aHR0cHM6Ly9zby5tLmpkLmNvbS93YXJlL3NlYXJjaC5hY3Rpb24/a2V5d29yZD0lRTklOTklQTQlRTYlQjklQkYlRTYlOUMlQkEmc2VhcmNoRnJvbT1ob21lJnNmPTE1JmFzPTA=

要做的是一个搜索的功能具体如图所示。

这里发现携带的参数中存在一个token还有一个加密参数,直接尝试复制它的curl之后发现这个请求中的token直接作用联系不大,只是一个简单的风控参数,来源于这个链接:jsTk.do,这个我们下一篇文章再来解释。

我们看到了一个h5st参数,具体如下。

20240606195410996;ii6izi5zi59tgmn0;e1a98;tk03wb5b31ca018nwau78qTRAzaoD3WqtTDkki5lafP5UNTYY3D7dFhCkEn1XhUrb-KQUkf6RVCRqt5Bax2y7vxTNhly;693d4eb275cce02b6c5f97b94346a71b263ab83ab529a0efc8bb3606711d81fb;4.7;1717674850996;TKmW5xlX4OeERlufjbL4A4fF25LZ7RCYf4e7xnwpb9gxji9S-9M4h2-CyYw1yg8fluTw8XIl0jUa4QEyrRbJ4ALPrO1zTZeQ_2Un1apIBsQP1Y-rqe9I1YXcghByJ7hhZJxJZzukfA62kzuY1sPkwoqy81ol-6dZOgUy5EEGcIJDNrLF-yhKL2Y7in7mEuecFvZljZBWsfmq-OWxR7VuGBITN4oWbSZjMXrgTajzRX8ae78MzZjJs4L3f7kgOAB3bk0ewP-y9kbc00LyqBnjVkvcKiW3S-B7zUWAG-D6NwkHU1EP3DnStZ-glzn7XzGEjXYX3ihna_fh5UkRYP3u3NWTS4TAlqQmLd8KAiIP_H9ZstmkAdV7FmFOwUMXelSekPVoJ0ItwNNxuBSgXhis6TWihsqe3KzB7K89QdjAvxWa1hwGxzRNDtBwYXJoTMRJ0YDA

我们发现有分割符号分割的,第一个比较容易理解,就是时间戳,第二个进行相关的搜索,发现是来自一个/request_algo,它是本地提交注册之后的产物,并且还携带了一些相关的加密参数。

看着这些加密参数使用了aes相关的,对于aes加密,一般有一下特征:

  1. 根据长度来的,不同的长度尝试的aes加密内容不同
  2. 带有/+和正常的26个英文字母还有数字的,而且长度会根据加密内容的多而边长
  3. 看看是否引入了crypto库,一般来说如果做了加密我们可以直接hook这个库,就可以解决全部的加密问题

但是现在产商都喜欢给aes加密出来的内容再增加一些乱七八糟的东西固定在前面几个位置,而且一般来说可能还不是完全固定的aes加密,所以也不能肯定,但是一般来说就是aes加密。

这个参数我们不处理,我们知道了这个fp的来历,那么这个fp是什么东西呢?他其实就是一个浏览器指纹,但是这里的处理这个fp是带有部分随机的,包含你的user-agent信息。

我们一点一点来看它的相关内容。

20240606195410996 -> 日期

ii6izi5zi59tgmn0 -> fp ->在request_algo里面看到

e1a98 -> appid 在request_algo里面看到是有的

tk03... -> 这个tk也是在request_algo返回的

693d... -> 由于特殊的长度,看着是sha256,一般来说长度是64是sha256或者md5,不过md5一般是32位的,128的是sha512

4.7 -> 版本号

1717674850996 -> 时间戳

TKmW5xlX... -> 看着是aes加密的相关内容

由于没有直接找到这个crypto,猜测可能不是用的直接的加密手段,尝试hook json相关的处理发现不行,直接全局搜索h5st找,发现有非常多的位置,经过查看后这个位置最可疑。

尝试在这里hook一下看到相关的参数

r -> {
    "functionId": "searchKeyword",
    "appid": "jd-cphdeveloper-m",
    "body": "0d321e956894899084b9ea9ce55784ba6ba4edb4c12b438281a491cf05afc191"
}

看到这里的时候这个body长度是64位的,往上看看这个body怎么来的。

var r = P(s); -> 这个s就是我们的参数里面的body参数,然后使用P函数得到的r就是我们的body加密参数,我们把这个s去传统的md5还有sha256来尝试一下,发现是传统的sha256加密,

具体P函数代码如下

 我们把这个body复制去CyberChef (icyberchef.com)里面查看后,发现就是直接sha256加密,然后我们执行这个代码。

A[o].sign(r).then(function(t) {
     return s.h5st = encodeURI(t.h5st || ""),
     e(s)
})

发现最后返回的这个t包含一个正常的h5st,然后刷新页面进入sign函数内部分析。

单步向下后找到具体的位置,这t就是一个Promise,这是一个非常标准的next构成,因为在我们es6转es5的时候我们的async和await关键字都会被处理掉,还有相关的next函数还有yield返回也都会被处理调用,这个时候我们可以直接在e.apply(n, a)这个地方直接执行,然后调用它的next方法。

具体执行如下所示:

需要先在var i = e.apply(n, a)部分打上断点。

直接执行发现到了我们想要的结果

这个时候我们其实就已经解决了,我们看到这个e函数,来自于这里,是一个jsvmp混淆。

但是因为jsvmp混淆逆向比较敏感,不展示具体的逆向过程与逆向具体实例了,具体的使用在这个时候可以使用rpc远程调用的方式。

这里只能告诉大家如何使用rpc来进行处理,我们知道它的加密是经过了sign函数,那么理论上把这个sign函数弄好就可以了,我们看到这个函数是一个re对象,我们找到它的构造函数。

在这里一个位置我们点击下面的点击进去。然后在这里hook一个点,我们看看这个re实在什么时候被创建的。刷新整个页面,发现re的上面来自于这个函数。

基本可以肯定就是new了一个ParamsSign对象了,我们定位进去这个ParamsSign,然后全局搜索发现,这个就是在加密的文件顶部,可以直接调用。

我们在控制台尝试成功之后,确定了我们的re是可以直接这个样子创建的,并且我们这个re的sigin也是可以正常使用的,这里开始编写rpc代码,这里直接给出前端js还有后端python的代码。

前端生成代码

(function () {
    // 从cookie中获取指定名称的值
    function getCookie(name) {
        const cookieValue = document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)');
        return cookieValue ? cookieValue.pop() : '';
    }

    function baseInit(json, token) {
        const re = new ParamsSign({
            appId: "ffb96",
            debug: !1,
            preRequest: !1,
            onSign: function (e) {
                e.code
            },
            onRequestTokenRemotely: function (e) {
                e.code;
                e.message
            },
            onRequestToken: function (e) {
                e.code;
                e.message
            }
        })
        re._token = token
        return re.sign(json)
    }

    // 建立WebSocket连接
    const socket = new WebSocket('ws://localhost:6789');

    // 当WebSocket连接建立时执行
    socket.onopen = function () {
        console.log('WebSocket连接已建立');
    };

    // 当收到来自服务器的消息时执行
    socket.onmessage = function (event) {
        const json = JSON.parse(event.data)
        const token = getCookie("cd_eid");
        console.log(json)
        console.log(token)
        baseInit(json, token).then(function (t) {
            socket.send(JSON.stringify(t))
        })
    };

    // 当发生错误时执行
    socket.onerror = function (error) {
        console.error('WebSocket发生错误:', error);
    };

    // 当WebSocket连接关闭时执行
    socket.onclose = function () {
        console.log('WebSocket连接已关闭');
    };
})();

后端python代码

from flask import Flask, request
import asyncio
import websockets
import threading
import json
from queue import Queue

app = Flask(__name__)
connected = set()
queueWs = {}


async def websocket_server(websocket, path):
    connected.add(websocket)
    queueWs[websocket] = Queue()
    try:
        while True:
            message = await websocket.recv()
            queueWs[websocket].put(message)
    except websockets.ConnectionClosed:
        print("连接关闭")
    finally:
        connected.remove(websocket)


@app.route('/send', methods=['POST'])
def send_message():
    body = request.json.get('body', '')
    message = {
        "functionId": "searchKeyword",
        "appid": "jd-cphdeveloper-m",
        "body": body
    }
    message = json.dumps(message, ensure_ascii=False)
    data = asyncio.run(send_to_websockets(message))
    if data:
        return json.loads(data), 200
    else:
        return {"error": "没有连接"}, 200


async def send_to_websockets(message):
    if connected:
        for ws in connected:
            await ws.send(message)
            data = queueWs[ws].get()
            print(data)
            return data


def websocket_thread():
    asyncio.set_event_loop(asyncio.new_event_loop())
    start_server = websockets.serve(websocket_server, "localhost", 6789)
    asyncio.get_event_loop().run_until_complete(start_server)
    asyncio.get_event_loop().run_forever()


if __name__ == '__main__':
    # 在另一个线程中运行websocket服务器
    threading.Thread(target=websocket_thread, daemon=True).start()
    # 运行Flask应用
    app.run(port=5000)

python需要安装一些第三方库才可以,然后使用这个如下:

import requests


def get_info_rpc(body: str):
    import hashlib
    # 待哈希的字符串
    # 创建SHA-256哈希对象
    hash_object = hashlib.sha256()
    # 更新哈希对象,这里可以多次调用update()来添加长数据或分段数据
    hash_object.update(body.encode('utf-8'))
    # 获取16进制表示的哈希值
    hex_dig = hash_object.hexdigest()
    print(hex_dig)
    h5st = get_h5st_rpc(hex_dig)
    return h5st


def get_h5st_rpc(body):
    import requests
    response = requests.post("http://127.0.0.1:5000/send", json={
        "body": body,
    })
    h5st = response.json()["h5st"]
    return h5st


cookies = {"""cookie自己补充"""}

headers = {
    'accept': 'application/json',
    'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
    'cache-control': 'no-cache',
    'origin': 'https://so.m.jd.com',
    'pragma': 'no-cache',
    'referer': 'https://so.m.jd.com/',
    'sec-fetch-dest': 'empty',
    'sec-fetch-mode': 'cors',
    'sec-fetch-site': 'same-site',
    'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1 Edg/123.0.0.0',
    'x-referer-page': 'https://so.m.jd.com/ware/search.action',
    'x-rp-client': 'h5_1.0.0',
}

body = '{"tenantCode":"jgm","bizModelCode":5,"bizModeClientType":"M","externalLoginType":"1","key":"洗衣机","datatype":"1","page":"1","pagesize":"10","ext_attr":"no","brand_col":"no","price_col":"no","color_col":"no","size_col":"no","ext_attr_sort":"no","merge_sku":"yes","multi_suppliers":"yes","area_ids":"1,72,2819","filt_type":"redisstore,1;","qp_disable":"no","debug":"false","t1":"1717238265"}'

print(body)
h5st = get_info_rpc(body)
params = {
    'functionId': 'searchKeyword', 'appid': 'jd-cphdeveloper-m',
    'body': body,
    'loginType': '2',
    'x-api-eid-token': 'jdd033EQ4QE2Y5LL2TE2TCE2ICN67LRLC73I5TOUJTTFYF4P6DH6HNP2UMOHVXX4OR73EGUAJMC5AK7DZHAR3BFQLBUSFOIAAAAMP2KXQC2IAAAAACNUIMESNISVXDUX',
    'h5st': h5st
}
response = requests.get('https://api.m.jd.com/api', params=params, cookies=cookies, headers=headers)
print(response.text)
print(h5st)
print()

到此为止其实整个就已经完成了,对于它的vmp还有它的具体算法原理都已经处理完毕,具体不方便进行详细的说明,但是难度不大,有兴趣可以自己尝试。

由于此文章是逆向完成之后写的计数文章,尽可能的去模拟了当时思考的一个逻辑,但是还是和真实思考的环境差异比较大,rpc算法还原的不理解的可以私信联系,可以无偿帮忙解疑答惑。

需要具体算法的也可以联系,不止4.7版本,3.1等一系列版本都有,不正常的h5st部分的情况下是无法使用的,使用是会出现问题的,部分情况可以使用还有部分情况不可以使用,这种就是h5st有问题了。注意:具体算法还原不是免费的!!!想要白嫖勿加。

qq: 2697279763

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1796063.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【网络安全的神秘世界】Kali火狐浏览器汉化教程

🌝博客主页:泥菩萨 💖专栏:Linux探索之旅 | 网络安全的神秘世界 | 专接本 打开火狐浏览器 进入设置后,搜索language 打开之后选择添加其他语言,简体中文在最后一个 Add后点击ok即可

代码签名证书:软件安全的守护神

在数字化日益普及的今天,软件安全问题愈发受到人们的关注。而在这其中,一个常被提及但可能不为大众所熟知的名词——“代码签名证书”,实际上在软件安全领域扮演着举足轻重的角色。今天,我们就来聊聊代码签名证书对软件安全到底有…

SVM模型实现城镇居民月平均消费数据分类

SVM模型实现城镇居民月平均消费数据分类 一、SVM支持向量机简介二、数据集介绍三、SVM建模流程及分析一、SVM支持向量机简介 支持向量机是由感知机发展而来的机器学习算法,属于监督学习算法。支持向量机具有完备的理论基础,算法通过对样本进行求解,得到最大边距的超平面,并…

485数据采集模块

在工业自动化与智能化的浪潮中,数据采集作为整个系统的基础和核心,其准确性和实时性直接关系到生产效率和产品质量。而485数据采集模块,作为连接现场设备与上位机的重要桥梁,其性能与稳定性对于整个系统的运行至关重要。HiWoo Box…

浪潮电脑文件消失怎么恢复?原来有这五种方法

无论是工作、学习还是娱乐,电脑都扮演着举足轻重的角色。然而,在使用电脑的过程中,我们有时会遇到一些令人头疼的问题,比如文件突然消失。对于使用浪潮电脑的用户来说,文件消失可能是一个令人焦虑的问题。本文将为您详…

如何通俗易懂地理解大模型参数?

大型语言模型 (LLM) 的大小是通过参数数量来衡量的。举几个典型例子,GPT-3 有 1750 亿个参数,1750亿也可称为175B(1B 10亿),Meta最新开源的Llama3 参数数量在 80 亿到 700 亿之间,智谱公司最新开源的GLM4-…

【再探】Java—Java 沙箱机制与类加载器

沙箱(Sandbox)机制是将Java程序限定在JVM特定的运行范围内,并严格限制代码对本地系统资源的访问,以保证代码的有效隔离,防止对本地系统造成破坏。 1 安全模型 类在加载过程中,类加载器会为类设置初始的安…

【Java毕业设计】基于JavaWeb的在线购物网站的设计与实现

文章目录 摘 要ABSTRACT目 录1 概述1.1 研究背景及意义1.2 国内外研究现状1.3 拟研究内容1.4 系统开发技术1.4.1 vue技术1.4.2 B/S结构1.4.3 Spring Boot框架1.4.4 MySQL数据库1.4.5 MVC模式 2 系统需求分析2.1 可行性分析2.2 功能需求分析 3 系统设计3.1 功能结构设计3.2 系统…

美国签证办理需要带哪些材料?

在申请美国签证时,准备充分的材料至关重要。以下知识人网整理的关于您可能需要携带的一些常见材料: 1.护照:您的护照必须是有效的,并且在签证申请过程中至少有六个月的有效期。 2.签证申请表:您需要填写并提交签证申请…

联合(union)和枚举(enum)学习(c语言)

前言 Hello,亲爱的小伙伴们,好久不见,今天我们继续来学习新的内容-----联合和枚举 如果喜欢作者菌的文章的话,就不要吝啬手中的三连呀,万分感谢!! 联合(共用体)(union&…

前端开发之性能优化

本文章 对各大学习技术论坛知识点,进行总结、归纳自用学习,共勉🙏 文章目录 1. [CDN](https://www.bootcdn.cn/)2.懒加载3.缓存4.图片压缩5.图片分割6.sprite7.Code Splitting8.gzip9.GPU加速10.Ajax11.Tree Shaking12.Resource Hints 1. CD…

VisualStudio 2022 安装net8sdk后无法创建net8项目

目录 一级目录原因分析解决办法 一级目录 VisualStudio 2022 安装net8sdk后无法创建net8项目 原因分析 解决办法 安装net8 查看安装的版本 dotnet --list-sdks升级VisualStudio 2022版本,重启电脑 当前版本 开始升级 升级后版本 已可以使用net8.0

盲盒一番赏小程序:开发探索之旅,打造独特互动体验

在快节奏的现代生活中,每个人都期待一份突如其来的惊喜。为了满足这一需求,我们倾力打造了“盲盒一番赏”小程序,为你带来全新的购物体验,让每一次点击都成为一次心跳加速的探险之旅。 一、盲盒文化,点燃惊喜火花 盲…

苹果不会在WWDC 2024中推出任何搭载M4芯片的Mac电脑

虽然苹果公司已在上月推出了首搭 M4 芯片的 iPad Pro,不过彭博社的马克・古尔曼在最近的实时通讯中透露苹果公司不会在即将进行的 WWDC 2024 开发者大会中推出任何搭载 M4 芯片的 Mac 电脑(不会推出任何硬件产品)。 此前报道,苹果…

Android 蓝牙概述

一、什么是蓝牙 蓝牙是一种短距离(一般10m内)无线通信技术。蓝牙技术允许固定和移动设备在不需要电缆的情况下进行通信和数据传输。 “蓝牙”这名称来自10世纪的丹麦国王哈拉尔德(Harald Gormsson)的外号。出身海盗家庭的哈拉尔德统一了北欧四分五裂的国…

用负载绿原酸的纳米复合水凝胶调节巨噬细胞表型以加速伤口愈合

引用信息 文 章:Modulating macrophage phenotype for accelerated wound healing with chlorogenic acid-loaded nanocomposite hydrogel. 期 刊:Journal of Controlled Release(影响因子:10.8) 发表时间&a…

【数据结构】C语言实现二叉树的基本操作——二叉树的遍历(先序遍历、中序遍历、后序遍历)

C语言实现二叉树的基本操作 导读一、二叉树的遍历二、先序遍历三、中序遍历四、后序遍历五、结点序列六、递归算法与非递归算法的转化结语 导读 大家好,很高兴又和大家见面啦!!! 通过前面的介绍,我们已经认识了二叉树…

五菱缤果Plus,便宜又大碗的纯电

五菱缤果Plus在技术和性能方面相较于比亚迪海豚有以下几个优势: 续航能力:五菱缤果Plus搭载了五菱液冷神炼电池和75kW三合一水冷扁线电机,能够提供最长510km的超长续航里程。相比之下,比亚迪海豚荣耀版的NEDC工况续航里程为401km…

NSSCTF-Web题目6

目录 [NISACTF 2022]checkin 1、题目 2、知识点 3、思路 [NISACTF 2022]babyupload 1、题目 2、知识点 3、思路 [SWPUCTF 2022 新生赛]1z_unserialize 1、题目 2、知识点 3、思路 [NISACTF 2022]checkin 1、题目 2、知识点 010编辑器的使用、url编码 3、思路 打…

力扣--数组6.Z字形变换

思路分析 处理特殊情况: 如果numRows为1,那么字符排列与原字符串相同,无需进行转换,直接返回原字符串。 定义和初始化变量: n:字符串长度。k:一个完整的“V”字形周期长度,计算公式为…