Fight against reverse engineering of Android APK

Source: Unsplash

If you are an Android developer you know that there is a possibility that someone will take your APK and reverse engineering it with some help of magic. Well, that is fine! If someone wants to see how awesome are my programming skills, they can, it’s not a problem. I could give him access to GitHub rep so they don’t even need to struggle with reverse engineering. I am perfectly aware of API keys that I use in the app, for example: a key for Google Maps, Google Places, Crashlytics, Fabric and so on… along with the fact that someone can retrieve them. I did not lose my mind and put secret keys it in my strings.xml file or hardcoded it somewhere. I was “smart” and put them in environment variables. I had all of my keys in env variables and thought that was safe.

I had the following setup:

buildTypes {  
release {
resValue "string" , "google_maps_api_key", System.getenv("MAPS_API_KEY_RELEASE" )
resValue "string" , "google_places_api_key", System.getenv("PLACES_API_KEY_RELEASE" )

}
debug {
resValue "string" , "google_maps_api_key", System.getenv("MAPS_API_KEY_DEBUG" )
resValue "string" , "google_places_api_key", System.getenv("PLACES_API_KEY_DEBUG" )
}

Safe enough, right? Well, guess again! When you do the magic and reverse my app, you would find the following in the strings.xml file.

<string name="google_maps_api_key">AIzaSdasdas3vBKf01SladdsaDG6nL2riF8</string>  
<string name="google_places_api_key">AIadasT0TygCdsadVJ1Pqp722kaoJzzaW32e</string>

Ok, it looks like in the process of building my apk file, evil Gradle took my keys and planted them in the string.xml file.

SHIT!

Well that kinda makes sense… I was creating resource values in the build process after all. Ok, I need to stop slacking and do some work on my security perspective in Android development. I need a better way to hide my API keys. I will keep my keys in environment variables, but this time with a twist. I will use my BuildConfig file to store the keys!

buildTypes {  
release {
buildConfigField "string" , "google_maps_api_key", System.getenv("MAPS_API_KEY_RELEASE" )
buildConfigField "string" , "google_places_api_key", System.getenv("PLACES_API_KEY_RELEASE" )

}
debug {
buildConfigField"string" , "google_maps_api_key", System.getenv("MAPS_API_KEY_DEBUG" )
buildConfigField "string" , "google_places_api_key", System.getenv("PLACES_API_KEY_DEBUG" )
}

I was far smarter this time! Let’s build the app and reverse it again… 
 I checked the string.xml file and no keys to be found! YES! I am the best! But, wait… Opening my .dex file reveals my Java classes with BuildConfig.java file right i sight, oh no…

SHIT!

public final class BuildConfig  
{
public static final String google_maps_api_key= "AIzaSdasdas3vBKf01SladdsaDG6nL2riF8 ";
public static final String google_maps_places_api_key= "AIadasT0TygCdsadVJ1Pqp722kaoJzzaW32e ";
}

Well, fuck you Google, fuck you Android studio, and fuck you Android as well!

I know that I could use Proguard and obfuscate my source code but my keys will still be able to be recovered after a bit of work. After a few attempts, I searched Google to find a good way to hide my keys from potential trouble makers. Is it really true that there is no other way to fight against reverse engineering than holding APi keys on the server or using some encryption/decryption on the client side?

If you know some way that I missed, please do let me know in the comments below. :)


Originally published at itworkslocal.ly on June 26, 2016.