Find Fabric through the render thread's class loader and make bytecode transformations safer for launcher-provided class definitions. Improve hook reporting, process-picker refresh behavior, and self-destruct cleanup; document Dawn and Lunar 1.21.11 setup.
Prestige injector (Rust)
PrestigeInjector loads the native loader library (prestige_native.dll / libprestige_native.so / libprestige_native.dylib)
into a running Minecraft 1.21.11 Fabric JVM (64-bit, Fabric Loader 0.19.x, Fabric API installed). It uses the same overall
method as the openvape bundle, written from scratch in Rust with no external crates.
Supported platforms
| OS | Architectures | Injector binary | Loader library |
|---|---|---|---|
| Windows | x86_64 | PrestigeInjector.exe |
prestige_native.dll |
| Linux | x86_64 | PrestigeInjector |
libprestige_native.so |
| macOS | x86_64, arm64 | PrestigeInjector |
libprestige_native.dylib |
The injector and library must be built for the same architecture as the target JVM.
How it works
- Injector lists the running Minecraft JVMs, then loads the library into the chosen process.
- Windows: lists visible
java.exe/javaw.exewindows (refreshed every 750 ms), then runsLoadLibraryWin the chosen process throughCreateRemoteThreadand confirms the module is mapped. - Linux / macOS: uses the HotSpot attach protocol (the same mechanism as
jcmd <pid> JVMTI.agent_load). The injector creates.attach_pid<pid>and sendsSIGQUITto the JVM, connects to its attach socket (/tmp/.java_pid<pid>, under$TMPDIRon macOS) and asks it to load the library. The JVMdlopenslibprestige_nativeand calls itsAgent_OnAttachentry point. No ptrace, no root, no per-architecture shellcode. Processes are found via/proc(Linux) orps(macOS); there are no window titles, so the picker shows the pid and instance name.
- Windows: lists visible
- The native library only spawns a worker thread from its entry point (
DllMainon Windows,Agent_OnAttachon unix, which also hands over theJavaVM*). The worker:- waits for the JVM (Windows:
jvm.dll,JNI_GetCreatedJavaVMs), attaches, acquires the JVMTI redefine/retransform capabilities; - writes the embedded payload jar (the remapped
prestige-*.jar) to the temp directory underPrestigeLoader; - looks for Fabric through the render thread's context class loader, then the system and other thread loaders;
FabricLauncherBase.getLauncher().addToClassPath(jar)so payload and game classes share the launcher's game class loader;- registers
NativeBridge.classBytes/NativeBridge.redefineand callsBootstrap.start().
- waits for the JVM (Windows:
Bootstrap(Java) waits for the client window, then for every ClassTransform hook target gets the current class bytes (JVMTI retransform capture), runs the hooks throughInPlaceTransformerand redefines the class. The bundled ClassTransform inlines hook handlers into the target methods, so normally nothing is added to the class and a plain redefine works. If a transformer ever does add methods (a running JVM cannot), they are moved into generateddev.zprestige.prestige.hooks.H*helper classes, call sites becomeinvokestatic, and private member access goes throughAccessMethodHandles. Finally the Prestige and ClickGUI entrypoints run on the client thread.
Build
The payload jar is embedded with include_bytes!, so each target needs its own build. Both scripts below build for the host OS only and run
gradlew remapJar, cargo build --release, and copy the results to dist/.
.\build-injector.ps1 # Windows: dist\PrestigeInjector.exe + dist\prestige_native.dll
./build-injector.sh # Linux/macOS: dist/PrestigeInjector + dist/libprestige_native.{so,dylib}
To build release zips for every platform from Windows, run build-release.bat. It cross-compiles Linux (x86_64,
glibc 2.17+, so one build covers every mainstream distro) and macOS (universal x86_64 + arm64) with cargo-zigbuild, installing
zig and cargo-zigbuild on first run, and writes dist\release\prestige-<ver>-{windows-x86_64,linux-x86_64,macos-universal}.zip,
the bare mod jar and SHA256SUMS.txt.
Set JAVA_HOME beforehand to choose the JDK for Gradle (build-injector.sh honours it). The GitHub Actions workflow
.github/workflows/injector.yml builds and tests all four targets (Windows x86_64, Linux x86_64, macOS x86_64, macOS arm64)
and uploads them as artifacts.
Use
Start a Fabric 1.21.11 instance, then run:
PrestigeInjector # interactive: pick the game from the list
PrestigeInjector <pid> [lib path] # inject into a specific pid, optionally with an explicit library path
On Windows this is PrestigeInjector.exe. By default the library is looked up beside the injector.
Dawn and Lunar Client 1.21.11
Use a 1.21.11 Fabric profile in Dawn or enable Lunar Client's Fabric add-on for 1.21.11. The target profile needs Fabric Loader 0.19.x and Fabric API. Wait for the title screen before selecting the game in the injector. The default Prestige menu key is Right Shift, which may overlap with a launcher keybind.
For Lunar, the native log should identify GenesisClassLoader. Check the game log for hooks installed
and client initialised. Hook counts refer to classes with changed bytecode. A skipped or failed hook
can leave its feature unavailable even if the menu opens.
An offline JVM replay accepted all 42 changed classes from Lunar's installed 1.21.11 cache after recalculating stack and local limits on the cached classes. Live injection and Dawn's in-game profile still need smoke testing.
Install as a mod instead
The payload jar is also a normal Fabric mod. Put prestige-*.jar (from dist/ or the CI payload-jar artifact) in the
mods/ folder of a Fabric Loader 0.19+ / Fabric API / Minecraft 1.21.11 instance; no injector is needed, on any OS.
Do not use both: if the mod is already loaded, the injector's bootstrap logs "already loaded as a Fabric mod" and skips.
Requirements (Linux / macOS)
- Run the injector as the same user as the game.
- The attach mechanism must be enabled: the game must not be started with
-XX:+DisableAttachMechanism. - The JVM architecture must match the injector build. On Apple Silicon use an arm64 JVM, or use the x86_64 build for JVMs running under Rosetta.
- Sandboxed launchers (Flatpak, Snap) hide the attach socket and are not supported.
Known limits
- On Linux/macOS the library stays loaded after self-destruct: hooks are removed and natives unregistered, but the library is
not
dlclosed (unmapping code the thread is still returning into would crash the JVM). On Windows the library is freed. - Linux and macOS support is compile-checked in CI; test on a real host before relying on it.
Log
prestige-native.log is written beside the loader library, plus [Prestige-Inject] lines in the game log.