How to hack an Android app: Fixing Annoying Email Validation

TL;DR

An Android app login page considered my email address invalid because it limited domain extensions up to four characters — mine has five (.email). Instead of creating a new email, I patched the APK by modifying the validation regex. Here’s how I did it.

Full Story

The problem

My email address is a bit different from most people. It doesn’t end with .com, .org or .fr, but .email. Why? Because I always feel the need to play the digital game in hard mode: using Linux, self-hosting my email server, even using an open-source self-hosted Netflix-like streaming service. I can’t help it. Usually it’s manageable, but sometimes, it requires a bit of work.

I recently subscribed to a service, and once on the login screen of the Android app I realized: my email address I used to create my account was now considered invalid. I quickly understood that the app enables the “log in” button only when the email address domain extension contains between two and four characters. .com? 3, fine. .cool? 4, okay. .email? 5, “wrong”.

It’s quite frustrating that email validation is still sometimes so arbitrary. Why only four characters? Why not three, or five, or even better, check against a list of actual domain extensions? I’m sure there are libraries for that. I know, I’m nitpicking, because most people have emails from Gmail, Microsoft or Outlook anyway, and only nerds like me always end up complicating things for “fun”.

So I contacted the tech support (btw sending an email with my “invalid” address…), politely pointing out the issue. Their solution wasn’t appealing: “Ask the marketing team to delete your account and to create a new one with a valid email.” Create a whole new email just for one app? I had a more entertaining idea.

The hack idea

I suspected the email validation system to be purely front-end — probably a regex that checks if the email domain extension is 2, 3, or 4 characters — and that the back-end would accept my email.

What if I perform a man-in-the-middle attack by intercepting the request sent by my phone, change the email, and send it to the server? Long story short: it doesn’t work that easily, because altering an HTTPS request is not that simple to do — thankfully — clients and servers use a mutually trusted certificate authority to encrypt requests.

I tried a different approach: what if I manage to access the source code of the app, find where the email validation is performed, and change it?

Here is the idea:

Spoiler alert: it worked! Here is how to do it.

Step-by-Step Instructions

1. Setup Tools

Install ADB (Android Debug Bridge):

For example on Fedora:

sudo dnf install android-tools

Install Android command-line tools:

Download or grab the link for the latest version here: https://developer.android.com/studio.
Download only the command line tools, not the Android Studio app.

# Download it
wget https://dl.google.com/android/repository/commandlinetools-linux-13114758_latest.zip

# Unzip it to the home directory
unzip commandlinetools-linux-*.zip -d $HOME/Android/Sdk/cmdline-tools

# Install the SDK Platform Tools
yes | $HOME/Android/Sdk/cmdline-tools/cmdline-tools/bin/sdkmanager --sdk_root=$HOME/Android/Sdk "platform-tools" "build-tools;34.0.0"

# Put Android paths to bashrc
echo 'export ANDROID_HOME=$HOME/Android/Sdk' >> ~/.bashrc

echo 'export PATH=$PATH:$ANDROID_HOME/platform-tools:$ANDROID_HOME/build-tools/34.0.0' >> ~/.bashrc

source ~/.bashrc
        

Install apktool:

Follow instructions here: https://apktool.org/docs/install/.

2. Extract and Decompile APK

On Android:

On the PC:

We will assume from now on that the Android app package name is com.my.app.

# Check that the phone is recognized by ADB
adb devices

# Create a working directory
mkdir patchedAPK
cd patchedAPK

# Find where the APK files are installed on the phone
adb shell pm path com.my.app

# Extract all files
for path in $(adb shell pm path com.my.app | cut -d: -f2);
    do adb pull "$path";
done

# Decompile the APK
apktool d base.apk -o src
        

We now have some sort of source code. Actually it’s not Java or Kotlin, but Smali, which is the human-readable assembly language for the instruction set that Android really executes. It means we don’t have exactly what the devs coded, but it’s enough to explore how the app is made, change it, and recompile it afterwards.

3. Patching time

Find the regex:

Let’s find the problematic regex limiting domain extensions. I supposed it’s something that checks if the end of a string contains between two and four letters, which is what I noticed when trying different emails on the login screen. There are many ways to write a regex for that, but what seems certain is “between 2 and 4”, which translate in regex to {2,4}. Let’s search the source code for that:

grep -R --line-number '{2,4}' src | head

It should return every file with line numbers that contain those characters. In my case I was lucky, 5 unreadable binary files, and only one file with a ridiculously long regex.

Patch the regex:

Change {2,4} to {2,5} to fix the validation issue. It’s that simple.

4. Rebuild the APK

We will now rebuild and sign the app. For a real-life production app, it would require more work, like Google Play Protect and Play Store compatibility, align the files (using zipalign) and use a proper signing key. Here I only do the bare minimum for the app to run on my device.

Recompile the APK:

apktool b src -o unsigned_base.apk

Generate a simple signing key:

keytool -genkeypair -alias mykey -keyalg RSA -keysize 2048 -validity 10000 -keystore mydebug.keystore -storepass changeit -keypass changeit -dname "CN=PixelTest,O=Dev,C=CH"

Sign all files:

for f in *.apk;
    do apksigner sign --ks mydebug.keystore --ks-pass pass:changeit --key-pass pass:changeit --ks-key-alias mykey --out signed_"$f" "$f"
done
        

5. Install the Patched APK

Remove the original app and install the patched version:

# Remove the original app
adb uninstall com.my.app

# Install the patched version
adb install signed_base.apk
        

And voila! Now the app accepts email domain extensions with up to 5 characters and I can log in.

Because the signing key is different than the original one, automatic app updates are broken. So every new version requires repeating the patch, but it’s definitely more enjoyable to me than creating a new email address. Told you, I can’t help it…

Happy patching!