标准文件:
App违法违规收集使⽤个⼈信息⾏为认定⽅法》
《移动互联网应用程序(App)收集使用个人信息自评估指南》
《关于开展纵深推进APP侵害用户权益专项整治行动的通知》工信部〔2020〕164
《移动互联网应用程序(App)系统权限申请使用指南》
《移动互联网应用程序(App)个人信息保护常见问题及处置指南》
《移动互联网应用程序(App)个人信息安全防范指引》
《常见类型移动互联网应用程序必要个人信息范围规定》
《GB/T 37964-2019 信息安全技术 个⼈信息去标识化指南》
《GB/T 35273-2020 信息安全技术 个⼈信息安全规范》
《中华人民共和国网络安全法》
《中华人民共和国数据安全法》
《中华人民共和国个人信息保护法》
《中华人民共和国消费者权益保护法》
《信息安全技术 移动互联网应用程序(App)收集个人信息基本要求》
参考(功能) : 小米开放平台、vivo开放平台
底层(行为):需要通过注入JSON,HOOK接口才能实现,目前参考该方法亲测有效。
一、python安装第三方库(前提你安装了python环境)
步骤1:打开cmd 输入以下命令:
方法一:
pip install frida
pip install frida==16.0.1 # 指定版本号
方法二:
# 豆瓣:http://pypi.douban.com/simple/
# 清华:https://pypi.tuna.tsinghua.edu.cn/simple
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple frida
注意:
1.安装过程先更新pip; pip install --upgrade pip
2.进行安装命令,安装过程中很慢的情况下,可以使用方法二或使用方法一但需要翻墙下载;
3.安装完成后,请记住你的版本号。
二、查看雷电模拟器CPU架构类型
步骤2:雷电模拟器提前打开root权限,再模拟器中进行设置。如图:
步骤2:安装雷电模拟器,安装的过程就不再介绍了,通过adb连接模拟器,依次输入:
adb devices # 查看设置连接
adb shell # 进入调试命令
su # 获取root权限
getprop ro.product.cpu.abi # 查看架构
打印的cpu架构类型64位x86架构。
步骤3: 访问该地址 https://github.com/frida/frida/releases 下载对应的frida版本,python安装的是PC端frida16.0.1最好保持版本一致。如图:
解压后,拷贝至模拟器
adb push E:\雷电模拟器\leidian\frida-server-16.0.1-android-x86_64 /data/local/tmp/frida-server-16.0.1-android-x86_64
启动服务
./frida-server-16.0.1-android-x86_64
注意:若运行不成功 chmod 777 frida-server-16.0.1-android-x86_64
运行成功截图:
三、python代码部分
这是一个使用Frida库进行Android应用程序的动态分析的Python脚本。Frida是一款强大的动态分析工具,可以用于分析和操纵应用程序的运行时行为。
以下是这个脚本的主要功能:
1. `__init__`方法:定义了一个名为`AppInstrumentation`的类,该类接受一个包名和一个脚本文件列表作为参数,并初始化一个设备和会话对象。
2. `attach`方法:连接到指定的Android设备,并启动指定的应用程序。然后,它会在设备上创建一个Frida会话,并附加到新启动的应用程序进程。
3. `detach`方法:从应用程序进程中分离Frida会话。
4. `load_script`方法:加载并注入指定的Frida脚本到应用程序进程。它首先读取脚本文件的内容,然后创建一个Frida脚本,将脚本内容注入到应用程序进程,并设置一个消息处理器来处理从脚本发送的消息。
5. `on_message`方法:处理从Frida脚本发送的消息。如果消息类型是'send',则将消息的有效载荷写入到指定的文件。
6. `run`方法:启动动态分析过程。它首先附加到应用程序进程,然后加载和注入Frida脚本,最后等待用户输入以分离从应用程序进程。
在主函数部分,它创建了一个`AppInstrumentation`对象,并运行它,开始对指定的Android应用程序进行动态分析。
需要注意的是,这个脚本需要在已经安装了Frida的环境中运行,并且需要有对应的Frida脚本文件(在这个例子中是"script.js"和"request.js")。而且,运行这个脚本的设备需要连接到一个Android设备,并且该设备上需要安装指定的应用程序。
import frida
import chardet
class AppInstrumentation(object):
def __init__(self, package_name, script_files):
self.package_name = package_name
self.script_files = script_files
self.device = None
self.session = None
def attach(self):
# 创建一个设备对象
self.device = frida.get_usb_device()
# 连接到目标应用程序
pid = self.device.spawn([self.package_name])
print(pid)
self.session = self.device.attach(pid)
self.device.resume(pid)
def detach(self):
# 分离会话
if self.session:
self.session.detach()
def load_script(self):
# 为应用程序注入 Frida 脚本
for script_file in self.script_files:
with open(script_file, 'rb') as f:
file_content = f.read()
encoding = chardet.detect(file_content)['encoding']
with open(script_file, 'r', encoding=encoding) as f:
script_content = f.read()
script = self.session.create_script(script_content)
script.on('message', self.on_message)
script.load()
def on_message(self, message, data):
if message['type'] == 'send':
payload = message['payload']
# print("这是python的打印",payload)
if 'java.lang.Exception' in payload:
with open("script_trace.txt", "a") as f:
f.write(payload + "\n")
elif 'http' in payload:
with open("request_trace.txt", "a") as f:
f.write(payload + "\n")
def run(self):
self.attach()
self.load_script()
input('[+] Press <Enter> at any time to detach from instrumented program.\n\n')
self.detach()
# 应用包名
# 天之禁 com.shenwan.tzjzjps51
APP_PACKAGE_NAME = "com.shenwan.tzjzjps51"
# Frida 脚本文件路径列表
SCRIPT_FILES = ["script.js", "request.js"]
# 创建 AppInstrumentation 对象并运行
instrumentation = AppInstrumentation(APP_PACKAGE_NAME, SCRIPT_FILES)
instrumentation.run()
注意:
1.python是通过注入js的方式,且需要提前创建txt文档用于接收堆栈信息内容和请求数据内容request_trace.txt和script_trace.txt
2.需提前安装apk,获取包名的方式有很多方法可以百度,包的要求(未加固过的过或有反root检测、反frida、反调试的app)不可执行。
四、json代码部分
script.js文件
这是一个使用Frida库进行Android应用程序的动态分析的JavaScript脚本。它主要用于拦截和记录一些敏感的API调用,包括获取设备信息、网络信息、传感器信息、电话信息、系统属性、运行进程、剪贴板内容和WiFi信息等。
以下是这个脚本的主要功能:
1. `formatDateTime`函数和`logAndSend`函数:这两个函数用于格式化日期时间和记录日志。它们会在每次拦截API调用时被调用,以记录API调用的详细信息。
2. 对各种敏感API的拦截:这个脚本拦截了一系列敏感的API调用,包括但不限于获取应用程序信息、获取无线网络信息、获取网络接口信息、获取传感器信息、获取电话信息、获取系统属性、获取运行进程、获取剪贴板内容和获取WiFi信息等。在每次拦截API调用时,它会记录API调用的详细信息,并发送到Frida的Python端。
这个脚本需要在已经安装了Frida的环境中运行,它会在目标应用程序的进程空间内执行,拦截和记录API调用。这个脚本可以用于动态分析Android应用程序的行为,以帮助理解应用程序的运行机制,或者发现应用程序的潜在问题。
// 日期格式化
const formatDateTime = (date) => {
const year = date.getFullYear().toString();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
const hour = date.getHours().toString().padStart(2, '0');
const minute = date.getMinutes().toString().padStart(2, '0');
const second = date.getSeconds().toString().padStart(2, '0');
const milliseconds = date.getMilliseconds().toString().padStart(3, '0');
return `${year}-${month}-${day} ${hour}:${minute}:${second}.${milliseconds}`;
};
// 日志记录和发送
const logAndSend = (methodName, message) => {
const currentPackage = Java.use('android.app.ActivityThread').currentPackageName();
const stackTrace = Java.use('android.util.Log').getStackTraceString(Java.use('java.lang.Exception').$new());
const formattedTime = formatDateTime(new Date());
const logMessage = `${formattedTime} - ${currentPackage} - ${methodName} - ${message}\n${stackTrace}`;
console.log(logMessage);
send(logMessage);
};
// android.app.ApplicationPackageManager类及方法
const PackageManager = Java.use('android.app.ApplicationPackageManager');
PackageManager.getApplicationInfoAsUser.overload('java.lang.String', 'int', 'int').implementation = function(packageName, flags, userId) {
const result = this.getApplicationInfoAsUser(packageName, flags, userId);
logAndSend('getApplicationInfoAsUser-获取给定(包名)应用程序信息(名称、图标、资源、权限)', `flags: ${flags}, userId: ${userId}, result: ${result}`);
return result;
};
PackageManager.getPackageInfoAsUser.implementation = function(packageName, flags, userId) {
const result = this.getPackageInfoAsUser(packageName, flags, userId);
logAndSend('getPackageInfoAsUser-获取应用(包名、flags)程序信息(版本号、版本代码、包名称等)', `flags: ${flags}, userId: ${userId}, result: ${result}`);
return result;
};
// android.net.wifi.WifiInfo类及方法
const WifiInfo = Java.use('android.net.wifi.WifiInfo');
WifiInfo.getSSID.implementation = function() {
const result = this.getSSID();
logAndSend('getSSID-获取无线网络名称信息', `result: ${result}`);
return result;
};
// "02:00:00:00:00:00" 是一种特殊的 MAC 地址,称为“未知的”或“空的”MAC地址。它通常用于表示 MAC 地址未知或未配置。
WifiInfo.getMacAddress.implementation = function() {
const result = this.getMacAddress();
logAndSend('getMacAddress-获取WLAN网卡设备硬件地址', `result: ${result}`);
return result;
};
WifiInfo.getBSSID.implementation = function() {
const result = this.getBSSID();
logAndSend('getBSSID-获取WLAN路由器设备地址', `result: ${result}`);
return result;
};
// android.net.NetworkInfo类及方法
const NetworkInfo = Java.use('android.net.NetworkInfo');
NetworkInfo.getTypeName.implementation = function() {
const result = this.getTypeName();
logAndSend('getTypeName-网络类型的名称', `result: ${result}`);
return result;
};
NetworkInfo.getType.implementation = function() {
const result = this.getType();
logAndSend('getType-获取当前连接wifi类型', `result: ${result}`);
return result;
};
// java.net.NetworkInterface类及方法
const NetworkInterface = Java.use('java.net.NetworkInterface');
NetworkInterface.getNetworkInterfaces.implementation = function() {
const result = this.getNetworkInterfaces();
const array = [];
while (result.hasMoreElements()) {
const obj = result.nextElement();
const networkInterface = Java.cast(obj, NetworkInterface);
array.push({
name: networkInterface.getName(), //网络接口的名称
displayName: networkInterface.getDisplayName(), // 网络接口的显示名称
hardwareAddress: networkInterface.getHardwareAddress(), // 网络接口的硬件地址,也就是 MAC 地址
mtu: networkInterface.getMTU(), // 网络接口的最大传