├── Makefile ├── PS4API.bin ├── README.md ├── include ├── commandHandlers.h ├── defines.h ├── global.h ├── kernel.h ├── process.h └── sock.h └── source └── main.c /Makefile: -------------------------------------------------------------------------------- 1 | LIBPS4 := $(PS4SDK)/libPS4 2 | 3 | TEXT := 0x926200000 4 | DATA := 0x926300000 5 | 6 | CC := gcc 7 | AS := gcc 8 | OBJCOPY := objcopy 9 | ODIR := build 10 | SDIR := source 11 | IDIRS := -I$(LIBPS4)/include -I. -Iinclude 12 | LDIRS := -L$(LIBPS4) -L. -Llib 13 | CFLAGS := $(IDIRS) -O2 -std=c11 -fno-builtin -nostartfiles -nostdlib -Wall -masm=intel -march=btver2 -mtune=btver2 -m64 -mabi=sysv -mcmodel=large -DTEXT_ADDRESS=$(TEXT) -DDATA_ADDRESS=$(DATA) 14 | SFLAGS := -nostartfiles -nostdlib -march=btver2 -mtune=btver2 15 | LFLAGS := $(LDIRS) -Xlinker -T $(LIBPS4)/linker.x -Wl,--build-id=none -Ttext=$(TEXT) -Tdata=$(DATA) 16 | CFILES := $(wildcard $(SDIR)/*.c) 17 | SFILES := $(wildcard $(SDIR)/*.s) 18 | OBJS := $(patsubst $(SDIR)/%.c, $(ODIR)/%.o, $(CFILES)) $(patsubst $(SDIR)/%.s, $(ODIR)/%.o, $(SFILES)) 19 | 20 | LIBS := -lPS4 21 | 22 | TARGET = $(shell basename $(CURDIR)).bin 23 | 24 | $(TARGET): $(ODIR) $(OBJS) 25 | $(CC) $(LIBPS4)/crt0.s $(ODIR)/*.o -o temp.t $(CFLAGS) $(LFLAGS) $(LIBS) 26 | $(OBJCOPY) -O binary temp.t $(TARGET) 27 | rm -f temp.t 28 | 29 | $(ODIR)/%.o: $(SDIR)/%.c 30 | $(CC) -c -o $@ $< $(CFLAGS) 31 | 32 | $(ODIR)/%.o: $(SDIR)/%.s 33 | $(AS) -c -o $@ $< $(SFLAGS) 34 | 35 | $(ODIR): 36 | @mkdir $@ 37 | 38 | s: clean $(TARGET) 39 | nc -w 3 192.168.100.8 9020 < $(TARGET) 40 | 41 | .PHONY: clean 42 | 43 | clean: 44 | rm -f $(TARGET) $(ODIR)/*.o 45 | -------------------------------------------------------------------------------- /PS4API.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xwal/PS4-API-SERVER/49e18d44ca6f5674826dff31842b09c05cab5a13/PS4API.bin -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PS4API Server 2 | 3 | This project allows you to control PS4 game memory for reading/writing calls. 4 | with this project you can make RTE/RTM tools 5 | 6 | 7 | ## Installation 8 | 9 | use [CTurt's PS4 SDK from xvortex's repository](https://github.com/xvortex/ps4-payload-sdk). 10 | then follow the instructions on how to add the sdk path to your environment. 11 | 12 | ## Usage 13 | 14 | char sendCommand(char command, void* args); 15 | 16 | commands: 17 | 18 | * 'a' attach to game process ( eboot.bin ) and the process will continued. 19 | * 'c' continue the process. 20 | * 'd' detach the process. 21 | * 's' suspend the process. 22 | * 'u' resume the process. 23 | * 'k' kill the process (seems not works) 24 | * 'n' send notification with text. 25 | * 'r' read memory. 26 | * 'w' write memory. 27 | 28 | args: 29 | 30 | * 'a'(void); 31 | * 'c'(void); 32 | * 'd'(void); 33 | * 's'(void); 34 | * 'u'(void); 35 | * 'k'(void); 36 | * 'n'(char text[]); 37 | * 'r'(unsigned int length, unsigned long int address); 38 | * 'w'(unsigned int length, unsigned long int address, char data[]); 39 | 40 | 41 | 42 | 43 | ## Contributing 44 | 45 | 1. Fork it! 46 | 2. Create your feature branch: `git checkout -b my-new-feature` 47 | 3. Commit your changes: `git commit -am 'Add some feature'` 48 | 4. Push to the branch: `git push origin my-new-feature` 49 | 5. Submit a pull request :D 50 | 51 | 52 | ## Credits 53 | 54 | CTurt -> the SDK. 55 | Specter -> exploit implementation. 56 | IDC, xvortex, 2much4u, who else I missed (message me for the Credits) 57 | -------------------------------------------------------------------------------- /include/commandHandlers.h: -------------------------------------------------------------------------------- 1 | #define MAX_PAYLOAD_LENGTH 512 2 | #define MAX_READ_LENGTH 1024 //NOT APPLIED FOR THE READER YET 3 | #define MAX_RECEIVE_LENGTH 1024 4 | 5 | #define GAME_PROCESS_1 "eboot.bin" 6 | #define GAME_PROCESS_2 "default_mp.elf" 7 | #define GAME_PROCESS_3 "default.elf" 8 | 9 | 10 | #define LENGTH_IS_NOT_CORRECT -2 11 | #define NO_PAYLOAD_RECEIVED -3 12 | #define READ_WRITE_FAILED -4 13 | #define UNKNOWN_COMMAND -5 14 | 15 | int attachedPid; 16 | 17 | typedef struct command{ 18 | char commandChar; 19 | int minLength; 20 | void (*handler)(const char* in, unsigned int inLength); 21 | } command_s; 22 | 23 | typedef struct client_io{ 24 | char commandChar; 25 | unsigned int length; 26 | unsigned long int address; 27 | } client_io_s; 28 | 29 | typedef struct clientReplyDate{ 30 | char code; 31 | int datalength; 32 | char*returnData; 33 | }clientReplyDate_s; 34 | 35 | 36 | void replyToClient(int clientfd, const clientReplyDate_s* clientData) 37 | { 38 | unsigned int dataToReplyLen = clientData->datalength; 39 | if (!clientData->returnData) 40 | { 41 | dataToReplyLen = 0; 42 | } 43 | char dataToReply[dataToReplyLen + 1]; 44 | 45 | dataToReply[0] = clientData->code; 46 | 47 | if (dataToReplyLen > 0) 48 | { 49 | for (unsigned int i = 0; i < dataToReplyLen; i++) { 50 | dataToReply[i + 1] = clientData->returnData[i]; 51 | } 52 | } 53 | unsigned int dataToSendLength = dataToReplyLen ? dataToReplyLen + 1 : 1; 54 | sendToClient(clientfd, dataToReply, dataToSendLength); 55 | } 56 | void writerHandler(const char* in, unsigned int inDataLength) 57 | { 58 | client_io_s cmdLine = *(client_io_s*)in; // length & address, beyond that is the payload 59 | clientReplyDate_s clientReply = {0, 0, 0}; 60 | if (cmdLine.length < 1) 61 | { 62 | clientReply.code = LENGTH_IS_NOT_CORRECT; 63 | goto exitMe; 64 | } 65 | 66 | int client_ioSize = sizeof(client_io_s); 67 | int payloadLength = inDataLength - client_ioSize; 68 | payloadLength = payloadLength > MAX_PAYLOAD_LENGTH ? MAX_PAYLOAD_LENGTH : payloadLength; 69 | if (!payloadLength) 70 | { 71 | clientReply.code = NO_PAYLOAD_RECEIVED; 72 | goto exitMe; 73 | } 74 | if (payloadLength < cmdLine.length){ 75 | cmdLine.length = payloadLength; 76 | }; 77 | 78 | unsigned char* payload = ((unsigned char*)in) + client_ioSize; 79 | 80 | if (writeMemory(attachedPid, (void*)cmdLine.address, payload, cmdLine.length) != 0) 81 | { 82 | clientReply.code = READ_WRITE_FAILED; 83 | goto exitMe; 84 | } 85 | clientReply.code = 0; 86 | exitMe: 87 | replyToClient(clientSockFd, &clientReply); 88 | } 89 | 90 | void readerHandler(const char* in, unsigned int inDataLength) 91 | { 92 | client_io_s cmdLine = *(client_io_s*)in; 93 | clientReplyDate_s clientReply = {0, 0, 0}; 94 | if (cmdLine.length < 1) 95 | { 96 | clientReply.code = LENGTH_IS_NOT_CORRECT; 97 | goto exitMe; 98 | } 99 | int lengthToAllocate = cmdLine.length + 1; 100 | clientReply.returnData = (char*)calloc(lengthToAllocate, 1); 101 | clientReply.datalength = cmdLine.length; 102 | if (readMemory(attachedPid, (void*)cmdLine.address, clientReply.returnData, clientReply.datalength) < 0) 103 | { 104 | clientReply.code = READ_WRITE_FAILED; 105 | goto exitMe; 106 | } 107 | 108 | exitMe: 109 | replyToClient(clientSockFd, &clientReply); 110 | free(clientReply.returnData); 111 | } 112 | 113 | int matchProcess(char* name, int pid){ 114 | if (cmp(name, GAME_PROCESS_1) || cmp(name, GAME_PROCESS_2) || cmp(name, GAME_PROCESS_3)) 115 | return true; 116 | return false; 117 | } 118 | void attachHandler(const char* in, unsigned int inDataLength) 119 | { 120 | int pid = getAllProcess(NULL, matchProcess); 121 | attachedPid = pid; 122 | int result = -1; 123 | errno = 0; 124 | int isAlreadyAttached = processgetVMTimeStamp(pid); 125 | if (isAlreadyAttached == -1 && pid != -1) 126 | result = processAttach(pid); 127 | result = (isAlreadyAttached != -1 || (result == -1 && errno == 16)) ? 0 : result; 128 | clientReplyDate_s clientReply = {result, 0, 0}; 129 | replyToClient(clientSockFd, &clientReply); 130 | } 131 | void detachHandler(const char* in, unsigned int inDataLength) 132 | { 133 | int result = -1; 134 | int pid = attachedPid; 135 | if (pid > 1) 136 | result = processDetach(pid); 137 | clientReplyDate_s clientReply = {result, 0, 0}; 138 | replyToClient(clientSockFd, &clientReply); 139 | } 140 | void suspendHandler(const char* in, unsigned int inDataLength) 141 | { 142 | int result = -1; 143 | int pid = attachedPid; 144 | if (pid > 1) 145 | result = processSuspend(pid); 146 | clientReplyDate_s clientReply = {result, 0, 0}; 147 | replyToClient(clientSockFd, &clientReply); 148 | } 149 | void resumeHandler(const char* in, unsigned int inDataLength) 150 | { 151 | int result = -1; 152 | int pid = attachedPid; 153 | if (pid > 1) 154 | result = processResume(pid); 155 | clientReplyDate_s clientReply = {result, 0, 0}; 156 | replyToClient(clientSockFd, &clientReply); 157 | } 158 | void killHandler(const char* in, unsigned int inDataLength) 159 | { 160 | int result = -1; 161 | int pid = attachedPid; 162 | if (pid > 1) 163 | result = processKill(pid); 164 | clientReplyDate_s clientReply = {result, 0, 0}; 165 | replyToClient(clientSockFd, &clientReply); 166 | } 167 | void continueHandler(const char* in, unsigned int inDataLength) 168 | { 169 | int result = -1; 170 | int pid = attachedPid; 171 | if (pid > 1){ 172 | struct reg rg; 173 | processGetRegs(pid, &rg); 174 | result = processContinue(pid, (void*)rg.r_rip); 175 | } 176 | clientReplyDate_s clientReply = {result, 0, 0}; 177 | replyToClient(clientSockFd, &clientReply); 178 | } 179 | void notfiyHandler(const char* in, unsigned int inDataLength){ 180 | void* commandEntry = (void*)in + 1; 181 | int notificationType = *(int*)commandEntry; 182 | char* text = commandEntry+sizeof(int); 183 | NOTIFYT(notificationType, text); 184 | clientReplyDate_s clientReply = {0, 0, 0}; 185 | replyToClient(clientSockFd, &clientReply); 186 | } 187 | 188 | command_s commands[] = { 189 | {'w', sizeof(client_io_s), writerHandler}, 190 | {'r', sizeof(client_io_s), readerHandler}, 191 | {'a', 1, attachHandler}, 192 | {'d', 1, detachHandler}, 193 | {'s', 1, suspendHandler}, 194 | {'u', 1, resumeHandler}, 195 | {'k', 1, killHandler}, 196 | {'c', 1, continueHandler}, 197 | {'n', 5, notfiyHandler}, 198 | 199 | }; 200 | int lenOfCommands = sizeof(commands)/sizeof(commands[0]); 201 | 202 | void unknownCommandHandler() 203 | { 204 | clientReplyDate_s clientReply = {UNKNOWN_COMMAND, 0, 0}; 205 | replyToClient(clientSockFd, &clientReply); 206 | } 207 | void quitCommandHandler() 208 | { 209 | clientReplyDate_s clientReply = {0, 0, 0}; 210 | replyToClient(clientSockFd, &clientReply); 211 | } -------------------------------------------------------------------------------- /include/defines.h: -------------------------------------------------------------------------------- 1 | #define INFINITE ;; 2 | #define bool char 3 | #define false 0 4 | #define true 1 -------------------------------------------------------------------------------- /include/global.h: -------------------------------------------------------------------------------- 1 | #define NOTIFYT(type, format, ...)\ 2 | do {\ 3 | char bufferForTheSocket[512];\ 4 | sprintf(bufferForTheSocket, format, ##__VA_ARGS__);\ 5 | sceSysUtilSendSystemNotificationWithText(type, bufferForTheSocket);\ 6 | } while(0) 7 | #define NOTIFY(format, ...) NOTIFYT(222, format, ##__VA_ARGS__) 8 | 9 | 10 | int countChars(char* source, char c ) 11 | { 12 | int count = 0; 13 | int index = 0; 14 | char theChar; 15 | while((theChar = *(source + index++)) != '\0') 16 | if (theChar == c) 17 | count++; 18 | return count; 19 | } 20 | 21 | int cmp(char* val1, char* val2){ 22 | return strcmp(val1, val2) == 0; 23 | } -------------------------------------------------------------------------------- /include/kernel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ps4.h" 3 | 4 | #define Inline static inline __attribute__((always_inline)) 5 | #define KERN_XFAST_SYSCALL 0x30EB30 6 | #define KERN_PROCESS_ASLR 0x2862D6 7 | #define KERN_PRISON_0 0xF26010 8 | #define KERN_ROOTVNODE 0x206D250 9 | #define KERN_PTRACE_CHECK_1 0xAC2F1 10 | #define KERN_PTRACE_CHECK_2 0xAC6A2 11 | 12 | #define X86_CR0_WP (1 << 16) 13 | 14 | struct auditinfo_addr { 15 | /* 16 | 4 ai_auid; 17 | 8 ai_mask; 18 | 24 ai_termid; 19 | 4 ai_asid; 20 | 8 ai_flags;r 21 | */ 22 | char useless[184]; 23 | }; 24 | 25 | struct ucred { 26 | uint32_t useless1; 27 | uint32_t cr_uid; // effective user id 28 | uint32_t cr_ruid; // real user id 29 | uint32_t useless2; 30 | uint32_t useless3; 31 | uint32_t cr_rgid; // real group id 32 | uint32_t useless4; 33 | void *useless5; 34 | void *useless6; 35 | void *cr_prison; // jail(2) 36 | void *useless7; 37 | uint32_t useless8; 38 | void *useless9[2]; 39 | void *useless10; 40 | struct auditinfo_addr useless11; 41 | uint32_t *cr_groups; // groups 42 | uint32_t useless12; 43 | }; 44 | 45 | struct filedesc { 46 | void *useless1[3]; 47 | void *fd_rdir; 48 | void *fd_jdir; 49 | }; 50 | 51 | struct proc { 52 | char useless[64]; 53 | struct ucred *p_ucred; 54 | struct filedesc *p_fd; 55 | }; 56 | 57 | struct thread { 58 | void *useless; 59 | struct proc *td_proc; 60 | }; 61 | 62 | int kernelPayload(struct thread *td, void* uap); 63 | 64 | Inline uint64_t readCr0(void) { 65 | uint64_t cr0; 66 | 67 | __asm__ __volatile__( 68 | "movq %0, %%cr0" 69 | : "=r" (cr0) 70 | : : "memory" 71 | ); 72 | 73 | return cr0; 74 | } 75 | 76 | Inline void writeCr0(uint64_t cr0) { 77 | __asm__ __volatile__( 78 | "movq %%cr0, %0" 79 | : : "r" (cr0) 80 | : "memory" 81 | ); 82 | } 83 | 84 | Inline uint8_t* getKernelBase() { 85 | uint32_t lo, hi; 86 | __asm__ __volatile__("rdmsr" : "=a" (lo), "=d" (hi) : "c"(0xC0000082)); 87 | return (uint8_t*)(((uint64_t)lo | ((uint64_t)hi << 32)) - KERN_XFAST_SYSCALL); 88 | } 89 | 90 | int kernelPayload(struct thread *td, void* uap) { 91 | uint8_t* ptrKernel = getKernelBase(); 92 | struct ucred* cred = td->td_proc->p_ucred; 93 | struct filedesc* fd = td->td_proc->p_fd; 94 | 95 | // Escalate privileges 96 | cred->cr_uid = 0; 97 | cred->cr_ruid = 0; 98 | cred->cr_rgid = 0; 99 | cred->cr_groups[0] = 0; 100 | 101 | // Escape sandbox 102 | void** prison0 = (void**)&ptrKernel[KERN_PRISON_0]; 103 | void** rootvnode = (void**)&ptrKernel[KERN_ROOTVNODE]; 104 | cred->cr_prison = *prison0; 105 | fd->fd_rdir = fd->fd_jdir = *rootvnode; 106 | 107 | void *td_ucred = *(void **)(((char *)td) + 304); // p_ucred == td_ucred 108 | 109 | // sceSblACMgrIsSystemUcred 110 | uint64_t *sonyCred = (uint64_t *)(((char *)td_ucred) + 96); 111 | *sonyCred = 0xffffffffffffffff; 112 | 113 | // sceSblACMgrGetDeviceAccessType 114 | uint64_t *sceProcType = (uint64_t *)(((char *)td_ucred) + 88); 115 | *sceProcType = 0x3801000000000013; // Max access 116 | 117 | // sceSblACMgrHasSceProcessCapability 118 | uint64_t *sceProcCap = (uint64_t *)(((char *)td_ucred) + 104); 119 | *sceProcCap = 0xffffffffffffffff; // Sce Process 120 | 121 | // Disable write protection 122 | uint64_t cr0 = readCr0(); 123 | writeCr0(cr0 & ~X86_CR0_WP); 124 | 125 | // Disable ptrace checks 126 | ptrKernel[KERN_PTRACE_CHECK_1] = 0xEB; 127 | *(uint16_t*)&ptrKernel[KERN_PTRACE_CHECK_2] = 0x27EB; 128 | 129 | // Disable process aslr 130 | *(uint16_t*)&ptrKernel[KERN_PROCESS_ASLR] = 0x9090; 131 | 132 | // Enable write protection 133 | writeCr0(cr0); 134 | 135 | return 0; 136 | } -------------------------------------------------------------------------------- /include/process.h: -------------------------------------------------------------------------------- 1 | 2 | // sys/ptrace.h 3 | #define PT_TRACE_ME 0 /* child declares it's being traced */ 4 | #define PT_READ_I 1 /* read word in child's I space */ 5 | #define PT_READ_D 2 /* read word in child's D space */ 6 | /* was PT_READ_U 3 * read word in child's user structure */ 7 | #define PT_WRITE_I 4 /* write word in child's I space */ 8 | #define PT_WRITE_D 5 /* write word in child's D space */ 9 | /* was PT_WRITE_U 6 * write word in child's user structure */ 10 | #define PT_CONTINUE 7 /* continue the child */ 11 | #define PT_KILL 8 /* kill the child process */ 12 | #define PT_STEP 9 /* single step the child */ 13 | #define PT_ATTACH 10 /* trace some running process */ 14 | #define PT_DETACH 11 /* stop tracing a process */ 15 | #define PT_IO 12 /* do I/O to/from stopped process. */ 16 | #define PT_LWPINFO 13 /* Info about the LWP that stopped. */ 17 | #define PT_GETNUMLWPS 14 /* get total number of threads */ 18 | #define PT_GETLWPLIST 15 /* get thread list */ 19 | #define PT_CLEARSTEP 16 /* turn off single step */ 20 | #define PT_SETSTEP 17 /* turn on single step */ 21 | #define PT_SUSPEND 18 /* suspend a thread */ 22 | #define PT_RESUME 19 /* resume a thread */ 23 | #define PT_TO_SCE 20 24 | #define PT_TO_SCX 21 25 | #define PT_SYSCALL 22 26 | #define PT_FOLLOW_FORK 23 27 | #define PT_GETREGS 33 /* get general-purpose registers */ 28 | #define PT_SETREGS 34 /* set general-purpose registers */ 29 | #define PT_GETFPREGS 35 /* get floating-point registers */ 30 | #define PT_SETFPREGS 36 /* set floating-point registers */ 31 | #define PT_GETDBREGS 37 /* get debugging registers */ 32 | #define PT_SETDBREGS 38 /* set debugging registers */ 33 | #define PT_VM_TIMESTAMP 40 /* Get VM version (timestamp) */ 34 | #define PT_VM_ENTRY 41 /* Get VM map (entry) */ 35 | 36 | #define PIOD_READ_D 1 /* Read from D space */ 37 | #define PIOD_WRITE_D 2 /* Write to D space */ 38 | #define PIOD_READ_I 3 /* Read from I space */ 39 | #define PIOD_WRITE_I 4 /* Write to I space */ 40 | 41 | // sys/wait.h 42 | #define WNOHANG 1 /* Don't hang in wait. */ 43 | #define WUNTRACED 2 /* Tell about stopped, untraced children. */ 44 | #define WSTOPPED WUNTRACED /* SUS compatibility */ 45 | #define WCONTINUED 4 /* Report a job control continued process. */ 46 | #define WNOWAIT 8 /* Poll only. Don't delete the proc entry. */ 47 | 48 | /* Argument structure for PT_VM_ENTRY. */ 49 | struct ptrace_vm_entry { 50 | int pve_entry; /* Entry number used for iteration. */ 51 | int pve_timestamp; /* Generation number of VM map. */ 52 | unsigned long pve_start; /* Start VA of range. */ 53 | unsigned long pve_end; /* End VA of range (incl). */ 54 | unsigned long pve_offset; /* Offset in backing object. */ 55 | unsigned int pve_prot; /* Protection of memory range. */ 56 | unsigned int pve_pathlen; /* Size of path. */ 57 | long pve_fileid; /* File ID. */ 58 | uint32_t pve_fsid; /* File system ID. */ 59 | char *pve_path; /* Path name of object. */ 60 | }; 61 | 62 | struct rusage { 63 | struct timeval ru_utime; /* user time used */ 64 | struct timeval ru_stime; /* system time used */ 65 | long ru_maxrss; /* max resident set size */ 66 | #define ru_first ru_ixrss 67 | long ru_ixrss; /* integral shared memory size */ 68 | long ru_idrss; /* integral unshared data " */ 69 | long ru_isrss; /* integral unshared stack " */ 70 | long ru_minflt; /* page reclaims */ 71 | long ru_majflt; /* page faults */ 72 | long ru_nswap; /* swaps */ 73 | long ru_inblock; /* block input operations */ 74 | long ru_oublock; /* block output operations */ 75 | long ru_msgsnd; /* messages sent */ 76 | long ru_msgrcv; /* messages received */ 77 | long ru_nsignals; /* signals received */ 78 | long ru_nvcsw; /* voluntary context switches */ 79 | long ru_nivcsw; /* involuntary " */ 80 | #define ru_last ru_nivcsw 81 | }; 82 | 83 | 84 | //machine/reg.h 85 | typedef long int register_t; 86 | struct reg { 87 | register_t r_r15; 88 | register_t r_r14; 89 | register_t r_r13; 90 | register_t r_r12; 91 | register_t r_r11; 92 | register_t r_r10; 93 | register_t r_r9; 94 | register_t r_r8; 95 | register_t r_rdi; 96 | register_t r_rsi; 97 | register_t r_rbp; 98 | register_t r_rbx; 99 | register_t r_rdx; 100 | register_t r_rcx; 101 | register_t r_rax; 102 | uint32_t r_trapno; 103 | uint16_t r_fs; 104 | uint16_t r_gs; 105 | uint32_t r_err; 106 | uint16_t r_es; 107 | uint16_t r_ds; 108 | register_t r_rip; 109 | register_t r_cs; 110 | register_t r_rflags; 111 | register_t r_rsp; 112 | register_t r_ss; 113 | }; 114 | struct __ptrace_io_desc { 115 | int piod_op; /* I/O operation */ 116 | void *piod_offs; /* child offset */ 117 | void *piod_addr; /* parent offset */ 118 | size_t piod_len; /* request length */ 119 | }; 120 | int getAllProcess(const char* targetProcess, int (*callBack)(char* pname, int pid)) 121 | { 122 | int names[] = {1, 14, 0}; 123 | int namesLength = sizeof(names) / sizeof(names[0]); 124 | unsigned long int lengthOfOldValue; 125 | int sysCtlReturn; 126 | sysCtlReturn = sysctl(names, namesLength, NULL, &lengthOfOldValue, NULL, NULL); 127 | 128 | if (sysCtlReturn == -1) 129 | return -1; 130 | 131 | char* data = (char*)malloc(lengthOfOldValue); 132 | sysCtlReturn = sysctl(names, namesLength, data, &lengthOfOldValue, NULL, NULL); 133 | if (sysCtlReturn == -1) 134 | { 135 | free(data); 136 | return -1; 137 | } 138 | int structSize = 1096; 139 | int procCount = lengthOfOldValue / structSize; 140 | int skipDupProcess = 0; 141 | 142 | for(int i = 0; i < procCount; i++) 143 | { 144 | void* processStructure = (data + (structSize * i)); 145 | int pid = *(int*)(processStructure + 72); 146 | if (skipDupProcess == pid) 147 | continue; 148 | skipDupProcess = pid; 149 | char* name = (char*)(processStructure + 447); 150 | if ((targetProcess != NULL && strcmp(targetProcess, name) == 0)) 151 | return pid; 152 | if (callBack != NULL && callBack(name, pid)) 153 | return pid; 154 | } 155 | free(data); 156 | return -1; 157 | } 158 | int getProcess(const char* procName) 159 | { 160 | return getAllProcess(procName, NULL); 161 | } 162 | int getProcessName(int pid, char* dist){ 163 | int names[] = {1, 14, 1, pid}; //nametomib kern.proc.pid 164 | int namesLength = sizeof(names) / sizeof(names[0]); 165 | unsigned long int lengthOfOldValue; 166 | void* dump = malloc(lengthOfOldValue); 167 | int sysCtlReturn = sysctl(names, namesLength, dump, &lengthOfOldValue, NULL, NULL); 168 | if (sysCtlReturn == -1) 169 | return -1; 170 | char* procName = (char*)(dump + 0x1BF); 171 | strcpy(dist, procName); 172 | free(dump); 173 | return sysCtlReturn; 174 | } 175 | int wait4(int pid, int *status, int options, struct rusage *rusage){ 176 | return syscall(7, pid, status, options, rusage); 177 | } 178 | int __ptrace(int req, int pid, void* addr, int data) { 179 | return syscall(26, req, pid, addr, data); 180 | } 181 | int processSingleStep(int pid){ 182 | return __ptrace(PT_STEP, pid, NULL, NULL); 183 | } 184 | int processClearStep(int pid){ 185 | return __ptrace(PT_CLEARSTEP, pid, NULL, NULL); 186 | } 187 | int processContinue(int pid, void* address){ 188 | return __ptrace(PT_CONTINUE, pid, address, NULL); 189 | } 190 | int processSuspend(int pid){ 191 | return __ptrace(PT_SUSPEND, pid, NULL, NULL); 192 | } 193 | int processResume(int pid){ 194 | return __ptrace(PT_RESUME, pid, NULL, NULL); 195 | } 196 | int processKill(int pid) 197 | { 198 | return __ptrace(PT_KILL, pid, NULL, NULL); 199 | } 200 | int processGetRegs(int pid, struct reg* rg){ 201 | return __ptrace(PT_GETREGS, pid, (void*)rg, NULL); 202 | } 203 | int processAttach(int pid) { 204 | 205 | int res = __ptrace(PT_ATTACH, pid, NULL, NULL); 206 | if (res != 0) 207 | return res; 208 | int status = 0; 209 | wait4(pid, &status, WUNTRACED, NULL); 210 | 211 | struct reg rg; 212 | processGetRegs(pid, &rg); 213 | processContinue(pid, (void*)rg.r_rip); 214 | return res; 215 | } 216 | 217 | int processDetach(int pid) { 218 | return __ptrace(PT_DETACH, pid, NULL, NULL); 219 | } 220 | int processgetVMTimeStamp(int pid){ 221 | return __ptrace(PT_VM_TIMESTAMP, pid, NULL, NULL); 222 | } 223 | int getVMEntry(int pid, struct ptrace_vm_entry* entryStructure){ 224 | return __ptrace(PT_VM_ENTRY, pid, entryStructure, NULL); 225 | } 226 | int processReadBytes(int pid, void* offset, void* buffer, size_t len) { 227 | struct __ptrace_io_desc pt_desc; 228 | pt_desc.piod_op = PIOD_READ_D; 229 | pt_desc.piod_addr = buffer; 230 | pt_desc.piod_offs = offset; 231 | pt_desc.piod_len = len; 232 | return __ptrace(PT_IO, pid, &pt_desc, NULL); 233 | } 234 | int processWriteBytes(int pid, void* offset, void *buffer, size_t len) { 235 | struct __ptrace_io_desc pt_desc; 236 | pt_desc.piod_op = PIOD_WRITE_D; 237 | pt_desc.piod_addr = buffer; 238 | pt_desc.piod_offs = offset; 239 | pt_desc.piod_len = len; 240 | return __ptrace(PT_IO, pid, &pt_desc, NULL); 241 | } 242 | int writeMemory(int pid, void* offset, void *buffer, size_t len) 243 | { 244 | int res = processWriteBytes(pid, offset, buffer, len); 245 | return res; 246 | } 247 | int readMemory(int pid, void* offset, void *buffer, size_t len) 248 | { 249 | int res = processReadBytes(pid, offset, buffer, len); 250 | return res; 251 | } 252 | -------------------------------------------------------------------------------- /include/sock.h: -------------------------------------------------------------------------------- 1 | 2 | #define LOG_IP IP(192, 168, 100, 2) 3 | #define LOG_PORT 9023 4 | #define SERVER_PORT 9090 5 | #define BACK_LOG 1 6 | #undef LOG 7 | 8 | #define PORT_RANGE_POSSIBILITY 3 9 | 10 | int logSock = -1; 11 | int serverSockFd = -1; 12 | int clientSockFd; 13 | #define PRINTS(format, ...)\ 14 | do {\ 15 | char bufferForTheSocket[512];\ 16 | int size = sprintf(bufferForTheSocket, format, ##__VA_ARGS__);\ 17 | sceNetSend(logSock, bufferForTheSocket, size, 0);\ 18 | } while(0) 19 | 20 | void initLog() 21 | { 22 | struct sockaddr_in logSocket; 23 | logSocket.sin_family = AF_INET; 24 | logSocket.sin_port = sceNetHtons(LOG_PORT); 25 | logSocket.sin_addr.s_addr = LOG_IP; 26 | memset(logSocket.sin_zero, 0, sizeof(logSocket.sin_zero)); 27 | logSocket.sin_len = sizeof(logSocket); 28 | logSock = sceNetSocket("SOCK", AF_INET, SOCK_STREAM, 0); 29 | 30 | if (logSock < 0) 31 | return; 32 | 33 | sceNetConnect(logSock, (struct sockaddr*)&logSocket, sizeof(logSocket)); 34 | } 35 | void closeLog() 36 | { 37 | sceNetSocketClose(logSock); 38 | } 39 | void initServer(int port) 40 | { 41 | struct sockaddr_in serverSocket; 42 | serverSocket.sin_family = AF_INET; 43 | serverSocket.sin_port = sceNetHtons(port); 44 | serverSocket.sin_addr.s_addr = IN_ADDR_ANY; 45 | memset(serverSocket.sin_zero, 0, sizeof(serverSocket.sin_zero)); 46 | serverSocket.sin_len = sizeof(serverSocket); 47 | int ret = sceNetSocket("SERVER", AF_INET, SOCK_STREAM, 0); 48 | 49 | if (ret < 0) 50 | return; 51 | int sock = ret; 52 | ret = sceNetBind(sock, (struct sockaddr*)&serverSocket, sizeof(serverSocket)); 53 | if (ret < 0) 54 | return; 55 | 56 | ret = sceNetListen(sock, BACK_LOG); 57 | if (ret < 0) 58 | return; 59 | serverSockFd = sock; 60 | } 61 | void closeServer() 62 | { 63 | sceNetSocketClose(serverSockFd); 64 | } 65 | int initSockets() 66 | { 67 | #ifdef LOG 68 | initLog(); 69 | #else 70 | #define PRINTS(...) 71 | #endif 72 | int severPort = SERVER_PORT; 73 | for(int i = 0; i < PORT_RANGE_POSSIBILITY; i++) 74 | { 75 | initServer(severPort); 76 | if (serverSockFd > 0) 77 | break; 78 | severPort += 1; 79 | } 80 | return serverSockFd > 0; 81 | } 82 | void closeSockets() 83 | { 84 | #ifdef LOG 85 | closeLog(); 86 | #endif 87 | closeServer(); 88 | } 89 | void closeSocket(int sockFd) 90 | { 91 | sceNetSocketClose(sockFd); 92 | } 93 | void abortSendRecv(int sockFd){ 94 | sceNetSocketAbort(sockFd, 1 | 2); 95 | } 96 | int acceptClient(struct sockaddr_in* clientSocket) 97 | { 98 | unsigned int sizeOfSock = sizeof(struct sockaddr_in); 99 | return sceNetAccept(serverSockFd, (struct sockaddr*)clientSocket, &sizeOfSock); 100 | } 101 | int sendToClient(int clientfd, const char* buffer, int length) 102 | { 103 | return sceNetSend(clientfd, buffer, length, 0); 104 | } 105 | 106 | int receiveFromClient(int clientfd, char* buffer, int length) 107 | { 108 | return sceNetRecv(clientfd, buffer, length, 0); 109 | } 110 | void clientIp(struct in_addr* inAddr, char* out) 111 | { 112 | sceNetInetNtop(AF_INET, inAddr, out, /*sizeof(struct in_addr)*/ 16); 113 | } -------------------------------------------------------------------------------- /source/main.c: -------------------------------------------------------------------------------- 1 | #include "ps4.h" 2 | #include "include/defines.h" 3 | #include "include/global.h" 4 | #include "include/kernel.h" 5 | #include "include/sock.h" 6 | #include "include/process.h" 7 | #include "include/commandHandlers.h" 8 | #define VERSION "1.1" 9 | 10 | 11 | #define MSG_CLIENT_CONNECED "Client [%s] connected" 12 | #define MSG_CLIENT_DISCONNECED "Client [%s] disconnected" 13 | #define MSG_CLIENT_THREAD_ERROR "Error handling the client" 14 | 15 | int createThread(void*(func)(void*), void* args) 16 | { 17 | ScePthread sceThread; 18 | return scePthreadCreate(&sceThread, NULL, func, args, "Clien Thread") == 0; 19 | } 20 | 21 | void* clientHandler(void* args) 22 | { 23 | struct sockaddr_in client = *(struct sockaddr_in*)args; 24 | 25 | int locClientSocketFd = clientSockFd; 26 | char clientIP[16];//IPv4 27 | bool gotUnknownCommand = true; 28 | command_s *localCommands = commands; 29 | int localCommandsLength = lenOfCommands; 30 | clientIp(&client.sin_addr, clientIP); 31 | NOTIFY(MSG_CLIENT_CONNECED, clientIP); 32 | for (INFINITE) 33 | { 34 | char bufferOfClient[MAX_RECEIVE_LENGTH] = {0}; 35 | int lenOfReceivedData = receiveFromClient(locClientSocketFd, bufferOfClient, MAX_RECEIVE_LENGTH); 36 | 37 | if (lenOfReceivedData < 1)//Client Disconnected ? 38 | { 39 | NOTIFY(MSG_CLIENT_DISCONNECED, clientIP); 40 | scePthreadExit(NULL); 41 | } 42 | 43 | if (bufferOfClient[0] == 'q') 44 | { 45 | quitCommandHandler(); 46 | closeSocket(locClientSocketFd); 47 | NOTIFY(MSG_CLIENT_DISCONNECED, clientIP); 48 | scePthreadExit(NULL); 49 | } 50 | for (size_t i = 0; i < localCommandsLength; i++) 51 | { 52 | if(localCommands[i].commandChar == bufferOfClient[0] && localCommands[i].minLength <= lenOfReceivedData && localCommands[i].handler != NULL) 53 | { 54 | localCommands[i].handler(bufferOfClient, lenOfReceivedData); 55 | gotUnknownCommand = false; 56 | break; 57 | } 58 | } 59 | if (gotUnknownCommand){ 60 | unknownCommandHandler(); 61 | } 62 | gotUnknownCommand = true; 63 | } 64 | return NULL; 65 | } 66 | 67 | int init(){ 68 | initKernel(); 69 | initLibc(); 70 | initNetwork(); 71 | initSysUtil(); 72 | initPthread(); 73 | kexec(kernelPayload, NULL); 74 | if (initSockets()) 75 | { 76 | NOTIFY("PS4API By BISOON STARTED v%s\n", VERSION); 77 | return 1; 78 | } 79 | else 80 | { 81 | NOTIFY("PS4API: Failed to run the port not available, try again later\n"); 82 | closeSockets(); 83 | return 0; 84 | } 85 | } 86 | int _main(void) { 87 | 88 | if (!init()) 89 | return 1; 90 | 91 | struct sockaddr_in clientStruct; 92 | int clientSocketMonitor = -1; 93 | for (INFINITE) 94 | { 95 | 96 | clientSockFd = acceptClient(&clientStruct); 97 | if (clientSocketMonitor != -1) 98 | { 99 | abortSendRecv(clientSocketMonitor); 100 | closeSocket(clientSocketMonitor); 101 | } 102 | clientSocketMonitor = clientSockFd; 103 | if (!createThread(clientHandler, &clientStruct)) 104 | NOTIFY(MSG_CLIENT_THREAD_ERROR); 105 | } 106 | closeSockets(); 107 | return 0; 108 | } 109 | --------------------------------------------------------------------------------