在之前的文章从零开始开发一个自动抓取教务系统课表等信息并动态显示的安卓课程表APP,原理分析及功能实现完美教程中,详细介绍了使用HttpClient抓取教务系统的方法,但是本次正方教务系统又?叒叕升级了,改用了AES加密,那本次就来分析并解决这个问题。
一、问题复现
在今天改进WTUCloud项目时,偶然发现一直无法登录教务系统,并提示200错误,尝试无数次后,依然没有办法,最终去官网查看,发现首页都变了——又更新了,使用
可以看到密码变成了一串108字符的乱码
果断翻看登陆界面源代码,发现多了如下内容:
一段id为
多了一个名为
以及一个名为
整理阅读代码后,在其中发现了如下函数:
1 2 3 4 5 6 7 | function encryptAES(data, _p1) { if (!_p1) { return data; } var encrypted = _gas(_rds(64) + data, _p1, _rds(16)); return encrypted; } |
根据这一个函数就可以得出如下结论:
- 刚刚的108位乱码是密码解析AES-CBC加密后的结果
- 在AES加密同时使用了Base64和Base16编码
pwdDefaultEncryptSalt 为加密公钥
有了如上结论,就可以手动模拟进行AES加密了
二、实现AES加密
为了防止教务系统的加密方式改动,这里使用教务系统云端的加密函数,不在本地存储,同之前模拟登录一样,使用GET方法抓取加密JS脚本
1 2 3 4 5 6 7 8 | RequestConfig config = RequestConfig.custom().setRedirectsEnabled(false).build();//不允许重定向 CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(config).build();//配置浏览器 String url="https://auth.wtu.edu.cn/authserver/custom/js/encrypt.js"; HttpGet httpGet=new HttpGet(url); CloseableHttpResponse response=httpClient.execute(httpGet); HttpEntity httpEntity=response.getEntity(); //获取js String js= EntityUtils.toString(httpEntity,"UTF-8"); |
抓取到JS脚本后,使用
1 2 3 4 5 | ScriptEngine engine = new ScriptEngineManager().getEngineByName("javascript"); //写入函数 engine.eval(js); //实例化引用 Invocable invoke = (Invocable) engine; |
最后返回所需要的结果
1 | String ans= (String) invoke.invokeFunction("encryptAES",password,pwdkey); |
注意!password是用户密码,需要手动输入,pwdkey是加密公钥,可以直接从登录页面抓取,方法同之前抓取lt一样
1 2 3 | //得到公钥 pwdkey=body.select("[id=pwdDefaultEncryptSalt]").attr("value"); System.out.println("pwdkey: " +pwdkey); |
三、在安卓上如何使用JS
刚刚方法测试环境为IDEA,可以完美通过,但是SDK中没有
最后将加密后的ans替换passwrod即可,其他流程同之前一样,就不在赘述,具体请参考上一篇文章,更新后的源码以及同步上传到Github,有需要的可以自取
Githu地址:Android-JAVA-ZFeducation-system
记录不易,查阅了很多资料,写笔记的初心是希望大家日后遇到同样问题,可以少走弯路,我为人人,人人为我,有用的话,记得点个赞哦~