Penetration Testing

Android Penetration Testing: APK Reversing (Part 2)


Android reverse engineering refers to the process of decompiling the APK for the purpose of investigating the source code that is running in the background of an application. In part 1 (refer here) we saw how an attacker would be able to decompile, change the smali files and recompile and sign the APK to perform some kind of function, for example, changing root detection logic of the application. In this extension of reversing articles, we’ll see different scenarios in which an attacker is able to extract juicy information by decompiling an APK while understanding various default files present in android. It is wrong to say this article covers all of the aspects of reversing and extracting info, however, it will lay out a fundamental process as to how one can proceed to do so. Let’s begin

Table of Content

  • Understanding default files
  • Understanding improper WebView implementation
  • Hardcoded secrets
  • Secrets in strings.xml file
  • Insecure classes implementation
  • Insecure decryption method for hardcoded values
  • Insecure cryptography in SQLite database
  • Hard coded AWS credentials

Understanding default files

 AndroidManifest.xml – Manifest literally means to show. This is the most literal file in the whole of the application as it does precisely what it’s name suggests. It begins with a <manifest> tag. It should also contain “xmlns: attribute” which declares several system attributes used within the file. It declares:

  • <permissions> – Permissions that APK requires to run
  • <activity> – Various activities in the APK
  • <intent-filter> – Intent filters
  • <data android:scheme=”string” /> – Data Schemes
  • <action android:name=”string” /> – Action that an intent performs
  • <uses-configuration> tag – specifies input mechanisms
  • <uses-sdk> tag – specifies android API to be used

Hence, Manifest file is the guide which is needed by the package to make particular components behave the way the developer intended them to.

Strings.xml – This XML file contains strings that can be referenced from the application or from other resource files (such as an XML layout). In other words, I can use a reference to strings’ object in my actual Java class so that I don’t have to type in the complete value then and there and also if there is a need to change that value in future, I won’t need to go to my java class every single time to change it, I can just change the value in the strings file. One example is supposed in Java file the code flows like this:

String string = getString(R.string.hello);

 Here, R.string.<string object> sets the value of variable string. I can make its reference in the layout file like this:

android:text=”@string/hello” />

This sets the type of view that the hello object would have while displaying in app. Here, @string/hello refers to strings.xml file’s hello object. So, finally in the strings.xml file code would be something like:

<?xml version=”1.0″ encoding=”utf-8″?>
<string name=”hello”>Hello!</string>

So, the variable string would indirectly get assigned a value “Hello!” Note that <resources> tag allocates a string value. file – It is an auto-generated file by aapt (Android Asset Packaging Tool) that contains resource IDs for all the resources of res/ directory. If you create any component in the activity_main.xml file, id for the corresponding component is automatically created in this file. This id can be used in the activity source file to perform any action on the component. If you delete this, it’ll get auto-generated again.

There are various other default files as well, we’ll talk about them later when we discover each.

Understanding improper WebView implementation

If you have no idea what a WebView is please first read this article. This will lay up your basics. Now, this article specifically talks about what code to look for in order to understand if webview implementation is insecure or not. Now, for the purpose of this article, I’ll be using InjuredAndroid.apk developed by Kyle Benac. You can find it here. It would look something like this

In the very first challenge of the application, we’ll see a poor webview implementation. First activity’s source code is:

Here, we can see that a string type variable post is receiving a value from an input field and supplying it to DisplayPostXSS.class using intent. We’ll understand what happens when it reaches the said class from the source code:

Here, we can easily see that the said input is getting parsed as an HTML and being displayed within a webview. Also, JavaScript is enabled. This means only one thing for us researchers. XSS!

After sending in the payload we can see that WebView is able to display the supplied input in an HTMl format like this

Hence, this taught us how we can look for XSS bugs by decompiling the application

HardCoded Secrets

Oftentimes, for ease of access developers would hard code various secret keys, decryption functions and other juicy things within the application and so by reversing the APK we can extract them. For example, if we see FlagOneLoginActivity developer has laid out a little hint at the bottom.

Now, let’s reverse the application using JADX and see what’s hidden under GUI. It can be easily inferred even after obfuscation that submitFlag() method is comparing a user supplied input with a given flag “F1ag_0n3”. Hence, the entire login mechanism is bypassed just by looking for the right class after reversing.

After we input the flag, we see that it was indeed correct.

Secrets in strings.xml file

Oftentimes, developers create a reference string and use that object in Java class whose actual value is stored in strings.xml file. For example, in FlagThreeActivity we can see the developer has laid out a little hint at the bottom.

Now, let’s look at this activity’s code in jadx first. We’ll observe that an object with a gibberish name is being used.

It is quite easily understood that user-supplied input is being compared with a resource that is stored in strings.xml file. Hence, what we’ll do is decompile the package using apktool and then traverse to the directory: /res/values/strings.xml

apktool d InjuredAndroid-1.0.10-release.apk
cd InjuredAndroid-1.0.10-release/res/values
cat strings.xml | grep cmVz

Hence, we have our third flag.

Insecure classes implementation

Just like an object can be referred from strings.xml file, similarly, other classes can also be implemented to perform a specific function with an object, and it’s return value be used. For example, in the FlagFourActivity we see something similar

Now, after observing the code underneath the class we see that return value from a certain g class’ a() method. Now, due to obfuscation the original classes and methods names have been changed.

Pondering over g.a() we’ll see that a base64 encoded value is being decoded and supplied as an input and typecasted in a byte array.

After encoding this, we’ll get this flag.

echo "NF9vdmVyZG9uZV9vbWVsZXRz" > to_decode
cat to_decode | base64 --decode

Insecure decryption method for hard coded values

 Oftentimes, developers implement methods to generate keys and encrypt some information which is either received from a user or to encrypt a secret such as login credentials within the application. For example in FlagSixLoginActivity  we can see that a certain k.a() return value is being compared with a user input.

This gibberish value is a base64 encoded byte array. Now, we are going to inspect k.a() method.

This certainly implies that a is receiving string str, which is getting base64 decoded first and then encrypted using a DES key generated. Reversing this function manually in very difficult, but it is certainly possible if we intercept the () method’s return value when it calculates and supplies the value to FlagSixLoginActivity. Kyle Benac has given a code in his repository to do this with javascript using Frida. Here is the code:

console.log("Script loaded successfully ");
Java.perform(function x() {
console.log("Inside java perform function");
var my_class = Java.use("b3nac.injuredandroid.VGV4dEVuY3J5cHRpb25Ud28");
var string_class = Java.use("java.lang.String");
my_class.decrypt.overload("java.lang.String").implementation = function (x) { //hooking the new function
var my_string = string_class.$new("k3FElEG9lnoWbOateGhj5pX6QsXRNJKh///8Jxi8KXW7iDpk2xRxhQ==");
console.log("Original arg: " + x);
var ret = this.decrypt(my_string);
console.log("Return value: " + ret);
return ret;
Java.choose("b3nac.injuredandroid", {
onMatch: function (instance) {
console.log("Found instance: " + instance);
console.log("Result of secret func: " + instance.decrypt());
onComplete: function () { }

Pretty easy to code this right? No? Then you must follow my previous article on Frida here to understand how to create hooks in a better way.

Insecure cryptography in SQLite database

Oftentimes, juicy information is obtained from an application’s SQLite database. This happens because the developer has stored some values like credentials, keys etc. within the sqlite itself. Let’s look at one such implementation in FlagSevenSqliteActivity

Now, each database has its own SQLite database associated with itself. We simply need to traverse to this database and dump values. Note that having root access is sometimes critical to do this, other times if your user has the permissions you’d be able to have a look at the database.

adb shell
cd /data/data/b3nac.injuredandroid/databases
sqlite3 Thisisatest.db
select * from Thisisatest;

And just like that we have the flag’s hash which is in MD5 and password which is encrypted in some format as well (ROT47). One can decrypt it and is good to go. It is essential for developers not to use old encryption and hashing techniques.

Hardcoded AWS key and access ID

“World is moving to cloud” ~ Google

“But stupidity exists everywhere” ~ Pentesters

Oftentimes developers hard code or create a reference value of AWS bucket credentials. One such example could be seen in FlagEightLoginActivity. Here, the developer has given a little hint at the bottom too.

On exploring the activity’s code we see that this client authenticates with aws.

One of the most common places to look for AWS creds is in the strings.xml file. So we check it:

cd /InjuredAndroid-1.0.10-release/res/values
cat strings.xml | grep AWS

And it worked like a charm.

Now we’ll create a profile of aws and can easily use AWS cli to connect to it. To make profile:

cd ~ && mkdir .aws
cd .aws && nano credentials

Copy the obtained ID and access key in it.


Even after string obfuscation, various classes, objects and strings can be reversed and used to harm an organisation. It is very essential that developers follow strict practices for security given by OWASP MSTG. Thanks for reading.

Author: Harshit Rajpal is an InfoSec researcher and left and right brain thinker. Contact here