A quick-start Android/Vector module template for authorized testing and rapid prototyping.
What it includes:
- Modern
libxposedAPI 102 entry point (io.github.libxposed:api:102.0.0,compileOnly). - One module APK for both rooted Vector and rootless LSPatch 1.0. LSPatch 1.0 is rebuilt on Vector
and loads modern libxposed API-102 modules through
META-INF/xposed/java_init.list; the obsolete API-93-onlylspatchflavor is no longer needed. Seedocs/LSPATCH_NONROOT.md. - Both
onPackageLoadedandonPackageReadycallbacks are overridden for broad compatibility. - Process-level filter:
TemplateConfig.TARGET_PROCESS_SUFFIXES+SKIP_PROCESS_SUFFIXESdefault to hooking only the main process and skipping common anti-cheat / push / crash-handler satellite processes. - Modern libxposed metadata under
META-INF/xposed/:java_init.listscope.listmodule.propwith the correctexceptionMode=protectivekey
- A safe Java hook smoke test using the API 102 interceptor-chain style.
FeatureRegistry— runtime feature flags (bool/float) with best-effort persistence and live-updating overlay toggles bound to each feature key. OPSEC caveat: persistence writes a plaintext toggle file into the target app's own sandbox (getFilesDir()); a readable file naming your features/toggles inside the target is a detection surface, so prefer in-memory-only state for stealth (drop thesave()/load()calls or pointFEATURE_STATE_FILE_NAMEat a path outside the target).EngineDetector— identifies Unity / Unreal / Cocos2d-x / Godot / Flutter / React-Native / Xamarin targets at startup so you can branch hook strategies.NativeUtils— JNI helpers for/proc/self/mapsmodule lookup, IDA-style pattern scan,dlsymresolution, and safemprotect-guarded read/write-memory primitives.- A movable dark/lavender Nyx-styled floating menu:
- movable oval bubble
- movable rectangular panel when opened (drag the header)
- one toggle row per
FeatureRegistrybool feature
- Optional native scaffold using ByteDance ShadowHook (
com.bytedance.android:shadowhook:2.0.1) registered viaJNI_OnLoad/RegisterNativesso there are no package-derived JNI export names in the.sosymbol table. - Debug/release split with
VERBOSE_LOGSas aBuildConfigfield — release builds strip verbose logs and run R8. Note thatproguard-rules.prodeliberately-keeps the classes the framework/JNI must find by name — the entry class (ModuleEntry),NativeBridge, andNativeUtils(their method names are bound as strings inJNI_OnLoad), and theFeatureRegistry.KEY_*constants — so those names are not obfuscated and stay visible to an app enumerating its classloader. Everything not kept is renamed/obfuscated by R8. - Neutral log tag (
AppRuntime) and worker thread name; release builds disable verbose Java and native logging by default. - The documented LSPatch/SAI workflow deliberately signs both the module and every patched target
split with the same existing Android debug key at
${HOME}/.android/debug.keystore. This is a stable local test key, not a production-distribution key. - Configure script supports
--native-libto rename the packaged.soaway from the obviouslibtemplate_native.so. - Frida-first Android emulator workflow documentation for reconnaissance before building permanent hooks.
- Engine-specific native workflow notes for Unity IL2CPP and other native-heavy targets, kept as optional documentation so the template remains engine-neutral.
Use this only on apps/systems you own or are authorized to test.
- Verified against upstream releases on 2026-08-19.
libxposedAPI:102.0.0; Vector 2.2 and LSPatch 1.0 implement modern API level 102.- LSPatch: stable
v1.0build 455 (released 2026-08-18). The newest prerelease checked wascanary-460(2026-08-19); use stable unless you are validating a specific canary fix. - ByteDance Android inline hook library (
shadowhook):2.0.1. - Android Gradle Plugin
9.3.1, Gradle9.7.0, compile/target SDK 37, Android NDK29.0.14206865, CMake4.1.2, and AndroidX Annotation1.10.0. - The resolved Kotlin stdlib remains
2.2.10, supplied by AGP's built-in Kotlin toolchain and ShadowHook. Do not override only the stdlib to 2.4.x; update the compiler/runtime together when a later AGP toolchain adopts it. - ShadowHook supports
armeabi-v7aandarm64-v8a; it does not supportx86/x86_64or Houdini-translated environments.
From this directory:
./tools/configure-template.py \
--package com.yourname.yourmodule \
--name "Your Module" \
--target com.example.target \
--author "YourName" \
--native-lib audio_util # optional; renames libtemplate_native.soThen build:
./gradlew :app:assembleReleaseInstall:
adb install -r app/build/outputs/apk/release/app-release.apkEnable the module in Vector, select the target scope, then force-stop and reopen the target app:
adb shell am force-stop com.example.target
adb shell monkey -p com.example.target 1
adb logcat -c
adb logcat -s AppRuntime shadowhook_tagRelease builds silence these logs by default (BuildConfig.VERBOSE_LOGS=false).
Use ./gradlew :app:installDebug while developing to get the chatty tag.
app/src/main/java/com/template/lsposed/TemplateConfig.javaapp/src/main/resources/META-INF/xposed/scope.listapp/src/main/resources/META-INF/xposed/module.propapp/src/main/res/values/strings.xml
The entry class extends io.github.libxposed.api.XposedModule and is listed in:
app/src/main/resources/META-INF/xposed/java_init.list
Hooking is interceptor-chain based:
hook(method)
.setExceptionMode(XposedInterface.ExceptionMode.PROTECTIVE)
.intercept(chain -> {
Object result = chain.proceed();
// post-call logic
return result;
});Important points:
- Keep
libxposedascompileOnly; never package the framework API into the APK. - Keep scope tight. Do not hook every app unless you are building a framework/system module and know why.
- Use
PROTECTIVEexception mode for release builds so hook failures do not crash the target app. - Use
deoptimize(executable)only when you actually need it; overusing deopt can hurt performance. - API 102 hot reload is deliberately disabled (
autoHotReload=false): the template owns native hooks, a worker thread, and Activity lifecycle callbacks, so safe hot reload requires a target-specific teardown/unhook implementation first.
ShadowHook is the recommended native inline-hook scaffold in this template because it is actively maintained and supports:
- hook by function address or
library + symbol - pending hooks for ELFs loaded later
- hook modes per proxy function (
shared,multi,unique) - instruction-level intercepts
- linker init/fini callbacks
- operation records for debugging
The template’s native code installs a harmless libc.so!getpid smoke-test hook and returns the original value unchanged. Replace that with your app-specific native hook only after finding stable symbols/addresses with Frida.
See docs/SHADOWHOOK_NOTES.md.
The template is deliberately not IL2CPP-specific. EngineDetector is only a routing helper:
use it to decide which research notes or hook installers are relevant, but keep target-specific
offsets, metadata dumps, and generated analysis files out of main.
For Unity IL2CPP targets, see docs/ENGINE_NATIVE_WORKFLOWS.md. That document covers static
metadata recovery, RVA-to-runtime-address mapping, value-type ABI checks, delayed library loading,
and settings-bridge issues that also apply to other native-heavy engines. Treat it as a playbook
for a branch that targets one app, not as default template behavior.
LSPatch 1.0 uses Vector's runtime and accepts this template's modern API-102 module directly. Build the same release APK used by rooted Vector. For this template, the non-root workflow is always:
- embed the module with
-m(never use manager mode); - sign the module and every patched target split with
${HOME}/.android/debug.keystore; - package the patched target APK set as
target-lspatched.apks; and - install that bundle with SAI (Split APKs Installer).
ANDROID_DEBUG_KEYSTORE="${HOME}/.android/debug.keystore"
test -f "$ANDROID_DEBUG_KEYSTORE"
env -u TEMPLATE_KS_PATH -u TEMPLATE_KS_PASS \
-u TEMPLATE_KEY_ALIAS -u TEMPLATE_KEY_PASS \
./gradlew :app:assembleReleaseThe module is already nested inside the patched base APK, so do not add app-release.apk as a
separate top-level member of the .apks archive. The complete copy-paste patch, signing, bundling,
verification, and SAI installation workflow is in
docs/LSPATCH_NONROOT.md.
Use Frida first to answer questions like:
- What process and ABI am I actually in?
- Which classes/methods are loaded?
- Which native libraries load and when?
- Which exported symbols exist?
- Which Java methods or native symbols are stable enough to become permanent libxposed/ShadowHook hooks?
Use the latest undetected Frida server linked in docs/FRIDA_EMULATOR_QUICKSTART.md for this workflow. Keep the host frida-tools version and device frida-server version aligned, and do not mix these steps with stock frida-server unless you are intentionally debugging a version/build mismatch.
See docs/FRIDA_EMULATOR_QUICKSTART.md.
Tap the Nyx bubble to open the rectangular display. Drag the title/subtitle header area to move the open panel. The bubble itself is also draggable.
If you use an x86/x86_64 emulator, Java libxposed hooks can still work, but the native ShadowHook scaffold will not. For native inline-hook testing, use a real arm64 device or an arm64 emulator image on Apple Silicon.
LICENSE— CC BY-NC-ND 4.0 license notice and official license links.SECURITY.md— safe issue-reporting expectations.CONTRIBUTING.md— contribution and validation expectations.docs/ENGINE_NATIVE_WORKFLOWS.md— optional notes for Unity IL2CPP and native-heavy targets.docs/LSPATCH_NONROOT.md— non-root delivery via LSPatch 1.0 (modes, splits, signing, CLI)..github/workflows/android.yml— GitHub Actions build for debug and release APKs.
This project is licensed under Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International (CC-BY-NC-ND-4.0). You may share the unmodified template with attribution for non-commercial use. Do not distribute modified versions without separate permission.