Advantages of Using the Build Integrity Verification
A build integrity verification brings many benefits to your project. Consider these advantages:
- Standard attacks and tools like lucky patcher won’t be able to break your application
- It’s easy to implement and maintain
- It’s not used commonly. Hackers may not be familiar with this technique—they might struggle to break it
- It’s reusable. Once implemented, it will be easy to use in your other applications
How Does the Build Integrity Verification Work?
We want to be able to detect changes to application source code and terminate the application once such changes occur. To do this, we can implement a cyclic redundancy check on the application’s bytecode. We will calculate the hash of the classes.dex file and then store it in strings.xml. Then at some point when the application is running, we can invoke the isCodeModified() function.
fun isCodeModified(): Boolean {
val hash = getString(R.string.crc)
val entry = ZipFile(app.packageCodePath).getEntry("classes.dex")
val classesCrc = Long.toHexString(entry.crc)
return classesCrc != hash
}
This function will retrieve the previously cached checksum and then compare it with the current classes.dex checksum value. If those values differ, then we know that the source code was modified and we can terminate the application process. One important point here is that the cached checksum should be stored in application resources, not directly in the source code. Otherwise the classes.dex checksum would change when you modify the cached crc value.
How to Automate the Caching Checksum Value?
Now that we know how to implement the build integrity verification one question remains: how and when should we store the checksum in strings.xml? Once we are ready for an application release, we could use this simplistic algorithm:
- Build apk like we normally would.
- Retrieve classes.dex file from apk file and calculate the checksum for that.
- Store calculated checksum in strings.xml file and then build application once again.
This process would be cumbersome if we had to perform these steps every time we want to release a new update to Google Play Store. Also, it’s common these days to use a continuous integration system to automate application builds. To address these issues, we will create two gradle tasks:
static def getChecksum() {
def command = "crc32 PATH_TO_CLASSES_DEX"
return command.execute().text
}
def getCachedChecksum() {
//retrieve cached checksum in strings.xml and return it
}
task verifyChecksum() {
doLast {
if(getChecksum() != getCachedChecksum()) {
throw new GradleException()
}
}
}
task updateChecksum() {
doLast {
//store currentChecksum in strings.xml
}
}
We left out certain implementation details as an exercise for you.
Now that we have those gradle tasks, we can utilize them in the bash script that will be executed by the CI system:
set -e
./gradlew clean
./gradlew app:assembleRelease
set +e
if ./gradlew verifyChecksum ; then
echo "Checksum valid"
else
set -e
./gradlew updateChecksum
./gradlew clean
./gradlew app:assembleRelease
./gradlew verifyChecksum
fi
Here we simply build an application and then verify the checksum. If the checksum is incorrect, then we update it and then build apk once again. Now the checksum should be correct, and we can safely distribute the build to our users.
It’s important to notice that we execute a “clean” task before each build. Otherwise the calculated checksums would differ and our algorithm wouldn’t work correctly.
The Build Integrity Verification Can Fortify Your Application
Unfortunately, the nature of mobile applications renders them impossible to be resilient to every attack. Potential attackers will always have a possibility to decompile your code and modify it. However, the build integrity verification will make potential attacks much more difficult. Hopefully this article will prove valuable to you, and you will consider implementing this security measure in your future projects. Happy coding!
Related articles
Supporting companies in becoming category leaders. We deliver full-cycle solutions for businesses of all sizes.