某h5st逆向分析

2024-06-07 06:36
文章标签 h5st 逆向 分析

本文主要是介绍某h5st逆向分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

具体网址经过了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 = tokenreturn 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 Queueapp = 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), 200else:return {"error": "没有连接"}, 200async def send_to_websockets(message):if connected:for ws in connected:await ws.send(message)data = queueWs[ws].get()print(data)return datadef 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 requestsdef 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 h5stdef get_h5st_rpc(body):import requestsresponse = requests.post("http://127.0.0.1:5000/send", json={"body": body,})h5st = response.json()["h5st"]return h5stcookies = {"""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

这篇关于某h5st逆向分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1038411

相关文章

[职场] 公务员的利弊分析 #知识分享#经验分享#其他

公务员的利弊分析     公务员作为一种稳定的职业选择,一直备受人们的关注。然而,就像任何其他职业一样,公务员职位也有其利与弊。本文将对公务员的利弊进行分析,帮助读者更好地了解这一职业的特点。 利: 1. 稳定的职业:公务员职位通常具有较高的稳定性,一旦进入公务员队伍,往往可以享受到稳定的工作环境和薪资待遇。这对于那些追求稳定的人来说,是一个很大的优势。 2. 薪资福利优厚:公务员的薪资和

高度内卷下,企业如何通过VOC(客户之声)做好竞争分析?

VOC,即客户之声,是一种通过收集和分析客户反馈、需求和期望,来洞察市场趋势和竞争对手动态的方法。在高度内卷的市场环境下,VOC不仅能够帮助企业了解客户的真实需求,还能为企业提供宝贵的竞争情报,助力企业在竞争中占据有利地位。 那么,企业该如何通过VOC(客户之声)做好竞争分析呢?深圳天行健企业管理咨询公司解析如下: 首先,要建立完善的VOC收集机制。这包括通过线上渠道(如社交媒体、官网留言

逆向学习汇编篇:内存管理与寻址方式

本节课在线学习视频(网盘地址,保存后即可免费观看): ​​https://pan.quark.cn/s/3ceeb9ae6d98​​ 在汇编语言的世界中,内存管理和寻址方式是构建程序的基础。理解这些概念不仅对于编写高效的汇编代码至关重要,也是进行逆向工程分析的关键技能。本文将深入探讨内存管理的基本原则和多种寻址方式,并通过代码案例来展示它们的实际应用。 1. 内存管理 内存管理涉及如何分配

打包体积分析和优化

webpack分析工具:webpack-bundle-analyzer 1. 通过<script src="./vue.js"></script>方式引入vue、vuex、vue-router等包(CDN) // webpack.config.jsif(process.env.NODE_ENV==='production') {module.exports = {devtool: 'none

Java中的大数据处理与分析架构

Java中的大数据处理与分析架构 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们来讨论Java中的大数据处理与分析架构。随着大数据时代的到来,海量数据的存储、处理和分析变得至关重要。Java作为一门广泛使用的编程语言,在大数据领域有着广泛的应用。本文将介绍Java在大数据处理和分析中的关键技术和架构设计。 大数据处理与

段,页,段页,三种内存(RAM)管理机制分析

段,页,段页         是为实现虚拟内存而产生的技术。直接使用物理内存弊端:地址空间不隔离,内存使用效率低。 段 段:就是按照二进制文件的格式,在内存给进程分段(包括堆栈、数据段、代码段)。通过段寄存器中的段表来进行虚拟地址和物理地址的转换。 段实现的虚拟地址 = 段号+offset 物理地址:被分为很多个有编号的段,每个进程的虚拟地址都有段号,这样可以实现虚实地址之间的转换。其实所谓的地

mediasoup 源码分析 (八)分析PlainTransport

mediasoup 源码分析 (六)分析PlainTransport 一、接收裸RTP流二、mediasoup 中udp建立过程 tips 一、接收裸RTP流 PlainTransport 可以接收裸RTP流,也可以接收AES加密的RTP流。源码中提供了一个通过ffmpeg发送裸RTP流到mediasoup的脚本,具体地址为:mediasoup-demo/broadcaste

Java并发编程—阻塞队列源码分析

在前面几篇文章中,我们讨论了同步容器(Hashtable、Vector),也讨论了并发容器(ConcurrentHashMap、CopyOnWriteArrayList),这些工具都为我们编写多线程程序提供了很大的方便。今天我们来讨论另外一类容器:阻塞队列。   在前面我们接触的队列都是非阻塞队列,比如PriorityQueue、LinkedList(LinkedList是双向链表,它实现了D

线程池ThreadPoolExecutor类源码分析

Java并发编程:线程池的使用   在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:   如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。   那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务?

ConcurrentHashMap之源码分析

集合是编程中最常用的数据结构。而谈到并发,几乎总是离不开集合这类高级数据结构的支持。比如两个线程需要同时访问一个中间临界区(Queue),比如常会用缓存作为外部文件的副本(HashMap)。这篇文章主要分析jdk1.5的3种并发集合类型(concurrent,copyonright,queue)中的ConcurrentHashMap,让我们从原理上细致的了解它们,能够让我们在深度项目开发中获益非浅