Posts Do you know the difference between strings and compiler symbols?
Post
Cancel

Do you know the difference between strings and compiler symbols?

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: 
#if DEBUG
    string const url = "https://dev.mycompany.com"
#else    
    string const url = "https://prod.mycompany.com"
#endif

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

This post is licensed under CC BY 4.0 by the author.