package com.xposed.miuianesthetist; import android.app.Activity; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.preference.CheckBoxPreference; import android.text.TextUtils; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XC_MethodReplacement; import de.robv.android.xposed.callbacks.XC_LoadPackage; import static com.xposed.miuianesthetist.XposedHelpersWraper.findAndHookConstructor; import static com.xposed.miuianesthetist.XposedHelpersWraper.findAndHookMethod; import static com.xposed.miuianesthetist.XposedHelpersWraper.findClass; import static com.xposed.miuianesthetist.XposedHelpersWraper.findField; import static com.xposed.miuianesthetist.XposedHelpersWraper.findMethodBestMatch; import static com.xposed.miuianesthetist.XposedHelpersWraper.findMethodExact; import static com.xposed.miuianesthetist.XposedHelpersWraper.getObjectField; import static com.xposed.miuianesthetist.XposedHelpersWraper.getStaticBooleanField; import static com.xposed.miuianesthetist.XposedHelpersWraper.getStaticObjectField; import static com.xposed.miuianesthetist.XposedHelpersWraper.hookMethod; import static com.xposed.miuianesthetist.XposedHelpersWraper.invokeOriginalMethod; import static com.xposed.miuianesthetist.XposedHelpersWraper.log; import static com.xposed.miuianesthetist.XposedHelpersWraper.setBooleanField; import static com.xposed.miuianesthetist.XposedHelpersWraper.setIntField; public class DisableSecurityCheck extends BaseXposedHookLoadPackage { private static volatile Resources res; private static volatile MenuItem menu2; @Override public void initZygote(StartupParam startupParam) { } @Override public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) { if (lpparam.packageName.equals("android")) { try { handleAndroid(lpparam); } catch (Throwable t) { log(t); } } //SecurityCenter.apk if (lpparam.packageName.equals("com.miui.securitycenter")) { try { handleSecurityCenter(lpparam); } catch (Throwable t) { log(t); } } //Settings.apk if (lpparam.packageName.equals("com.android.settings")) { try { handleSettings(lpparam); } catch (Throwable t) { log(t); } } //MiuiInstaller.apk if (lpparam.packageName.equals("com.miui.packageinstaller")) { try { handleInstaller(lpparam); } catch (Throwable t) { log(t); } } } //Remove limit for installing system apps from unofficial channels private void handleInstaller(XC_LoadPackage.LoadPackageParam lpparam) { ClassLoader classLoader = lpparam.classLoader; Class<?> pia = findClass("com.android.packageinstaller.PackageInstallerActivity", classLoader); if (pia == null) return; List<Method> methods = new LinkedList<>(); for (Method m : pia.getMethods()) { if (Arrays.equals(m.getParameterTypes(), new Class[]{Uri.class})) { methods.add(m); } } XC_MethodHook xc_methodHook = new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { Field[] fields = pia.getDeclaredFields(); Field P = null; for (Field f : fields) { if (f.getType() == List.class) { List sf = (List) getStaticObjectField(pia, f.getName()); if (sf.contains("com.android.vending")) { P = f; break; } } } Uri uri = (Uri) param.args[0]; String scheme = uri.getScheme(); if (scheme == null || !scheme.equals("file")) return; String path = uri.getPath(); if (TextUtils.isEmpty(path)) return; Class<?> ppc = findClass("com.android.packageinstaller.compat.PackageParserCompat", classLoader); Method parsePackage = findMethodBestMatch(ppc, "parsePackage", File.class, int.class);//file, 0 Method createPackageUserState = findMethodBestMatch(ppc, "createPackageUserState"); Method generatePackageInfo = findMethodBestMatch(ppc, "generatePackageInfo", Object.class, int[].class, int.class, long.class, long.class, Set.class, Object.class); //this.d = PackageParserCompat.generatePackageInfo(v1_1, v2, 0x1080, 0, 0, ((Set)v2), PackageParserCompat.createPackageUserState()); File file = new File(path); Object v1_1 = parsePackage.invoke(null, file, 0); int[] v2 = {}; PackageInfo packageInfo = (PackageInfo) generatePackageInfo.invoke(null, v1_1, v2, 0x1080, 0, 0, new HashSet(), createPackageUserState.invoke(null)); String packageName = packageInfo.packageName; List p = (List<String>) getStaticObjectField(pia, P.getName()); if (p != null && !p.contains(packageName)) p.add(packageName); } }; for (Method m : methods) { String mname = m.getName(); findAndHookMethod(pia, mname, Uri.class, xc_methodHook); } } private void handleSettings(XC_LoadPackage.LoadPackageParam lpparam) { ClassLoader classLoader = lpparam.classLoader; //Try to return a fake result of if an app is a system app, invalid Class<?> nshClass = findClass("com.android.settings.notification.NotificationSettingsHelper", classLoader); for (Method m : nshClass.getMethods()) { if (Arrays.equals(m.getParameterTypes(), new Class[]{int.class})) { log(m.getName()); hookMethod(m, XC_MethodReplacement.returnConstant(false)); break; } } final Class<?> appRowClass = findClass("com.android.settings.notification.MiuiNotificationBackend$AppRow", classLoader); findAndHookMethod("com.android.settings.notification.MiuiNotificationBackend", classLoader, "markAppRowWithBlockables", String[].class, appRowClass, String.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) { log("arg0:" + Arrays.toString((String[]) param.args[0])); log("arg2:" + param.args[2]); param.setResult(null); } }); //Try to allow users disable AppNotificationSettings ,invalid Class<?> ans = findClass("com.android.settings.notification.AppNotificationSettings", classLoader); findAndHookMethod(ans, "onResume", new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) { Object o = null; try { o = findFirstFieldByExactType(ans, appRowClass).get(param.thisObject); } catch (IllegalAccessException e) { log(e); } setBooleanField(o, "systemApp", false); Method findPreference = findMethodBestMatch(ans, "findPreference", String.class); CheckBoxPreference block = null; try { if (findPreference != null) { findPreference.setAccessible(true); block = (CheckBoxPreference) findPreference.invoke(param.thisObject, "block"); } } catch (Throwable t) { log(t); } if (block != null) block.setEnabled(true); } }); } private void handleAndroid(XC_LoadPackage.LoadPackageParam lpparam) { ClassLoader classLoader = lpparam.classLoader; //Check if MIUI is global version if (null == iib) { iib = getStaticBooleanField(findClass("miui.os.Build", classLoader), "IS_INTERNATIONAL_BUILD"); } //Disable integrity check when boot in services.jar Class sms = findClass("com.miui.server.SecurityManagerService" , classLoader); findAndHookConstructor(sms, Context.class, boolean.class/*onlyCore*/, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) { //Set the instance of SecurityManagerService class to be onlyCore mode, //then checkSystemSelfProtection() method will do nothing param.args[1] = true; } @Override protected void afterHookedMethod(MethodHookParam param) { //Set system apps' states to be not cracked setIntField(param.thisObject, "mSysAppCracked", 0); } }); //Remove the limit for disabling system apps in services.jar findAndHookMethod("com.android.server.pm.PackageManagerServiceInjector" , classLoader, "isAllowedDisable", String.class, int.class, XC_MethodReplacement.returnConstant(true)); //Remove the limit for installing WebViewGoogle manually on MIUI China ROM in services.jar findAndHookMethod("com.android.server.pm.PackageManagerServiceInjector", classLoader, "isAllowedInstall", Context.class, File.class, int.class, String.class, XC_MethodReplacement.returnConstant(true)); //Prevent some ultra sticky system apps (MiuiDaemon, FindDevice, etc.) from running //after have been disabled in services.jar findAndHookMethod("com.android.server.am.ActivityManagerServiceInjector", classLoader, "shouldAddPersistApp", ApplicationInfo.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) { ApplicationInfo info = (ApplicationInfo) param.args[0]; if (!info.packageName.equals("com.miui.greenguard") && info.enabled) { param.setResult(true); return; } //Shorten TAG ActivityManagerServiceInjector log("AMSInjector", "persist app : " + info.packageName + " should not add to start"); param.setResult(false); } }); //Allow users disable system apps' notification chanel in framework.jar findAndHookConstructor("android.app.NotificationChannel", classLoader, Parcel.class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) { setBooleanField(param.thisObject, "mBlockableSystem", true); } }); findAndHookConstructor("android.app.NotificationChannel", classLoader, String.class, CharSequence.class, int.class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) { setBooleanField(param.thisObject, "mBlockableSystem", true); } }); //Return an intent before it get processed to avoid being hijacked in services.jar if (!iib) { Class<?> pmsClazz = findClass("com.android.server.pm.PackageManagerService", classLoader); findAndHookMethod("com.android.server.pm.PackageManagerServiceInjector" , classLoader, "checkMiuiIntent", pmsClazz, Intent.class, String.class, int.class, List.class, int.class, new XC_MethodReplacement() { @Override protected Object replaceHookedMethod(MethodHookParam param) { Intent intent = (Intent) param.args[1]; if (("market".equals(intent.getScheme()) && "android.intent.action.VIEW".equals(intent.getAction())) || ("http".equals(intent.getScheme()) || "https".equals(intent.getScheme())) && "android.intent.action.VIEW".equals(intent.getAction())) { //Return mResolveInfo of the first arg pms return getObjectField(param.args[0], "mResolveInfo"); } return invokeOriginalMethod(param.method, param.thisObject, param.args); } }); } } private void handleSecurityCenter(XC_LoadPackage.LoadPackageParam lpparam) { ClassLoader classLoader = lpparam.classLoader; //Allow users to disable system apps using SecurityCenter's manage apps function //FIXME menuItem get disabled after selected and icon changed Class<?> ada = findClass("com.miui.appmanager.ApplicationsDetailsActivity", classLoader); XC_MethodHook xc_enable_menuItem = new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) { try { if (param.args.length == 1) //Index: 0 force stop; 1 uninstall/disable/enable; 2 clear data/cache menu2 = ((Menu) param.args[0]).getItem(1); if (menu2 != null) menu2.setEnabled(true); } catch (Throwable t) { log(t); } } }; findAndHookMethod(ada, "onCreateOptionsMenu", Menu.class, xc_enable_menuItem); findAndHookMethod(ada, "onPrepareOptionsMenu", Menu.class, xc_enable_menuItem); findAndHookMethod(ada, "onResume", xc_enable_menuItem); //Allow users to revoke system app internet access permission //FIXME network control state preview abnormal, title disappear or turn off data, invalid after reboot findAndHookMethod(ada, "initData", new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) { try { initRes(param); int R_id_am_detail_net = res.getIdentifier("am_detail_net", "id", "com.miui.securitycenter"); View am_detail_net = ((Activity) param.thisObject).findViewById(R_id_am_detail_net); am_detail_net.setVisibility(View.VISIBLE); } catch (Throwable t) { log(t); } } }); findAndHookMethod(ada, "onClick", View.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) { try { setBooleanField(param.thisObject, "mIsSystem", false); } catch (Throwable t) { log(t); } } }); //Allow users to set third-party launcher to be default findAndHookMethod("com.miui.securitycenter.provider.ThirdDesktopProvider", classLoader, "call", String.class, String.class, Bundle.class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) { try { if (param.args[0].equals("getModeAndList")) { Bundle result = (Bundle) param.getResult(); //mode=0 can't use unauthorized third-party launcher; //mode=1 can't use official launcher; other value no limit result.putInt("mode", -1); param.setResult(result); } } catch (Throwable t) { log(t); } } }); //Remove waiting time for applying device admin app findAndHookMethod("com.miui.permcenter.install.DeviceManagerApplyActivity", classLoader, "onCreate", Bundle.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) { bypassSuperNotCalledException(param); } }); //Remove waiting time for applying adb input findAndHookMethod("com.miui.permcenter.install.AdbInputApplyActivity", classLoader, "onCreate", Bundle.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) { try { setProp(classLoader,"persist.security.adbinput","1"); bypassSuperNotCalledException(param); } catch (Exception e) { log(e); } } }); //Remove waiting time for applying install verify findAndHookMethod("com.miui.permcenter.install.AdbInstallVerifyActivity", classLoader, "onCreate", Bundle.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { callPreference(param, "security_adb_install_enable", true); setProp(classLoader,"persist.security.adbinstall","1"); bypassSuperNotCalledException(param); } }); //Remove waiting time for applying root access findAndHookMethod("com.miui.permcenter.root.RootApplyActivity", classLoader, "onCreate", Bundle.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) { try { grantRootAccess(param); } catch (Exception e) { log(e); } } }); } private void grantRootAccess(XC_MethodHook.MethodHookParam param) { Activity activity = (Activity) param.thisObject; String mPkgName = activity.getIntent().getStringExtra("extra_pkgname"); if (TextUtils.isEmpty(mPkgName)) { bypassSuperNotCalledException(param); return; } String mAppName = getAppName(param,mPkgName); Bundle bundle = new Bundle(); bundle.putLong("extra_permission", 512); bundle.putInt("extra_action", 3); bundle.putStringArray("extra_package", new String[]{mPkgName}); bundle.putInt("extra_flags", 0); Uri content_uri = Uri.parse("content://com.lbe.security.miui.permmgr"); activity.getApplicationContext().getContentResolver().call(content_uri, "6", null, bundle); Resources resources = activity.getResources(); int toast_root_apply_accept = resources.getIdentifier("toast_root_apply_accept", "string", "com.miui.securitycenter"); Toast.makeText(activity, resources.getString(toast_root_apply_accept, mAppName), Toast.LENGTH_SHORT).show(); bypassSuperNotCalledException(param); } private String getAppName(XC_MethodHook.MethodHookParam param,String packageName) { Activity activity = (Activity) param.thisObject; if ("root".equals(packageName)) { return "root"; } if ("com.android.shell".equals(packageName)) { return "Interactive Shell"; } try { PackageManager packageManager = activity.getApplicationContext().getPackageManager(); return packageManager.getApplicationInfo(packageName,0).loadLabel(packageManager).toString(); } catch (PackageManager.NameNotFoundException e) { return packageName; } } private void setProp(ClassLoader classLoader,String key,String value) throws IllegalAccessException, InvocationTargetException { Method setProp = findMethodExact("android.os.SystemProperties", classLoader, "set", String.class, String.class); setProp.invoke(null,key,value); } private void callPreference(XC_MethodHook.MethodHookParam param, String key, boolean value){ Activity activity = (Activity) param.thisObject; ContentResolver contentResolver = activity.getContentResolver(); Bundle bundle = new Bundle(); bundle.putInt("type", 1); bundle.putString("key", key); bundle.putBoolean("value", value); remoteChange("SET", bundle,contentResolver); contentResolver.notifyChange(Uri.withAppendedPath(Uri.parse("content://com.miui.securitycenter.remoteprovider"), key), null, false); } private Bundle remoteChange(String action, Bundle bundle, ContentResolver contentResolver) { Uri uri; if (getMyUerId()==999) { Uri parse = Uri.parse("content://com.miui.securitycenter.remoteprovider"); Uri.Builder buildUpon = parse.buildUpon(); String authority = "0@" + parse.getEncodedAuthority(); buildUpon.encodedAuthority(authority); uri = buildUpon.build(); } else { uri = Uri.parse("content://com.miui.securitycenter.remoteprovider"); } return contentResolver.call(uri, "callPreference", action, bundle); } private int getMyUerId() { int myUserId = 0; if (Build.VERSION.SDK_INT >= 21) { try { Integer num = (Integer) findMethodBestMatch(android.os.UserHandle.class, "myUserId").invoke(null); if (num != null) myUserId = num; } catch (Exception e) { log(e); } } return myUserId; } private void bypassSuperNotCalledException(XC_MethodHook.MethodHookParam param) { Activity activity = (Activity) param.thisObject; findField(Activity.class,"mCalled").setAccessible(true); setBooleanField(activity,"mCalled",true); activity.setResult(Activity.RESULT_OK); activity.finish(); param.setResult(null); } }