android隐私违规获取问题处理 及 Hook拦截处理记录 (VirtualXposted/epic等)

Posted iOSTianNan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android隐私违规获取问题处理 及 Hook拦截处理记录 (VirtualXposted/epic等)相关的知识,希望对你有一定的参考价值。

最近公司启动了隐私合规检测,报告告知我们在用户未同意隐私协议前,我们APP提前获取了WIIF/SSID/Mac地址等信息,不合规需要处理 (就是在同意前以及拒绝后, 不进行某些SDK的初始化…)

APP启动时,在用户授权同意隐私政策前,APP及SDK不可以提前收集和使用IMEI、OAID、IMSI、MAC、应用列表等信息

为了处理上面问题,或者说, 为了自己能够检测改版后的APP 是否符合要求, 我们就需要自己进行对APP进行检测和验证, 确保修改后达到效果
(第三方检测机构出的报告, 我们也要能自己给自己出 ╭(╯^╰)╮)

一通了解折腾以后, 我遇到了这么些框架/工具/demo, 这里逐个介绍一下
Xposed -> Dexposed -> Epic -> VirtualXposed ->HookLoginDemo

Xposed框架不用多说 rovo90 - Xposed , Xpose中文站 但是直接使用这个,需要走root,搞机等操作,较为麻烦

Dexposed 是阿里开源的 alibaba/dexposed,能在非root情况下掌控自己进程空间内的任意Java方法调用, 主要的就是用框架进行hook, 来抓取系统函数调用, 追踪三方SDK的启动情况/函数调用等

Epic - github 是weishu大神基于ART重新实现的一套 Dexposed( ART取代Dalvik成为android的运行时,Dexposed无法支持更高版本的安卓系统) 这边一篇大神的Epic介绍

Epic可以在你自己的android工程中添加依赖,

dependencies 
    compile 'com.github.tiann:epic:0.11.2'

然后可以通过

class ThreadMethodHook extends XC_MethodHook
    @Override
    protected void beforeHookedMethod(MethodHookParam param) throws Throwable 
        super.beforeHookedMethod(param);
        Thread t = (Thread) param.thisObject;
        Log.i(TAG, "thread:" + t + ", started..");
    

    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable 
        super.afterHookedMethod(param);
        Thread t = (Thread) param.thisObject;
        Log.i(TAG, "thread:" + t + ", exit..");
    


DexposedBridge.hookAllConstructors(Thread.class, new XC_MethodHook() 
    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable 
        super.afterHookedMethod(param);
        Thread thread = (Thread) param.thisObject;
        Class<?> clazz = thread.getClass();
        if (clazz != Thread.class) 
            Log.d(TAG, "found class extend Thread:" + clazz);
            DexposedBridge.findAndHookMethod(clazz, "run", new ThreadMethodHook());
        
        Log.d(TAG, "Thread: " + thread.getName() + " class:" + thread.getClass() +  " is created.");
    
);
DexposedBridge.findAndHookMethod(Thread.class, "run", new ThreadMethodHook());

提供的函数进行 hook操作, 但是只支持 inhook,就是你自己有android工程, 自己在项目里面添加epic依赖后, 自己写代码自己抓日志,
其实, 如果仅仅是为了验证 用户隐私确认前合规的改版后APP. Epic其实足够使用了. 借助Epic,我们可以通过移除SDK来比对监听偷跑的WIFI/MAC地址等行为是否还存在

贴一下我项目里面的一些调用
在MainActivity中, oncreat() 中调用就可以

implementation 'com.github.tiann:epic:0.11.2'
    private String TAG ="ddddd";

    private void startHook() 
        XC_MethodHook hook = new XC_MethodHook() 
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable 
                super.beforeHookedMethod(param);
                Object hookObj = param.thisObject;
                String clsName = "unknownClass";
                if (hookObj != null) 
                    clsName = hookObj.getClass().getName();
                
                String mdName = "unknownMethod";
                if (param.method != null) 
                    mdName = param.method.getName();
                
                Log.d(TAG, "beforeHookedMethod: " + clsName + "-" + mdName);
            

            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable 
                super.beforeHookedMethod(param);
                Object hookObj = param.thisObject;
                String clsName = "unknownClass";
                if (hookObj != null) 
                    clsName = hookObj.getClass().getName();
                
                String mdName = "unknownMethod";
                if (param.method != null) 
                    mdName = param.method.getName();
                
                Log.d(TAG, "afterHookedMethod: " + clsName + "-" + mdName);
            
        ;
        try 
            // hook系统方法
            // hook系统方法
//            DexposedBridge.hookAllMethods(Thread.class, "run", hook);
            // hook构造方法
//            DexposedBridge.hookAllConstructors(Thread.class, hook);

            DexposedBridge.hookAllMethods(BluetoothLeScanner.class, "startScan", hook);
            // deviceID
            DexposedBridge.hookAllMethods(TelephonyManager.class,"getDeviceId", hook);
            // wifi
            DexposedBridge.hookAllMethods(WifiManager.class,"", hook);
            // wifi - 构造hook
            DexposedBridge.hookAllConstructors(WifiManager.class, hook);
            // MAC
            DexposedBridge.hookAllMethods(WifiManager.class,"getMacAddress", hook);
         catch (Throwable t) 
            t.printStackTrace();
        
    

踩坑1: Epic依赖的minSdkVersion21, 记得把项目的minSdkVersion改为一样否则跑不了程序

但是,检测机构是如何检测我们的APP?

猜测也是借助于 VirtualXposed 等工具,自行编写hook插件 , 来扫描 提交审核的 APP

VirtualXposed - 官方介绍及使用视频 是一个apk应用程序, 目的就是 过简单的 APP 使用 Xposed,无需 root、解锁引导加载程序或刷写系统映像。
具体使用开官网/或者视频,

VirtualXposed 是基于VirtualApp 和 epic 在非ROOT环境下运行Xposed模块的实现(支持5.0~10.0)。

我最后使用的是 0.20.3 版本, 其他版本都没成功, 要么唤起不了自己的APP, 要么安装不了 Xposed install 失败

这是目前我测试确认可以使用的环境:

设备: 小米 Mix2s  
Androdi版本:10
VirtualXposed版本: 0.20.3

踩坑1: VirtualXposed 仅支持到 Android 5~10 , 在2022的今天, 也好在我的Mix2s还能使用, 一开始我用公司测试机 都是Android11, 不支持…

踩坑2: 确定自己项目的APP 是 32位 还是 64位 , 32位的仅仅能使用 0.18版本

HookLoginDemo 是一个插件(也是APP) , 基于这个插件 , 可以让我们方便的对我们的APP进行hook, 通过查看日志来方便的检测 在用户同意隐私前我们的APP或第三方SDK, 有没有偷跑一些系统API, (就像检测机构对我们APP做的检测一样)

当然, 也可以在 HookLoginDemo中添加跟多的检测 比如SSID / WIFI列表. 只要稍微修改代码编译成apk 安装到手机, 接着就是 VirtualXposed 的时间了

贴一下 HookLoginDemo 中 HookLogin代码的修改 (有错误的代码… 后面再完善)

package com.example.hooklogin;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.location.LocationManager;
import android.util.Log;
import android.widget.AutoCompleteTextView;
import android.widget.EditText;
import android.widget.Toast;

import java.lang.reflect.Field;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

import static de.robv.android.xposed.XposedHelpers.findField;

public class HookLogin implements IXposedHookLoadPackage 
    private static final String TAG = "HookLogin";

    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) 

        if (lpparam == null) 
            return;
        

        Log.e(TAG, "Load app packageName:" + lpparam.packageName);
        /*判断hook的包名*/

//        if (!MyApplication.pageName.equals(lpparam.packageName)  && !"com.enhance.kaomanfen.yasilisteningapp".equals(lpparam.packageName)
//        && !"com.tal.tiku".equals(lpparam.packageName)) 
//            return;
//        

//        //固定格式
//        XposedHelpers.findAndHookMethod(
//                "com.", // 需要hook的方法所在类的完整类名
//                lpparam.classLoader,                            // 类加载器,固定这么写就行了
//                "attachBaseContext",                     // 需要hook的方法名
//                Context.class,
//                new XC_MethodHook() 
//                    @Override
//                    protected void beforeHookedMethod(MethodHookParam param) 
//                        XposedBridge.log("调用getDeviceId()获取了imei");
//                    
//
//                    @Override
//                    protected void afterHookedMethod(MethodHookParam param) throws Throwable 
//                        XposedBridge.log(getMethodStack());
//                        super.afterHookedMethod(param);
//                    
//                
//        );

        //固定格式
        XposedHelpers.findAndHookMethod(
                android.telephony.TelephonyManager.class.getName(), // 需要hook的方法所在类的完整类名
                lpparam.classLoader,                            // 类加载器,固定这么写就行了
                "getDeviceId",                     // 需要hook的方法名
                new XC_MethodHook() 
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) 
                        XposedBridge.log("调用getDeviceId()获取了imei");
                    

                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable 
                        XposedBridge.log(getMethodStack());
                        super.afterHookedMethod(param);
                    
                
        );
        XposedHelpers.findAndHookMethod(
                android.telephony.TelephonyManager.class.getName(),
                lpparam.classLoader,
                "getDeviceId",
                int.class,
                new XC_MethodHook() 
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) 
                        XposedBridge.log("调用getDeviceId(int)获取了imei");
                    

                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable 
                        XposedBridge.log(getMethodStack());
                        super.afterHookedMethod(param);
                    
                
        );

//            XposedHelpers.findAndHookMethod(
//                    "com.android.internal.telephony.PhoneSubInfo",
//                    lpparam.classLoader,
//                    "getDeviceId",
//                    new XC_MethodHook() 
//                        @Override
//                        protected void beforeHookedMethod(MethodHookParam param) 
//                            XposedBridge.log("调用PhoneSubInfo的getDeviceId()获取了imei");
//                        
//                    
//            );

        XposedHelpers.findAndHookMethod(
                android.telephony.TelephonyManager.class.getName(),
                lpparam.classLoader,
                "getSubscriberId",
                int.class,
                new XC_MethodHook() 
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) 
                        XposedBridge.log("调用getSubscriberId获取了imsi");
                    

                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable 
                        XposedBridge.log(getMethodStack());
                        super.afterHookedMethod(param);
                    
                
        );

        XposedHelpers.findAndHookMethod(
                android.net.wifi.WifiInfo.class.getName(),
                lpparam.classLoader,
                "getMacAddress",
                new XC_MethodHook() 
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) 
                        XposedBridge.log("调用getMacAddress()获取了mac地址");
                    

                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable 
                        XposedBridge.log(getMethodStack());
                        super.afterHookedMethod(param);
                    
                
        );

        // wifiName
        XposedHelpers.findAndHookMethod(
                android.net.wifi.WifiInfo.class.getName(),
                lpparam.classLoader,
                "getWifiName",
                new XC_MethodHook() 

                    protected void beforeHookedMethod(MethodHookParam param) 
                        XposedBridge.log("调用getWifiName()获取了wifi地址");
                    

                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable 
                        XposedBridge.log(getMethodStack());
                        super.afterHookedMethod(param);
                    
                
        );

        //SSID
        XposedHelpers.findAndHookMethod(
                android.net.wifi.WifiInfo.class.getName(),
                lpparam.classLoader,
                "getSSID",
                new XC_MethodHook() 

                    protected void beforeHookedMethod(MethodHookParam param) 
                        XposedBridge.log("调用getSSID()获取了wifi地址");
                    

                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable 
                        XposedBridge.log(getMethodStack());
                        super.afterHookedMethod(param);
                    
                
        );

        //BSSID
        XposedHelpers.findAndHookMethod(
                android.net.wifi.WifiInfo.class.getName(),
                lpparam.classLoader,
                "getBSSID",
                new XC_MethodHook() 

                    protected void beforeHookedMethod(MethodHookParam param) 
                        XposedBridge.log("调用getBSSID()获取了wifi地址");
                    

                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable 
                        XposedBridge.log(getMethodStack());
                        super.afterHookedMethod(param);
                    
                
        );

        XposedHelpers.findAndHookMethod(
                java.net.NetworkInterface.class.getName(),
                lpparam.classLoader,
                "getHardwareAddress",
                new XC_MethodHook() 
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) 
                        XposedBridge.log("调用getHardwareAddress()获取了mac地址");
                    

                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable 
                        XposedBridge.log(getMethodStack());
                        super.afterHookedMethod(param);
                    
                
        );

        XposedHelpers.findAndHookMethod(
                android.provider.Settings.Secure.class.getName(),
                lpparam.classLoader,
                "getString",
                ContentResolver.class,
             

以上是关于android隐私违规获取问题处理 及 Hook拦截处理记录 (VirtualXposted/epic等)的主要内容,如果未能解决你的问题,请参考以下文章

隐私保护!27%的Android手机APP越界获取用户隐私权限

ASM hook隐私方法调用,防止App被下架

在 ZipOutputStream.write() 方法中强化隐私违规

Android检测获取MAC权限--基于Xposed的方法检测

Android登录注册功能加密处理

安全隐私之路没有尽头,vivo 坚守用户隐私安全底线