在这篇文章中,我们将深入探讨如何破解极验滑动验证码中的关键参数 w。我们将通过分析每个请求的参数,逐步拆解并重构代码,以实现对 w 参数的破解。
请求总览
破解极验滑动验证码涉及多个请求及其参数的分析。以下是主要的请求及其作用:
gettype.php:获取核心 JS 文件链接。
get.php:收集浏览器信息并上报,作为无感验证的一部分。
ajax.php:执行无感验证,可能返回需要进行滑块验证。
slide.x.x.x.js:加载滑动验证相关的 JS 文件。
get.php:获取滑动验证所需的基本数据。
ajax.php:执行滑动验证,成功后返回 validate。
关键参数
gt:固定值,是极验申请的 ID。
challenge:每次操作返回的新 ID,用于标识行为。
w:加密数据,是验证通过与否的核心参数。
破解 w 参数
破解 w 参数的核心在于理解其生成逻辑,并能够模拟这一过程。我们通过调试和分析代码,逐步破解其组成部分。
观察 w 参数生成过程
通过在代码中搜索 w 参数,并设置断点进行调试,我们可以发现 w 参数由两部分组成,每部分有独特的构造逻辑。我们需要分别破解这两部分。
破解 u 参数
u 参数的生成涉及一个随机值和加密过程。以下是生成 u 参数的代码:
javascript
function getRandomTextHelper() {
const helper = () => ((65536 * (1 + Math.random())) | 0).toString(16).substring(1);
return helper() + helper() + helper() + helper();
}
var oldRandomText = getRandomTextHelper();
function getRandomText(needRefresh) {
if (needRefresh) {
oldRandomText = getRandomTextHelper();
}
return oldRandomText;
}
function getU() {
var e = new U().encrypt(getRandomText());
while (!e || 256 !== e.length) e = new U().encrypt(getRandomText(true));
return e;
}
var U = ...; // U 对象的定义
破解 h 参数
h 参数的生成相对复杂,需要结合多个步骤来完成。
l 参数
l 参数是 h 参数的一部分,它的生成涉及加密和序列化操作:
javascript
function getL({ c, s, trace, challenge }) {
const o = {
lang: 'zh-cn',
userresponse: H(trace.at(-1)[0], challenge),
passtime: trace.at(-1)[2],
imgload: Math.floor(Math.random() * 50 + 30),
aa: getAA(encodeTrace(trace), c, s),
ep: {
v: '7.8.8',
$_BIQ: false,
me: true,
tm: -1,
td: -1,
},
};
return V.encrypt(stringify(o), getRandomText());
}
function getRandomText() {
const helper = () => ((65536 * (1 + Math.random())) | 0).toString(16).substring(1);
return helper() + helper() + helper() + helper();
}
var V = ...; // V 对象的定义
o 参数
o 参数包含了滑动验证的各个细节信息:
lang:语言,可以设为 'zh-cn'。
userresponse:滑动距离的加密结果。
passtime:滑动验证的耗时。
imgload:验证码图片的加载时间。
aa:滑动轨迹的加密结果。
ep:额外参数。
构造滑动轨迹
滑动轨迹是一个包含多个记录的小数组的数组,每个小数组记录一次滑动的 x 坐标、y 坐标和时间:
javascript
function generateSlideTrace(distance) {
const trace = [
[random(-50, -10), random(-50, -10), 0],
[0, 0, 0],
];
let t = random(50, 100);
let lastX = 0;
let lastY = 0;
let lastYCount = 0;
const count = 30 + Math.floor(distance / 2);
for (let i = 0; i < count; i++) {
const x = Math.round(i === count ? 1 : (1 - Math.pow(2, (-10 * i) / count)) * distance);
t += random(10, 20);
if (x === lastX) continue;
lastYCount += 1;
if (lastYCount > random(5, 10)) {
lastYCount = 0;
lastY = random(-2, 2);
}
lastX = x;
trace.push([x, lastY, t]);
}
return trace;
}
合并 u 和 h
最终,我们需要将两个部分合并生成 w 参数。以下是完整的代码实现:
javascript
export function getSlideW(props) {
return getSlideLeft(props) + getRight();
}
function getSlideLeft(props) {
return encodeLeft(getL(props));
}
function getL({ c, s, trace, challenge }) {
const o = {
lang: 'zh-cn',
userresponse: H(trace.at(-1)[0], challenge),
passtime: trace.at(-1)[2],
imgload: Math.floor(Math.random() * 50 + 30),
aa: getAA(encodeTrace(trace), c, s),
ep: {
v: '7.8.8',
$_BIQ: false,
me: true,
tm: -1,
td: -1,
},
};
return V.encrypt(stringify(o), getRandomText());
}
function getRight() {
var e = new U().encrypt(getRandomText());
while (!e || 256 !== e.length) e = new U().encrypt(getRandomText(true));
return e;
}
function getRandomTextHelper() {
const helper = () => ((65536 * (1 + Math.random())) | 0).toString(16).substring(1);
return helper() + helper() + helper() + helper();
}
var oldRandomText = getRandomTextHelper();
function getRandomText(needRefresh) {
if (needRefresh) {
oldRandomText = getRandomTextHelper();
}
return oldRandomText;
}
// 下面的是从 slide 文件里抠出来的逻辑
function stringify(t, e, n) { ... }
function H(t, e) { ... }
function getAA(t, e, n) { ... }
function encodeTrace(arr) { ... }
function encodeLeft(l) { ... }
var U = ...;
var V = ...;