极验第四代滑块验证码破解(一):AST还原混淆JS

  • 声明
  • 一、环境安装
  • 二、AST还原混淆JS
    • 1. 需要还原的js代码链接
    • 2. AST还原源码
    • 3. 极验不同js或不同版本还原方式
  • 三、结语
    • *本期文章结束啦,如果对您有帮助,记得收藏加关注哦,后期文章会持续更新 ~~~*

声明

原创文章,请勿转载!

本文内容仅限于安全研究,不公开具体源码。维护网络安全,人人有责。

本文关联文章超链接:

  1. 极验第四代滑块验证码破解(一):AST还原混淆JS
  2. 极验第四代滑块验证码破解(二):滑块缺口识别
  3. 极验第四代滑块验证码破解(三):滑块轨迹构造
  4. 极验第四代滑块验证码破解(四):请求分析及加密参数破解

首先,极验第四代验证码加密方式和极验第三代差不多。所以,有看过我之前极验三系列破解方式的小伙伴,破解起来还是比较轻松的。
本系列文章为极验第四代滑块验证码破解,内容会对比极验三代的破解过程,会有些冗余,但很细致,小伙伴们仔细学习哦。

一、环境安装

环境安装,请查看极验三破解链接:极验滑块验证码破解与研究(一):AST还原混淆JS

二、AST还原混淆JS

注意:极验三代、四代js代码混淆方式一模一样,所以用极验三的AST还原函数改一下即可。
AST还原函数详解,请查看极验三破解链接:极验滑块验证码破解与研究(一):AST还原混淆JS

1. 需要还原的js代码链接

https://static.geetest.com/v4/static/v1.4.4/js/gcaptcha4.js

2. AST还原源码

const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
const fs = require("fs");// #######################################
// 还原需要用到的js源码
// #######################################
khCTZ.$_AY = function() {// 从gcaptcha4.js源码中抠出来
}();
khCTZ.$_BS = function() {// 从gcaptcha4.js源码中抠出来
}();
khCTZ.$_Cl = function() {// 从gcaptcha4.js源码中抠出来
};
khCTZ.$_DX = function() {// 从gcaptcha4.js源码中抠出来
};
function khCTZ() {}// #######################################// #######################################
// AST解析函数
// #######################################
// 删除节点中的extra属性(二进制、Unicode等编码 -> utf-8)
function replace_unicode(path) {let node = path.node;if (node.extra === undefined)return;delete node.extra;
}// 定义一个全局变量,存放待替换变量名
let name_array = [];function get_name_array(path) {let {kind, declarations} = path.nodeif (kind !== 'var'|| declarations.length !== 3|| declarations[0].init === null|| declarations[0].init.property === undefined)return;if (declarations[0].init.property.name !== "$_Cl")return;// 获取待替换节点变量名let name1 = declarations[0].id.name// 获取待输出变量名let name2 = declarations[2].id.name// 将变量名存入数组name_array.push(name1, name2)// 删除下一个节点path.getNextSibling().remove()// 删除下一个节点path.getNextSibling().remove()// 删除path节点path.remove()
}function replace_name_array(path) {let {callee, arguments} = path.nodeif (callee === undefined || callee.name === undefined)return;// 不在name_array中的节点不做替换操作if (name_array.indexOf(callee.name) === -1)return;// 调用khCTZ.$_Cl函数获取结果let value = khCTZ.$_Cl(arguments[0].value);// 创建节点并替换结果let string_node = t.stringLiteral(value)path.replaceWith(string_node)
}function replace_$_Cl(path) {let {arguments, callee} = path.node// 解析arguments参数if (arguments.length !== 1) return;if (arguments[0].type !== 'NumericLiteral') return;// 解析calleeif (callee.type !== 'MemberExpression') return;let {object, property} = callee;if (object.type !== 'Identifier' || property.type !== 'Identifier') return;if (property.name === '$_Cl') {// 计算值let value = khCTZ.$_Cl(arguments[0].value);// 创建节点并替换let string_node = t.stringLiteral(value)path.replaceWith(string_node)}
}// 控制流平坦化
function replace_ForStatement(path) {var node = path.node;// 获取上一个节点,也就是VariableDeclarationvar PrevSibling = path.getPrevSibling();// 判断上个节点的各个属性,防止报错if (PrevSibling.type === undefined|| PrevSibling.container === undefined|| PrevSibling.container[0].declarations === undefined|| PrevSibling.container[0].declarations[0].init === null|| PrevSibling.container[0].declarations[0].init.object === undefined|| PrevSibling.container[0].declarations[0].init.object.object === undefined)return;if (PrevSibling.container[0].declarations[0].init.object.object.callee.property.name !== '$_DX')return;// SwitchStatement节点var body = node.body.body;// 判断当前节点的body[0]属性和body[0].discriminant是否存在if (!t.isSwitchStatement(body[0]))return;if (!t.isIdentifier(body[0].discriminant))return;// 获取控制流的初始值var argNode = PrevSibling.container[0].declarations[0].init;var init_arg_f = argNode.object.property.value;var init_arg_s = argNode.property.value;var init_arg = khCTZ.$_DX()[init_arg_f][init_arg_s];// 提取for节点中的if判断参数的value作为判断参数var break_arg_f = node.test.right.object.property.value;var break_arg_s = node.test.right.property.value;var break_arg = khCTZ.$_DX()[break_arg_f][break_arg_s];// 提取switch下所有的casevar case_list = body[0].cases;var resultBody = [];// 遍历全部的casefor (var i = 0; i < case_list.length; i++) {for (; init_arg != break_arg;) {// 提取并计算case后的条件判断的值var case_arg_f = case_list[i].test.object.property.value;var case_arg_s = case_list[i].test.property.value;var case_init = khCTZ.$_DX()[case_arg_f][case_arg_s];if (init_arg == case_init) {//当前case下的所有节点var targetBody = case_list[i].consequent;// 删除break节点,和break节点的上一个节点的一些无用代码if (t.isBreakStatement(targetBody[targetBody.length - 1])&& t.isExpressionStatement(targetBody[targetBody.length - 2])&& targetBody[targetBody.length - 2].expression.right.object.object.callee.object.name == "khCTZ") {// 提取break节点的上一个节点AJgjJ.EMf()后面的两个索引值var change_arg_f = targetBody[targetBody.length - 2].expression.right.object.property.value;var change_arg_s = targetBody[targetBody.length - 2].expression.right.property.value;// 修改控制流的初始值init_arg = khCTZ.$_DX()[change_arg_f][change_arg_s];targetBody.pop(); // 删除breaktargetBody.pop(); // 删除break节点的上一个节点}//删除breakelse if (t.isBreakStatement(targetBody[targetBody.length - 1])) {targetBody.pop();}resultBody = resultBody.concat(targetBody);break;} else {break;}}}//替换for节点,多个节点替换一个节点用replaceWithMultiplepath.replaceWithMultiple(resultBody);//删除上一个节点PrevSibling.remove();
}// 删除无关函数
function delete_func(path) {let {expression} = path.nodeif (expression === undefined|| expression.left === undefined|| expression.left.property === undefined)return;if (expression.left.property.name === '$_AY'|| expression.left.property.name === '$_Cl'|| expression.left.property.name === '$_BS'|| expression.left.property.name === '$_DX') {path.remove()}
}// #######################################// #######################################
// AST还原流程
// #######################################
// 需要解码的文件位置
let encode_file = "gcaptcha4.js"
// 解码后的文件位置
let decode_file = "gcaptcha4_decode.js"// 读取需要解码的js文件, 注意文件编码为utf-8格式
let jscode = fs.readFileSync(encode_file, {encoding: "utf-8"});// 将js代码修转成AST语法树
let ast = parser.parse(jscode);
// AST结构修改逻辑
const visitor = {StringLiteral: {enter: [replace_unicode]},VariableDeclaration: {enter: [get_name_array]},CallExpression: {enter: [replace_name_array, replace_$_Cl]},ForStatement: {enter: [replace_ForStatement]},ExpressionStatement: {enter: [delete_func]},
}// 遍历语法树节点,调用修改函数
traverse(ast, visitor);// 将ast转成js代码,{jsescOption: {"minimal": true}} unicode -> 中文
let {code} = generator(ast, opts = {jsescOption: {"minimal": true}});
// 将js代码保存到文件
fs.writeFile(decode_file, code, (err) => {});

3. 极验不同js或不同版本还原方式

请查看极验三破解链接:极验滑块验证码破解与研究(一):AST还原混淆JS

三、结语

友情链接:极验第四代滑块验证码破解(二):滑块缺口识别

本期文章结束啦,如果对您有帮助,记得收藏加关注哦,后期文章会持续更新 ~~~

极验第四代滑块验证码破解(一):AST还原混淆JS相关推荐

  1. 极验第四代滑块验证码破解(三):滑块轨迹构造

    极验第四代滑块验证码破解(三):滑块轨迹构造 声明 一.极验滑动轨迹分析 1. 生成滑动轨迹的js入口 2. 滑动轨迹的python实现 二.结语 *本期文章结束啦,如果对您有帮助,记得收藏加关注哦, ...

  2. 极验第四代滑块验证码破解(四):请求分析及加密参数破解

    极验第四代滑块验证码破解(四):请求分析及加密参数破解 声明 一.极验请求分析 1. 滑块测试网站入口 2. 滑块验证过程抓包 3. 请求详解 3.1. adaptive-captcha-demo 3 ...

  3. 极验第四代滑块验证码破解(二):滑块缺口识别

    极验第四代滑块验证码破解(二):滑块缺口识别 声明 一.环境安装 1. 第三方库安装 二.滑块缺口识别 1. 与极验三代滑块对比 2. 缺口识别完整代码 三.结语 *本期文章结束啦,如果对您有帮助,记 ...

  4. 【原创】极验滑块验证:AST还原混淆JS

    本文仅供学习交流使用,如侵立删! 极验滑块验证:AST还原混淆JS 操作环境 win10 . mac node14.17 v_jstools reres 分析 极验验证测试:aHR0cHM6Ly93d ...

  5. 对极验geetest滑块验证码图片还原算法的研究

    免责声明 本文章所提到的技术仅用于学习用途,禁止使用本文章的任何技术进行发起网络攻击.非法利用等网络犯罪行为,一切信息禁止用于任何非法用途.若读者利用文章所提到的技术实施违法犯罪行为,其责任一概由读者 ...

  6. 【JavaScript 逆向】极验三代滑块验证码逆向分析

    声明 本文章中所有内容仅供学习交流,相关链接做了脱敏处理,若有侵权,请联系我立即删除! 案例目标 极验验证码 demo:aHR0cHM6Ly93d3cuZ2VldGVzdC5jb20vZGVtby8= ...

  7. 极验滑块验证码破解最新版

    一.简述: 最近无聊想搞一下极验的滑块验证码破解这块,发现破解js代码耗时又耗力出现版本更新可能以前的所有努力都要推翻重做,不够通用性,最后还是选用selenium + PIL 来实现滑块验证码的破解 ...

  8. 极验滑块验证码破解与研究(二):缺口图片还原

    极验滑块验证码破解与研究(二):缺口图片还原 声明 一.缺口图片还原js分析 1. 为什么需要还原 2. 本篇文章需要用到的小工具 2.1. reres插件 3. 找到图片还原js入口函数 3.1. ...

  9. 极验滑块验证码破解与研究(三):滑块缺口识别

    极验滑块验证码破解与研究(三):滑块缺口识别 声明 一.环境安装 1. 第三方库安装 二.滑块缺口识别 1. 准备工作 2. 工具函数说明 3. 接口识别原理讲解 4. 缺口识别完整代码 三.结语 * ...

最新文章

  1. vue通信方法EventBus的实现
  2. MATLAB时间序列的排序函数
  3. 这 30 个常用的 Maven 命令你必须熟悉!
  4. qt git linux 安装,git – 如何在Ubuntu上安装QtWebEngine
  5. 【bzoj1597】 土地购买
  6. 《剑指Offer》 二维数组中的查找
  7. cad镂空图案切割_贺卡纸张卡片激光镂空雕花设备 激光打标机
  8. sql 键查找 索引查找_残留谓词对SQL Server索引查找操作的影响
  9. duilib入门简明教程 -- 前言(1)
  10. cookie与session的比较
  11. luogu_4551【题解】最长异或路径 trie树
  12. 初学C语言 输出图形
  13. openGauss 训练营第三期结营啦!PPT 85个FAQ大放送!文末附51位结营学员名单
  14. 网络管理-Pageadmin CMS构建企业网站的方法
  15. 数据库操作--已更新或删除的行值要么不能使该行成为唯一行,要么改变了多个行
  16. Java分解整型质因数
  17. 判断数组中是否存在某个元素
  18. 路由器和电脑IP地址、端口号、网卡mac查询方式
  19. OOM和StackOverFlow的区别
  20. 数据库系统概论 实验报告答案 实验二:创建及管理数据表

热门文章

  1. mysql+优化器+软解析_MySQL执行计划 - osc_93u9qofu的个人空间 - OSCHINA - 中文开源技术交流社区...
  2. GBase 8s与Oracle对比分析
  3. 思科《计算机网络》考试
  4. 【子桓说】过生日的徐峥:要学会在职场做个“技术派”
  5. 解决每次启动都弹出UAC对话框
  6. 房地产广告语忽悠大全
  7. linux网页制作教程,linux:.htaccess文件使用教程
  8. 生成Jupyter Lab快捷方式
  9. 【系统分析与设计】Homework1
  10. win10安装软件 打开时报错 找不到 msvcp120.dll