# Reverse Engineering Android Apps: A Practical Guide

**Author:** kelexine  
**Date:** 2025-12-06  
**Category:** Security  
**Tags:** Android, Reverse Engineering, Security, APK, Frida  
**URL:** https://kelexine.is-a.dev/blog/reverse-engineering-android

---

# The Art of Taking Apps Apart

Reverse engineering isn't just for hackers—it's for developers who want to understand how things work, security researchers finding vulnerabilities, and curious minds who refuse to treat software as a black box.

## Legal Disclaimer

Before we begin: reverse engineering is legal for security research, interoperability, and personal education in most jurisdictions. However, respect intellectual property and never use these skills maliciously.

## The Toolkit

```bash
# Essential tools
sudo apt install apktool jadx dex2jar

# Frida for dynamic analysis
pip install frida-tools

# ADB for device communication
sudo apt install adb
```

## Step 1: Extracting the APK

```bash
# From a connected device
adb shell pm list packages | grep targetapp
adb shell pm path com.target.app
adb pull /data/app/com.target.app-xxx/base.apk

# Or use APK mirror sites for legal apps
```

## Step 2: Static Analysis with APKTool

APKTool decompiles the APK into readable smali code:

```bash
apktool d app.apk -o output_folder

# Directory structure
output_folder/
├── AndroidManifest.xml   # Permissions, components
├── res/                   # Resources
├── smali/                 # Dalvik bytecode
└── assets/               # Raw files
```

The `AndroidManifest.xml` reveals:
- Requested permissions
- Activities (screens)
- Services (background tasks)
- Broadcast receivers
- Content providers

## Step 3: Decompilation with JADX

JADX converts DEX bytecode back to readable Java:

```bash
jadx app.apk -d output_java

# Or use the GUI
jadx-gui app.apk
```

Now you can read the actual source code:

```java
public class LoginActivity extends AppCompatActivity {
    private void validateLogin(String username, String password) {
        // Check if password matches hardcoded value
        if (password.equals("supersecret123")) {
            startActivity(new Intent(this, MainActivity.class));
        }
    }
}
```

## Step 4: Analyzing Network Traffic

### Setup Charles Proxy / mitmproxy

```bash
# Install mitmproxy
pip install mitmproxy

# Start proxy
mitmproxy --listen-port 8080

# Configure device proxy settings to your IP:8080
# Install mitmproxy CA certificate on device
```

### Bypassing SSL Pinning

Many apps implement certificate pinning. Bypass with Frida:

```javascript
// ssl_bypass.js
Java.perform(function() {
    var TrustManager = Java.use('javax.net.ssl.X509TrustManager');
    var SSLContext = Java.use('javax.net.ssl.SSLContext');
    
    // Custom TrustManager that accepts all certificates
    var TrustManagerImpl = Java.registerClass({
        name: 'com.fake.TrustManager',
        implements: [TrustManager],
        methods: {
            checkClientTrusted: function(chain, authType) {},
            checkServerTrusted: function(chain, authType) {},
            getAcceptedIssuers: function() { return []; }
        }
    });
    
    // Replace SSL context
    SSLContext.init.overload('[Ljavax.net.ssl.KeyManager;', 
                             '[Ljavax.net.ssl.TrustManager;', 
                             'java.security.SecureRandom')
        .implementation = function(km, tm, sr) {
            this.init(km, [TrustManagerImpl.$new()], sr);
        };
});
```

```bash
frida -U -l ssl_bypass.js -f com.target.app
```

## Step 5: Dynamic Analysis with Frida

Frida lets you inject JavaScript into running apps:

```bash
# List running apps
frida-ps -U

# Attach to app
frida -U com.target.app

# Spawn app with script
frida -U -l script.js -f com.target.app
```

### Hooking Methods

```javascript
Java.perform(function() {
    // Hook a specific method
    var LoginClass = Java.use('com.app.LoginActivity');
    
    LoginClass.validatePassword.implementation = function(password) {
        console.log('Password entered: ' + password);
        return this.validatePassword(password);
    };
});
```

### Modifying Return Values

```javascript
Java.perform(function() {
    var LicenseCheck = Java.use('com.app.LicenseManager');
    
    LicenseCheck.isLicensed.implementation = function() {
        console.log('License check bypassed!');
        return true;  // Always return true
    };
});
```

### Dumping Encrypted Data

```javascript
Java.perform(function() {
    var Cipher = Java.use('javax.crypto.Cipher');
    
    Cipher.doFinal.overload('[B').implementation = function(input) {
        var result = this.doFinal(input);
        console.log('Encrypted: ' + bytesToHex(input));
        console.log('Decrypted: ' + bytesToHex(result));
        return result;
    };
});
```

## Step 6: Patching and Repackaging

### Modify Smali Code

```bash
# Decompile
apktool d app.apk

# Edit smali files
# Find the method you want to modify

# Example: Change isLicensed to always return true
.method public isLicensed()Z
    .locals 1
    const/4 v0, 0x1    # Changed from 0x0 to 0x1
    return v0
.end method

# Rebuild
apktool b output_folder -o patched.apk

# Sign the APK
keytool -genkey -v -keystore my.keystore -keyalg RSA -keysize 2048 -validity 10000 -alias mykey
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my.keystore patched.apk mykey

# Install
adb install patched.apk
```

## Common Patterns to Look For

### Hardcoded Secrets
```bash
grep -r "api_key" output_folder/
grep -r "secret" output_folder/
grep -r "password" output_folder/
```

### Root Detection
Apps often check for root:
```java
// Common root checks to bypass
new File("/system/app/Superuser.apk").exists()
new File("/system/xbin/su").exists()
Build.TAGS.contains("test-keys")
```

### Debug Detection
```java
// Anti-debugging checks
android.os.Debug.isDebuggerConnected()
```

## Ethical Considerations

Use these skills responsibly:
- ✅ Security research
- ✅ Understanding how apps work
- ✅ Finding vulnerabilities to report
- ❌ Piracy
- ❌ Stealing user data
- ❌ Malware development

## Conclusion

Reverse engineering is a superpower. It transforms you from a passive user into someone who truly understands the systems they interact with.

Start small. Pick an app you're curious about. Decompile it. Read the code. You'll be amazed at what you find.

---

**Resources**:
- [Frida Handbook](https://learnfrida.info/)
- [OWASP Mobile Testing Guide](https://mas.owasp.org/)
- [Android Security Internals](https://nelenkov.blogspot.com/)

---

*This content is available at [kelexine.is-a.dev/blog/reverse-engineering-android](https://kelexine.is-a.dev/blog/reverse-engineering-android)*
