Skip to content

Commit

Permalink
Merge pull request #124 from wanam/origin/master
Browse files Browse the repository at this point in the history
Hide Ad cards
  • Loading branch information
wanam authored Jan 2, 2023
2 parents 270fb0b + 7600c8b commit 53c6068
Show file tree
Hide file tree
Showing 22 changed files with 203 additions and 43 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand Down
1 change: 0 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
<meta-data
Expand Down
Binary file added app/src/main/ic_launcher-playstore.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
148 changes: 145 additions & 3 deletions app/src/main/java/ma/wanam/youtubeadaway/BFAsync.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import android.content.Context;
import android.os.AsyncTask;
import android.text.TextUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
Expand All @@ -24,15 +26,50 @@ public class BFAsync extends AsyncTask<XC_LoadPackage.LoadPackageParam, Void, Bo
private boolean DEBUG = BuildConfig.DEBUG;
private volatile boolean sigAdFound = false;
private volatile boolean sigBgFound = false;
private volatile boolean generalAdsFound = false;
private volatile Method emptyComponentMethod = null;
private volatile Method fingerprintMethod = null;

private static final String filterAds = new StringBuffer().append(".*(").append(String.join("|", new String[]{
"ads_video_with_context",
"banner_text_icon",
"square_image_layout",
"watch_metadata_app_promo",
"video_display_full_layout",
"browsy_bar",
"compact_movie",
"horizontal_movie_shelf",
"movie_and_show_upsell_card",
"compact_tvfilm_item",
"video_display_full_buttoned_layout",
"full_width_square_image_layout",
"_ad_with",
"landscape_image_wide_button_layout",
"carousel_ad",
"in_feed_survey",
"compact_banner"
})).append(").*").toString();

private static final String filterIgnore = new StringBuffer().append(".*(").append(String.join("|", new String[]{
"home_video_with_context",
"related_video_with_context",
"comment_thread",
"comment\\.",
"download_",
"library_recent_shelf",
"playlist_add_to_option_wrapper"
})).append(").*").toString();


@Override
protected Boolean doInBackground(XC_LoadPackage.LoadPackageParam... params) {
ClassLoader cl = params[0].classLoader;

boolean foundBGClass = bruteForceBGP(cl);
boolean foundInVideoAds = bruteForceInVideoAds(cl);
boolean foundGNADS = bruteForceGADS(cl);

return foundBGClass && foundInVideoAds;
return foundBGClass && foundInVideoAds && foundGNADS;
}

private boolean bruteForceInVideoAds(ClassLoader cl) {
Expand Down Expand Up @@ -173,7 +210,7 @@ private void findAndHookVideoBGP3C(char a1, char a2, char a3, ClassLoader cl) {

try {
if (!sigBgFound) {
Class cListenableFuture = XposedHelpers.findClass("com.google.common.util.concurrent.ListenableFuture", cl);
Class<?> cListenableFuture = XposedHelpers.findClass("com.google.common.util.concurrent.ListenableFuture", cl);
Optional<Method> fMethod = Arrays.asList(methods).parallelStream().filter(method -> method.getParameterTypes().length == 2
&& method.getParameterTypes()[0].equals(Context.class)
&& method.getParameterTypes()[1].equals(Executor.class)
Expand Down Expand Up @@ -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<Method> 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<Method> fMethods = Arrays.asList(methods).parallelStream().filter(method ->
Modifier.isPublic(method.getModifiers())
&& Modifier.isStatic(method.getModifiers())
&& method.getParameterTypes().length == 1
).collect(Collectors.toList());

List<Method> 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<Method> 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!");
}
Expand Down
44 changes: 16 additions & 28 deletions app/src/main/java/ma/wanam/youtubeadaway/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
});
}
}
8 changes: 7 additions & 1 deletion app/src/main/java/ma/wanam/youtubeadaway/Xposed.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/java/ma/wanam/youtubeadaway/utils/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
18 changes: 14 additions & 4 deletions app/src/main/java/ma/wanam/youtubeadaway/utils/Utils.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
}
Expand Down
Binary file removed app/src/main/res/drawable-hdpi/ic_launcher.png
Binary file not shown.
Binary file removed app/src/main/res/drawable-ldpi/ic_launcher.png
Binary file not shown.
Binary file removed app/src/main/res/drawable-mdpi/ic_launcher.png
Binary file not shown.
Binary file removed app/src/main/res/drawable-xhdpi/ic_launcher.png
Binary file not shown.
File renamed without changes
5 changes: 5 additions & 0 deletions app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions app/src/main/res/values-fr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
<string name="module_inactive">n\'est pas actif!\nVérifier qu\'il est activé et redémarrer l\'appareil.</string>
<string name="donate">Supporter</string>
<string name="no_thanks">Non merci!</string>
<string name="whats_in">"Ce qui est implémenté:\nBloquer les annonces dans les videos\nActiver la lecture en arrière plan"</string>
<string name="whats_not">"Reste à faire: Bloquer les cartes d'annonces (Pas d\'ETA!)\nLe projet est open source, les contributions sont les bienvenues."</string>
<string name="whats_in">"Ce qui est implémenté:\nBloquer les annonces dans les videos\nActiver la lecture en arrière plan\nBloquer les cartes d'annonces (BETA)"</string>
<string name="whats_not">"Le projet est open source, les contributions sont les bienvenues."</string>
<string name="donate_btc">Don en BTC</string>
<string name="addr_copied">Adresse BTC copiée!</string>
</resources>
4 changes: 4 additions & 0 deletions app/src/main/res/values/ic_launcher_background.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFFFFF</color>
</resources>
4 changes: 2 additions & 2 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
<string name="module_inactive">is NOT active!\nMake sure it is enabled and REBOOT.</string>
<string name="donate">Donate</string>
<string name="no_thanks">No thanks</string>
<string name="whats_in">"What's in:\nBlock in-video ads\nEnable background play"</string>
<string name="whats_not">"TODO: Block ad video cards (No ETA!)\nThis project is open source, feel free to contribute."</string>
<string name="whats_in">"What's in:\nBlock in-video ads\nEnable background play\nBlock ad cards (BETA)"</string>
<string name="whats_not">"This project is open source, feel free to contribute."</string>
<string name="donate_btc">Donate BTC</string>
<string name="addr_copied">BTC address copied!</string>
</resources>

0 comments on commit 53c6068

Please sign in to comment.