diff --git a/app/build.gradle b/app/build.gradle index d6e97a2..4cad630 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,8 +9,8 @@ android { applicationId "ma.wanam.youtubeadaway" minSdk 27 targetSdk 31 - versionCode 502 - versionName "5.0.2" + versionCode 503 + versionName "5.0.3" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0de2377..f4ea3b3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,7 +6,6 @@ android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" - android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.MyApplication"> cListenableFuture = XposedHelpers.findClass("com.google.common.util.concurrent.ListenableFuture", cl); Optional fMethod = Arrays.asList(methods).parallelStream().filter(method -> method.getParameterTypes().length == 2 && method.getParameterTypes()[0].equals(Context.class) && method.getParameterTypes()[1].equals(Executor.class) @@ -205,9 +242,114 @@ private void findAndHookVideoBGP3C(char a1, char a2, char a3, ClassLoader cl) { } } + private boolean bruteForceGADS(ClassLoader cl) { + Instant start = Instant.now(); + start: + for (char a1 = 'a'; a1 <= 'z'; a1++) { + for (char a2 = 'a'; a2 <= 'z'; a2++) { + for (char a3 = 'a'; a3 <= 'z'; a3++) { + findAdCardsMethods(a1, a2, a3, cl); + if (emptyComponentMethod != null && fingerprintMethod != null) + break start; + } + } + } + + if (emptyComponentMethod == null || fingerprintMethod == null) + return false; + + hookAdCardsMethods(fingerprintMethod, emptyComponentMethod); + XposedBridge.log("Ad cards hooks applied in " + Duration.between(start, Instant.now()).getSeconds() + " seconds!"); + generalAdsFound = true; + return true; + } + + private void findAdCardsMethods(char a1, char a2, char a3, ClassLoader cl) { + Class aClass; + Method[] methods; + + try { + aClass = XposedHelpers.findClass(new StringBuffer().append(a1).append(a2).append(a3).toString(), cl); + methods = aClass.getDeclaredMethods(); + } catch (Throwable e1) { + return; + } + + try { + if (fingerprintMethod == null) { + List fMethods = Arrays.asList(methods).parallelStream().filter(method -> method.getParameterTypes().length == 7 + && method.getParameterTypes()[0].getName().length() == 3 + && method.getParameterTypes()[6].equals(boolean.class) + && method.getParameterTypes()[5].equals(int.class) + && method.getName().equals(method.getName().toLowerCase()) + && Modifier.isFinal(method.getModifiers()) + && Modifier.isPublic(method.getModifiers()) + ).collect(Collectors.toList()); + + if (fMethods.size() == 1) { + fingerprintMethod = fMethods.size() == 1 ? fMethods.get(0) : null; + XposedBridge.log("Found ad cards class: " + aClass.getName() + "." + fMethods.get(0).getName()); + return; + } + } + } catch (Throwable e) { + XposedBridge.log("YouTube AdAway: Failed to hook ad cards class: " + aClass.getName()); + XposedBridge.log(e); + } + + try { + if (emptyComponentMethod == null) { + List fMethods = Arrays.asList(methods).parallelStream().filter(method -> + Modifier.isPublic(method.getModifiers()) + && Modifier.isStatic(method.getModifiers()) + && method.getParameterTypes().length == 1 + ).collect(Collectors.toList()); + + List fMethods2 = Arrays.asList(methods).parallelStream().filter(method -> Modifier.isProtected(method.getModifiers()) + && Modifier.isFinal(method.getModifiers()) + && method.getParameterTypes().length == 1 + ).collect(Collectors.toList()); + + if (fMethods.size() == 1 && fMethods2.size() == 1 && methods.length == 2) { + emptyComponentMethod = fMethods.get(0); + XposedBridge.log("Found emptyComponent class: " + aClass.getName() + "." + fMethods.get(0).getName()); + } + } + } catch (Throwable e) { + XposedBridge.log("YouTube AdAway: Failed to hook EmptyElement class: " + aClass.getName()); + XposedBridge.log(e); + } + } + + private void hookAdCardsMethods(Method cMethod, final Method emptyMethod) { + final Optional filterMethod = Arrays.asList(cMethod.getParameterTypes()[1].getDeclaredMethods()).parallelStream().filter(method -> + Modifier.isPublic(method.getModifiers()) + && Modifier.isFinal(method.getModifiers()) + && method.getName().length() == 1 + && method.getParameterTypes().length == 1 + && method.getParameterTypes()[0].equals(String.class) + ).findFirst(); + + if (!filterMethod.isPresent()) { + XposedBridge.log("YouTube AdAway: Failed to find filter method!"); + return; + } + + XposedBridge.hookMethod(cMethod, new XC_MethodHook() { + @Override + protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable { + String val = (String) filterMethod.get().invoke(param.args[1], ""); + if (!TextUtils.isEmpty(val) && !val.matches(filterIgnore) && val.matches(filterAds)) { + Object x = emptyMethod.invoke(null, param.args[0]); + Object y = XposedHelpers.getObjectField(x, "a"); + param.setResult(y); + } + } + }); + } + @Override protected void onPostExecute(Boolean found) { - if (!found) { XposedBridge.log("YouTube AdAway: brute force failed!"); } diff --git a/app/src/main/java/ma/wanam/youtubeadaway/MainActivity.java b/app/src/main/java/ma/wanam/youtubeadaway/MainActivity.java index 90d2b28..f5daf6d 100644 --- a/app/src/main/java/ma/wanam/youtubeadaway/MainActivity.java +++ b/app/src/main/java/ma/wanam/youtubeadaway/MainActivity.java @@ -9,7 +9,6 @@ import android.graphics.Color; import android.net.Uri; import android.os.Bundle; -import android.view.View; import android.widget.TextView; import android.widget.Toast; @@ -36,41 +35,30 @@ protected void onCreate(Bundle savedInstanceState) { + " " + (XChecker.isEnabled() ? res.getString(R.string.module_active) : res .getString(R.string.module_inactive)); - TextView tvStatus = ((TextView) findViewById(id.moduleStatus)); + TextView tvStatus = findViewById(id.moduleStatus); tvStatus.setText(status); tvStatus.setTextColor((XChecker.isEnabled() ? Color.GREEN : Color.RED)); - findViewById(id.btnOK).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); + findViewById(id.btnOK).setOnClickListener(v -> finish()); - findViewById(id.btnDonate).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - try { - Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(DONATE_URL)); - startActivity(browserIntent); - } catch (Throwable e) { - e.printStackTrace(); - } finally { - finish(); - } + findViewById(id.btnDonate).setOnClickListener(v -> { + try { + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(DONATE_URL)); + startActivity(browserIntent); + } catch (Throwable e) { + e.printStackTrace(); + } finally { + finish(); } }); TextView tv = findViewById(id.textViewBTCAdr); - tv.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - ClipboardManager cm = (ClipboardManager) getApplicationContext().getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = ClipData.newPlainText("btc_adr", tv.getText()); - cm.setPrimaryClip(clip); - Toast.makeText(getApplicationContext(), R.string.addr_copied, Toast.LENGTH_SHORT).show(); - return false; - } + tv.setOnLongClickListener(v -> { + ClipboardManager cm = (ClipboardManager) getApplicationContext().getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText("btc_adr", tv.getText()); + cm.setPrimaryClip(clip); + Toast.makeText(getApplicationContext(), R.string.addr_copied, Toast.LENGTH_SHORT).show(); + return false; }); } } diff --git a/app/src/main/java/ma/wanam/youtubeadaway/Xposed.java b/app/src/main/java/ma/wanam/youtubeadaway/Xposed.java index 8dd348c..25824e3 100644 --- a/app/src/main/java/ma/wanam/youtubeadaway/Xposed.java +++ b/app/src/main/java/ma/wanam/youtubeadaway/Xposed.java @@ -13,7 +13,13 @@ public class Xposed implements IXposedHookLoadPackage { @Override public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable { - if (lpparam.packageName.equals(Constants.GOOGLE_YOUTUBE_PACKAGE)) { + if (lpparam.packageName.equals(Constants.GOOGLE_YOUTUBE_PACKAGE) + || lpparam.packageName.equals(Constants.GOOGLE_YOUTUBE_KIDS_PACKAGE) + || lpparam.packageName.equals(Constants.GOOGLE_YOUTUBE_GAMING) + || lpparam.packageName.equals(Constants.GOOGLE_YOUTUBE_MUSIC) + || lpparam.packageName.equals(Constants.GOOGLE_YOUTUBE_MANGO) + || lpparam.packageName.equals(Constants.GOOGLE_YOUTUBE_TV1_PACKAGE) + || lpparam.packageName.equals(Constants.GOOGLE_YOUTUBE_TV2_PACKAGE)) { try { String ytVersion = Utils.getPackageVersion(lpparam); XposedBridge.log("Hooking YouTube version: " + lpparam.packageName + " " + ytVersion); diff --git a/app/src/main/java/ma/wanam/youtubeadaway/utils/Constants.java b/app/src/main/java/ma/wanam/youtubeadaway/utils/Constants.java index 162d4a2..471a8ea 100644 --- a/app/src/main/java/ma/wanam/youtubeadaway/utils/Constants.java +++ b/app/src/main/java/ma/wanam/youtubeadaway/utils/Constants.java @@ -2,4 +2,10 @@ public class Constants { public static final String GOOGLE_YOUTUBE_PACKAGE = "com.google.android.youtube"; + public static final String GOOGLE_YOUTUBE_KIDS_PACKAGE = "com.google.android.apps.youtube.kids"; + public static final String GOOGLE_YOUTUBE_TV1_PACKAGE = "com.google.android.youtube.tv"; + public static final String GOOGLE_YOUTUBE_TV2_PACKAGE = "com.google.android.youtube.googletv"; + public static final String GOOGLE_YOUTUBE_GAMING = "com.google.android.apps.youtube.gaming"; + public static final String GOOGLE_YOUTUBE_MUSIC = "com.google.android.apps.youtube.music"; + public static final String GOOGLE_YOUTUBE_MANGO = "com.google.android.apps.youtube.mango"; } diff --git a/app/src/main/java/ma/wanam/youtubeadaway/utils/Utils.java b/app/src/main/java/ma/wanam/youtubeadaway/utils/Utils.java index f692fbc..95498ef 100644 --- a/app/src/main/java/ma/wanam/youtubeadaway/utils/Utils.java +++ b/app/src/main/java/ma/wanam/youtubeadaway/utils/Utils.java @@ -1,5 +1,10 @@ package ma.wanam.youtubeadaway.utils; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Build; + import java.io.File; import de.robv.android.xposed.XposedHelpers; @@ -9,11 +14,16 @@ public class Utils { public static String getPackageVersion(XC_LoadPackage.LoadPackageParam lpparam) { try { - Class parserCls = XposedHelpers.findClass("android.content.pm.PackageParser", lpparam.classLoader); - Object parser = parserCls.newInstance(); File apkPath = new File(lpparam.appInfo.sourceDir); - Object pkg = XposedHelpers.callMethod(parser, "parsePackage", apkPath, 0); - return (String) XposedHelpers.getObjectField(pkg, "mVersionName"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + Class pkgParserClass = XposedHelpers.findClass("android.content.pm.PackageParser", lpparam.classLoader); + Object packageLite = XposedHelpers.callStaticMethod(pkgParserClass, "parsePackageLite", apkPath, 0); + return String.valueOf(XposedHelpers.getIntField(packageLite, "versionCode")); + } else { + Class parserCls = XposedHelpers.findClass("android.content.pm.PackageParser", lpparam.classLoader); + Object pkg = XposedHelpers.callMethod(parserCls.newInstance(), "parsePackage", apkPath, 0); + return String.valueOf(XposedHelpers.getIntField(pkg, "mVersionCode")); + } } catch (Throwable e) { return null; } diff --git a/app/src/main/res/drawable-hdpi/ic_launcher.png b/app/src/main/res/drawable-hdpi/ic_launcher.png deleted file mode 100644 index 5ce61d4..0000000 Binary files a/app/src/main/res/drawable-hdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/drawable-ldpi/ic_launcher.png b/app/src/main/res/drawable-ldpi/ic_launcher.png deleted file mode 100644 index 664dfdd..0000000 Binary files a/app/src/main/res/drawable-ldpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_launcher.png b/app/src/main/res/drawable-mdpi/ic_launcher.png deleted file mode 100644 index 68deb8c..0000000 Binary files a/app/src/main/res/drawable-mdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_launcher.png b/app/src/main/res/drawable-xhdpi/ic_launcher.png deleted file mode 100644 index 6d4b048..0000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_launcher.png b/app/src/main/res/drawable/ic_launcher.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_launcher.png rename to app/src/main/res/drawable/ic_launcher.png diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..036d09b --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..dd2c058 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..5882ddc Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..88dcc70 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..2ac6b85 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..2a8ce03 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index ef6fdfc..f200b0b 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -5,8 +5,8 @@ n\'est pas actif!\nVérifier qu\'il est activé et redémarrer l\'appareil. Supporter Non merci! - "Ce qui est implémenté:\nBloquer les annonces dans les videos\nActiver la lecture en arrière plan" - "Reste à faire: Bloquer les cartes d'annonces (Pas d\'ETA!)\nLe projet est open source, les contributions sont les bienvenues." + "Ce qui est implémenté:\nBloquer les annonces dans les videos\nActiver la lecture en arrière plan\nBloquer les cartes d'annonces (BETA)" + "Le projet est open source, les contributions sont les bienvenues." Don en BTC Adresse BTC copiée! \ No newline at end of file diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 0000000..c5d5899 --- /dev/null +++ b/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4e859d7..c4fe855 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -5,8 +5,8 @@ is NOT active!\nMake sure it is enabled and REBOOT. Donate No thanks - "What's in:\nBlock in-video ads\nEnable background play" - "TODO: Block ad video cards (No ETA!)\nThis project is open source, feel free to contribute." + "What's in:\nBlock in-video ads\nEnable background play\nBlock ad cards (BETA)" + "This project is open source, feel free to contribute." Donate BTC BTC address copied! \ No newline at end of file