Search code examples
androidadmobapk

Android admob prevent remove ads by decompile apk


After decompile apk with APK Easy Tool and edit AndroidManifest.xml file:

change it:

<activity android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" android:exported="false" android:name="com.google.android.gms.ads.AdActivity" android:theme="@android:style/Theme.Translucent"/>

--> "com.google.android.gms.ads.AdActivity"

to:

<activity android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" android:exported="false" android:name="hacked_com.google.android.gms.ads.AdActivity" android:theme="@android:style/Theme.Translucent"/>

--> "hacked_com.google.android.gms.ads.AdActivity"

or edit:

<meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="ca-app-pub-0000000000000000~123456789"/> // change app id

and save and compile to apk again. my banners and interstitial ads not showing. how to fix this hard bug?


Solution

  • Try this out from this source: https://www.airpair.com/android/posts/adding-tampering-detection-to-your-android-app:

    2 Verifying your app's signing certificate at runtime

    Prerequisite: The Android developers blog has a great article on signing your app. I Recommend reading this first as this technique relies on that knowledge.

    In a nutshell, developers must sign applications with their private key/certificate (contained in a .keystore file) before the app can be installed on user devices. The signing certificate must stay consistent throughout the life of the app, and typically have an expiry date of 25 years in the future.

    The consistency of the developer signing certificate is relied upon by the Android system when dealing with app upgrades. For example, while I could create an app with the same App ID as Facebook, I couldn't trick users into upgrading to my version as it's not signed with Facebook's certificate. As developers, we must keep this certificate private otherwise we risk others being able to sign applications as us.

    Tip: Keep your private key (.keystore file) out of source control and in a separately secured and backed-up system.

    The app signature will be broken if the .apk is altered in any way — unsigned apps cannot typically be installed. We can imagine an attacker removing license-checking code to enable full app features without paying, for instance. A more dangerous example would be altering the .apk to include malware in a legitimate app to harvest sensitive user data. In order for the altered .apk to be installed, the attacker must resign it.

    This technique details how to ensure that your .apk has been signed with your developer certificate, and leverages the fact that the certificate remains consistent and that only you have access to it.

    We can break this technique into 3 simple steps:

    Find your developer certificate signature. Embed your signature in a String constant in your app. Check that the signature at runtime matches our embedded developer signature.

      private static final int VALID = 0;
    
      private static final int INVALID = 1;
    
      public static int checkAppSignature(Context context) {
    
        try {
    
          PackageInfo packageInfo = context.getPackageManager()
    
              .getPackageInfo(context.getPackageName(),
    
                  PackageManager.GET_SIGNATURES);
    
          for (Signature signature : packageInfo.signatures) {
    
            byte[] signatureBytes = signature.toByteArray();
    
            MessageDigest md = MessageDigest.getInstance("SHA");
    
            md.update(signature.toByteArray());
    
            final String currentSignature = Base64.encodeToString(md.digest(), Base64.DEFAULT);
    
    Log.d("REMOVE_ME", "Include this string as a value for SIGNATURE:" + currentSignature);
    
            //compare signatures
    
            if (SIGNATURE.equals(currentSignature)){
    
              return VALID;
    
            };
    
          }
    
        } catch (Exception e) {
    
    //assumes an issue in checking signature., but we let the caller decide on what to do.
    
        }
    
        return INVALID;
    
      }
    

    First, we need to find the signature of our certificate so that we can embed it in the app. I've included a line to calculate and log this to the system log — it should go without saying this should be removed once your have a copy.

    Check your logcat output for a message similar to this:

    10-10 17:37:11.483: D/REMOVE_ME:(111): 478yYkKAQF+KST8y4ATKvHkYibo=

    Make a note of the encoded signature and replace the value of the static constant SIGNATURE:

    private static final String SIGNATURE = "478yYkKAQF+KST8y4ATKvHkYibo=";

    At runtime, the PackageManager allows us to query the signatures of our application. We iterate through this array of signatures and compare it against our signature.

    Now, when you run checkAppSignature on your app — when signed with your release developer certificate — you should see that it returns 0, i.e. valid. This hardcoded signature is an ideal candidate for DexGuard's String Encryption.


    Alternatively you could count the signatures. If there are more than 1 -> Abort:

    public final String checkSignature()
    {
        Log.i(TAG, "executeSignatureCheck()");
    
        Signature[] sigs;
        try
        {
            sigs = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES).signatures;
        }
        catch (PackageManager.NameNotFoundException e)
        {
            throw new RuntimeException("PackageManager name not found.");
        }
    
        String signature = null;
        int sigCount = 0;
        for (Signature sig : sigs)
        {
            signature = getSHA1(sig.toByteArray());
            Log.i(TAG, "Signature: " + signature);
            sigCount++;
        }
    
        if (sigCount > 1)
        {
            throw new RuntimeException("Invalid signature.");
        }
    
        return signature;
    }
    

    You should also consider to check, if the app was downloaded from Google Play. (See: "Verifying the installer" from that link I posted). But unfortunately you can't be sure that this works on every device. I deployed such check and released to Alpha in Google Play, but 2 of 9 devices didn't return the string. I was not able to figure out, if the Google Play Store is broken or the devices really don't return any of these strings. (see my problem here: Is it possible that getInstallerPackageName() is null when app downloaded from Google Play Store?)