破解极验三代滑动验证,成功率百分之百(一):AST 反混淆

声明

原创文章,请勿转载!

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

环节概述

  1. 获取目标文件

    极验的验证逻辑由多个 JS 文件共同构成,其中和滑动验证的核心逻辑来自 slide.js 文件。
    涉及到的文件我们可以从 极验官网里直接复制到本地。
    onlinedemo

  2. 通过 AST 反混淆

    打开刚才下载下来的文件,可以发现,里面充斥着类似下面这种完全无法阅读的代码:
    codepreview
    这种代码其实是对方将自己的源码通过一些特定的方式加密混淆后的结果。我们要做的就是通过观察它的一些特征,然后反过来调整 AST,最后输出成比较好理解的一些代码。

    关于 AST,简单来说就是通过解析代码文字本身,将其转化为一个树形结构。我强烈建议大家先了解下 AST 大概长什么样子,这个 在线网站可以直观的看到代码和 AST 的对应关系。

    我们这一步需要做的事情大概是这样的:读取原代码文件 -> 解析为 AST -> 处理 AST -> 输出新代码文件。

环境准备

  1. 首先我们需要在电脑中准备好 node 环境。推荐使用 volta 或者 nvm 这类管理工具,他们能帮助我们便捷的切换 node 和 npm 版本
  2. 新开一个文件夹,通过 npm init 创建下基本的 package.json 文件,然后装一些基本依赖
  3. 安装基本依赖:npm install @babel/core @babel/generator
    babel 是一个非常常用的解析代码的工具,其中 core 里提供了解析代码、遍历 AST 的能力,以及一些辅助功能,generator 提供了将 AST 输出为代码字符串的功能。

基本框架

在基本框架里,我们需要完成核心模块的实现,也就是读取、解析、处理以及最后输出的部分。具体如何去处理,我们在后续的步骤里逐步完善。

import fs from 'fs'
import { parse, traverse } from '@babel/core'
import generator from '@babel/generator'

// 1. 读取原文件
const originCodeStr = fs.readFileSync('原代码文件地址')

// 2. 解析为 AST
const ast = parse(originCodeStr)

// 3. 处理 AST
const processList = [] // 具体处理 AST 的逻辑后续会逐步追加到这里
// processList.push(...)
processList.forEach((process) => {
  traverse(ast, process())
})

// 4. 输出为新文件
fs.writeFileSync(
  '新代码的文件地址',
  generator(ast, { jsescOption: { minimal: true } }).code
)

处理 AST

下面列出的多个函数,最后 push 到上面的 processList 中即可

  1. 移除 unicode

    首先我们可以看到,代码里有很多 /uxxxx 的东西,我们首先要把这个 unicode 转换为平常我们使用的语言。

    const removeUnicode = () => ({
      StringLiteral(path) {
        delete path.node.extra
      }
    })
    

    效果:removeunicode

  2. 简化引用关系

    观察代码,发现 JS 文件里,有个基本的对象,然后在主逻辑里,存在多处对这个对象的引用。

    refinedemo

    以下面第一个箭头所指的部分举例:$_CT$_CIEE$_CIF_ 三者其实都是一个东西,所以我们可以把这里的直接化简掉。

    同时它们都是一个函数,并且最后会调用它。我们可以直接用函数的执行结果做替换,进一步化简。

    所以我们这里要做的事情有这么几点:

    1. 获取基本对象所有被引用的地方,以及对应的变量名叫什么,并移除无用代码

      // 基本对象的四个字段名
      const baseFnName = ['$_AP', '$_Bi', '$_CT', '$_DO']
      // 用来缓存变量名前后的关系
      const replaceNameMap = {}
      
      const getNameList = () => ({
        VariableDeclaration(path) {
          const { kind, declarations } = path.node
          const propertyName = declarations[0]?.init?.property?.name
          // 代码特征
          if (kind !== 'var' || declarations.length !== 3 || !baseFnName.includes(name)) {
            return
          }
          // 待替换节点变量名
          const inputVarName = declarations[0].id.name
          // 待输出变量名
          const outputVarName = declarations[2].id.name
          replaceNameMap[inputVarName] = name
          replaceNameMap[outputVarName] = name
          // 移除无用代码
          path.getNextSibling().getNextSibling().remove()
          path.getNextSibling().remove()
          path.remove()
        },
      })
      
    2. 执行目标函数,替换引用关系

      // 把之前的 obj 抠出来,接下来我们需要运行下他里面的方法
      const obj = {}
      
      const restoreVar = () => ({
        CallExpression(path) {
          const replaceNameArray = () => {
            const { callee, arguments: args } = path.node
            // 先做些特征判断
            if (!callee || !args?.length) {
              return
            }
            const name = callee.name
            if (!replaceNameMap[name]) {
              return
            }
            // 替换变量
            const value = obj[replaceNameMap[name]](args[0].value)
            path.replaceWith(types.stringLiteral(value))
          }
          const replaceTargetField = () => {
            const { callee, arguments: args } = path.node
            // 先做些特征判断
            if (!args?.length) {
              return
            }
            if (args[0].type !== 'NumericLiteral') {
              return
            }
            if (callee.type !== 'MemberExpression') {
              return
            }
            const { object, property } = callee
            if (object.type !== 'Identifier' || property.type !== 'Identifier') {
              return
            }
            if (!baseFnName.includes(property.name)) {
              return
            }
            // 替换变量
            const value = obj[property.name](args[0].value)
            path.replaceWith(types.stringLiteral(value))
          }
          replaceNameArray()
          replaceTargetField()
        },
      })
      

      效果:refine

  3. 反流程平坦化

    观察代码我们还会发现,代码整体充斥着 for switch 的嵌套逻辑,完全看不懂里面做了点什么。

    flatdemo

    这个就是一个标准的流程平坦化操作,具体大家可以搜索看看他的一些定义和解释。简单来说,就是把原本线性的逻辑,转化为了一个由某个模块控制的循环逻辑,每次循环都会改变一些条件从而走向不同的分支,最后逻辑执行完毕后会走向一个结束分支。

    这块儿的特征也是非常的明显,我们所需要做的就是,把离散的流程分支跑一遍,然后把结果做替换

    const flat = () => ({
      ForStatement(path) {
        const prevNodePath = path.getPrevSibling()
        if (!types.isVariableDeclaration(prevNodePath)) {
          return
        }
        const init = prevNodePath.node.declarations?.[0]?.init
        if (!init) {
          return
        }
        const initFirstObject = init.object
        if (!initFirstObject) {
          return
        }
        const initFirstObjectObject = initFirstObject.object
        if (!initFirstObjectObject) {
          return
        }
        const callee = initFirstObjectObject.callee
        if (!callee) {
          return
        }
        const name = callee.property?.name
        if (!baseFnName.includes(name)) {
          return
        }
        const switchNode = path.node.body?.body?.[0]
        if (!types.isSwitchStatement(switchNode) || !switchNode.discriminant) {
          return
        }
        const test = path.node.test
        if (!test) {
          return
        }
        const testRight = test.right
        if (!testRight) {
          return
        }
        // 控制流初始值
        const baseFnFirstParam = initFirstObject.property.value
        const baseFnSecondParam = init.property.value
        let initState = obj[name]()[baseFnFirstParam][baseFnSecondParam]
        // for 循环的参数
        const breakFirstParam = testRight.object?.property?.value
        const breakSecondParam = testRight.property?.value
        const breakState = obj[name]()[breakFirstParam][breakSecondParam]
    
        const caseList = switchNode.cases
        const resultList = []
        // 遍历 cases
        for (const caseItem of caseList) {
          while (initState !== breakState) {
            const caseFirstParam = caseItem.test.object.property.value
            const caseSecondParam = caseItem.test.property.value
            const caseState = obj[name]()[caseFirstParam][caseSecondParam]
            if (initState !== caseState) {
              break
            }
            const caseContent = caseItem.consequent
            if (
              types.isBreakStatement(caseContent.at(-1)) &&
              types.isExpressionStatement(caseContent.at(-2)) &&
              caseContent.at(-2).expression.right.object.object.callee.object.name === objName
            ) {
              const firstParam = caseContent.at(-2).expression.right.object.property.value
              const secondParam = caseContent.at(-2).expression.right.property.value
              initState = obj[name]()[firstParam][secondParam]
              caseContent.pop()
              caseContent.pop()
            } else if (types.isBreakStatement(caseContent.at(-1))) {
              caseContent.pop()
            }
            resultList.push(caseContent)
            break
          }
        }
        path.replaceWithMultiple(resultList.flat(1))
        prevNodePath.remove()
      },
    })
    

    效果:
    flat

总结

这一节内容里,我们搭建了基本的代码环境,下载了目标代码,并对目标代码做了解析和处理,生成了能够进行阅读的新代码。对于处理部分,我只列出了最核心的部分,如果大家还希望对代码做其他处理,可以自行扩展(比如我可能还喜欢用 prettier 把代码做一次格式化)。

另外针对不同版本的 slide 文件,或者针对极验其他的 JS 文件,均可采用同方式来做处理,只需要替换下基本的 obj 对象即可(具体 obj 对象是啥自己从代码里扣下来吧)。

下一节我们要开始对滑动验证页面的图片做分析和处理,来还原缺口图片并得到所需的滑动距离。


本期文章到这里就结束了,如果对您有帮助,记得收藏关注,有什么想法也可以联系我哦。

后续内容持续更新中。。。

__aoko
关注 关注
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一种针对GeeTest滑动验证的高识别率解决方案python源码.zip
12-26
一种针对GeeTest滑动验证的高识别率解决方案python源码.zip 引入动量收敛 以及 震荡 等仿生算法解决二维空间中的像素对齐问题。当这个难倒了大批爬虫玩家的问题被抽象成缺口识别以及像素对齐两个指标时使用本方案进行百次实: 当缺口识别率为100%时,gt3通过率为92%。失败案例中超半数由收敛超时引发,剩下的被怪兽吃掉了; 当缺口识别率为100%时,gt2通过率100%。仅在缺口被遮挡时失败,但此时倾向认为缺口识别率<100%; 本项目依赖 google-chrome 完成挑战,请确保您的设备中已装有 最新版谷歌浏览器! 本项目由 webdriver-manager 实现驱动托管。因此,你不需要关心浏览器驱动的存放路径问题,只要你的设备上装了谷歌浏览器,webdriver-manager 可以自动下载版本匹配的驱动并放置到绝对索引路径。
asp.net验证滑动卡位验证
01-10
asp.net验证滑动卡位验证),这资源很少我也是找了很久。
AST原理(混淆
最新发布
weixin_63958646的博客
05-04 674
当我们说 Babel 允许代码“运行在当前和旧版本的浏览器或其他环境中”时,意思是 Babel 生成的代码不仅可以在支持最新 JavaScript 特性的最新浏览器中运行,也可以在那些只支持旧 JavaScript 版本的旧浏览器中运行。​ 根据官网介绍,它是一个JavaScript 编译器,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容 的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。是函数调用的一部分,那么可能需要以不同的方式处理它。
使用puppeteer破解滑动验证
12-23
基本的流程: 1. 打开前端网,点击登录。 2. 填写账号,密码。 3. 点解验证按钮,通过滑动验证,最后成功登陆。 代码实现: github上可以checkout。 具体代码如下所示: run.js const puppeteer = require('puppeteer'); const devices = require('puppeteer/DeviceDescriptors'); const iPhone = devices['iPhone 6 Plus']; let timeout = function (delay) { return new Promise((resolv
AST混淆js还原工具2.0.zip
04-20
1.基于丁仔大佬js还原工具进行的二次开发,增加功能多达10+, 2.对丁仔大佬已开发的功能进行优化及修改,兼容更多可能,提升兼容性。 3.对1.0版本已存在的错误进行修复 4.针对最新的https://obfuscator.io/混淆规则进行针对性处理 5.提升部分功能的兼容性 6.新增三元表达式转if-else功能,解决原版涉及的作用域问题 目前可处理2022-4-20当前最新的https://obfuscator.io/中的混淆规则,是js逆向与爬虫工程师的应对js混淆的不二神器
geetest_crack:geetest二代滑动、三代滑动和汉字点选破解
05-28
每日限制50次, 仅供学习交流 geetest二代滑动、三代滑动和汉字点选破解 免责声明 本仓库仅用于学术交流, 不得用于任何商业用途!!! 说明 本仓库不提供相关模型源代码、模型文件、数据集、服务源代码等. 通过率 滑动: 通过算法生成轨迹 二代: 重试一次通过率99% 三代: 不重试, 通过率99% 汉字点选: 99% 耗时 滑动: 4s以内 汉字点选: 10s以内(CPU上YOLO3比较耗时) 结果样例 二代滑动: 三代点击: 三代滑动: 三代按文字点选: 三代按语序点选: 开发环境 python3.6 tensorflow keras darknet(YOLO3) labelImg(YOLO3数据标签工具) opencv(定位滑动缺口距离) pyppeteer 算法 YOLO3: 定位汉字位置 CRNN: 校文字识别 CNN: 定位后的文字识别 数据集 汉字点选 4000+汉
AST入门与混淆初体
自成背后的博客
02-02 1694
AST入门体
【JavaScript 逆向】AST 技术混淆
热门推荐
Yy_Rose的博客
04-24 1万+
JavaScript 常见混淆技术类型,及如何使用 AST 技术混淆,通过 javascript-obfuscator 库混淆 JavaScript 代码
滑块验证破解与研究(一):AST还原混淆JS
帯泪的鱼的博客
11-28 9251
滑块验证破解与研究(一):AST还原混淆JS声明一、环境安装1. node安装1.1. node下载1.2. 配置环境变量1.3. node安装检测1.4. pycharm配置node环境2. babel库安装2.1. babel库安装命令2.2. babel库安装检测二、AST还原混淆JS1. 模块导入2. AST还原流程3. 复制还原需要用到的js源码4. AST还原函数详解4.1. replace_unicode4.2. replace_unicode, replace_name_array,
爬虫 JavaScript 逆向进阶!利用 AST 技术还原混淆代码
静觅
05-08 3424
这是「进击的Coder」的第 617篇技术分享作者:K 小哥来源:K 哥爬虫“ 阅读本文大概需要 47分钟。 ”目录文章较长,可作为 AST Babel 入门手册,强烈建议收藏!什么是 ASTAST(Abstract Syntax Tree),中文抽象语法树,简称语法树(Syntax Tree),是源代码的抽象语法结构的树状表现形式,树上的每个节点都表示源代码中的一种...
AST 混淆
TF的博客
04-16 461
*desc :const {const {} , // 替换完了就没用了,将其删除 VariableDeclarator(path) {const {if(!//只处理字面量 const binding = path . scope . getBinding(id . name);if(!//如果该变量的值被修改则不能处理 return;const {if(!if(!if(!let {
30分钟入门babel插件
Missy_xw2018的博客
04-10 1053
快速学习什么是babel、babel的流程、通过AST可视化平台介绍babel ast、babel api等,快速入门Babel插件
c#(asp.net/core)杂谈笔记
weixin_33835103的博客
07-10 782
1.js解析json格式的时间 View Code //转换json格式时间的方法 如Date(1340239979000)转换为正常 function ConvertJSONDateToJSDateObject(JSONDateString) { var date = new Date(parseInt(JSONDat...
AST混淆实战|变量被复赋值如何还原?
Python3 爬虫实战 1:应对特殊字体,爬取猫眼电影实时排行榜
12-26 518
本文章中所有内容仅供学习交流,不可用于任何商业用途和非法用途,否则后果自负,如有侵权,请联系作者立即删除!
逆向进阶,利用 AST 技术还原 JavaScript 混淆代码
Tips的博客
04-29 5064
什么是 AST AST(Abstract Syntax Tree),中文抽象语法树,简称语法树(Syntax Tree),是源代码的抽象语法结构的树状表现形式,树上的每个节点都表示源代码中的一种结构。语法树不是某一种编程语言独有的,JavaScript、Python、Java、Golang 等几乎所有编程语言都有语法树。 小时候我们得到一个玩具,总喜欢把玩具拆解成一个一个小零件,然后按照我们自己的想法,把零件重新组装起来,一个新玩具就诞生了。而 JavaScript 就像一台精妙运作的机器,通过 AST
[639]验证破解分析&滑动验证码的识别
周小董
07-18 5972
本节我们分析并实现了验证码的识别,其关键在于识别的思路,如怎样识别缺口位置,怎样生成运动轨迹等,学会了这些思路后以后我们再遇到类似原理的验证码同样可以完成识别过程。最后,放上代码,有需要的小伙伴可以自取,在使用时请注意,需要更改自己的账号密码,如果没有,则需要注册。'''验证码特点:首先点击按钮进行智能验证,如果验证不通过,则会弹出滑动验证的窗口,拖动滑块拼合图像进行验证,之后生成三个加密参数,通过表单提交到后台,后台还会进行一次验证。识别验证需要三步:1.模拟点击验证按钮。
爬虫逆向-AST混淆
06-11 2148
js代码是不安全的,任何人都可以阅读,分析,复制,甚至篡改,于是各种混淆技术出现了 变量混淆 将带有含意的变量名、方法名、常量名随机变为无意义的类乱码字符串,降低代码可读性,如转成单个字符或十六进制字符串。 字符串混淆 将字符串阵列化集中放置、并可进行 MD5 或 Base64 加密存储,使代码中不出现明文字符串,这样可以避免使用全局搜索字符串的方式定位到入口点。 属性加密 针对 JavaScript 对象的属性进行加密转化,隐藏代码之间的调用关系。 控制流平坦化 打乱函数原有代码执行流程及函数调
使用AST进行JavaScript混淆(2022年增值税发票查js)
池塘
09-28 1827
在做爬虫或是某些业务时难免会碰到JS混淆,这篇文字是记录本人在处理一次deobfuscate的心得。
Java滑动验证_3.0滑动拼图验证的使用--java
05-17
3.0滑动拼图验证是一种常用的人机验证方式,可以有效防止机器恶意攻击,保障网站安全。在Java中,可以通过调用的API来实现滑动验证功能。下面是一个简单的使用示例: 1. 在官网申请账号,并创建一个验证项目,获得验证ID和密钥。 2. 下载的Java SDK,解压后将其中的geetest-lib.jar文件添加到项目的classpath中。 3. 在Java代码中调用API实现验证功能,示例代码如下: ```java import com.geetest.sdk.GTConfig; import com.geetest.sdk.GeetestLib; public class GeetestVerify { private static final String GEETEST_ID = "your_geetest_id"; // 验证ID private static final String GEETEST_KEY = "your_geetest_key"; // 验证密钥 public static boolean verify(String challenge, String validate, String seccode) { GeetestLib gtSdk = new GeetestLib(GEETEST_ID, GEETEST_KEY); GTConfig config = new GTConfig(); config.setCaptchaId(GEETEST_ID); config.setPrivateKey(GEETEST_KEY); gtSdk.setConfig(config); // 自定义参数,可选择添加 // Map<String, String> paramMap = new HashMap<>(); // paramMap.put("user_id", "your_user_id"); // paramMap.put("client_type", "web"); // paramMap.put("ip_address", "127.0.0.1"); // 调用验证接口 int result = gtSdk.enhencedValidateRequest(challenge, validate, seccode, null); // 验证结果,0表示成功,1表示失败 return result == 0; } } ``` 4. 在前端页面中嵌入验证组件,具体实现方式可参考官网提供的相关文档和示例代码。在用户完成验证后,将验证结果传递给后台Java程序进行验证,通过调用上述示例代码实现验证功能即可。 总的来说,Java实现滑动验证相对较为简单,只需要调用提供的Java SDK即可。需要注意的是,官网提供的Java SDK版本可能会更新,需要及时更新SDK文件以保证验证功能的正常运作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
写文章

热门文章

  • 破解极验三代滑动验证,成功率百分之百(一):AST 反混淆 2303
  • 破解极验三代滑动验证,成功率百分之百(二):分析图片得到滑动距离 1848

大家在看

  • Android BroadcastReceiver 详解(BroadcastReceiver背景和概述以及作用、BroadcastReceiver分类和基本使用以及生命周期) 378
  • JavaScript的DOM
  • 【建站教程】Ubuntu结合宝塔面板本地部署Inis博客并发布公网 720
  • 使用Java中的map存数据和使用Redis存数据有什么区别
  • go语言接口之flag.Value接口 307

最新文章

  • 破解极验三代滑动验证,成功率百分之百(二):分析图片得到滑动距离
2022年2篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

PHP网站源码永湖网站搜索优化公司丹东网站优化推广多少钱武威网站优化按天扣费哪家好张家口网站建设公司迪庆百度爱采购哪家好遵义模板网站建设多少钱坪山SEO按效果付费公司塘坑网页设计邢台百度网站优化价格昭通网站制作价格黔南百度网站优化多少钱岳阳网站搜索优化报价朝阳百度网站优化报价巢湖网站关键词优化榆林seo网站优化公司兴安盟SEO按天扣费多少钱昌吉建设网站报价宿迁设计网站推荐天水外贸网站制作哪家好来宾建网站多少钱烟台网站推广报价塔城网站建设设计哪家好泰州百姓网标王公司同乐网站推广哪家好永湖关键词按天扣费哪家好清徐网站开发公司邢台建网站报价天津推广网站多少钱黑河网站排名优化迪庆企业网站改版公司歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

PHP网站源码 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化