Reverse Engineering APKs
Lately I have been working on reverse engineering an app. Along the way I came across something interesting that I had to share. I decompiled the APK from the Play Store (very easy to do), and went looking around the files. In the decompiled APK, I found many problems (which was why I was decompiling it in the first place). In the strings.xml
file, was something very surprising to me; to the point that it inspired this blog post. The urls for the app were all stored in the strings.xml
file! This included the dev and staging environments, of which there were a few. This is not the best practise.
What is the strings.xml
file really for?
The purpose of the strings.xml
file for Android (Xamarin Forms uses the .Resx
file extension; the concept is the same) is only for text that will appear on the UI of the app. By doing this it allows for internationalization (allowing the app to support multiple languages).
Adding additional information here has a few downsides. Data for a DEV build should not be in a production; if only to prove that the user can never see it. Consider the url issue. If the DEV url is not present in the release version of the app, then it is impossible for a developer to make a coding error where the app uses the DEV url. That also means the developer has less testing to do, since it is is not possible to write a unit test for an impossible scenario.
Security is also improved by only putting UI text in the strings.xml
file. An attacker would have less information to find vulnerabilities in the system. Putting code (strings are code) in the correct place also makes the code clearer for other developers. It makes the intent obvious that text in the strings.xml
is for the UI (and careful attention to the language should be given as the text is for an end user), while strings should be in the code. Strings are for developers and the developer should write strings (like any piece of code) with other developers in mind.
Using compiler symbols
The solution is in fact rather easy - use compiler symbols. As already mentioned, it will provide many benefits in helping that the release APK works as intended. Compiler symbols, allow a developer to instruct the compiler which sections of the code to include or omit. When a developer complies the app, the symbols are passed to the compiler that controls the behaviour (the symbols are generally controlled by the configuration of the IDE eg DEBUG/RELEASE). An example is easy to understand:
1: 2: 3: 4: 5: |
|
The statements are rather intuitive. For the line #if DEBUG
, if the symbol DEBUG
is defined, the compiler will include the nested code. Otherwise the compiler will include the #else
section of the code. Compiler statements do not need to contain an #else
block.
When using any IDE (Visual Studio or Android Studio) there are options to control the configuration ie what complier symbols are present. Be default the configuration DEBUG
is selected and as a result the DEBUG
compiler symbol will be added when compiling. For the section of the code above, the app that is compiled will have the url "https://dev.mycompany.com"
. If RELEASE
was selected as the configuration, then the DEBUG
symbol would not be present. And as you guessed, the resulting app would have a url of "https://prod.mycompany.com"
If you have more than one dev,test,staging environment, add more code in the #if DEBUG
section, and ensure that when the RELEASE
configuration is selected, there is no dev/test code in the APK. Following this pattern will help reduce any silly mistakes with a production version of the app, make the code clear for other developers to understand, and reduce the APK size. Until next time
Happy coding