UPDATE (20-Mar-2022): MagiskHide has been dropped from Magisk 24.3. Checkout my blog post on comparing root detection for 24 banking apps where I also use Frida to spawn apps.

For mobile app analysis, using a rooted device with Magisk and Frida has become my bread and butter. I’m aware that emulators exist (which I also use) but solutions, such as Android Studio or Genymotion fail to offer the same level of performance as a physical device. I use a second-hand Google Pixel 3a bought on Amazon for most of my testing.

Magisk

Magisk is a suite of open source software for customizing Android devices. It provides users the ability to execute system commands on production devices and even extend features through modules. Magisk also provides a neat feature called MagiskHide, which hides certain root artifacts from detection methods used by apps.

Frida

Frida is a dynamic code instrumentation toolkit that allows you inject JavaScript code into native apps on Windows, macOS, GNU/Linux, iOS and Android. I use Frida mostly for bypassing Certificate Pinning and hooking into interesting functions - read my post on how I discovered a EV provider leaking 140k customers’ data.

MagiskHide and Frida works together fine if you only want to attach to an already running process. There are three ways (I am not covering patched APKs):

  • Attach by the process ID e.g. frida -U -l hook.js -p <PID>
  • Attach by the process name e.g. frida -U -l hook.js -n 'app name'
  • Attach by unique app name e.g. frida -U -l hook.js com.example.app

Problem

When MagiskHide is enabled, it is not possible to spawn or launch a process using Frida (with the -f option). You will get the following error when you try to run frida -U -l hook.js -f com.example.app --no-pause:

Failed to spawn: unable to access zygote while preparing for app launch; try disabling Magisk Hide in case it is active

Why?

The short answer is both Frida and Magisk require Zygote module to spawn processes.

For people wondering why this is needed, Magisk Hide ptraces the zygote module in order to intercept calls, which locks out other apps from doing so, and zygote is needed by Frida to spawn apps and do early hooking. – gmlime on Stackoverflow

Solution(s)

More of workarounds.

Disable MagiskHide

The obvious one is to temporarily disable MagiskHide. You can quickly disable it through the command-line using adb. Run adb shell "su -c magiskhide disable" (note: using su -c because adb shell root does not work on production builds).

Run a Script

Another way is to create a script to automatically start an app using built-in Android utilities, then quickly attach to that process with Frida. This method is not fool proof but does provide decent results. You can use utilities like adb shell am start or adb shell monkey to spawn a process.

I personally like to use the latter because you don’t need to specify an Activity Name, only the app itself. Below is a simple script I wrote which spawns an app using monkey, gets the PID of the process, and then finally attaches to it using the local Frida client:

#!/bin/bash

run_proc=$(adb shell monkey -p $1 1)
get_pid=$(adb shell ps | grep -i $1 | awk '{printf $2}')

if [[ -z "$get_pid" ]];
then
    echo "Didn't find PID :("
else
    echo "Attaching to process.."
    frida -U -l $2 -p $get_pid
fi

Here is an example of the script launching Adidas’s Confirmed app:

alt text

To use this script you need the following:

  • A Frida-server running on the mobile device
  • A Frida client on your local machine
  • A device connected via USB
  • A hook.js file to load

Resources

There were a few users on Github also experiencing the same issue here and here. Somebody suggest to temporarily disable MagiskHide, spawn an app using Frida and re-enable it again. However, this didn’t work for me and caused my device to crash and reboot.