Duck-Detector-Refactoring
Development rules: see CODING_STANDARDS.md before making code, workflow, or commit changes.
DuckDetector is an Android security inspection app focused on local, device-side evidence collection for root-related tampering, runtime hooking, mount manipulation, attestation trust, and virtualized execution environments.
The project combines a Jetpack Compose UI, modular Kotlin feature packages, and native C++ / assembly probes to surface detector cards with structured findings, method coverage, and scan-state summaries.
Highlights
- Modular detector architecture with feature-specific repositories, mappers, view models, and card UIs.
- Native startup preload through a transparent
NativeActivitylauncher for early mount and virtualization evidence collection. - Native runtime probes implemented in C++ and arm64 assembly where timing, syscall, or mount visibility matters.
- Cross-process and isolated-process consistency checks for stronger runtime validation.
- Dashboard aggregation with per-detector status, top findings, loading states, and detailed drill-down cards.
- Mostly local, offline inspection. Network access is only used when the user allows online TEE revocation checks in Settings.
Detector Modules
The current app includes the following major detector areas:
| Module | Focus |
|---|---|
| Bootloader | Bootloader unlock state and related security posture |
| Custom ROM | ROM fingerprints, platform-file fallbacks, and ROM indicators |
| Dangerous Apps | Installed app corroboration for known risky packages |
| Kernel Check | Kernel build and runtime consistency signals |
| LSPosed | Java-side and native LSPosed / Xposed runtime evidence |
| Memory | Runtime hook residue, suspicious mappings, and loader visibility |
| Mount | Mount tables, mount consistency, startup preload findings, overlay signals, and namespace anomalies |
| Native Root | Native root-runtime traces, corroborated residue paths, and low-level system anomalies |
| Play Integrity Fix | Property spoofing and related runtime consistency checks |
| SELinux | SELinux mode, policy, audit integrity, and context consistency |
| SU | Root binary and runtime root-context indicators |
| System Properties | Property consistency, native snapshots, and raw property-area residue |
| TEE | Key attestation, certificate chain analysis, revocation checks, StrongBox, and RKP signals |
| Virtualization | Emulator / guest / translation / host-app / consistency / honeypot evidence |
| Zygisk | Zygisk state, FD traps, linker residue, and cross-process evidence |
Supporting app areas such as dashboard, settings, and deviceinfo provide
aggregation, user controls, and device context.
Architecture
The codebase is organized around feature modules under:
app/src/main/java/com/eltavine/duckdetector/features/<feature>
Most features follow the same high-level shape:
domain: report and result modelsdata: repositories, probes, native bridges, service helperspresentation: mapper and UI-state reducersui: card composables and UI models
Shared infrastructure lives under:
app/src/main/java/com/eltavine/duckdetector/coreapp/src/main/cpp
Runtime pipeline
- A transparent
NativeActivitylaunches first and performs startup preload collection for time-sensitive evidence. - Preload results are passed into
MainActivityand captured in in-memory preload stores. - The Compose app shell creates detector view models and collects feature reports.
- Repositories combine Java-side probes, native bridges, and helper-process results into normalized report objects.
- Card mappers convert reports into dashboard-ready UI models.
Native components
Native probes live under:
app/src/main/cpp/preloadapp/src/main/cpp/mountapp/src/main/cpp/virtualizationapp/src/main/cpp/asm/arm64
These components are built into a single shared library and are used for mount inspection, preload capture, virtualization snapshots, graphics renderer checks, and arm64 trap / honeypot paths.
Build Requirements
- Android Studio with Android SDK 37.0
- Android Build Tools
37.0.0 - JDK 17
- Android NDK
30.0.14904198 - CMake
4.1.2
Project build configuration is split between gradle.properties,
build-logic/, and app/build.gradle.kts with:
minSdk = 29targetSdk = 37compileSdk = 37.0versionCode = 214versionName = 26.3.14-alpha
Build
Debug
On Windows:
./gradlew.bat :app:assembleDebug
On macOS / Linux:
./gradlew :app:assembleDebug
Release
Release signing is optional and controlled through environment variables:
ANDROID_KEYSTORE_PATHANDROID_KEYSTORE_PASSWORDANDROID_KEY_ALIASANDROID_KEY_PASSWORD
If all four variables are present, the release build uses the ciRelease
signing config.
Example:
$env:ANDROID_KEYSTORE_PATH="C:\path\to\keystore.jks"
$env:ANDROID_KEYSTORE_PASSWORD="***"
$env:ANDROID_KEY_ALIAS="release"
$env:ANDROID_KEY_PASSWORD="***"
./gradlew.bat :app:assembleRelease
Output APK Naming
APK artifacts are renamed through a custom Gradle transformation task. Typical output names follow this pattern:
Duck Detector-<version>-Universal.apkDuck Detector-<version>-<filter>.apk
Testing and Verification
Useful verification commands:
./gradlew.bat :app:compileDebugKotlin
./gradlew.bat :app:testDebugUnitTest
./gradlew.bat :app:assembleDebug
Because several detectors rely on process state, mount state, native ABI, and device-specific runtime behavior, manual validation on real hardware remains important even when unit tests pass.
Privacy and Network Use
- Detector logic is primarily local and device-side.
- The app does not require root access to run.
- Some probes may report reduced coverage or
support/unavailablestates when Android sandbox rules or OEM restrictions block access. - Network access is only relevant for TEE certificate revocation checks, and only when the user enables online CRL checks in Settings.
Project Layout
DuckDetector_new/
|- build-logic/
|- app/
| |- src/main/java/com/eltavine/duckdetector/
| | |- core/
| | |- features/
| | \- ui/
| \- src/main/cpp/
|- gradle/
|- scripts/
|- build.gradle.kts
\- settings.gradle.kts
Development Notes
- Detector detail rows are intentionally standardized through a shared composable so long labels, statuses, and evidence strings wrap consistently across cards.
- Startup preload heuristics are conservative by design and may be tightened further if specific device families produce noisy evidence.
- Virtualization detection is intentionally split across preload, Java probes, native probes, helper processes, and isolated processes to reduce reliance on any single signal source.
Limitations
- Security detection is heuristic. No single signal should be treated as perfect proof in isolation.
- OEM kernels, Android version differences, mount layout changes, and sandbox policies can alter probe coverage or produce device-specific edge cases.
- Some low-level checks are ABI-specific. For example, certain trap paths are
only fully implemented on
arm64-v8a.
Status
This repository is an actively evolving detector application. New modules and heuristics are still being added, and some detector thresholds may continue to be tuned to reduce false positives on stock devices.
