环境:
- 粉笔考研 v6.3.15:https://www.wandoujia.com/apps/1220941/history_v6031500
- 雷电9 模拟器:https://www.ldmnq.com/
- 安装 magisk:https://blog.csdn.net/Ruaki/article/details/135580772
- 安装 Dia 插件 (作用:禁用弹窗):https://github.com/Xposed-Modules-Repo/dialog.box
Dia 插件 功能
- 取消弹窗。(取消 app 的强制升级。例如:得物app、粉笔考研app)
- 禁用退出(退出+完成)(可以与键控制组合)
- 按关键字禁用弹出框(悬停窗口+对话框)(可与按键控制结合使用)
- 版本自定义(版本号+版本名称)
- 伪装系统时间(系统时间+ GPS时间+本地访问服务器时间)
- 此模块的反检测,Xposed,Root
- 启动时禁用网络(可设置禁用时间)
- 强制结束当前活动(Activity)(通过组合键控制)
- 反禁用Xposed(简单禁用)
直接搜索关键字 "major/school_score"
major/major_score
分析后发现是 rsa 加密方式,rsa 是非对称加密,需要一个公钥、一个私钥。
通过 hook 验证,发现 函数a 就是用来解密的。
- 方法 1:逆向算法,直接 python 实现
- 方法 2:用 java 实现,然后打包成 jar 包,python 调用 jar 包
- 方法 3:通过 rpc 方式
下面 通过 rpc 方式实现。
模拟器中执行 frida-server,并设置端口转发。
rcp 方式调用
import time
import frida
import uvicorn
from pathlib import Path
from fastapi import FastAPI, Requestjs_code = """
console.log("Script loaded successfully ");
function callDecryptFunc(mi_str) { //定义导出函数let local_result;Java.perform(function x() {console.log("hook 成功");console.log(mi_str);let li9 = Java.use("li9");let result = li9.a(mi_str);console.log(`result ---> ${result}`);local_result = resultreturn result;});return local_result;
}
rpc.exports = {// 导出名不可以有大写字母或者下划线calldecrypyfunc: callDecryptFunc
};
"""def my_message_handler(message, payload):print(message)print(payload)def get_session():device = frida.get_usb_device()time.sleep(2) # 睡眠2秒, 防止程序运行过快从而导致附加不上session = device.attach("粉笔考研")return sessiong_session = get_session()
script = g_session.create_script(js_code)
script.on("message", my_message_handler)
script.load()app = FastAPI()@app.get("/decrypt_data")
@app.post("/decrypt_data")
async def root(request: Request):data_dict = await request.json()encrypt_data = data_dict['encrypt_data']global scriptdecrypt_data = script.exports_sync.calldecrypyfunc(encrypt_data)ret_val = {'encrypt_data': encrypt_data,'decrypt_data': decrypt_data}return ret_valif __name__ == '__main__':uvicorn.run(f'{Path(__file__).stem}:app', host="0.0.0.0", port=6666)pass
执行结果
测试脚本。"Cookie": "换成自己的cookies"
import json
import requestsrequests.packages.urllib3.disable_warnings()headers = {"User-Agent": "fenbi-android","Host": "schoolapi.fenbi.com","Cookie": "换成自己的cookies"
}def get_decrypt_data(data_dict=None):url = "http://127.0.0.1:6666/decrypt_data"resp_2 = requests.post(url, json=data_dict, verify=False)ret_val = {'name': data_dict['name'],'decrypt_data': resp_2.json()['decrypt_data'],}return ret_valdef main():url_1 = "https://schoolapi.fenbi.com/kaoyan/android/kyzz/major/school_score"url_2 = "https://schoolapi.fenbi.com/kaoyan/android/kyzz/major/major_score"college_info = [{"dm": "10001", "name": "北京大学"},{"dm": "10003", "name": "清华大学"},]for item in college_info:dm = item['dm']name = item['name']querystring_1 = {# "school": "10007", "type": "01", "year": "0","school": dm, "type": "01", "year": "0",# "client_context_id": "2F3B0BCDA482C2DE2D23",# "version": "6.3.15", "vendor": "Huawei",# "app": "kaoyan", "av": "69", "kav": "27", "hav": "4",# "deviceId": "AKJWMHTPfy/pM1yprG3inw==",# "quizId": "0", "imei": "", "oaid": "",}querystring_2 = {"school": dm, "type": "01", "year": "0", "department": "",# "client_context_id": "A28D05AA5A8943BF6D8F",# "version": "6.3.15", "vendor": "Huawei",# "app": "kaoyan", "av": "69", "kav": "27", "hav": "4",# "deviceId": "AKJWMHTPfy/pM1yprG3inw==",# "quizId": "0", "imei": "", "oaid": "",}resp = requests.get(url_1, headers=headers, params=querystring_1, verify=False)resp_json = resp.json()post_data = {'name': name,'encrypt_data': resp_json['data']}data_1 = get_decrypt_data(post_data)resp = requests.get(url_2, headers=headers, params=querystring_2, verify=False)resp_json = resp.json()post_data = {'name': name,'encrypt_data': resp_json['data']}data_2 = get_decrypt_data(post_data)data = {'name': name,'school_score': data_1['decrypt_data'],'major_score': data_2['decrypt_data']}print(data)if __name__ == '__main__':main()pass
执行结果
app 显示结果