2.3 KiB
OnionHEN SPRX Loader
libonion_sprx provides a reusable, synchronous use-case for loading a
.sprx/.prx module into an already-running PS5 process. It is intentionally
separate from the FPS sampler and from the ELF plugin manager.
Design
The public SprxLoader owns validation and idempotency policy. It depends only
on IRemoteSprxRuntime, so host tests or another platform can provide a fake
runtime without linking ptrace or PS5 kernel code. PtraceSprxRuntime is the
production adapter and contains the PS5-specific details:
- Elevate the loader process to
PTRACE_AUTHIDfor one scoped operation. - Attach to the target and resolve
sceKernelLoadStartModuleandpthread_createby NID. - Allocate three temporary target pages for context, path, and thread data.
- Start a short remote thread thunk. The thunk calls
sceKernelLoadStartModule(path, 0, 0, 0, 0, 0)and records its return code. - Detach while the module initializes and poll the target's dynlib table.
- Reattach only after the thunk completed, then unmap temporary pages.
The loader does not inject a persistent ELF payload and does not leave a custom SPRX resident beyond the module requested by the caller.
Usage
#include <onion/sprx_loader.hpp>
onion::sprx::PtraceSprxRuntime runtime;
onion::sprx::NoopTargetAccessPolicy access;
onion::sprx::TitleIdAllowlist allowlist;
allowlist.add_exact("CUSA12345");
onion::sprx::SprxLoader loader(runtime, access, allowlist);
const auto result = loader.load({
.pid = game_pid,
.path = "/data/plugins/example.sprx",
.options = {.timeout_ms = 5000, .poll_ms = 10},
});
if (!result.succeeded()) {
// load_status_name(result.status), result.remote_result
}
The target must be able to resolve the two NIDs and access the requested path. For a sandboxed game, the caller must apply the project's existing target jailbreak/privilege policy before loading, or provide a runtime adapter that does so. The framework deliberately does not silently jailbreak arbitrary processes.
Why this is not wired into FPS
FPS currently uses daemon-side /dev/dce, DMAP, and a BC GNM detour. This
loader is a general infrastructure component for future user-requested SPRX
plugins; adding it to the FPS path would reintroduce the old FPS injection
coupling.