Payload API
Everything a payload calls from managed code lives under the SharpProspero.Payload namespace.
This page groups the surface by what it does, names the wrapper class, and shows one call for
each.
Entry point and arguments
| Type | What it holds |
|---|---|
PayloadEntryPoint |
The loader-supplied arguments the CRT captured. PayloadEntryPoint.Args returns the PayloadArgs* — null when the loader did not supply one. |
PayloadArgs |
The struct the loader hands the payload: the resolver entry, the pipe primitive descriptors, and the kernel data base. |
PayloadArgs* args = PayloadEntryPoint.Args;
if (args == null) { /* loader did not supply args */ }
Kernel
| Class | What it does |
|---|---|
PayloadKernel |
Process-oriented helpers: walk the process list, promote a running application (credentials, capabilities, filesystem view), cache the root vnode. See Kernel access. |
PayloadKernelIo |
The raw read/write surface: ReadU64, WriteU64, Read, Write, and TryRead*/TryWrite* for a soft failure. |
Networking
int listener = PayloadNetwork.Listen(9069, backlog: 8);
int client = PayloadNetwork.Accept(listener);
Span<byte> buf = stackalloc byte[1024];
long n = PayloadNetwork.Receive(client, buf);
PayloadNetwork.SendAll(client, buf.Slice(0, (int)n));
PayloadNetwork.Close(client);
PayloadNetwork.Close(listener);
// Outbound
int s = PayloadNetwork.Connect(192, 168, 1, 10, 9069);
The socket API routes through the POSIX interop layer, which binds to libSceNet.sprx at run
time via the payload’s DT_NEEDED list. libSceNet.sprx is one of the default entries, so a
payload calls the socket surface without any extra project declaration.
Filesystem
PayloadFileSystem wraps opendir, readdir, closedir, and stat from libc, with a small
IsDirectory(mode) helper:
bool isDir = PayloadFileSystem.IsDirectory(mode);
For any other filesystem call the payload needs (open, read, write, mkdir, unlink, and
so on), declare it with [LibraryImport] in the payload’s own Program.cs — every FreeBSD libc
call is available through the resolver cascade. Every path is applied in the host process’s
filesystem view, which is the per-title sandbox by default. A companion daemon promotes another
process to lift that view — see Promoting a running application.
Process
int rc = PayloadProcess.GetAppInfo(pid, out PayloadAppInfo info);
// info.AppId, info.AppType, info.TitleId (10-byte identifier)
PayloadAppInfo exposes AppId, AppType, and the ten-byte TitleId identifier for the
running process. Use PayloadKernel.FindProcessByComm(...) or FindProcessByTitleId(...) to walk
the process list and locate the target of a credential-write.
Notifications
PayloadNotification.SendKernelNotification("unjail: daemon ready"u8);
PayloadNotification.SendNotification(userId: 1, isLogged: true, jsonPayload: "..."u8);
PayloadNotification.SendNotificationById(userId: 1, isLogged: true,
id: "myEventId"u8, jsonData: "{...}"u8);
The kernel variant is what the CRT uses for daemon bring-up messages. The user-visible variants
open on top of the system notification service; the id argument names a notification identifier
the system recognises, and jsonData carries the notification body.
Dynamic library loading
void* handle = PayloadDlfcn.Dlopen(nameUtf8, PayloadDlfcn.RtldLazy);
void* sym = PayloadDlfcn.Dlsym(handle, "someSymbol"u8);
PayloadDlfcn.Dlclose(handle);
PayloadDlfcn covers dlopen, dlsym, dlclose, and dlerror for a module the payload has to
load itself instead of declaring in the project. The mode constants are PayloadDlfcn.RtldLazy
and PayloadDlfcn.RtldNow.
Random bytes
Span<byte> buffer = stackalloc byte[32];
int rc = PayloadRandom.GetRandomBytes(buffer);
GetRandomBytes fills the buffer through the system random library (libSceRandom.sprx); the
call is capped at 64 bytes. GetRandomBytesFull loops for larger requests until every byte is
filled.
sysctl
PayloadSysctl wraps sysctl and getmntinfo for reading kernel-published state. Use it to
read a numeric sysctl node, or to list every mounted filesystem the host process can see.
Hardware information
int rc = PayloadHardwareInfo.GetModelName(out string model);
int rc = PayloadHardwareInfo.GetSerialNumber(out string serial);
int rc = PayloadHardwareInfo.GetCpuTemperature(out int celsius);
int rc = PayloadHardwareInfo.GetSocSensorTemperature(sensor: 0, out int celsius);
The hardware-info reads are behind libkernel_sys.sprx, so a payload that uses them sets
<ProsperoKernelSprx>libkernel_sys.sprx</ProsperoKernelSprx>.
User service
PayloadUserService.Initialize();
int rc = PayloadUserService.GetInitialUser(out int userId);
PayloadUserService.Terminate();
PayloadUserService is the read-side of the user-account service. Add
<ProsperoSprx Include="libSceUserService.sprx" /> in the project.
Browser
int rc = PayloadBrowser.LaunchWebBrowser("https://example.local/"u8);
Launches the system browser at the URL. Add both libSceSystemService.sprx and
libSceUserService.sprx to the project.
HTTP/2
int rc = PayloadHttp2.InitStack("prospero"u8,
netPoolSize: 0x40000,
sslPoolSize: 0x40000,
httpPoolSize: 0x40000,
out int netMem,
out int sslCtx,
out int httpCtx);
// ... request setup, send, receive ...
PayloadHttp2.Cleanup(reqId: 0, tmplId: 0, httpCtx, sslCtx, netMem);
The HTTP/2 stack is bigger than the raw socket API but handles TLS through libSceSsl. Add both
libSceHttp2.sprx and libSceSsl.sprx in the project.
Package install
int rc = PayloadAppInstaller.InstallFromDirectory("PPSA99099\0"u8, "/user/app/\0"u8);
InstallFromDirectory hands a staged folder to the package installer for the named title id. The
title id and path are passed as null-terminated UTF-8. The installer takes over from there.
Debug
PayloadDebug collects the CRT breadcrumb emitters, the sp:* string helpers, and small
diagnostic hooks. A production payload leaves them out; a diagnostic build (see
-DiagnosticBreadcrumbs in Building a payload) uses them to walk the
bring-up sequence.
Layout
Every wrapper class is a plain static class with [LibraryImport] interop declarations. The
source lives under src/SharpProspero/Payload/. A missing wrapper for a symbol the payload needs
is usually one of two things: add a LibraryImport in the payload’s Program.cs (fast path), or
add the wrapper to the SDK (permanent path, with the matching SPRX declaration).