Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 32 additions & 13 deletions app/src/main/java/tw/fatminmin/xposed/minminguard/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String> hookedPackages = new HashSet<>();
private static Set<String> hookedPackages = Collections.synchronizedSet(new HashSet<String>());

private static boolean isEnabled(SharedPreferences pref, String pkgName)
{
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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.");
}
}

Expand Down Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
});
}
Expand Down Expand Up @@ -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);
}
});
}
Expand Down Expand Up @@ -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);
}
});
}
Expand Down Expand Up @@ -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);
}
});
}
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Loading
Loading