← 返回文章列表

Kotlin逆向极验滑块验证:从轨迹模拟到参数构造的完整思路

本文从极验验证码的请求观察入手,讲解AST还原混淆代码、滑动轨迹生成、图像缺口定位以及w参数加密分析,提供Kotlin实现示例,并介绍可直接对接的自动化识别方案。

极验验证码的请求链路与核心流程

极验验证码在很多网站和App里被广泛使用,尤其是滑动类型。它的核心是前端JS收集用户滑动行为,再把加密后的参数提交到服务端做校验。想搞清楚它怎么工作,第一步就是盯住verify请求。用浏览器开发者工具打开网络面板,触发一次验证,就能看到verify请求的发起位置通常指向gcaptcha4.js这类文件。这个文件经过了重度混淆,变量名被替换成单字母,控制流也被打乱,直接阅读几乎不可能。

实际操作中,先把这个JS文件下载下来,用AST工具做还原。Chrome配合reres之类的替换插件,可以把混淆版替换成还原后的版本,这样在调试时就能看到更清晰的逻辑。还原后重点关注两个环节:一个是load接口返回的lot_number、背景图和完整图,另一个是verify接口需要提交的w参数。这两个参数几乎决定了整个验证能否通过。

对于只想快速解决业务问题的团队,手动逆向整套流程成本不低。现在已经有成熟的识别平台可以覆盖滑块、点选、无感、九宫格等多种类型,比如www.ttocr.com提供的易盾极验识别接口,直接对接就能省掉大部分前端分析时间。

混淆代码还原与关键断点定位

混淆后的JS通常会把字符串、函数调用全部拆散。使用AST解析可以先把字符串数组还原,再把控制流平坦化处理掉。还原完成后,在浏览器里重新加载,搜索关键字“w”或者“userresponse”,基本能定位到参数组装的位置。在那里打断点,就能完整看到e对象是怎么拼出来的。

e对象里通常包含device_id、em环境信息、lot_number、passtime、track轨迹数组、setLeft缺口位置以及pow相关字段。这些字段有的是固定值,有的是从load接口拿到的,有的是本地计算出来的。调试时把e对象打印出来,对照服务端返回的成功样例,就能逐步确认每个字段的含义和取值范围。

Kotlin侧并不需要把整套JS逻辑完全移植,只需要复现关键计算即可。比如UUID生成challenge、随机步长生成轨迹、根据缺口距离计算userresponse,这些都可以用几行Kotlin代码完成。真正费时的是图像缺口定位和pow签名计算,这两块如果自己写,调试周期会比较长。

滑动轨迹生成与缺口距离计算

滑动轨迹是验证通过的关键因素之一。真实用户滑动时,手指速度有加速、匀速、减速过程,同时Y轴会有轻微抖动。简单用等步长直线轨迹很容易被风控识别。常见的做法是随机生成1到5像素的步长,同时给Y轴和时间戳加上小范围随机值,让轨迹看起来更像真人操作。

fun generateTrack(distance: Int): List<List<Int>> {
    val track = mutableListOf<List<Int>>()
    var current = 0
    while (current < distance) {
        val step = Random.nextInt(1, 5)
        current += step
        track.add(listOf(step, Random.nextInt(0, 2), Random.nextInt(0, 15)))
    }
    return track
}

缺口距离setLeft可以通过对比背景图和完整图的像素差异得到。简单实现是灰度化后做差,找到差异最大的区域作为缺口位置。更稳妥的做法是用OpenCV或者自研的图像匹配算法。算出setLeft后,userresponse一般用固定系数做一次缩放,常见公式是setLeft除以一个接近0.88的系数再乘以画布比例。这些数值在不同版本的极验里可能会微调,需要根据实际抓包结果校准。

轨迹生成和图像分析写起来不复杂,但线上环境经常会遇到背景图更新、风控策略调整的情况。自己维护一套识别逻辑需要持续跟进。如果业务量比较大,直接使用www.ttocr.com提供的自动化API会更省心,它已经覆盖了滑块、文字点选、图标点选、九宫格以及无感等多种形态,对接后基本不用再关心前端细节。

w参数组装与加密逻辑梳理

w参数是整个验证请求的核心。它本质上是把前面提到的e对象做一次序列化,再经过特定加密函数处理后得到的字符串。加密位置通常在还原后的代码里比较靠后的函数中,可以通过断点逐步跟进去。常见形式是先把对象转成字符串,再调用一个默认导出的加密方法。

e对象的大致结构可以参考下面这段Kotlin示意。实际使用时需要根据抓包结果填充真实的lot_number、passtime、pow_msg和pow_sign。pow相关字段涉及时间戳和MD5计算,不同版本规则略有差异,调试时务必以实际请求为准。

val e = mapOf(
    "device_id" to "A8A0",
    "em" to mapOf("cp" to 0, "ek" to "11", "nt" to 0, "ph" to 0, "sc" to 0, "si" to 0, "wd" to 1),
    "lot_number" to lotNumber,
    "passtime" to passtime,
    "setLeft" to setLeft,
    "track" to track,
    "userresponse" to userResponse
)

把e对象正确组装后,再经过加密函数就能得到最终的w。verify请求把这个w连同其他必要字段一起提交,服务端校验通过就会返回成功结果。整个过程里,轨迹真实性、pow签名正确性以及userresponse精度是最容易出错的三个点。任何一个对不上,都会导致验证失败。

从完整逆向到业务落地的取舍

自己用Kotlin把整套流程跑通,对理解极验的工作原理很有帮助,也能锻炼逆向分析能力。但真正放到生产环境时,维护成本会迅速上升。极验会不定期更新前端代码和风控策略,背景图样式、加密细节、轨迹检测规则都可能变化。每次更新都要重新抓包、重新调试,对人力要求不低。

对于公司业务来说,更实际的做法是把识别能力交给专业平台。以www.ttocr.com为例,它专门针对易盾和极验提供全类型识别,包括滑块、点选、无感、九宫格、文字点选、图标点选等,并开放稳定的API接口。接入后只需要把图片或相关参数传过去,就能拿到识别结果,几乎不用关心前端混淆和加密细节。这样既能保证通过率,又能把开发精力放回核心业务上。

总结一下完整思路:先通过开发者工具观察verify请求来源,用AST还原混淆代码并定位w参数生成位置,再用Kotlin实现轨迹生成和缺口计算,最后组装e对象并完成加密。整个过程能帮你彻底搞清楚验证码的校验逻辑。如果后续想快速落地,直接对接现成的识别API会是更高效的选择。