Papers
Topics
Authors
Recent
Search
2000 character limit reached

Android Minimal PEMS Overview

Updated 17 April 2026
  • Android-based Minimal PEMS is a static, user-mode mechanism that intercepts and restricts blacklisted system API calls in APKs using Dalvik bytecode instrumentation.
  • It employs a pipeline that unpacks APKs, extracts and merges dex files, generates method stubs for sensitive API calls, and repackages applications for non-rooted devices.
  • The approach offers a transparent, low-overhead API filtering solution while facing limitations with reflective calls, JNI, and multi-dex applications.

An Android-based minimal PEMS (Policy Enforcement/Permission-Filtering Mechanism) is a static, user-mode approach for intercepting and restricting blacklisted Android system API calls within application packages (APKs). Based entirely on static Dalvik VM bytecode instrumentation, as specified and proven in the implementation by Minibaev (2017), this technique modifies application bytecode to redirect invocations of sensitive methods (e.g., device identifiers) to developer-injected stubs that return safe defaults. Notably, this method requires no root access or device firmware changes, enabling distribution via standard channels such as the Play Market and operation across unmodified, non-rooted Android devices (Minibaev, 2017).

1. Pipeline Overview: Static Instrumentation Architecture

The pipeline for this minimal Android PEMS operates at the application package level, taking as input a signed APK and producing a re-signed, bytecode-patched APK in which blacklisted API calls are redirected. The core process consists of the following steps (Minibaev, 2017):

  1. APK Unpacking: Decompress the APK to expose Dalvik executable components and other resources.
  2. DEX Extraction: Isolate classes.dex as the principal bytecode payload.
  3. Stub Generation: For each blacklisted method, generate a stub method using Android's dx tool or equivalent (DexBuilder). Each stub mirrors the method's signature and returns a predetermined safe value (null, 0, empty string), packaged in stub.dex.
  4. DEX Merging: Merge the application's original and stub dex files into merged.dex using dx --dex.
  5. Patch Invoke Instructions: Scan merged.dex for all method invocation opcodes (invoke-xxx). Overwrite method indices for blacklisted calls with the corresponding stub method indices.
  6. APK Reassembly: Replace the original dex in the decompressed APK with the patched one, repackage, zipalign, and re-sign the APK using apksigner.

This process may be encapsulated within scripts (e.g., instrument.sh) or integrated into CI tools such as Gradle.

2. Formal Algorithm: Locate-and-Rewrite Semantics

The algorithmic foundation involves manipulating the dalvik method reference tables and replacing invocation targets mathematically as follows (Minibaev, 2017):

Let D0D₀ be the original dex’s method_ids table. Let SS denote the set of blacklisted signatures (e.g., s1=s₁ = Landroid/telephony/TelephonyManager;.getDeviceId:()Ljava/lang/String;). Stub methods are defined in D1D₁, all in a non-colliding package (e.g., Lru/innopolis/Stub;).

For each sSs \in S:

  • orig_idx[s]\mathrm{orig\_idx}[s] is the original dex method index.
  • stub_idx[s]\mathrm{stub\_idx}[s] is the stub method index in the merged dex.

Rewriting scans for opcodes in INVOKE_OPCODES={0x6e0x72,0x740x77}\mathrm{INVOKE\_OPCODES} = \{0x6e–0x72, 0x74–0x77\} and substitutes method_idxstub_idx[s]\mathrm{method\_idx} \leftarrow \mathrm{stub\_idx}[s] if the original matches any sSs \in S. The fixed-length encoding of invoke instructions (6 bytes) precludes any issues with alignment or control-flow reanalysis.

No control or data-flow analysis is required; direct matching suffices, substantially improving implementability and reliability on arbitrary APKs.

3. Bytecode Modification: Stub Structure and Replacement Pattern

Stub classes are generated to match the method descriptors of blacklisted invocations. For example, to intercept TelephonyManager.getDeviceId(), a stub is compiled as:

SS0

At the original call site, bytecode such as:

SS1

is replaced by:

SS2

Stubs precisely mirror parameter and return signatures (including register usage) to maintain call-site compatibility. This approach ensures that program logic and stack integrity are preserved, and runtime behavior is minimally perturbed except for the blocking of the sensitive call (Minibaev, 2017).

4. Constraints, Applicability, and Limitations

The static instrumentation approach is purposefully minimalist and rootless, but is subject to several constraints (Minibaev, 2017):

  • Reflection Limitations: Bytecode-based invocation redirection does not intercept calls performed via Java reflection (Class.forName(), getMethod(), invoke()), leaving dynamic invocations unfiltered.
  • JNI and Native Escapes: Native method invocations via JNI are beyond Dalvik instrumentation scope.
  • Multi-DEX Handling: For applications employing multiple classesN.dex files, instrumentation must be repetitively applied to all such components.
  • Obfuscation: Code obfuscation that renames or hides API accesses behind reflection can evade instrumentation.
  • Runtime Format Compatibility: The approach is confined to Dalvik .dex format only; AOT-compiled ART/OAT files are unsupported.
  • Stub Naming: The injected stub class package (e.g., ru.innopolis.Stub) must be selected to avoid collisions with extant app classes.

This suggests that effective deployment at scale or in adversarial application environments may require supplementary static and dynamic analysis.

5. Performance Characteristics

The technique imposes minimal instrumentation and runtime overheads (Minibaev, 2017):

  • Instrument Time: Merging dex files with dx is the dominant factor (200–400 ms on typical desktops).
  • APK Size: The increase is generally the additive size of stub.dex (typically <2 KB per stub).
  • Runtime Overhead: The indirection through a 6-byte invoke-static instruction is negligible, and no startup or JIT realignment penalties occur.
  • No Control-Flow Side Effects: As instructions remain length-stable, there is no impact on control transfer or verifier semantics.

A plausible implication is that the method is practically transparent during application execution, maintaining user experience and app compatibility except for the blocked sensitive operations.

6. Practical Integration and Reference Procedures

Deployment requires only standard Android tooling and a list of blacklisted method signatures (e.g., generated from datasets such as PScout). Integration steps, as specified, involve generating stubs (Java pseudocode provided in the source), patching method references (Java pseudocode with DexReader and DexBuilder), and a script (e.g., instrument.sh) to automate the sequence.

Example shell script invocation permits patching and repacking of any arbitrary APK for non-rooted device deployment. Blacklisted APIs invoked by the patched app are non-disruptively rerouted to return safe defaults.

Tool Prerequisites:

Tool Purpose Typical Usage
dx (Android SDK) DEX merging/generation Merge dex + stubs
zipalign Alignment for APK Prepare for signing
apksigner APK signing Required for install

The capability to wrap the process into CI and build pipelines allows for programmatic enforcement of API access policies across Android apps at distribution time (Minibaev, 2017).


See "Static Dalvik VM bytecode instrumentation" (Minibaev, 2017) for detailed implementation and specification.

Definition Search Book Streamline Icon: https://streamlinehq.com
References (1)

Topic to Video (Beta)

No one has generated a video about this topic yet.

Whiteboard

No one has generated a whiteboard explanation for this topic yet.

Follow Topic

Get notified by email when new papers are published related to Android-based Minimal PEMS.