< Back to all hacks

#26 boot-debloat.sh (51+ Packages via Dirty COW)

Debloat
Problem
After factory reset all packages are back. Manual pm disable one-by-one is tedious.
Solution
Single script: Dirty COW root + pm disable 51+ packages in one command.
Lesson
pm disable via root persists across reboot and is reversible (unlike pm uninstall on Android 6).

Context

On the Moto E2 with 1 GB RAM, every unnecessary package counts. Android 6.0 ships with 70+ pre-installed packages running in the background: Chrome, Email, Calendar, Camera, Hangouts, Play Store, carrier bloatware, Motorola services. After applying the initial no-root debloat (Hack #23), about 20 packages could be disabled via adb shell pm disable-user. But 30+ more are protected by Android and require actual root access.

After a factory reset (or boot loop recovery), every single disabled package comes back. Manually running pm disable 51 times via ADB is tedious and error-prone. A single automated script was needed.

Prerequisites

  • Dirty COW root access (Hack #34)
  • SELinux bypass via app_process32 (Hack #36)
  • ADB connection to the phone (USB)

Implementation

The script lives at /data/local/tmp/boot-debloat.sh and runs from ADB shell (uid 2000, shell domain). It uses Dirty COW to overwrite run-as with a root payload, then iterates through the package list calling pm disable for each.

# Run after every reboot or factory reset:
adb shell sh /data/local/tmp/boot-debloat.sh

The script uses the Dirty COW exploit to gain root, then disables packages in bulk:

# Core logic inside boot-debloat.sh:
# 1. Dirty COW overwrites /system/bin/run-as with root payload
# 2. Root payload calls pm disable for each package
# 3. Package states persist in /data/system/users/0/package-restrictions.xml

PACKAGES="
com.android.browser
com.android.calendar
com.android.camera2
com.android.chrome
com.android.email
com.android.exchange2
com.android.gallery3d
com.android.inputmethod.latin
com.android.music
com.android.providers.calendar
com.android.stk
com.google.android.apps.books
com.google.android.apps.docs
com.google.android.apps.magazines
com.google.android.apps.maps
com.google.android.apps.photos
com.google.android.apps.plus
com.google.android.gm
com.google.android.googlequicksearchbox
com.google.android.music
com.google.android.talk
com.google.android.videos
com.google.android.youtube
com.motorola.help
com.motorola.migrate
"
# ... 51+ total packages

Verification

# Check how many packages are disabled:
adb shell pm list packages -d | wc -l
# Expected: 51+

# Check total enabled packages:
adb shell pm list packages -e | wc -l
# Expected: 13

# Verify specific package is disabled:
adb shell pm list packages -d | grep chrome
# package:com.android.chrome

Gotchas

  • Must run from ADB shell (uid 2000), NOT from Termux SSH. Termux runs as untrusted_app (uid 10001) and cannot access /system/bin/run-as due to SELinux
  • NEVER disable com.motorola.android.providers.settings — causes boot loop
  • NEVER disable ALL launchers — Android hangs at boot logo without a HOME activity
  • Disabling com.android.defcontainer breaks adb install — re-enable with pm enable com.android.defcontainer before installing APKs
  • pm uninstall -k --user 0 is PERMANENT on Android 6 — no restore without factory reset. Always prefer pm disable
  • Script takes ~10 seconds to complete. The Dirty COW exploit itself takes ~5 seconds

Result

MetricBeforeAfter
Enabled packages64+13
Background processes35+~12
Available RAM~180 MB~350 MB
Boot-to-ready time~90s~45s