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

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

本文章更新部分有误以更新,抱歉!!!

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

  • 无感(fullpage.js)无感分析
  • 滑动(sense.js)滑动分析
  • 点选(click.js)点选and整合

总体来说就分为这三种,当前了点选还分了文字,语序,图标,九空格,空间其略有变化的九宫格其他的一模一样可以使用同一套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还原可以去看看相关的文章(我这里就不介绍了)。


这里就是我们刚才看到的那个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那里,去还原看看。

原来就是_对象属性生成的呀。


看看这几个值都是什么吧。

进去执行看看,这是使用鼠标的轨迹加密了,这个轨迹不能写死,不然只能成功一次。

e值加密的方法如下

function encode_fIeV(e) {var i = "()*,-./0123456789:?@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~";function SwsR(e) {var t = "";var r = e["length"] / 6;for (var n = 0; n < r; n = n + 1) {t += i["charAt"](parseInt(e["slice"](n * 6, (n + 1) * 6), 2));}return t;}function t(e) {var t = [];var r = [];var n = [];var i = [];for (var o = 0, a = e["length"]; o < a; o = o + 1) {var s = e[o];var _ = s["length"];t["push"](s[0]);r["push"](_ === 2 ? s[1] : s[2]);if (_ === 3) {n["push"](s[1][0]);i["push"](s[1][1]);}}var c = g(t);var l = YlIj(r, false);var u = YlIj(n, true);var f = YlIj(i, true);var p = c + l + u + f;var d = p["length"];if (d % 6 != 0) {p += Tr_F(0, 6 - d % 6);}return SwsR(p);}var p = {"move": 0,"down": 1,"up": 2,"scroll": 3,"focus": 4,"blur": 5,"unload": 6,"unknown": 7};var d = 8;function Tr_F(e, t) {var r = e["toString"](2);var n = r["length"];var i = "";for (var o = n + 1; o <= t; o = o + 1) {i += "0";}r = i + r;return r;}function g(e) {var t = [];var r = e["length"];var n = 0;while (n < r) {var i = e[n];var o = 0;while (true) {if (o >= 1 << 4) {break;}var a = n + o + 1;if (a >= r) {break;}var s = e[a];if (s !== i) {break;}o += 1;}n = n + 1 + o;var _ = p[i];if (o != 0) {t["push"](_ | d);t["push"](o - 1);} else {t["push"](_);}}var c = Tr_F(r | 32768, 16);var l = "";for (var u = 0, f = t["length"]; u < f; u = u + 1) {l += Tr_F(t[u], 4);}return c + l;}function UyHc(e, t) {var r = [];for (var n = 0, i = e["length"]; n < i; n = n + 1) {r["push"](t(e[n]));}return r;}function VySC(e, t) {var r = [];UyHc(e, function (e) {if (t(e)) {r["push"](e);}});return r;}function WaSD(e) {var t = (1 << 15) - 1;e = UyHc(e, function (e) {if (e > t) {return t;} else if (e < -t) {return -t;}return e;});var r = e["length"];var n = 0;var i = [];while (n < r) {var o = 1;var a = e[n];var s = Math["abs"](a);while (true) {if (n + o >= r) {break;}if (e[n + o] !== a) {break;}if (s >= 127 || o >= 127) {break;}o += 1;}if (o > 1) {i["push"]((a < 0 ? 49152 : 32768) | o << 7 | s);} else {i["push"](a);}n += o;}return i;}function XyMI(e, t) {if (e === 0) {return 0;}return Math["log"](e) / Math["log"](t);}function YlIj(e, t) {e = WaSD(e);var r = [],n = [],i;UyHc(e, function (e) {var t = Math["ceil"](XyMI(Math["abs"](e) + 1, 16));if (t === 0) {t = 1;}r["push"](Tr_F(t - 1, 2));n["push"](Tr_F(Math["abs"](e), t * 4));});var o = r["join"]("");var a = n["join"]("");if (!t) {i = "";} else {i = UyHc(VySC(e, function (e) {return e != 0 && e >> 15 != 1;}), function (e) {return e < 0 ? "1" : "0";})["join"]("");}var s = Tr_F(e["length"] | 32768, 16);return s + o + a + i;}return t(e);
}
function RandomNum(minNum, maxNum, decimalNum) {var max = 0,min = 0;minNum <= maxNum ? (min = minNum, max = maxNum) : (min = maxNum, max = minNum);switch (arguments.length) {case 1:return Math.floor(Math.random() * (max + 1));break;case 2:return Math.floor(Math.random() * (max - min + 1) + min);break;case 3:return (Math.random() * (max - min) + min).toFixed(decimalNum);break;default:return Math.random();break;}
}
var sliding_len = RandomNum(60, 100),start_x = RandomNum(600, 1000),start_y = RandomNum(300, 350),init_x = RandomNum(-70, -40),trajectory = new Array();trajectory.push(['move', [start_x, start_y], 0]);for (var s = 0; sliding_len > s; s++) {init_x += RandomNum(5, 7);if (Math.abs(init_x) >= 10) {trajectory.push(['move', [init_x, RandomNum(-7, 7)], RandomNum(10, 25)])} else {trajectory.push(['move', [0 + RandomNum(-1, 2), RandomNum(-3, 5)], RandomNum(10, 20)])init_x = 0}if (s === sliding_len - 1) {trajectory.push(["down", [0, 0], RandomNum(2, 4)]);trajectory.push(["up", [0, 0], RandomNum(60, 100)]);}
}e = encode_fIeV(trajectory);

这四个值就只检测了e的值其他的写死就好了,像这样↓↓↓

还有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随机数生成的。

对于其他的函数什么的你就缺什么补什么就行了,直接找到那个函数,在找到它相关的基本上没啥问题。

后面会更新有滑动的和点选的。
如有错误的地方请及时联系我-

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

  1. PAT 1089 狼人杀-简单版(20 分)(代码+测试点分析)

    1089 狼人杀-简单版(20 分) 以下文字摘自<灵机一动·好玩的数学>:"狼人杀"游戏分为狼人.好人两大阵营.在一局"狼人杀"游戏中,1 号玩家 ...

  2. 手机信号测试软件 电脑版,PC端和移动端通杀 神器SpeedTest_网络设备无线网络和技术-中关村在线...

    PC端和移动端通杀 神器SpeedTest 说到测试网速,第一推荐的就是"SpeedTest"这个软件,使用起来也非常简单,能够快速准确的测试出使用者的宽带速率.并且"S ...

  3. android安卓手机变身无线网卡,实现“畅无线“电脑版”台式机笔记本通杀

    转载http://blog.sina.com.cn/s/blog_6088f2be01012p8b.html 先上附件, WIN732位或XP及以下 http://dl.dbank.com/c0ge4 ...

  4. js版palppy brid代码_从 JS 引擎到 JS 运行时(上)

    V8 和 Node.js 的关系,是许多前端同学们所津津乐道的--浏览器里的语言,又兼容了浏览器外的环境,两份快乐重叠在一起.而这两份快乐,又带来了更多的快乐--但你有没有想过,这两份快乐到底是如何重 ...

  5. 通用滑块识别-通杀滑块

    遇到滑块问题 在写爬虫的时候,经常会遇到滑块问题,很多次都想过尝试如何攻破滑块,但是每次都没成功,除了最开始的极验滑块,当时通过原图和滑块图的对比,能够得出缺口坐标,但是随着极验.网易.腾讯滑块的更新 ...

  6. Python Java 滑块识别-通杀滑块

    遇到滑块问题 在写爬虫的时候,经常会遇到滑块问题,很多次都想过尝试如何攻破滑块,但是每次都没成功,除了最开始的极验滑块,当时通过原图和滑块图的对比,能够得出缺口坐标,但是随着极验.网易.腾讯滑块的更新 ...

  7. python爬虫逆向|某版本sojson加密逻辑分析与通杀

    网站链接 aHR0cDovL3d3dy5wYmMuZ292LmNuL2dvdXRvbmdqaWFvbGl1LzExMzQ1Ni8xMTM0NjkvaW5kZXguaHRtbA== (base64解密后 ...

  8. JS版剑指offer

    JS版剑指offer JS刷题总结 牛客网 递归算法的时间复杂度:递归的总次数*每次递归的数量. 递归算法的空间复杂度:递归的深度*每次递归创建变量的个数. 二叉树(12道): 剑指Offer(4): ...

  9. /plus/recommend.php sql注入漏洞,DedeCMS 全版本通杀SQL注入漏洞利用代码及工具 -

    DedeCMS 全版本通杀SQL注入漏洞利用代码及工具 目前官方最新版已修复该漏洞 V5.7.37 GBK正式版20140228常规更新补丁 http://www.dedecms.com/pl/ ht ...

最新文章

  1. 暑假没人带怎么办?还有我们为你推荐论文 | 本周值得读
  2. 在命令行中打开远程端的图形应用程序
  3. php system 执行失败,PHP 执行 system、exec 等函数发生错误
  4. SPOJ MYQ10 (数位DP)
  5. 实例解读什么是Redis缓存穿透、缓存雪崩和缓存击穿
  6. 05-BIO,NIO,AIO几种通讯模式的比较
  7. Android导入第三方类库
  8. apktool + dex2jar + xjad反编译apk文件
  9. The TARGETDIR variable must be provided when invoking this installer的解决方案
  10. SL4A_API翻译贴镜像
  11. rust怎么建柱子_原神慈盐之末任务怎么做?原神钟离传说任务的方碑柱子点亮顺序...
  12. 互联网公司的几种销售模式
  13. 华为手机如何与台式计算机连接不上,华为手机怎样与电脑连接?USB数据线及WLAN无线两种连接电脑方式介绍...
  14. uniapp 打包成安卓app
  15. 设计如下类: 1) 建立一个Point类,表示平面中的一个点;建立一个Line类,表示平面中的一条线端, 内含两个Point类的对象;建立Triangle类,表示一个三角形
  16. 1697_python编程_assertions and exceptions
  17. 华硕X84L无线驱动查找
  18. MATLAB常用命令及函数大全(字母顺序)
  19. Mysql数据库连接池之C3p0的使用
  20. Linux系统上的防火墙命令

热门文章

  1. 怎么样向云服务器上传文件_向云服务器上传文件以及移动到指定文件夹
  2. Linux用户获得超级管理员权限
  3. 拉格朗日四平方和定理
  4. 【基于TensorFlow2.3.0的果蔬识别系统的设计】
  5. 2021-04-19-记录学习linux
  6. 【excel实战】-- 批量提取批注多重区域复制粘贴
  7. 应用JavaFX实现的填字游戏
  8. Java里format什么意思_java String.Format详解
  9. 「2019纪中集训Day23」解题报告
  10. 商业智能助力 银行业数据“挖金”