爬虫 APP 逆向 ---> 粉笔考研

环境:

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, Request


js_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 = result
        return 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 session


g_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 script
    decrypt_data = script.exports_sync.calldecrypyfunc(encrypt_data)
    ret_val = {
        'encrypt_data': encrypt_data,
        'decrypt_data': decrypt_data
    }
    return ret_val


if __name__ == '__main__':
    uvicorn.run(f'{Path(__file__).stem}:app', host="0.0.0.0", port=6666)
    pass


执行结果

测试脚本。"Cookie": "换成自己的cookies"

import json
import requests


requests.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_val


def 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 显示结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值