博客配套代码发布于github:喜马拉雅登录 (欢迎顺手Star一下⭐)

相关知识点:webpack 补环境

相关爬虫专栏:JS逆向爬虫实战  爬虫知识点合集  爬虫实战案例 逆向知识点合集


此案例目标为逆向成功对应的参数,并成功返回对应请求。

一、爬取工作准备

进入网址:喜马拉雅登录,再点击右上角那个小电脑,进入密码登录界面。

手机号输入123456789,密码输入123456,点开F12,再点击登录,就可以开始我们的表演了。

一看就知道这个就是我们要的数据,再看载荷:

能看出我们大致要破解的四个参数:account,nonce,password,signature.

老规矩,直接复制这个数据包到curl to python,并将其复制到py运行查看结果(步骤在以往JS逆向案例有,不懂的直接看往期操作即可)

可以看到运行结果应是这个。如果并非这个结果说明参数传递错误。

二、逆向入口分析

直接encrypt搜,搜到七个,分析发现只有下面四个长得像,依次打上断点。

只剩这俩地方断的住。

试着从第二个开始找,我们直接选择最下层的这个匿名,进去查看下:巧了不是,account,password,nonce都看到了,这儿还有这么完美的四大参数,不是这我吃。现在再挨个分析即可。

account:

account是n,n是→这里getEncryptPwd点进去的确可以进入到下层栈然后接着找,再补环境,但未免落了下成。往上再捋捋看看a的位置在哪。一直翻翻翻,终于看到:看到a=r(19),webpack与加载器,看到这就很开心了,后面可以直接一套公式流webpack过掉,轻轻又松松啊。

password:

password是i,i是→跟上面的account近乎一个样,也是webpack,处理近乎一致。

nonce:

nonce是t,t是→

呃,是传入参数。而且这个t还是个一直变动的值。找不到上下层堆栈。

别急:当你看到检测参数较多而且某个值似乎无法通过溯源找到适,可以看看其他的数据包:

果然,是从另一个数据包获得的nonce,那我们只需要通过单独向这个数据包发请求获得nonce即可。

signature:

siganture是e,e是→可以将其简化,即:

var e = a.getSignature({
                account: n,
                password: i,
                nonce: t
            })

乍一看,也是用了a加载器,直接像上面的账密一样...不行!

这里有个坑,而且非常隐蔽,笔者在这里就捣鼓了好久才知晓原因。

如果你用的是加载器的方式得到,它最后作为参数是错误的。原因极大概率是因为其获取方式与常规加载器的逻辑不同。这里说一下此处的分析思路应如何。

正常来讲是会去想到直接去用加载器,但用前一定先在控制台打印观察下。此处可以看到打印出来格式为哈希算法,则:尽可能别用加载器,加密算法的逻辑就单独用算法方式解决,两者获取可能会冲突。

点进a.getSiganture看对应层逻辑:

 

这里选中的是e.toUpperCase()),能看到它是一个很长的由上方拼接获取的字符

同时我们再把这一串打印进控制台:

发现没有:在同一时间线(同个ajax请求)下,获得的两个算法最终答案相近,但后者(加密算法)才对。

同时这里能通过分析哈希算法长度,即40位,基本确定其为sha1算法。

但还是有点不放心。我们这里是想直接用sha1的加密逻辑得到,但不确定它有没有加盐(魔改)算法,到SHA1加密网络转换器里,将e.toUpeerCase()的东西输入进去看下(记得去掉引号)

与上述答案一致。那么就可以放心直接用算法了,至此这个逻辑基本完成。

综上,所有参数分析完毕后可以开始我们的正式操作了。

三、破解逆向

1.补webpack

这段就老生常谈的公式了,尽量简化描述:

(如需更详细的步骤请参考我往期写的webpack处理公式)

选中加载器,刷新页面并进去里面,全选复制粘贴过来并简单处理掉里面的html元素,并在顶部写个window=global。再把刷新进去位置的函数(function i(r)),设置个console.log('r:::',r)与window.loader=i

最后再将传入代码写作:

一般如果webpack里是r('GSGX')这种还能依靠直接搜'GSGX'复制粘贴过来,但如果是像上图这种r(19)的webpack,就得通过源函数来进入了:

选中r(19):进入里面这个栈并全局复制到mod01即可(对应的是数组,不用分析半天究竟是谁)

缺这玩意儿就全局搜并全部复制(注意这个搜索的是var xx,切记把这个var去掉不然没法上升为全局变量),再给个mod02补上,并require过来(注意require的顺序):

看到这里就能确定webpack环节结束,接下来到补环境阶段。

2.补环境

却啥补啥,补到此时:

有点怪,好像不太好补。那就把我们的监控器递出来吧↓

(监控器具体用法在文章 [逆向知识] 补环境 -- 让本地逆向如鱼得水 处有讲,建议在这里看一看)

function setProxy(proxyObjArr) {for (let i = 0; i < proxyObjArr.length; i++) {const handler = `{get: function(target, property, receiver) {console.log("方法:", "get  ", "对象:", "${proxyObjArr[i]}", "  属性:", property, "  属性类型:", typeof property, ", 属性值:", target[property], ", 属性值类型:", typeof target[property]);return target[property];},set: function(target, property, value, receiver) {console.log("方法:", "set  ", "对象:", "${proxyObjArr[i]}", "  属性:", property, "  属性类型:", typeof property, ", 属性值:", value, ", 属性值类型:", typeof target[property]);return Reflect.set(...arguments);}}`;eval(`try {${proxyObjArr[i]};${proxyObjArr[i]} = new Proxy(${proxyObjArr[i]}, ${handler});} catch (e) {${proxyObjArr[i]} = {};${proxyObjArr[i]} = new Proxy(${proxyObjArr[i]}, ${handler});}`);}
}setProxy(['window', 'document','canvas'])

document补全,看到:

很明显知道canvas少了个toDataURL,加进去即可。

同样,其他补环境逻辑也大致相同,陆续为setProxy加东西即可,只有一个点要注意下:

大大的userAgent,这玩意儿就不要再传空值或空func,直接控制台打印个丢过来不好吗

这个点也是不太好处理,但只要全局搜就可以了,搜到发现隶属于document对象,仿写过来就行。同理,后面好几个环境也可以靠这样补。

最终成功补完没再报错,将setProxy的代理与之前console.log的r都注释掉,

这个是window对象,也补上环境就消失了,

最终输出:账户与密码的逻辑搞定。

3.py与js代码互传

首先我们要确定py与js互传的方式。分为execjs与subprocess。正好这里都会用到。execjs用于构建环境较简单,没有很多浏览器原生的bom/dom,api或更复杂的模拟环境这些;subprocess则用于如之前代码中复杂的环境模拟,最终输出。

(1) execjs

它的使用方式相较非常简单,直接传递即可。这里我们以siganture的获得举例

cryptoJs = require("crypto-js")function y(t) {var e = "", r = Object.keys(t).sort((function (t, e) {return (t = t.charCodeAt(0)) - (e = e.charCodeAt(0))})), n = r.length;return r.forEach((function (r, o) {var i = t[r];e += "".concat(r, "=").concat(i),o < n - 1 && (e += "&")})),e
}function getSignature() {var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, e = y(t) + "&" + "WEB-V1-PRODUCT-E7768904917C4154A925FBE1A3848BC3E84E2C7770744E56AFBC9600C267891F";return e.toUpperCase(),cryptoJs.SHA1(e.toUpperCase()).toString()
}

这个signature在js中的构建逻辑,而在py中,我们只需要通过如下的代码即可获取对应js生成的代码。

js_compile = execjs.compile(open('sign.js',encoding='utf8').read())
data = {'account': enc_account,'password': enc_password,'nonce': nonce_val}
signature = js_compile.call('getSignature',data)

其中data是传递进去的参数,'getSignature'则是用于选择这个文件的这个函数。

(2) subprocess

其使用相较就复杂很多,这里也是分别放js与py文件对应代码:

function get_all(account, password) {function get_account() {return (0, a.getEncryptPwd)(account)}function get_pwd() {return (0, a.getEncryptPwd)(password)}return {account:get_account(),pwd:get_pwd(),}
}act = process.argv[2]
pwd = process.argv[3]
const ret = get_all(act,pwd)
res = JSON.stringify(ret)
console.log(res)process.exit()

在js文件中,通过process.argv获取传递过来的原始账密并传递给get_all,再生成后打印到控制台上。py文件再通过控制台的消息对应接收过来。本质上可以理解为双方是靠终端来接收各自的数据。

all_ = subprocess.check_output(f'node get_sign.js "{account}" "{password}"') # 分别获得传递
all_ = all_.decode('utf8').strip()
# 通过json传递取出对应值
js_data = json.loads(all_)
account = js_data['account']
pwd = js_data['pwd']

注意:这里我用的是json数据来互传。因为js传递过来的数据是个长字符串,用json格式才方便将其转化为字典格式以提取。

四、完整逻辑构建

如上,我们基本已完成了相关具体逻辑与所有代码的构建。

最终我们将其模块化打包输出:

if __name__ == '__main__':account = '123456789'password = '123456'cur_nonce = get_nonce()enc_account,enc_pwd = get_encrypt(account, password)signature = get_signature(enc_account,enc_pwd,cur_nonce)ret = login(enc_account,enc_pwd,cur_nonce,signature)print(ret)

答案获取成功,逆向完成。

由于代码量过大,本文并未将所有代码都放上来。但可以看我的github开源代码,来进一步全面分析。

📌 项目代码 + 后续案例合集 全部发布在 GitHub 仓库中,持续更新中,欢迎收藏!

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大语言模型推理系统综述

摘要 近年来&#xff0c;随着 ChatGPT 等服务推动大语言模型&#xff08;LLM&#xff09;的快速普及&#xff0c;一批专门面向 LLM 推理的系统相继涌现&#xff0c;如 vLLM、SGLang、Mooncake 和 DeepFlow。这些系统设计工作的核心动因是 LLM 请求处理过程中所特有的自回归特性…

用Firecrawl轻松获取网站数据,提升AI应用的效率!

&#x1f525; Firecrawl&#xff1a;助力AI应用的强大工具&#xff01; 在数字化信息爆炸的时代&#xff0c;如何高效地从海量网页中提取有用数据变得尤其重要。Firecrawl的问世&#xff0c;为我们揭开了一种便捷的方法来应对这一挑战。它不仅能够将整个网站的数据转化为适用…

【王阳明代数讲义】谷歌编程智能体Gemini CLI 使用指南、架构详解与核心框架分析

Gemini CLI 使用指南、架构详解与核心框架分析 Gemini CLI 使用指南、架构详解与核心框架分析Gemini CLI 使用指南Gemini CLI 架构详解Gemini CLI 核心框架总结 Gemini CLI 使用指南、架构详解与核心框架分析 Gemini CLI 使用指南 1. 安装与配置 环境要求&#xff1a; Node.…

camera调试:安卓添加xml注册

对接安卓的平台时&#xff0c;需要注册对应的camera设备&#xff0c;供安卓标准api进行操作&#xff0c;rk的平台需要在HAL层配置camera3_profiles.xml文件&#xff0c;适配驱动的信息&#xff0c;进行注册camera设备。该xml对应的内容很多&#xff0c;很多CTS测试问题都是该文…

使用 Ansys Discovery 为初学者准备几何结构

介绍 设计几何体通常会包含一些特征&#xff0c;使其无法直接导入我们的仿真工具&#xff0c;例如 Ansys Mechanical、LS-DYNA、Fluent 等。有些干扰或错位虽然适合制造&#xff0c;但在我们的仿真工具中却会造成问题。有时&#xff0c;一些小特征&#xff08;例如孔或圆角&am…

推客系统全栈开发指南:从架构设计到商业化落地

一、推客系统概述 推客系统&#xff08;TuiKe System&#xff09;是一种结合社交网络与内容分发的创新型平台&#xff0c;旨在通过用户间的相互推荐机制实现内容的高效传播。这类系统通常包含用户关系管理、内容发布、智能推荐、数据分析等核心模块&#xff0c;广泛应用于电商…

大数据开发实战:如何做企业级的数据服务产品

1.背景 数据服务通常以解决方案的形式进行组织&#xff0c;面向一个应用场景的所有数据需求或数据内容可以通过一个解决方案进行封装&#xff0c;统一对外服务。一个数据需求或数据接口以一个数据服务实例的形式存在于解决方案之下。 下游消费方可以通过统一API进行数据消费&…

基于IndexTTS的零样本语音合成

IndexTTS 项目采用模块化设计&#xff0c;将 BPE 文本编码、GPT 单元预测、dVAE 语音特征抽取和 BigVGAN 音频生成串联为完整的语音合成流程。系统通过统一的配置文件和模型目录规范&#xff0c;实现高效的文本到语音转换&#xff0c;支持命令行与 Web 界面双模式操作&#xff…

基于go-zero的短链生成系统

go-zero框架 gozero&#xff08;又称go-zero&#xff09;是一款由知名开发者kevwan设计的Golang微服务框架&#xff0c;专注于高性能、低延迟和易用性。其核心目标是简化分布式系统的开发&#xff0c;提供开箱即用的工具链&#xff0c;涵盖API网关、RPC服务、缓存管理、数据库…

Linux-修改线上MariaDB服务端口号

准备工作&#xff08;很重要&#xff01;&#xff01;&#xff01;&#xff09;&#xff1a; 提前做好Linux服务器快照 提前做好数据库数据备份 1. 修改配置文件 首先&#xff0c;我们需要找到MariaDB的配置文件。通常情况下&#xff0c;这个文件位于以下位置&#xff1a;…

Spring Cloud 微服务(负载均衡策略深度解析)

&#x1f4cc; 摘要 在微服务架构中&#xff0c;负载均衡是实现高可用、高性能服务调用的关键机制之一。Spring Cloud 提供了基于客户端的负载均衡组件 Ribbon&#xff0c;结合 Feign 和 OpenFeign&#xff0c;实现了服务间的智能路由与流量分配。 本文将深入讲解 Spring Clo…

HTML/CSS基础

1.html:超文本标记语言。它是一种标识性的语言&#xff0c;非编程语言&#xff0c;不能使用逻辑运算。通过标签将网络上的文本格式进行统一&#xff0c;使用分散网络资源链接为一个逻辑整体&#xff0c;属于标记语言。 超文本&#xff1a;就是指页面内可以包含图片&#xff0…

C# 事件驱动编程的核心:深度解析发布者_订阅者模式

适用场景&#xff1a;GUI交互、消息队列、微服务通信等需要解耦事件生产与消费的系统 &#x1f9e9; 模式核心组件解析 发布者&#xff08;Publisher&#xff09; 作用&#xff1a;定义事件并管理订阅者列表关键行为&#xff1a; 提供和-运算符注册/注销订阅者通过Invoke()方…

华为云Flexus+DeepSeek征文 | 从零开始搭建Dify-LLM应用开发平台:华为云全流程单机部署实战教程

华为云FlexusDeepSeek征文 | 从零开始搭建Dify-LLM应用开发平台&#xff1a;华为云全流程单机部署实战教程 前言一、华为云Dify-LLM平台介绍1. Dify-LLM解决方案简介2. Dify-LLM解决方案地址3. Dify-LLM单机架构介绍4. 预估成本说明 二、华为云Maas平台介绍1. 华为云ModelArts …

oracle集合三嵌套表(Nested Table)学习

嵌套表 嵌套表(Nested Table)是Oracle中的一种集合数据类型&#xff0c;它允许在表中存储多值属性&#xff0c;类似于在表中嵌套另一个表。 嵌套表具有以下特点&#xff1a; 是Oracle对象关系特性的一部分 可以看作是一维数组&#xff0c;没有最大元素数量限制 存储在单独…

Python学习之——单例模式

Python学习之——单例模式 参考1 利用__metaclass__实现单例super的用法class Singleton(type)元类 2 重载__new__方法实现单例模式3 利用装饰器实现单例考虑一个类如果继承一个单例类的问题 参考 python之metaclasssingleton&#xff08;一&#xff09; python之metaclasssin…

【Linux】U-boot常用命令总结

U-Boot 是嵌入式系统中常用的引导加载程序&#xff08;bootloader&#xff09;&#xff0c;它提供了一套命令行接口&#xff0c;用于调试、加载操作系统镜像以及进行硬件测试等操作。 1、变量操作命令 这些命令用于管理 U-Boot 的环境变量。 命令功能说明setenv name value设…

【Linux】不小心又创建了一个root权限账户,怎么将它删除?!

一.前言 今天在学习linux提权的时候&#xff0c;把新建的一个普通账户权限提升成了root&#xff0c; 当我练习完提权&#xff0c;想要把这个账户删掉的时候。 发现… 好家伙&#xff0c;这个根本删不掉 随后试了各种各样的方法&#xff0c;都不行&#xff0c;后来突然想到是否…

数据结构:数组(Array)

目录 什么是数组&#xff08;Array&#xff09;&#xff1f; &#x1f50d;为什么数组的下标要从 0 开始&#xff1f; 一、内存地址与偏移量的关系&#xff1a;从 0 开始是最自然的映射 二、指针的起点就是第 0 个元素的地址 三、历史原因&#xff1a;BCPL → B → C → …

视频内存太大怎么压缩变小一点?视频压缩的常用方法

视频传生活或者工作中很常见&#xff0c;如发送视频邮件、在线视频播放、视频上传下载等。未压缩的大内存视频文件传输时&#xff0c;不仅会消耗大量的网络带宽资源&#xff0c;还会使传输时间大幅增加。在网速有限的情况下&#xff0c;发送一个几 GB 的未压缩视频可能需要数小…