某验通杀js版,流程各个验证码那对应的js分析,你确定不进来看看(无感)?

你只管努力,剩下的交给天意。

文章只提供学习,如有侵权请立即联系我。

前言
某验官网:官网
总体来说某验的验证码配合js总共分为三套

总体来说就分为这三种,当前了点选还分了文字,语序,图标,九空格,空间其略有变化的九宫格其他的一模一样可以使用同一套js解决。

这篇文章只写无感!!!

ok那就开始吧!!!

在这里插入图片描述

进入我上面提供的官网进来点击只能组合验证如下图:
在这里插入图片描述
咱们先点击一下试试看看效果(这里有可能出现的不是无感的而是滑动多试几次)
在这里插入图片描述

在这里插入图片描述
这里可以看到validate这个值那么没错他就是我们现在需要获取到的值。

ok有目标咱们再看看请求的时候都需要了什么参数
在这里插入图片描述
看来参数挺多的哈gt,challenge,lang,client_type,w,callback,这都啥啊?
在这里插入图片描述
不过我们一眼可以看出来lang,pt,client_type,callback这几个值都是写死的,你可以多尝试几次看看是否一样?

在这里插入图片描述

我知道你尝试了而且确定了是一样,那么我们就不用管它了,来看看gt,challenge,w

我们先来搜索一下吧,看看是不是在其他的请求的返回值里。
在这里插入图片描述
果不其然就在这里,这就是gtchallenge的值了(gt的值是会变得应该是跟ip绑定的,不要以为他不变就是死的)。
在这里插入图片描述

既然找到这个了,那么就剩下一个w了。
在这里插入图片描述
搜索之后无果,那么就需要去看他的来源。
在这里插入图片描述
掉头发的又来了。
在这里插入图片描述

在这里插入图片描述
嗯嗯嗯,js大概就是这样(心里存了一万句来着祖安的问候),那咋整啊???

就是得还原呗,怎么还原呢?生整啊?不如先看看代码的结构吧!

整体是一个自执行函数,函数里面有两个函数一个是有四个方法的函数一个是自执行

在这里插入图片描述
可以看到自执行函数里面有很多的这种调用了AENQy函数的DsH方法。

在这里插入图片描述
随便的debugger一下看看这个值是什么。

在这里插入图片描述
给这里打上断点看看
在这里插入图片描述
然后一步步执行看看
在这里插入图片描述
在这里插入图片描述
第0个是不是就是object,那么就是AENQ对象生成了一个很大的数组然后根据不同的下表获取到不同的值,也就达到了混淆的效果了。

那我们怎么整呢?用字符串替换还原?nonono 太难受这写到什么时候了。
推荐使用nodeast,关于ast还原可以去看看相关的文章(我这里就不介绍了)。

在这里插入图片描述

ast还原js代码
这里就是我们刚才看到的那个list需要单独引入进来(const {$_DAIr} = require('./ast_字符还原模型.js');)如下图
在这里插入图片描述
里面写了注释可以很清楚地看到流程 注:(删除套娃节点,以及无用的变量可能会出现问题,因为有的代码可能在eval里执行,表面看起来这个变量没用,但是在eval中使用到的,导致这个变量在全局看起来没有使用,而删除的错误)

如果有这种情况建议直接使用源码的js不用使用还原过后js

// 这是文件流
const fs = require('fs');
// 解析js代码为json格式
const {parse} = require("@babel/parser");
// 根据是json格式的节点来处理json格式的js代码
const traverse = require("@babel/traverse").default;
// 节点的处理类型以及判断等等
const t = require("@babel/types");
// 根据处理好的json格式代码在还原成js代码
const generator = require("@babel/generator").default;
// 读取你的需要操作的js代码
const jscode = fs.readFileSync("./jseval.js", {encoding: "utf-8"});
// 引入你需要还原的js字符串list
const {$_DAIr} = require('./ast_字符还原模型.js');

const ast = parse(jscode);

// 字符串还原
const visitor = {
    CallExpression(path) {
        //加密字符还原如_DAED(39)还原成真实的字符串
        const {callee, arguments} = path.node;
        if (!t.isIdentifier(callee) || arguments.length !== 1) return;
        if (!t.isNumericLiteral(arguments[0])) return;

        path.replaceWith(t.valueToNode($_DAIr(arguments[0].value).toString()))
    },
    StringLiteral(path) {
        // 还原"\u0024\u005f\u0049\u0042\u0052" unicode对节点extra删除还原 注:中文需要在generator代码还原时添加opts = {jsescOption: {"minimal": true}}
        delete path.node.extra
    }

};

// 删除无用的js代码
const remove = {
    VariableDeclarator(path) {
        //对于没有引用变量删除
        const {id} = path.node;
        const binding = path.scope.getBinding(id.name);
        if (!binding || binding.constantViolations.length > 0) {
            return;
        }
        if (binding.referencePaths.length === 0) {
            path.remove();
        }
    },
    BlockStatement(path) {
        //删除没必要的套娃节点
        if (path.node.body.length < 3) {
            return
        }
        const path_var = path.node.body[0];
        const path_function = path.node.body[1];
        if (path_var == null || !t.isVariableDeclaration(path_var) || !path_var.hasOwnProperty('declarations')) {
            return
        }
        if (path_var.declarations === undefined && path_var.declarations.length > 2) {
            return
        }
        if (!t.isMemberExpression(path_var.declarations[0].init)) {
            return
        }
        if (path_function == null && !t.isExpressionStatement(path_function)) {
            return
        }
        delete path.node.body[0];
        delete path.node.body[1];
    }
};

traverse(ast, visitor);
traverse(ast, remove);

// 在还原回js
let {code} = generator(ast, opts = {jsescOption: {"minimal": true}});

//写入新的js
fs.writeFile('sense.js', code, (err) => {
});

还原过后的代码就成这个样子喽、结构看起来很清晰,我们在搜索就可以搜索到我们需要用到的js代码中了。
在这里插入图片描述

在这里插入图片描述
然后我们找到跟我们刚才获取gt,challenge,lang,client_type,w,callback样子很像的那个位置在游览器上断点,如下图
在这里插入图片描述
在这里我们就可以看到w值了,你以为这样就完了吗?

张:汤师爷你给我解释解释什么tm的是惊喜!
汤:惊喜嘛,就是惊喜。
张:汤师爷解释解释什么tm的叫tm的惊喜
黄:惊喜就是这个并不是我们要找validate的参数。
汤:惊喜就是还有一个w值需要找。

在这里插入图片描述
对不起,这才是刚开始。

你会发现我们获取的这请求的值并不是我们想要的,而是get.php请求的返回值。
在这里插入图片描述
我们接着看获取到validate那个请求的页面。
在这里插入图片描述
看到这里点进去给每一个打debugger,测试看看它请求这个页面的时候到底是走了哪一步。

第一个是这个函数打上debugger测试,是否走了这里。
在这里插入图片描述
然而并没有、
在这里插入图片描述
在这里插入图片描述
再看第二个
在这里插入图片描述
在点击提交,会发现debugger住了。在这里插入图片描述

在这里插入图片描述
会发现s的值里面就是我们需要找的在这里插入图片描述

在这里插入图片描述
ok这里查看调用栈看看这个变量是在哪里是哪生成的。

在这里插入图片描述
这里发现还在上面,我们继续找。
在这里插入图片描述
到这里发现值是从这里来的。
**加粗样式**
继续我们发现原来就是r这个值,不过这是空的那应该就是eval这里做了什么不为人知的事情了,我们在这里debugger看看他到底做了什么。
在这里插入图片描述
ok,一二三四再来一次。
在这里插入图片描述
我们打好断点后,再次点击,发现直接debugger住了,好我们进去看看。
在这里插入图片描述
我们发现这里生成了gxjn这个变量值。
在这里插入图片描述
我们在进入第二个eval里看看,他做了什么。
在这里插入图片描述
没错这个值就在第二个eval里,看看我们看到的这个值是不是我们想要的w
在这里插入图片描述
果然没错,就在这里。
在这里插入图片描述

在这里插入图片描述
好,到了这里,我们就需要再去还原还原第二个eval代码看看,里面到底做了什么,还原完成代码如下图(可以手动删除无用的for循环和switch and case看起来会更清晰)。
在这里插入图片描述
好了,删除完成的代入如下,基本上就很清晰了,我们先去看看gxjn这个值是怎么来的。在这里插入图片描述
直接找到第一个eval那里,去还原看看。
在这里插入图片描述
原来就是_对象属性生成的呀。
在这里插入图片描述

在这里插入图片描述
看看这几个值都是什么吧。
在这里插入图片描述

进去执行看看,这是使用鼠标的轨迹加密了,不过这个轨迹可以写死就行了。
在这里插入图片描述
这四个值直接写死某验并没有检测。
在这里插入图片描述
在这里插入图片描述
还有i的值就是我们获取到的那个get.php这个请求里面的参数,按照get.php返回值进行修改就可以了(这个aeskey不是get.php里面的但是是重点,后面我会说到)继续找吧,其他的值应该没什么太难的了直接对应写上就行,我们继续看第二个eval
在这里插入图片描述

可以根据eval2还原的代码看到,我们需要_对象,并排需要他的很多属性,
你可以去找找这些值都可以写死,当前如果是get.php返回值的话直接传进去就行。

var a = [["lang", i["lang"] || "zh-cn"], ["type", "fullpage"], ["tt", tvBD(e, i["c"], i["s"]) || -1], ["light", n || -1], ["s", AWYz(OYFZ["fIeV"](t))], ["h", AWYz(OYFZ["fIeV"](r))], ["hh", AWYz(r)], ["hi", AWYz(_["LJXM"])], ["vip_order", _["vip_order"] || -1], ["ct", _["ct"] || -1], ["ep", _["hFWy"]() || -1], ["passtime", o || -1], ["rp", AWYz(i["gt"] + i["challenge"] + o)]];

小彩蛋:(说一下这个LJXM这个值的由来,他根据lToF里面的hqsa也就是当前页面所有html元素的个数生成的,里面包括了很多如下图,不过LJXM这个值可以直接写死就行没必要非要生成。)
在这里插入图片描述
在这里插入图片描述

重点!!!重点!!!重点!!!还记得我们用获取第一次获取get.php这个请求吗?get.php请求的时候生成了一个aeskey,这个aeskey在你提交ajax.php这个请求的时候你还需要这个aeskey如果两个aeskey不一样就无法解析,所以整体来说就是get.php请求只是给某验了一个aseskey这个值,而ajax.php提交的时候需要用get.php提交的aeskey来解析,这就是aeskey随机数生成的。
在这里插入图片描述
对于其他的函数什么的你就缺什么补什么就行了,直接找到那个函数,在找到它相关的基本上没啥问题。
在这里插入图片描述
后面会更新有滑动的和点选的。
如有错误的地方请及时联系我-

猜你喜欢

转载自blog.csdn.net/qq_38999456/article/details/107905853