Asad

ASAD

Bypassing Android Root Detection Using Smali Patching — Part 1

Introduction

💡Most security researchers reach for Frida the moment they see root detection. But very few understand how to bypass it at the bytecode level — without any dynamic tools. This blog is one of those rare guides.

⚠️Disclaimer: This blog is for educational purposes only. All techniques demonstrated here are performed on intentionally vulnerable applications (OWASP UnCrackable Level 1) in a controlled testing environment. Never apply these techniques on apps without proper authorization.

Have you ever installed an app on a rooted Android device and seen this message?

🔔“Root detected! This is unacceptable. The app is now going to exit.”

 

This is called Root Detection — a security mechanism developers use to prevent their app from running on rooted devices. But as a security researcher, understanding how it works and how it can be bypassed is essential knowledge.

In this blog, we will:

  • Understand what root detection is
  • Set up a proper testing environment
  • Analyze the app’s code
  • Bypass root detection using smali code

What is Root Detection?

When you root an Android device, you gain superuser (root) access — similar to admin access on Windows. This allows you to:

  • Modify system files
  • Bypass app restrictions
  • Intercept network traffic

Because of this, many apps (especially banking and payment apps) implement root detection to protect themselves. If they detect a rooted device, they simply refuse to run.

Before we begin — A Note on Smali

Most people treat Smali like a black box — they copy-paste patches from the internet without understanding why it works. But here’s the truth:

If you understand Smali, you don’t need to rely on tools blindly — you become the tool.

Before going further, I strongly recommend clearing your basics:

📖 Dalvik Opcodes Reference — Every instruction explained → http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html

📖 Smali Types, Methods & Fields — Official wiki → https://github.com/JesusFreke/smali/wiki/TypesMethodsAndFields

📖 Smali Cheat Sheet — Quick reference → https://sallam.gitbook.io/sec-88/android-appsec/smali/smali-cheat-sheet

I won’t sugarcoat it — Smali took me 20+ hours to get comfortable with, and I still consider myself a 2or3/10. But that’s okay. You don’t need to master it — you need to understand it well enough to read, analyze and patch. That’s exactly what this blog will help you do.

What is Smali Patching?

Before we dive in, let’s understand the two main approaches to Android app manipulation:

Technique Type How it Works Changes
Frida Dynamic Instrumentation Hooks into the running app at runtime Temporary — lost on restart
Smali Patching Static Patching Modifies the app’s binary directly Permanent — baked into APK

Think of it this way — Frida is like whispering instructions to someone while they’re working. Smali Patching is like rewriting their job description permanently.

Smali is the human-readable form of Android’s Dalvik bytecode. When an Android app is compiled, your Java/Kotlin code gets converted into .dex (Dalvik Executable) files. When you decompile an APK using APKTool, those .dex files are converted back into Smali — which you can read, understand, and most importantly — modify.

In short: Smali Patching = Decompile → Understand → Modify → Recompile

Tools Required

Tool Purpose Download
Android Studio Emulator setup developer.android.com
ADB Android Debug Bridge Comes with Android Studio
APKTool Decompile/Recompile APK github.com/iBotPeaches/Apktool
JADX-GUI Decompile APK to readable Java code github.com/skylot/jadx
Uber APK Signer Sign the patched APK github.com/patrickfav/uber-apk-signer
OWASP UnCrackable L1 Target app github.com/OWASP/owasp-mastg

Target Application

In this blog, we are using OWASP UnCrackable Level 1 — an intentionally vulnerable Android application designed for security testing and research.

Download: github.com/OWASP/owasp-mastg/tree/master/Crackmes/Android/Level_01

 

Walkthrough

Step 1 — First, install the UnCrackable Level 1 APK on your emulator using ADB:

adb install UnCrackable-Level1.apk

 

Step 2 — As soon as you open the application, you will see a popup saying “Root Detected!”

This confirms that the app has successfully detected our rooted emulator and is refusing to run as per its security mechanism.

Step 3 — Now let’s open the APK in JADX-GUI to understand what’s happening behind the scenes.

Open JADX-GUI → Load the APK → Navigate to MainActivity

Inside MainActivity, we find the root detection logic:

java

if (c.a() || c.b() || c.c()) { a("Root detected!"); }

Notice the OR operator (||) — this means if even one of the three conditions returns true, root is detected. All three must return false to bypass it.

Step 4 — Click into class c — here we find three methods responsible for root detection:

  • a() — Checks if su binary exists in PATH
  • b() — Checks if Build.TAGS contains test-keys
  • c() — Checks if common root files exist on the device

Step 5 — Now let’s decompile the APK using APKTool to get access to the Smali code:

Command: apktool d UnCrackable-Level1.apk 

Step 6 — Open the decompiled folder in VS Code and navigate to:

smali → sg → vantagepoint → a → c.smali

This is the same class we analyzed in JADX-GUI — but now in Smali form. You will see all three methods a(), b(), and c() here.

Step 7 — Now the actual patching begins!

Add these 2 lines at the top of each method, right after .locals:

const/4 v0, 0x0 return v0

Understanding the Logic

Method a() returns a boolean value — in Smali, Z represents boolean:

java

public static boolean a() {
    // searches for su binary...
    return true;  // if found
    return false; // if not found
}

In Smali:

  • 0x1 = true
  • 0x0 = false

Breaking Down the Patch

const/4 v0, 0x0   # Load false into register v0
return v0          # Return immediately

const/4 — This is a Smali opcode (instruction). It means “load a constant value into a register”. The /4 refers to the size — it handles 4-bit literal values.

v0 — This is a register. Think of registers like temporary variables that store values during execution. In Smali, registers are named v0, v1, v2 and so on.

0x0 — This is the value being loaded. In hexadecimal, 0x0 = 0 = false in boolean terms.

So the full instruction reads:

“Load the value false into register v0

return v0 — Return whatever is stored in v0 — which is false.

In Simple Words

Smali Java Equivalent
const/4 v0, 0x0 boolean result = false;
return v0 return result;

Before our patch, the method would run through all the root checks and maybe return true. After our patch, it returns false immediately — no checks run at all!

What’s the Effect?

if (c.a() || c.b() || c.c()) {
    a("Root detected!");  // This will NEVER execute!
}

All three methods return false → condition is falseRoot detected dialog never appears!

Save the code (ctrl + s)

Step 8 — Now let’s rebuild the patched APK:

Command: apktool b UnCrackable-Level1 -o UnCrackable-Level1-R.apk

Step 9 — Every Android APK must be signed before installation. We will use Uber APK Signer — an all-in-one tool that handles keytool, jarsigner, and zipalign in a single command:

Command: java -jar uber-apk-signer-1.3.0.jar -a 
"C:\\Users\\MohdAsadAnsari\\Documents\\Android Testing\\Crackable\\UnCrackable-Level1-R.apk”

Uber APK Signer automatically creates a new signed file — UnCrackable-Level1-R-aligned-debugSigned.apk. Always install this new file, not the original!

Step 10 — Before installing the patched version, remove the original:

Command: adb uninstall owasp.mstg.uncrackable1

Step 11 — Install the Patched APK

command: adb install UnCrackable-Level1-R-aligned-debugSigned.apk

Open the app — no root detection dialog! The app launches normally on our rooted emulator.

We have successfully bypassed the root detection mechanism using Smali Early Return Patching!

Key Takeaways

  • Smali is powerful — you don’t need to be a Frida expert to bypass security mechanisms. Understanding bytecode gives you direct control over app behavior.
  • Root detection is not foolproof — with just 2 lines of Smali code, we completely disabled all three root checks.
  • Early Return is the simplest technique — force the method to return false before any check even runs.
  • APKTool + Uber APK Signer is a powerful combo — decompile, patch, recompile and sign in minutes.

For Developers — How to Make Root Detection Stronger

If you are a developer reading this, here’s what you should know:

Root detection alone is never enough. A determined attacker can always patch your Smali code. Consider layering your security:

  • Combine multiple checks — don’t rely on just su binary detection
  • Use Native (C/C++) code for root checks — Smali patching won’t work on native libraries
  • Implement integrity checks — detect if your APK has been tampered with
  • Use runtime verification — verify app signature at runtime
  • Consider using Google Play Integrity API — much harder to bypass than manual checks

What’s Next?

This was Technique 1 — Early Return. We used 2 lines of Smali code to completely disable root detection.

In the next blog, we will achieve the exact same result with just 1 line change using the Jump Redirect technique — a cleaner and more surgical approach to Smali patching.

Stay tuned! 🔐

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top