爬虫反爬:JS逆向实战练习1

2023-12-01 02:40

本文主要是介绍爬虫反爬:JS逆向实战练习1,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 简介

快速优雅地学会JS逆向,就需要从实战开始,接下来我会提供Base64加密的原网址以及接口参数,从实战中学习如何下断点、抠代码、本地运行等操作,此技术一般用于爬虫上,是一个爬虫程序猿进阶的必经之路。

2. 实战信息

网址:
aHR0cHM6Ly9mYW55aS5iYWlkdS5jb20vP2FsZHR5cGU9MTYwNDcjYXV0by96aA==
接口:
aHR0cHM6Ly9mYW55aS5iYWlkdS5jb20vdjJ0cmFuc2FwaT9mcm9tPXpoJnRvPWVu
逆向参数:

  • sign:232427.485594
  • token:3dde9ef10b6f6ae310af38e6f1bd564f

3. 实战流程

3.1抓包找接口

首先,进入页面按F12,打开控制面板,调到Network板块后在翻译处写入需要翻译的信息(我这里输入的是“你好”)触发网络请求,打开请求面板查看该请求的具体信息。
在这里插入图片描述

3.1.1 General

请求信息

  • URL:请求API地址
  • Method:请求方式GET/POST
3.1.2 Request headers

除了自定义请求头参数,其余Host、Origin、Referer一般为爬虫必须参数,Cookie看站点是否有对其校验,如果有特殊的自定义参数一般也为爬虫需要。

  • Acs-Token:自定义的校验参数
  • Cookie:客户端缓存信息
  • Host:域名
  • Origin:来源信息
  • Referer:防止跨站攻击

3.2 查找加密参数

在这里插入图片描述
从上图中可以看到sign和token有加密嫌疑,所以目标就暂定为对这两个参数进行一个简单逆向。

3.3 断点分类

下断多种方法:

  • 元素下断
  • 事件下断
  • XHR下断
  • 搜索下断

3.4 学会快速下断

这里主要展示XHR下断和搜索下断,在此比较好用。
XHR断点:首先复制请求链接?前的部分路径,这里是/v2transapi,到Source下的XHR断点处下断,回车输入新翻译内容即可触发。
在这里插入图片描述
在这里插入图片描述
可以看到断点断在了send()方法的调用处,在Call stack中查看函数方法的调用栈,目前代码可读性太低,我们需要对其进行格式化查看,就需要左下角的此按钮。
在这里插入图片描述
在调用栈中查看自己所需参数的作用域,首先在调用栈中找到加密后的参数位置,然后往前推,直到找到加密的方法,此处直接展示寻找结果。
在这里插入图片描述
如上图,作用域的位置就看提示的参数数据即可,windows下如果使用Chrome可以用ctrl键触发,这里查看的是ajax()的方法栈,同时我们可以找到加密后的结果,鼠标放到函数参数里可以看到,我们也可以直接从Scope中查看然后返回源码找。
在这里插入图片描述
此处左右两侧都可以看到一个加密后的sign和token数据,就往前找调用的方法栈即可。
在这里插入图片描述
再往前一个方法栈就可以看到,headers里面必须有个"Acs-Token"的参数,data中的数据来源是b,往上看b是一个对象,请求内容在对象里,sign:x(n)|token:window.common.token这两个参数是这样获取的。
我们可以直接知道x(n)就是sign的加密函数,token存在window.common下。
在这里插入图片描述
鼠标放置在x函数上会给一个跳转提示,点击index_61616b2.js有利于我们直接找到函数调用的方法,我们可以直接去抠代码本地运行,n鼠标放上去可以发现就是"你好",将断点打在8782行,重新键入更改断点作用域。
在这里插入图片描述
测试确认x(n)方法确实是sign获取的方法位置,进入函数。
在这里插入图片描述
此处可以直接抠到本地用Node运行,代码调用可以看到调用了两个作用域里的函数,所以对代码抠全,进行部分改写,此处直接粘代码。

function a(r) {if (Array.isArray(r)) {for (var o = 0, t = Array(r.length); o < r.length; o++)t[o] = r[o];return t}return Array.from(r)
}
function n(r, o) {for (var t = 0; t < o.length - 2; t += 3) {var a = o.charAt(t + 2);a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a),a = "+" === o.charAt(t + 1) ? r >>> a : r << a,r = "+" === o.charAt(t) ? r + a & 4294967295 : r ^ a}return r
}
function e(r) {var o = r.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);if (null === o) {var t = r.length;t > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(t / 2) - 5, 10) + r.substr(-10, 10))} else {for (var e = r.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), C = 0, h = e.length, f = []; h > C; C++)"" !== e[C] && f.push.apply(f, a(e[C].split(""))),C !== h - 1 && f.push(o[C]);var g = f.length;g > 30 && (r = f.slice(0, 10).join("") + f.slice(Math.floor(g / 2) - 5, Math.floor(g / 2) + 5).join("") + f.slice(-10).join(""))}var u = void 0, l = "" + String.fromCharCode(103) + String.fromCharCode(116) + String.fromCharCode(107);u = null !== i ? i : (i = window[l] || "") || "";for (var d = u.split("."), m = Number(d[0]) || 0, s = Number(d[1]) || 0, S = [], c = 0, v = 0; v < r.length; v++) {var A = r.charCodeAt(v);128 > A ? S[c++] = A : (2048 > A ? S[c++] = A >> 6 | 192 : (55296 === (64512 & A) && v + 1 < r.length && 56320 === (64512 & r.charCodeAt(v + 1)) ? (A = 65536 + ((1023 & A) << 10) + (1023 & r.charCodeAt(++v)),S[c++] = A >> 18 | 240,S[c++] = A >> 12 & 63 | 128) : S[c++] = A >> 12 | 224,S[c++] = A >> 6 & 63 | 128),S[c++] = 63 & A | 128)}for (var p = m, F = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(97) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(54)), D = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(51) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(98)) + ("" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(102)), b = 0; b < S.length; b++)p += S[b],p = n(p, F);return p = n(p, D),p ^= s,0 > p && (p = (2147483647 & p) + 2147483648),p %= 1e6,p.toString() + "." + (p ^ m)
}
console.log(e('你好'))

调试发现报错(命令行输入node xx.js):
在这里插入图片描述
因为本地环境没有window对象,因为l是一步计算的到为固定值,我们需要获取到window[l]的值,就先获取l的值,鼠标放在l上即可获取因为此算法为固定值,获取到l = “gtk”,所以此处的window[l] === window[“gtk”],我们通过搜索ctrl+shift+f/Command+shift+f调出搜索面板,通过搜索(window[“gtk”]|window[‘gtk’]|window.gtk)这三个方法去查找,就看此处调用哪个,某度翻译用的window.gtk,是一个固定值。
在这里插入图片描述
直接抠值替换源码里的window[l]即可,调试发现i还是undefined,所以在变量上定义一个i的初始化方法即可。
在这里插入图片描述
再次测试调用,对比浏览器请求参数。
在这里插入图片描述
在这里插入图片描述
结果一致就说明获取成功了,获取到sign了还有个token值没有获取,这个又怎么获取呢。上面我们发现是window.common.token产生,通过搜索(window[“common”]|window[‘common’]|window.common)先找父节点值,这里用window[‘common’]即可搜到,发现common是页面定义的变量,刷新页面发现token值写死我们这里就直接获取到了token值。
在这里插入图片描述

4. JS完整代码

var token = "3dde9ef10b6f6ae310af38e6f1bd564f"function a(r) {if (Array.isArray(r)) {for (var o = 0, t = Array(r.length); o < r.length; o++)t[o] = r[o];return t}return Array.from(r)
}
function n(r, o) {for (var t = 0; t < o.length - 2; t += 3) {var a = o.charAt(t + 2);a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a),a = "+" === o.charAt(t + 1) ? r >>> a : r << a,r = "+" === o.charAt(t) ? r + a & 4294967295 : r ^ a}return r
}
function e(r) {var o = r.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);if (null === o) {var t = r.length;t > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(t / 2) - 5, 10) + r.substr(-10, 10))} else {for (var e = r.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), C = 0, h = e.length, f = []; h > C; C++)"" !== e[C] && f.push.apply(f, a(e[C].split(""))),C !== h - 1 && f.push(o[C]);var g = f.length;g > 30 && (r = f.slice(0, 10).join("") + f.slice(Math.floor(g / 2) - 5, Math.floor(g / 2) + 5).join("") + f.slice(-10).join(""))}var u = void 0, l = "" + String.fromCharCode(103) + String.fromCharCode(116) + String.fromCharCode(107);var i = null;u = null !== i ? i : (i = "320305.131321201" || "") || "";for (var d = u.split("."), m = Number(d[0]) || 0, s = Number(d[1]) || 0, S = [], c = 0, v = 0; v < r.length; v++) {var A = r.charCodeAt(v);128 > A ? S[c++] = A : (2048 > A ? S[c++] = A >> 6 | 192 : (55296 === (64512 & A) && v + 1 < r.length && 56320 === (64512 & r.charCodeAt(v + 1)) ? (A = 65536 + ((1023 & A) << 10) + (1023 & r.charCodeAt(++v)),S[c++] = A >> 18 | 240,S[c++] = A >> 12 & 63 | 128) : S[c++] = A >> 12 | 224,S[c++] = A >> 6 & 63 | 128),S[c++] = 63 & A | 128)}for (var p = m, F = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(97) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(54)), D = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(51) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(98)) + ("" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(102)), b = 0; b < S.length; b++)p += S[b],p = n(p, F);return p = n(p, D),p ^= s,0 > p && (p = (2147483647 & p) + 2147483648),p %= 1e6,p.toString() + "." + (p ^ m)
}
// console.log(e('你好'))
// console.log(token)// 获取Sign
function getSign(str){return e(str)
}
// 获取Token
function getToken(){return token
}
// Node导出方法方式
module.exports = {getSign,getToken
}

这篇关于爬虫反爬:JS逆向实战练习1的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Spring AI与DeepSeek实战一之快速打造智能对话应用

《SpringAI与DeepSeek实战一之快速打造智能对话应用》本文详细介绍了如何通过SpringAI框架集成DeepSeek大模型,实现普通对话和流式对话功能,步骤包括申请API-KEY、项目搭... 目录一、概述二、申请DeepSeek的API-KEY三、项目搭建3.1. 开发环境要求3.2. mav

Python与DeepSeek的深度融合实战

《Python与DeepSeek的深度融合实战》Python作为最受欢迎的编程语言之一,以其简洁易读的语法、丰富的库和广泛的应用场景,成为了无数开发者的首选,而DeepSeek,作为人工智能领域的新星... 目录一、python与DeepSeek的结合优势二、模型训练1. 数据准备2. 模型架构与参数设置3

Node.js net模块的使用示例

《Node.jsnet模块的使用示例》本文主要介绍了Node.jsnet模块的使用示例,net模块支持TCP通信,处理TCP连接和数据传输,具有一定的参考价值,感兴趣的可以了解一下... 目录简介引入 net 模块核心概念TCP (传输控制协议)Socket服务器TCP 服务器创建基本服务器服务器配置选项服

mac安装nvm(node.js)多版本管理实践步骤

《mac安装nvm(node.js)多版本管理实践步骤》:本文主要介绍mac安装nvm(node.js)多版本管理的相关资料,NVM是一个用于管理多个Node.js版本的命令行工具,它允许开发者在... 目录NVM功能简介MAC安装实践一、下载nvm二、安装nvm三、安装node.js总结NVM功能简介N

Java实战之利用POI生成Excel图表

《Java实战之利用POI生成Excel图表》ApachePOI是Java生态中处理Office文档的核心工具,这篇文章主要为大家详细介绍了如何在Excel中创建折线图,柱状图,饼图等常见图表,需要的... 目录一、环境配置与依赖管理二、数据源准备与工作表构建三、图表生成核心步骤1. 折线图(Line Ch

Python爬虫selenium验证之中文识别点选+图片验证码案例(最新推荐)

《Python爬虫selenium验证之中文识别点选+图片验证码案例(最新推荐)》本文介绍了如何使用Python和Selenium结合ddddocr库实现图片验证码的识别和点击功能,感兴趣的朋友一起看... 目录1.获取图片2.目标识别3.背景坐标识别3.1 ddddocr3.2 打码平台4.坐标点击5.图

Java使用Tesseract-OCR实战教程

《Java使用Tesseract-OCR实战教程》本文介绍了如何在Java中使用Tesseract-OCR进行文本提取,包括Tesseract-OCR的安装、中文训练库的配置、依赖库的引入以及具体的代... 目录Java使用Tesseract-OCRTesseract-OCR安装配置中文训练库引入依赖代码实

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2

JS 实现复制到剪贴板的几种方式小结

《JS实现复制到剪贴板的几种方式小结》本文主要介绍了JS实现复制到剪贴板的几种方式小结,包括ClipboardAPI和document.execCommand这两种方法,具有一定的参考价值,感兴趣的... 目录一、Clipboard API相关属性方法二、document.execCommand优点:缺点: