Persistent root via the Dirty Frag on Android. A stable second-stage root: get temporary root once with another exploit (e.g. ghostlock), persist a system-UID app, then use Dirty Frag from it for all subsequent roots.
Tested only on Galaxy S26 OneUI 8.5 (samsung/m1qjpnx/m1q:16/BP4A.251205.006/S942QOPU1AZDE_SJP1AZDE:user/release-keys), but might work on other versions.
Exploits of ghostlock vulnerability are somewhat unstable on Android. It's frustrating to get temporary root for each reboots while scared of kernel crashes. This exploit achives comfortable second-stage root by Dirty Frag.
temp root (ghostlock) -> DFInstaller injects key -> soft reboot
-> install DFReroot as android.uid.system -> Run DirtyFrag -> root (ksud)
- DFInstaller (
com.polygraphene.df.installer, normal app) edits/data/system/packages.xmlas root, inserting signing key into theandroid.uid.systemshared-userpastSigs. - After a soft reboot PMS re-reads
packages.xml. - DFReroot (
com.polygraphene.df.reroot,sharedUserId="android.uid.system") installs as system UID and survives reboots. - DFReroot hops
system_server -> network_stack(which candlopenand holdsCAP_NET_ADMIN), patches vendor/libc/libc++ via Dirty Frag, loads a tiny LKM that sets SELinux permissive, and late-loads ksud.
- A vulnerability to get temporary root access
- A kernel vulnerable to Dirty Frag
- Obtain temporary root with another explot (e.g. ghostlock).
- Install
df_installer_(version).apkfrom Release, and grant root on it from root managers. - Inject -> Soft reboot (restarts the framework; PMS re-reads
packages.xml). - Install DFReroot (via
pm install, needssuagain after the reboot). - Open DFReroot, press Run DirtyFrag.
df_reroot.apk is bundled in df_installer.apk. No need to download/install it manually.
- Run Uninstall key to revert modifications to
packages.xml. - Uninstall DFReroot and DFInstaller.
# Generate app/keystore.jks
$ ./create-keystore.sh
# Generate df_reroot.apk + df_installer.apk
$ ANDROID_NDK_HOME=(ndk path) ANDROID_HOME=(sdk path) ./build.shThe LKM rebuild needs Docker (GKI DDK), see dirtyfrag-lkm/build.sh.
Build ksud from kdp-612-3.3.0 branch of my fork of KernelSU.
installer/— DFInstaller app:PackagesXml/Abx(packages.xml read/write, ABX-aware),InjectMain(rootapp_processentry:--check/--dry-run/--dump/--uninstall/inject),SysKey/SigKey(cert via PackageManager, v1/v2/v3 agnostic), GUI.app/— DFReroot app:StageHop(system_server -> network_stack),DirtyFrag(JNI bridge, package name must stayorg.lsposed.lspromise),KsudStage, nativeexp.c+stage1.S(arm64),dirtyfrag.ko.dirtyfrag-lkm/— LKM source (resolveskallsyms_lookup_name, clearsselinux_state.enforcing).logtestexe/— standalone logcat-socket test binary.
packages.xmlis backed up once topackages.xml.bak-df-installer.
- Dirty Frag by @V4bel - Discovering and exploiting Dirty Frag
- LSPromise by @LSPosed - Exploiting Dirty Frag on android
- AbxOverflow by @michalbednarski - Idea for persistent
system_serverprivilege