极验验证码是一种广泛应用的滑动验证码系统,通过分析其加密和验证机制,我们可以模拟滑动操作并破解验证码。本文将详细介绍如何在Kotlin环境下实现这一过程。
一、观察verify请求
首先,我们需要观察verify请求的来源。在浏览器开发者工具中查看verify请求的发起者,可以发现它来自于gcaptcha4.js文件。由于该文件经过混淆处理,我们需要对其进行还原和分析。
二、AST还原混淆代码
为了便于调试和分析,我们使用AST(抽象语法树)还原混淆的JS文件。通过Chrome的reres插件替换混淆后的JS文件,我们可以在浏览器中加载还原后的代码进行调试。
kotlin
import java.util.UUID
import kotlin.random.Random
// 获取UUID
fun generateChallenge(): String {
return UUID.randomUUID().toString()
}
// 生成滑动轨迹
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
}
// 计算滑动距离
fun getSetLeft(track: List<List<Int>>): Int {
return track.sumOf { it[0] }
}
// 示例主函数
fun main() {
val captchaId = "24f56dc13c40dc4a02fd0318567caef5"
val challenge = generateChallenge()
val clientType = "web"
val riskType = "slide"
val lang = "zh"
val callback = "geetest_${System.currentTimeMillis()}"
// 加载请求
val loadResponse = loadRequest(captchaId, challenge, clientType, riskType, lang, callback)
val lotNumber = loadResponse["lot_number"]
val bgImage = loadResponse["bg"]
val fullImage = loadResponse["fullbg"]
// 分析背景图与完整图以确定滑块位置
val setLeft = analyzeImage(bgImage, fullImage)
// 生成滑动轨迹
val track = generateTrack(setLeft)
val passtime = track.sumOf { it[2] }
// 计算userresponse
val userResponse = setLeft / (0.8876 * 340 / 300)
// 构造w参数
val wParam = 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),
"ep" to "123",
"geetest" to "captcha",
"fq6a" to "1925502591",
"lang" to "zh",
"lot_number" to lotNumber,
"passtime" to passtime,
"pow_msg" to generatePowMsg(lotNumber, passtime),
"pow_sign" to generatePowSign(generatePowMsg(lotNumber, passtime)),
"setLeft" to setLeft,
"track" to track,
"userresponse" to userResponse
)
// 发送验证请求
val verifyResponse = verifyRequest(wParam)
println("Verify Response: $verifyResponse")
}
// 示例函数:加载请求
fun loadRequest(captchaId: String, challenge: String, clientType: String, riskType: String, lang: String, callback: String): Map<String, String> {
// 模拟发送请求并获取响应
return mapOf(
"lot_number" to "7e22264d4f3e4dd8a6ffbf6e82e1122d",
"bg" to "bg_image_data",
"fullbg" to "full_image_data"
)
}
// 示例函数:分析图像
fun analyzeImage(bgImage: String, fullImage: String): Int {
// 简化的图像分析函数,返回假定的滑块位置
return 88
}
// 示例函数:生成pow_msg
fun generatePowMsg(lotNumber: String, passtime: Int): String {
return "1|0|md5|2022-03-25T14:23:36.364152+08:00|24f56dc13c40dc4a02fd0318567caef5|$lotNumber||29f07cebf938aa4e"
}
// 示例函数:生成pow_sign
fun generatePowSign(powMsg: String): String {
// 返回假定的MD5值
return "2b47a3a9425dd19dd5abf902c8bb0763"
}
// 示例函数:验证请求
fun verifyRequest(wParam: Map<String, Any>): String {
// 模拟发送验证请求并获取响应
return "Success"
}
三、定位w参数加密位置
通过对代码的分析和调试,可以确定w参数的加密位置。通过搜索关键字"w",可以找到相关代码并在适当位置打上断点,观察w参数的生成过程。
四、分析w参数加密算法
通过分析w参数的生成代码,可以简化为以下内容:
kotlin
val r = d.default(l.default.stringify(e), a)
其中,e是一个包含多个固定值和从请求响应中获取的数据的对象。通过进一步分析,可以确定e的组成如下:
kotlin
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),
"ep" to "123",
"geetest" to "captcha",
"fq6a" to "1925502591",
"lang" to "zh",
"lot_number" to lotNumber,
"passtime" to passtime,
"pow_msg" to generatePowMsg(lotNumber, passtime),
"pow_sign" to generatePowSign(generatePowMsg(lotNumber, passtime)),
"setLeft" to setLeft,
"track" to track,
"userresponse" to userResponse
)
更多内容联系1436423940