DuckUSB

Makes apps read USB debugging as OFF while it stays really ON, same for wireless debugging and Developer Options. Also spoofs the raw sys.usb.* properties and can hide the "USB debugging enabled" notification.

Source, issues & builds: https://github.com/Bouteillepleine/DuckUSB

DuckUSB UI

Scope

Tick the entry whose package is system. That is the one that injects into system_server, and framework mode needs it. Not the one whose package is android; that does not inject there, and picking it gives you a module that looks enabled and does nothing.

Add System UI for the notification hider, and individual apps only if you want the property spoof in them. Reboot after scoping.

How it works

Detection apps don't read any real adb state. They query the settings provider for adb_enabled, adb_wifi_enabled and development_settings_enabled.

Framework mode (recommended) hooks the settings provider inside system_server, covering every app at once with no per-app scope. Callers at uid < 10000 (root/system/shell) always see the truth, so adb keeps working, and OS file-transfer components are spared so MTP is unaffected.

Per-app mode is the older client-side hook, for when you don't want system_server touched. The two are mutually exclusive; the UI enforces it.

A diagnostics card lists every caller that was lied to since boot, so a mis-scoped module can't masquerade as a working one.

DuckUSB never lies to itself. LSPosed loads a module into its own process whether or not you scope it, so DuckUSB used to spoof its own UI: the readings card showed adb_enabled 0 on a device where it was 1. Both halves now skip our own package, which also removes an inline libc hook from a process that never needed one.

Toggles

Pause (live, stops everything) · Spoof USB debugging · Framework mode · Per-app spoof · Hide notification · Verbose logging.

Property spoofing is automatic in scoped apps (except DuckUSB itself), because property reads are process-local, so it only works in apps you scope. All three bionic read routes are covered: by name, and by handle through both __system_property_read_callback and the legacy __system_property_read, so a property can't read spoofed one way and truthful another.

Tested on

OnePlus 15 / OxygenOS / Android 16 with LSPosed + KernelSU. Framework mode is verified there and nowhere else.

Releases

1.3.3

Stable

8/29/2026, 9:19:47 AM

Framework mode was unreachable on a fresh install (#4). Framework mode and the per-app spoof cover the same ground, so only one may run — and that was enforced by greying the other out. Per-app ships ON, so the framework switch arrived disabled behind a subtitle that never said what to turn off first. Scope System Framework correctly, and the app still reported "Not reachable". Both switches now stay live: turning one on turns the other off.

The diagnostics stopped blaming your scope. "Not reachable" used to lead with "System Framework (system) not scoped" even when the scope was fine and the toggle was simply off — the state every fresh install starts in. It now names the actual cause: framework mode off, or on but not yet live.

Honest status. Two states that used to show as a green "Active" are now reported for what they are. Reboot needed — framework mode is on but its hook is not in system_server yet, so nothing is spoofing until you reboot. Nothing is spoofing — both layers are off, which two taps can reach.

The service card no longer goes stale. Flipping framework mode left it showing the previous state until you left the screen and came back.

Source, issues and builds: https://github.com/Bouteillepleine/DuckUSB

Assets

1

1.4.0

Stable

8/29/2026, 9:40:40 AM

⚠️ Beta. This build requires LSPosed 2.x — a framework implementing libxposed API 101. DuckUSB is now a modern Xposed module: it carries no xposedmodule meta-data, so an older LSPosed does not reject it, it never lists it as a module at all. Nothing crashes and nothing bootloops; the app installs, opens, and reports "Not active" forever. On an older framework, stay on 1.3.3.

⚠️ Your settings reset to defaults. Module settings moved into the framework's remote preferences, and a modern module gets no world-readable-prefs redirect, so the 1.3.x values cannot be read. Re-check your toggles after updating. Your LSPosed scope is preserved.

Migrated to the modern Xposed API (libxposed 101). META-INF/xposed/ descriptors replace the manifest meta-data and assets/ entry points; XposedModule with onSystemServerStarting / onPackageReady replaces handleLoadPackage, so system_server is stated by the framework instead of inferred from a package name; interceptors replace XC_MethodHook; remote preferences replace XSharedPreferences. The UI can finally read its own LSPosed scope, and tells you when it is empty.

Framework mode is the stealthier mode, measurably. Inline hooks dirty code pages via copy-on-write, and a detector reading its own /proc/self/smaps sees them. Framework mode installs nothing inside the target, so there is nothing to find. Measured against Duck Detector: per-app leaves 4 kB dirty in libc.so, 28 kB in libart.so and 4 kB in linker64, and its Memory verdict is [DANGER] with 10 high-risk signals. Framework mode leaves none of it, and its Memory verdict is [CLEAR] — while the app still reads adb_enabled as 0. Per-app remains the only mode that also spoofs sys.usb.*; it just pays for that in the target's memory.

Two switches became one Method choice. Framework and per-app were always mutually exclusive, and as switches they could reach a state where framework mode was greyed out with nothing saying what to turn off first — the confusion behind #4. Picking one is now turning the other off.

Honest reporting. "Reboot needed" and "Nothing is spoofing" are distinct states instead of a green "Active". The readings card no longer tick-marks values — DuckUSB never spoofs itself, so that card is the real device state, not a pass/fail. The pause switch is captioned, because it stops hook bodies and is not the module's off switch. A manual "Check for updates" row was added; it only runs when tapped, and it refuses to offer a build your framework cannot load.

persist.sys.usb.config is still deliberately not spoofed: spoofing it makes reflection and libc disagree with getprop, and a detector reads that divergence as evidence of hooking. Truthful is quieter than inconsistent.

Verified on OP15 (Android 16, LSPosed 7846 / API 102) and OP11 (Android 16, LSPosed 7732 / API 101).

Source, issues and builds: https://github.com/Bouteillepleine/DuckUSB

Assets

1

1.3.2

Stable

8/22/2026, 7:48:24 PM

Fixes a crash on launch (#2). LSPosed loads a module into its own process whether or not you scope it, so DuckUSB was inline-hooking libc inside its own UI for no reason. On some ROMs that hook took SIGILL on the first property read and killed the app seconds after launch. It now refuses to hook its own process.

The readings card tells the truth. It exists to show the real device state, but it was reading DuckUSB's own lie — adb_enabled 0 on a device where it was 1. Framework mode now spares our own UI too.

Property spoofing covers every read route. Previously only the by-name route was rewritten; a native caller resolving a handle read sys.usb.state as empty rather than mtp. Both handle routes are now covered, so a property can't read spoofed one way and truthful another.

Source, issues and builds: https://github.com/Bouteillepleine/DuckUSB

Assets

1

1.3.0

Stable

8/16/2026, 7:28:49 PM

Framework mode now works, and it is the recommended way to use DuckUSB: one hook in system_server covers every app at once, with no per-app scope.

⚠️ Scope the right entry

In LSPosed → DuckUSB → Scope, tick "Cadre du sous-système" / package system.

Not "Système Android" / package android — that one does not inject into system_server. Picking it gives you a module that looks enabled and silently does nothing. This release declares an xposedscope recommendation so LSPosed highlights the correct entries. Reboot after scoping.

What's new

  • Framework mode, hooking ContentProvider.attachInfo and then only the settings provider's call(), matched by authority so ROMs that subclass SettingsProvider still work. Callers below uid 10000 (root / system / shell) always see the truth, so adb and the Settings toggle keep working.
  • Diagnostics that prove it. A small binder service inside system_server (never registered with ServiceManager) reports the hook count, uptime, and every caller that was lied to since boot with per-key counts. A mis-scoped module used to look identical to a working one.
  • Live config. Toggles push to system_server over that binder and apply immediately, no reboot.
  • Pause switch — stops all spoofing at once. It does not uninstall hooks or unload the native library; LSPosed's own switch remains the real off.
  • Property spoof is now automatic in scoped non-core apps — the toggle is gone. Scoping an app already states the intent.
  • Mutually exclusive settings layers. Framework mode and per-app spoof cover the same ground; whichever is on greys out the other.
  • UI: merged status card, collapsible caller list, light/dark toggle, regrouped sections, optional verbose logging.

Fixed

  • sys.usb.ffs.ready is no longer spoofed. It is the USB function-filesystem ready flag — machinery the USB stack acts on, not telemetry a detector reads. Claiming 0 could take the whole USB gadget down: no MTP and no adb.
  • Core processes are properly protected. handleLoadPackage fires once per package hosted in a process, not once per process — with the system scope, system_server reports android, com.android.providers.settings, com.android.location.fused, com.android.server.telecom and more, all at uid 1000. The old package-name check caught only the first, so the property spoof could install inside system_server. Now guarded three ways: uid, process name, and package name.
  • OS file-transfer plumbing is spared from both spoofs — com.android.mtp and friends run at app uids, so the uid guard alone does not reach them.

Upgrading

Signed with the same key as 1.1, so this installs as an in-place update — no uninstall, and your LSPosed enable/scope is preserved.

Tested on

OnePlus 15 (CPH2747) / OxygenOS / Android 16 with LSPosed + KernelSU. Framework mode is verified there and nowhere else; other ROMs are unknown, though the provider is matched by authority and the guards key off uid and process name rather than OEM-specific package names.

Assets

1

1.1

Stable

8/9/2026, 10:10:06 AM

  • Add USB system-property spoof (sys.usb.* / init.svc.adbd) via Java SystemProperties + native libc hooks — catches detectors that skip the Settings provider.
  • Redesigned Material 3 app UI.
  • Native hooks skip core OS processes and publish their override map lock-free (no impact on system_server / SystemUI).

Assets

1

1.0

Stable

7/20/2026, 5:22:28 PM

First release under the DuckUSB name (renamed from DuckADB).

  • Spoof USB debugging / wireless debugging / Developer Options as off to scoped apps, while they stay genuinely on.
  • Hide the persistent "USB debugging enabled" notification (needs System Framework + System UI scoped).
  • Two live toggles, both on by default, applied without a reboot.
  • Core OS is hard-skipped for the spoof half.

Assets

1