13

What I Have

I have an Android app with some sensitive data. I want to make sure that the client app calls the server only if it has not been tampered with in any way. Basically, I want to check the integrity of the Android app.

What I Have Done

For that, I have implemented a method that can check if the signature is same as the signature I have signed the APK with. Here is a code sample,

fun isApkSignatureBroken(): Boolean {
        val packageInfo = context.packageManager.getPackageInfo(context.packageName, GET_SIGNATURES)

        val signatures = packageInfo.signatures
        if (signatures == null || signatures.isEmpty()) {
            return true
        }

        return signatures
                .map { it.toByteArray() }
                .map { hash.getSha1(it) }
                .none { it.equals(getRealAppSignature(), true) }
    }

Here, getRealAppSignature() returns my actual signature with which I have signed the app.

Observations

  • I have seen this method to work well sometimes. Whenever a tampered app is discovered, this method returns true and the user is blocked from using the app and I am notified by an event. I have found many users being blocked in this way.

  • I have seen many other cases being reported in forums and other social media sites, that people are using my app even if they are having tampered apps. I have observed many of my apps having malformed version names and application names being used by many users. Like, if my original apps version is 2.2 then they will create a malformed version 2.2-TERMINATOR.

Analysis

I did some analysis on the apps and found some tampered apps from some forums. Those are clearly modded apps having malformed version and application names. Some even have minor UI changes. I tried to install those apps, but they can't be installed with the message "Package is corrupted".

I tried to run keytool on those apps to check their signature, like this,

keytool -list -printcert -jarfile TAMPERED_APP.apk

but I always got,

keytool error: java.lang.SecurityException: SHA1 digest error for classes.dex

I finally rooted my device, installed Xposed Framework and disabled "App Signature Verification" and then was able to install those apps. What I found was that the app was not getting blocked as my signature checking method always returned "false". That means, it always found the original signature inside the apk.

More Analysis

I spend some more time and was able to unpackage the APK using ApkTool. Inside the META-INF folder I found the CERT.RSA to only contain my original signature and no other signature. I opened the MANIFEST.MF file and found that all the entries have different SHA1 than my original APKs manifest file.

It clearly means that the app was modified and was signed by another signature (hence the change in MANIFEST.MF) but my CERTIFICATE.RSA only had my original signature because of which my app always got the original SHA from PackageManager.

Questions

  • How is the app being re-signed but the new signature is not stored in CERTIFICATE.RSA?

  • Why is my original certificate still present in CERTIFICATE.RSA?

  • If the app was resigned, then multiple signatures should be present? But that is true here.

  • In this situation, how do I detect that the app has been tampered with? Is there any way I can compute the SHA of the app myself instead of querying the PackageManager?

EDIT #1: The entire code is obfuscated using DexGuard. So, the chance of the tamper detection logic getting messed up is pretty less.

Aritra Roy
  • 15,355
  • 10
  • 73
  • 107
  • Related: https://stackoverflow.com/questions/9865162/how-to-secure-my-app-against-piracy and https://stackoverflow.com/questions/8611960/piracy-piracy-piracy-what-can-i-do – Morrison Chang Mar 19 '18 at 19:43
  • 3
    "how do I detect that the app has been tampered?" -- if they can tamper with your app, they can tamper with any tamper-detection code that you may have in your app. – CommonsWare Mar 19 '18 at 19:58
  • @CommonsWare Yes, agree. But all this detection logic is obfuscated using DexGuard. Its very difficult for them to tamper with the logic directly. Is there any other way to check the integrity of the app? – Aritra Roy Mar 20 '18 at 05:49
  • Even very heavily obsfucated apps can be tampered easily enough - I have seen pretty few apps that a dedicated cracker cannot crack. – Akhil Kedia Mar 31 '18 at 21:18
  • @AritraRoy did you find an answer to your questions or any way forward with this ? – Sharp Edge Feb 22 '21 at 18:00

0 Answers0