本次逆向的结果可能大概率对您没有任何用处,但是您也可以参考一下思路。
前情提要
话说我之前在宿舍里部署了路由器和番剧服务器,这路由器什么都好,可就是每天半夜校园网断网后第二天早上需要手动重新登录,于是我就想写一个自动登录校园网的脚本,让每天凌晨的时候树莓派能自动执行脚本登录一下。
实战经历
首先观察登陆页面:

看到登录需要提供账密以及验证码,那么按照常规思路,账密肯定是在数据包中要发给后端的,因此首要的就是要过验证码这一关,果断启动Burpsuite抓个包。
好消息,启动抓包后点击验证码刷新并没有受到影响,而bp也没有抓到包,这说明整个验证码的生成和校验过程是在前端进行的,因此我们大概率可以直接获取到当前验证码的值,甚至绕过验证码直接发包。
验证码
不过包着好奇心,还是来了解一下验证码相关的逻辑:
按F12打开开发人员模式。选择源代码,到js文件夹里把几个js文件都保存下来备用
不过直接保存下来的话js文件只有一行,非常不利于分析,所以建议还是在本地新建同名文件,然后把浏览器里面格式化之后的js脚本内容复制粘贴一下。

我们在下面的搜索栏中搜索相关关键词,例如vercode,看到app.5ee45fcc.js这个文件里出现了很多次这个关键词,随便点进一个搜索结果:
看到相关的代码
|
|
我肯定是不想看也看不懂的,所以交给AI分析,AI得出的结果是:
- 值就在
this.options.code里 - 校验只发生在前端
validate() - 后端大概率根本不验证验证码
核心:
|
|
e = 验证码字符数组
this.options.code = 最终验证码字符串
canvas 只是“画出来”
再看:
|
|
校验逻辑:
用户输入 vs this.options.code
完全在前端
再看 Vue:
|
|
说明:
e是验证码字符来源refresh()每次重新画图- code 是 refresh 时生成的
所以我们可以直接在控制台 Console 中执行下面的命令拿到验证码:
|
|
登录校验
既然验证码肯定是不需要了,那么接下来就着手看看账密怎么解决。
因为我们学校的校园网登录分为两步,
- 第一步:输入账密和验证码(已知可绕过),点击登录
- 第二步:在弹出的运营商列表中选择校园卡所属的运营商,如图:

按照惯例,分成这两步,抓个包先:
登录.txt
|
|
选运营商.txt
|
|
分析这两部的数据包,可以看到对/api/v1/login这个接口发起了POST请求,参数是前端加密过后的,共有5个:
- username
- passward
- ifautologin
- channel
- pagesign
- usripadd
并且其中channel和pagesign在一二两部中值也不同。
到目前为止,其实要写出自动化脚本已经足够了,直接把这几个不明所以的参数一发就完事,但是不知道持久性如何,而且既然要逆向,何不一探究竟呢?正如千反田爱瑠所说:“我很好奇!”
根据刚才对数据包的分析结果,我们选取pagesign作为关键词,同样在开发者模式的源代码中的几个js脚本中搜索:结果显示,chunk-2bb67818.1726b525.js中有3条结果:
|
|
可以看到里面多次提到了Object(A.a)(参数1,参数2)和Object(A.b)(参数1,参数2)的形式
并且大概可以推断出之前抓到登录中的channel就对应着A.a("_GET", key),而在选运营商中channel就变成了别的字符串。
所以接下来的目标很明朗,就是要找到这个A.a()和A.b()的源码,搞清楚它们究竟在做什么。
由于javascript的逆天结构,一个函数背后会有其id,再根据id映射到源码,还有可能层层套娃,所以根本不是人看的,这里我们借助集成AI的IDE来完成这项工作,为了不浪费我的Codex额度,我使用国产免费的Trae。
在Trae中打开到之前我们保存js脚本的文件夹,让ChatGPT给我们写一个prompt:
|
|
把prompt粘贴到IDE的聊天侧栏中回车,AI就开始工作了。
大概两分钟,AI输出了结果:
分析结果
变量A的来源 在 chunk-2bb67818.1726b525.js 文件的第161行,变量A是通过以下方式引入的:
|
|
模块定义
在 app.5ee45fcc.js 文件的第14515行,找到了模块90c5的定义:
|
|
函数分析
- A.a 函数
|
|
分析:
- 加密算法: AES-ECB
- 填充方式: Pkcs7
- 默认密钥: “axaQiQpsdFAacccs”
- 输入:
- 第一个参数:要加密的数据
- 第二个参数(可选):密钥,默认为"axaQiQpsdFAacccs"
- 输出: AES加密后的十六进制字符串
- A.b 函数
|
|
分析:
- 哈希算法: SHA256
- 输入: username
- 处理逻辑: 对"axaQiQpsdFAacccs"+username进行SHA256哈希,然后取前16个字符
- 输出: SHA256哈希值的前16个字符
- 依赖库 :
- 第三方库: CryptoJS
- 模块3452: 是CryptoJS库的入口点,包含了AES和SHA256等加密算法的实现
至此已经基本一目了然了,现在唯一的一点就是选运营商时发生改变的channel和pagesign了,不过根据前面看到的登录时pagesign的明文是firstauth可以大致推断第二次发包里明文应该是secauth,反正密钥和加密方法都确定了反向解密不就行了吗?
验证猜想和编写脚本
根据目前已经收集的信息,初步得到一个脚本:
|
|
不过先不着急使用它,我们先按照逻辑生成一个key拿到cyberchef上反向解密一下第二个channel的明文:

解密结果竟然是3,不过回想起来第一次登录时候服务端返回的内容也就明白了:
{"code":200,"message":"ok","data":{"channels":[{"id":"1","name":"校园网"},{"id":"3","name":"中国电信"},{"id":"2","name":"中国移动"},{"id":"4","name":"中国联通"}]}}
所以这里的明文其实就对应着所列出的运营商的id。
接下来顺手把第二个pagesign反向解密一下:

事实证明它的明文是secondauth。
至此,整个逻辑链条已经被我们完全破解,把上面的脚本优化一下就可以得到一个更适合实际部署的脚本:
|
|
然后再在树莓派上设一个计划任务就可以愉快的使用了。
经验总结
js这种不是给人看的东西一定要多用AI。