K哥爬虫 发表于 2023-4-7 18:18

【验证码逆向专栏】某验三代、四代一键通过模式逆向分析

![](https://s1.ax1x.com/2022/11/25/zY5cgs.png)

## 声明

**本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!**

**本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请联系作者立即删除!**

## 逆向目标

- 目标:某验三代、四代一键通过模式(无感验证)逆向分析
- 三代主页:`aHR0cHM6Ly93d3cuZ2VldGVzdC5jb20vZGVtby9mdWxscGFnZS5odG1s`
- 四代主页:`aHR0cHM6Ly9ndDQuZ2VldGVzdC5jb20v`

## 通讯流程

接口相关:

!(https://s1.ax1x.com/2022/12/26/zx3Maq.png)

完整流程:

!(https://s1.ax1x.com/2022/12/26/zx3QI0.jpg)

## 三代抓包情况

`register-fullpage` 会返回 `challenge` 和 `gt` 值,后期有用到。

!(https://s1.ax1x.com/2022/12/15/zoljER.png)

`get.php` 会返回 `c` 和 `s`,同样后期会用到,这个请求同样需要 `w` 值,在某验的点选滑块里,这个请求可以不要 `w` 值,但在三代无感里,必须得要,不然最后是会验证失败的,可能不带 `w` 请求,返回的 `s` 是个假的值,导致最后验证失败。

!(https://s1.ax1x.com/2022/12/15/zo1cPx.png)

`ajax.php` 验证是否成功,同样需要 `w` 值,成功则会返回一个 `validate`。

!(https://s1.ax1x.com/2022/12/15/zoIvCj.png)

## 三代逆向分析

### 第一个w值

相信看过K哥以前滑块、点选的文章,对于定位 `w` 的值很熟练了,这里也是类似的,`"\u0077"` 就是 `"w"`,其值为 `i + r`,如下图所示:

!(https://s1.ax1x.com/2022/12/15/zTiPL8.png)

主要就是 r、o、i 的值,关键代码:

```javascript
var r = t[$_CFAGw(1326)]()
, o = $_BFx()[$_CFAGw(1367)](pe[$_CFAFP(416)](t[$_CFAGw(353)]), t[$_CFAGw(1393)]())
, i = O[$_CFAGw(1375)](o)
```

先看看 r,跟进去就是我们熟悉的 RSA 了,和以前的处理一样,把代码扣下来或者用库都行。

!(https://s1.ax1x.com/2022/12/15/zTVwIU.png)

同样需要注意的是上图中 `this[$_CHCFe(1393)]()` 也是个随机字符串,会遇到多次,但整体一次验证下来都是相同的值,不然验证会失败,点选、滑块等一系列都一样的。

!(https://s1.ax1x.com/2022/12/15/zTV5Je.png)

!(https://s1.ax1x.com/2022/12/15/zTVIRH.png)

然后是 o 的值,这里和以前一样,跟进去看仍然是 AES 加密。` t[$_CFAGw(1393)]()` 依旧是随机字符串。

!(https://s1.ax1x.com/2022/12/16/z7piYn.png)

中间这一串 `pe[$_CFAFP(416)](t[$_CFAGw(353)])`,也没啥特别的,除了 `gt` 和 `challenge`,其他都是定值,最后面那一串 `i` 的值,实测写死、置空都行。

!(https://s1.ax1x.com/2022/12/16/z7Px9s.png)

然后继续跟进 `i`,把前面 `o` 的值转换成一个大的字符串,这里也不是很复杂,直接扣代码即可:

!(https://s1.ax1x.com/2022/12/16/z7BqN6.png)

!(https://s1.ax1x.com/2022/12/16/z7BRhT.png)

然后 `i + r` 就是 `w` 的值了,到这里第一个 `w` 的值就搞完了。

### 第二个 w 值

第二个 w 的值和以往的地方都不太一样,不过通过跟栈的方式也很容易找到,来到有个 `var n = {};` 的地方,如下图所示:

!(https://s1.ax1x.com/2022/12/16/z7yAC6.png)

`t[$_CGABi(1436)]` 就是 w 值,也就是 `t['$_CEDO']`,前面定义了 `var t = this`,经过第 8215 行的 `t[$_CGAAX(1462)]()` 之后,就有了 w 的值,所以要跟进去重点看这一行。

!(https://s1.ax1x.com/2022/12/16/z7g3P1.png)

如上图所示,e、t、n、r 中涉及到一些浏览器环境值的计算,当然还有鼠标移动等相关数据的计算,如下图所示:

!(https://s1.ax1x.com/2022/12/16/z7gl5R.png)

而实际测试发现这四个值直接置空也可以,在本例中可以,不知道是否有其他案例校验更加严格,知道的朋友可以在评论区提出来,再往下,会遇到很多给变量赋值的地方,如下图所示,G 是 MD5 方法,中间的 `O[$_CGBFp(948)]` 和以前类似,返回一个对象中的 `res` 和 `end` 相加,这里就不再赘述了。

!(https://s1.ax1x.com/2022/12/16/z7RgEQ.png)

`i[$_CGBGa(1415)]` 这里就是将每个变量和值挨个相加,组成一个大的字符串。

!(https://s1.ax1x.com/2022/12/16/z7WjoQ.png)

然后到 r 这里,就多了一个 `captcha_token`,然后用 `{}` 将所有数据包了起来。

!(https://s1.ax1x.com/2022/12/16/z7ffXV.png)

这些数据我们格式化一下,大致结构如下图所示:

!(https://s1.ax1x.com/2022/12/16/z7hpAe.png)

其中 `ep` 里面的 `ven`、`ren` 是显卡相关信息,`fp`、`lp` 是取了两个鼠标移动的位置信息,直接写死为 `null` 也可以,`tm` 就是 `window.performance.timing` 的一些东西,自己随便伪造一下就行了。

最后一步 `i[$_CGDBA(1436)]`,随机字符串为 key,将前面的数据 r 进行 AES 加密,得到我们最终的 w 值,如下图所示:

!(https://s1.ax1x.com/2022/12/16/z7h4gI.png)

## 三代结果验证

!(https://s1.ax1x.com/2022/12/16/z75Myq.png)

## 四代抓包情况

`load` 接口返回值如下:

!(https://s1.ax1x.com/2022/12/28/pSS3FG6.png)

- captcha_type:验证码类型,无感为 ai

- gct_path:gct4 文件路径
- lot_number:生成 pow_msg、w 的关键参数
- payload:verify 请求参数
- datetime:ISO 8601 扩展格式的日期,生成 pow_msg 的关键参数
- process_token:verify 请求参数

`verify` 接口返回值如下:

!(https://s1.ax1x.com/2022/12/29/pSS5rLT.png)

- captcha_id:验证码 id
- captcha_output:login 请求参数
- gen_time:login 请求参数
- lot_number:login 请求参数
- pass_token:login 请求参数

`login` 接口验证登录成功:

!(https://s1.ax1x.com/2022/12/29/pSS7o3d.png)

## 四代逆向分析

### w 参数

与三代无感一样,四代无感 w 参数同样直接搜索 `"\u0077"` 即可定位到,r 为 w 参数的值:

!(https://s1.ax1x.com/2022/12/29/pSSjHJK.png)

r 参数定义在第 6237 行,内容如下:

```JavaScript
(0,d[$_CBHHO(84)])(f[$_CBHIE(84)][$_CBHHO(562)](e), i)
d["default"])(f["default"]["stringify"](e), i)
```

由上可知,r 是将 i 参数和转为字符串的 e 参数加密得到的,跟进到 `d[$_CBHHO(84)]` 中,加密函数定义在第 11669 行,在第 11707 行打下断在,返回值为 r 参数的值,即 w 值:

!(https://s1.ax1x.com/2022/12/29/pSSzjL4.png)

```JavaScript
(0,d[$_DIEHS(177)])(c) + u
d["arrayToHex")(c) + u
```

这里是将 c 数组转换成了十六进制的字符串然后加上 u 得到的 r 值,`d[$_DIEHS(177)]` 跟进去直接扣出来即可,c 定义在第 11705 行:

```
var c = s[$_DIEIq(1403)][$_DIEHS(1498)](e, i);
var c = s["symmetrical"]["encrypt"](e, i);
```

e 后文分析,i 为 16 位字符串:

!(https://s1.ax1x.com/2022/12/29/pSpp45n.png)

i 定义在第 11702 行,跟进到 `d[$_DIEIq(103)]` 方法中,i 为 16 位随机数:

!(https://s1.ax1x.com/2022/12/29/pSppzP1.png)

e 参数内容如下:

!(https://s1.ax1x.com/2022/12/29/pSp9Yin.png)

`device_id`、`lot_number` 由 `load` 接口返回,`pow_msg` 为 `"1|0|md5|" + datetime + "|" +captcha_id + "|" + lot_number + "||" + 16位随机数`,`pow_msg` 经过 MD5 加密即为 `pow_sign`,`"l0zs":"53502544"` 为动态变化的键值对,在往期四代滑块的文章中均有详细介绍,接下来跟进到 `s[$_DIEIq(1403)][$_DIEHS(1498)]` 中,c 为 AES 加密,扣代码或者直接引库:

!(https://s1.ax1x.com/2022/12/29/pSpCtTH.png)

u 定义在第 11704 行,i 为十六位随机字符串:

```
u = new l[($_DIEHS(84))]()[$_DIEIq(1498)](i);
u = new l["default"]()["encrypt"](i);
```

跟进到加密函数 `l[($_DIEHS(84))]` 中,在第 12725 行,于 12741 行打下断点,可以看到这里就是个 RSA 加密,扣代码或者直接引库即可:

!(https://s1.ax1x.com/2022/12/29/pSpC7BF.png)

## 四代结果验证

!(https://s1.ax1x.com/2023/01/03/pSiQUCn.png)

good7801 发表于 2023-4-10 18:18

太棒了,有这个可省事多了

xionghaizi 发表于 2023-4-11 15:16

k哥厉害啊

eoo 发表于 2023-4-13 20:24

k哥厉害啊 还是要多出更详细的流程教程

hirehao123 发表于 2023-4-14 08:13

震撼到我了

yxa52033 发表于 2023-4-15 01:31

牛批,只能说太牛皮
页: [1]
查看完整版本: 【验证码逆向专栏】某验三代、四代一键通过模式逆向分析