说实话这个软件的确很良心,突然不能用了有点难受,我在搜索了一番也没有找到解决方案,目前唯一的解决办法就是用HttpCanary重写相应验证的网络请求响应,但是得每次启动都把HttpCanary打开才行,麻烦但是能行。
看着剩余时间从15天到了现在的3天,每次打开都能看见这个验证,怎么彻底解决这个问题一直困扰着我,今天闲着的时候顿悟,我学了安卓开发,又学了安卓逆向,解决这个问题不是手到擒来,只可惜学逆向看的教程用的Hook方法和我想用的不一样就没上手练过,这次算是有机会给我练练了,就这么有了这篇记录。
验证提示截图:
Screenshot_20241026-211421_Matrixx Home.png (140.97 KB, 下载次数: 0)
下载附件
2024-10-26 21:22 上传
分析:
由于之前用HttpCanary抓包分析了相应验证,就打算Hook相应验证的网络请求的方法,在验证前改写网络请求回调传入的参数。
首先身份验证请求的链接是:https://tob-api.jd.com/tob/api/college/user/verify/info……
返回的参数是json数据:{"data":{"need_verify":true,"verify_state":0,"start_prompt_time":1728884471000,"remain_verify_days":3},"result_code":0,"message":"SUCCESS"}
没有加密,意思也很明确了,改写need_verify和verify_state就可以了
现在就是怎么Hook相应的网络请求验证方法了
首先要先找到验证的方法,我通过搜索相应的数据类属性来查找的调用处,由于开发的时候通常都是这么写的,我想这个App应该也是这样,那么就用Jadx打开apk文件反编译代码,尽量搜索唯一的关键字,我选择的是start_prompt_time,直接搜start_prompt_time或者startPromptTime,直接搜start_prompt_time没有找到,搜startPromptTime就有了,如下图所示:
2024.10.26_215502.png (62.7 KB, 下载次数: 0)
下载附件
2024-10-26 21:55 上传
跳转过去后就看到数据类实体了,和网络请求返回的一样,如下图所示:
2024.10.26_215630.png (64.96 KB, 下载次数: 0)
下载附件
2024-10-26 21:57 上传
然后右键VerifyInfoEntity点击查找用例,找到这个实体类在哪被使用了,跳转后的截图如下:
2024.10.26_220000.png (217.63 KB, 下载次数: 0)
下载附件
2024-10-26 22:00 上传
很明显UserVerifySelectAction类中的内部类a的j方法就是身份验证的的网络请求回调,里面还有计算时间的代码,100%确定了。
代码位置找到了,现在就是编写lsposed模块来持久化Hook了,由于我学的Hook是跟着论坛里的教程学了,用的是java,但是我不想写java,又因为很久没写java不会写了,只会kotlin。
正好有大佬编写了一套Kotlin的Hook:YukiHookAPI,首先用YukiHookAPI构建工具创建了一个lsposed项目模板,再用Android Studio打开,边看文档和示例代码就开始写了,期间不会的就问chatgpt了,想不到chatgpt连安卓逆向也会,Ai真的太强大了
顺带用同样的方法把启动页给关掉了,每次启动都要等3秒,虽然显示的不是广告,但是和广告达到了同样的效果,让用户点跳过或者等3秒……,不过现在清爽了
最终核心代码20行不到,我之前还一直以为Hook会比开发要难,结果出乎我的意料,不过仔细想想,也是因为有各个大佬开发的框架,才可以这么便利的Hook,感谢大佬!
论坛的代码插入居然没有Kotlin,那就选java吧,实际上是Kotlin,核心代码如下:
[Java] 纯文本查看 复制代码
@InjectYukiHookWithXposed
class HookEntry : IYukiHookXposedInit {
override fun onInit() = configs {
configs {
debugLog {
tag = "JingDongReaderCampus"
isEnable = true
isRecord = false
elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID)
}
isDebug = true
isEnableModuleAppResourcesCache = true
isEnableHookSharedPreferences = false
isEnableDataChannel = true
}
}
override fun onHook() = encase {
loadApp(name = "com.jingdong.app.reader.campus") {
// 注册模块 Activity 代{过}{滤}理
onAppLifecycle {
onCreate { registerModuleAppActivities() }
}
val headersClass by lazyClass("okhttp3.Headers")
// Hook验证
"com.jingdong.app.reader.main.action.UserVerifySelectAction\$a".toClass().apply {
method {
name = "j"
param(IntType, headersClass, StringClass)
}.hook {
before {
// 修改传入的参数 `str`
args[2] =
"{\"data\":{\"need_verify\":false,\"verify_state\":1,\"start_prompt_time\":1728884471000,\"remain_verify_days\":365},\"result_code\":0,\"message\":\"SUCCESS\"}"
}
}
}
// Hook启动页
"com.jingdong.app.reader.logo.action.GetSplashImageAction\$a".toClass().apply {
method {
name = "j"
param(IntType, headersClass, StringClass)
}.hook {
before {
// 修改传入的参数 `str`
args[2] =
"{\"data\":{\"has_adv\":false,\"name\":\"浙江大学的启动图\",\"pic_address\":\"https://img10.360buyimg.com/ebookadmin/jfs/t1/194181/34/42246/108158/655abb8cF1a52e14c/e9fe15f9f3072098.png.dpg\",\"jump_type\":0},\"result_code\":0,\"message\":\"SUCCESS\"}"
}
}
}
}
}
}
下载地址:
蓝奏云:https://wwur.lanzout.com/b0pm3gdza
密码:jdds