python+Android-APP隐私合规检测-模拟器操作

标准文件:
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(), // 网络接口的最大传
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值