本帖最后由 loushimin 于 2023-8-22 14:13 编辑
前言:
本篇帖子是在我爬虫笔记里的的记录
只是操作记录,代码量少
主要记录了脱壳、调试、objection hook、frIDA hook注入,最后调用注入的方法获取加密参数
一、环境准备:
1、某药品监管apk:v5.3.2
2、安卓端脱壳工具——BlackDex:无版本要求,最新的即可
github : https://github.com/CodingGay/BlackDex/releases
脱壳环境要求
- 一台普通手机
- 无需Xposed
- 无需Frida
- 无需Magisk
- 无需Root
- 无需定制系统
安卓端脱壳工具——BlackDex
3、Frida
frida 15.2.2
frida-tools 11.0.0
4、objection
objection github:https://github.com/sensepost/objection
pip install objection
pip安装最新的即可,无版本要求
5、jadx
6、安卓真机或模拟器
安卓 7
逍遥模拟器
7、Android Studio
8、python 3.7
二、开始
1、抓包分析
通过对app的抓包可知app端就一个加密参数 tzRgz52a签名
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
将下载的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
3、app脱壳
在手机上安装 药监局app 和 BlackDex app
对于BlackDex 64位的和32位的都要安装,如果一个脱壳失败,就换另一个版本
根据提示将脱壳后的dex文件提取出来
4、调试
使用jadx打开dex文件
先在jadx中全局搜索tzRgz52a 结果是搜不到的
如果经验多的话 这时候就应该知道,先搜索与header有关的
搜索 getheader 结果如下
可以发现,搜索到了很多,重点观察com开头的节点,发现两个可以的方法com.msec.MSecClient 的 _ts_getHeaderKey, _ts_getRequestHeader
下一步就可以根据上面的结果进一步调试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
结果如下
com.hxzk.android.hxzksyjg_xj 即是包名
2、objection hook
cmd执行 ,进入objection
[Shell] 纯文本查看 复制代码 objection -g com.hxzk.android.hxzksyjg_xj explore
根据二、4的结果 搜索msec相关的类
[Shell] 纯文本查看 复制代码 android hooking search classes msec
hook com.msec.MSecClient 类,查看类中的方法,找到要hook的方法
[Shell] 纯文本查看 复制代码 android hooking watch class com.msec.MSecClient
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结果
根据hook结果可知 _ts_getRequestHeader()方法的返回值 即是 tzRgz52a签名
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 而并非包名
如图所示,注入成功
在app中重新请求 接口,hook结果如下
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 签名
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()方法接口通过接口形式调用:
|