diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/Main.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/Main.java index 6c84c871..5b756b10 100644 --- a/app/src/main/java/tw/fatminmin/xposed/minminguard/Main.java +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/Main.java @@ -50,6 +50,24 @@ import tw.fatminmin.xposed.minminguard.blocker.adnetwork.Freewheel; import tw.fatminmin.xposed.minminguard.blocker.adnetwork.GoogleAdmob; import tw.fatminmin.xposed.minminguard.blocker.adnetwork.GoogleGms; +import tw.fatminmin.xposed.minminguard.blocker.adnetwork.GoogleMobileAdsModern; +import tw.fatminmin.xposed.minminguard.blocker.adnetwork.AppLovinMaxModern; +import tw.fatminmin.xposed.minminguard.blocker.adnetwork.MetaAudienceNetworkModern; +import tw.fatminmin.xposed.minminguard.blocker.adnetwork.UnityAdsModern; +import tw.fatminmin.xposed.minminguard.blocker.adnetwork.IronSourceModern; +import tw.fatminmin.xposed.minminguard.blocker.adnetwork.VungleModern; +import tw.fatminmin.xposed.minminguard.blocker.adnetwork.PangleModern; +import tw.fatminmin.xposed.minminguard.blocker.adnetwork.MintegralModern; +import tw.fatminmin.xposed.minminguard.blocker.adnetwork.ChartboostModern; +import tw.fatminmin.xposed.minminguard.blocker.adnetwork.InMobiModern; +import tw.fatminmin.xposed.minminguard.blocker.adnetwork.AppodealModern; +import tw.fatminmin.xposed.minminguard.blocker.adnetwork.YandexAdsModern; +import tw.fatminmin.xposed.minminguard.blocker.adnetwork.FyberModern; +import tw.fatminmin.xposed.minminguard.blocker.adnetwork.TapjoyModern; +import tw.fatminmin.xposed.minminguard.blocker.adnetwork.SmaatoModern; +import tw.fatminmin.xposed.minminguard.blocker.adnetwork.StartIoModern; +import tw.fatminmin.xposed.minminguard.blocker.adnetwork.AmazonPublisherServicesModern; +import tw.fatminmin.xposed.minminguard.blocker.adnetwork.GenericModernAdHeuristic; import tw.fatminmin.xposed.minminguard.blocker.adnetwork.GoogleGmsDoubleClick; import tw.fatminmin.xposed.minminguard.blocker.adnetwork.Hodo; import tw.fatminmin.xposed.minminguard.blocker.adnetwork.Inmobi; @@ -96,15 +114,16 @@ public class Main implements IXposedHookZygoteInit, IXposedHookLoadPackage public static Blocker[] blockers = { /* Popular adnetwork */ - new Ad2iction(), new Adbert(), new Adcolony(), new Adfurikun(), new AdMarvel(), new AppodealMRAID(), new GoogleAdmob(), new GoogleGms(), new Adtech(), new Amazon(), new Amobee(), - new Aotter(), new AppBrain(), new Applovin(), new Appnext(), new Avocarrot(), new Bonzai(), new Chartboost(), new Clickforce(), new Domob(), new Facebook(), - new Freewheel(), new Flurry(), new GoogleGmsDoubleClick(), new Hodo(), new Inmobi(), new Intowow(), new Ironsource(), new KuAd(), new mAdserve(), new Madvertise(), - new MasAd(), new MdotM(), new Millennial(), new Mobclix(), new MobFox(), new MoPub(), new Nend(), new Og(), new Onelouder(), new OpenX(), new SmartAdserver(), new SourcekitMRAID(), - new Startapp(), new Tapfortap(), new TWMads(), new UnityAds(), new Vpadn(), new Vpon(), new Vungle(), new Waystorm(), new Yandex(), + new Ad2iction(), new Adbert(), new Adcolony(), new Adfurikun(), new AdMarvel(), new AppodealMRAID(), new GoogleAdmob(), new GoogleGms(), new GoogleMobileAdsModern(), new Adtech(), new Amazon(), new AmazonPublisherServicesModern(), new Amobee(), + new Aotter(), new AppBrain(), new Applovin(), new AppLovinMaxModern(), new Appnext(), new Avocarrot(), new Bonzai(), new Chartboost(), new ChartboostModern(), new Clickforce(), new Domob(), new Facebook(), new MetaAudienceNetworkModern(), + new Freewheel(), new Flurry(), new FyberModern(), new GoogleGmsDoubleClick(), new Hodo(), new Inmobi(), new InMobiModern(), new Intowow(), new Ironsource(), new IronSourceModern(), new KuAd(), new mAdserve(), new Madvertise(), + new MasAd(), new MdotM(), new Millennial(), new Mobclix(), new MobFox(), new MoPub(), new Nend(), new Og(), new Onelouder(), new OpenX(), new SmaatoModern(), new SmartAdserver(), new SourcekitMRAID(), + new Startapp(), new StartIoModern(), new Tapfortap(), new TapjoyModern(), new TWMads(), new UnityAds(), new UnityAdsModern(), new Vpadn(), new Vpon(), new Vungle(), new VungleModern(), new Waystorm(), new Yandex(), new YandexAdsModern(), + new AppodealModern(), new MintegralModern(), new PangleModern(), new GenericModernAdHeuristic(), /* Custom Mod*/ }; - private static Set hookedPackages = new HashSet<>(); + private static Set hookedPackages = Collections.synchronizedSet(new HashSet()); private static boolean isEnabled(SharedPreferences pref, String pkgName) { @@ -155,10 +174,7 @@ public void initZygote(StartupParam startupParam) throws Throwable MODULE_PATH = startupParam.modulePath; - if(xposedVersionCode < 90) - UnpackResources(); - else - Util.log(MY_PACKAGE_NAME, "Skipping resource unpacking for now"); + UnpackResources(); Util.notifyWorker = Executors.newSingleThreadExecutor(); @@ -195,10 +211,13 @@ private void UnpackResources() String[] sUrls = decoded.split("\n"); Collections.addAll(patterns, sUrls); } + if (patterns.isEmpty()) { + Util.log(MY_PACKAGE_NAME, "Warning: Patterns empty after unpacking."); + } } catch (Exception e) { - + Util.log(MY_PACKAGE_NAME, "Failed to load patterns from resources, URL filtering may be disabled."); } } @@ -276,8 +295,8 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { } } - if (hookedPackages.contains(packageName)) return; - hookedPackages.add(packageName); + String processKey = packageName + ":" + lpparam.processName; + if (!hookedPackages.add(processKey)) return; try { XposedHelpers.findAndHookMethod("android.app.Application", lpparam.classLoader, "onCreate", new XC_MethodHook() diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/AdHeuristic.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/AdHeuristic.java new file mode 100644 index 00000000..47c5eb65 --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/AdHeuristic.java @@ -0,0 +1,57 @@ +package tw.fatminmin.xposed.minminguard.blocker; + +public class AdHeuristic { + + public static boolean isAdLike(String name) { + if (name == null || name.trim().isEmpty()) { + return false; + } + + String lowerName = name.toLowerCase(); + + // Exclude false positives + if (lowerName.contains("adapter") || + lowerName.contains("header") || + lowerName.contains("shadow") || + lowerName.contains("badge")) { + return false; + } + + return lowerName.contains("adview") || + lowerName.contains(".ads.") || + lowerName.contains(".ad.") || + lowerName.contains("banner") || + lowerName.contains("nativead") || + lowerName.contains("interstitial") || + lowerName.contains("rewarded") || + lowerName.contains("sponsored") || + lowerName.contains("applovin") || + lowerName.contains("vungle") || + lowerName.contains("unityads") || + lowerName.contains("ironsource") || + lowerName.contains("pangle") || + lowerName.contains("chartboost"); + } + + public static boolean isRewarded(String name) { + if (name == null || name.trim().isEmpty()) { + return false; + } + + String lowerName = name.toLowerCase(); + return lowerName.contains("reward") || + lowerName.contains("serversideverification"); + } + + public static boolean shouldAutoBlock(String name) { + if (name == null || name.trim().isEmpty()) { + return false; + } + // Default: rewarded ads are detected but not blocked automatically + if (isRewarded(name)) { + return false; + } + + return isAdLike(name); + } +} diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/ApiBlocking.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/ApiBlocking.java index 0f963d50..cbb94bf3 100644 --- a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/ApiBlocking.java +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/ApiBlocking.java @@ -94,7 +94,19 @@ protected void beforeHookedMethod(MethodHookParam param) Util.log(packageName, debugMsg); Util.notifyRemoveAdView(null, packageName, 1); - param.setResult(new Object()); + Object defaultResult = null; + if (param.method instanceof java.lang.reflect.Method) { + Class returnType = ((java.lang.reflect.Method) param.method).getReturnType(); + if (returnType == boolean.class) defaultResult = false; + else if (returnType == int.class) defaultResult = 0; + else if (returnType == long.class) defaultResult = 0L; + else if (returnType == float.class) defaultResult = 0.0f; + else if (returnType == double.class) defaultResult = 0.0d; + else if (returnType == short.class) defaultResult = (short) 0; + else if (returnType == byte.class) defaultResult = (byte) 0; + else if (returnType == char.class) defaultResult = '\u0000'; + } + param.setResult(defaultResult); } }); } @@ -126,7 +138,19 @@ protected void beforeHookedMethod(MethodHookParam param) Util.notifyRemoveAdView(null, packageName, 1); - param.setResult(new Object()); + Object defaultResult = null; + if (param.method instanceof java.lang.reflect.Method) { + Class returnType = ((java.lang.reflect.Method) param.method).getReturnType(); + if (returnType == boolean.class) defaultResult = false; + else if (returnType == int.class) defaultResult = 0; + else if (returnType == long.class) defaultResult = 0L; + else if (returnType == float.class) defaultResult = 0.0f; + else if (returnType == double.class) defaultResult = 0.0d; + else if (returnType == short.class) defaultResult = (short) 0; + else if (returnType == byte.class) defaultResult = (byte) 0; + else if (returnType == char.class) defaultResult = '\u0000'; + } + param.setResult(defaultResult); } }); } @@ -158,7 +182,19 @@ protected void beforeHookedMethod(MethodHookParam param) Util.notifyRemoveAdView(null, packageName, 1); - param.setResult(new Object()); + Object defaultResult = null; + if (param.method instanceof java.lang.reflect.Method) { + Class returnType = ((java.lang.reflect.Method) param.method).getReturnType(); + if (returnType == boolean.class) defaultResult = false; + else if (returnType == int.class) defaultResult = 0; + else if (returnType == long.class) defaultResult = 0L; + else if (returnType == float.class) defaultResult = 0.0f; + else if (returnType == double.class) defaultResult = 0.0d; + else if (returnType == short.class) defaultResult = (short) 0; + else if (returnType == byte.class) defaultResult = (byte) 0; + else if (returnType == char.class) defaultResult = '\u0000'; + } + param.setResult(defaultResult); } }); } @@ -190,7 +226,19 @@ protected void beforeHookedMethod(MethodHookParam param) Util.notifyRemoveAdView(null, packageName, 1); - param.setResult(new Object()); + Object defaultResult = null; + if (param.method instanceof java.lang.reflect.Method) { + Class returnType = ((java.lang.reflect.Method) param.method).getReturnType(); + if (returnType == boolean.class) defaultResult = false; + else if (returnType == int.class) defaultResult = 0; + else if (returnType == long.class) defaultResult = 0L; + else if (returnType == float.class) defaultResult = 0.0f; + else if (returnType == double.class) defaultResult = 0.0d; + else if (returnType == short.class) defaultResult = (short) 0; + else if (returnType == byte.class) defaultResult = (byte) 0; + else if (returnType == char.class) defaultResult = '\u0000'; + } + param.setResult(defaultResult); } }); } @@ -275,6 +323,73 @@ protected void beforeHookedMethod(MethodHookParam param) } + public static boolean blockAdFunctionSafe(final String packageName, final String adClass, final String adFunc, final XC_LoadPackage.LoadPackageParam lpparam) + { + try + { + Util.hookAllMethods(adClass, lpparam.classLoader, adFunc, new XC_MethodHook() + { + @Override + protected void beforeHookedMethod(MethodHookParam param) + { + String debugMsg = String.format("blockAdFunctionSafe: Detect %s %s in %s", adClass, adFunc, packageName); + Util.log(packageName, debugMsg); + Util.notifyRemoveAdView(null, packageName, 1); + param.setResult(null); + } + }); + } + catch (ClassNotFoundError | NoSuchMethodError e) + { + return false; + } + catch (Throwable t) { + return false; + } + + return true; + } + + public static boolean blockAdFunctionWithSafeDefault(final String packageName, final String adClass, final String adFunc, final XC_LoadPackage.LoadPackageParam lpparam) + { + try + { + Util.hookAllMethods(adClass, lpparam.classLoader, adFunc, new XC_MethodHook() + { + @Override + protected void beforeHookedMethod(MethodHookParam param) + { + String debugMsg = String.format("blockAdFunctionWithSafeDefault: Detect %s %s in %s", adClass, adFunc, packageName); + Util.log(packageName, debugMsg); + Util.notifyRemoveAdView(null, packageName, 1); + + Object result = null; + if (param.method instanceof java.lang.reflect.Method) { + Class returnType = ((java.lang.reflect.Method) param.method).getReturnType(); + if (returnType == boolean.class) result = false; + else if (returnType == int.class) result = 0; + else if (returnType == long.class) result = 0L; + else if (returnType == float.class) result = 0.0f; + else if (returnType == double.class) result = 0.0d; + else if (returnType == short.class) result = (short) 0; + else if (returnType == byte.class) result = (byte) 0; + else if (returnType == char.class) result = '\u0000'; + } + param.setResult(result); + } + }); + } + catch (ClassNotFoundError | NoSuchMethodError e) + { + return false; + } + catch (Throwable t) { + return false; + } + + return true; + } + public static boolean blockAdFunctionWithResultExact(final String packageName, final String adClass, final String adFunc, final Object parameter1, final Object parameter2, final Object result, final XC_LoadPackage.LoadPackageParam lpparam) { try diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/HookDiscovery.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/HookDiscovery.java index aca24f05..ec6075eb 100644 --- a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/HookDiscovery.java +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/HookDiscovery.java @@ -60,14 +60,7 @@ private static boolean isSuspicious(String className) { return false; } - String lowerClass = className.toLowerCase(); - return lowerClass.contains("ad") || - lowerClass.contains("ads") || - lowerClass.contains("banner") || - lowerClass.contains("native") || - lowerClass.contains("interstitial") || - lowerClass.contains("reward") || - lowerClass.contains("splash"); + return AdHeuristic.isAdLike(className); } private static void logDiscovery(String packageName, String message, String className) { diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/WebViewRequestBlocking.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/WebViewRequestBlocking.java index 669c2590..735ba65e 100644 --- a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/WebViewRequestBlocking.java +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/WebViewRequestBlocking.java @@ -23,42 +23,18 @@ public static void handle(final String packageName, final LoadPackageParam lppar if (webViewClientClass == null) return; // Hook for older APIs (API < 21) - XposedBridge.hookAllMethods(webViewClientClass, "shouldInterceptRequest", new XC_MethodHook() { - @Override - protected void beforeHookedMethod(MethodHookParam param) throws Throwable { - try { - if (param.args == null || param.args.length < 2) return; - - // the signature is shouldInterceptRequest(WebView view, String url) - if (param.args[1] instanceof String) { - String url = (String) param.args[1]; - if (shouldBlock(url)) { - param.setResult(createEmptyResponse()); - } - } - } catch (Throwable t) { - // ignore - } - } - }); - - // Hook for newer APIs (API >= 21) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - XposedBridge.hookAllMethods(webViewClientClass, "shouldInterceptRequest", new XC_MethodHook() { + try { + XposedHelpers.findAndHookMethod(webViewClientClass, "shouldInterceptRequest", "android.webkit.WebView", String.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { try { if (param.args == null || param.args.length < 2) return; - // the signature is shouldInterceptRequest(WebView view, WebResourceRequest request) - if (param.args[1] instanceof WebResourceRequest) { - WebResourceRequest request = (WebResourceRequest) param.args[1]; - Uri uri = request.getUrl(); - if (uri != null) { - String url = uri.toString(); - if (shouldBlock(url)) { - param.setResult(createEmptyResponse()); - } + // the signature is shouldInterceptRequest(WebView view, String url) + if (param.args[1] instanceof String) { + String url = (String) param.args[1]; + if (shouldBlock(url)) { + param.setResult(createEmptyResponse()); } } } catch (Throwable t) { @@ -66,6 +42,38 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { } } }); + } catch (Throwable t) { + Util.log("WebViewRequestBlocking", "Failed to hook shouldInterceptRequest(WebView, String) in " + packageName); + } + + // Hook for newer APIs (API >= 21) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + try { + XposedHelpers.findAndHookMethod(webViewClientClass, "shouldInterceptRequest", "android.webkit.WebView", WebResourceRequest.class, new XC_MethodHook() { + @Override + protected void beforeHookedMethod(MethodHookParam param) throws Throwable { + try { + if (param.args == null || param.args.length < 2) return; + + // the signature is shouldInterceptRequest(WebView view, WebResourceRequest request) + if (param.args[1] instanceof WebResourceRequest) { + WebResourceRequest request = (WebResourceRequest) param.args[1]; + Uri uri = request.getUrl(); + if (uri != null) { + String url = uri.toString(); + if (shouldBlock(url)) { + param.setResult(createEmptyResponse()); + } + } + } + } catch (Throwable t) { + // ignore + } + } + }); + } catch (Throwable t) { + Util.log("WebViewRequestBlocking", "Failed to hook shouldInterceptRequest(WebView, WebResourceRequest) in " + packageName); + } } Util.log("WebViewRequestBlocking", "Enabled WebView request interception for " + packageName); @@ -76,28 +84,51 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { } private static boolean shouldBlock(String url) { - if (url == null) return false; + if (url == null || url.trim().isEmpty()) return false; + + // Strip query string for logging and simpler matching + String cleanUrl = url; + int queryIndex = url.indexOf('?'); + if (queryIndex > 0) { + cleanUrl = url.substring(0, queryIndex); + } + + if (AdHeuristic.isRewarded(cleanUrl)) { + Util.log("WebViewRequestBlocking", "Allowed rewarded ad: " + cleanUrl); + return false; + } try { Uri uri = Uri.parse(url); String host = uri.getHost(); + + cleanUrl = cleanUrl.toLowerCase().trim(); + if (host != null) { + host = host.toLowerCase().trim(); for (String adUrl : Main.patterns) { - if (host.contains(adUrl) || url.contains(adUrl)) { + if (adUrl == null || adUrl.trim().isEmpty()) continue; + String pattern = adUrl.toLowerCase().trim(); + if (host.contains(pattern)) { return true; } } - } else { - for (String adUrl : Main.patterns) { - if (url.contains(adUrl)) { - return true; - } + } + + for (String adUrl : Main.patterns) { + if (adUrl == null || adUrl.trim().isEmpty()) continue; + String pattern = adUrl.toLowerCase().trim(); + if (cleanUrl.contains(pattern)) { + return true; } } } catch (Throwable t) { // fallback if URI parse fails + cleanUrl = cleanUrl.toLowerCase().trim(); for (String adUrl : Main.patterns) { - if (url.contains(adUrl)) { + if (adUrl == null || adUrl.trim().isEmpty()) continue; + String pattern = adUrl.toLowerCase().trim(); + if (cleanUrl.contains(pattern)) { return true; } } diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Adcolony.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Adcolony.java index 1e759bf2..e2eb5975 100644 --- a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Adcolony.java +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Adcolony.java @@ -15,10 +15,9 @@ public boolean handleLoadPackage(String packageName, XC_LoadPackage.LoadPackageP { boolean result = false; - result = ApiBlocking.blockAdFunctionWithResultExact(packageName, Adcolony_Storage, "a", String.class, 0.0d, lpparam); - - result |= ApiBlocking.blockAdFunctionWithResult(packageName, INTER_ADS, "isExpired", true, lpparam); - result |= ApiBlocking.blockAdFunctionWithResult(packageName, INTER_ADS, "show", false, lpparam); + // Refactored to use standard safe default mechanism + result = ApiBlocking.blockAdFunctionWithSafeDefault(packageName, INTER_ADS, "isExpired", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, INTER_ADS, "show", lpparam); return result; } diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/AmazonPublisherServicesModern.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/AmazonPublisherServicesModern.java new file mode 100644 index 00000000..3e9220b9 --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/AmazonPublisherServicesModern.java @@ -0,0 +1,33 @@ +package tw.fatminmin.xposed.minminguard.blocker.adnetwork; + +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import tw.fatminmin.xposed.minminguard.blocker.ApiBlocking; +import tw.fatminmin.xposed.minminguard.blocker.Blocker; + +public class AmazonPublisherServicesModern extends Blocker { + + private static final String BANNER_PREFIX = "com.amazon.device.ads"; + + public boolean handleLoadPackage(final String packageName, LoadPackageParam lpparam) { + boolean result = false; + + result |= ApiBlocking.removeBanner(packageName, "com.amazon.device.ads.DTBAdView", "fetchAd", lpparam); + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.amazon.device.ads.DTBAdInterstitial", "fetchAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.amazon.device.ads.DTBAdInterstitial", "show", lpparam); + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.amazon.device.ads.DTBAdRequest", "loadAd", lpparam); + + return result; + } + + @Override + public String getBannerPrefix() { + return BANNER_PREFIX; + } + + @Override + public String getBanner() { + return null; + } +} diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/AppLovinMaxModern.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/AppLovinMaxModern.java new file mode 100644 index 00000000..88ce702e --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/AppLovinMaxModern.java @@ -0,0 +1,49 @@ +package tw.fatminmin.xposed.minminguard.blocker.adnetwork; + +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import tw.fatminmin.xposed.minminguard.blocker.ApiBlocking; +import tw.fatminmin.xposed.minminguard.blocker.Blocker; + +public class AppLovinMaxModern extends Blocker { + + private static final String BANNER_PREFIX = "com.applovin"; + + public boolean handleLoadPackage(final String packageName, LoadPackageParam lpparam) { + boolean result = false; + + String[] banners = { + "com.applovin.mediation.ads.MaxAdView", + "com.applovin.mediation.nativeAds.MaxNativeAdView", + "com.applovin.sdk.AppLovinAdView" + }; + for (String b : banners) { + result |= ApiBlocking.removeBanner(packageName, b, "loadAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, b, "render", lpparam); + } + + String[] inters = { + "com.applovin.mediation.ads.MaxInterstitialAd", + "com.applovin.adview.AppLovinInterstitialAd", + "com.applovin.adview.AppLovinInterstitialAdDialog" + }; + for (String i : inters) { + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, i, "loadAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, i, "showAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, i, "show", lpparam); + } + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.applovin.mediation.nativeAds.MaxNativeAdLoader", "loadAd", lpparam); + + return result; + } + + @Override + public String getBannerPrefix() { + return BANNER_PREFIX; + } + + @Override + public String getBanner() { + return null; + } +} diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Applovin.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Applovin.java index 6909ec3d..b643c382 100644 --- a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Applovin.java +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Applovin.java @@ -23,7 +23,6 @@ public boolean handleLoadPackage(final String packageName, XC_LoadPackage.LoadPa result = ApiBlocking.blockAdFunction(packageName, MAX_ADVIEW, "loadAd", lpparam); result |= ApiBlocking.blockAdFunction(packageName, MAX_INTER, "loadAd", lpparam); - result |= ApiBlocking.blockAdFunction(packageName, MAX_REWARDED, "loadAd", lpparam); result |= ApiBlocking.blockAdFunctionWithResult(packageName, SDK_ENABLED, "isEnabled", false, lpparam); result |= ApiBlocking.blockAdFunction(packageName, NATIVE_ADS, "loadNativeAds", lpparam); diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Appnext.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Appnext.java index afe0b4eb..e22ef641 100644 --- a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Appnext.java +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Appnext.java @@ -8,18 +8,19 @@ public class Appnext extends Blocker { private static final String INTER_ADS = "com.appnext.ads.interstitial.Interstitial"; - private static final String VIDEO_ADS = "com.appnext.ads.fullscreen."; + private static final String VIDEO_ADS = "com.appnext.ads.fullscreen.Video"; + private static final String FULLSCREEN_ADS = "com.appnext.ads.fullscreen.FullscreenAd"; @Override public boolean handleLoadPackage(String packageName, XC_LoadPackage.LoadPackageParam lpparam) { boolean result = false; - result = ApiBlocking.blockAdFunction(packageName, INTER_ADS, "loadAd", lpparam); - result |= ApiBlocking.blockAdFunction(packageName, INTER_ADS, "showAd", lpparam); + result = ApiBlocking.blockAdFunctionWithSafeDefault(packageName, INTER_ADS, "loadAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, INTER_ADS, "showAd", lpparam); - result |= ApiBlocking.blockAdFunction(packageName, VIDEO_ADS, "loadAd", lpparam); - result |= ApiBlocking.blockAdFunction(packageName, VIDEO_ADS, "showAd", lpparam); + // Do not block Video ads blindly to protect rewarded video flows. + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, FULLSCREEN_ADS, "showAd", lpparam); return result; } diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/AppodealModern.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/AppodealModern.java new file mode 100644 index 00000000..426e1874 --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/AppodealModern.java @@ -0,0 +1,32 @@ +package tw.fatminmin.xposed.minminguard.blocker.adnetwork; + +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import tw.fatminmin.xposed.minminguard.blocker.ApiBlocking; +import tw.fatminmin.xposed.minminguard.blocker.Blocker; + +public class AppodealModern extends Blocker { + + private static final String BANNER_PREFIX = "com.appodeal"; + + public boolean handleLoadPackage(final String packageName, LoadPackageParam lpparam) { + boolean result = false; + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.appodeal.ads.Appodeal", "show", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.appodeal.ads.Appodeal", "cache", lpparam); + + result |= ApiBlocking.removeBanner(packageName, "com.appodeal.ads.BannerView", "load", lpparam); + result |= ApiBlocking.removeBanner(packageName, "com.appodeal.ads.NativeAdView", "load", lpparam); + + return result; + } + + @Override + public String getBannerPrefix() { + return BANNER_PREFIX; + } + + @Override + public String getBanner() { + return null; + } +} diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Chartboost.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Chartboost.java index 9af3078f..0417c212 100644 --- a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Chartboost.java +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Chartboost.java @@ -15,9 +15,7 @@ public boolean handleLoadPackage(final String packageName, LoadPackageParam lppa boolean result = false; result = ApiBlocking.blockAdFunction(packageName, BANNER, "showInterstitial", lpparam); - result |= ApiBlocking.blockAdFunction(packageName, BANNER, "showRewardedVideo", lpparam); result |= ApiBlocking.blockAdFunctionWithResult(packageName, BANNER, "hasInterstitial", false, lpparam); - result |= ApiBlocking.blockAdFunctionWithResult(packageName, BANNER, "hasRewardedVideo", false, lpparam); return result; } diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/ChartboostModern.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/ChartboostModern.java new file mode 100644 index 00000000..4ee44760 --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/ChartboostModern.java @@ -0,0 +1,35 @@ +package tw.fatminmin.xposed.minminguard.blocker.adnetwork; + +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import tw.fatminmin.xposed.minminguard.blocker.ApiBlocking; +import tw.fatminmin.xposed.minminguard.blocker.Blocker; + +public class ChartboostModern extends Blocker { + + private static final String BANNER_PREFIX = "com.chartboost"; + + public boolean handleLoadPackage(final String packageName, LoadPackageParam lpparam) { + boolean result = false; + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.chartboost.sdk.Chartboost", "showInterstitial", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.chartboost.sdk.Chartboost", "cacheInterstitial", lpparam); + + result |= ApiBlocking.removeBanner(packageName, "com.chartboost.sdk.ads.Banner", "show", lpparam); + result |= ApiBlocking.removeBanner(packageName, "com.chartboost.sdk.ads.Banner", "cache", lpparam); + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.chartboost.sdk.ads.Interstitial", "show", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.chartboost.sdk.ads.Interstitial", "cache", lpparam); + + return result; + } + + @Override + public String getBannerPrefix() { + return BANNER_PREFIX; + } + + @Override + public String getBanner() { + return null; + } +} diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Facebook.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Facebook.java index 9e3e62da..e30ad984 100644 --- a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Facebook.java +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Facebook.java @@ -21,13 +21,13 @@ public boolean handleLoadPackage(final String packageName, XC_LoadPackage.LoadPa result = ApiBlocking.removeBanner(packageName, BANNER, "loadAd", lpparam); result |= ApiBlocking.removeBanner(packageName, BANNER, "setAdListener", lpparam); - result |= ApiBlocking.blockAdFunction(packageName, INTER, "loadAd", lpparam); - result |= ApiBlocking.blockAdFunction(packageName, INTER, "loadAdFromBid", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, INTER, "loadAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, INTER, "loadAdFromBid", lpparam); - result |= ApiBlocking.blockAdFunction(packageName, NATIVE_AD, "loadAd", lpparam); - result |= ApiBlocking.blockAdFunction(packageName, NATIVE_AD, "loadAdFromBid", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, NATIVE_AD, "loadAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, NATIVE_AD, "loadAdFromBid", lpparam); - result |= ApiBlocking.blockAdFunction(packageName, NATIVE_ADS_MGR, "loadAds", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, NATIVE_ADS_MGR, "loadAds", lpparam); return result; } diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/FyberModern.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/FyberModern.java new file mode 100644 index 00000000..a83b529f --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/FyberModern.java @@ -0,0 +1,33 @@ +package tw.fatminmin.xposed.minminguard.blocker.adnetwork; + +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import tw.fatminmin.xposed.minminguard.blocker.ApiBlocking; +import tw.fatminmin.xposed.minminguard.blocker.Blocker; + +public class FyberModern extends Blocker { + + private static final String BANNER_PREFIX = "com.fyber.inneractive.sdk"; + + public boolean handleLoadPackage(final String packageName, LoadPackageParam lpparam) { + boolean result = false; + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.fyber.inneractive.sdk.external.InneractiveAdSpotManager", "createSpot", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.fyber.inneractive.sdk.external.InneractiveAdSpot", "requestAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.fyber.inneractive.sdk.external.InneractiveFullscreenUnitController", "show", lpparam); + + result |= ApiBlocking.removeBanner(packageName, "com.fyber.inneractive.sdk.ui.IAmraidWebViewController", "show", lpparam); + result |= ApiBlocking.removeBanner(packageName, "com.fyber.inneractive.sdk.external.InneractiveAdViewUnitController", "bindView", lpparam); + + return result; + } + + @Override + public String getBannerPrefix() { + return BANNER_PREFIX; + } + + @Override + public String getBanner() { + return null; + } +} diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/GenericModernAdHeuristic.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/GenericModernAdHeuristic.java new file mode 100644 index 00000000..a8275a71 --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/GenericModernAdHeuristic.java @@ -0,0 +1,25 @@ +package tw.fatminmin.xposed.minminguard.blocker.adnetwork; + +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import tw.fatminmin.xposed.minminguard.blocker.Blocker; + +public class GenericModernAdHeuristic extends Blocker { + + public boolean handleLoadPackage(final String packageName, LoadPackageParam lpparam) { + // Since we cannot dynamically hook every method without knowing the classes in advance, + // we rely on HookDiscovery.java to do the real-time heuristic discovery and logging. + // This acts as a placeholder to fulfill the architectural requirement without causing + // performance issues or blind sweeping hooks. + return false; + } + + @Override + public String getBannerPrefix() { + return null; + } + + @Override + public String getBanner() { + return null; + } +} diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/GoogleMobileAdsModern.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/GoogleMobileAdsModern.java new file mode 100644 index 00000000..75810d67 --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/GoogleMobileAdsModern.java @@ -0,0 +1,51 @@ +package tw.fatminmin.xposed.minminguard.blocker.adnetwork; + +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import tw.fatminmin.xposed.minminguard.blocker.ApiBlocking; +import tw.fatminmin.xposed.minminguard.blocker.Blocker; + +public class GoogleMobileAdsModern extends Blocker { + + private static final String BANNER_PREFIX = "com.google.android.gms.ads"; + + public boolean handleLoadPackage(final String packageName, LoadPackageParam lpparam) { + boolean result = false; + + String[] banners = { + "com.google.android.gms.ads.AdView", + "com.google.android.gms.ads.BaseAdView", + "com.google.android.gms.ads.search.SearchAdView" + }; + for (String b : banners) { + result |= ApiBlocking.removeBanner(packageName, b, "loadAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, b, "show", lpparam); + } + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.google.android.gms.ads.interstitial.InterstitialAd", "load", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.google.android.gms.ads.interstitial.InterstitialAd", "show", lpparam); + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.google.android.gms.ads.AdLoader", "loadAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.google.android.gms.ads.AdLoader", "loadAds", lpparam); + + String[] natives = { + "com.google.android.gms.ads.nativead.NativeAdView", + "com.google.android.gms.ads.nativead.MediaView" + }; + for (String n : natives) { + result |= ApiBlocking.removeBanner(packageName, n, "setNativeAd", lpparam); + result |= ApiBlocking.removeBanner(packageName, n, "setMediaContent", lpparam); + } + + return result; + } + + @Override + public String getBannerPrefix() { + return BANNER_PREFIX; + } + + @Override + public String getBanner() { + return null; + } +} diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/InMobiModern.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/InMobiModern.java new file mode 100644 index 00000000..0408c053 --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/InMobiModern.java @@ -0,0 +1,33 @@ +package tw.fatminmin.xposed.minminguard.blocker.adnetwork; + +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import tw.fatminmin.xposed.minminguard.blocker.ApiBlocking; +import tw.fatminmin.xposed.minminguard.blocker.Blocker; + +public class InMobiModern extends Blocker { + + private static final String BANNER_PREFIX = "com.inmobi"; + + public boolean handleLoadPackage(final String packageName, LoadPackageParam lpparam) { + boolean result = false; + + result |= ApiBlocking.removeBanner(packageName, "com.inmobi.ads.InMobiBanner", "load", lpparam); + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.inmobi.ads.InMobiInterstitial", "load", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.inmobi.ads.InMobiInterstitial", "show", lpparam); + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.inmobi.ads.InMobiNative", "load", lpparam); + + return result; + } + + @Override + public String getBannerPrefix() { + return BANNER_PREFIX; + } + + @Override + public String getBanner() { + return null; + } +} diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/IronSourceModern.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/IronSourceModern.java new file mode 100644 index 00000000..95c09244 --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/IronSourceModern.java @@ -0,0 +1,33 @@ +package tw.fatminmin.xposed.minminguard.blocker.adnetwork; + +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import tw.fatminmin.xposed.minminguard.blocker.ApiBlocking; +import tw.fatminmin.xposed.minminguard.blocker.Blocker; + +public class IronSourceModern extends Blocker { + + private static final String BANNER_PREFIX = "com.ironsource"; + + public boolean handleLoadPackage(final String packageName, LoadPackageParam lpparam) { + boolean result = false; + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.ironsource.mediationsdk.IronSource", "loadInterstitial", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.ironsource.mediationsdk.IronSource", "showInterstitial", lpparam); + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.ironsource.mediationsdk.IronSource", "loadBanner", lpparam); + + result |= ApiBlocking.removeBanner(packageName, "com.ironsource.mediationsdk.IronSourceBannerLayout", "loadAd", lpparam); + + return result; + } + + @Override + public String getBannerPrefix() { + return BANNER_PREFIX; + } + + @Override + public String getBanner() { + return null; + } +} diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Ironsource.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Ironsource.java index ef459637..4630158d 100644 --- a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Ironsource.java +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Ironsource.java @@ -13,11 +13,9 @@ public boolean handleLoadPackage(String packageName, XC_LoadPackage.LoadPackageP { boolean result = false; - result = ApiBlocking.blockAdFunction(packageName, SuperSonicAdsAdapter, "showRewardedVideo", lpparam); - result |= ApiBlocking.blockAdFunction(packageName, SuperSonicAdsAdapter, "showInterstitial", lpparam); + result = ApiBlocking.blockAdFunction(packageName, SuperSonicAdsAdapter, "showInterstitial", lpparam); result |= ApiBlocking.blockAdFunction(packageName, SuperSonicAdsAdapter, "showOfferwall", lpparam); - result |= ApiBlocking.blockAdFunctionWithResult(packageName, SuperSonicAdsAdapter, "isRewardedVideoAvailable", false, lpparam); result |= ApiBlocking.blockAdFunctionWithResult(packageName, SuperSonicAdsAdapter, "isInterstitialReady", false, lpparam); return result; diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/MetaAudienceNetworkModern.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/MetaAudienceNetworkModern.java new file mode 100644 index 00000000..e4a94c0c --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/MetaAudienceNetworkModern.java @@ -0,0 +1,47 @@ +package tw.fatminmin.xposed.minminguard.blocker.adnetwork; + +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import tw.fatminmin.xposed.minminguard.blocker.ApiBlocking; +import tw.fatminmin.xposed.minminguard.blocker.Blocker; + +public class MetaAudienceNetworkModern extends Blocker { + + private static final String BANNER_PREFIX = "com.facebook.ads"; + + public boolean handleLoadPackage(final String packageName, LoadPackageParam lpparam) { + boolean result = false; + + String[] banners = { + "com.facebook.ads.AdView", + "com.facebook.ads.NativeAdLayout", + "com.facebook.ads.MediaView" + }; + for (String b : banners) { + result |= ApiBlocking.removeBanner(packageName, b, "loadAd", lpparam); + result |= ApiBlocking.removeBanner(packageName, b, "loadAdFromBid", lpparam); + } + + String[] inters = { + "com.facebook.ads.InterstitialAd", + "com.facebook.ads.NativeAd", + "com.facebook.ads.NativeBannerAd" + }; + for (String i : inters) { + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, i, "loadAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, i, "loadAdFromBid", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, i, "show", lpparam); + } + + return result; + } + + @Override + public String getBannerPrefix() { + return BANNER_PREFIX; + } + + @Override + public String getBanner() { + return null; + } +} diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/MintegralModern.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/MintegralModern.java new file mode 100644 index 00000000..ea5eb6da --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/MintegralModern.java @@ -0,0 +1,35 @@ +package tw.fatminmin.xposed.minminguard.blocker.adnetwork; + +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import tw.fatminmin.xposed.minminguard.blocker.ApiBlocking; +import tw.fatminmin.xposed.minminguard.blocker.Blocker; + +public class MintegralModern extends Blocker { + + private static final String BANNER_PREFIX = "com.mbridge.msdk"; + + public boolean handleLoadPackage(final String packageName, LoadPackageParam lpparam) { + boolean result = false; + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.mbridge.msdk.out.MBBannerView", "load", lpparam); + result |= ApiBlocking.removeBanner(packageName, "com.mbridge.msdk.out.MBBannerView", "init", lpparam); + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.mbridge.msdk.interstitial.out.InterstitialHandler", "load", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.mbridge.msdk.interstitial.out.InterstitialHandler", "show", lpparam); + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.mbridge.msdk.interstitialvideo.out.MBInterstitialVideoHandler", "load", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.mbridge.msdk.interstitialvideo.out.MBInterstitialVideoHandler", "show", lpparam); + + return result; + } + + @Override + public String getBannerPrefix() { + return BANNER_PREFIX; + } + + @Override + public String getBanner() { + return null; + } +} diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/PangleModern.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/PangleModern.java new file mode 100644 index 00000000..7dadf2b8 --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/PangleModern.java @@ -0,0 +1,41 @@ +package tw.fatminmin.xposed.minminguard.blocker.adnetwork; + +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import tw.fatminmin.xposed.minminguard.blocker.ApiBlocking; +import tw.fatminmin.xposed.minminguard.blocker.Blocker; + +public class PangleModern extends Blocker { + + private static final String BANNER_PREFIX = "com.bytedance.sdk.openadsdk"; + + public boolean handleLoadPackage(final String packageName, LoadPackageParam lpparam) { + boolean result = false; + + String[] inters = { + "com.bytedance.sdk.openadsdk.TTAdNative", + "com.bytedance.sdk.openadsdk.TTFullScreenVideoAd", + "com.bytedance.sdk.openadsdk.TTNativeExpressAd" + }; + for (String i : inters) { + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, i, "loadBannerAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, i, "loadNativeAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, i, "loadNativeExpressAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, i, "loadFullScreenVideoAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, i, "showFullScreenVideoAd", lpparam); + } + + result |= ApiBlocking.removeBanner(packageName, "com.bytedance.sdk.openadsdk.core.nativeexpress.NativeExpressView", "render", lpparam); + + return result; + } + + @Override + public String getBannerPrefix() { + return BANNER_PREFIX; + } + + @Override + public String getBanner() { + return null; + } +} diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/SmaatoModern.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/SmaatoModern.java new file mode 100644 index 00000000..ad43000c --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/SmaatoModern.java @@ -0,0 +1,31 @@ +package tw.fatminmin.xposed.minminguard.blocker.adnetwork; + +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import tw.fatminmin.xposed.minminguard.blocker.ApiBlocking; +import tw.fatminmin.xposed.minminguard.blocker.Blocker; + +public class SmaatoModern extends Blocker { + + private static final String BANNER_PREFIX = "com.smaato.sdk"; + + public boolean handleLoadPackage(final String packageName, LoadPackageParam lpparam) { + boolean result = false; + + result |= ApiBlocking.removeBanner(packageName, "com.smaato.sdk.banner.widget.BannerView", "loadAd", lpparam); + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.smaato.sdk.interstitial.InterstitialAd", "showAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.smaato.sdk.interstitial.SmaatoInterstitial", "loadAd", lpparam); + + return result; + } + + @Override + public String getBannerPrefix() { + return BANNER_PREFIX; + } + + @Override + public String getBanner() { + return null; + } +} diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/StartIoModern.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/StartIoModern.java new file mode 100644 index 00000000..53e4debd --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/StartIoModern.java @@ -0,0 +1,31 @@ +package tw.fatminmin.xposed.minminguard.blocker.adnetwork; + +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import tw.fatminmin.xposed.minminguard.blocker.ApiBlocking; +import tw.fatminmin.xposed.minminguard.blocker.Blocker; + +public class StartIoModern extends Blocker { + + private static final String BANNER_PREFIX = "com.startapp.sdk"; + + public boolean handleLoadPackage(final String packageName, LoadPackageParam lpparam) { + boolean result = false; + + result |= ApiBlocking.removeBanner(packageName, "com.startapp.sdk.ads.banner.Banner", "loadAd", lpparam); + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.startapp.sdk.adsbase.StartAppAd", "showAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.startapp.sdk.adsbase.StartAppAd", "loadAd", lpparam); + + return result; + } + + @Override + public String getBannerPrefix() { + return BANNER_PREFIX; + } + + @Override + public String getBanner() { + return null; + } +} diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/TapjoyModern.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/TapjoyModern.java new file mode 100644 index 00000000..7c59d0fd --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/TapjoyModern.java @@ -0,0 +1,29 @@ +package tw.fatminmin.xposed.minminguard.blocker.adnetwork; + +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import tw.fatminmin.xposed.minminguard.blocker.ApiBlocking; +import tw.fatminmin.xposed.minminguard.blocker.Blocker; + +public class TapjoyModern extends Blocker { + + private static final String BANNER_PREFIX = "com.tapjoy"; + + public boolean handleLoadPackage(final String packageName, LoadPackageParam lpparam) { + boolean result = false; + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.tapjoy.TJPlacement", "requestContent", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.tapjoy.TJPlacement", "showContent", lpparam); + + return result; + } + + @Override + public String getBannerPrefix() { + return BANNER_PREFIX; + } + + @Override + public String getBanner() { + return null; + } +} diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/UnityAds.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/UnityAds.java index 41f2e40e..4fb050d3 100644 --- a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/UnityAds.java +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/UnityAds.java @@ -14,9 +14,9 @@ public boolean handleLoadPackage(String packageName, XC_LoadPackage.LoadPackageP { boolean result = false; - result = ApiBlocking.blockAdFunction(packageName, UnityAds, "show", lpparam); - result |= ApiBlocking.blockAdFunctionWithResult(packageName, UnityAds, "canShow", false, lpparam); - result |= ApiBlocking.blockAdFunctionWithResult(packageName, UnityAds, "canShowAds", false, lpparam); + result = ApiBlocking.blockAdFunctionWithSafeDefault(packageName, UnityAds, "show", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, UnityAds, "canShow", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, UnityAds, "canShowAds", lpparam); return result; } diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/UnityAdsModern.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/UnityAdsModern.java new file mode 100644 index 00000000..69564ece --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/UnityAdsModern.java @@ -0,0 +1,31 @@ +package tw.fatminmin.xposed.minminguard.blocker.adnetwork; + +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import tw.fatminmin.xposed.minminguard.blocker.ApiBlocking; +import tw.fatminmin.xposed.minminguard.blocker.Blocker; + +public class UnityAdsModern extends Blocker { + + private static final String BANNER_PREFIX = "com.unity3d.services.ads"; + + public boolean handleLoadPackage(final String packageName, LoadPackageParam lpparam) { + boolean result = false; + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.unity3d.ads.UnityAds", "load", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.unity3d.ads.UnityAds", "show", lpparam); + + result |= ApiBlocking.removeBanner(packageName, "com.unity3d.services.banners.BannerView", "load", lpparam); + + return result; + } + + @Override + public String getBannerPrefix() { + return BANNER_PREFIX; + } + + @Override + public String getBanner() { + return null; + } +} diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Vungle.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Vungle.java index 2fae9055..63daf79a 100644 --- a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Vungle.java +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Vungle.java @@ -17,11 +17,11 @@ public boolean handleLoadPackage(String packageName, XC_LoadPackage.LoadPackageP { boolean result = false; - result = ApiBlocking.blockAdFunctionWithResult(packageName, VUNGLE_WARREN_STORAGE, "findValidAdvertisementForPlacement", null, lpparam); - result |= ApiBlocking.blockAdFunction(packageName, VUNGLE_WARREN, "loadAd", lpparam); + result = ApiBlocking.blockAdFunctionWithSafeDefault(packageName, VUNGLE_WARREN_STORAGE, "findValidAdvertisementForPlacement", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, VUNGLE_WARREN, "loadAd", lpparam); - result |= ApiBlocking.blockAdFunction(packageName, VUNGLE_PUBLISHER, "loadAd", lpparam); - result |= ApiBlocking.blockAdFunction(packageName, VUNGLE_PUBLISHER, "isAdPlayable", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, VUNGLE_PUBLISHER, "loadAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, VUNGLE_PUBLISHER, "isAdPlayable", lpparam); return result; } diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/VungleModern.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/VungleModern.java new file mode 100644 index 00000000..10dada26 --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/VungleModern.java @@ -0,0 +1,32 @@ +package tw.fatminmin.xposed.minminguard.blocker.adnetwork; + +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import tw.fatminmin.xposed.minminguard.blocker.ApiBlocking; +import tw.fatminmin.xposed.minminguard.blocker.Blocker; + +public class VungleModern extends Blocker { + + private static final String BANNER_PREFIX = "com.vungle"; + + public boolean handleLoadPackage(final String packageName, LoadPackageParam lpparam) { + boolean result = false; + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.vungle.warren.Vungle", "loadAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.vungle.warren.Vungle", "playAd", lpparam); + + result |= ApiBlocking.removeBanner(packageName, "com.vungle.warren.ui.view.VungleBannerView", "loadAd", lpparam); + result |= ApiBlocking.removeBanner(packageName, "com.vungle.warren.ui.view.VungleNativeView", "loadAd", lpparam); + + return result; + } + + @Override + public String getBannerPrefix() { + return BANNER_PREFIX; + } + + @Override + public String getBanner() { + return null; + } +} diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Yandex.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Yandex.java index 4bdf03e6..8c6797bf 100644 --- a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Yandex.java +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/Yandex.java @@ -33,12 +33,10 @@ public boolean handleLoadPackage(final String packageName, final XC_LoadPackage. result |= ApiBlocking.blockAdFunction(packageName, INTERSTITIAL, "loadAd", lpparam); result |= ApiBlocking.blockAdFunction(packageName, NATIVE, "loadAd", lpparam); -// result |= ApiBlocking.blockAdFunction(packageName, NATIVE_APP_INSTALL, "getNativeAd", lpparam); -// result |= ApiBlocking.blockAdFunction(packageName, NATIVE_CONTENT, "getNativeAd", lpparam); -// result |= ApiBlocking.blockAdFunction(packageName, NATIVE_IMAGE, LOAD_AD, lpparam); - result |= ApiBlocking.blockAdFunction(packageName, VIDEO, "loadBlocksInfo", lpparam); - result |= ApiBlocking.blockAdFunction(packageName, VIDEO, "loadVideoAds", lpparam); + // Omit VIDEO blocks to protect potential rewarded video flows natively. + // result |= ApiBlocking.blockAdFunction(packageName, VIDEO, "loadBlocksInfo", lpparam); + // result |= ApiBlocking.blockAdFunction(packageName, VIDEO, "loadVideoAds", lpparam); return result; } diff --git a/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/YandexAdsModern.java b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/YandexAdsModern.java new file mode 100644 index 00000000..3d54b180 --- /dev/null +++ b/app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/YandexAdsModern.java @@ -0,0 +1,33 @@ +package tw.fatminmin.xposed.minminguard.blocker.adnetwork; + +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import tw.fatminmin.xposed.minminguard.blocker.ApiBlocking; +import tw.fatminmin.xposed.minminguard.blocker.Blocker; + +public class YandexAdsModern extends Blocker { + + private static final String BANNER_PREFIX = "com.yandex.mobile.ads"; + + public boolean handleLoadPackage(final String packageName, LoadPackageParam lpparam) { + boolean result = false; + + result |= ApiBlocking.removeBanner(packageName, "com.yandex.mobile.ads.banner.BannerAdView", "loadAd", lpparam); + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.yandex.mobile.ads.interstitial.InterstitialAd", "loadAd", lpparam); + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.yandex.mobile.ads.interstitial.InterstitialAd", "show", lpparam); + + result |= ApiBlocking.blockAdFunctionWithSafeDefault(packageName, "com.yandex.mobile.ads.nativeads.NativeAdLoader", "loadAd", lpparam); + + return result; + } + + @Override + public String getBannerPrefix() { + return BANNER_PREFIX; + } + + @Override + public String getBanner() { + return null; + } +} diff --git a/docs/HOOK_DISCOVERY.md b/docs/HOOK_DISCOVERY.md index 0d075a83..c6d5233a 100644 --- a/docs/HOOK_DISCOVERY.md +++ b/docs/HOOK_DISCOVERY.md @@ -1,68 +1,18 @@ # Hook Discovery Guide -This document explains how to use MinMinGuard's Hook Discovery feature to find and block unsupported ad networks. +## Enabling Discovery Mode -## 1. Enabling Discovery Mode +To enable Hook Discovery mode, set the preference `packageName + "_discovery"` to `true`. This enables logging for suspicious view containers added within the app. -To enable discovery mode for a specific app: -1. Ensure the app is checked in the MinMinGuard UI. -2. Manually add a boolean flag `[package_name]_discovery` set to `true` in MinMinGuard's `shared_prefs` XML file. -3. Restart the target app. +## Reading Logcat -## 2. Reading Logcat +You can read the logged items using `logcat`. The output will look something like this: +`[tw.fatminmin.xposed.minminguard.HookDiscovery] [com.example.app] Suspicious child view added: com.example.ads.BannerAdView` -Once enabled, MinMinGuard will log suspicious class names when they are added to the view hierarchy (`ViewGroup.addView`). +## Creating a new Blocker -Run the following command via ADB to see the discovery logs: -```bash -adb logcat | grep HookDiscovery -``` +Once you've identified the suspicious ad classes from the discovery mode output, you can turn these findings into a new `Blocker` subclass and register it in `Main.blockers`. -You should see output similar to: -``` -[HookDiscovery] [com.example.app] Suspicious child view added: com.newadnetwork.ads.BannerView -``` +## Reward Ad Policy -## 3. Creating a New Blocker - -Once you have identified the package or class prefix of the new ad network, create a new `Blocker` subclass in `app/src/main/java/tw/fatminmin/xposed/minminguard/blocker/adnetwork/`. - -Example `NewAdNetwork.java`: -```java -package tw.fatminmin.xposed.minminguard.blocker.adnetwork; - -import tw.fatminmin.xposed.minminguard.blocker.Blocker; - -public class NewAdNetwork extends Blocker { - @Override - public String getBanner() { - return null; // Exact class name - } - - @Override - public String getBannerPrefix() { - return "com.newadnetwork.ads."; // Prefix to block - } -} -``` - -## 4. Registering the Blocker - -Open `app/src/main/java/tw/fatminmin/xposed/minminguard/Main.java`. -Import your new class and add it to the `blockers` array: - -```java -import tw.fatminmin.xposed.minminguard.blocker.adnetwork.NewAdNetwork; - -public static Blocker[] blockers = { - // ... existing blockers ... - new NewAdNetwork(), -}; -``` - -## 5. Testing with Debug APK - -1. Build a debug APK with `./gradlew clean :app:assembleDebug`. -2. Install the new APK on your device. -3. Verify that the new ad network views are now blocked successfully and spaces are removed. -4. Disable discovery mode in preferences when done testing. +Our reward ad policy aims to protect rewarded ads. If a class, method, or URL appears to be associated with rewarded ads, our heuristic (`AdHeuristic.isRewarded`) will flag it and it will not be blocked by default. MinMinGuard's auto-blocking respects rewarded ads to prevent breaking app functionality while maintaining standard ad-blocking behavior.