先贴出 Github 地址: https://github.com/lyc8503/VizpowerHook.
众所周知, 因为一只蝙蝠, 暑假没有了, 寒假像滚雪球似的越来越长, (网课却照上不误).
我们学校使用了一款名叫 无限宝 的网课软件, 软件功能主要就是课程直播, 附带(?)了一些点名签到, 自动锁屏, 认真度统计**(会直接截取电脑屏幕)**. 用了几天之后, 想添加一个自动进入课堂, 自动签到, 外加自动录像保存的功能.
开始打算逆向它的协议, 结果它的协议是基于TCP的, 用的Java nio, 整个通讯协议还是挺复杂的, 感觉重写协议栈耗时过久代价太大, 便换了个思路, 打算用客户端的逆向与修改实现功能.
以前到现在用的语言一直是 Java, 安卓开发也学过, 所以客户端的逆向难度应该也不是很大…(flag高高挂起x
结果刚刚反编译客户端就遇到了麻烦: 他喵的这客户端加固过了 !!
一看 qihoo, 是360的壳, 网上找找工具应该能脱下来, 利用 Java 的反射或直接 Hook 系统的载入 Dex 文件代码也都能很轻易的脱壳, 就是费点事, 不再多说.
很快拿到真正的 Dex 文件, 二话不说直接丢进 Jadx 反编译. 发现这段代码没有混淆.(??)
反编译过后的源代码
以逆向登陆协议为例:
直接抓包找到相关接口…通过 Fiddler 抓到相关包, 分析后用 python requests 库可以写成这样的代码:
1 2 3 4 5 6 7 8 9
| r = requests.get("http://" + prefix + ".kehou.com/courseList.action", params={ "uid": user_name, "pwd": pwd, "pwd2": pwd2, "salt": salt, "callfrom": "vpAndroid", "mac": "00:00:00:00:00:00", "needReplayInfo": "CourseListAndReplayCourseList" })
|
其中 salt 是当前的 unix 时间戳, pwd 和 pwd2 是 MD5 加密过后的密码.
1 2
| String pwd = MD5.stringMD5(UserName + strPassword + strSalt + "WINUPON").toLowerCase(); String pwd2 = MD5.stringMD5(UserName + MD5.stringMD5(strPassword).toLowerCase() + strSalt + "WINUPON").toLowerCase();
|
有了登陆协议可以轻松获取模拟客户端的登陆… 返回数据样例如下(是一个ini文件):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| [mt1] MeetId=55172457 timesId=13 Meeting-Subject=高一学年测试学员是否正常登陆课堂 MeetCurrTime=2020-02-29 13:27:52 Meeting-Duration=06:00:00-23:00:00 EastimateTime=1020 MeetStartTime=2020-02-29 06:00:00.000 Meeting-Chairman=主讲教师 Meeting-Project=[REMOVED] Meeting-BeforeTime=15 userId=72949 NickName=[REMOVED] Course-Big-PictureUrl=http://cnkehou.kehou.com/vipkehou/upload/course/12/2020/02/18/55172457_1582010896851_big.jpg Course-Total-time=44 WinAppTitle=[REMOVED] ProjectName=[REMOVED] NeedSSR=1 ServerIP=hzlawxlogin.wanpeng.net Port=7000 AutoRecordPrompt=0 Meeting-AddTime=15 ClientType=1 ProxyAllocType=0 MultiMeeting=0 listenType=0 MeetingQuitURL= PresidentKey2=f0cbeb337a58fd8db2849698627f1553 VerifyKey=cf10bc1b4c7f592948335a4a2c1d8d67 signupCount=0 TeacherOverviewURL=http://sdfz.vip.kehou.com/teacherInfo.htm?userId=67934 StudentDetailURL=http://sdfz.vip.kehou.com/studentInfo.htm? SnapUploadURL=http://vpbridge.vip.kehou.com/dataii/wxb_snapshot_upload.do TestResultURL= VoteResultURL= RestVodURL=http://cnkehou.kehou.com/vipkehou/sysfile/video/ybjc.swf QRCodeBaseURL= ClassNoteURL=http://vpbridge.vip.kehou.com/dataii/class_note_interaction.do? StuSchool=[REMOVED] StuClass=[REMOVED] StuPhone= CameraRemind=0 CameraSnap=0 NDConf=100 ShowUserCount=0 ClassAutoLock=0 IPVCamera=0 VideoQualityLevel=1 AllowHLS=0 NetDiskProtocol=4 NetDiskUploadURL=0: NetDiskNotifyURL=[REMOVED] NetDiskUserName=[REMOVED] NetDiskUserPasswd=[REMOVED] EvaluateURL=https://sdfz.vip.kehou.com/wxbCourse/courseComment-openDiv.htm?userId=72949&courseId=55172457&courseSeq=13&mil=1582954072348&sign=552cc56b59c618ecd3944bf2cdee4caa&source=1& DocURL=http://vpbridge.vip.kehou.com/dataii/wxb_doc_interaction.do? GreenScreenURL=http://sdfz.vip.kehou.com/background/queryBackgroundPic.htm?agencyId=12 FeedbackURL=http://sdfz.vip.kehou.com/wxbSuggestion/wxbSuggestion-openDiv.htm?userId=72949&mil=1582954072348&sign=d87f8ef2f2baacd01e29ad6af5720822 MultiVideoChannels=0 SensitiveWordsURL=http://cnkehou.kehou.com/vipkehou/upload/filterWord/2020/02/20/sensitiveWords_1582191548329.txt EditTestStdAns=0
|
从返回数据中可以获取下一步登陆服务器的 IP 地址和端口… 但是接下来的通讯都使用了 TCP 协议, 逆向分析相对比较复杂… 就换了一个角度: 使用 Xposed 框架直接 Hook 软件本身获取或修改相关数据.
以强制打开公聊为例: 搜索”私聊”字样, 找到如下代码.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public final void clickSwitchChatTo() { if (ChatMgr.getInstance().canSendChatPub() && ChatMgr.getInstance().canSendChatPriv()) { this.m_bChatToPub = !this.m_bChatToPub; checkEnableInput(); if (this.m_bChatToPub) { iMeetingApp.getInstance().showAppTips("切换到公聊"); } else { iMeetingApp.getInstance().showAppTips("切换到与老师私聊"); } } else if (this.m_bChatToPub) { iMeetingApp.getInstance().showAppTips("当前仅限进行公聊!"); } else { iMeetingApp.getInstance().showAppTips("当前仅限与老师进行私聊!"); } }
|
很显然 ChatMgr.getInstance().canSendChatPub() 方法是判断是否能进行公聊的方法.
直接使用 Xposed Hook 方法, 直接返回 true.
代码如下(前面绕过 360 加固部分的代码太长就不发了x):
1 2 3 4 5 6 7
| public class PubChatHook extends XC_MethodHook { @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); param.setResult(true); } }
|
再次登陆课堂, 发现可以在老师没有打开公聊权限的时候发送公聊…
效果图
以此类推, 可以实现很多更多的功能, 详见 Github: https://github.com/lyc8503/VizpowerHook.
至于自动录像课程… 有点懒暂时不想做了(反而开始了写外挂了(雾)), 反正丢在虚拟机里开个 OBS 就可以录制了.
总结: 学到了挺多知识的, 踩坑肯定会有, 另开文章再写, 进一步熟悉了Android开发(终于不是抄抄样例程序混日子了x), 顺便找到这个相对简单的任务练练手, 学会了Xposed API, 不知道 接下来 Hook QQ & 微信 有没有希望.(或者可能选用他人现成的 QQ & 微信 框架不要重造轮子更好…?)
(其实本来学 Xposed 真的只是想写一个 QQ 机器人没想到副产物就是这个 Vizpower Hook了.)
2020.03.12 补充: 后来反编译的代码被官方发现了, 然后就在 Github 上面把无限宝本体的代码下架了, 那些漏洞官方应该也会修, 但官方也没要求我删除这个项目, 留下这个 Github 项目留念也不错, 恰好我们学校因为大课堂效果不好, 在3月中旬之后也不使用无限宝上课了, (也算是有一个比较完美的结局?), 所以就这样啦~
2020.08.13更新: 写了无限宝作业爬虫之后发现现在使用 AES 加密来加密登陆参数. 逆向思路类似就不再写文章了.