Back to lab
Tutorial Android 12 min

Frida on Android: Dynamic Instrumentation, Bypass and APK Repackaging

May 26, 2026

What is Frida

Frida is a dynamic instrumentation framework that injects a JavaScript agent into running processes. In the context of Android pentesting, it allows you to intercept method calls, modify return values and bypass protections at runtime — without requiring the app's source code.


Lab environment

Requirements:

  • Rooted Android device (physical or emulator such as Genymotion/rooted AVD)
  • adb installed and device connected
  • Python 3 for the Frida server
# Install Frida CLI and tools
pip install frida-tools

# Verify version
frida --version

Download frida-server to the device:

# Discover device architecture
adb shell getprop ro.product.cpu.abi
# Example output: arm64-v8a

# Download the matching frida-server at:
# https://github.com/frida/frida/releases
# Ex: frida-server-16.x.x-android-arm64

# Push to device
adb push frida-server /data/local/tmp/
adb shell chmod 755 /data/local/tmp/frida-server

# Start server (in background)
adb shell /data/local/tmp/frida-server &

Basic Java method hooking

Base structure of a Frida script:

Java.perform(() => {
  const TargetClass = Java.use('com.example.app.MyClass')

  TargetClass.targetMethod.implementation = function (param) {
    console.log('[*] targetMethod called with:', param)
    const result = this.targetMethod(param) // call original
    console.log('[*] original return:', result)
    return result // or return modified value
  }
})

Running the script:

frida -U -f com.example.app -l my_script.js --no-pause

| Flag | Meaning | |------|---------| | -U | Connect via USB | | -f | Spawn the app (cold start) | | -l | Script to load | | --no-pause | Do not pause on startup |


SSL Pinning Bypass

SSL Pinning is implemented in different ways. Below are the most common bypasses:

OkHttp / CertificatePinner

Java.perform(() => {
  const CertificatePinner = Java.use('okhttp3.CertificatePinner')

  CertificatePinner.check.overload('java.lang.String', 'java.util.List')
    .implementation = function (hostname, peerCertificates) {
      console.log('[*] SSL Pinning bypassed for:', hostname)
      // Does not call original — removes validation
    }
})

Custom TrustManager

Java.perform(() => {
  const X509TrustManager = Java.use('javax.net.ssl.X509TrustManager')
  const SSLContext = Java.use('javax.net.ssl.SSLContext')

  const TrustManagerImpl = Java.registerClass({
    name: 'com.frida.TrustManager',
    implements: [X509TrustManager],
    methods: {
      checkClientTrusted(chain, authType) {},
      checkServerTrusted(chain, authType) {},
      getAcceptedIssuers() { return [] },
    },
  })

  const ctx = SSLContext.getInstance('TLS')
  ctx.init(null, [TrustManagerImpl.$new()], null)
  SSLContext.setDefault(ctx)
  console.log('[*] TrustManager replaced')
})

Tip: The universal script ssl-pinning-bypass from frida-codeshare covers most cases with one line.


Root Detection Bypass

Java.perform(() => {
  // RootBeer
  try {
    const RootBeer = Java.use('com.scottyab.rootbeer.RootBeer')
    RootBeer.isRooted.implementation = function () {
      console.log('[*] RootBeer.isRooted bypassed')
      return false
    }
  } catch (_) {}

  // Check via Runtime.exec
  const Runtime = Java.use('java.lang.Runtime')
  Runtime.exec.overload('java.lang.String').implementation = function (cmd) {
    if (cmd.indexOf('su') !== -1) {
      console.log('[*] Blocking execution of:', cmd)
      return null
    }
    return this.exec(cmd)
  }
})

APK Unpacking and Repackaging with APKTool

APKTool decompiles the APK into smali (readable bytecode) and resources.

Installation

wget https://raw.githubusercontent.com/iBotPeaches/Apktool/master/scripts/linux/apktool
wget https://bitbucket.org/iBotPeaches/apktool/downloads/apktool_2.x.x.jar
chmod +x apktool
sudo mv apktool apktool_2.x.x.jar /usr/local/bin/

Unpack, modify and repackage

apktool d app.apk -o app_decompiled/

# After changes:
apktool b app_decompiled/ -o app_modified.apk

keytool -genkey -v -keystore my_key.keystore -alias alias_name \
        -keyalg RSA -keysize 2048 -validity 10000

jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA-256 \
          -keystore my_key.keystore app_modified.apk alias_name

adb install app_modified.apk

Warning: Apps with Play Integrity or SafetyNet detect non-original APKs. Use Frida without modifying the APK in those cases.


References

Frida on Android: Dynamic Instrumentation, Bypass and APK Repackaging — APCosta Lab — APCosta