Skip to content

#HITB2023HKT D2T2 - Take A Picture Of Your App Code: Android MRI Interpreter

SungHyoun Song

MobileHack In The Box Security Conference52 minAdvancedOpen on YouTube ↗

SungHyoun Song examines #HITB2023HKT D2T2 - Take A Picture Of Your App Code: Android MRI Interpreter.

Summary

### Overview In this presentation, San, a mobile security researcher at the Financial Security Institute (FSI) in South Korea, introduces the "Android MRI Interpreter"—a customized runtime and kernel-level analysis environment designed to inspect Android application execution and bypass Runtime Application Self-Protection (RASP) mechanisms without patching app binaries or using detectable user-space hooking tools.

Drawing an analogy to medical imaging, the speaker compares traditional penetration testing tools (like ptrace, Frida, and IDA Pro) to invasive surgery with a scalpel, which triggers application defense mechanisms and requires significant time to bypass. In contrast, the Android MRI Interpreter functions like an MRI scanner, observing internal behavior non-invasively at the operating system and interpreter level.

### Key Topics - **ART Execution Flow Modification**: Android applications mix Dalvik bytecode, ahead-of-time (AOT) compiled native code, and just-in-time (JIT) compiled code across cold, warm, and hot execution states. Because optimized native code is difficult to reverse-engineer dynamically, the speaker modified the Android Runtime (ART) code flow so that native execution requests are bypassed, forcing all execution through a custom interpreter. - **Interpreter-Level Inspection**: By replacing standard ART interpreters (the switch interpreter and mterp) with the custom MRI interpreter, the system directly inspects Dalvik instructions, methods, program counters, and virtual register values stored in ART's `ShadowFrame` and `ManagedStack` objects without alerting user-space anti-tamper protections. - **Taint Analysis and Call Graph Generation**: The interpreter traces target data (such as sensitive strings) across data manipulation and transfer instructions (e.g., `move`). By traversing historical frames on the managed stack, it reconstructs execution call graphs displaying where sensitive data originates (highlighted in red) and where it is subsequently propagated or used (highlighted in green), filtering out duplicate calls and dead code. - **Stealthy RASP & Integrity Bypass**: To bypass anti-rooting checks, Google SafetyNet, and commercial RASP modules, changes were kept inside a custom kernel rather than modifying standard user-space Android Open Source Project (AOSP) frameworks. The kernel intercepts `/proc/cmdline` to report clean boot state parameters (`verifiedbootstate=green` instead of orange caused by OEM unlocking). A minimalist privilege escalation mechanism was also embedded directly into the kernel's `sys_execve` handler: invoking the standard, unmodified `/system/bin/sh` binary automatically assigns root credentials (`uid 0`, `gid 0`) without installing detectable user-space root binaries.

### Technical Details & Demonstration To showcase the tool's effectiveness, the speaker analyzed a widely used messaging application ("watch"), focusing on its two-step verification PIN handling. After configuring the target application's UID and the test PIN string in a configuration file (`/data/local/tmp` via BusyBox): - **Instruction and Register Logging**: Real-time logging captured the function names, Dalvik instructions, and virtual registers when the six-digit PIN was processed. - **Call Graph Inspection**: Mode 3 graph generation traced the PIN's lifecycle across app restarts, discovering that the PIN was persistently stored and decrypted via Android default decryption functions from `SharedPreferences` upon each app launch. - **Target Function Tracing**: Using the identified method name, the tool focused execution tracing on specific internal functions, proving unnecessary memory exposure of the credential without triggering the messenger's rooted environment restrictions.

### Takeaways Instrumenting the runtime interpreter and performing stealthy kernel patches provides deep dynamic visibility while completely evading user-space RASP defenses. When asked how developers can protect sensitive credentials from this level of memory tracing, the speaker recommended avoiding immutable string objects (which persist in memory) in favor of byte arrays or raw pointers that can be explicitly wiped or overwritten immediately after use.

Related talks