Files
OpenSourcereR-dev 9c649a44dc Initial public release: ps5debug-NG v1.2.2
PS5 debugger payload, inspired by Ctn's ps5debug 1.0b5 and
wire-compatible with it. Runs the wire-protocol server inside
SceShellCore via an umtx-loaded installer that injects the embedded
debugger ELF.

Features: process scan/RPC/ELF-inject, on-console scan, full
debugger (breakpoints, watchpoints, single-step, regs/FP/DR access),
kernel R/W, server-side Zydis disassembly, on-console Keystone
assembler (0xBDAA0024), foreground-app metadata (0xBDDD0006),
server-side RBP stack walk (CMD_PROC_READ_STACK), klog forwarder
(TCP 3232), rest-mode survival and a lot more.

Supports FW families 3.x / 4.0 / 4.x (incl. 4.51) / 5.x / 6.x /
7.x / 7.5x / 8.x via the kpatch routine in installer/source/main.c.

GPL-3.0-only.
2026-05-14 13:44:35 +07:00

116 lines
3.9 KiB
C

// SPDX-License-Identifier: GPL-3.0-only
#include "sdk_shim.h"
#include "protocol.h"
#include "proc.h"
#include "kdbg.h"
extern int kernel_mprotect(pid_t pid, intptr_t addr, uint64_t len, int prot);
extern int proc_remote_alloc(uint32_t pid, uint64_t *out_addr, uint64_t length, uint64_t flags);
extern int proc_remote_free (uint32_t pid, uint64_t addr, uint64_t length);
extern int proc_remote_call (int pid, struct sys_proc_call_args *args);
extern long sys_proc_elf (unsigned long pid, unsigned long elf, unsigned long length);
extern long sys_proc_elf_rpc (unsigned long pid, unsigned long elf, unsigned long length, uint64_t *out_entry);
extern int sys_proc_vm_map (uint32_t pid, void **out_maps, int *out_count);
int sys_proc_cmd(uint64_t pid, uint64_t cmd, void *data) {
if (!data) return 1;
switch (cmd) {
case SYS_PROC_VM_MAP: {
struct sys_proc_vm_map_args *args = (struct sys_proc_vm_map_args *)data;
void *maps = NULL;
int count = 0;
int rc = sys_proc_vm_map((uint32_t)pid, &maps, &count);
if (rc != 0) {
sceKernelUsleep(10000);
for (int retries = 21; retries > 0; retries--) {
if (sys_proc_vm_map((uint32_t)pid, &maps, &count) == 0) { rc = 0; break; }
sceKernelUsleep(10000);
}
if (rc != 0) return 1;
}
if (!args->maps) {
args->num = (uint64_t)(count + 1);
if (maps) free(maps);
} else {
uint64_t to_copy = args->num < (uint64_t)count ? args->num : (uint64_t)count;
if (maps && to_copy > 0) {
memcpy(args->maps, maps,
(size_t)to_copy * sizeof(struct proc_vm_map_entry));
}
args->num = to_copy;
if (maps) free(maps);
}
return 0;
}
case SYS_PROC_ALLOC: {
struct sys_proc_alloc_args *args = (struct sys_proc_alloc_args *)data;
uint64_t out_addr = 0;
if (proc_remote_alloc((uint32_t)pid, &out_addr, args->length, 0x4000) != 0) return 1;
args->address = out_addr;
return 0;
}
case SYS_PROC_ALLOC_HINTED: {
struct sys_proc_alloc_args *args = (struct sys_proc_alloc_args *)data;
uint64_t out_addr = args->address;
if (proc_remote_alloc((uint32_t)pid, &out_addr, args->length, args->address) != 0) {
args->address = out_addr;
return 1;
}
args->address = out_addr;
return 0;
}
case SYS_PROC_FREE: {
struct sys_proc_free_args *args = (struct sys_proc_free_args *)data;
return proc_remote_free((uint32_t)pid, args->address, args->length);
}
case SYS_PROC_PROTECT: {
struct sys_proc_protect_args *args = (struct sys_proc_protect_args *)data;
return kernel_mprotect((pid_t)pid, (intptr_t)args->address,
args->length, (int)args->prot);
}
case SYS_PROC_CALL:
return proc_remote_call((int)pid, (struct sys_proc_call_args *)data);
case SYS_PROC_ELF: {
struct sys_proc_elf_args *args = (struct sys_proc_elf_args *)data;
long elf_rc = sys_proc_elf((unsigned long)pid,
(unsigned long)(uintptr_t)args->elf,
(unsigned long)args->length);
return elf_rc != 0 ? 1 : 0;
}
case SYS_PROC_ELF_RPC: {
struct sys_proc_elf_rpc_args *args = (struct sys_proc_elf_rpc_args *)data;
uint64_t entry = 0;
long elf_rc = sys_proc_elf_rpc((unsigned long)pid,
(unsigned long)(uintptr_t)args->elf,
(unsigned long)args->length,
&entry);
args->entry = entry;
return elf_rc != 0 ? 1 : 0;
}
case SYS_PROC_INSTALL:
case SYS_PROC_INFO:
case SYS_PROC_THRINFO:
default:
return 1;
}
}