Refactor native modules and migrate to new Zygisk architecture - #550
Conversation
|
@Dev4Mod, @Stillhard, @ale5000-git, please test this refactor build and have a look at the code documentation I added. Leave your comments if you spot errors, or current docs / codes are still unclear for you. |
|
It seems to be a symbol resolution problem. Please test the latest CI again and upload logs. |
This comment was marked as outdated.
This comment was marked as outdated.
|
Crash zygisk bro |
|
@huynhbaman If you can, please provide logs as described in #123. |
|
|
@Dev4Mod @huynhbaman Please test again the latest CI buid: https://github.com/JingMatrix/LSPosed/actions/runs/22737067570 |
|
Vector has now started normally, however there is a problem with my WAEnhancer module which uses XC_InitPackageResources to obtain resources. |
|
|
@Dev4Mod Please test https://github.com/JingMatrix/LSPosed/actions/runs/22758702203 and upload logs if anything abnormal is observed. |
|
It's working fine now, with no error logs in Vector. |
Note that the signature of rewriteXmlReferencesNative is changed to separate sub-projects xposed and core.
Better to change it after database is redesigned
Java string created via NewStringUTF is detectable by searching the JVM heap. Renaming `LSPosed` to another string, is stupid but can defeat detectors such as https://github.com/RiRiRawrZ615/Known-Root-Detectors/blob/main/Risk%20Detector_1.6.apk Of course, there are plenty of robust solutions to overcome this detection point. This commit is just for fun, in the process of refactoring LSPosed into Vector.
Add more comments and simplify logic
1. Avoid hard-coding transaction codes for maintance convience. 2. No need to enforce descriptor, which only introduce detection point.
However, we should keep the file `zygisk.json` for smooth updating experience.
This part is replaced by the native module
Using bias_ comparison could be buggy
The Android dynamic linker (Bionic) restricts loading libraries from unauthorized paths via LD_PRELOAD. This causes the linker to reject the hook library with a "not accessible for the namespace" fatal error. To bypass this restriction, we exploit a fallback in Bionic that explicitly skips the namespace accessibility check for files located on tmpfs. We use `memfd_create` to create an anonymous tmpfs-backed file descriptor, copy the library into it using `sendfile`, and pass the new memfd to LD_PRELOAD instead. Reference: function `load_library` in https://cs.android.com/android/platform/superproject/main/+/main:bionic/linker/linker.cpp
Correct bugs in dynamical construction of XResources methods.
…atrix#550) We replace the legacy magisk-loader and core JNI with a rewritten Zygisk module and a centralized native library. Major changes: - Zygisk Module: Replaced magisk-loader with a rewritten Zygisk implementation in Kotlin and C++. - Native Migration: Moved ELF parsing, symbol caching, and hooking logic from core/jni to a standalone native module. - Anti-detection: Removed enforced parcel descriptors to evade heap-based string detection. - Scripting: Simplified Magisk module shell scripts (customize.sh, service.sh) and removed redundant utility functions. - Dex-obfuscation: Refactored obfuscation management to improve code clarity. Note that `zygisk.json` and the `lspd` directory are kept to ensure a smooth update path and database continuity.
buildSrc holds two Gradle task classes no build script registers, and neither output survives: there is no LangList.java and no material_theme_builder.xml, the locale list comes from BuildConfig.TRANSLATIONS computed in manager/build.gradle.kts, and the only XML theme left wraps Theme.DeviceDefault.NoActionBar. Its README documents registering both tasks against :app, gone since #796. The directory goes, with the format task's include for its Kotlin. The version catalog still pins the whole View stack -- Glide, Rikka's rikkax-* widgets, Fragment, Navigation 2 with safeargs, preference, RecyclerView, SwipeRefreshLayout, ConstraintLayout, Material Components for Views. No build script references any of those 26 aliases, the safeargs plugin, or the nav, glide and appcenter versions. rikkax-parcelablelist stays; :services:manager-service exposes it for the AIDL's ParcelableListSlice. hiddenapi/stubs carries 20 files nothing compiles against, mostly LSPosed-era rather than rewrite fallout. Where the platform declares the same class the stub is already inert: :daemon compiles PackageManager.VERSION_CODE_HIGHEST and XSharedPreferences compiles Environment.getDataDirectory(), neither of which the stub declares, so android.jar wins today. They are compileOnly and never reach a dex, so lsplant's FindClass on dalvik/system/VMRuntime keeps resolving the framework class. Four HiddenApiBridge wrappers and the stub members that existed only to type them go with them. In :manager the four @serializable models for the Actions runs and artifacts API became unreachable when eb07955 moved canary sourcing to release prereleases, and relativeTime, levelLabel, sectionHeaderStyle, SeedScheme.parseHex, VectorLightColors, VectorDarkColors, ModulesViewModel.selectAll, LogPaneState.atOldest and GOOD_FIRST_ISSUE_URL have no call site at all. RelativeTime.kt becomes TimeText.kt, since relative time is what left it. Seventeen strings go too, translations deleted alongside their source so the next Crowdin pull does not add them back. Three of them -- store_offline, settings_window, module_toggle_failed -- read more like missing features than dead weight, and their translated copy in eighteen languages goes with them. Daemon-side, CliHandler.isPackageInstalled, Utils.getZoneId, Utils.isLENOVO and :xposed's trackedApks have no caller; the live tracker is LoadedApkTracker.activeApks. magisk-loader goes as well, and that is the one deletion here that ships behaviour. Before #550 the loader baked the raw githubusercontent URL of magisk-loader/update/zygisk.json into every module.prop, so Magisk on a pre-v2.0 install polls it and will now get a 404. Effectively everyone is on v2.0 by now, and zygisk/update.json -- what module.prop has pointed at since -- is untouched. Nothing else changes behaviour. Release builds already shrink unused resources, and no deletion touches a de.robv or io.github.libxposed surface, an AIDL transaction id, a JNI name, a manifest entry or a keep rule.
The GitHub sign-in came from a `githubClientId` Gradle property set nowhere -- not in gradle.properties, not in CI -- so every build compiled GITHUB_CLIENT_ID as "". isConfigured was therefore always false: the card returned before drawing anything, signIn() short-circuited to Unavailable, and tokenProvider() always returned null, so no request ever carried an Authorization header. It bought only the rate limit, 60 requests an hour anonymous against 5000 signed in, and nothing depends on having it: the canary screen sources its zips from release assets precisely so that testing a build needs no account. Deleted rather than given a client id, because the flow also has nowhere good to keep a token. Parasitically the manager's SharedPreferences land in com.android.shell's data directory, whose shared_prefs is world-executable, so a token would sit outside our own sandbox. That is worth solving before offering sign-in again, not alongside it. The rest is what #796 left unreferenced. buildSrc held two Gradle task classes no build script registers and whose outputs no longer exist -- the locale list comes from BuildConfig.TRANSLATIONS now. The version catalog still pinned the whole View stack: 26 aliases, the safeargs plugin, and the nav, glide and appcenter versions. hiddenapi/stubs carried 20 files nothing compiles against, with four HiddenApiBridge wrappers and the stub members that existed only to type them. In :manager the four @serializable models for the Actions runs and artifacts API became unreachable when eb07955 moved canary sourcing to release prereleases, and nine symbols -- relativeTime, levelLabel, sectionHeaderStyle, SeedScheme.parseHex, VectorLightColors, VectorDarkColors, ModulesViewModel.selectAll, LogPaneState.atOldest and GOOD_FIRST_ISSUE_URL -- have no call site at all. Seventeen strings go with them, translations deleted alongside their source so the next Crowdin pull does not add them back. Daemon-side, CliHandler.isPackageInstalled, Utils.getZoneId, Utils.isLENOVO and :xposed's trackedApks have no caller; the live tracker is LoadedApkTracker.activeApks. One deletion ships behaviour. Before #550 the loader baked the raw githubusercontent URL of magisk-loader/update/zygisk.json into every module.prop, so Magisk on a pre-v2.0 install polls it and will now get a 404. Effectively everyone is on v2.0 by now, and zygisk/update.json -- what module.prop has pointed at since -- is untouched.


We replace the legacy magisk-loader and core JNI with a rewritten Zygisk module and a centralized native library.
Major changes: