Promon SHIELD¶
Promon SHIELD is a commercial RASP (Runtime Application Self-Protection) solution developed by Promon (Oslo, Norway). Unlike traditional packers that encrypt DEX bytecode, SHIELD focuses on runtime integrity checks, environment detection, and anti-tampering. It is the dominant mobile app protection solution in European banking, reportedly used by over 50% of leading European financial institutions.
Vendor Information¶
| Attribute | Details |
|---|---|
| Developer | Promon AS |
| Origin | Oslo, Norway |
| Type | Commercial RASP / Application Shielding |
| Platforms | Android, iOS, Desktop (Windows, macOS) |
| Products | SHIELD for Mobile, SHIELD for Desktop, SDK Protection, IP Protection Pro |
| Founded | 2006 |
RASP vs Packer¶
Promon SHIELD operates fundamentally differently from packers like DexGuard or Virbox.
| Aspect | RASP (Promon SHIELD) | Packer (DexGuard, Virbox) |
|---|---|---|
| Primary function | Runtime environment monitoring | Code transformation and encryption |
| DEX encryption | No | Yes |
| String encryption | No (externalizes to native layer) | Yes (inline decryption methods) |
| Code virtualization | No | Yes (Virbox), optional (DexGuard) |
| Anti-debugging | Core feature | Secondary feature |
| Root/hook detection | Core feature | Secondary feature |
| Overlay protection | Yes | No |
| Screen capture blocking | Yes | No |
| Integration model | Injected native library + config | Build-time transformation |
SHIELD wraps an application by injecting a native library that loads before anything else in the process. The library performs all checks at the native level, making Java-layer bypasses insufficient. The app's own code remains largely unmodified -- the protection is external rather than woven into the bytecode.
Identification¶
APKiD Detection¶
APKiD detects Promon SHIELD through ELF segment analysis of native libraries:
Detection is segment-based rather than filename-based, since library names are randomized in newer versions.
File Artifacts¶
| Artifact | Description |
|---|---|
| Native library | Randomized name (e.g., libenhefoocjfcl.so, libniiblkgocjbb.so). Legacy versions used libshield.so or libshield.XXXXXXXX.so |
| Config file | config-encrypt.txt in assets -- encrypted configuration consumed by the native library |
| Mapping file | pbi.bin in assets -- encrypted mapping data |
| Architecture | Typically arm64-v8a, may include armeabi-v7a and x86 |
| Library size | Noticeably large compared to typical app native libraries |
Java-Side Indicators¶
Promon SHIELD externalizes strings and class initialization to native methods. A bridge class (obfuscated name, e.g., C6539Z) exposes two native methods:
The first retrieves strings by index from the native layer. The second initializes classes by ID. The library name itself is XOR-encrypted before being passed to System.loadLibrary().
If decompiled code shows string retrieval through indexed native calls rather than inline string literals or Java-based decryption methods, it is likely Promon SHIELD.
Distinguishing from Other Protectors¶
- No DEX encryption: classes.dex is readable in JADX (strings are missing, but structure is intact)
- No
o/oo/ooodecryption classes: unlike DexGuard, there are no Java string decryption stubs - Single large native library: unlike Chinese packers that have recognizable library names (
libjiagu.so,libshella.so) - OLLVM-obfuscated native code: the native library uses Obfuscator-LLVM with control flow flattening
Protection Mechanisms¶
Native Library Lifecycle¶
.init_arrayconstructor executes beforeJNI_OnLoad- Constructor unpacks the encrypted
.textsection and resolves imports dynamically viadlsym()and direct syscalls (SVC 0) - Configuration is decrypted from
config-encrypt.txt - Environment checks begin immediately
- If checks pass, the app's original code proceeds normally
Anti-Debugging¶
Process isolation via ptrace lock:
fork()creates a child process- Parent calls
prctl(PR_SET_PTRACER)to restrict tracing to the child only - Child attaches to parent via
ptrace(PTRACE_ATTACH) prctl(PR_SET_DUMPABLE, false)blocks external debuggers
This prevents any other process from attaching a debugger to the protected app. The child process acts as a watchdog.
JDWP disablement:
Patches art::JDWP::JdwpState::HandlePacket() at the ART runtime level to kill Java debugging entirely. This goes beyond checking ro.debuggable -- it neutralizes the debug protocol handler in-process.
Root Detection¶
Checks over 20 system properties and file paths:
| Category | Examples |
|---|---|
| System properties | ro.debuggable, ro.secure, persist.sys.root_access, service.adb.root |
| Su binaries | /system/xbin/su, /system/bin/su, /sbin/su |
| Magisk artifacts | /data/adb/magisk/magisk, /data/data/com.topjohnwu.magisk |
| SuperSU artifacts | /init.supersu.rc, SuperSU package paths |
| Other root tools | Kingroot paths, root management app packages |
Directory watches via inotify_add_watch() monitor /bin, /system/bin, /system/xbin, and /vendor/bin for changes -- detecting root tools installed after the app starts.
Hooking Framework Detection¶
| Framework | Detection Method |
|---|---|
| Frida | Scans /proc/self/maps for libFridaGadget.so, checks memory page integrity |
| Xposed | Looks for libxposed_art.so in memory, checks for art::mirror::ArtMethod::EnableXposedHook() export symbol |
| Cydia Substrate | Scans for libsubstrate.so and libsubstrate-dvm.so in loaded libraries |
| Memory patching | Validates memory page contents -- modifications trigger process termination |
Emulator Detection¶
Checks system properties that leak virtual hardware:
ro.kernel.qemu(QEMU-based emulators)ro.hardware(goldfish, ranchu)- Device manufacturer, model, and hardware strings
- ChromeOS and virtual machine indicators
- Telephony state anomalies
- Hardware sensor availability
Repackaging Detection¶
- Opens the installed
base.apkdirectly viaopenat()syscall (bypasses Java file APIs) - Parses the APK signing block to extract signing certificates
- Compares against expected certificate embedded in the native library
- Verifies
libshield.sochecksum before proceeding with other checks
The syscall-based file access makes it harder to intercept with standard Java hooks.
Overlay Detection¶
Detects if another application draws over the protected app's window. Prevents tapjacking and phishing overlays that attempt to capture user input. The app can block interaction, alert the user, or terminate when an overlay is detected.
Screen Capture Prevention¶
Blocks screenshots, screen recordings, and screen mirroring of the protected app. Uses FLAG_SECURE and additional native-level enforcement to prevent data leakage through screen capture.
Dynamic Imports and Syscalls¶
The native library avoids standard libc imports for security-critical operations. Functions resolved at runtime via dlsym() or invoked through direct SVC 0 syscalls include:
ptrace, prctl, fork, execl, __system_property_get,
dlopen, dladdr, inotify_init, inotify_add_watch,
eventfd, dl_iterate_phdr, openat, read, write, mmap
Direct syscalls bypass any LD_PRELOAD or linker-level hooking.
Native Code Obfuscation¶
The SHIELD library itself is protected with:
- OLLVM control flow flattening: function CFGs are destroyed and replaced with dispatcher-based execution
- Packed .text section: encrypted at rest, unpacked by
.init_arrayconstructor at load time - No readable string table: strings resolved dynamically
- Stripped symbols: no exported function names beyond JNI entry points
Unpacking Methodology¶
Frida-Based String Index Enumeration¶
Since SHIELD externalizes all strings to native methods accessed by index, you can brute-force the index space to reconstruct the string table:
Java.perform(function() {
var bridge = Java.use("com.target.app.C6539Z");
for (var i = 0; i < 5000; i++) {
try {
var s = bridge.m1788a(i);
if (s !== null && s.length > 0) {
console.log("idx " + i + " -> " + s);
}
} catch(e) {}
}
});
The bridge class name and method name will differ per app -- locate them by searching for classes with native methods that take a single int parameter and return String.
Bypassing ptrace Lock¶
The fork-and-attach pattern can be defeated by:
- Patching the native library: NOP out the
fork()andptrace()calls in the unpacked.textsection - Early Frida injection: attach Frida before the native library's
.init_arrayruns by spawning withfrida -fand hookingandroid_dlopen_extto intercept the library load - Hooking
fork(): return 0 (pretend to be the child) or -1 (pretend fork failed) to prevent the watchdog process from starting
Bypassing Root Detection¶
Java.perform(function() {
var Runtime = Java.use("java.lang.Runtime");
Runtime.exec.overload("java.lang.String").implementation = function(cmd) {
if (cmd.indexOf("su") !== -1 || cmd.indexOf("which") !== -1) {
throw Java.use("java.io.IOException").$new("not found");
}
return this.exec(cmd);
};
});
For native-level checks, intercept __system_property_get via Interceptor.attach:
var prop_get = Module.findExportByName(null, "__system_property_get");
Interceptor.attach(prop_get, {
onEnter: function(args) {
this.name = args[0].readUtf8String();
},
onLeave: function(retval) {
if (this.name === "ro.debuggable" || this.name === "ro.secure") {
args[1].writeUtf8String("0");
}
}
});
Bypassing Repackaging Detection¶
The promon-reversal project demonstrates that APK signature verification can be bypassed by:
- Extracting the original signing certificate from the native library's embedded data
- Hooking the certificate comparison at the native level
- Returning the expected certificate when SHIELD performs its check
Native Library Patching¶
For persistent bypass (lab environment):
1. Extract the APK
2. Identify the SHIELD library (randomized name, largest .so in lib/)
3. Load in Ghidra/IDA -> locate .init_array entry point
4. Trace from init_array through the unpacking routine
5. Dump the unpacked .text section at runtime
6. Patch detection routines (NOP out fork/ptrace/property checks)
7. Replace the library, resign the APK
8. Install with signature verification bypass (Frida hook or debug certificate)
This approach requires re-bypassing the repackaging check since the modified library will fail its own integrity verification.
Magisk-Based Approach¶
MagiskHide (deprecated) or Shamiko/Zygisk-based hiding can prevent SHIELD from seeing root artifacts in the filesystem and process list. Combined with a Frida server renamed and running on a non-default port, this avoids the most common detection vectors.
Banking App Context¶
Promon SHIELD is the primary protection for European banking and financial apps. During mobile penetration tests of banking applications, SHIELD is the most frequently encountered defense layer.
Key considerations for pentesters:
| Aspect | Detail |
|---|---|
| Prevalence | Over 50% of top European banks reportedly use Promon SHIELD |
| Typical deployment | Combined with certificate pinning, obfuscation (often R8/ProGuard), and server-side fraud detection |
| Response behavior | Configurable per customer -- may silently report, block functionality, or force-close the app |
| Multi-layered | Banks often stack SHIELD with DexGuard or proprietary obfuscation |
| Server reporting | Detection events may be reported server-side, potentially flagging the tester's device or account |
When assessing a SHIELD-protected banking app, disable telemetry reporting hooks early to avoid triggering server-side fraud alerts during testing.
Comparison with Other Protectors¶
| Feature | Promon SHIELD | DexGuard | Virbox | Chinese Packers |
|---|---|---|---|---|
| Primary approach | RASP (runtime checks) | Code transformation | DEX virtualization | DEX encryption |
| DEX encryption | No | Yes | Yes (VM-based) | Yes |
| String protection | Native externalization | AES/XOR decryption | VM-based | Native layer XOR |
| Anti-debugging | Comprehensive (ptrace lock, JDWP patch) | Comprehensive | Moderate | Basic |
| Root detection | Comprehensive (20+ checks, inotify) | Moderate | Moderate | Basic |
| Overlay protection | Yes | No | No | No |
| Screen capture block | Yes | No | No | No |
| Hooking detection | Frida, Xposed, Substrate, memory integrity | Frida, Xposed | ptrace, debug flags | ptrace |
| Bypass difficulty | Medium-High (native-heavy) | Medium (Frida hooks effective) | High (VM interpretation) | Low (DEX dump) |
| Typical customers | European banks, fintech | Enterprise, some malware | Chinese market, some malware | Chinese market, malware |
Analyst Workflow¶
1. Run APKiD -> confirm "Promon Shield" detection on the native library
2. Open in JADX -> note intact class structure but missing string literals
3. Locate the bridge class with native int->String methods
4. Spawn app with Frida (-f flag to attach early)
5. Hook android_dlopen_ext to intercept SHIELD library loading
6. Enumerate string indices via the bridge class native method
7. Hook fork() and ptrace() to disable the anti-debug watchdog
8. Hook __system_property_get to feed clean values for root checks
9. If repackaging needed -> bypass certificate verification at native level
10. For SSL pinning -> standard Frida SSL pinning bypass after RASP is neutralized
The critical difference from packer analysis: there is no DEX to unpack. The app code is already readable. The challenge is getting the app to run in an instrumented environment, not recovering hidden code.