某药品监管app——安卓端脱壳+RPC服务调用参数生成方法

查看 157|回复 11
作者:loushimin   
前言:
本篇帖子是在我爬虫笔记里的的记录
只是操作记录,代码量少
主要记录了脱壳、调试、objection hook、frIDA hook注入,最后调用注入的方法获取加密参数
一、环境准备:
1、某药品监管apk:v5.3.2
2、安卓端脱壳工具——BlackDex:无版本要求,最新的即可
github :
[color=]https://github.com/CodingGay/BlackDex/releases
脱壳环境要求
  • 一台普通手机
  • 无需Xposed
  • 无需Frida
  • 无需Magisk
  • 无需Root
  • 无需定制系统



    截图.png (45.75 KB, 下载次数: 1)
    下载附件
    安卓端脱壳工具——BlackDex
    2023-8-18 14:55 上传

       
    3、Frida  
    frida                   15.2.2
    frida-tools             11.0.0
    4、objection
    objection github:
    [color=]https://github.com/sensepost/objection
    pip install objection
    pip安装最新的即可,无版本要求
    5、jadx


    6、安卓真机或模拟器
    安卓 7
    逍遥模拟器
    7、Android Studio
    8、python 3.7


    二、开始
    1、抓包分析
    通过对app的抓包可知app端就一个加密参数 tzRgz52a签名
    [color=]
    headers:
    [JavaScript] 纯文本查看 复制代码  Accept-Language: zh-CN,zh;q=0.8
      User-Agent: Mozilla/5.0 (Linux; U; Android 7.1.2; zh-cn; HD1910 Build/N2G48H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
      Connection: close
      Host: mobile.nmpa.gov.cn
      Accept-Encoding: gzip
      tzRgz52a: BlRnN9IbxigK7nqPZitab6KNJ5oaPyiKKmPOSV-k_6JsT7bS0ywp0DhUwx7pDVsvshj5S5Mj26SqTg6YK_jc81sahiH4oH86rAotrTjoK8I3NYzEGP_wDWlJtGolNxD8XgDZr0z3hoyGzTI7dCuL2RI5e_uNwyIuD-yUEWz9TrTEKVO9Po1iWTPGbgfns9xN7bgjDYfbmHxiXi0IRWmBNZY2uNZ6I7b2iI2GeR2lLN_Zj42B2UP_oClQv5jdPxENikZ8GOa8UoJM4Slja0hY2k-FT6RWtjDoL6IvXIYy40WdnM0pYvMWxE2kkczs_WuN7nuFPKjZplGDwJYABG5R4qSchFSoIt_95rLa3N9OtgRvWMur9qQM3rHVZa16WqRKcYJqHwIrxiOncUS-udOLYfFtQlCLsxe0RlFpVxn0ykiw1O0ualP2_2r-mY7VoOKS0wDCM6aaWynDAfVdNQJonnRv1SjS9MjgJ0BgAMGdPwENNTUn_cAkwFK-HVZpw35H7PGqAk0DoMhNfQ9vR0XQ7p3eUkyc1Lp3bdDXL94AHZb3lVSEUicex9BumrwnkNGM3F3s4B1zjdetUk3tZZlj8u3v_Fj48wDC7zsR8-KOBkrGMBj-t2rOahfGk1PXqK8_epWVIysgbLlXInHP35587M0
      Connection: close
      Cache-Control: no-cache
    2、frida-server
    下载与frida版本对应的 frida-server,模拟器就下载 x86版本的(红框),安卓真机就下载arm版本的(蓝框),也可以adb shell 进入手机终端,执行以下命令查看内核版本,再下载相应的frida-server
    [Shell] 纯文本查看 复制代码adb shell
    getprop ro.product.cpu.abi


    截图2.png (6.41 KB, 下载次数: 0)
    下载附件
    2023-8-18 14:59 上传



    截图3.png (97.48 KB, 下载次数: 0)
    下载附件
    2023-8-18 14:59 上传

    将下载的frida-server-15.2.2-android-x86_64.xz解压,将文件夹中的 frida-server-15.2.2-android-x86_64 push到安卓目录 /data/local/tmp/ 下,并给该文件添加权限,然后并启动
    [Shell] 纯文本查看 复制代码adb shell
    cd /data/local/tmp
    su
    #添加权限
    chmod 777 frida-server-15.2.2-android-x86_64
    #启动frida-server
    ./frida-server-15.2.2-android-x86_64
    新建cmd窗口开启端口转发
    [Shell] 纯文本查看 复制代码adb forward tcp:27042 tcp:27042
    adb forward tcp:27043 tcp:27043
    在cmd窗口中输入 frida-ps -U命令后输出模拟器进程,说明frida安装成功
    [Shell] 纯文本查看 复制代码frida-ps -U


    截图4.png (16.37 KB, 下载次数: 0)
    下载附件
    2023-8-22 14:07 上传

    3、app脱壳
    在手机上安装 药监局app 和 BlackDex app
    对于BlackDex 64位的和32位的都要安装,如果一个脱壳失败,就换另一个版本


    截图5.png (140.07 KB, 下载次数: 0)
    下载附件
    2023-8-18 15:02 上传

    根据提示将脱壳后的dex文件提取出来


    截图6.png (12.75 KB, 下载次数: 0)
    下载附件
    2023-8-18 15:02 上传



    截图7.png (78.32 KB, 下载次数: 1)
    下载附件
    2023-8-18 15:02 上传

    4、调试
    使用jadx打开dex文件


    截图8.png (16.53 KB, 下载次数: 1)
    下载附件
    2023-8-18 15:05 上传

    先在jadx中全局搜索tzRgz52a 结果是搜不到的
    如果经验多的话 这时候就应该知道,先搜索与header有关的
    搜索 getheader 结果如下


    截图9.png (75.83 KB, 下载次数: 0)
    下载附件
    2023-8-18 15:05 上传

    可以发现,搜索到了很多,重点观察com开头的节点,发现两个可以的方法com.msec.MSecClient 的 _ts_getHeaderKey, _ts_getRequestHeader


    截图10.png (67.21 KB, 下载次数: 0)
    下载附件
    2023-8-18 15:05 上传

    下一步就可以根据上面的结果进一步调试hook看能否拿到我们想要的数据
    调试方法有很多
    1、objection hook
    2、python 写脚本 hook
    3、fridamanager 注入 js hook
    4、xposed 插件注入 js hook
    5、aosp 内置 frida hook
    都可进行尝试,这里用的是objection
    三、objection hook
    1、查找app及其包名


    cmd窗口执行  
    [Shell] 纯文本查看 复制代码frida-ps -Uai
    结果如下


    截图16.png (15.69 KB, 下载次数: 0)
    下载附件
    2023-8-22 14:07 上传

    com.hxzk.android.hxzksyjg_xj  即是包名
    2、objection hook
    cmd执行 ,进入objection
    [Shell] 纯文本查看 复制代码objection -g com.hxzk.android.hxzksyjg_xj explore


    截图12.png (13.33 KB, 下载次数: 0)
    下载附件
    2023-8-22 14:07 上传

    根据二、4的结果  搜索msec相关的类
    [Shell] 纯文本查看 复制代码android hooking search classes msec


    截图13.png (17.11 KB, 下载次数: 0)
    下载附件
    2023-8-18 15:07 上传

    hook com.msec.MSecClient 类,查看类中的方法,找到要hook的方法
    [Shell] 纯文本查看 复制代码android hooking watch class com.msec.MSecClient


    截图14.png (36.14 KB, 下载次数: 0)
    下载附件
    2023-8-18 15:09 上传

    hook以上两个方法
    [Shell] 纯文本查看 复制代码android hooking watch class_method com.msec.MSecClient._ts_getH
    eaderKey --dump-args --dump-backtrace --dump-return
    android hooking watch class_method com.msec.MSecClient._ts_getRequestHeader --dump-args --dump-backtrace --dump-return
    去app中请求接口,即可看到hook结果


    截图15.png (49.41 KB, 下载次数: 2)
    下载附件
    2023-8-18 15:09 上传

    根据hook结果可知 _ts_getRequestHeader()方法的返回值 即是  tzRgz52a签名
    [color=]
    3、使用frida hook并注入,hookjs如下:
    [JavaScript] 纯文本查看 复制代码function get_yjj_tzRgz52a() {
        console.log('script 加载成功')
        Java.perform(function () {
            console.log('hook test')
            var MainActivity = Java.use('com.msec.MSecClient');
            MainActivity._ts_getRequestHeader.implementation = function (x, y, z) {
                // 这里开始是原函数的逻辑
                console.log(x)
                console.log(y)
                console.log(z)
                // 这里对原函数的参数重新赋值
                var vaule = this._ts_getRequestHeader(x, y, z);
                // 返回原函数的结果
                console.log(vaule);
                return vaule
            }
        })
    }
    setTimeout(get_yjj_tzRgz52a)
    使用 以下命令注入:
    [Shell] 纯文本查看 复制代码frida -U -l 1.js 中国药品监管
    注意:这里注入后面写的是name 而并非包名
    如图所示,注入成功


    截图17.png (17.26 KB, 下载次数: 1)
    下载附件
    2023-8-18 15:11 上传

    在app中重新请求 接口,hook结果如下


    截图18.png (44.84 KB, 下载次数: 1)
    下载附件
    2023-8-18 15:11 上传

    0 0 http://mobile.nmpa.gov.cn/datasearch/QueryList?tableId=25&searchF=Quick%20SearchK&pageIndex=4&pageSize=15
    分别对应方法的参数 x y z,多次请求后发现 0 0是固定的,即只有参数z是变量,z就是 请求的数据接口链接
    4、RPC主动调用
    确定方法的参数后即可使用RPC将被动调用 改为主动调用
    稍微改动下hook的js
    [JavaScript] 纯文本查看 复制代码function getYjjTzRgz52a(x, y, z) {
        var vaule;
        Java.perform(function () {
            Java.choose('com.msec.MSecClient', {
                onMatch: function (instance) {
                    vaule = instance._ts_getRequestHeader(x, y, z);
                },
                onComplete: function () {
                    console.log('_ts_getRequestHeader()调用完成')
                }
            })
        })
        return vaule
    }
    rpc.exports = {
        getyjjtzrgz52a: getYjjTzRgz52a
    }
    RPC使用python实现,代码如下:
    [Python] 纯文本查看 复制代码#!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    #
    # Copyright (c) 2022 LouShimin, Inc. All Rights Reserved
    #
    # @version : 1.0
    # @AuThor  : LouShimin
    # @Time    :
    # @FileName: yjj.py
    # @desc    :
    import frida
    def on_message(message, data):
        if message['type'] == 'send':
            print(message['payload'])
        elif message['type'] == 'error':
            print(message['stack'])
    device = frida.get_usb_device()
    process = device.attach('中国药品监管')
    with open('./yjj_end_rpc.js', encoding='utf-8') as f:
        jscode = f.read()
    script = process.create_script(jscode)
    script.on('message', on_message)
    script.load()
    def get_yjj_rpc():
        rpc = script.exports
        return rpc
    def get_yjj_tzRgz52a(page):
        rpc = get_yjj_rpc()
        a1 = rpc.getyjjtzrgz52a(0, 0,
                                 'http://mobile.nmpa.gov.cn/datasearch/QueryList?tableId=25&searchF=Quick%20SearchK&pageIndex={}&pageSize=15'.format(
                                     page))
        print(a1)
    if __name__ == '__main__':
        while True:
            page = input('请输入页码:')
            print(page)
            get_yjj_tzRgz52a(page)
    运行程序后输入页码,返回值即为tzRgz52a 签名


    截图19.png (25.02 KB, 下载次数: 1)
    下载附件
    2023-8-18 15:14 上传

    5、Sanic+RPC远程调用
    接口文件如下:
    [Python] 纯文本查看 复制代码#!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    #
    # Copyright (c) 2022 LouShimin, Inc. All Rights Reserved
    #
    # @Version : 1.0
    # @Author  : LouShimin
    # @Time    :
    # @FileName: sanic_app.py
    # @Desc    :
    from sanic import Sanic
    from sanic.response import json as response_json
    from commons.frida_rpc.yjj_rpc import get_yjj_rpc
    app = Sanic(__name__)
    yjj_rpc = get_yjj_rpc()
    @app.route("/getSignFromJni", methods=['POST'])
    async def req_proxy_data(request):
        res = request.json
        yjj_url = res['yjj_url']
        tzRgz52a = yjj_rpc.getyjjtzrgz52a(0, 0, yjj_url)
        print(tzRgz52a)
        res_data = {
            'msg': 'success',
            'code': 200,
            'tzRgz52a': tzRgz52a,
            'yjj_url': yjj_url
        }
        return response_json(res_data)
    if __name__ == '__main__':
        app.run("0.0.0.0", port=16383, debug=True, workers=30)
    改造并引入三、4中的 getyjjtzrgz52a()方法接口通过接口形式调用:


    截图20.png (85.59 KB, 下载次数: 0)
    下载附件
    2023-8-18 15:14 上传

    下载次数, 截图

  • loushimin
    OP
      


    嘛哩嘛哩轰 发表于 2023-11-12 20:38
    怎么现在 5.3.2的apk 打开直接弹 禁止root 设备安装apk了。。。。

    在面具中对该应用隐藏面具,再使用JsHook app对该应用hook,过掉root检测。如图:
    loushimin
    OP
      


    天空宫阙 发表于 2023-11-11 11:58
    rpc调用确实很方便,就是感觉不能大量调用,加密参数可能包含了设备的信息

    这个我个人觉得不是太大的问题,web端可以用指纹浏览器,安卓端可以用“应用伪装”等app去修改设备的信息,所以我认为设备信息对于rpc来说只是个小坎,稍微做点改动就过去了
    zhouzheng1201   

    不错不错,支持一下
    嘛哩嘛哩轰   

    不错不错,支持一下
    wantwill   

    不错不错,支持一下
    中原一点红   

    过来看看
    mcby   

    再学习一下大脑的技术。
    Mist520   

    感谢分享 谢谢大佬
    天空宫阙   

    rpc调用确实很方便,就是感觉不能大量调用,加密参数可能包含了设备的信息
    您需要登录后才可以回帖 登录 | 立即注册

    返回顶部