diff --git a/README.md b/README.md index fa949ac..504ccab 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ At the same time, some "smart" apps use various loopholes to acquire your applis This module provides some methods to test whether you have already hided your applist nicely. Also, it can work as an Xposed module to hide some apps or reject applist requests to protect your privacy. Attension: Xposed API version lower than 93 is NOT supported due to a permission problem +## Compilation +This project uses Hidden API, so you should replace android.jar in Android Studio. [Reference](https://github.com/anggrayudi/android-hidden-api) ## 关于该模块 虽然“检测安装的应用是不正确的做法”,而且很蠢,但是并不是所有的插件类应用都提供了随机包名支持。在这种情况下,检测到安装了root类应用(如Fake Location、存储重定向)与检测到了root本身区别不大。(会使用检测手段的app可不会认为你是在“我就蹭蹭不进去”) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b995e57..8f8f5f9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -18,13 +18,13 @@ android:supportsRtl="true" android:theme="@style/Theme.HideMyApplist"> + \ No newline at end of file diff --git a/app/src/main/java/com/tsng/hidemyapplist/ui/about/AboutFragment.kt b/app/src/main/java/com/tsng/hidemyapplist/ui/AboutFragment.kt similarity index 95% rename from app/src/main/java/com/tsng/hidemyapplist/ui/about/AboutFragment.kt rename to app/src/main/java/com/tsng/hidemyapplist/ui/AboutFragment.kt index 529a00d..c87e3de 100644 --- a/app/src/main/java/com/tsng/hidemyapplist/ui/about/AboutFragment.kt +++ b/app/src/main/java/com/tsng/hidemyapplist/ui/AboutFragment.kt @@ -1,4 +1,4 @@ -package com.tsng.hidemyapplist.ui.about +package com.tsng.hidemyapplist.ui import android.os.Bundle import android.view.LayoutInflater diff --git a/app/src/main/java/com/tsng/hidemyapplist/ui/detection/DetectionFragment.java b/app/src/main/java/com/tsng/hidemyapplist/ui/DetectionFragment.java similarity index 53% rename from app/src/main/java/com/tsng/hidemyapplist/ui/detection/DetectionFragment.java rename to app/src/main/java/com/tsng/hidemyapplist/ui/DetectionFragment.java index cbbceab..e9aefd6 100644 --- a/app/src/main/java/com/tsng/hidemyapplist/ui/detection/DetectionFragment.java +++ b/app/src/main/java/com/tsng/hidemyapplist/ui/DetectionFragment.java @@ -1,10 +1,10 @@ -package com.tsng.hidemyapplist.ui.detection; +package com.tsng.hidemyapplist.ui; +import android.Manifest; import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; import android.content.SharedPreferences; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.AsyncTask; @@ -30,11 +30,17 @@ import com.tsng.hidemyapplist.R; import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.TreeSet; +import java.util.function.IntFunction; public class DetectionFragment extends Fragment implements View.OnClickListener { @@ -87,11 +93,31 @@ public class DetectionFragment extends Fragment implements View.OnClickListener } } - private class DetectionTask extends AsyncTask { + private class DetectionTask extends AsyncTask { int progress; - String Results = ""; + int[][] methodStatus = new int[5][30]; ProgressDialog dialog; + final Map M0 = new LinkedHashMap() {{ + put("pm", 0); + put("getInstalledPackages", 1); + put("getInstalledApplications", 2); + put("getPackagesHoldingPermissions", 3); + put("queryInstrumentation", 4); + }}; + + final Map M1 = new LinkedHashMap() {{ + put("queryIntentActivities", 0); + }}; + + final Map M2 = new LinkedHashMap() {{ + put("getPackagesForUid", 0); + }}; + + final Map M3 = new LinkedHashMap() {{ + put("javaFile", 0); + }}; + @Override protected void onPreExecute() { progress = 1; @@ -103,47 +129,78 @@ public class DetectionFragment extends Fragment implements View.OnClickListener } @Override - protected void onProgressUpdate(String... str) { - Results += str[0] + "\n"; + protected void onProgressUpdate(Void... voids) { dialog.setMessage(getResources().getString(R.string.detection_using_method) + " " + (++progress) + "/5"); } @Override protected Void doInBackground(Void... voids) { - Debug(method_pm(), "pm command"); - Debug(method_api(), "API request"); - Debug(method_intent(), "intent query"); - Debug(method_uid(), "uid getname"); - Debug(method_datafile(), "datafile detection"); + method_pm(); + publishProgress(); + checkList(0, M0.get("getInstalledPackages"), main.getPackageManager().getInstalledPackages(0)); + publishProgress(); + checkList(0, M0.get("getInstalledApplications"), main.getPackageManager().getInstalledApplications(0)); + publishProgress(); + method_getPackagesHoldingPermissions(); + publishProgress(); + checkList(0, M0.get("queryInstrumentation"), main.getPackageManager().queryInstrumentation(null, PackageManager.GET_META_DATA)); + publishProgress(); + + method_intent(); + publishProgress(); + + method_uid(); + publishProgress(); + + method_datafile(); + publishProgress(); return null; } @Override protected void onPostExecute(Void aVoid) { dialog.dismiss(); + + IntFunction res = (int r) -> r == 1 ? "\uD83D\uDFE5" : r == 0 ? "\uD83D\uDFE9" : "\uD83D\uDFE8"; + StringBuilder br = new StringBuilder(); + br.append("API requests:\n"); + for (Map.Entry entry : M0.entrySet()) + br.append(res.apply(methodStatus[0][entry.getValue()])).append(entry.getKey()).append('\n'); + br.append("Intent queries:\n"); + for (Map.Entry entry : M1.entrySet()) + br.append(res.apply(methodStatus[1][entry.getValue()])).append(entry.getKey()).append('\n'); + br.append("UID detections:\n"); + for (Map.Entry entry : M2.entrySet()) + br.append(res.apply(methodStatus[2][entry.getValue()])).append(entry.getKey()).append('\n'); + br.append("File detections:\n"); + for (Map.Entry entry : M3.entrySet()) + br.append(res.apply(methodStatus[3][entry.getValue()])).append(entry.getKey()).append('\n'); + new MaterialAlertDialogBuilder(main) .setTitle(getString(R.string.detection_finished)) - .setMessage(Results) + .setMessage(br.toString()) .setPositiveButton(getString(R.string.accept), null).show(); } - private void Debug(Set L, String method) { - String outputText = getResources().getString(R.string.detection_method) + ": " + method + "\n"; - if (L == null) - outputText += getResources().getString(R.string.detection_permission_denied) + "\n"; - else if (L.isEmpty()) - outputText += getResources().getString(R.string.detection_target_not_found) + "\n"; - else for (String s : L) - outputText += getResources().getString(R.string.detection_target_found) + " " + s + "\n"; - publishProgress(outputText); + private void checkList(int generalId, int methodId, List list) { + if (list == null) { + methodStatus[generalId][methodId] = -1; + return; + } + Set packages = new TreeSet<>(); + try { + for (Object it : list) + packages.add((String) it.getClass().getField("packageName").get(it)); + } catch (Exception ignored) { } + methodStatus[generalId][methodId] = findPackages(packages); } - private Set method_pm() { + private void method_pm() { Set packages = new TreeSet<>(); try { java.lang.Process p = Runtime.getRuntime().exec("pm list packages"); - BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), "utf-8")); - String line = null; + BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8)); + String line; while ((line = br.readLine()) != null) { line = line.trim(); if (line.length() > 8) { @@ -157,52 +214,43 @@ public class DetectionFragment extends Fragment implements View.OnClickListener } br.close(); p.destroy(); - } catch (Throwable t) { - Log.e("db_method_pm", t.toString()); - } - return findPackages(packages); + } catch (Exception ignored) { } + if (packages.isEmpty()) packages = null; + methodStatus[0][M0.get("pm")] = findPackages(packages); } - private Set method_api() { + private void method_getPackagesHoldingPermissions() { + List permissions = new ArrayList<>(); + for (Field field : Manifest.permission.class.getFields()) { + try { + if (field.getType() == String.class) + permissions.add((String) field.get(null)); + } catch (Exception ignored) { } + } + checkList(0, M0.get("getPackagesHoldingPermissions"), main.getPackageManager().getPackagesHoldingPermissions(permissions.toArray(new String[0]), 0)); + } + + private void method_intent() { Set packages = new TreeSet<>(); - try { - List packageInfos = main.getPackageManager().getInstalledPackages(0); - for (PackageInfo info : packageInfos) - packages.add(info.packageName); - } catch (Throwable t) { - Log.e("db_method_api", t.toString()); - } - return findPackages(packages); + Intent intent = new Intent(Intent.ACTION_MAIN); + List infos = main.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_ALL); + for (ResolveInfo i : infos) + packages.add(i.activityInfo.packageName); + if (packages.isEmpty()) packages = null; + methodStatus[1][M1.get("queryIntentActivities")] = findPackages(packages); } - private Set method_intent() { + private void method_uid() { Set packages = new TreeSet<>(); - try { - Intent intent = new Intent(Intent.ACTION_MAIN); - List infos = main.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_ALL); - for (ResolveInfo i : infos) - packages.add(i.activityInfo.packageName); - } catch (Throwable t) { - Log.e("db_method_intent", t.toString()); + for (int i = Process.SYSTEM_UID; i <= Process.LAST_APPLICATION_UID; i++) { + String[] uid = main.getPackageManager().getPackagesForUid(i); + if (uid != null) + Collections.addAll(packages, uid); } - return findPackages(packages); + methodStatus[2][M2.get("getPackagesForUid")] = findPackages(packages); } - private Set method_uid() { - Set packages = new TreeSet<>(); - try { - for (int i = Process.SYSTEM_UID; i <= Process.LAST_APPLICATION_UID; i++) { - String[] uid = main.getPackageManager().getPackagesForUid(i); - if (uid != null) - Collections.addAll(packages, uid); - } - } catch (Throwable t) { - Log.e("db_method_uid", t.toString()); - } - return findPackages(packages); - } - - private Set method_datafile() { + private void method_datafile() { Set packages = new TreeSet<>(); try { for (String pkg : targets) { @@ -212,17 +260,15 @@ public class DetectionFragment extends Fragment implements View.OnClickListener } catch (Throwable t) { Log.e("db_method_datafile", t.toString()); } - return findPackages(packages); + methodStatus[3][M3.get("javaFile")] = findPackages(packages); } - private Set findPackages(Set packages) { - if (packages.isEmpty()) return null; - Set found = new TreeSet<>(); - for (String name : packages) { + private int findPackages(Set packages) { + if (packages == null) return -1; + for (String name : packages) if (targets.contains(name)) - found.add(name); - } - return found; + return 1; + return 0; } } diff --git a/app/src/main/java/com/tsng/hidemyapplist/ScopeManageActivity.kt b/app/src/main/java/com/tsng/hidemyapplist/ui/ScopeManageActivity.kt similarity index 96% rename from app/src/main/java/com/tsng/hidemyapplist/ScopeManageActivity.kt rename to app/src/main/java/com/tsng/hidemyapplist/ui/ScopeManageActivity.kt index b2e93b8..7830b16 100644 --- a/app/src/main/java/com/tsng/hidemyapplist/ScopeManageActivity.kt +++ b/app/src/main/java/com/tsng/hidemyapplist/ui/ScopeManageActivity.kt @@ -1,4 +1,4 @@ -package com.tsng.hidemyapplist +package com.tsng.hidemyapplist.ui import android.content.pm.ApplicationInfo import android.os.Bundle @@ -6,6 +6,7 @@ import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.preference.ListPreference import androidx.preference.PreferenceFragmentCompat +import com.tsng.hidemyapplist.R import kotlin.collections.set class ScopeManageActivity : AppCompatActivity() { diff --git a/app/src/main/java/com/tsng/hidemyapplist/TemplateManageActivity.java b/app/src/main/java/com/tsng/hidemyapplist/ui/TemplateManageActivity.java similarity index 96% rename from app/src/main/java/com/tsng/hidemyapplist/TemplateManageActivity.java rename to app/src/main/java/com/tsng/hidemyapplist/ui/TemplateManageActivity.java index 369fb15..d28013d 100644 --- a/app/src/main/java/com/tsng/hidemyapplist/TemplateManageActivity.java +++ b/app/src/main/java/com/tsng/hidemyapplist/ui/TemplateManageActivity.java @@ -1,4 +1,4 @@ -package com.tsng.hidemyapplist; +package com.tsng.hidemyapplist.ui; import android.content.Context; import android.content.Intent; @@ -12,8 +12,8 @@ import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.tsng.hidemyapplist.R; -import java.io.File; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; diff --git a/app/src/main/java/com/tsng/hidemyapplist/TemplateSettingsActivity.kt b/app/src/main/java/com/tsng/hidemyapplist/ui/TemplateSettingsActivity.kt similarity index 96% rename from app/src/main/java/com/tsng/hidemyapplist/TemplateSettingsActivity.kt rename to app/src/main/java/com/tsng/hidemyapplist/ui/TemplateSettingsActivity.kt index 977cee6..1d68008 100644 --- a/app/src/main/java/com/tsng/hidemyapplist/TemplateSettingsActivity.kt +++ b/app/src/main/java/com/tsng/hidemyapplist/ui/TemplateSettingsActivity.kt @@ -1,4 +1,4 @@ -package com.tsng.hidemyapplist +package com.tsng.hidemyapplist.ui import android.content.pm.ApplicationInfo import android.os.Bundle @@ -7,6 +7,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.preference.CheckBoxPreference import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat +import com.tsng.hidemyapplist.R class TemplateSettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback { diff --git a/app/src/main/java/com/tsng/hidemyapplist/ui/xposed/XposedFragment.java b/app/src/main/java/com/tsng/hidemyapplist/ui/XposedFragment.java similarity index 83% rename from app/src/main/java/com/tsng/hidemyapplist/ui/xposed/XposedFragment.java rename to app/src/main/java/com/tsng/hidemyapplist/ui/XposedFragment.java index 53da430..81545cf 100644 --- a/app/src/main/java/com/tsng/hidemyapplist/ui/xposed/XposedFragment.java +++ b/app/src/main/java/com/tsng/hidemyapplist/ui/XposedFragment.java @@ -1,6 +1,7 @@ -package com.tsng.hidemyapplist.ui.xposed; +package com.tsng.hidemyapplist.ui; import android.app.Activity; +import android.content.Context; import android.content.Intent; import android.graphics.Color; import android.os.Bundle; @@ -13,11 +14,8 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; -import androidx.preference.PreferenceManager; import com.tsng.hidemyapplist.R; -import com.tsng.hidemyapplist.ScopeManageActivity; -import com.tsng.hidemyapplist.TemplateManageActivity; public class XposedFragment extends Fragment implements View.OnClickListener { @@ -35,7 +33,7 @@ public class XposedFragment extends Fragment implements View.OnClickListener { main = getActivity(); root.findViewById(getXposedStatus() ? R.id.xposed_activated : R.id.xposed_not_activated).setVisibility(View.VISIBLE); Button btn_HookSelf = root.findViewById(R.id.hook_self); - isHookSelf = isHookSelfOnCreate = PreferenceManager.getDefaultSharedPreferences(getContext()).getBoolean("HookSelf", false); + isHookSelf = isHookSelfOnCreate = getActivity().getSharedPreferences("Templates", Context.MODE_WORLD_READABLE).getBoolean("HookSelf", false); btn_HookSelf.setBackgroundColor(isHookSelf ? ContextCompat.getColor(getContext(), R.color.cyan_A700) : Color.GRAY); btn_HookSelf.setOnClickListener(this); root.findViewById(R.id.xposed_tv_template_manage).setOnClickListener(this); @@ -50,7 +48,7 @@ public class XposedFragment extends Fragment implements View.OnClickListener { else switch (v.getId()) { case R.id.hook_self: isHookSelf = !isHookSelf; - PreferenceManager.getDefaultSharedPreferences(getContext()).edit().putBoolean("HookSelf", isHookSelf).apply(); + getActivity().getSharedPreferences("Templates", Context.MODE_WORLD_READABLE).edit().putBoolean("HookSelf", isHookSelf).apply(); v.setBackgroundColor(isHookSelf ? ContextCompat.getColor(getContext(), R.color.cyan_A700) : Color.GRAY); Toast.makeText(getContext(), getString(R.string.xposed_restart_self_to_apply), Toast.LENGTH_SHORT).show(); break; diff --git a/app/src/main/java/com/tsng/hidemyapplist/xposed/XposedEntry.java b/app/src/main/java/com/tsng/hidemyapplist/xposed/XposedEntry.java deleted file mode 100644 index 916ff9f..0000000 --- a/app/src/main/java/com/tsng/hidemyapplist/xposed/XposedEntry.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.tsng.hidemyapplist.xposed; -import android.util.Log; - -import com.tsng.hidemyapplist.BuildConfig; -import com.tsng.hidemyapplist.xposed.hooks.IndividualHooks; - -import de.robv.android.xposed.IXposedHookLoadPackage; -import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; - -public class XposedEntry implements IXposedHookLoadPackage { - public static final String LOG = "hma_log"; - public static final String APPNAME = BuildConfig.APPLICATION_ID; - - @Override - public void handleLoadPackage(final LoadPackageParam lpp) { - new IndividualHooks().handleLoadPackage(lpp); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tsng/hidemyapplist/xposed/XposedEntry.kt b/app/src/main/java/com/tsng/hidemyapplist/xposed/XposedEntry.kt new file mode 100644 index 0000000..43803b3 --- /dev/null +++ b/app/src/main/java/com/tsng/hidemyapplist/xposed/XposedEntry.kt @@ -0,0 +1,58 @@ +package com.tsng.hidemyapplist.xposed + +import android.util.Log +import com.tsng.hidemyapplist.BuildConfig +import com.tsng.hidemyapplist.xposed.hooks.PackageManagerService +import de.robv.android.xposed.IXposedHookLoadPackage +import de.robv.android.xposed.XC_MethodHook +import de.robv.android.xposed.XSharedPreferences +import de.robv.android.xposed.XposedHelpers +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam + +class XposedEntry : IXposedHookLoadPackage { + override fun handleLoadPackage(lpp: LoadPackageParam) { + if (lpp.packageName == APPNAME) { + XposedHelpers.findAndHookMethod("com.tsng.hidemyapplist.ui.XposedFragment", lpp.classLoader, "getXposedStatus", object : XC_MethodHook() { + override fun afterHookedMethod(param: MethodHookParam) { + param.result = true + } + }) + } + PackageManagerService().handleLoadPackage(lpp) + //IndividualHooks().handleLoadPackage(lpp) + } + + companion object { + const val LOG = "hma_log" + const val APPNAME = BuildConfig.APPLICATION_ID + + @JvmStatic + fun getTemplatePref(pkg: String?): XSharedPreferences? { + val template = XSharedPreferences(APPNAME, "Scope").getString(pkg, null) ?: return null + return XSharedPreferences(APPNAME, "tpl_$template") + } + + @JvmStatic + fun isUseHook(pref: XSharedPreferences, callerName: String, hook: String): Boolean { + if (callerName == APPNAME) + if (!XSharedPreferences(APPNAME, "Templates").getBoolean("HookSelf", false)) + return false + val enableAllHooks = pref.getBoolean("EnableAllHooks", false) + val enabled = pref.getStringSet("ApplyHooks", HashSet()) + return enableAllHooks or enabled.contains(hook) + } + + @JvmStatic + fun isToHide(pref: XSharedPreferences?, callerName: String, pkgstr: String): Boolean { + if (pref == null) return false + if (pref.getBoolean("ExcludeSelf", false) && pkgstr.contains(callerName)) return false + if (pref.getBoolean("HideAllApps", false)) return true + val set = pref.getStringSet("HideApps", HashSet()) + for (pkg in set) if (pkgstr.contains(pkg)) { + Log.d(LOG, "HIDE $pkgstr") + return true + } + return false + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tsng/hidemyapplist/xposed/hooks/IndividualHooks.java b/app/src/main/java/com/tsng/hidemyapplist/xposed/hooks/IndividualHooks.java index 4c836c9..828002d 100644 --- a/app/src/main/java/com/tsng/hidemyapplist/xposed/hooks/IndividualHooks.java +++ b/app/src/main/java/com/tsng/hidemyapplist/xposed/hooks/IndividualHooks.java @@ -11,7 +11,6 @@ import java.io.File; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -22,50 +21,24 @@ import de.robv.android.xposed.XSharedPreferences; import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; -import static com.tsng.hidemyapplist.xposed.XposedEntry.LOG; import static com.tsng.hidemyapplist.xposed.XposedEntry.APPNAME; +import static com.tsng.hidemyapplist.xposed.XposedEntry.LOG; +import static com.tsng.hidemyapplist.xposed.XposedEntry.getTemplatePref; +import static com.tsng.hidemyapplist.xposed.XposedEntry.isToHide; public class IndividualHooks implements IXposedHookLoadPackage { @Override public void handleLoadPackage(final LoadPackageParam lpp) { - if (lpp.packageName.equals(APPNAME)) { - XposedHelpers.findAndHookMethod("com.tsng.hidemyapplist.ui.xposed.XposedFragment", lpp.classLoader, "getXposedStatus", new XC_MethodHook() { - @Override - protected void afterHookedMethod(MethodHookParam param) { - param.setResult(true); - } - }); - if (!new XSharedPreferences(APPNAME, APPNAME + "_preferences").getBoolean("HookSelf", false)) - return; - } - //判断模块是否生效 - - XSharedPreferences pref = new XSharedPreferences(APPNAME, "Scope"); - final String template = pref.getString(lpp.packageName, null); - if (template == null) return; - //判断是否hook该应用 - - pref = new XSharedPreferences(APPNAME, "tpl_" + template); + final XSharedPreferences pref = getTemplatePref(lpp.packageName); + if (pref == null) return; final boolean enable_all_hooks = pref.getBoolean("EnableAllHooks", false); final Set enabled = pref.getStringSet("ApplyHooks", null); - //获取模板 if (enable_all_hooks || enabled.contains("method_pm")) pmHook(lpp, pref); if (enable_all_hooks || enabled.contains("method_api")) apiHook(lpp, pref); if (enable_all_hooks || enabled.contains("method_intent")) intentHook(lpp, pref); if (enable_all_hooks || enabled.contains("method_uid")) uidHook(lpp, pref); if (enable_all_hooks || enabled.contains("method_datafile")) fileHook(lpp, pref); - //下钩子 - } - - boolean isToHide(final XSharedPreferences pref, String lppname, String pkgstr) { - if (pref.getBoolean("ExcludeSelf", false) && pkgstr.contains(lppname)) return false; - if (pref.getBoolean("HideAllApps", false)) return true; - Set set = pref.getStringSet("HideApps", new HashSet<>()); - for (String pkg : set) - if (pkgstr.contains(pkg)) - return true; - return false; } void pmHook(final LoadPackageParam lpp, final XSharedPreferences pref) { diff --git a/app/src/main/java/com/tsng/hidemyapplist/xposed/hooks/PackageManagerService.java b/app/src/main/java/com/tsng/hidemyapplist/xposed/hooks/PackageManagerService.java index cce7682..bd85690 100644 --- a/app/src/main/java/com/tsng/hidemyapplist/xposed/hooks/PackageManagerService.java +++ b/app/src/main/java/com/tsng/hidemyapplist/xposed/hooks/PackageManagerService.java @@ -1,26 +1,56 @@ package com.tsng.hidemyapplist.xposed.hooks; +import android.content.pm.PackageInfo; +import android.content.pm.ParceledListSlice; import android.os.Binder; import android.util.Log; +import java.lang.reflect.Method; +import java.util.Iterator; + import de.robv.android.xposed.IXposedHookLoadPackage; import de.robv.android.xposed.XC_MethodHook; +import de.robv.android.xposed.XSharedPreferences; +import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; -import com.tsng.hidemyapplist.xposed.XposedEntry; +import static com.tsng.hidemyapplist.xposed.XposedEntry.APPNAME; +import static com.tsng.hidemyapplist.xposed.XposedEntry.LOG; +import static com.tsng.hidemyapplist.xposed.XposedEntry.getTemplatePref; +import static com.tsng.hidemyapplist.xposed.XposedEntry.isToHide; +import static com.tsng.hidemyapplist.xposed.XposedEntry.isUseHook; public class PackageManagerService implements IXposedHookLoadPackage { @Override public void handleLoadPackage(LoadPackageParam lpp) { - if(!lpp.packageName.equals("android"))return; - Class PMS = XposedHelpers.findClass("com.android.server.pm.PackageManagerService", lpp.classLoader); - XC_MethodHook apiHook = new XC_MethodHook() { - @Override - protected void afterHookedMethod(MethodHookParam param){ - String callerName = (String) XposedHelpers.callMethod(param.thisObject, "getNameForUid", Binder.getCallingUid()); - Log.d(XposedEntry.LOG, "caller: " + callerName); + if (!lpp.packageName.equals("android")) return; + Class PKMS = XposedHelpers.findClass("com.android.server.pm.PackageManagerService", lpp.classLoader); + for (Method method : PKMS.getDeclaredMethods()) + switch (method.getName()) { + case "getInstalledPackages": + case "getInstalledApplications": + case "getPackagesHoldingPermissions": + case "queryInstrumentation": + XposedBridge.hookMethod(method, new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) throws Throwable { + String callerName = (String) XposedHelpers.callMethod(param.thisObject, "getNameForUid", Binder.getCallingUid()); + + if (callerName == APPNAME) { + Log.d(LOG, "PKMS caller: " + callerName); + Log.d(LOG, "PKMS method: " + param.method.getName()); + } + + XSharedPreferences pref = getTemplatePref(callerName); + if (!isUseHook(pref, callerName, "method_api")) return; + for (Iterator iterator = ((ParceledListSlice)param.getResult()).getList().iterator(); iterator.hasNext(); ) + if (isToHide(pref, callerName, (String) XposedHelpers.getObjectField(iterator.next(), "packageName"))) + iterator.remove(); + Log.d(LOG, "PKMS dealt"); + } + }); + break; } - }; } } \ No newline at end of file diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml index 3126b50..37ccdcd 100644 --- a/app/src/main/res/navigation/mobile_navigation.xml +++ b/app/src/main/res/navigation/mobile_navigation.xml @@ -6,18 +6,18 @@ \ No newline at end of file diff --git a/app/src/main/res/values-zh-rCN/strings_detection.xml b/app/src/main/res/values-zh-rCN/strings_detection.xml index 1b6d26b..1aaae3b 100644 --- a/app/src/main/res/values-zh-rCN/strings_detection.xml +++ b/app/src/main/res/values-zh-rCN/strings_detection.xml @@ -3,10 +3,6 @@ 输入要检测的包名 添加 开始检测 - 检测方法 - 找到包名 - 未找到包名 - 拒绝访问 检测中 检测结束 执行检测方法 diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 19497e3..e92a8f3 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -1,4 +1,7 @@ + + android + pm command API request diff --git a/app/src/main/res/values/strings_detection.xml b/app/src/main/res/values/strings_detection.xml index c97017e..00da738 100644 --- a/app/src/main/res/values/strings_detection.xml +++ b/app/src/main/res/values/strings_detection.xml @@ -3,10 +3,6 @@ Input package name add start detection - Detection method - Target found - Target not found. - Permission denied. Executing detections Detection finished Using method @@ -15,7 +11,7 @@ com.topjohnwu.magisk de.robv.android.xposed.installer org.meowcat.edxposed.manager - io.github.lsposed.manager + org.lsposed.manager me.weishu.exp \ No newline at end of file diff --git a/app/src/main/res/xml/template_preferences.xml b/app/src/main/res/xml/template_preferences.xml index 2e814f6..8d11757 100644 --- a/app/src/main/res/xml/template_preferences.xml +++ b/app/src/main/res/xml/template_preferences.xml @@ -28,7 +28,7 @@ android:title="@string/xposed_template_exclude_self" />