xposed開發之清除應用數據(研究歷程)

    最近在研究xposed,有個需求要作到清除其餘應用數據,xposed功能足夠強大,應該能夠實現這個功能,下面是基於android4.4.4研究的思路。java

    google只能開放了清楚緩存的API,清除數據的API隱藏了,而調用清理數據的方法在「設置」中的「應用」裏,找到設置功能的源碼,代碼位置 com.android.settings.applications.InstalledAppDetails ,點擊事件在這linux

調用了initiateClearUserData,看看這裏面怎麼實現的android

調用了ActivityManager的clearApplicationUserData,參數是該應用的包名和一個ClearUserDataObserver的實例緩存

IPackageDataObserver是有AIDL生成的,位於android.content.pm包內,咱們能夠新建一個相同的包名,把AIDL放在這裏。app

注:有些應用詳情裏該按鈕不是清除數據,是管理空間,清除數據的按鈕在應用自定義的界面裏,可是最終實現清除數據仍是調用的clearApplicationUserDatasocket

clearApplicationUserData是隱藏方法,直接調用了ActivityManagerNative的方法ide

ActivityManagerNative:學習

這裏直接使用反射或者Xposed的callmethod調用這兩個方法都會報錯,缺乏權限ui

android.permission.CLEAR_APP_USER_DATA

這裏並無實現具體的方法,真正的實如今ActivityManagerService中,參考http://www.jianshu.com/p/18517a4ef8e1google

ActivityManagerService:

該方法上面部分是獲取pid、uid,給IPackageManager的對象賦值和權限檢測,下面執行清除數據。最開始的思路是直接hook AppGlobals.getPackageManager()的clearApplicationUserData,可是仍舊報缺乏權限錯誤。。。繼續分析:

AppGlobals:

ActivityThread:

到這裏遇到IPackageManager.aidl生成的Stub類,PackageManagerService繼承了IPackageManager.Stub

PackageManagerService:

又是權限檢測,跳過,進入clearApplicationUserDataLI

int retCode = mInstaller.clearUserData(packageName, userId);

進入Installer方法

該類大概是建立本地socket,執行linux命令行,進行各類應用的安裝、移動、卸載、清除數據等

可是hook此方法,仍舊報錯,空指針異常,並且hook connect也鏈接不上

Class installCls = XposedHelpers.findClass("com.android.server.pm.Installer",lpp.classLoader);
Object installObj = XposedHelpers.newInstance(installCls);
boolean lean = (boolean) XposedHelpers.callMethod(installObj,"ping");
boolean bo = (boolean) XposedHelpers.callMethod(installObj,"connect");
XposedBridge.log("lean:"+lean+"--bo:"+bo);

實例化Installer出的問題.查了資料,Installer在系統啓動時由其餘類調用,啓動完成後用findAndHookMethod沒法hook到。因而實現Xposed另外一接口XposedHookZygoteInit 

@Override
public void initZygote(StartupParam startupParam) throws Throwable {
    Class installCls = XposedHelpers.findClass("com.android.server.pm.Installer",null);
    XposedHelpers.findAndHookMethod(installCls, "writeCommand",String.class, new XC_MethodHook() {
        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            String string = (String) param.args[0];
            XposedBridge.log("string:"+string);
            if(string.contains("com.google.android.gms"))
                param.args[0] = "rmuserdata com.google.android.gms 0";
        }

    });

}

以google play service爲例,這種狀況下能夠清除此app的數據。可是這種方法不可控,必須放在initZygote中,並且Installer不能經過反射實例化,只能另想辦法。

    鬱悶兩天後,想到既然從ActivityManager、PackageManagerService等類中不能調用是由於權限限制,那就hook檢測權限的方法,讓個人應用經過權限檢測。最開始打算之外部調用的方式(在非Xposed中,例如activity,以反射的方式調用清除數據的方法,Xposed hook權限檢測方法)從 ActivityManagerService入手,由於PackageManagerService的構造方法須要傳多個參數,包括Installer的對象。ActivityManagerService裏檢測權限的是checkComponentPermission方法,可是經過反射獲取ActivityManagerService對象時又報錯,FileNotFoundException,引起異常的位置是mBatteryStatsService = new BatteryStatsService(new File( systemDir, "batterystats.bin").toString());

batterystats.bin文件位於/data/system/下,但即便我得到了root權限依然觸發異常,不知道什麼緣由。這樣只能在handleLoadPackage中調用清除數據,在Xposed外部設置個合適方法觸發清理數據,好比得到IMEI、殺掉某個進程等,經過hook這些方法,而後調用清除數據的方法:

XposedHelpers.findAndHookMethod("android.app.ActivityManager", lpp.classLoader, "killBackgroundProcesses",String.class, new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                String process = (String) param.args[0];
                XposedBridge.log("process:"+process);
                if("com.google.android.gsf".equals(process)){
                    ActivityManager manager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
                    XposedHelpers.callMethod(manager,"clearApplicationUserData",packageName,clearDataUserData);

                }

            }
        });

這是以殺死com.google.android.gsf爲例。

    權限檢測這裏有兩部分,就是ActivityManagerService 的checkComponentPermission了:

XposedHelpers.findAndHookMethod("com.android.server.am.ActivityManagerService", lpp.classLoader, "checkComponentPermission", String.class, int.class, int.class, int.class, boolean.class, new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                if(Manifest.permission.CLEAR_APP_USER_DATA.equals(param.args[0])) {
                    int re = (int) param.getResult();
                    XposedBridge.log("ActivityManagerService re:"+re);
                    param.setResult(0);//PackageManager.PERMISSION_GRANTED

                }
            }
        });

    總結:最終實現的方法很簡單,可是過程分析花費的時間很長,一方面源於對源碼的不瞭解,好比AIDL原理,系統啓動的順序等等。好在源碼結構好,容易看懂,否則還沒分析完就歇菜放棄了。這裏主要是爲學習作個筆記,清除其餘應用的數據是很危險的行爲,必定要慎用!慎用

相關文章
相關標籤/搜索