├── .gitattributes ├── .gitignore ├── .gitmodules ├── README.md ├── build.sh ├── debugger ├── Makefile ├── include │ ├── console.h │ ├── debug.h │ ├── errno.h │ ├── kdbg.h │ ├── kern.h │ ├── net.h │ ├── proc.h │ ├── protocol.h │ ├── ptrace.h │ ├── server.h │ └── sparse.h └── source │ ├── console.c │ ├── debug.c │ ├── kdbg.c │ ├── kern.c │ ├── main.c │ ├── net.c │ ├── proc.c │ ├── ptrace.c │ └── server.c ├── installer ├── Makefile ├── crt0.s ├── include │ ├── elf.h │ ├── installer.h │ ├── proc.h │ ├── rpcasm.h │ └── syscall.h ├── linker.x └── source │ ├── elf.c │ ├── embed.s │ ├── installer.c │ ├── main.c │ ├── proc.c │ └── syscall.s ├── kdebugger ├── Makefile ├── crt0.s ├── include │ ├── elf.h │ ├── hooks.h │ ├── proc.h │ └── rpcasm.h ├── kdebugger.x └── source │ ├── elf.c │ ├── hooks.c │ ├── main.c │ └── proc.c ├── libdebug ├── README.md ├── cpp │ ├── CMakeLists.txt │ ├── example │ │ └── example.cpp │ ├── include │ │ ├── PS4DBG.hpp │ │ ├── Platform.hpp │ │ ├── Process.hpp │ │ └── Registers.hpp │ └── source │ │ ├── PS4DBG.cpp │ │ └── Process.cpp └── csharp │ ├── PS4DBG.Console.cs │ ├── PS4DBG.Debug.cs │ ├── PS4DBG.Kernel.cs │ ├── PS4DBG.Proc.cs │ ├── PS4DBG.cs │ ├── Process.cs │ ├── Properties │ └── AssemblyInfo.cs │ ├── Registers.cs │ └── libdebug.csproj └── send.sh /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.bin 3 | *.elf 4 | *.rar 5 | *.zip 6 | *.dll 7 | *.pdb 8 | temp.t 9 | .vscode 10 | .vs 11 | libdebug/csharp/obj/ 12 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ps4-payload-sdk"] 2 | path = ps4-payload-sdk 3 | url = https://github.com/GiantPluto/ps4-payload-sdk.git 4 | [submodule "ps4-ksdk"] 5 | path = ps4-ksdk 6 | url = https://github.com/Joonie86/ps4-ksdk.git 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ps4debug for 7.55 2 | This is a debugger for the PlayStation 4. Yes thats right! Look around and you will find some very useful tools online or on the PS4 Source Discord channel. Anything is possible, except kernel mode debugging, which I decided to leave out. 3 | 4 | ### Quickstart Guide 5 | I am going to try to give you a little rundown on how to use ps4debug.... 6 | 1. Download Debug Watch or another debugging tool, checkout the discord for downloads 7 | 2. Load the latest version of `ps4debug.bin` on the console (on the release page) 8 | 3. I recommend just loading ps4debug and your choice of HEN 9 | 4. Start your favorite game! 10 | 5. Attach to the game (or userland process) 11 | 6. Start messing around with your debugging tool, try to find a bug for me! 12 | 7. Make l33t hacks. 13 | 14 | Please look at the libdebug folder for a library to use with this payload. 15 | 16 | ### Contributing 17 | If you want to contribute, then feel free to make a pull request or open an issue with a bug that you have found! I am always in need of people to test for me. Join the PS4 Source Discord and look for golden. Also I need someone that is good at writing to spiff up this readme document. I am always in need of people to do work! It seems like I do everything... 18 | 19 | ### Created by **golden** 20 | 21 | ### Contributors 22 | 23 | - ChendoChap - For his intial work till 5.05 and his guidance during 6.72 porting on ptrace 24 | - berkayylmao 25 | - 2much4u 26 | - idc 27 | - zecoxao 28 | - DeathRGH - For second [ptrace](https://github.com/GiantPluto/ps4debug/blob/457c2bf5468329e68a272b5f1e1ab88957f5f2d8/installer/source/installer.c#L53) patch for 6.72 29 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # I decide to just clean it all then build from scratch each go around lol 3 | # golden :P 4 | 5 | clean_build() { 6 | cd ps4-ksdk 7 | make clean 8 | cd .. 9 | 10 | cd ps4-payload-sdk/libPS4/ 11 | make clean 12 | cd ../../ 13 | 14 | cd debugger 15 | make clean 16 | cd .. 17 | 18 | cd kdebugger 19 | make clean 20 | cd .. 21 | 22 | cd installer 23 | make clean 24 | cd .. 25 | } 26 | 27 | build_submodules() { 28 | cd ps4-ksdk 29 | make 30 | cd .. 31 | 32 | cd ps4-payload-sdk/libPS4/ 33 | make 34 | cd ../../ 35 | } 36 | 37 | build_debugger() { 38 | cd debugger 39 | make 40 | cd .. 41 | } 42 | 43 | build_kdebugger() { 44 | cd kdebugger 45 | make 46 | cd .. 47 | } 48 | 49 | build_installer() { 50 | cd installer 51 | make 52 | cd .. 53 | } 54 | 55 | if (( $# == 1 )); 56 | then 57 | if [ $1 == "clean" ] 58 | then 59 | echo "cleaning build..." 60 | clean_build 61 | fi 62 | fi 63 | 64 | echo "ps4debug building..." 65 | 66 | echo "=> submodules..." 67 | build_submodules 68 | echo "=> debugger..." 69 | build_debugger 70 | echo "=> kdebugger..." 71 | build_kdebugger 72 | echo "=> installer..." 73 | build_installer 74 | 75 | cp ./installer/installer.bin ./ps4debug.bin 76 | 77 | echo "" 78 | echo "enjoy ps4debug! golden :P" 79 | -------------------------------------------------------------------------------- /debugger/Makefile: -------------------------------------------------------------------------------- 1 | LIBPS4 := ../ps4-payload-sdk/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 = debugger.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 | .PHONY: clean 39 | 40 | clean: 41 | rm -f $(TARGET) $(ODIR)/*.o 42 | -------------------------------------------------------------------------------- /debugger/include/console.h: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #ifndef _CONSOLE_H 6 | #define _CONSOLE_H 7 | 8 | #include 9 | #include "protocol.h" 10 | #include "net.h" 11 | #include "debug.h" 12 | 13 | int console_reboot_handle(int fd, struct cmd_packet *packet); 14 | int console_print_handle(int fd, struct cmd_packet *packet); 15 | int console_notify_handle(int fd, struct cmd_packet *packet); 16 | int console_info_handle(int fd, struct cmd_packet *packet); 17 | 18 | int console_handle(int fd, struct cmd_packet *packet); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /debugger/include/debug.h: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #ifndef _DEBUG_H 6 | #define _DEBUG_H 7 | 8 | #include 9 | #include "protocol.h" 10 | #include "net.h" 11 | #include "ptrace.h" 12 | 13 | struct __reg64 { 14 | uint64_t r_r15; 15 | uint64_t r_r14; 16 | uint64_t r_r13; 17 | uint64_t r_r12; 18 | uint64_t r_r11; 19 | uint64_t r_r10; 20 | uint64_t r_r9; 21 | uint64_t r_r8; 22 | uint64_t r_rdi; 23 | uint64_t r_rsi; 24 | uint64_t r_rbp; 25 | uint64_t r_rbx; 26 | uint64_t r_rdx; 27 | uint64_t r_rcx; 28 | uint64_t r_rax; 29 | uint32_t r_trapno; 30 | uint16_t r_fs; 31 | uint16_t r_gs; 32 | uint32_t r_err; 33 | uint16_t r_es; 34 | uint16_t r_ds; 35 | uint64_t r_rip; 36 | uint64_t r_cs; 37 | uint64_t r_rflags; 38 | uint64_t r_rsp; 39 | uint64_t r_ss; 40 | }; 41 | 42 | /* Contents of each x87 floating point accumulator */ 43 | struct fpacc87 { 44 | uint8_t fp_bytes[10]; 45 | }; 46 | 47 | /* Contents of each SSE extended accumulator */ 48 | struct xmmacc { 49 | uint8_t xmm_bytes[16]; 50 | }; 51 | 52 | /* Contents of the upper 16 bytes of each AVX extended accumulator */ 53 | struct ymmacc { 54 | uint8_t ymm_bytes[16]; 55 | }; 56 | 57 | struct envxmm { 58 | uint16_t en_cw; /* control word (16bits) */ 59 | uint16_t en_sw; /* status word (16bits) */ 60 | uint8_t en_tw; /* tag word (8bits) */ 61 | uint8_t en_zero; 62 | uint16_t en_opcode; /* opcode last executed (11 bits ) */ 63 | uint64_t en_rip; /* floating point instruction pointer */ 64 | uint64_t en_rdp; /* floating operand pointer */ 65 | uint32_t en_mxcsr; /* SSE sontorol/status register */ 66 | uint32_t en_mxcsr_mask; /* valid bits in mxcsr */ 67 | }; 68 | 69 | struct savefpu { 70 | struct envxmm sv_env; 71 | struct { 72 | struct fpacc87 fp_acc; 73 | uint8_t fp_pad[6]; /* padding */ 74 | } sv_fp[8]; 75 | struct xmmacc sv_xmm[16]; 76 | uint8_t sv_pad[96]; 77 | } __attribute__((aligned(16))); 78 | 79 | struct xstate_hdr { 80 | uint64_t xstate_bv; 81 | uint8_t xstate_rsrv0[16]; 82 | uint8_t xstate_rsrv[40]; 83 | }; 84 | 85 | struct savefpu_xstate { 86 | struct xstate_hdr sx_hd; 87 | struct ymmacc sx_ymm[16]; 88 | }; 89 | 90 | struct savefpu_ymm { 91 | struct envxmm sv_env; 92 | struct { 93 | struct fpacc87 fp_acc; 94 | int8_t fp_pad[6]; /* padding */ 95 | } sv_fp[8]; 96 | struct xmmacc sv_xmm[16]; 97 | uint8_t sv_pad[96]; 98 | struct savefpu_xstate sv_xstate; 99 | } __attribute__((aligned(64))); 100 | 101 | struct __dbreg64 { 102 | uint64_t dr[16]; /* debug registers */ 103 | /* Index 0-3: debug address registers */ 104 | /* Index 4-5: reserved */ 105 | /* Index 6: debug status */ 106 | /* Index 7: debug control */ 107 | /* Index 8-15: reserved */ 108 | }; 109 | 110 | struct debug_interrupt_packet { 111 | uint32_t lwpid; 112 | uint32_t status; 113 | char tdname[40]; 114 | struct __reg64 reg64; 115 | struct savefpu_ymm savefpu; 116 | struct __dbreg64 dbreg64; 117 | } __attribute__((packed)); 118 | #define DEBUG_INTERRUPT_PACKET_SIZE 0x4A0 119 | 120 | #define DBREG_DR7_DISABLE 0x00 121 | #define DBREG_DR7_LOCAL_ENABLE 0x01 122 | #define DBREG_DR7_GLOBAL_ENABLE 0x02 123 | 124 | #define DBREG_DR7_LEN_1 0x00 /* 1 byte length */ 125 | #define DBREG_DR7_LEN_2 0x01 126 | #define DBREG_DR7_LEN_4 0x03 127 | #define DBREG_DR7_LEN_8 0x02 128 | 129 | #define DBREG_DR7_EXEC 0x00 /* break on execute */ 130 | #define DBREG_DR7_WRONLY 0x01 /* break on write */ 131 | #define DBREG_DR7_RDWR 0x03 /* break on read or write */ 132 | 133 | #define DBREG_DR7_MASK(i) ((uint64_t)(0xf) << ((i) * 4 + 16) | 0x3 << (i) * 2) 134 | #define DBREG_DR7_SET(i, len, access, enable) ((uint64_t)((len) << 2 | (access)) << ((i) * 4 + 16) | (enable) << (i) * 2) 135 | #define DBREG_DR7_GD 0x2000 136 | #define DBREG_DR7_ENABLED(d, i) (((d) & 0x3 << (i) * 2) != 0) 137 | #define DBREG_DR7_ACCESS(d, i) ((d) >> ((i) * 4 + 16) & 0x3) 138 | #define DBREG_DR7_LEN(d, i) ((d) >> ((i) * 4 + 18) & 0x3) 139 | 140 | #define DBREG_DRX(d,x) ((d)->dr[(x)]) /* reference dr0 - dr7 by register number */ 141 | 142 | #define DEBUG_PORT 755 143 | 144 | extern int g_debugging; 145 | extern struct server_client *curdbgcli; 146 | extern struct debug_context *curdbgctx; 147 | 148 | int debug_attach_handle(int fd, struct cmd_packet *packet); 149 | int debug_detach_handle(int fd, struct cmd_packet *packet); 150 | int debug_breakpt_handle(int fd, struct cmd_packet *packet); 151 | int debug_watchpt_handle(int fd, struct cmd_packet *packet); 152 | int debug_threads_handle(int fd, struct cmd_packet *packet); 153 | int debug_stopthr_handle(int fd, struct cmd_packet *packet); 154 | int debug_resumethr_handle(int fd, struct cmd_packet *packet); 155 | int debug_getregs_handle(int fd, struct cmd_packet *packet); 156 | int debug_setregs_handle(int fd, struct cmd_packet *packet); 157 | int debug_getfpregs_handle(int fd, struct cmd_packet *packet); 158 | int debug_setfpregs_handle(int fd, struct cmd_packet *packet); 159 | int debug_getdbregs_handle(int fd, struct cmd_packet *packet); 160 | int debug_setdbregs_handle(int fd, struct cmd_packet *packet); 161 | int debug_stopgo_handle(int fd, struct cmd_packet *packet); 162 | int debug_thrinfo_handle(int fd, struct cmd_packet *packet); 163 | int debug_singlestep_handle(int fd, struct cmd_packet *packet); 164 | 165 | int connect_debugger(struct debug_context *dbgctx, struct sockaddr_in *client); 166 | void debug_cleanup(struct debug_context *dbgctx); 167 | 168 | int debug_handle(int fd, struct cmd_packet *packet); 169 | 170 | #endif 171 | -------------------------------------------------------------------------------- /debugger/include/errno.h: -------------------------------------------------------------------------------- 1 | #ifndef _ERRNO_H 2 | #define _ERRNO_H 3 | 4 | #define EPERM 1 /* Operation not permitted */ 5 | #define ENOENT 2 /* No such file or directory */ 6 | #define ESRCH 3 /* No such process */ 7 | #define EINTR 4 /* Interrupted system call */ 8 | #define EIO 5 /* Input/output error */ 9 | #define ENXIO 6 /* Device not configured */ 10 | #define E2BIG 7 /* Argument list too long */ 11 | #define ENOEXEC 8 /* Exec format error */ 12 | #define EBADF 9 /* Bad file descriptor */ 13 | #define ECHILD 10 /* No child processes */ 14 | #define EDEADLK 11 /* Resource deadlock avoided */ 15 | /* 11 was EAGAIN */ 16 | #define ENOMEM 12 /* Cannot allocate memory */ 17 | #define EACCES 13 /* Permission denied */ 18 | #define EFAULT 14 /* Bad address */ 19 | #ifndef _POSIX_SOURCE 20 | #define ENOTBLK 15 /* Block device required */ 21 | #endif 22 | #define EBUSY 16 /* Device busy */ 23 | #define EEXIST 17 /* File exists */ 24 | #define EXDEV 18 /* Cross-device link */ 25 | #define ENODEV 19 /* Operation not supported by device */ 26 | #define ENOTDIR 20 /* Not a directory */ 27 | #define EISDIR 21 /* Is a directory */ 28 | #define EINVAL 22 /* Invalid argument */ 29 | #define ENFILE 23 /* Too many open files in system */ 30 | #define EMFILE 24 /* Too many open files */ 31 | #define ENOTTY 25 /* Inappropriate ioctl for device */ 32 | #ifndef _POSIX_SOURCE 33 | #define ETXTBSY 26 /* Text file busy */ 34 | #endif 35 | #define EFBIG 27 /* File too large */ 36 | #define ENOSPC 28 /* No space left on device */ 37 | #define ESPIPE 29 /* Illegal seek */ 38 | #define EROFS 30 /* Read-only filesystem */ 39 | #define EMLINK 31 /* Too many links */ 40 | #define EPIPE 32 /* Broken pipe */ 41 | 42 | /* math software */ 43 | #define EDOM 33 /* Numerical argument out of domain */ 44 | #define ERANGE 34 /* Result too large */ 45 | 46 | /* non-blocking and interrupt i/o */ 47 | #define EAGAIN 35 /* Resource temporarily unavailable */ 48 | #ifndef _POSIX_SOURCE 49 | #define EWOULDBLOCK EAGAIN /* Operation would block */ 50 | #define EINPROGRESS 36 /* Operation now in progress */ 51 | #define EALREADY 37 /* Operation already in progress */ 52 | 53 | /* ipc/network software -- argument errors */ 54 | #define ENOTSOCK 38 /* Socket operation on non-socket */ 55 | #define EDESTADDRREQ 39 /* Destination address required */ 56 | #define EMSGSIZE 40 /* Message too long */ 57 | #define EPROTOTYPE 41 /* Protocol wrong type for socket */ 58 | #define ENOPROTOOPT 42 /* Protocol not available */ 59 | #define EPROTONOSUPPORT 43 /* Protocol not supported */ 60 | #define ESOCKTNOSUPPORT 44 /* Socket type not supported */ 61 | #define EOPNOTSUPP 45 /* Operation not supported */ 62 | #define ENOTSUP EOPNOTSUPP /* Operation not supported */ 63 | #define EPFNOSUPPORT 46 /* Protocol family not supported */ 64 | #define EAFNOSUPPORT 47 /* Address family not supported by protocol family */ 65 | #define EADDRINUSE 48 /* Address already in use */ 66 | #define EADDRNOTAVAIL 49 /* Can't assign requested address */ 67 | 68 | /* ipc/network software -- operational errors */ 69 | #define ENETDOWN 50 /* Network is down */ 70 | #define ENETUNREACH 51 /* Network is unreachable */ 71 | #define ENETRESET 52 /* Network dropped connection on reset */ 72 | #define ECONNABORTED 53 /* Software caused connection abort */ 73 | #define ECONNRESET 54 /* Connection reset by peer */ 74 | #define ENOBUFS 55 /* No buffer space available */ 75 | #define EISCONN 56 /* Socket is already connected */ 76 | #define ENOTCONN 57 /* Socket is not connected */ 77 | #define ESHUTDOWN 58 /* Can't send after socket shutdown */ 78 | #define ETOOMANYREFS 59 /* Too many references: can't splice */ 79 | #define ETIMEDOUT 60 /* Operation timed out */ 80 | #define ECONNREFUSED 61 /* Connection refused */ 81 | 82 | #define ELOOP 62 /* Too many levels of symbolic links */ 83 | #endif /* _POSIX_SOURCE */ 84 | #define ENAMETOOLONG 63 /* File name too long */ 85 | 86 | /* should be rearranged */ 87 | #ifndef _POSIX_SOURCE 88 | #define EHOSTDOWN 64 /* Host is down */ 89 | #define EHOSTUNREACH 65 /* No route to host */ 90 | #endif /* _POSIX_SOURCE */ 91 | #define ENOTEMPTY 66 /* Directory not empty */ 92 | 93 | /* quotas & mush */ 94 | #ifndef _POSIX_SOURCE 95 | #define EPROCLIM 67 /* Too many processes */ 96 | #define EUSERS 68 /* Too many users */ 97 | #define EDQUOT 69 /* Disc quota exceeded */ 98 | 99 | /* Network File System */ 100 | #define ESTALE 70 /* Stale NFS file handle */ 101 | #define EREMOTE 71 /* Too many levels of remote in path */ 102 | #define EBADRPC 72 /* RPC struct is bad */ 103 | #define ERPCMISMATCH 73 /* RPC version wrong */ 104 | #define EPROGUNAVAIL 74 /* RPC prog. not avail */ 105 | #define EPROGMISMATCH 75 /* Program version wrong */ 106 | #define EPROCUNAVAIL 76 /* Bad procedure for program */ 107 | #endif /* _POSIX_SOURCE */ 108 | 109 | #define ENOLCK 77 /* No locks available */ 110 | #define ENOSYS 78 /* Function not implemented */ 111 | 112 | #ifndef _POSIX_SOURCE 113 | #define EFTYPE 79 /* Inappropriate file type or format */ 114 | #define EAUTH 80 /* Authentication error */ 115 | #define ENEEDAUTH 81 /* Need authenticator */ 116 | #define EIDRM 82 /* Identifier removed */ 117 | #define ENOMSG 83 /* No message of desired type */ 118 | #define EOVERFLOW 84 /* Value too large to be stored in data type */ 119 | #define ECANCELED 85 /* Operation canceled */ 120 | #define EILSEQ 86 /* Illegal byte sequence */ 121 | #define ENOATTR 87 /* Attribute not found */ 122 | 123 | #define EDOOFUS 88 /* Programming error */ 124 | #endif /* _POSIX_SOURCE */ 125 | 126 | #define EBADMSG 89 /* Bad message */ 127 | #define EMULTIHOP 90 /* Multihop attempted */ 128 | #define ENOLINK 91 /* Link has been severed */ 129 | #define EPROTO 92 /* Protocol error */ 130 | 131 | #ifndef _POSIX_SOURCE 132 | #define ENOTCAPABLE 93 /* Capabilities insufficient */ 133 | #define ECAPMODE 94 /* Not permitted in capability mode */ 134 | #define ENOTRECOVERABLE 95 /* State not recoverable */ 135 | #define EOWNERDEAD 96 /* Previous owner died */ 136 | #endif /* _POSIX_SOURCE */ 137 | 138 | #ifndef _POSIX_SOURCE 139 | #define ELAST 96 /* Must be equal largest errno */ 140 | #endif /* _POSIX_SOURCE */ 141 | 142 | /* pseudo-errors returned inside kernel to modify return to process */ 143 | #define ERESTART (-1) /* restart syscall */ 144 | #define EJUSTRETURN (-2) /* don't modify regs, just return */ 145 | #define ENOIOCTL (-3) /* ioctl not handled by this layer */ 146 | #define EDIRIOCTL (-4) /* do direct ioctl in GEOM */ 147 | #define ERELOOKUP (-5) /* retry the directory lookup */ 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /debugger/include/kdbg.h: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #ifndef _KDEBUGGER_H 6 | #define _KDEBUGGER_H 7 | 8 | #include 9 | #include 10 | 11 | void prefault(void *address, size_t size); 12 | void *pfmalloc(size_t size); 13 | void hexdump(void *data, size_t size); 14 | 15 | // custom syscall 107 16 | struct proc_list_entry { 17 | char p_comm[32]; 18 | int pid; 19 | } __attribute__((packed)); 20 | int sys_proc_list(struct proc_list_entry *procs, uint64_t *num); 21 | 22 | // custom syscall 108 23 | int sys_proc_rw(uint64_t pid, uint64_t address, void *data, uint64_t length, uint64_t write); 24 | 25 | // custom syscall 109 26 | #define SYS_PROC_ALLOC 1 27 | #define SYS_PROC_FREE 2 28 | #define SYS_PROC_PROTECT 3 29 | #define SYS_PROC_VM_MAP 4 30 | #define SYS_PROC_INSTALL 5 31 | #define SYS_PROC_CALL 6 32 | #define SYS_PROC_ELF 7 33 | #define SYS_PROC_INFO 8 34 | #define SYS_PROC_THRINFO 9 35 | struct sys_proc_alloc_args { 36 | uint64_t address; 37 | uint64_t length; 38 | } __attribute__((packed)); 39 | struct sys_proc_free_args { 40 | uint64_t address; 41 | uint64_t length; 42 | } __attribute__((packed)); 43 | struct sys_proc_protect_args { 44 | uint64_t address; 45 | uint64_t length; 46 | uint64_t prot; 47 | } __attribute__((packed)); 48 | struct sys_proc_vm_map_args { 49 | struct proc_vm_map_entry *maps; 50 | uint64_t num; 51 | } __attribute__((packed)); 52 | struct sys_proc_install_args { 53 | uint64_t stubentryaddr; 54 | } __attribute__((packed)); 55 | struct sys_proc_call_args { 56 | uint32_t pid; 57 | uint64_t rpcstub; 58 | uint64_t rax; 59 | uint64_t rip; 60 | uint64_t rdi; 61 | uint64_t rsi; 62 | uint64_t rdx; 63 | uint64_t rcx; 64 | uint64_t r8; 65 | uint64_t r9; 66 | } __attribute__((packed)); 67 | struct sys_proc_elf_args { 68 | void *elf; 69 | } __attribute__((packed)); 70 | struct sys_proc_info_args { 71 | int pid; 72 | char name[40]; 73 | char path[64]; 74 | char titleid[16]; 75 | char contentid[64]; 76 | } __attribute__((packed)); 77 | struct sys_proc_thrinfo_args { 78 | uint32_t lwpid; 79 | uint32_t priority; 80 | char name[32]; 81 | } __attribute__((packed)); 82 | int sys_proc_cmd(uint64_t pid, uint64_t cmd, void *data); 83 | 84 | // custom syscall 110 85 | int sys_kern_base(uint64_t *kbase); 86 | 87 | // custom syscall 111 88 | int sys_kern_rw(uint64_t address, void *data, uint64_t length, uint64_t write); 89 | 90 | // custom syscall 112 91 | #define SYS_CONSOLE_CMD_REBOOT 1 92 | #define SYS_CONSOLE_CMD_PRINT 2 93 | #define SYS_CONSOLE_CMD_JAILBREAK 3 94 | int sys_console_cmd(uint64_t cmd, void *data); 95 | 96 | #define uprintf(fmt, ...) { char buffer[256]; snprintf(buffer, 256, fmt, ##__VA_ARGS__); sys_console_cmd(SYS_CONSOLE_CMD_PRINT, buffer); } 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /debugger/include/kern.h: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #ifndef _KERN_H 6 | #define _KERN_H 7 | 8 | #include 9 | #include "protocol.h" 10 | #include "net.h" 11 | 12 | int kern_base_handle(int fd, struct cmd_packet *packet); 13 | int kern_read_handle(int fd, struct cmd_packet *packet); 14 | int kern_write_handle(int fd, struct cmd_packet *packet); 15 | 16 | int kern_handle(int fd, struct cmd_packet *packet); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /debugger/include/net.h: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #ifndef _NET_H 6 | #define _NET_H 7 | 8 | #include 9 | #include "errno.h" 10 | 11 | #define NET_MAX_LENGTH 8192 12 | 13 | #define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */ 14 | #define SO_LINGER 0x0080 /* linger on close if data present */ 15 | #define SO_NOSIGPIPE 0x0800 /* no SIGPIPE from EPIPE */ 16 | #define SO_SNDBUF 0x1001 /* send buffer size */ 17 | #define SO_RCVBUF 0x1002 /* receive buffer size */ 18 | #define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */ 19 | #define SO_LINGER 0x0080 /* linger on close if data present */ 20 | #define SO_NOSIGPIPE 0x0800 /* no SIGPIPE from EPIPE */ 21 | #define SO_SNDBUF 0x1001 /* send buffer size */ 22 | #define SO_RCVBUF 0x1002 /* receive buffer size */ 23 | #define SO_DEBUG 0x00000001 /* turn on debugging info recording */ 24 | #define SO_ACCEPTCONN 0x00000002 /* socket has had listen() */ 25 | #define SO_REUSEADDR 0x00000004 /* allow local address reuse */ 26 | #define SO_KEEPALIVE 0x00000008 /* keep connections alive */ 27 | #define SO_DONTROUTE 0x00000010 /* just use interface addresses */ 28 | #define SO_BROADCAST 0x00000020 /* permit sending of broadcast msgs */ 29 | 30 | // I would like to move away from the stupid sony wrapper functions 31 | // They do not always return what I expect and I want to use straight syscalls 32 | 33 | #define FD_SETSIZE 1024 34 | typedef unsigned long fd_mask; 35 | 36 | typedef struct { 37 | unsigned long fds_bits[FD_SETSIZE / 8 / sizeof(long)]; 38 | } fd_set; 39 | 40 | #define FD_ZERO(s) do { int __i; unsigned long *__b=(s)->fds_bits; for(__i=sizeof (fd_set)/sizeof (long); __i; __i--) *__b++=0; } while(0) 41 | #define FD_SET(d, s) ((s)->fds_bits[(d)/(8*sizeof(long))] |= (1UL<<((d)%(8*sizeof(long))))) 42 | #define FD_CLR(d, s) ((s)->fds_bits[(d)/(8*sizeof(long))] &= ~(1UL<<((d)%(8*sizeof(long))))) 43 | #define FD_ISSET(d, s) !!((s)->fds_bits[(d)/(8*sizeof(long))] & (1UL<<((d)%(8*sizeof(long))))) 44 | 45 | int net_select(int fd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 46 | 47 | int net_send_data(int fd, void *data, int length); 48 | int net_recv_data(int fd, void *data, int length, int force); 49 | int net_send_status(int fd, uint32_t status); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /debugger/include/proc.h: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #ifndef _PROC_H 6 | #define _PROC_H 7 | 8 | #include 9 | #include 10 | #include "protocol.h" 11 | #include "net.h" 12 | 13 | struct proc_vm_map_entry { 14 | char name[32]; 15 | uint64_t start; 16 | uint64_t end; 17 | uint64_t offset; 18 | uint16_t prot; 19 | } __attribute__((packed)); 20 | 21 | int proc_list_handle(int fd, struct cmd_packet *packet); 22 | int proc_read_handle(int fd, struct cmd_packet *packet); 23 | int proc_write_handle(int fd, struct cmd_packet *packet); 24 | int proc_maps_handle(int fd, struct cmd_packet *packet); 25 | int proc_install_handle(int fd, struct cmd_packet *packet); 26 | int proc_call_handle(int fd, struct cmd_packet *packet); 27 | int proc_protect_handle(int fd, struct cmd_packet *packet); 28 | int proc_scan_handle(int fd, struct cmd_packet *packet); 29 | int proc_info_handle(int fd, struct cmd_packet *packet); 30 | int proc_alloc_handle(int fd, struct cmd_packet *packet); 31 | int proc_free_handle(int fd, struct cmd_packet *packet); 32 | 33 | int proc_handle(int fd, struct cmd_packet *packet); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /debugger/include/protocol.h: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #ifndef _PROTOCOL_H 6 | #define _PROTOCOL_H 7 | 8 | #include 9 | #include "errno.h" 10 | #include "kdbg.h" 11 | 12 | #define PACKET_VERSION "1.2" 13 | #define PACKET_MAGIC 0xFFAABBCC 14 | 15 | #define CMD_VERSION 0xBD000001 16 | 17 | #define CMD_PROC_LIST 0xBDAA0001 18 | #define CMD_PROC_READ 0xBDAA0002 19 | #define CMD_PROC_WRITE 0xBDAA0003 20 | #define CMD_PROC_MAPS 0xBDAA0004 21 | #define CMD_PROC_INTALL 0xBDAA0005 22 | #define CMD_PROC_CALL 0xBDAA0006 23 | #define CMD_PROC_ELF 0xBDAA0007 24 | #define CMD_PROC_PROTECT 0xBDAA0008 25 | #define CMD_PROC_SCAN 0xBDAA0009 26 | #define CMD_PROC_INFO 0xBDAA000A 27 | #define CMD_PROC_ALLOC 0xBDAA000B 28 | #define CMD_PROC_FREE 0xBDAA000C 29 | 30 | #define CMD_DEBUG_ATTACH 0xBDBB0001 31 | #define CMD_DEBUG_DETACH 0xBDBB0002 32 | #define CMD_DEBUG_BREAKPT 0xBDBB0003 33 | #define CMD_DEBUG_WATCHPT 0xBDBB0004 34 | #define CMD_DEBUG_THREADS 0xBDBB0005 35 | #define CMD_DEBUG_STOPTHR 0xBDBB0006 36 | #define CMD_DEBUG_RESUMETHR 0xBDBB0007 37 | #define CMD_DEBUG_GETREGS 0xBDBB0008 38 | #define CMD_DEBUG_SETREGS 0xBDBB0009 39 | #define CMD_DEBUG_GETFPREGS 0xBDBB000A 40 | #define CMD_DEBUG_SETFPREGS 0xBDBB000B 41 | #define CMD_DEBUG_GETDBGREGS 0xBDBB000C 42 | #define CMD_DEBUG_SETDBGREGS 0xBDBB000D 43 | #define CMD_DEBUG_STOPGO 0xBDBB0010 44 | #define CMD_DEBUG_THRINFO 0xBDBB0011 45 | #define CMD_DEBUG_SINGLESTEP 0xBDBB0012 46 | 47 | #define CMD_KERN_BASE 0xBDCC0001 48 | #define CMD_KERN_READ 0xBDCC0002 49 | #define CMD_KERN_WRITE 0xBDCC0003 50 | 51 | #define CMD_CONSOLE_REBOOT 0xBDDD0001 52 | #define CMD_CONSOLE_END 0xBDDD0002 53 | #define CMD_CONSOLE_PRINT 0xBDDD0003 54 | #define CMD_CONSOLE_NOTIFY 0xBDDD0004 55 | #define CMD_CONSOLE_INFO 0xBDDD0005 56 | 57 | #define VALID_CMD(cmd) (((cmd & 0xFF000000) >> 24) == 0xBD) 58 | #define VALID_PROC_CMD(cmd) (((cmd & 0x00FF0000) >> 16) == 0xAA) 59 | #define VALID_DEBUG_CMD(cmd) (((cmd & 0x00FF0000) >> 16) == 0xBB) 60 | #define VALID_KERN_CMD(cmd) (((cmd & 0x00FF0000) >> 16) == 0xCC) 61 | #define VALID_CONSOLE_CMD(cmd) (((cmd & 0x00FF0000) >> 16) == 0xDD) 62 | 63 | #define CMD_SUCCESS 0x80000000 64 | #define CMD_ERROR 0xF0000001 65 | #define CMD_TOO_MUCH_DATA 0xF0000002 66 | #define CMD_DATA_NULL 0xF0000003 67 | #define CMD_ALREADY_DEBUG 0xF0000004 68 | #define CMD_INVALID_INDEX 0xF0000005 69 | 70 | #define CMD_FATAL_STATUS(s) ((s >> 28) == 15) 71 | 72 | struct cmd_packet { 73 | uint32_t magic; 74 | uint32_t cmd; 75 | uint32_t datalen; 76 | // (field not actually part of packet, comes after) 77 | void *data; 78 | } __attribute__((packed)); 79 | #define CMD_PACKET_SIZE 12 80 | 81 | // proc 82 | struct cmd_proc_read_packet { 83 | uint32_t pid; 84 | uint64_t address; 85 | uint32_t length; 86 | } __attribute__((packed)); 87 | #define CMD_PROC_READ_PACKET_SIZE 16 88 | 89 | struct cmd_proc_write_packet { 90 | uint32_t pid; 91 | uint64_t address; 92 | uint32_t length; 93 | } __attribute__((packed)); 94 | #define CMD_PROC_WRITE_PACKET_SIZE 16 95 | 96 | struct cmd_proc_maps_packet { 97 | uint32_t pid; 98 | } __attribute__((packed)); 99 | #define CMD_PROC_MAPS_PACKET_SIZE 4 100 | 101 | struct cmd_proc_install_packet { 102 | uint32_t pid; 103 | } __attribute__((packed)); 104 | struct cmd_proc_install_response { 105 | uint64_t rpcstub; 106 | } __attribute__((packed)); 107 | #define CMD_PROC_INSTALL_PACKET_SIZE 4 108 | #define CMD_PROC_INSTALL_RESPONSE_SIZE 8 109 | 110 | struct cmd_proc_call_packet { 111 | uint32_t pid; 112 | uint64_t rpcstub; 113 | uint64_t rpc_rip; 114 | uint64_t rpc_rdi; 115 | uint64_t rpc_rsi; 116 | uint64_t rpc_rdx; 117 | uint64_t rpc_rcx; 118 | uint64_t rpc_r8; 119 | uint64_t rpc_r9; 120 | } __attribute__((packed)); 121 | struct cmd_proc_call_response { 122 | uint32_t pid; 123 | uint64_t rpc_rax; 124 | } __attribute__((packed)); 125 | #define CMD_PROC_CALL_PACKET_SIZE 68 126 | #define CMD_PROC_CALL_RESPONSE_SIZE 12 127 | 128 | struct cmd_proc_elf_packet { 129 | uint32_t pid; 130 | uint32_t length; 131 | } __attribute__((packed)); 132 | #define CMD_PROC_ELF_PACKET_SIZE 8 133 | 134 | struct cmd_proc_protect_packet { 135 | uint32_t pid; 136 | uint64_t address; 137 | uint32_t length; 138 | uint32_t newprot; 139 | } __attribute__((packed)); 140 | #define CMD_PROC_PROTECT_PACKET_SIZE 20 141 | 142 | typedef enum cmd_proc_scan_valuetype { 143 | valTypeUInt8 = 0, 144 | valTypeInt8, 145 | valTypeUInt16, 146 | valTypeInt16, 147 | valTypeUInt32, 148 | valTypeInt32, 149 | valTypeUInt64, 150 | valTypeInt64, 151 | valTypeFloat, 152 | valTypeDouble, 153 | valTypeArrBytes, 154 | valTypeString 155 | } __attribute__((__packed__)) cmd_proc_scan_valuetype; 156 | 157 | typedef enum cmd_proc_scan_comparetype { 158 | cmpTypeExactValue = 0, 159 | cmpTypeFuzzyValue, 160 | cmpTypeBiggerThan, 161 | cmpTypeSmallerThan, 162 | cmpTypeValueBetween, 163 | cmpTypeIncreasedValue, 164 | cmpTypeIncreasedValueBy, 165 | cmpTypeDecreasedValue, 166 | cmpTypeDecreasedValueBy, 167 | cmpTypeChangedValue, 168 | cmpTypeUnchangedValue, 169 | cmpTypeUnknownInitialValue 170 | } __attribute__((__packed__)) cmd_proc_scan_comparetype; 171 | 172 | struct cmd_proc_scan_packet { 173 | uint32_t pid; 174 | uint8_t valueType; 175 | uint8_t compareType; 176 | uint32_t lenData; 177 | } __attribute__((packed)); 178 | #define CMD_PROC_SCAN_PACKET_SIZE 10 179 | 180 | struct cmd_proc_info_packet { 181 | uint32_t pid; 182 | } __attribute__((packed)); 183 | struct cmd_proc_info_response { 184 | uint32_t pid; 185 | char name[40]; 186 | char path[64]; 187 | char titleid[16]; 188 | char contentid[64]; 189 | } __attribute__((packed)); 190 | #define CMD_PROC_INFO_PACKET_SIZE 4 191 | #define CMD_PROC_INFO_RESPONSE_SIZE 188 192 | 193 | struct cmd_proc_alloc_packet { 194 | uint32_t pid; 195 | uint32_t length; 196 | } __attribute__((packed)); 197 | struct cmd_proc_alloc_response { 198 | uint64_t address; 199 | } __attribute__((packed)); 200 | #define CMD_PROC_ALLOC_PACKET_SIZE 8 201 | #define CMD_PROC_ALLOC_RESPONSE_SIZE 8 202 | 203 | struct cmd_proc_free_packet { 204 | uint32_t pid; 205 | uint64_t address; 206 | uint32_t length; 207 | } __attribute__((packed)); 208 | #define CMD_PROC_FREE_PACKET_SIZE 16 209 | 210 | // debug 211 | struct cmd_debug_attach_packet { 212 | uint32_t pid; 213 | } __attribute__((packed)); 214 | #define CMD_DEBUG_ATTACH_PACKET_SIZE 4 215 | 216 | struct cmd_debug_breakpt_packet { 217 | uint32_t index; 218 | uint32_t enabled; 219 | uint64_t address; 220 | } __attribute__((packed)); 221 | #define CMD_DEBUG_BREAKPT_PACKET_SIZE 16 222 | 223 | struct cmd_debug_watchpt_packet { 224 | uint32_t index; 225 | uint32_t enabled; 226 | uint32_t length; 227 | uint32_t breaktype; 228 | uint64_t address; 229 | } __attribute__((packed)); 230 | #define CMD_DEBUG_WATCHPT_PACKET_SIZE 24 231 | 232 | struct cmd_debug_stopthr_packet { 233 | uint32_t lwpid; 234 | } __attribute__((packed)); 235 | #define CMD_DEBUG_STOPTHR_PACKET_SIZE 4 236 | 237 | struct cmd_debug_resumethr_packet { 238 | uint32_t lwpid; 239 | } __attribute__((packed)); 240 | #define CMD_DEBUG_RESUMETHR_PACKET_SIZE 4 241 | 242 | struct cmd_debug_getregs_packet { 243 | uint32_t lwpid; 244 | } __attribute__((packed)); 245 | #define CMD_DEBUG_GETREGS_PACKET_SIZE 4 246 | 247 | struct cmd_debug_setregs_packet { 248 | uint32_t lwpid; 249 | uint32_t length; 250 | } __attribute__((packed)); 251 | #define CMD_DEBUG_SETREGS_PACKET_SIZE 8 252 | 253 | struct cmd_debug_stopgo_packet { 254 | uint32_t stop; 255 | } __attribute__((packed)); 256 | #define CMD_DEBUG_STOPGO_PACKET_SIZE 4 257 | 258 | struct cmd_debug_thrinfo_packet { 259 | uint32_t lwpid; 260 | } __attribute__((packed)); 261 | struct cmd_debug_thrinfo_response { 262 | uint32_t lwpid; 263 | uint32_t priority; 264 | char name[32]; 265 | // TODO: add more information 266 | } __attribute__((packed)); 267 | #define CMD_DEBUG_THRINFO_PACKET_SIZE 4 268 | #define CMD_DEBUG_THRINFO_RESPONSE_SIZE 40 269 | 270 | // kern 271 | struct cmd_kern_read_packet { 272 | uint64_t address; 273 | uint32_t length; 274 | } __attribute__((packed)); 275 | #define CMD_KERN_READ_PACKET_SIZE 12 276 | 277 | struct cmd_kern_write_packet { 278 | uint64_t address; 279 | uint32_t length; 280 | } __attribute__((packed)); 281 | #define CMD_KERN_WRITE_PACKET_SIZE 12 282 | 283 | // console 284 | struct cmd_console_print_packet { 285 | uint32_t length; 286 | } __attribute__((packed)); 287 | #define CMD_CONSOLE_PRINT_PACKET_SIZE 4 288 | 289 | struct cmd_console_notify_packet { 290 | uint32_t messageType; 291 | uint32_t length; 292 | } __attribute__((packed)); 293 | #define CMD_CONSOLE_NOTIFY_PACKET_SIZE 8 294 | 295 | struct cmd_console_info_response { 296 | // todo 297 | } __attribute__((packed)); 298 | #define CMD_CONSOLE_INFO_RESPONSE_SIZE 8 299 | 300 | #define MAX_BREAKPOINTS 30 301 | #define MAX_WATCHPOINTS 4 302 | 303 | struct debug_breakpoint { 304 | uint32_t enabled; 305 | uint64_t address; 306 | uint8_t original; 307 | }; 308 | 309 | struct debug_watchpoint { 310 | uint32_t enabled; 311 | uint64_t address; 312 | uint8_t breaktype; 313 | uint8_t length; 314 | }; 315 | 316 | struct debug_context { 317 | int pid; 318 | int dbgfd; 319 | struct debug_breakpoint breakpoints[MAX_BREAKPOINTS]; 320 | // XXX: use actual __dbreg64 structure please 321 | struct { 322 | uint64_t dr[16]; 323 | } watchdata; 324 | }; 325 | 326 | struct server_client { 327 | int id; 328 | int fd; 329 | int debugging; 330 | struct sockaddr_in client; 331 | struct debug_context dbgctx; 332 | }; 333 | 334 | #endif 335 | -------------------------------------------------------------------------------- /debugger/include/ptrace.h: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #ifndef _PTRACE_H 6 | #define _PTRACE_H 7 | 8 | #include 9 | #include "sparse.h" 10 | #include "kdbg.h" 11 | 12 | // taken from ptrace.h 13 | 14 | #define PT_TRACE_ME 0 /* child declares it's being traced */ 15 | #define PT_READ_I 1 /* read word in child's I space */ 16 | #define PT_READ_D 2 /* read word in child's D space */ 17 | /* was PT_READ_U 3 * read word in child's user structure */ 18 | #define PT_WRITE_I 4 /* write word in child's I space */ 19 | #define PT_WRITE_D 5 /* write word in child's D space */ 20 | /* was PT_WRITE_U 6 * write word in child's user structure */ 21 | #define PT_CONTINUE 7 /* continue the child */ 22 | #define PT_KILL 8 /* kill the child process */ 23 | #define PT_STEP 9 /* single step the child */ 24 | #define PT_ATTACH 10 /* trace some running process */ 25 | #define PT_DETACH 11 /* stop tracing a process */ 26 | #define PT_IO 12 /* do I/O to/from stopped process. */ 27 | #define PT_LWPINFO 13 /* Info about the LWP that stopped. */ 28 | #define PT_GETNUMLWPS 14 /* get total number of threads */ 29 | #define PT_GETLWPLIST 15 /* get thread list */ 30 | #define PT_CLEARSTEP 16 /* turn off single step */ 31 | #define PT_SETSTEP 17 /* turn on single step */ 32 | #define PT_SUSPEND 18 /* suspend a thread */ 33 | #define PT_RESUME 19 /* resume a thread */ 34 | #define PT_TO_SCE 20 35 | #define PT_TO_SCX 21 36 | #define PT_SYSCALL 22 37 | #define PT_FOLLOW_FORK 23 38 | #define PT_GETREGS 33 /* get general-purpose registers */ 39 | #define PT_SETREGS 34 /* set general-purpose registers */ 40 | #define PT_GETFPREGS 35 /* get floating-point registers */ 41 | #define PT_SETFPREGS 36 /* set floating-point registers */ 42 | #define PT_GETDBREGS 37 /* get debugging registers */ 43 | #define PT_SETDBREGS 38 /* set debugging registers */ 44 | #define PT_VM_TIMESTAMP 40 /* Get VM version (timestamp) */ 45 | #define PT_VM_ENTRY 41 /* Get VM map (entry) */ 46 | 47 | #define __LOW(v) ((v) & 0377) 48 | #define __HIGH(v) (((v) >> 8) & 0377) 49 | 50 | #define WNOHANG 1 /* do not wait for child to exit */ 51 | #define WUNTRACED 2 /* for job control; not implemented */ 52 | 53 | #define WIFEXITED(s) (__LOW(s) == 0) /* normal exit */ 54 | #define WEXITSTATUS(s) (__HIGH(s)) /* exit status */ 55 | #define WTERMSIG(s) (__LOW(s) & 0177) /* sig value */ 56 | #define WIFSIGNALED(s) ((((unsigned int)(s)-1) & 0xFFFF) < 0xFF) /* signaled */ 57 | #define WIFSTOPPED(s) (__LOW(s) == 0177) /* stopped */ 58 | #define WSTOPSIG(s) (__HIGH(s) & 0377) /* stop signal */ 59 | 60 | // some signals 61 | #define SIGHUP 1 /* hangup */ 62 | #define SIGINT 2 /* interrupt */ 63 | #define SIGQUIT 3 /* quit */ 64 | #define SIGILL 4 /* illegal instruction (not reset when caught) */ 65 | #define SIGTRAP 5 /* trace trap (not reset when caught) */ 66 | #define SIGABRT 6 /* abort() */ 67 | #define SIGIOT SIGABRT /* compatibility */ 68 | #define SIGEMT 7 /* EMT instruction */ 69 | #define SIGFPE 8 /* floating point exception */ 70 | #define SIGKILL 9 /* kill (cannot be caught or ignored) */ 71 | #define SIGBUS 10 /* bus error */ 72 | #define SIGSEGV 11 /* segmentation violation */ 73 | #define SIGSYS 12 /* bad argument to system call */ 74 | #define SIGPIPE 13 /* write on a pipe with no one to read it */ 75 | #define SIGALRM 14 /* alarm clock */ 76 | #define SIGTERM 15 /* software termination signal from kill */ 77 | #define SIGURG 16 /* urgent condition on IO channel */ 78 | #define SIGSTOP 17 /* sendable stop signal not from tty */ 79 | #define SIGTSTP 18 /* stop signal from tty */ 80 | #define SIGCONT 19 /* continue a stopped process */ 81 | #define SIGCHLD 20 /* to parent on child stop or exit */ 82 | #define SIGTTIN 21 /* to readers pgrp upon background tty read */ 83 | #define SIGTTOU 22 /* like TTIN for output if (tp->t_local<OSTOP) */ 84 | #define SIGIO 23 /* input/output possible signal */ 85 | #define SIGXCPU 24 /* exceeded CPU time limit */ 86 | #define SIGXFSZ 25 /* exceeded file size limit */ 87 | #define SIGVTALRM 26 /* virtual time alarm */ 88 | #define SIGPROF 27 /* profiling time alarm */ 89 | #define SIGWINCH 28 /* window size changes */ 90 | #define SIGINFO 29 /* information request */ 91 | #define SIGUSR1 30 /* user defined signal 1 */ 92 | #define SIGUSR2 31 /* user defined signal 2 */ 93 | 94 | TYPE_BEGIN(struct ptrace_lwpinfo, 0x98); 95 | TYPE_FIELD(uint32_t pl_lwpid, 0); 96 | TYPE_FIELD(char pl_tdname[24], 0x80); 97 | TYPE_END(); 98 | 99 | int ptrace(int req, int pid, void *addr, int data); 100 | int wait4(int wpid, int *status, int options, void *rusage); 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /debugger/include/server.h: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #ifndef _SERVER_H 6 | #define _SERVER_H 7 | 8 | #include 9 | #include "protocol.h" 10 | #include "net.h" 11 | 12 | #include "proc.h" 13 | #include "debug.h" 14 | #include "kern.h" 15 | #include "console.h" 16 | 17 | #define SERVER_PORT 744 18 | #define SERVER_MAXCLIENTS 8 19 | 20 | #define BROADCAST_PORT 1010 21 | #define BROADCAST_MAGIC 0xFFFFAAAA 22 | 23 | extern struct server_client servclients[SERVER_MAXCLIENTS]; 24 | 25 | struct server_client *alloc_client(); 26 | void free_client(struct server_client *svc); 27 | 28 | int handle_version(int fd, struct cmd_packet *packet); 29 | int cmd_handler(int fd, struct cmd_packet *packet); 30 | int check_debug_interrupt(); 31 | int handle_client(struct server_client *svc); 32 | 33 | void configure_socket(int fd); 34 | void *broadcast_thread(void *arg); 35 | int start_server(); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /debugger/include/sparse.h: -------------------------------------------------------------------------------- 1 | #ifndef _SPARSE_H 2 | #define _SPARSE_H 3 | 4 | #define JOIN_HELPER(x, y) x##y 5 | #define JOIN(x, y) JOIN_HELPER(x, y) 6 | 7 | #define TYPE_PAD(size) char JOIN(_pad_, __COUNTER__)[size] 8 | #define TYPE_VARIADIC_BEGIN(name) name { union { 9 | #define TYPE_BEGIN(name, size) name { union { TYPE_PAD(size) 10 | #define TYPE_END(...) }; } __VA_ARGS__ 11 | #define TYPE_FIELD(field, offset) struct { TYPE_PAD(offset); field; } 12 | 13 | #define TYPE_CHECK_SIZE(name, size) \ 14 | _Static_assert(sizeof(name) == (size), "Size of " #name " != " #size) 15 | 16 | #define TYPE_CHECK_FIELD_OFFSET(name, member, offset) \ 17 | _Static_assert(offsetof(name, member) == (offset), "Offset of " #name "." #member " != " #offset) 18 | 19 | #define TYPE_CHECK_FIELD_SIZE(name, member, size) \ 20 | _Static_assert(sizeof(((name*)0)->member) == (size), "Size of " #name "." #member " != " #size) 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /debugger/source/console.c: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #include "console.h" 6 | 7 | int console_reboot_handle(int fd, struct cmd_packet *packet) { 8 | if(g_debugging) { 9 | debug_cleanup(curdbgctx); 10 | 11 | // close the socket, we are not about to call free_client 12 | // this is a little hacky but meh 13 | sceNetSocketClose(fd); 14 | } 15 | 16 | sys_console_cmd(SYS_CONSOLE_CMD_REBOOT, NULL); 17 | return 1; 18 | } 19 | 20 | int console_print_handle(int fd, struct cmd_packet *packet) { 21 | struct cmd_console_print_packet *pp; 22 | void *data; 23 | 24 | pp = (struct cmd_console_print_packet *)packet->data; 25 | 26 | if(pp) { 27 | data = pfmalloc(pp->length); 28 | if(!data) { 29 | net_send_status(fd, CMD_DATA_NULL); 30 | return 1; 31 | } 32 | 33 | memset(data, NULL, pp->length); 34 | 35 | net_recv_data(fd, data, pp->length, 1); 36 | 37 | sys_console_cmd(SYS_CONSOLE_CMD_PRINT, data); 38 | net_send_status(fd, CMD_SUCCESS); 39 | 40 | free(data); 41 | 42 | return 0; 43 | } 44 | 45 | net_send_status(fd, CMD_DATA_NULL); 46 | 47 | return 1; 48 | } 49 | 50 | int console_notify_handle(int fd, struct cmd_packet *packet) { 51 | struct cmd_console_notify_packet *np; 52 | void *data; 53 | 54 | np = (struct cmd_console_notify_packet *)packet->data; 55 | 56 | if(np) { 57 | data = pfmalloc(np->length); 58 | if(!data) { 59 | net_send_status(fd, CMD_DATA_NULL); 60 | return 1; 61 | } 62 | 63 | memset(data, NULL, np->length); 64 | 65 | net_recv_data(fd, data, np->length, 1); 66 | 67 | sceSysUtilSendSystemNotificationWithText(np->messageType, data); 68 | net_send_status(fd, CMD_SUCCESS); 69 | 70 | free(data); 71 | 72 | return 0; 73 | } 74 | 75 | net_send_status(fd, CMD_DATA_NULL); 76 | 77 | return 1; 78 | } 79 | 80 | int console_info_handle(int fd, struct cmd_packet *packet) { 81 | //struct cmd_console_info_response resp; 82 | //size_t len; 83 | 84 | //extern int (*sysctl)(int *name, unsigned int namelen, char *oldval, size_t *oldlen, char *newval, size_t newlen); 85 | //extern int (*sysctlbyname)(char *name, char *oldval, size_t *oldlen, char *newval, size_t newlen); 86 | 87 | // TODO: implement this 88 | 89 | net_send_status(fd, CMD_SUCCESS); 90 | //net_send_data(fd, &resp, CMD_CONSOLE_INFO_RESPONSE_SIZE); 91 | 92 | return 0; 93 | } 94 | 95 | int console_handle(int fd, struct cmd_packet *packet) { 96 | switch(packet->cmd) { 97 | case CMD_CONSOLE_REBOOT: 98 | return console_reboot_handle(fd, packet); 99 | case CMD_CONSOLE_END: 100 | return 1; 101 | case CMD_CONSOLE_PRINT: 102 | return console_print_handle(fd, packet); 103 | case CMD_CONSOLE_NOTIFY: 104 | return console_notify_handle(fd, packet); 105 | case CMD_CONSOLE_INFO: 106 | return console_info_handle(fd, packet); 107 | } 108 | 109 | return 0; 110 | } 111 | -------------------------------------------------------------------------------- /debugger/source/kdbg.c: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #include "kdbg.h" 6 | 7 | void prefault(void *address, size_t size) { 8 | for(uint64_t i = 0; i < size; i++) { 9 | volatile uint8_t c; 10 | (void)c; 11 | 12 | c = ((char *)address)[i]; 13 | } 14 | } 15 | 16 | void *pfmalloc(size_t size) { 17 | void *p = malloc(size); 18 | prefault(p, size); 19 | return p; 20 | } 21 | 22 | void hexdump(void *data, size_t size) { 23 | unsigned char *p; 24 | int i; 25 | 26 | p = (unsigned char *)data; 27 | 28 | for(i = 0; i < size; i++) { 29 | uprintf("%02X ", *p++); 30 | if(!(i % 16) && i != 0) { 31 | uprintf("\n"); 32 | } 33 | } 34 | 35 | uprintf("\n"); 36 | } 37 | 38 | // custom syscall 107 39 | int sys_proc_list(struct proc_list_entry *procs, uint64_t *num) { 40 | return syscall(107, procs, num); 41 | } 42 | 43 | // custom syscall 108 44 | int sys_proc_rw(uint64_t pid, uint64_t address, void *data, uint64_t length, uint64_t write) { 45 | return syscall(108, pid, address, data, length, write); 46 | } 47 | 48 | // custom syscall 109 49 | #define SYS_PROC_CMD_ALLOC 1 50 | #define SYS_PROC_CMD_FREE 2 51 | #define SYS_PROC_CMD_PROTECT 3 52 | #define SYS_PROC_VM_MAP 4 53 | #define SYS_PROC_CMD_CALL 5 54 | int sys_proc_cmd(uint64_t pid, uint64_t cmd, void *data) { 55 | return syscall(109, pid, cmd, data); 56 | } 57 | 58 | // custom syscall 110 59 | int sys_kern_base(uint64_t *kbase) { 60 | return syscall(110, kbase); 61 | } 62 | 63 | // custom syscall 111 64 | int sys_kern_rw(uint64_t address, void *data, uint64_t length, uint64_t write) { 65 | return syscall(111, address, data, length, write); 66 | } 67 | 68 | // custom syscall 112 69 | int sys_console_cmd(uint64_t cmd, void *data) { 70 | return syscall(112, cmd, data); 71 | } 72 | -------------------------------------------------------------------------------- /debugger/source/kern.c: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #include "kern.h" 6 | 7 | int kern_base_handle(int fd, struct cmd_packet *packet) { 8 | uint64_t kernbase; 9 | 10 | sys_kern_base(&kernbase); 11 | 12 | net_send_status(fd, CMD_SUCCESS); 13 | net_send_data(fd, &kernbase, sizeof(uint64_t)); 14 | 15 | return 0; 16 | } 17 | 18 | int kern_read_handle(int fd, struct cmd_packet *packet) { 19 | struct cmd_kern_read_packet *rp; 20 | void *data; 21 | 22 | rp = (struct cmd_kern_read_packet *)packet->data; 23 | 24 | if(rp) { 25 | data = pfmalloc(rp->length); 26 | if(!data) { 27 | net_send_status(fd, CMD_DATA_NULL); 28 | return 1; 29 | } 30 | 31 | sys_kern_rw(rp->address, data, rp->length, 0); 32 | 33 | net_send_status(fd, CMD_SUCCESS); 34 | net_send_data(fd, data, rp->length); 35 | 36 | free(data); 37 | 38 | return 0; 39 | } 40 | 41 | net_send_status(fd, CMD_DATA_NULL); 42 | 43 | return 0; 44 | } 45 | 46 | int kern_write_handle(int fd, struct cmd_packet *packet) { 47 | struct cmd_kern_write_packet *wp; 48 | void *data; 49 | 50 | wp = (struct cmd_kern_write_packet *)packet->data; 51 | 52 | if(wp) { 53 | data = pfmalloc(wp->length); 54 | if(!data) { 55 | net_send_status(fd, CMD_DATA_NULL); 56 | return 1; 57 | } 58 | 59 | net_send_status(fd, CMD_SUCCESS); 60 | 61 | net_recv_data(fd, data, wp->length, 1); 62 | sys_kern_rw(wp->address, data, wp->length, 1); 63 | 64 | net_send_status(fd, CMD_SUCCESS); 65 | 66 | free(data); 67 | 68 | return 0; 69 | } 70 | 71 | net_send_status(fd, CMD_DATA_NULL); 72 | 73 | return 0; 74 | } 75 | 76 | int kern_handle(int fd, struct cmd_packet *packet) { 77 | switch(packet->cmd) { 78 | case CMD_KERN_BASE: 79 | return kern_base_handle(fd, packet); 80 | case CMD_KERN_READ: 81 | return kern_read_handle(fd, packet); 82 | case CMD_KERN_WRITE: 83 | return kern_write_handle(fd, packet); 84 | } 85 | 86 | return 1; 87 | } 88 | -------------------------------------------------------------------------------- /debugger/source/main.c: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #include 6 | #include "ptrace.h" 7 | #include "server.h" 8 | #include "debug.h" 9 | 10 | int _main(void) { 11 | initKernel(); 12 | initLibc(); 13 | initPthread(); 14 | initNetwork(); 15 | initSysUtil(); 16 | 17 | // sleep a few seconds 18 | // maybe lower our thread priority? 19 | sceKernelSleep(2); 20 | 21 | // just a little notify 22 | sceSysUtilSendSystemNotificationWithText(222, "ps4debug by golden\n 7.55 port by Joonie86"); 23 | 24 | // jailbreak current thread 25 | sys_console_cmd(SYS_CONSOLE_CMD_JAILBREAK, NULL); 26 | 27 | // updates 28 | mkdir("/update/PS4UPDATE.PUP", 0777); 29 | mkdir("/update/PS4UPDATE.PUP.net.temp", 0777); 30 | 31 | // start the server, this will block 32 | start_server(); 33 | 34 | return 0; 35 | } -------------------------------------------------------------------------------- /debugger/source/net.c: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #include "net.h" 6 | 7 | int net_select(int fd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { 8 | return syscall(93, fd, readfds, writefds, exceptfds, timeout); 9 | } 10 | 11 | int net_send_data(int fd, void *data, int length) { 12 | int left = length; 13 | int offset = 0; 14 | int sent = 0; 15 | 16 | errno = NULL; 17 | 18 | while (left > 0) { 19 | if (left > NET_MAX_LENGTH) { 20 | sent = write(fd, data + offset, NET_MAX_LENGTH); 21 | } else { 22 | sent = write(fd, data + offset, left); 23 | } 24 | 25 | if (sent <= 0) { 26 | if(errno && errno != EWOULDBLOCK) { 27 | return sent; 28 | } 29 | } else { 30 | offset += sent; 31 | left -= sent; 32 | } 33 | } 34 | 35 | return offset; 36 | } 37 | 38 | int net_recv_data(int fd, void *data, int length, int force) { 39 | int left = length; 40 | int offset = 0; 41 | int recv = 0; 42 | 43 | errno = NULL; 44 | 45 | while (left > 0) { 46 | if (left > NET_MAX_LENGTH) { 47 | recv = read(fd, data + offset, NET_MAX_LENGTH); 48 | } else { 49 | recv = read(fd, data + offset, left); 50 | } 51 | 52 | if (recv <= 0) { 53 | if (force) { 54 | if(errno && errno != EWOULDBLOCK) { 55 | return recv; 56 | } 57 | } else { 58 | return offset; 59 | } 60 | } else { 61 | offset += recv; 62 | left -= recv; 63 | } 64 | } 65 | 66 | return offset; 67 | } 68 | 69 | int net_send_status(int fd, uint32_t status) { 70 | uint32_t d = status; 71 | 72 | return net_send_data(fd, &d, sizeof(uint32_t)); 73 | } 74 | -------------------------------------------------------------------------------- /debugger/source/ptrace.c: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #include "ptrace.h" 6 | 7 | int ptrace(int req, int pid, void *addr, int data) { 8 | int r; 9 | 10 | errno = NULL; 11 | 12 | r = syscall(26, req, pid, addr, data); 13 | 14 | //uprintf("ptrace(req %i, pid %i, addr 0x%llX, data 0x%X) = %i (errno %i)", req, pid, addr, data, r, errno); 15 | 16 | return r; 17 | } 18 | 19 | int wait4(int wpid, int *status, int options, void *rusage) { 20 | return syscall(7, wpid, status, options, rusage); 21 | } 22 | -------------------------------------------------------------------------------- /debugger/source/server.c: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #include "server.h" 6 | 7 | struct server_client servclients[SERVER_MAXCLIENTS]; 8 | 9 | struct server_client *alloc_client() { 10 | for(int i = 0; i < SERVER_MAXCLIENTS; i++) { 11 | if(servclients[i].id == 0) { 12 | servclients[i].id = i + 1; 13 | return &servclients[i]; 14 | } 15 | } 16 | 17 | return NULL; 18 | } 19 | 20 | void free_client(struct server_client *svc) { 21 | svc->id = 0; 22 | sceNetSocketClose(svc->fd); 23 | 24 | if(svc->debugging) { 25 | debug_cleanup(&svc->dbgctx); 26 | } 27 | 28 | memset(svc, NULL, sizeof(struct server_client)); 29 | } 30 | 31 | int handle_version(int fd, struct cmd_packet *packet) { 32 | uint32_t len = strlen(PACKET_VERSION); 33 | net_send_data(fd, &len, sizeof(uint32_t)); 34 | net_send_data(fd, PACKET_VERSION, len); 35 | return 0; 36 | } 37 | 38 | int cmd_handler(int fd, struct cmd_packet *packet) { 39 | if (!VALID_CMD(packet->cmd)) { 40 | return 1; 41 | } 42 | 43 | uprintf("cmd_handler %X", packet->cmd); 44 | 45 | if(packet->cmd == CMD_VERSION) { 46 | return handle_version(fd, packet); 47 | } 48 | 49 | if(VALID_PROC_CMD(packet->cmd)) { 50 | return proc_handle(fd, packet); 51 | } else if(VALID_DEBUG_CMD(packet->cmd)) { 52 | return debug_handle(fd, packet); 53 | } else if(VALID_KERN_CMD(packet->cmd)) { 54 | return kern_handle(fd, packet); 55 | } else if(VALID_CONSOLE_CMD(packet->cmd)) { 56 | return console_handle(fd, packet); 57 | } 58 | 59 | return 0; 60 | } 61 | 62 | int check_debug_interrupt() { 63 | struct debug_interrupt_packet resp; 64 | struct debug_breakpoint *breakpoint; 65 | struct ptrace_lwpinfo *lwpinfo; 66 | uint8_t int3; 67 | int status; 68 | int signal; 69 | int r; 70 | 71 | r = wait4(curdbgctx->pid, &status, WNOHANG, NULL); 72 | if(!r) { 73 | return 0; 74 | } 75 | 76 | signal = WSTOPSIG(status); 77 | uprintf("check_debug_interrupt signal %i", signal); 78 | 79 | if(signal == SIGSTOP) { 80 | uprintf("passed on a SIGSTOP"); 81 | return 0; 82 | } else if(signal == SIGKILL) { 83 | debug_cleanup(curdbgctx); 84 | 85 | // the process will die 86 | ptrace(PT_CONTINUE, curdbgctx->pid, (void *)1, SIGKILL); 87 | 88 | uprintf("sent final SIGKILL"); 89 | return 0; 90 | } 91 | 92 | // If lwpinfo is on the stack it fails, maybe I should patch ptrace? idk 93 | lwpinfo = (struct ptrace_lwpinfo *)pfmalloc(sizeof(struct ptrace_lwpinfo)); 94 | if(!lwpinfo) { 95 | uprintf("could not allocate memory for thread information"); 96 | return 1; 97 | } 98 | 99 | // grab interrupt data 100 | r = ptrace(PT_LWPINFO, curdbgctx->pid, lwpinfo, sizeof(struct ptrace_lwpinfo)); 101 | if(r) { 102 | uprintf("could not get lwpinfo errno %i", errno); 103 | } 104 | 105 | // fill response 106 | memset(&resp, NULL, DEBUG_INTERRUPT_PACKET_SIZE); 107 | resp.lwpid = lwpinfo->pl_lwpid; 108 | resp.status = status; 109 | 110 | // TODO: fix size mismatch with these fields 111 | memcpy(resp.tdname, lwpinfo->pl_tdname, sizeof(lwpinfo->pl_tdname)); 112 | 113 | r = ptrace(PT_GETREGS, resp.lwpid, &resp.reg64, NULL); 114 | if(r) { 115 | uprintf("could not get registers errno %i", errno); 116 | } 117 | 118 | r = ptrace(PT_GETFPREGS, resp.lwpid, &resp.savefpu, NULL); 119 | if(r) { 120 | uprintf("could not get float registers errno %i", errno); 121 | } 122 | 123 | r = ptrace(PT_GETDBREGS, resp.lwpid, &resp.dbreg64, NULL); 124 | if(r) { 125 | uprintf("could not get debug registers errno %i", errno); 126 | } 127 | 128 | // if it is a software breakpoint we need to handle it accordingly 129 | breakpoint = NULL; 130 | for(int i = 0; i < MAX_BREAKPOINTS; i++) { 131 | if(curdbgctx->breakpoints[i].address == resp.reg64.r_rip - 1) { 132 | breakpoint = &curdbgctx->breakpoints[i]; 133 | break; 134 | } 135 | } 136 | 137 | if(breakpoint) { 138 | uprintf("dealing with software breakpoint"); 139 | uprintf("breakpoint: %llX %X", breakpoint->address, breakpoint->original); 140 | 141 | // write old instruction 142 | sys_proc_rw(curdbgctx->pid, breakpoint->address, &breakpoint->original, 1, 1); 143 | 144 | // backstep 1 instruction 145 | resp.reg64.r_rip -= 1; 146 | ptrace(PT_SETREGS, resp.lwpid, &resp.reg64, NULL); 147 | 148 | // single step over the instruction 149 | ptrace(PT_STEP, resp.lwpid, (void *)1, NULL); 150 | while(!wait4(curdbgctx->pid, &status, WNOHANG, NULL)) { 151 | sceKernelUsleep(4000); 152 | } 153 | 154 | uprintf("waited for signal %i", WSTOPSIG(status)); 155 | 156 | // set breakpoint again 157 | int3 = 0xCC; 158 | sys_proc_rw(curdbgctx->pid, breakpoint->address, &int3, 1, 1); 159 | } else { 160 | uprintf("dealing with hardware breakpoint"); 161 | } 162 | 163 | r = net_send_data(curdbgctx->dbgfd, &resp, DEBUG_INTERRUPT_PACKET_SIZE); 164 | if(r != DEBUG_INTERRUPT_PACKET_SIZE) { 165 | uprintf("net_send_data failed %i %i", r, errno); 166 | } 167 | 168 | uprintf("check_debug_interrupt interrupt data sent"); 169 | 170 | free(lwpinfo); 171 | 172 | return 0; 173 | } 174 | 175 | int handle_client(struct server_client *svc) { 176 | struct cmd_packet packet; 177 | uint32_t rsize; 178 | uint32_t length; 179 | void *data; 180 | int fd; 181 | int r; 182 | 183 | fd = svc->fd; 184 | 185 | // setup time val for select 186 | struct timeval tv; 187 | memset(&tv, NULL, sizeof(tv)); 188 | tv.tv_usec = 1000; 189 | 190 | while(1) { 191 | // do a select 192 | fd_set sfd; 193 | FD_ZERO(&sfd); 194 | FD_SET(fd, &sfd); 195 | errno = NULL; 196 | net_select(FD_SETSIZE, &sfd, NULL, NULL, &tv); 197 | 198 | // check if we can recieve 199 | if(FD_ISSET(fd, &sfd)) { 200 | // zero out 201 | memset(&packet, NULL, CMD_PACKET_SIZE); 202 | 203 | // recieve our data 204 | rsize = net_recv_data(fd, &packet, CMD_PACKET_SIZE, 0); 205 | 206 | // if we didnt recieve hmm 207 | if (rsize <= 0) { 208 | goto error; 209 | } 210 | 211 | // check if disconnected 212 | if (errno == ECONNRESET) { 213 | goto error; 214 | } 215 | } else { 216 | // if we have a valid debugger context then check for interrupt 217 | // this does not block, as wait is called with option WNOHANG 218 | if(svc->debugging) { 219 | if(check_debug_interrupt()) { 220 | goto error; 221 | } 222 | } 223 | 224 | // check if disconnected 225 | if (errno == ECONNRESET) { 226 | goto error; 227 | } 228 | 229 | sceKernelUsleep(25000); 230 | continue; 231 | } 232 | 233 | uprintf("client packet recieved"); 234 | 235 | // invalid packet 236 | if (packet.magic != PACKET_MAGIC) { 237 | uprintf("invalid packet magic %X!", packet.magic); 238 | continue; 239 | } 240 | 241 | // mismatch received size 242 | if (rsize != CMD_PACKET_SIZE) { 243 | uprintf("invalid recieve size %i!", rsize); 244 | continue; 245 | } 246 | 247 | length = packet.datalen; 248 | if (length) { 249 | // allocate data 250 | data = pfmalloc(length); 251 | if (!data) { 252 | goto error; 253 | } 254 | 255 | uprintf("recieving data length %i", length); 256 | 257 | // recv data 258 | r = net_recv_data(fd, data, length, 1); 259 | if (!r) { 260 | goto error; 261 | } 262 | 263 | // set data 264 | packet.data = data; 265 | } else { 266 | packet.data = NULL; 267 | } 268 | 269 | // special case when attaching 270 | // if we are debugging then the handler for CMD_DEBUG_ATTACH will send back the right error 271 | if(!g_debugging && packet.cmd == CMD_DEBUG_ATTACH) { 272 | curdbgcli = svc; 273 | curdbgctx = &svc->dbgctx; 274 | } 275 | 276 | // handle the packet 277 | r = cmd_handler(fd, &packet); 278 | 279 | if (data) { 280 | free(data); 281 | data = NULL; 282 | } 283 | 284 | // check cmd handler error 285 | if (r) { 286 | goto error; 287 | } 288 | } 289 | 290 | error: 291 | uprintf("client disconnected"); 292 | free_client(svc); 293 | 294 | return 0; 295 | } 296 | 297 | void configure_socket(int fd) { 298 | int flag; 299 | 300 | flag = 1; 301 | sceNetSetsockopt(fd, SOL_SOCKET, SO_NBIO, (char *)&flag, sizeof(flag)); 302 | 303 | flag = 1; 304 | sceNetSetsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)); 305 | 306 | flag = 1; 307 | sceNetSetsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (char *)&flag, sizeof(flag)); 308 | } 309 | 310 | void *broadcast_thread(void *arg) { 311 | struct sockaddr_in server; 312 | struct sockaddr_in client; 313 | unsigned int clisize; 314 | int serv; 315 | int flag; 316 | int r; 317 | uint32_t magic; 318 | 319 | uprintf("broadcast server started"); 320 | 321 | // setup server 322 | server.sin_len = sizeof(server); 323 | server.sin_family = AF_INET; 324 | server.sin_addr.s_addr = IN_ADDR_ANY; 325 | server.sin_port = sceNetHtons(BROADCAST_PORT); 326 | memset(server.sin_zero, NULL, sizeof(server.sin_zero)); 327 | 328 | serv = sceNetSocket("broadsock", AF_INET, SOCK_DGRAM, 0); 329 | if(serv < 0) { 330 | uprintf("failed to create broadcast server"); 331 | return NULL; 332 | } 333 | 334 | flag = 1; 335 | sceNetSetsockopt(serv, SOL_SOCKET, SO_BROADCAST, (char *)&flag, sizeof(flag)); 336 | 337 | r = sceNetBind(serv, (struct sockaddr *)&server, sizeof(server)); 338 | if(r) { 339 | uprintf("failed to bind broadcast server"); 340 | return NULL; 341 | } 342 | 343 | // TODO: XXX: clean this up, but meh not too dirty? is it? hmmm 344 | int libNet = sceKernelLoadStartModule("libSceNet.sprx", 0, NULL, 0, 0, 0); 345 | int (*sceNetRecvfrom)(int s, void *buf, unsigned int len, int flags, struct sockaddr *from, unsigned int *fromlen); 346 | int (*sceNetSendto)(int s, void *msg, unsigned int len, int flags, struct sockaddr *to, unsigned int tolen); 347 | RESOLVE(libNet, sceNetRecvfrom); 348 | RESOLVE(libNet, sceNetSendto); 349 | 350 | while(1) { 351 | scePthreadYield(); 352 | 353 | magic = 0; 354 | clisize = sizeof(client); 355 | r = sceNetRecvfrom(serv, &magic, sizeof(uint32_t), 0, (struct sockaddr *)&client, &clisize); 356 | 357 | if(r >= 0) { 358 | uprintf("broadcast server received a message"); 359 | if(magic == BROADCAST_MAGIC) { 360 | sceNetSendto(serv, &magic, sizeof(uint32_t), 0, (struct sockaddr *)&client, clisize); 361 | } 362 | } else { 363 | uprintf("sceNetRecvfrom failed"); 364 | } 365 | 366 | sceKernelSleep(1); 367 | } 368 | 369 | return NULL; 370 | } 371 | 372 | int start_server() { 373 | struct sockaddr_in server; 374 | struct sockaddr_in client; 375 | struct server_client *svc; 376 | unsigned int len = sizeof(client); 377 | int serv, fd; 378 | int r; 379 | 380 | uprintf("ps4debug " PACKET_VERSION " server started"); 381 | 382 | ScePthread broadcast; 383 | scePthreadCreate(&broadcast, NULL, broadcast_thread, NULL, "broadcast"); 384 | 385 | // server structure 386 | server.sin_len = sizeof(server); 387 | server.sin_family = AF_INET; 388 | server.sin_addr.s_addr = IN_ADDR_ANY; 389 | server.sin_port = sceNetHtons(SERVER_PORT); 390 | memset(server.sin_zero, NULL, sizeof(server.sin_zero)); 391 | 392 | // start up server 393 | serv = sceNetSocket("debugserver", AF_INET, SOCK_STREAM, 0); 394 | if(serv < 0) { 395 | uprintf("could not create socket!"); 396 | return 1; 397 | } 398 | 399 | configure_socket(serv); 400 | 401 | r = sceNetBind(serv, (struct sockaddr *)&server, sizeof(server)); 402 | if(r) { 403 | uprintf("bind failed!"); 404 | return 1; 405 | } 406 | 407 | r = sceNetListen(serv, SERVER_MAXCLIENTS * 2); 408 | if(r) { 409 | uprintf("bind failed!"); 410 | return 1; 411 | } 412 | 413 | // reset clients 414 | memset(servclients, NULL, sizeof(struct server_client) * SERVER_MAXCLIENTS); 415 | 416 | // reset debugging stuff 417 | g_debugging = 0; 418 | curdbgcli = NULL; 419 | curdbgctx = NULL; 420 | 421 | while(1) { 422 | scePthreadYield(); 423 | 424 | errno = NULL; 425 | fd = sceNetAccept(serv, (struct sockaddr *)&client, &len); 426 | if(fd > -1 && !errno) { 427 | uprintf("accepted a new client"); 428 | 429 | svc = alloc_client(); 430 | if(!svc) { 431 | uprintf("server can not accept anymore clients"); 432 | continue; 433 | } 434 | 435 | configure_socket(fd); 436 | 437 | svc->fd = fd; 438 | svc->debugging = 0; 439 | memcpy(&svc->client, &client, sizeof(svc->client)); 440 | memset(&svc->dbgctx, NULL, sizeof(svc->dbgctx)); 441 | 442 | ScePthread thread; 443 | scePthreadCreate(&thread, NULL, (void * (*)(void *))handle_client, (void *)svc, "clienthandler"); 444 | } 445 | 446 | sceKernelSleep(2); 447 | } 448 | 449 | return 0; 450 | } 451 | -------------------------------------------------------------------------------- /installer/Makefile: -------------------------------------------------------------------------------- 1 | KSDK := ../ps4-ksdk/ 2 | 3 | CC := gcc 4 | AS := gcc 5 | OBJCOPY := objcopy 6 | ODIR := build 7 | SDIR := source 8 | IDIRS := -I$(KSDK)/include -I. -Iinclude 9 | LDIRS := -L$(KSDK) -L. -Llib 10 | MAPFILE := $(shell basename $(CURDIR)).map 11 | CFLAGS := $(IDIRS) -Os -std=gnu11 -ffunction-sections -fdata-sections -fno-builtin -nostartfiles -nostdlib -Wall -masm=intel -march=btver2 -mtune=btver2 -m64 -mabi=sysv -mcmodel=small -fpie 12 | SFLAGS := -nostartfiles -nostdlib -march=btver2 -mtune=btver2 13 | LFLAGS := $(LDIRS) -Xlinker -T linker.x -Wl,--build-id=none -Wl,--gc-sections 14 | CFILES := $(wildcard $(SDIR)/*.c) 15 | SFILES := $(wildcard $(SDIR)/*.s) 16 | OBJS := $(patsubst $(SDIR)/%.c, $(ODIR)/%.o, $(CFILES)) $(patsubst $(SDIR)/%.s, $(ODIR)/%.o, $(SFILES)) 17 | 18 | LIBS := -lKSDK 19 | 20 | TARGET = installer.bin 21 | 22 | $(TARGET): $(ODIR) $(OBJS) 23 | $(CC) crt0.s $(ODIR)/*.o -o temp.t $(CFLAGS) $(LFLAGS) $(LIBS) 24 | $(OBJCOPY) -O binary temp.t $(TARGET) 25 | rm -f temp.t 26 | 27 | $(ODIR)/%.o: $(SDIR)/%.c 28 | $(CC) -c -o $@ $< $(CFLAGS) 29 | 30 | $(ODIR)/%.o: $(SDIR)/%.s 31 | $(AS) -c -o $@ $< $(SFLAGS) 32 | 33 | $(ODIR): 34 | @mkdir $@ 35 | 36 | .PHONY: clean 37 | 38 | clean: 39 | rm -f $(TARGET) $(ODIR)/*.o 40 | -------------------------------------------------------------------------------- /installer/crt0.s: -------------------------------------------------------------------------------- 1 | .intel_syntax noprefix 2 | .text 3 | 4 | .global _start 5 | _start: 6 | jmp _main 7 | -------------------------------------------------------------------------------- /installer/include/installer.h: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #ifndef _INSTALLER_H 6 | #define _INSTALLER_H 7 | 8 | #include 9 | #include "proc.h" 10 | 11 | #define PAYLOAD_BASE 0x926200000 12 | #define PAYLOAD_SIZE 0x400000 13 | 14 | int runinstaller(); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /installer/include/proc.h: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #ifndef _PROC_H 6 | #define _PROC_H 7 | 8 | #include 9 | #include "rpcasm.h" 10 | #include "elf.h" 11 | 12 | #define PAGE_SIZE 0x4000 13 | 14 | struct proc_vm_map_entry { 15 | char name[32]; 16 | uint64_t start; 17 | uint64_t end; 18 | uint64_t offset; 19 | uint16_t prot; 20 | } __attribute__((packed)); 21 | 22 | struct proc *proc_find_by_name(const char *name); 23 | struct proc *proc_find_by_pid(int pid); 24 | int proc_get_vm_map(struct proc *p, struct proc_vm_map_entry **entries, uint64_t *num_entries); 25 | 26 | int proc_rw_mem(struct proc *p, void *ptr, uint64_t size, void *data, uint64_t *n, int write); 27 | int proc_read_mem(struct proc *p, void *ptr, uint64_t size, void *data, uint64_t *n); 28 | int proc_write_mem(struct proc *p, void *ptr, uint64_t size, void *data, uint64_t *n); 29 | int proc_allocate(struct proc*p, void **address, uint64_t size); 30 | int proc_deallocate(struct proc *p, void *address, uint64_t size); 31 | int proc_mprotect(struct proc *p, void *address, void *end, int new_prot); 32 | int proc_create_thread(struct proc *p, uint64_t address); 33 | int proc_map_elf(struct proc *p, void *elf, void *exec); 34 | int proc_relocate_elf(struct proc *p, void *elf, void *exec); 35 | int proc_load_elf(struct proc *p, void *elf, uint64_t *elfbase, uint64_t *entry); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /installer/include/rpcasm.h: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #ifndef _RPCASM_H 6 | #define _RPCASM_H 7 | 8 | #include 9 | 10 | #define RPCSTUB_MAGIC 0x42545352 11 | 12 | struct rpcstub_header { 13 | uint32_t magic; 14 | uint64_t entry; 15 | uint64_t rpc_rip; 16 | uint64_t rpc_rdi; 17 | uint64_t rpc_rsi; 18 | uint64_t rpc_rdx; 19 | uint64_t rpc_rcx; 20 | uint64_t rpc_r8; 21 | uint64_t rpc_r9; 22 | uint64_t rpc_rax; 23 | uint8_t rpc_go; 24 | uint8_t rpc_done; 25 | } __attribute__((packed)); 26 | 27 | #define RPCLDR_MAGIC 0x52444C52 28 | 29 | struct rpcldr_header { 30 | uint32_t magic; 31 | uint64_t entry; 32 | uint8_t ldrdone; 33 | uint64_t stubentry; 34 | uint64_t scePthreadAttrInit; 35 | uint64_t scePthreadAttrSetstacksize; 36 | uint64_t scePthreadCreate; 37 | uint64_t thr_initial; 38 | } __attribute__((packed)); 39 | 40 | static const uint8_t rpcstub[410] = { 41 | 0x52, 0x53, 0x54, 0x42, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 42 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x69, 0x62, 0x6B, 0x65, 0x72, 48 | 0x6E, 0x65, 0x6C, 0x2E, 0x73, 0x70, 0x72, 0x78, 0x00, 0x6C, 0x69, 0x62, 49 | 0x6B, 0x65, 0x72, 0x6E, 0x65, 0x6C, 0x5F, 0x77, 0x65, 0x62, 0x2E, 0x73, 50 | 0x70, 0x72, 0x78, 0x00, 0x6C, 0x69, 0x62, 0x6B, 0x65, 0x72, 0x6E, 0x65, 51 | 0x6C, 0x5F, 0x73, 0x79, 0x73, 0x2E, 0x73, 0x70, 0x72, 0x78, 0x00, 0x00, 52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x63, 0x65, 0x4B, 0x65, 53 | 0x72, 0x6E, 0x65, 0x6C, 0x55, 0x73, 0x6C, 0x65, 0x65, 0x70, 0x00, 0x00, 54 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB9, 0x00, 0x00, 0x00, 0x00, 55 | 0x48, 0x8D, 0x15, 0xD4, 0xFF, 0xFF, 0xFF, 0xBE, 0x00, 0x00, 0x00, 0x00, 56 | 0x48, 0x8D, 0x3D, 0x93, 0xFF, 0xFF, 0xFF, 0xE8, 0xC4, 0x00, 0x00, 0x00, 57 | 0x48, 0x85, 0xC0, 0x74, 0x3F, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 58 | 0x15, 0xB2, 0xFF, 0xFF, 0xFF, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 59 | 0x3D, 0x80, 0xFF, 0xFF, 0xFF, 0xE8, 0xA2, 0x00, 0x00, 0x00, 0x48, 0x85, 60 | 0xC0, 0x74, 0x1D, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x15, 0x90, 61 | 0xFF, 0xFF, 0xFF, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x3D, 0x71, 62 | 0xFF, 0xFF, 0xFF, 0xE8, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x15, 0x90, 63 | 0xFF, 0xFF, 0xFF, 0x48, 0x8D, 0x35, 0x79, 0xFF, 0xFF, 0xFF, 0x48, 0x8B, 64 | 0x3D, 0x6A, 0xFF, 0xFF, 0xFF, 0xE8, 0x71, 0x00, 0x00, 0x00, 0x80, 0x3D, 65 | 0x27, 0xFF, 0xFF, 0xFF, 0x00, 0x74, 0x49, 0x4C, 0x8B, 0x0D, 0x0E, 0xFF, 66 | 0xFF, 0xFF, 0x4C, 0x8B, 0x05, 0xFF, 0xFE, 0xFF, 0xFF, 0x48, 0x8B, 0x0D, 67 | 0xF0, 0xFE, 0xFF, 0xFF, 0x48, 0x8B, 0x15, 0xE1, 0xFE, 0xFF, 0xFF, 0x48, 68 | 0x8B, 0x35, 0xD2, 0xFE, 0xFF, 0xFF, 0x48, 0x8B, 0x3D, 0xC3, 0xFE, 0xFF, 69 | 0xFF, 0x4C, 0x8B, 0x25, 0xB4, 0xFE, 0xFF, 0xFF, 0x41, 0xFF, 0xD4, 0x48, 70 | 0x89, 0x05, 0xE2, 0xFE, 0xFF, 0xFF, 0xC6, 0x05, 0xE3, 0xFE, 0xFF, 0xFF, 71 | 0x00, 0xC6, 0x05, 0xDD, 0xFE, 0xFF, 0xFF, 0x01, 0xBF, 0xA0, 0x86, 0x01, 72 | 0x00, 0x4C, 0x8B, 0x25, 0x1F, 0xFF, 0xFF, 0xFF, 0x41, 0xFF, 0xD4, 0xEB, 73 | 0x9D, 0x31, 0xC0, 0xC3, 0xB8, 0x52, 0x02, 0x00, 0x00, 0x49, 0x89, 0xCA, 74 | 0x0F, 0x05, 0xC3, 0xB8, 0x4F, 0x02, 0x00, 0x00, 0x49, 0x89, 0xCA, 0x0F, 75 | 0x05, 0xC3 76 | }; 77 | 78 | static const uint8_t rpcldr[255] = { 79 | 0x52, 0x4C, 0x44, 0x52, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 80 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 81 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 82 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 83 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 84 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x70, 0x63, 85 | 0x73, 0x74, 0x75, 0x62, 0x00, 0x48, 0x8B, 0x3D, 0xD9, 0xFF, 0xFF, 0xFF, 86 | 0x48, 0x8B, 0x37, 0x48, 0x8B, 0xBE, 0xE0, 0x01, 0x00, 0x00, 0xE8, 0x7A, 87 | 0x00, 0x00, 0x00, 0x48, 0x8D, 0x3D, 0xD3, 0xFF, 0xFF, 0xFF, 0x4C, 0x8B, 88 | 0x25, 0xA4, 0xFF, 0xFF, 0xFF, 0x41, 0xFF, 0xD4, 0xBE, 0x00, 0x00, 0x08, 89 | 0x00, 0x48, 0x8D, 0x3D, 0xBD, 0xFF, 0xFF, 0xFF, 0x4C, 0x8B, 0x25, 0x96, 90 | 0xFF, 0xFF, 0xFF, 0x41, 0xFF, 0xD4, 0x4C, 0x8D, 0x05, 0xB4, 0xFF, 0xFF, 91 | 0xFF, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x15, 0x70, 0xFF, 0xFF, 92 | 0xFF, 0x48, 0x8D, 0x35, 0x99, 0xFF, 0xFF, 0xFF, 0x48, 0x8D, 0x3D, 0x8A, 93 | 0xFF, 0xFF, 0xFF, 0x4C, 0x8B, 0x25, 0x73, 0xFF, 0xFF, 0xFF, 0x41, 0xFF, 94 | 0xD4, 0xC6, 0x05, 0x50, 0xFF, 0xFF, 0xFF, 0x01, 0xBF, 0x00, 0x00, 0x00, 95 | 0x00, 0xE8, 0x01, 0x00, 0x00, 0x00, 0xC3, 0xB8, 0xAF, 0x01, 0x00, 0x00, 96 | 0x49, 0x89, 0xCA, 0x0F, 0x05, 0xC3, 0xB8, 0xA5, 0x00, 0x00, 0x00, 0x49, 97 | 0x89, 0xCA, 0x0F, 0x05, 0xC3, 0x55, 0x48, 0x89, 0xE5, 0x53, 0x48, 0x83, 98 | 0xEC, 0x18, 0x48, 0x89, 0x7D, 0xE8, 0x48, 0x8D, 0x75, 0xE8, 0xBF, 0x81, 99 | 0x00, 0x00, 0x00, 0xE8, 0xDA, 0xFF, 0xFF, 0xFF, 0x48, 0x83, 0xC4, 0x18, 100 | 0x5B, 0x5D, 0xC3 101 | }; 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /installer/include/syscall.h: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #ifndef _SYSCALL_H 6 | #define _SYSCALL_H 7 | 8 | #define SYSCALL(name, number) \ 9 | __asm__(".intel_syntax noprefix"); \ 10 | __asm__(".globl " #name ""); \ 11 | __asm__("" #name ":"); \ 12 | __asm__("movq rax, " #number ""); \ 13 | __asm__("jmp syscall_macro"); \ 14 | 15 | unsigned long syscall(unsigned long n, ...); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /installer/linker.x: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") 2 | OUTPUT_ARCH(i386:x86-64) 3 | 4 | ENTRY(_start) 5 | 6 | PHDRS 7 | { 8 | code_seg PT_LOAD; 9 | rdata_seg PT_LOAD; 10 | data_seg PT_LOAD; 11 | bss_seg PT_LOAD; 12 | } 13 | 14 | SECTIONS 15 | { 16 | . = 0x926200000; 17 | .text : { 18 | *(.text.start) 19 | *(.text*) 20 | } : code_seg 21 | .rodata : { 22 | *(.rodata) 23 | *(.rodata*) 24 | } : rdata_seg 25 | .data : { *(.data) } : data_seg 26 | .bss : { *(.bss) } : bss_seg 27 | /DISCARD/ : { 28 | *(.comment) 29 | *(.note.GNU-stack) 30 | *(.eh_frame) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /installer/source/elf.c: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #include "elf.h" 6 | 7 | int elf_mapped_size(void *elf, uint64_t *msize) { 8 | struct Elf64_Ehdr *ehdr = (struct Elf64_Ehdr *)elf; 9 | 10 | // check magic 11 | if (memcmp(ehdr->e_ident, ElfMagic, 4)) { 12 | return LDR_INVALID_ELF; 13 | } 14 | 15 | uint64_t s = 0; 16 | 17 | struct Elf64_Phdr *phdr = elf_pheader(ehdr); 18 | if (phdr) { 19 | // use segments 20 | for (int i = 0; i < ehdr->e_phnum; i++) { 21 | struct Elf64_Phdr *phdr = elf_segment(ehdr, i); 22 | 23 | uint64_t delta = phdr->p_paddr + phdr->p_memsz; 24 | if (delta > s) { 25 | s = delta; 26 | } 27 | } 28 | } else { 29 | // use sections 30 | for (int i = 0; i < ehdr->e_shnum; i++) { 31 | struct Elf64_Shdr *shdr = elf_section(ehdr, i); 32 | 33 | uint64_t delta = shdr->sh_addr + shdr->sh_size; 34 | if (delta > s) { 35 | s = delta; 36 | } 37 | } 38 | } 39 | 40 | if (msize) { 41 | *msize = s; 42 | } 43 | 44 | return LDR_SUCCESS; 45 | } 46 | 47 | int map_elf(void *elf, void *exec) { 48 | struct Elf64_Ehdr *ehdr = (struct Elf64_Ehdr *)elf; 49 | 50 | struct Elf64_Phdr *phdr = elf_pheader(ehdr); 51 | if (phdr) { 52 | // use segments 53 | for (int i = 0; i < ehdr->e_phnum; i++) { 54 | struct Elf64_Phdr *phdr = elf_segment(ehdr, i); 55 | 56 | if (phdr->p_filesz) { 57 | memcpy((uint8_t *)exec + phdr->p_paddr, (uint8_t *)elf + phdr->p_offset, phdr->p_filesz); 58 | } 59 | 60 | if (phdr->p_memsz - phdr->p_filesz) { 61 | memset((uint8_t *)exec + phdr->p_paddr + phdr->p_filesz, NULL, phdr->p_memsz - phdr->p_filesz); 62 | } 63 | } 64 | } else { 65 | // use sections 66 | for (int i = 0; i < ehdr->e_shnum; i++) { 67 | struct Elf64_Shdr *shdr = elf_section(ehdr, i); 68 | 69 | if (!(shdr->sh_flags & SHF_ALLOC)) { 70 | continue; 71 | } 72 | 73 | if (shdr->sh_size) { 74 | memcpy((uint8_t *)exec + shdr->sh_addr, (uint8_t *)elf + shdr->sh_offset, shdr->sh_size); 75 | } 76 | } 77 | } 78 | 79 | return LDR_SUCCESS; 80 | } 81 | 82 | int relocate_elf(void *elf, void *exec) { 83 | struct Elf64_Ehdr *ehdr = (struct Elf64_Ehdr *)elf; 84 | 85 | for (int i = 0; i < ehdr->e_shnum; i++) { 86 | struct Elf64_Shdr *shdr = elf_section(ehdr, i); 87 | 88 | // check table 89 | if (shdr->sh_type == SHT_REL) { 90 | // process each entry in the table 91 | for (int j = 0; j < shdr->sh_size / shdr->sh_entsize; j++) { 92 | struct Elf64_Rela *reltab = &((struct Elf64_Rela *)((uint64_t)ehdr + shdr->sh_offset))[j]; 93 | uint8_t **ref = (uint8_t **)((uint8_t *)exec + reltab->r_offset); 94 | 95 | switch (ELF64_R_TYPE(reltab->r_info)) { 96 | case R_X86_64_RELATIVE: 97 | *ref = (uint8_t *)exec + reltab->r_addend; 98 | break; 99 | case R_X86_64_64: 100 | case R_X86_64_JUMP_SLOT: 101 | case R_X86_64_GLOB_DAT: 102 | // not supported 103 | break; 104 | } 105 | } 106 | } 107 | } 108 | 109 | return LDR_SUCCESS; 110 | } 111 | 112 | int load_elf(void *elf, uint64_t size, void *exec, uint64_t msize, void **entry) { 113 | // check arguments 114 | if (!elf || !exec || !size || !msize) { 115 | return LDR_INVALID_ELF; 116 | } 117 | 118 | struct Elf64_Ehdr *ehdr = (struct Elf64_Ehdr *)elf; 119 | 120 | // check magic 121 | if (memcmp(ehdr->e_ident, ElfMagic, 4)) { 122 | return LDR_INVALID_ELF; 123 | } 124 | 125 | // only support relocatable elfs rn lol 126 | if (ehdr->e_type != ET_REL && ehdr->e_type != ET_DYN) { 127 | return LDR_INVALID_ELF; 128 | } 129 | 130 | uint64_t s = 0; 131 | if (elf_mapped_size(elf, &s)) { 132 | return LDR_SIZE_ERROR; 133 | } 134 | 135 | if (s > msize) { 136 | return LDR_SIZE_ERROR; 137 | } 138 | 139 | if (map_elf(elf, exec)) { 140 | return LDR_MAP_ERROR; 141 | } 142 | 143 | if (relocate_elf(elf, exec)) { 144 | return LDR_RELOC_ERROR; 145 | } 146 | 147 | if (entry) { 148 | *entry = (void *)((uint64_t)exec + ehdr->e_entry); 149 | } 150 | 151 | return LDR_SUCCESS; 152 | } 153 | -------------------------------------------------------------------------------- /installer/source/embed.s: -------------------------------------------------------------------------------- 1 | .section .rodata 2 | 3 | .global kernelelf 4 | .type kernelelf, @object 5 | .align 4 6 | kernelelf: 7 | .incbin "../kdebugger/kdebugger.elf" 8 | kernelelfend: 9 | .global kernelelf_size 10 | .type kernelelf_size, @object 11 | .align 4 12 | kernelelf_size: 13 | .int kernelelfend - kernelelf 14 | 15 | .global debuggerbin 16 | .type debuggerbin, @object 17 | .align 4 18 | debuggerbin: 19 | .incbin "../debugger/debugger.bin" 20 | debuggerbinend: 21 | .global debuggerbin_size 22 | .type debuggerbin_size, @object 23 | .align 4 24 | debuggerbin_size: 25 | .int debuggerbinend - debuggerbin 26 | -------------------------------------------------------------------------------- /installer/source/installer.c: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #include "installer.h" 6 | 7 | extern uint8_t kernelelf[]; 8 | extern int32_t kernelelf_size; 9 | 10 | extern uint8_t debuggerbin[]; 11 | extern int32_t debuggerbin_size; 12 | 13 | void ascii_art() { 14 | printf("\n\n"); 15 | printf(" _____ .___ ___. \n"); 16 | printf("______ ______ / | | __| _/____\\_ |__ __ __ ____ \n"); 17 | printf("\\____ \\/ ___// | |_/ __ |/ __ \\| __ \\| | \\/ ___\\ \n"); 18 | printf("| |_> >___ \\/ ^ / /_/ \\ ___/| \\_\\ \\ | / /_/ >\n"); 19 | printf("| __/____ >____ |\\____ |\\___ >___ /____/\\___ / \n"); 20 | printf("|__| \\/ |__| \\/ \\/ \\/ /_____/ \n"); 21 | printf(" \n"); 22 | } 23 | 24 | void patch_kernel() { 25 | cpu_disable_wp(); 26 | 27 | uint64_t kernbase = get_kbase(); 28 | 29 | // patch memcpy first 30 | *(uint8_t *)(kernbase + 0x28F80D) = 0xEB; 31 | 32 | // patch sceSblACMgrIsAllowedSystemLevelDebugging 33 | memcpy((void *)(kernbase + 0x364CD0), "\x48\xC7\xC0\x01\x00\x00\x00\xC3", 8); 34 | 35 | // patch sceSblACMgrHasMmapSelfCapability 36 | memcpy((void *)(kernbase + 0x364D40), "\x48\xC7\xC0\x01\x00\x00\x00\xC3", 8); 37 | 38 | // patch sceSblACMgrIsAllowedToMmapSelf 39 | memcpy((void *)(kernbase + 0x364D60), "\x48\xC7\xC0\x01\x00\x00\x00\xC3", 8); 40 | 41 | // disable sysdump_perform_dump_on_fatal_trap 42 | // will continue execution and give more information on crash, such as rip 43 | *(uint8_t *)(kernbase + 0x0077F9A0) = 0xC3; 44 | 45 | // self patches 46 | memcpy((void *)(kernbase + 0x0DCED1), "\x31\xC0\x90\x90\x90", 5); 47 | 48 | // patch vm_map_protect check 49 | memcpy((void *)(kernbase + 0x003014C8), "\x90\x90\x90\x90\x90\x90", 6); 50 | 51 | // patch ptrace 52 | *(uint8_t *)(kernbase + 0x361CF5) = 0xEB; 53 | memcpy((void *)(kernbase + 0x3621CF), "\xE9\x7C\x02\x00\x00", 5); 54 | 55 | // patch ASLR, thanks 2much4u 56 | *(uint8_t *)(kernbase + 0x218AF4) = 0xEB; 57 | 58 | // patch kmem_alloc 59 | *(uint8_t *)(kernbase + 0x1754AC) = VM_PROT_ALL; 60 | *(uint8_t *)(kernbase + 0x1754B4) = VM_PROT_ALL; 61 | 62 | cpu_enable_wp(); 63 | } 64 | 65 | void *rwx_alloc(uint64_t size) { 66 | uint64_t alignedSize = (size + 0x3FFFull) & ~0x3FFFull; 67 | return (void *)kmem_alloc(*kernel_map, alignedSize); 68 | } 69 | 70 | int load_kdebugger() { 71 | uint64_t mapsize; 72 | void *kmemory; 73 | int (*payload_entry)(void *p); 74 | 75 | // calculate mapped size 76 | if (elf_mapped_size(kernelelf, &mapsize)) { 77 | printf("[ps4debug] invalid kdebugger elf!\n"); 78 | return 1; 79 | } 80 | 81 | // allocate memory 82 | kmemory = rwx_alloc(mapsize); 83 | if(!kmemory) { 84 | printf("[ps4debug] could not allocate memory for kdebugger!\n"); 85 | return 1; 86 | } 87 | 88 | // load the elf 89 | if (load_elf(kernelelf, kernelelf_size, kmemory, mapsize, (void **)&payload_entry)) { 90 | printf("[ps4debug] could not load kdebugger elf!\n"); 91 | return 1; 92 | } 93 | 94 | // call entry 95 | if (payload_entry(NULL)) { 96 | return 1; 97 | } 98 | 99 | return 0; 100 | } 101 | 102 | int load_debugger() { 103 | struct proc *p; 104 | struct vmspace *vm; 105 | struct vm_map *map; 106 | int r; 107 | 108 | p = proc_find_by_name("SceShellCore"); 109 | if(!p) { 110 | printf("[ps4debug] could not find SceShellCore process!\n"); 111 | return 1; 112 | } 113 | 114 | vm = p->p_vmspace; 115 | map = &vm->vm_map; 116 | 117 | // allocate some memory 118 | vm_map_lock(map); 119 | r = vm_map_insert(map, NULL, NULL, PAYLOAD_BASE, PAYLOAD_BASE + 0x400000, VM_PROT_ALL, VM_PROT_ALL, 0); 120 | vm_map_unlock(map); 121 | if(r) { 122 | printf("[ps4debug] failed to allocate payload memory!\n"); 123 | return r; 124 | } 125 | 126 | // write the payload 127 | r = proc_write_mem(p, (void *)PAYLOAD_BASE, debuggerbin_size, debuggerbin, NULL); 128 | if(r) { 129 | printf("[ps4debug] failed to write payload!\n"); 130 | return r; 131 | } 132 | 133 | // create a thread 134 | r = proc_create_thread(p, PAYLOAD_BASE); 135 | if(r) { 136 | printf("[ps4debug] failed to create payload thread!\n"); 137 | return r; 138 | } 139 | 140 | return 0; 141 | } 142 | 143 | int runinstaller() { 144 | init_ksdk(); 145 | 146 | // enable uart 147 | *disable_console_output = 0; 148 | 149 | ascii_art(); 150 | 151 | // patch the kernel 152 | printf("[ps4debug] patching kernel...\n"); 153 | patch_kernel(); 154 | 155 | printf("[ps4debug] loading kdebugger...\n"); 156 | 157 | if(load_kdebugger()) { 158 | return 1; 159 | } 160 | 161 | printf("[ps4debug] loading debugger...\n"); 162 | 163 | if(load_debugger()) { 164 | return 1; 165 | } 166 | 167 | printf("[ps4debug] ps4debug created by golden\n"); 168 | 169 | return 0; 170 | } 171 | -------------------------------------------------------------------------------- /installer/source/main.c: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #include "syscall.h" 6 | #include "installer.h" 7 | 8 | int _main(void) { 9 | return syscall(11, runinstaller); 10 | } 11 | -------------------------------------------------------------------------------- /installer/source/proc.c: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #include "proc.h" 6 | 7 | struct proc *proc_find_by_name(const char *name) { 8 | struct proc *p; 9 | 10 | if (!name) { 11 | return NULL; 12 | } 13 | 14 | p = *allproc; 15 | do { 16 | if (!memcmp(p->p_comm, name, strlen(name))) { 17 | return p; 18 | } 19 | } while ((p = p->p_forw)); 20 | 21 | return NULL; 22 | } 23 | 24 | struct proc *proc_find_by_pid(int pid) { 25 | struct proc *p; 26 | 27 | p = *allproc; 28 | do { 29 | if (p->pid == pid) { 30 | return p; 31 | } 32 | } while ((p = p->p_forw)); 33 | 34 | return NULL; 35 | } 36 | 37 | int proc_get_vm_map(struct proc *p, struct proc_vm_map_entry **entries, uint64_t *num_entries) { 38 | struct proc_vm_map_entry *info = NULL; 39 | struct vm_map_entry *entry = NULL; 40 | int r = 0; 41 | 42 | struct vmspace *vm = p->p_vmspace; 43 | struct vm_map *map = &vm->vm_map; 44 | 45 | vm_map_lock_read(map); 46 | 47 | int num = map->nentries; 48 | if (!num) { 49 | goto error; 50 | } 51 | 52 | r = vm_map_lookup_entry(map, NULL, &entry); 53 | if(r) { 54 | goto error; 55 | } 56 | 57 | info = (struct proc_vm_map_entry *)malloc(num * sizeof(struct proc_vm_map_entry), M_TEMP, 2); 58 | if (!info) { 59 | r = 1; 60 | goto error; 61 | } 62 | 63 | for (int i = 0; i < num; i++) { 64 | info[i].start = entry->start; 65 | info[i].end = entry->end; 66 | info[i].offset = entry->offset; 67 | info[i].prot = entry->prot & (entry->prot >> 8); 68 | memcpy(info[i].name, entry->name, sizeof(info[i].name)); 69 | 70 | if (!(entry = entry->next)) { 71 | break; 72 | } 73 | } 74 | 75 | error: 76 | vm_map_unlock_read(map); 77 | 78 | if (entries) { 79 | *entries = info; 80 | } 81 | 82 | if (num_entries) { 83 | *num_entries = num; 84 | } 85 | 86 | return 0; 87 | } 88 | 89 | int proc_rw_mem(struct proc *p, void *ptr, uint64_t size, void *data, uint64_t *n, int write) { 90 | struct thread *td = curthread(); 91 | struct iovec iov; 92 | struct uio uio; 93 | int r = 0; 94 | 95 | if (!p) { 96 | return 1; 97 | } 98 | 99 | if (size == 0) { 100 | if (n) { 101 | *n = 0; 102 | } 103 | 104 | return 0; 105 | } 106 | 107 | memset(&iov, NULL, sizeof(iov)); 108 | iov.iov_base = (uint64_t)data; 109 | iov.iov_len = size; 110 | 111 | memset(&uio, NULL, sizeof(uio)); 112 | uio.uio_iov = (uint64_t)&iov; 113 | uio.uio_iovcnt = 1; 114 | uio.uio_offset = (uint64_t)ptr; 115 | uio.uio_resid = (uint64_t)size; 116 | uio.uio_segflg = UIO_SYSSPACE; 117 | uio.uio_rw = write ? UIO_WRITE : UIO_READ; 118 | uio.uio_td = td; 119 | 120 | r = proc_rwmem(p, &uio); 121 | 122 | if (n) { 123 | *n = (uint64_t)((uint64_t)size - uio.uio_resid); 124 | } 125 | 126 | return r; 127 | } 128 | 129 | inline int proc_read_mem(struct proc *p, void *ptr, uint64_t size, void *data, uint64_t *n) { 130 | return proc_rw_mem(p, ptr, size, data, n, 0); 131 | } 132 | 133 | inline int proc_write_mem(struct proc *p, void *ptr, uint64_t size, void *data, uint64_t *n) { 134 | return proc_rw_mem(p, ptr, size, data, n, 1); 135 | } 136 | 137 | int proc_allocate(struct proc *p, void **address, uint64_t size) { 138 | uint64_t addr = NULL; 139 | int r = 0; 140 | 141 | if (!address) { 142 | r = 1; 143 | goto error; 144 | } 145 | 146 | struct vmspace *vm = p->p_vmspace; 147 | struct vm_map *map = &vm->vm_map; 148 | 149 | vm_map_lock(map); 150 | 151 | r = vm_map_findspace(map, NULL, size, &addr); 152 | if (r) { 153 | vm_map_unlock(map); 154 | goto error; 155 | } 156 | 157 | r = vm_map_insert(map, NULL, NULL, addr, addr + size, VM_PROT_ALL, VM_PROT_ALL, 0); 158 | 159 | vm_map_unlock(map); 160 | 161 | if (r) { 162 | goto error; 163 | } 164 | 165 | if (address) { 166 | *address = (void *)addr; 167 | } 168 | 169 | error: 170 | return r; 171 | } 172 | 173 | int proc_deallocate(struct proc *p, void *address, uint64_t size) { 174 | int r = 0; 175 | 176 | struct vmspace *vm = p->p_vmspace; 177 | struct vm_map *map = &vm->vm_map; 178 | 179 | vm_map_lock(map); 180 | 181 | r = vm_map_delete(map, (uint64_t)address, (uint64_t)address + size); 182 | 183 | vm_map_unlock(map); 184 | 185 | return r; 186 | } 187 | 188 | int proc_mprotect(struct proc *p, void *address, void *end, int new_prot) { 189 | int r = 0; 190 | 191 | uint64_t addr = (uint64_t)address; 192 | uint64_t addrend = (uint64_t)end; 193 | 194 | struct vmspace *vm = p->p_vmspace; 195 | struct vm_map *map = &vm->vm_map; 196 | 197 | // update the max prot then set new prot 198 | r = vm_map_protect(map, addr, addrend, new_prot, 1); 199 | if (r) { 200 | return r; 201 | } 202 | 203 | r = vm_map_protect(map, addr, addrend, new_prot, 0); 204 | 205 | return r; 206 | } 207 | 208 | int proc_create_thread(struct proc *p, uint64_t address) { 209 | void *rpcldraddr = NULL; 210 | void *stackaddr = NULL; 211 | struct proc_vm_map_entry *entries = NULL; 212 | uint64_t num_entries = 0; 213 | uint64_t n = 0; 214 | int r = 0; 215 | 216 | uint64_t ldrsize = sizeof(rpcldr); 217 | ldrsize += (PAGE_SIZE - (ldrsize % PAGE_SIZE)); 218 | 219 | uint64_t stacksize = 0x80000; 220 | 221 | // allocate rpc ldr 222 | r = proc_allocate(p, &rpcldraddr, ldrsize); 223 | if (r) { 224 | goto error; 225 | } 226 | 227 | // allocate stack 228 | r = proc_allocate(p, &stackaddr, stacksize); 229 | if (r) { 230 | goto error; 231 | } 232 | 233 | // write loader 234 | r = proc_write_mem(p, rpcldraddr, sizeof(rpcldr), (void *)rpcldr, &n); 235 | if (r) { 236 | goto error; 237 | } 238 | 239 | // donor thread 240 | struct thread *thr = TAILQ_FIRST(&p->p_threads); 241 | 242 | // find libkernel base 243 | r = proc_get_vm_map(p, &entries, &num_entries); 244 | if (r) { 245 | goto error; 246 | } 247 | 248 | // offsets are for 7.55 libraries 249 | 250 | // libkernel.sprx 251 | // 0x13630 scePthreadAttrInit 252 | // 0x13650 scePthreadAttrSetstacksize 253 | // 0x13A70 scePthreadCreate 254 | // 0x8D420 thr_initial 255 | 256 | // libkernel_web.sprx 257 | // 0x1FA70 scePthreadAttrInit 258 | // 0x10380 scePthreadAttrSetstacksize 259 | // 0x09F10 scePthreadCreate 260 | // 0x8D420 thr_initial 261 | 262 | // libkernel_sys.sprx 263 | // 0x14160 scePthreadAttrInit 264 | // 0x14180 scePthreadAttrSetstacksize 265 | // 0x145A0 scePthreadCreate 266 | // 0x8D830 thr_initial 267 | 268 | uint64_t _scePthreadAttrInit = 0, _scePthreadAttrSetstacksize = 0, _scePthreadCreate = 0, _thr_initial = 0; 269 | for (int i = 0; i < num_entries; i++) { 270 | if (entries[i].prot != (PROT_READ | PROT_EXEC)) { 271 | continue; 272 | } 273 | 274 | if (!memcmp(entries[i].name, "libkernel.sprx", 14)) { 275 | _scePthreadAttrInit = entries[i].start + 0x13630; 276 | _scePthreadAttrSetstacksize = entries[i].start + 0x13650; 277 | _scePthreadCreate = entries[i].start + 0x13A70; 278 | _thr_initial = entries[i].start + 0x8D420; 279 | break; 280 | } 281 | if (!memcmp(entries[i].name, "libkernel_web.sprx", 18)) 282 | { 283 | _scePthreadAttrInit = entries[i].start + 0x1FA70; 284 | _scePthreadAttrSetstacksize = entries[i].start + 0x10380; 285 | _scePthreadCreate = entries[i].start + 0x09F10; 286 | _thr_initial = entries[i].start + 0x8D420; 287 | break; 288 | } 289 | if (!memcmp(entries[i].name, "libkernel_sys.sprx", 18)) { 290 | _scePthreadAttrInit = entries[i].start + 0x14160; 291 | _scePthreadAttrSetstacksize = entries[i].start + 0x14180; 292 | _scePthreadCreate = entries[i].start + 0x145A0; 293 | _thr_initial = entries[i].start + 0x8D830; 294 | break; 295 | } 296 | } 297 | 298 | if (!_scePthreadAttrInit) { 299 | goto error; 300 | } 301 | 302 | // write variables 303 | r = proc_write_mem(p, rpcldraddr + offsetof(struct rpcldr_header, stubentry), sizeof(address), (void *)&address, &n); 304 | if (r) { 305 | goto error; 306 | } 307 | 308 | r = proc_write_mem(p, rpcldraddr + offsetof(struct rpcldr_header, scePthreadAttrInit), sizeof(_scePthreadAttrInit), (void *)&_scePthreadAttrInit, &n); 309 | if (r) { 310 | goto error; 311 | } 312 | 313 | r = proc_write_mem(p, rpcldraddr + offsetof(struct rpcldr_header, scePthreadAttrSetstacksize), sizeof(_scePthreadAttrSetstacksize), (void *)&_scePthreadAttrSetstacksize, &n); 314 | if (r) { 315 | goto error; 316 | } 317 | 318 | r = proc_write_mem(p, rpcldraddr + offsetof(struct rpcldr_header, scePthreadCreate), sizeof(_scePthreadCreate), (void *)&_scePthreadCreate, &n); 319 | if (r) { 320 | goto error; 321 | } 322 | 323 | r = proc_write_mem(p, rpcldraddr + offsetof(struct rpcldr_header, thr_initial), sizeof(_thr_initial), (void *)&_thr_initial, &n); 324 | if (r) { 325 | goto error; 326 | } 327 | 328 | // execute loader 329 | // note: do not enter in the pid information as it expects it to be stored in userland 330 | uint64_t ldrentryaddr = (uint64_t)rpcldraddr + *(uint64_t *)(rpcldr + 4); 331 | r = create_thread(thr, NULL, (void *)ldrentryaddr, NULL, stackaddr, stacksize, NULL, NULL, NULL, 0, NULL); 332 | if (r) { 333 | goto error; 334 | } 335 | 336 | // wait until loader is done 337 | uint8_t ldrdone = 0; 338 | while (!ldrdone) { 339 | r = proc_read_mem(p, (void *)(rpcldraddr + offsetof(struct rpcldr_header, ldrdone)), sizeof(ldrdone), &ldrdone, &n); 340 | if (r) { 341 | goto error; 342 | } 343 | } 344 | 345 | error: 346 | if (entries) { 347 | free(entries, M_TEMP); 348 | } 349 | 350 | if (rpcldraddr) { 351 | proc_deallocate(p, rpcldraddr, ldrsize); 352 | } 353 | 354 | if (stackaddr) { 355 | proc_deallocate(p, stackaddr, stacksize); 356 | } 357 | 358 | return r; 359 | } 360 | 361 | int proc_map_elf(struct proc *p, void *elf, void *exec) { 362 | struct Elf64_Ehdr *ehdr = (struct Elf64_Ehdr *)elf; 363 | 364 | struct Elf64_Phdr *phdr = elf_pheader(ehdr); 365 | if (phdr) { 366 | // use segments 367 | for (int i = 0; i < ehdr->e_phnum; i++) { 368 | struct Elf64_Phdr *phdr = elf_segment(ehdr, i); 369 | 370 | if (phdr->p_filesz) { 371 | proc_write_mem(p, (void *)((uint8_t *)exec + phdr->p_paddr), phdr->p_filesz, (void *)((uint8_t *)elf + phdr->p_offset), NULL); 372 | } 373 | } 374 | } else { 375 | // use sections 376 | for (int i = 0; i < ehdr->e_shnum; i++) { 377 | struct Elf64_Shdr *shdr = elf_section(ehdr, i); 378 | 379 | if (!(shdr->sh_flags & SHF_ALLOC)) { 380 | continue; 381 | } 382 | 383 | if (shdr->sh_size) { 384 | proc_write_mem(p, (void *)((uint8_t *)exec + shdr->sh_addr), shdr->sh_size, (void *)((uint8_t *)elf + shdr->sh_offset), NULL); 385 | } 386 | } 387 | } 388 | 389 | return 0; 390 | } 391 | 392 | int proc_relocate_elf(struct proc *p, void *elf, void *exec) { 393 | struct Elf64_Ehdr *ehdr = (struct Elf64_Ehdr *)elf; 394 | 395 | for (int i = 0; i < ehdr->e_shnum; i++) { 396 | struct Elf64_Shdr *shdr = elf_section(ehdr, i); 397 | 398 | // check table 399 | if (shdr->sh_type == SHT_REL) { 400 | // process each entry in the table 401 | for (int j = 0; j < shdr->sh_size / shdr->sh_entsize; j++) { 402 | struct Elf64_Rela *reltab = &((struct Elf64_Rela *)((uint64_t)ehdr + shdr->sh_offset))[j]; 403 | uint8_t **ref = (uint8_t **)((uint8_t *)exec + reltab->r_offset); 404 | uint8_t *value = NULL; 405 | 406 | switch (ELF64_R_TYPE(reltab->r_info)) { 407 | case R_X86_64_RELATIVE: 408 | // *ref = (uint8_t *)exec + reltab->r_addend; 409 | value = (uint8_t *)exec + reltab->r_addend; 410 | proc_write_mem(p, ref, sizeof(value), (void *)&value, NULL); 411 | break; 412 | case R_X86_64_64: 413 | case R_X86_64_JUMP_SLOT: 414 | case R_X86_64_GLOB_DAT: 415 | // not supported 416 | break; 417 | } 418 | } 419 | } 420 | } 421 | 422 | return 0; 423 | } 424 | 425 | int proc_load_elf(struct proc *p, void *elf, uint64_t *elfbase, uint64_t *entry) { 426 | void *elfaddr = NULL; 427 | uint64_t msize = 0; 428 | int r = 0; 429 | 430 | struct Elf64_Ehdr *ehdr = (struct Elf64_Ehdr *)elf; 431 | 432 | r = elf_mapped_size(elf, &msize); 433 | if (r) { 434 | goto error; 435 | } 436 | 437 | // resize to pages 438 | msize += (PAGE_SIZE - (msize % PAGE_SIZE)); 439 | 440 | // allocate 441 | r = proc_allocate(p, &elfaddr, msize); 442 | if (r) { 443 | goto error; 444 | } 445 | 446 | // map 447 | r = proc_map_elf(p, elf, elfaddr); 448 | if (r) { 449 | goto error; 450 | } 451 | 452 | // relocate 453 | r = proc_relocate_elf(p, elf, elfaddr); 454 | if (r) { 455 | goto error; 456 | } 457 | 458 | if (elfbase) { 459 | *elfbase = (uint64_t)elfaddr; 460 | } 461 | 462 | if (entry) { 463 | *entry = (uint64_t)elfaddr + ehdr->e_entry; 464 | } 465 | 466 | error: 467 | return r; 468 | } 469 | -------------------------------------------------------------------------------- /installer/source/syscall.s: -------------------------------------------------------------------------------- 1 | .intel_syntax noprefix 2 | 3 | .extern __error 4 | 5 | .text 6 | 7 | .globl syscall 8 | syscall: 9 | xor rax, rax 10 | 11 | .globl syscall_macro 12 | syscall_macro: 13 | mov r10, rcx 14 | syscall 15 | ret 16 | -------------------------------------------------------------------------------- /kdebugger/Makefile: -------------------------------------------------------------------------------- 1 | KSDK := ../ps4-ksdk/ 2 | 3 | LFILE = ./kdebugger.x 4 | 5 | CC := gcc 6 | AS := gcc 7 | OBJCOPY := objcopy 8 | ODIR := build 9 | SDIR := source 10 | IDIRS := -I$(KSDK)/include -I. -Iinclude 11 | LDIRS := -L$(KSDK) -L. -Llib 12 | CFLAGS := $(IDIRS) -O3 -std=gnu11 -fno-builtin -fno-exceptions -fno-asynchronous-unwind-tables -nostartfiles -nostdlib -Wall -masm=intel -march=btver2 -mtune=btver2 -m64 -mabi=sysv -mcmodel=small -fPIE 13 | SFLAGS := -nostartfiles -nostdlib -masm=intel -march=btver2 -mtune=btver2 -m64 -mabi=sysv -mcmodel=small 14 | LFLAGS := $(LDIRS) -Xlinker -T $(LFILE) -Wl,--build-id=none -pie 15 | CFILES := $(wildcard $(SDIR)/*.c) 16 | SFILES := $(wildcard $(SDIR)/*.s) 17 | OBJS := $(patsubst $(SDIR)/%.c, $(ODIR)/%.o, $(CFILES)) $(patsubst $(SDIR)/%.s, $(ODIR)/%.o, $(SFILES)) 18 | 19 | LIBS := -lKSDK 20 | 21 | TARGET = kdebugger.elf 22 | 23 | $(TARGET): $(ODIR) $(OBJS) 24 | $(CC) crt0.s $(ODIR)/*.o -o $(TARGET) $(CFLAGS) $(LFLAGS) $(LIBS) 25 | elfedit --output-type=DYN $(TARGET) 26 | strip $(TARGET) 27 | 28 | $(ODIR)/%.o: $(SDIR)/%.c 29 | $(CC) -c -o $@ $< $(CFLAGS) 30 | 31 | $(ODIR)/%.o: $(SDIR)/%.s 32 | $(AS) -c -o $@ $< $(SFLAGS) 33 | 34 | $(ODIR): 35 | @mkdir $@ 36 | 37 | .PHONY: clean 38 | 39 | clean: 40 | rm -f $(TARGET) $(ODIR)/*.o -------------------------------------------------------------------------------- /kdebugger/crt0.s: -------------------------------------------------------------------------------- 1 | .intel_syntax noprefix 2 | .text 3 | 4 | .global _start 5 | _start: 6 | jmp _main 7 | -------------------------------------------------------------------------------- /kdebugger/include/hooks.h: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #ifndef _HOOKS_H 6 | #define _HOOKS_H 7 | 8 | #include 9 | #include "proc.h" 10 | #include "elf.h" 11 | 12 | // custom syscall 107 13 | struct proc_list_entry { 14 | char p_comm[32]; 15 | int pid; 16 | } __attribute__((packed)); 17 | 18 | struct sys_proc_list_args { 19 | struct proc_list_entry *procs; 20 | uint64_t *num; 21 | } __attribute__((packed)); 22 | int sys_proc_list(struct thread *td, struct sys_proc_list_args *uap); 23 | 24 | // custom syscall 108 25 | struct sys_proc_rw_args { 26 | uint64_t pid; 27 | uint64_t address; 28 | void *data; 29 | uint64_t length; 30 | uint64_t write; 31 | } __attribute__((packed)); 32 | int sys_proc_rw(struct thread *td, struct sys_proc_rw_args *uap); 33 | 34 | // custom syscall 109 35 | #define SYS_PROC_ALLOC 1 36 | #define SYS_PROC_FREE 2 37 | #define SYS_PROC_PROTECT 3 38 | #define SYS_PROC_VM_MAP 4 39 | #define SYS_PROC_INSTALL 5 40 | #define SYS_PROC_CALL 6 41 | #define SYS_PROC_ELF 7 42 | #define SYS_PROC_INFO 8 43 | #define SYS_PROC_THRINFO 9 44 | struct sys_proc_alloc_args { 45 | uint64_t address; 46 | uint64_t length; 47 | } __attribute__((packed)); 48 | struct sys_proc_free_args { 49 | uint64_t address; 50 | uint64_t length; 51 | } __attribute__((packed)); 52 | struct sys_proc_protect_args { 53 | uint64_t address; 54 | uint64_t length; 55 | uint64_t prot; 56 | } __attribute__((packed)); 57 | struct sys_proc_vm_map_args { 58 | struct proc_vm_map_entry *maps; 59 | uint64_t num; 60 | } __attribute__((packed)); 61 | struct sys_proc_install_args { 62 | uint64_t stubentryaddr; 63 | } __attribute__((packed)); 64 | struct sys_proc_call_args { 65 | uint32_t pid; 66 | uint64_t rpcstub; 67 | uint64_t rax; 68 | uint64_t rip; 69 | uint64_t rdi; 70 | uint64_t rsi; 71 | uint64_t rdx; 72 | uint64_t rcx; 73 | uint64_t r8; 74 | uint64_t r9; 75 | } __attribute__((packed)); 76 | struct sys_proc_elf_args { 77 | void *elf; 78 | } __attribute__((packed)); 79 | struct sys_proc_info_args { 80 | int pid; 81 | char name[40]; 82 | char path[64]; 83 | char titleid[16]; 84 | char contentid[64]; 85 | } __attribute__((packed)); 86 | struct sys_proc_thrinfo_args { 87 | uint32_t lwpid; 88 | uint32_t priority; 89 | char name[32]; 90 | } __attribute__((packed)); 91 | struct sys_proc_cmd_args { 92 | uint64_t pid; 93 | uint64_t cmd; 94 | void *data; 95 | } __attribute__((packed)); 96 | int sys_proc_cmd(struct thread *td, struct sys_proc_cmd_args *uap); 97 | 98 | // custom syscall 110 99 | struct sys_kern_base_args { 100 | uint64_t *kbase; 101 | } __attribute__((packed)); 102 | int sys_kern_base(struct thread *td, struct sys_kern_base_args *uap); 103 | 104 | // custom syscall 111 105 | struct sys_kern_rw_args { 106 | uint64_t address; 107 | void *data; 108 | uint64_t length; 109 | uint64_t write; 110 | } __attribute__((packed)); 111 | int sys_kern_rw(struct thread *td, struct sys_kern_rw_args *uap); 112 | 113 | // custom syscall 112 114 | #define SYS_CONSOLE_CMD_REBOOT 1 115 | #define SYS_CONSOLE_CMD_PRINT 2 116 | #define SYS_CONSOLE_CMD_JAILBREAK 3 117 | struct sys_console_cmd_args { 118 | uint64_t cmd; 119 | void *data; 120 | } __attribute__((packed)); 121 | int sys_console_cmd(struct thread *td, struct sys_console_cmd_args *uap); 122 | 123 | void hook_trap_fatal(struct trapframe *tf); 124 | void install_syscall(uint32_t n, void *func); 125 | int install_hooks(); 126 | 127 | #endif 128 | -------------------------------------------------------------------------------- /kdebugger/include/proc.h: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #ifndef _PROC_H 6 | #define _PROC_H 7 | 8 | #include 9 | #include "rpcasm.h" 10 | #include "elf.h" 11 | 12 | #define PAGE_SIZE 0x4000 13 | 14 | struct proc_vm_map_entry { 15 | char name[32]; 16 | uint64_t start; 17 | uint64_t end; 18 | uint64_t offset; 19 | uint16_t prot; 20 | } __attribute__((packed)); 21 | 22 | struct proc *proc_find_by_name(const char *name); 23 | struct proc *proc_find_by_pid(int pid); 24 | int proc_get_vm_map(struct proc *p, struct proc_vm_map_entry **entries, uint64_t *num_entries); 25 | 26 | int proc_rw_mem(struct proc *p, void *ptr, uint64_t size, void *data, uint64_t *n, int write); 27 | int proc_read_mem(struct proc *p, void *ptr, uint64_t size, void *data, uint64_t *n); 28 | int proc_write_mem(struct proc *p, void *ptr, uint64_t size, void *data, uint64_t *n); 29 | int proc_allocate(struct proc*p, void **address, uint64_t size); 30 | int proc_deallocate(struct proc *p, void *address, uint64_t size); 31 | int proc_mprotect(struct proc *p, void *address, uint64_t size, int new_prot); 32 | int proc_create_thread(struct proc *p, uint64_t address); 33 | int proc_map_elf(struct proc *p, void *elf, void *exec); 34 | int proc_relocate_elf(struct proc *p, void *elf, void *exec); 35 | int proc_load_elf(struct proc *p, void *elf, uint64_t *elfbase, uint64_t *entry); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /kdebugger/include/rpcasm.h: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #ifndef _RPCASM_H 6 | #define _RPCASM_H 7 | 8 | #include 9 | 10 | #define RPCSTUB_MAGIC 0x42545352 11 | 12 | struct rpcstub_header { 13 | uint32_t magic; 14 | uint64_t entry; 15 | uint64_t rpc_rip; 16 | uint64_t rpc_rdi; 17 | uint64_t rpc_rsi; 18 | uint64_t rpc_rdx; 19 | uint64_t rpc_rcx; 20 | uint64_t rpc_r8; 21 | uint64_t rpc_r9; 22 | uint64_t rpc_rax; 23 | uint8_t rpc_go; 24 | uint8_t rpc_done; 25 | } __attribute__((packed)); 26 | 27 | #define RPCLDR_MAGIC 0x52444C52 28 | 29 | struct rpcldr_header { 30 | uint32_t magic; 31 | uint64_t entry; 32 | uint8_t ldrdone; 33 | uint64_t stubentry; 34 | uint64_t scePthreadAttrInit; 35 | uint64_t scePthreadAttrSetstacksize; 36 | uint64_t scePthreadCreate; 37 | uint64_t thr_initial; 38 | } __attribute__((packed)); 39 | 40 | static const uint8_t rpcstub[410] = { 41 | 0x52, 0x53, 0x54, 0x42, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 42 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x69, 0x62, 0x6B, 0x65, 0x72, 48 | 0x6E, 0x65, 0x6C, 0x2E, 0x73, 0x70, 0x72, 0x78, 0x00, 0x6C, 0x69, 0x62, 49 | 0x6B, 0x65, 0x72, 0x6E, 0x65, 0x6C, 0x5F, 0x77, 0x65, 0x62, 0x2E, 0x73, 50 | 0x70, 0x72, 0x78, 0x00, 0x6C, 0x69, 0x62, 0x6B, 0x65, 0x72, 0x6E, 0x65, 51 | 0x6C, 0x5F, 0x73, 0x79, 0x73, 0x2E, 0x73, 0x70, 0x72, 0x78, 0x00, 0x00, 52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x63, 0x65, 0x4B, 0x65, 53 | 0x72, 0x6E, 0x65, 0x6C, 0x55, 0x73, 0x6C, 0x65, 0x65, 0x70, 0x00, 0x00, 54 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB9, 0x00, 0x00, 0x00, 0x00, 55 | 0x48, 0x8D, 0x15, 0xD4, 0xFF, 0xFF, 0xFF, 0xBE, 0x00, 0x00, 0x00, 0x00, 56 | 0x48, 0x8D, 0x3D, 0x93, 0xFF, 0xFF, 0xFF, 0xE8, 0xC4, 0x00, 0x00, 0x00, 57 | 0x48, 0x85, 0xC0, 0x74, 0x3F, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 58 | 0x15, 0xB2, 0xFF, 0xFF, 0xFF, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 59 | 0x3D, 0x80, 0xFF, 0xFF, 0xFF, 0xE8, 0xA2, 0x00, 0x00, 0x00, 0x48, 0x85, 60 | 0xC0, 0x74, 0x1D, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x15, 0x90, 61 | 0xFF, 0xFF, 0xFF, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x3D, 0x71, 62 | 0xFF, 0xFF, 0xFF, 0xE8, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x15, 0x90, 63 | 0xFF, 0xFF, 0xFF, 0x48, 0x8D, 0x35, 0x79, 0xFF, 0xFF, 0xFF, 0x48, 0x8B, 64 | 0x3D, 0x6A, 0xFF, 0xFF, 0xFF, 0xE8, 0x71, 0x00, 0x00, 0x00, 0x80, 0x3D, 65 | 0x27, 0xFF, 0xFF, 0xFF, 0x00, 0x74, 0x49, 0x4C, 0x8B, 0x0D, 0x0E, 0xFF, 66 | 0xFF, 0xFF, 0x4C, 0x8B, 0x05, 0xFF, 0xFE, 0xFF, 0xFF, 0x48, 0x8B, 0x0D, 67 | 0xF0, 0xFE, 0xFF, 0xFF, 0x48, 0x8B, 0x15, 0xE1, 0xFE, 0xFF, 0xFF, 0x48, 68 | 0x8B, 0x35, 0xD2, 0xFE, 0xFF, 0xFF, 0x48, 0x8B, 0x3D, 0xC3, 0xFE, 0xFF, 69 | 0xFF, 0x4C, 0x8B, 0x25, 0xB4, 0xFE, 0xFF, 0xFF, 0x41, 0xFF, 0xD4, 0x48, 70 | 0x89, 0x05, 0xE2, 0xFE, 0xFF, 0xFF, 0xC6, 0x05, 0xE3, 0xFE, 0xFF, 0xFF, 71 | 0x00, 0xC6, 0x05, 0xDD, 0xFE, 0xFF, 0xFF, 0x01, 0xBF, 0xA0, 0x86, 0x01, 72 | 0x00, 0x4C, 0x8B, 0x25, 0x1F, 0xFF, 0xFF, 0xFF, 0x41, 0xFF, 0xD4, 0xEB, 73 | 0x9D, 0x31, 0xC0, 0xC3, 0xB8, 0x52, 0x02, 0x00, 0x00, 0x49, 0x89, 0xCA, 74 | 0x0F, 0x05, 0xC3, 0xB8, 0x4F, 0x02, 0x00, 0x00, 0x49, 0x89, 0xCA, 0x0F, 75 | 0x05, 0xC3 76 | }; 77 | 78 | static const uint8_t rpcldr[255] = { 79 | 0x52, 0x4C, 0x44, 0x52, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 80 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 81 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 82 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 83 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 84 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x70, 0x63, 85 | 0x73, 0x74, 0x75, 0x62, 0x00, 0x48, 0x8B, 0x3D, 0xD9, 0xFF, 0xFF, 0xFF, 86 | 0x48, 0x8B, 0x37, 0x48, 0x8B, 0xBE, 0xE0, 0x01, 0x00, 0x00, 0xE8, 0x7A, 87 | 0x00, 0x00, 0x00, 0x48, 0x8D, 0x3D, 0xD3, 0xFF, 0xFF, 0xFF, 0x4C, 0x8B, 88 | 0x25, 0xA4, 0xFF, 0xFF, 0xFF, 0x41, 0xFF, 0xD4, 0xBE, 0x00, 0x00, 0x08, 89 | 0x00, 0x48, 0x8D, 0x3D, 0xBD, 0xFF, 0xFF, 0xFF, 0x4C, 0x8B, 0x25, 0x96, 90 | 0xFF, 0xFF, 0xFF, 0x41, 0xFF, 0xD4, 0x4C, 0x8D, 0x05, 0xB4, 0xFF, 0xFF, 91 | 0xFF, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x15, 0x70, 0xFF, 0xFF, 92 | 0xFF, 0x48, 0x8D, 0x35, 0x99, 0xFF, 0xFF, 0xFF, 0x48, 0x8D, 0x3D, 0x8A, 93 | 0xFF, 0xFF, 0xFF, 0x4C, 0x8B, 0x25, 0x73, 0xFF, 0xFF, 0xFF, 0x41, 0xFF, 94 | 0xD4, 0xC6, 0x05, 0x50, 0xFF, 0xFF, 0xFF, 0x01, 0xBF, 0x00, 0x00, 0x00, 95 | 0x00, 0xE8, 0x01, 0x00, 0x00, 0x00, 0xC3, 0xB8, 0xAF, 0x01, 0x00, 0x00, 96 | 0x49, 0x89, 0xCA, 0x0F, 0x05, 0xC3, 0xB8, 0xA5, 0x00, 0x00, 0x00, 0x49, 97 | 0x89, 0xCA, 0x0F, 0x05, 0xC3, 0x55, 0x48, 0x89, 0xE5, 0x53, 0x48, 0x83, 98 | 0xEC, 0x18, 0x48, 0x89, 0x7D, 0xE8, 0x48, 0x8D, 0x75, 0xE8, 0xBF, 0x81, 99 | 0x00, 0x00, 0x00, 0xE8, 0xDA, 0xFF, 0xFF, 0xFF, 0x48, 0x83, 0xC4, 0x18, 100 | 0x5B, 0x5D, 0xC3 101 | }; 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /kdebugger/kdebugger.x: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") 2 | OUTPUT_ARCH(i386:x86-64) 3 | 4 | ENTRY(_start) 5 | 6 | PHDRS 7 | { 8 | headers PT_LOAD PHDRS; 9 | text PT_LOAD; 10 | data PT_LOAD; 11 | bss PT_LOAD; 12 | } 13 | 14 | SECTIONS 15 | { 16 | . = SIZEOF_HEADERS; 17 | 18 | .text : { 19 | *(.text) 20 | } :text 21 | 22 | .rodata : { 23 | *(.rodata) 24 | *(.rodata.*) 25 | } :text 26 | 27 | .data : { 28 | *(.data) 29 | *(.got) 30 | *(.got.*) 31 | } :data 32 | 33 | .bss : { 34 | *(.bss) 35 | *(COMMON) 36 | } :bss 37 | } 38 | -------------------------------------------------------------------------------- /kdebugger/source/elf.c: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #include "elf.h" 6 | 7 | int elf_mapped_size(void *elf, uint64_t *msize) { 8 | struct Elf64_Ehdr *ehdr = (struct Elf64_Ehdr *)elf; 9 | 10 | // check magic 11 | if (memcmp(ehdr->e_ident, ElfMagic, 4)) { 12 | return 1; 13 | } 14 | 15 | uint64_t s = 0; 16 | 17 | struct Elf64_Phdr *phdr = elf_pheader(ehdr); 18 | if (phdr) { 19 | // use segments 20 | for (int i = 0; i < ehdr->e_phnum; i++) { 21 | struct Elf64_Phdr *phdr = elf_segment(ehdr, i); 22 | 23 | uint64_t delta = phdr->p_paddr + phdr->p_memsz; 24 | if (delta > s) { 25 | s = delta; 26 | } 27 | } 28 | } else { 29 | // use sections 30 | for (int i = 0; i < ehdr->e_shnum; i++) { 31 | struct Elf64_Shdr *shdr = elf_section(ehdr, i); 32 | 33 | uint64_t delta = shdr->sh_addr + shdr->sh_size; 34 | if (delta > s) { 35 | s = delta; 36 | } 37 | } 38 | } 39 | 40 | if (msize) { 41 | *msize = s; 42 | } 43 | 44 | return 0; 45 | } -------------------------------------------------------------------------------- /kdebugger/source/hooks.c: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #include "hooks.h" 6 | 7 | inline void write_jmp(uint64_t address, uint64_t destination) { 8 | // absolute jump 9 | *(uint8_t *)(address) = 0xFF; 10 | *(uint8_t *)(address + 1) = 0x25; 11 | *(uint8_t *)(address + 2) = 0x00; 12 | *(uint8_t *)(address + 3) = 0x00; 13 | *(uint8_t *)(address + 4) = 0x00; 14 | *(uint8_t *)(address + 5) = 0x00; 15 | *(uint64_t *)(address + 6) = destination; 16 | } 17 | 18 | int sys_proc_list(struct thread *td, struct sys_proc_list_args *uap) { 19 | struct proc *p; 20 | int num; 21 | int r; 22 | 23 | r = 0; 24 | 25 | if(!uap->num) { 26 | r = 1; 27 | goto finish; 28 | } 29 | 30 | if(!uap->procs) { 31 | // count 32 | num = 0; 33 | p = *allproc; 34 | do { 35 | num++; 36 | } while ((p = p->p_forw)); 37 | 38 | *uap->num = num; 39 | } else { 40 | // fill structure 41 | num = *uap->num; 42 | p = *allproc; 43 | for (int i = 0; i < num; i++) { 44 | memcpy(uap->procs[i].p_comm, p->p_comm, sizeof(uap->procs[i].p_comm)); 45 | uap->procs[i].pid = p->pid; 46 | 47 | if (!(p = p->p_forw)) { 48 | break; 49 | } 50 | } 51 | } 52 | 53 | finish: 54 | td->td_retval[0] = r; 55 | return r; 56 | } 57 | 58 | int sys_proc_rw(struct thread *td, struct sys_proc_rw_args *uap) { 59 | struct proc *p; 60 | int r; 61 | 62 | r = 1; 63 | 64 | p = proc_find_by_pid(uap->pid); 65 | if(p) { 66 | r = proc_rw_mem(p, (void *)uap->address, uap->length, uap->data, 0, uap->write); 67 | } 68 | 69 | td->td_retval[0] = r; 70 | return r; 71 | } 72 | 73 | int sys_proc_alloc_handle(struct proc *p, struct sys_proc_alloc_args *args) { 74 | uint64_t address; 75 | 76 | if(proc_allocate(p, (void **)&address, args->length)) { 77 | return 1; 78 | } 79 | 80 | args->address = address; 81 | 82 | return 0; 83 | } 84 | 85 | int sys_proc_free_handle(struct proc *p, struct sys_proc_free_args *args) { 86 | return proc_deallocate(p, (void *)args->address, args->length); 87 | } 88 | 89 | int sys_proc_protect_handle(struct proc *p, struct sys_proc_protect_args *args) { 90 | return proc_mprotect(p, (void *)args->address, args->length, args->prot); 91 | } 92 | 93 | int sys_proc_vm_map_handle(struct proc *p, struct sys_proc_vm_map_args *args) { 94 | struct vmspace *vm; 95 | struct vm_map *map; 96 | struct vm_map_entry *entry; 97 | 98 | vm = p->p_vmspace; 99 | map = &vm->vm_map; 100 | 101 | vm_map_lock_read(map); 102 | 103 | if(!args->maps) { 104 | args->num = map->nentries; 105 | } else { 106 | if(vm_map_lookup_entry(map, NULL, &entry)) { 107 | vm_map_unlock_read(map); 108 | return 1; 109 | } 110 | 111 | for (int i = 0; i < args->num; i++) { 112 | args->maps[i].start = entry->start; 113 | args->maps[i].end = entry->end; 114 | args->maps[i].offset = entry->offset; 115 | args->maps[i].prot = entry->prot & (entry->prot >> 8); 116 | memcpy(args->maps[i].name, entry->name, sizeof(args->maps[i].name)); 117 | 118 | if(!(entry = entry->next)) { 119 | break; 120 | } 121 | } 122 | } 123 | 124 | vm_map_unlock_read(map); 125 | 126 | return 0; 127 | } 128 | 129 | int sys_proc_install_handle(struct proc *p, struct sys_proc_install_args *args) { 130 | void *stubaddr; 131 | uint64_t stubsize = sizeof(rpcstub); 132 | stubsize += (PAGE_SIZE - (stubsize % PAGE_SIZE)); 133 | 134 | // allocate memory for the stub 135 | if(proc_allocate(p, &stubaddr, stubsize)) { 136 | return 1; 137 | } 138 | 139 | // write the actual stub 140 | if(proc_write_mem(p, stubaddr, sizeof(rpcstub), (void *)rpcstub, NULL)) { 141 | return 1; 142 | } 143 | 144 | // load stub 145 | uint64_t stubentryaddr = (uint64_t)stubaddr + *(uint64_t *)(rpcstub + 4); 146 | if(proc_create_thread(p, stubentryaddr)) { 147 | return 1; 148 | } 149 | 150 | args->stubentryaddr = (uint64_t)stubaddr; 151 | 152 | return 0; 153 | } 154 | 155 | int sys_proc_call_handle(struct proc *p, struct sys_proc_call_args *args) { 156 | 157 | uint64_t rpcstub = args->rpcstub; 158 | // write registers 159 | // these two structures are basically 1:1 (it is hackey but meh) 160 | uint64_t regsize = offsetof(struct rpcstub_header, rpc_rax) - offsetof(struct rpcstub_header, rpc_rip); 161 | if (proc_write_mem(p, (void *)(rpcstub + offsetof(struct rpcstub_header, rpc_rip)), regsize, &args->rip, NULL)) { 162 | return 1; 163 | } 164 | 165 | // trigger call 166 | uint8_t go = 1; 167 | if (proc_write_mem(p, (void *)(rpcstub + offsetof(struct rpcstub_header, rpc_go)), sizeof(go), &go, NULL)) { 168 | return 1; 169 | } 170 | 171 | // check until done 172 | uint8_t done = 0; 173 | while (!done) { 174 | if (proc_read_mem(p, (void *)(rpcstub + offsetof(struct rpcstub_header, rpc_done)), sizeof(done), &done, NULL)) { 175 | return 1; 176 | } 177 | } 178 | 179 | // write done to be zero 180 | done = 0; 181 | if (proc_write_mem(p, (void *)(rpcstub + offsetof(struct rpcstub_header, rpc_done)), sizeof(done), &done, NULL)) { 182 | return 1; 183 | } 184 | 185 | // return value 186 | uint64_t rax = 0; 187 | if (proc_read_mem(p, (void *)(rpcstub + offsetof(struct rpcstub_header, rpc_rax)), sizeof(rax), &rax, NULL)) { 188 | return 1; 189 | } 190 | 191 | args->rax = rax; 192 | 193 | return 0; 194 | } 195 | 196 | int sys_proc_elf_handle(struct proc *p, struct sys_proc_elf_args *args) { 197 | struct proc_vm_map_entry *entries; 198 | uint64_t num_entries; 199 | uint64_t entry; 200 | 201 | // load the elf into the process 202 | if(proc_load_elf(p, args->elf, NULL, &entry)) { 203 | return 1; 204 | } 205 | 206 | // change main executable protection in process to rwx 207 | if(proc_get_vm_map(p, &entries, &num_entries)) { 208 | return 1; 209 | } 210 | 211 | for (int i = 0; i < num_entries; i++) { 212 | if (entries[i].prot != (PROT_READ | PROT_EXEC)) { 213 | continue; 214 | } 215 | 216 | if (!memcmp(entries[i].name, "executable", 10)) { 217 | proc_mprotect(p, (void *)entries[i].start, (uint64_t)(entries[i].end - entries[i].start), VM_PROT_ALL); 218 | break; 219 | } 220 | } 221 | 222 | // launch the elf in a new thread 223 | if(proc_create_thread(p, entry)) { 224 | return 1; 225 | } 226 | 227 | return 0; 228 | } 229 | 230 | int sys_proc_info_handle(struct proc *p, struct sys_proc_info_args *args) { 231 | args->pid = p->pid; 232 | memcpy(args->name, p->p_comm, sizeof(args->name)); 233 | memcpy(args->path, p->path, sizeof(args->path)); 234 | memcpy(args->titleid, p->titleid, sizeof(args->titleid)); 235 | memcpy(args->contentid, p->contentid, sizeof(args->contentid)); 236 | return 0; 237 | } 238 | 239 | int sys_proc_thrinfo_handle(struct proc *p, struct sys_proc_thrinfo_args *args) { 240 | struct thread *thr; 241 | 242 | TAILQ_FOREACH(thr, &p->p_threads, td_plist) { 243 | if(thr->tid == args->lwpid) { 244 | args->priority = thr->td_priority; 245 | memcpy(args->name, thr->td_name, sizeof(args->name)); 246 | break; 247 | } 248 | } 249 | 250 | if(thr && thr->tid == args->lwpid) { 251 | return 0; 252 | } 253 | 254 | return 1; 255 | } 256 | 257 | int sys_proc_cmd(struct thread *td, struct sys_proc_cmd_args *uap) { 258 | struct proc *p; 259 | int r; 260 | 261 | p = proc_find_by_pid(uap->pid); 262 | if(!p) { 263 | r = 1; 264 | goto finish; 265 | } 266 | 267 | switch(uap->cmd) { 268 | case SYS_PROC_ALLOC: 269 | r = sys_proc_alloc_handle(p, (struct sys_proc_alloc_args *)uap->data); 270 | break; 271 | case SYS_PROC_FREE: 272 | r = sys_proc_free_handle(p, (struct sys_proc_free_args *)uap->data); 273 | break; 274 | case SYS_PROC_PROTECT: 275 | r = sys_proc_protect_handle(p, (struct sys_proc_protect_args *)uap->data); 276 | break; 277 | case SYS_PROC_VM_MAP: 278 | r = sys_proc_vm_map_handle(p, (struct sys_proc_vm_map_args *)uap->data); 279 | break; 280 | case SYS_PROC_INSTALL: 281 | r = sys_proc_install_handle(p, (struct sys_proc_install_args *)uap->data); 282 | break; 283 | case SYS_PROC_CALL: 284 | r = sys_proc_call_handle(p, (struct sys_proc_call_args *)uap->data); 285 | break; 286 | case SYS_PROC_ELF: 287 | r = sys_proc_elf_handle(p, (struct sys_proc_elf_args *)uap->data); 288 | break; 289 | case SYS_PROC_INFO: 290 | r = sys_proc_info_handle(p, (struct sys_proc_info_args *)uap->data); 291 | break; 292 | case SYS_PROC_THRINFO: 293 | r = sys_proc_thrinfo_handle(p, (struct sys_proc_thrinfo_args *)uap->data); 294 | break; 295 | default: 296 | r = 1; 297 | break; 298 | } 299 | 300 | finish: 301 | td->td_retval[0] = r; 302 | return r; 303 | } 304 | 305 | int sys_kern_base(struct thread *td, struct sys_kern_base_args *uap) { 306 | *uap->kbase = get_kbase(); 307 | td->td_retval[0] = 0; 308 | return 0; 309 | } 310 | 311 | int sys_kern_rw(struct thread *td, struct sys_kern_rw_args *uap) { 312 | if(uap->write) { 313 | cpu_disable_wp(); 314 | memcpy((void *)uap->address, uap->data, uap->length); 315 | cpu_enable_wp(); 316 | } else { 317 | memcpy(uap->data, (void *)uap->address, uap->length); 318 | } 319 | 320 | td->td_retval[0] = 0; 321 | return 0; 322 | } 323 | 324 | int sys_console_cmd(struct thread *td, struct sys_console_cmd_args *uap) { 325 | switch(uap->cmd) { 326 | case SYS_CONSOLE_CMD_REBOOT: 327 | kern_reboot(0); 328 | break; 329 | case SYS_CONSOLE_CMD_PRINT: 330 | if(uap->data) { 331 | printf("[ps4debug] %s\n", uap->data); 332 | } 333 | break; 334 | case SYS_CONSOLE_CMD_JAILBREAK: { 335 | struct ucred* cred; 336 | struct filedesc* fd; 337 | struct thread *td; 338 | 339 | td = curthread(); 340 | fd = td->td_proc->p_fd; 341 | cred = td->td_proc->p_ucred; 342 | 343 | cred->cr_uid = 0; 344 | cred->cr_ruid = 0; 345 | cred->cr_rgid = 0; 346 | cred->cr_groups[0] = 0; 347 | cred->cr_prison = *prison0; 348 | fd->fd_rdir = fd->fd_jdir = *rootvnode; 349 | break; 350 | } 351 | } 352 | 353 | td->td_retval[0] = 0; 354 | return 0; 355 | } 356 | 357 | void hook_trap_fatal(struct trapframe *tf) { 358 | // print registers 359 | const char regnames[15][8] = { "rdi", "rsi", "rdx", "rcx", "r8", "r9", "rax", "rbx", "rbp", "r10", "r11", "r12", "r13", "r14", "r15" }; 360 | for(int i = 0; i < 15; i++) { 361 | uint64_t rv = *(uint64_t *)((uint64_t)tf + (sizeof(uint64_t) * i)); 362 | printf(" %s %llX %i\n", regnames[i], rv, rv); 363 | } 364 | printf(" rip %llX %i\n", tf->tf_rip, tf->tf_rip); 365 | printf(" rsp %llX %i\n", tf->tf_rsp, tf->tf_rsp); 366 | 367 | uint64_t sp = 0; 368 | if ((tf->tf_rsp & 3) == 3) { 369 | sp = *(uint64_t *)(tf + 1); 370 | } else { 371 | sp = (uint64_t)(tf + 1); 372 | } 373 | 374 | // stack backtrace 375 | uint64_t kernbase = get_kbase(); 376 | printf("kernelbase: 0x%llX\n", kernbase); 377 | uint64_t backlog = 128; 378 | printf("stack backtrace (0x%llX):\n", sp); 379 | for (int i = 0; i < backlog; i++) { 380 | uint64_t sv = *(uint64_t *)((sp - (backlog * sizeof(uint64_t))) + (i * sizeof(uint64_t))); 381 | if (sv > kernbase) { 382 | printf(" %i +0x%llX\n", i, sv - kernbase); 383 | } 384 | } 385 | 386 | kern_reboot(4); 387 | } 388 | 389 | void install_syscall(uint32_t n, void *func) { 390 | struct sysent *p = &sysents[n]; 391 | memset(p, NULL, sizeof(struct sysent)); 392 | p->sy_narg = 8; 393 | p->sy_call = func; 394 | p->sy_thrcnt = 1; 395 | } 396 | 397 | int install_hooks() { 398 | cpu_disable_wp(); 399 | 400 | // trap_fatal hook 401 | uint64_t kernbase = get_kbase(); 402 | memcpy((void *)(kernbase + 0x1718D8), "\x4C\x89\xE7", 3); // mov rdi, r12 403 | write_jmp(kernbase + 0x1718DB, (uint64_t)hook_trap_fatal); 404 | 405 | // proc 406 | install_syscall(107, sys_proc_list); 407 | install_syscall(108, sys_proc_rw); 408 | install_syscall(109, sys_proc_cmd); 409 | 410 | // kern 411 | install_syscall(110, sys_kern_base); 412 | install_syscall(111, sys_kern_rw); 413 | 414 | // console 415 | install_syscall(112, sys_console_cmd); 416 | 417 | cpu_enable_wp(); 418 | 419 | return 0; 420 | } 421 | -------------------------------------------------------------------------------- /kdebugger/source/main.c: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #include 6 | #include "hooks.h" 7 | 8 | int _main(void) { 9 | init_ksdk(); 10 | 11 | printf("[ps4debug] kernel base 0x%llX\n", get_kbase()); 12 | 13 | if(install_hooks()) { 14 | printf("[ps4debug] failed to install hooks\n"); 15 | return 1; 16 | } 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /kdebugger/source/proc.c: -------------------------------------------------------------------------------- 1 | // golden 2 | // 6/12/2018 3 | // 4 | 5 | #include "proc.h" 6 | 7 | struct proc *proc_find_by_name(const char *name) { 8 | struct proc *p; 9 | 10 | if (!name) { 11 | return NULL; 12 | } 13 | 14 | p = *allproc; 15 | do { 16 | if (!memcmp(p->p_comm, name, strlen(name))) { 17 | return p; 18 | } 19 | } while ((p = p->p_forw)); 20 | 21 | return NULL; 22 | } 23 | 24 | struct proc *proc_find_by_pid(int pid) { 25 | struct proc *p; 26 | 27 | p = *allproc; 28 | do { 29 | if (p->pid == pid) { 30 | return p; 31 | } 32 | } while ((p = p->p_forw)); 33 | 34 | return NULL; 35 | } 36 | 37 | int proc_get_vm_map(struct proc *p, struct proc_vm_map_entry **entries, uint64_t *num_entries) { 38 | struct proc_vm_map_entry *info = NULL; 39 | struct vm_map_entry *entry = NULL; 40 | int r = 0; 41 | 42 | struct vmspace *vm = p->p_vmspace; 43 | struct vm_map *map = &vm->vm_map; 44 | 45 | vm_map_lock_read(map); 46 | 47 | int num = map->nentries; 48 | if (!num) { 49 | goto error; 50 | } 51 | 52 | r = vm_map_lookup_entry(map, NULL, &entry); 53 | if(r) { 54 | goto error; 55 | } 56 | 57 | info = (struct proc_vm_map_entry *)malloc(num * sizeof(struct proc_vm_map_entry), M_TEMP, 2); 58 | if (!info) { 59 | r = 1; 60 | goto error; 61 | } 62 | 63 | for (int i = 0; i < num; i++) { 64 | info[i].start = entry->start; 65 | info[i].end = entry->end; 66 | info[i].offset = entry->offset; 67 | info[i].prot = entry->prot & (entry->prot >> 8); 68 | memcpy(info[i].name, entry->name, sizeof(info[i].name)); 69 | 70 | if (!(entry = entry->next)) { 71 | break; 72 | } 73 | } 74 | 75 | error: 76 | vm_map_unlock_read(map); 77 | 78 | if (entries) { 79 | *entries = info; 80 | } 81 | 82 | if (num_entries) { 83 | *num_entries = num; 84 | } 85 | 86 | return 0; 87 | } 88 | 89 | int proc_rw_mem(struct proc *p, void *ptr, uint64_t size, void *data, uint64_t *n, int write) { 90 | struct thread *td = curthread(); 91 | struct iovec iov; 92 | struct uio uio; 93 | int r = 0; 94 | 95 | if (!p) { 96 | return 1; 97 | } 98 | 99 | if (size == 0) { 100 | if (n) { 101 | *n = 0; 102 | } 103 | 104 | return 0; 105 | } 106 | 107 | memset(&iov, NULL, sizeof(iov)); 108 | iov.iov_base = (uint64_t)data; 109 | iov.iov_len = size; 110 | 111 | memset(&uio, NULL, sizeof(uio)); 112 | uio.uio_iov = (uint64_t)&iov; 113 | uio.uio_iovcnt = 1; 114 | uio.uio_offset = (uint64_t)ptr; 115 | uio.uio_resid = (uint64_t)size; 116 | uio.uio_segflg = UIO_SYSSPACE; 117 | uio.uio_rw = write ? UIO_WRITE : UIO_READ; 118 | uio.uio_td = td; 119 | 120 | r = proc_rwmem(p, &uio); 121 | 122 | if (n) { 123 | *n = (uint64_t)((uint64_t)size - uio.uio_resid); 124 | } 125 | 126 | return r; 127 | } 128 | 129 | inline int proc_read_mem(struct proc *p, void *ptr, uint64_t size, void *data, uint64_t *n) { 130 | return proc_rw_mem(p, ptr, size, data, n, 0); 131 | } 132 | 133 | inline int proc_write_mem(struct proc *p, void *ptr, uint64_t size, void *data, uint64_t *n) { 134 | return proc_rw_mem(p, ptr, size, data, n, 1); 135 | } 136 | 137 | int proc_allocate(struct proc *p, void **address, uint64_t size) { 138 | uint64_t addr = NULL; 139 | int r = 0; 140 | uint64_t alignedSize = (size + 0x3FFFull) & ~0x3FFFull; 141 | 142 | if (!address) { 143 | r = 1; 144 | goto error; 145 | } 146 | 147 | struct vmspace *vm = p->p_vmspace; 148 | struct vm_map *map = &vm->vm_map; 149 | 150 | vm_map_lock(map); 151 | 152 | r = vm_map_findspace(map, NULL, size, &addr); 153 | if (r) { 154 | vm_map_unlock(map); 155 | goto error; 156 | } 157 | 158 | r = vm_map_insert(map, NULL, NULL, addr, addr + alignedSize, VM_PROT_ALL, VM_PROT_ALL, 0); 159 | 160 | vm_map_unlock(map); 161 | 162 | if (r) { 163 | goto error; 164 | } 165 | 166 | if (address) { 167 | *address = (void *)addr; 168 | } 169 | 170 | error: 171 | return r; 172 | } 173 | 174 | int proc_deallocate(struct proc *p, void *address, uint64_t size) { 175 | int r = 0; 176 | uint64_t alignedSize = (size + 0x3FFFull) & ~0x3FFFull; 177 | 178 | struct vmspace *vm = p->p_vmspace; 179 | struct vm_map *map = &vm->vm_map; 180 | 181 | vm_map_lock(map); 182 | 183 | r = vm_map_delete(map, (uint64_t)address, (uint64_t)address + alignedSize); 184 | 185 | vm_map_unlock(map); 186 | 187 | return r; 188 | } 189 | 190 | int proc_mprotect(struct proc *p, void *address, uint64_t size, int new_prot) { 191 | int r = 0; 192 | 193 | uint64_t alignedSize = (size + 0x3FFFull) & ~0x3FFFull; 194 | uint64_t addr = (uint64_t)address; 195 | uint64_t addrend = addr + alignedSize; 196 | 197 | struct vmspace *vm = p->p_vmspace; 198 | struct vm_map *map = &vm->vm_map; 199 | 200 | // update the max prot then set new prot 201 | r = vm_map_protect(map, addr, addrend, new_prot, 1); 202 | if (r) { 203 | return r; 204 | } 205 | 206 | r = vm_map_protect(map, addr, addrend, new_prot, 0); 207 | 208 | return r; 209 | } 210 | 211 | int proc_create_thread(struct proc *p, uint64_t address) { 212 | void *rpcldraddr = NULL; 213 | void *stackaddr = NULL; 214 | struct proc_vm_map_entry *entries = NULL; 215 | uint64_t num_entries = 0; 216 | uint64_t n = 0; 217 | int r = 0; 218 | 219 | uint64_t ldrsize = sizeof(rpcldr); 220 | ldrsize += (PAGE_SIZE - (ldrsize % PAGE_SIZE)); 221 | 222 | uint64_t stacksize = 0x80000; 223 | 224 | // allocate rpc ldr 225 | r = proc_allocate(p, &rpcldraddr, ldrsize); 226 | if (r) { 227 | goto error; 228 | } 229 | 230 | // allocate stack 231 | r = proc_allocate(p, &stackaddr, stacksize); 232 | if (r) { 233 | goto error; 234 | } 235 | 236 | // write loader 237 | r = proc_write_mem(p, rpcldraddr, sizeof(rpcldr), (void *)rpcldr, &n); 238 | if (r) { 239 | goto error; 240 | } 241 | 242 | // donor thread 243 | struct thread *thr = TAILQ_FIRST(&p->p_threads); 244 | 245 | // find libkernel base 246 | r = proc_get_vm_map(p, &entries, &num_entries); 247 | if (r) { 248 | goto error; 249 | } 250 | 251 | // offsets are for 7.55 libraries 252 | 253 | // libkernel.sprx 254 | // 0x13630 scePthreadAttrInit 255 | // 0x13650 scePthreadAttrSetstacksize 256 | // 0x13A70 scePthreadCreate 257 | // 0x8D420 thr_initial 258 | 259 | // libkernel_web.sprx 260 | // 0x1FA70 scePthreadAttrInit 261 | // 0x10380 scePthreadAttrSetstacksize 262 | // 0x09F10 scePthreadCreate 263 | // 0x8D420 thr_initial 264 | 265 | // libkernel_sys.sprx 266 | // 0x14160 scePthreadAttrInit 267 | // 0x14180 scePthreadAttrSetstacksize 268 | // 0x145A0 scePthreadCreate 269 | // 0x8D830 thr_initial 270 | 271 | uint64_t _scePthreadAttrInit = 0, _scePthreadAttrSetstacksize = 0, _scePthreadCreate = 0, _thr_initial = 0; 272 | for (int i = 0; i < num_entries; i++) { 273 | if (entries[i].prot != (PROT_READ | PROT_EXEC)) { 274 | continue; 275 | } 276 | 277 | if (!memcmp(entries[i].name, "libkernel.sprx", 14)) { 278 | _scePthreadAttrInit = entries[i].start + 0x13630; 279 | _scePthreadAttrSetstacksize = entries[i].start + 0x13650; 280 | _scePthreadCreate = entries[i].start + 0x13A70; 281 | _thr_initial = entries[i].start + 0x8D420; 282 | break; 283 | } 284 | if (!memcmp(entries[i].name, "libkernel_web.sprx", 18)) 285 | { 286 | _scePthreadAttrInit = entries[i].start + 0x1FA70; 287 | _scePthreadAttrSetstacksize = entries[i].start + 0x10380; 288 | _scePthreadCreate = entries[i].start + 0x09F10; 289 | _thr_initial = entries[i].start + 0x8D420; 290 | break; 291 | } 292 | if (!memcmp(entries[i].name, "libkernel_sys.sprx", 18)) { 293 | _scePthreadAttrInit = entries[i].start + 0x14160; 294 | _scePthreadAttrSetstacksize = entries[i].start + 0x14180; 295 | _scePthreadCreate = entries[i].start + 0x145A0; 296 | _thr_initial = entries[i].start + 0x8D830; 297 | break; 298 | } 299 | } 300 | 301 | if (!_scePthreadAttrInit) { 302 | goto error; 303 | } 304 | 305 | // write variables 306 | r = proc_write_mem(p, rpcldraddr + offsetof(struct rpcldr_header, stubentry), sizeof(address), (void *)&address, &n); 307 | if (r) { 308 | goto error; 309 | } 310 | 311 | r = proc_write_mem(p, rpcldraddr + offsetof(struct rpcldr_header, scePthreadAttrInit), sizeof(_scePthreadAttrInit), (void *)&_scePthreadAttrInit, &n); 312 | if (r) { 313 | goto error; 314 | } 315 | 316 | r = proc_write_mem(p, rpcldraddr + offsetof(struct rpcldr_header, scePthreadAttrSetstacksize), sizeof(_scePthreadAttrSetstacksize), (void *)&_scePthreadAttrSetstacksize, &n); 317 | if (r) { 318 | goto error; 319 | } 320 | 321 | r = proc_write_mem(p, rpcldraddr + offsetof(struct rpcldr_header, scePthreadCreate), sizeof(_scePthreadCreate), (void *)&_scePthreadCreate, &n); 322 | if (r) { 323 | goto error; 324 | } 325 | 326 | r = proc_write_mem(p, rpcldraddr + offsetof(struct rpcldr_header, thr_initial), sizeof(_thr_initial), (void *)&_thr_initial, &n); 327 | if (r) { 328 | goto error; 329 | } 330 | 331 | // execute loader 332 | // note: do not enter in the pid information as it expects it to be stored in userland 333 | uint64_t ldrentryaddr = (uint64_t)rpcldraddr + *(uint64_t *)(rpcldr + 4); 334 | r = create_thread(thr, NULL, (void *)ldrentryaddr, NULL, stackaddr, stacksize, NULL, NULL, NULL, 0, NULL); 335 | if (r) { 336 | goto error; 337 | } 338 | 339 | // wait until loader is done 340 | uint8_t ldrdone = 0; 341 | while (!ldrdone) { 342 | r = proc_read_mem(p, (void *)(rpcldraddr + offsetof(struct rpcldr_header, ldrdone)), sizeof(ldrdone), &ldrdone, &n); 343 | if (r) { 344 | goto error; 345 | } 346 | } 347 | 348 | error: 349 | if (entries) { 350 | free(entries, M_TEMP); 351 | } 352 | 353 | if (rpcldraddr) { 354 | proc_deallocate(p, rpcldraddr, ldrsize); 355 | } 356 | 357 | if (stackaddr) { 358 | proc_deallocate(p, stackaddr, stacksize); 359 | } 360 | 361 | return r; 362 | } 363 | 364 | int proc_map_elf(struct proc *p, void *elf, void *exec) { 365 | struct Elf64_Ehdr *ehdr = (struct Elf64_Ehdr *)elf; 366 | 367 | struct Elf64_Phdr *phdr = elf_pheader(ehdr); 368 | if (phdr) { 369 | // use segments 370 | for (int i = 0; i < ehdr->e_phnum; i++) { 371 | struct Elf64_Phdr *phdr = elf_segment(ehdr, i); 372 | 373 | if (phdr->p_filesz) { 374 | proc_write_mem(p, (void *)((uint8_t *)exec + phdr->p_paddr), phdr->p_filesz, (void *)((uint8_t *)elf + phdr->p_offset), NULL); 375 | } 376 | } 377 | } else { 378 | // use sections 379 | for (int i = 0; i < ehdr->e_shnum; i++) { 380 | struct Elf64_Shdr *shdr = elf_section(ehdr, i); 381 | 382 | if (!(shdr->sh_flags & SHF_ALLOC)) { 383 | continue; 384 | } 385 | 386 | if (shdr->sh_size) { 387 | proc_write_mem(p, (void *)((uint8_t *)exec + shdr->sh_addr), shdr->sh_size, (void *)((uint8_t *)elf + shdr->sh_offset), NULL); 388 | } 389 | } 390 | } 391 | 392 | return 0; 393 | } 394 | 395 | int proc_relocate_elf(struct proc *p, void *elf, void *exec) { 396 | struct Elf64_Ehdr *ehdr = (struct Elf64_Ehdr *)elf; 397 | 398 | for (int i = 0; i < ehdr->e_shnum; i++) { 399 | struct Elf64_Shdr *shdr = elf_section(ehdr, i); 400 | 401 | // check table 402 | if (shdr->sh_type == SHT_REL) { 403 | // process each entry in the table 404 | for (int j = 0; j < shdr->sh_size / shdr->sh_entsize; j++) { 405 | struct Elf64_Rela *reltab = &((struct Elf64_Rela *)((uint64_t)ehdr + shdr->sh_offset))[j]; 406 | uint8_t **ref = (uint8_t **)((uint8_t *)exec + reltab->r_offset); 407 | uint8_t *value = NULL; 408 | 409 | switch (ELF64_R_TYPE(reltab->r_info)) { 410 | case R_X86_64_RELATIVE: 411 | // *ref = (uint8_t *)exec + reltab->r_addend; 412 | value = (uint8_t *)exec + reltab->r_addend; 413 | proc_write_mem(p, ref, sizeof(value), (void *)&value, NULL); 414 | break; 415 | case R_X86_64_64: 416 | case R_X86_64_JUMP_SLOT: 417 | case R_X86_64_GLOB_DAT: 418 | // not supported 419 | break; 420 | } 421 | } 422 | } 423 | } 424 | 425 | return 0; 426 | } 427 | 428 | int proc_load_elf(struct proc *p, void *elf, uint64_t *elfbase, uint64_t *entry) { 429 | void *elfaddr = NULL; 430 | uint64_t msize = 0; 431 | int r = 0; 432 | 433 | struct Elf64_Ehdr *ehdr = (struct Elf64_Ehdr *)elf; 434 | 435 | r = elf_mapped_size(elf, &msize); 436 | if (r) { 437 | goto error; 438 | } 439 | 440 | // resize to pages 441 | msize += (PAGE_SIZE - (msize % PAGE_SIZE)); 442 | 443 | // allocate 444 | r = proc_allocate(p, &elfaddr, msize); 445 | if (r) { 446 | goto error; 447 | } 448 | 449 | // map 450 | r = proc_map_elf(p, elf, elfaddr); 451 | if (r) { 452 | goto error; 453 | } 454 | 455 | // relocate 456 | r = proc_relocate_elf(p, elf, elfaddr); 457 | if (r) { 458 | goto error; 459 | } 460 | 461 | if (elfbase) { 462 | *elfbase = (uint64_t)elfaddr; 463 | } 464 | 465 | if (entry) { 466 | *entry = (uint64_t)elfaddr + ehdr->e_entry; 467 | } 468 | 469 | error: 470 | return r; 471 | } 472 | -------------------------------------------------------------------------------- /libdebug/README.md: -------------------------------------------------------------------------------- 1 | # libdbg 2 | 3 | The 'powerful' remote debugging library for the PlayStation 4! Haha... this may or may not be out of date. Documentation and changes are coming! Hopefully someday this folder will also contain a C/C++ version. -------------------------------------------------------------------------------- /libdebug/cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(libdebug) 3 | 4 | set(CMAKE_STATIC_LIBRARY_PREFIX "") 5 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/) 6 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/) 7 | add_library(libdebug STATIC 8 | source/PS4DBG.cpp 9 | source/Process.cpp 10 | ) 11 | target_compile_features(libdebug PRIVATE cxx_std_17) 12 | target_include_directories(libdebug 13 | PUBLIC 14 | ${PROJECT_SOURCE_DIR}/include 15 | ) 16 | 17 | 18 | 19 | add_executable(example 20 | example/example.cpp 21 | ) 22 | target_compile_features(example PRIVATE cxx_std_17) 23 | set(THREADS_PREFER_PTHREAD_FLAG ON) 24 | find_package(Threads REQUIRED) 25 | target_link_libraries( example 26 | PRIVATE 27 | libdebug 28 | Threads::Threads 29 | ) -------------------------------------------------------------------------------- /libdebug/cpp/example/example.cpp: -------------------------------------------------------------------------------- 1 | #include "PS4DBG.hpp" 2 | #include 3 | 4 | void Breadsticks(uint32_t lwpid, uint32_t status, const std::string& tdname, libdebug::regs regs, libdebug::fpregs fpregs, libdebug::dbregs dbregs) 5 | { 6 | std::cout << "lwpid: " << lwpid << std::endl; 7 | std::cout << "status: " << status << std::endl; 8 | std::cout << "tdname: " << tdname << std::endl; 9 | std::cout << "rip: 0x" << std::hex << regs.r_rip << std::endl; 10 | std::cout << "rax: 0x" << std::hex << regs.r_rax << std::endl; 11 | } 12 | int main() 13 | { 14 | 15 | libdebug::PS4DBG ps4("192.168.1.147"); 16 | ps4.Connect(); 17 | auto procList = ps4.GetProcessList(); 18 | auto proc = procList.FindProcess("eboot.bin"); 19 | if(!proc) 20 | { 21 | return 0; 22 | } 23 | auto entries = ps4.GetProcessMaps(proc->pid); 24 | uint64_t executable; 25 | for(auto entry : entries.entries) 26 | { 27 | if (entry->prot == 5) 28 | { 29 | std::cout << "executable base : 0x" << std::hex << entry->start << std::endl; 30 | executable = entry->start; 31 | break; 32 | } 33 | } 34 | if(!executable) 35 | { 36 | return 0; 37 | } 38 | auto info = ps4.GetProcessInfo(proc->pid); 39 | std::cout << info.name << " " << info.titleid << std::endl; 40 | 41 | ps4.Notify(210, "Hello"); 42 | 43 | ps4.AttachDebugger(proc->pid, Breadsticks); 44 | ps4.ProcessKill(); 45 | auto info2 = ps4.GetThreadList(); 46 | std::cout << "**Threads**\r\n"; 47 | for(auto thr : info2) 48 | { 49 | auto info3 = ps4.GetThreadInfo(thr); 50 | std::cout << "name: " << info3.name << " pid: " << info3.pid << " priority: " << info3.priority << "\r\n"; 51 | } 52 | auto regs = ps4.GetRegisters(info2[info2.size() - 1]); 53 | //std::cout << proc->name; 54 | while(true) 55 | { 56 | 57 | } 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /libdebug/cpp/include/PS4DBG.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Platform.hpp" 3 | #include "Process.hpp" 4 | #include "Registers.hpp" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | using std::string_literals::operator""s; 18 | 19 | using DebuggerInterruptCallback = std::function; 20 | namespace libdebug 21 | { 22 | class PS4DBG 23 | { 24 | private: 25 | Socket sock; 26 | sockaddr_in server; 27 | std::thread debugThread; 28 | bool connected = false; 29 | bool debugging = false; 30 | 31 | inline static std::string LIBRARY_VERSION = "1.2"; 32 | 33 | static constexpr int32_t PS4DBG_PORT = 744; 34 | static constexpr int32_t PS4DBG_DEBUG_PORT = 755; 35 | static constexpr int32_t NET_MAX_LENGTH = 8192; 36 | 37 | static constexpr int32_t BROADCAST_PORT = 1010; 38 | static constexpr uint32_t BROADCAST_MAGIC = 0xFFFFAAAA; 39 | 40 | static constexpr uint32_t CMD_PACKET_MAGIC = 0xFFAABBCC; 41 | 42 | static constexpr uint32_t MAX_BREAKPOINTS = 10; 43 | static constexpr uint32_t MAX_WATCHPOINTS = 4; 44 | 45 | //proc 46 | // send size 47 | static constexpr int32_t CMD_PROC_READ_PACKET_SIZE = 16; 48 | static constexpr int32_t CMD_PROC_WRITE_PACKET_SIZE = 16; 49 | static constexpr int32_t CMD_PROC_MAPS_PACKET_SIZE = 4; 50 | static constexpr int32_t CMD_PROC_INSTALL_PACKET_SIZE = 4; 51 | static constexpr int32_t CMD_PROC_CALL_PACKET_SIZE = 68; 52 | static constexpr int32_t CMD_PROC_ELF_PACKET_SIZE = 8; 53 | static constexpr int32_t CMD_PROC_PROTECT_PACKET_SIZE = 20; 54 | static constexpr int32_t CMD_PROC_SCAN_PACKET_SIZE = 10; 55 | static constexpr int32_t CMD_PROC_INFO_PACKET_SIZE = 4; 56 | static constexpr int32_t CMD_PROC_ALLOC_PACKET_SIZE = 8; 57 | static constexpr int32_t CMD_PROC_FREE_PACKET_SIZE = 16; 58 | // receive size 59 | static constexpr int32_t PROC_LIST_ENTRY_SIZE = 36; 60 | static constexpr int32_t PROC_MAP_ENTRY_SIZE = 58; 61 | static constexpr int32_t PROC_INSTALL_SIZE = 8; 62 | static constexpr int32_t PROC_CALL_SIZE = 12; 63 | static constexpr int32_t PROC_PROC_INFO_SIZE = 184; 64 | static constexpr int32_t PROC_ALLOC_SIZE = 8; 65 | 66 | // kernel 67 | //send size 68 | static constexpr int32_t CMD_KERN_READ_PACKET_SIZE = 12; 69 | static constexpr int32_t CMD_KERN_WRITE_PACKET_SIZE = 12; 70 | //receive size 71 | static constexpr int32_t KERN_BASE_SIZE = 8; 72 | 73 | //console 74 | // send size 75 | static constexpr int32_t CMD_CONSOLE_PRINT_PACKET_SIZE = 4; 76 | static constexpr int32_t CMD_CONSOLE_NOTIFY_PACKET_SIZE = 8; 77 | 78 | //debug 79 | //send size 80 | static constexpr int32_t CMD_DEBUG_ATTACH_PACKET_SIZE = 4; 81 | static constexpr int32_t CMD_DEBUG_BREAKPT_PACKET_SIZE = 16; 82 | static constexpr int32_t CMD_DEBUG_WATCHPT_PACKET_SIZE = 24; 83 | static constexpr int32_t CMD_DEBUG_STOPTHR_PACKET_SIZE = 4; 84 | static constexpr int32_t CMD_DEBUG_RESUMETHR_PACKET_SIZE = 4; 85 | static constexpr int32_t CMD_DEBUG_GETREGS_PACKET_SIZE = 4; 86 | static constexpr int32_t CMD_DEBUG_SETREGS_PACKET_SIZE = 8; 87 | static constexpr int32_t CMD_DEBUG_STOPGO_PACKET_SIZE = 4; 88 | static constexpr int32_t CMD_DEBUG_THRINFO_PACKET_SIZE = 4; 89 | //receive size 90 | static constexpr int32_t DEBUG_INTERRUPT_SIZE = 0x4A0; 91 | static constexpr int32_t DEBUG_THRINFO_SIZE = 40; 92 | static constexpr int32_t DEBUG_REGS_SIZE = 0xB0; 93 | static constexpr int32_t DEBUG_FPREGS_SIZE = 0x340; 94 | static constexpr int32_t DEBUG_DBGREGS_SIZE = 0x80; 95 | 96 | enum class CMDS : uint32_t 97 | { 98 | CMD_VERSION = 0xBD000001, 99 | 100 | CMD_PROC_LIST = 0xBDAA0001, 101 | CMD_PROC_READ = 0xBDAA0002, 102 | CMD_PROC_WRITE = 0xBDAA0003, 103 | CMD_PROC_MAPS = 0xBDAA0004, 104 | CMD_PROC_INTALL = 0xBDAA0005, 105 | CMD_PROC_CALL = 0xBDAA0006, 106 | CMD_PROC_ELF = 0xBDAA0007, 107 | CMD_PROC_PROTECT = 0xBDAA0008, 108 | CMD_PROC_SCAN = 0xBDAA0009, 109 | CMD_PROC_INFO = 0xBDAA000A, 110 | CMD_PROC_ALLOC = 0xBDAA000B, 111 | CMD_PROC_FREE = 0xBDAA000C, 112 | 113 | CMD_DEBUG_ATTACH = 0xBDBB0001, 114 | CMD_DEBUG_DETACH = 0xBDBB0002, 115 | CMD_DEBUG_BREAKPT = 0xBDBB0003, 116 | CMD_DEBUG_WATCHPT = 0xBDBB0004, 117 | CMD_DEBUG_THREADS = 0xBDBB0005, 118 | CMD_DEBUG_STOPTHR = 0xBDBB0006, 119 | CMD_DEBUG_RESUMETHR = 0xBDBB0007, 120 | CMD_DEBUG_GETREGS = 0xBDBB0008, 121 | CMD_DEBUG_SETREGS = 0xBDBB0009, 122 | CMD_DEBUG_GETFPREGS = 0xBDBB000A, 123 | CMD_DEBUG_SETFPREGS = 0xBDBB000B, 124 | CMD_DEBUG_GETDBGREGS = 0xBDBB000C, 125 | CMD_DEBUG_SETDBGREGS = 0xBDBB000D, 126 | CMD_DEBUG_STOPGO = 0xBDBB0010, 127 | CMD_DEBUG_THRINFO = 0xBDBB0011, 128 | CMD_DEBUG_SINGLESTEP = 0xBDBB0012, 129 | 130 | CMD_KERN_BASE = 0xBDCC0001, 131 | CMD_KERN_READ = 0xBDCC0002, 132 | CMD_KERN_WRITE = 0xBDCC0003, 133 | 134 | CMD_CONSOLE_REBOOT = 0xBDDD0001, 135 | CMD_CONSOLE_END = 0xBDDD0002, 136 | CMD_CONSOLE_PRINT = 0xBDDD0003, 137 | CMD_CONSOLE_NOTIFY = 0xBDDD0004, 138 | CMD_CONSOLE_INFO = 0xBDDD0005, 139 | }; 140 | 141 | enum class CMD_STATUS : uint32_t 142 | { 143 | CMD_SUCCESS = 0x80000000, 144 | CMD_ERROR = 0xF0000001, 145 | CMD_TOO_MUCH_DATA = 0xF0000002, 146 | CMD_DATA_NULL = 0xF0000003, 147 | CMD_ALREADY_DEBUG = 0xF0000004, 148 | CMD_INVALID_INDEX = 0xF0000005 149 | }; 150 | 151 | 152 | struct CMDPacket 153 | { 154 | uint32_t magic; 155 | uint32_t cmd; 156 | uint32_t datalen; 157 | }; 158 | struct DebuggerInterruptPacket 159 | { 160 | uint32_t lwpid; 161 | uint32_t status; 162 | uint8_t tdname[40]; 163 | regs reg64; 164 | fpregs savefpu; 165 | dbregs dbreg64; 166 | }; 167 | 168 | public: 169 | enum class VM_PROTECTIONS : uint32_t 170 | { 171 | VM_PROT_NONE = 0x00, 172 | VM_PROT_READ = 0x01, 173 | VM_PROT_WRITE = 0x02, 174 | VM_PROT_EXECUTE = 0x04, 175 | VM_PROT_DEFAULT = (VM_PROT_READ | VM_PROT_WRITE), 176 | VM_PROT_ALL = (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE), 177 | VM_PROT_NO_CHANGE = 0x08, 178 | VM_PROT_COPY = 0x10, 179 | VM_PROT_WANTS_COPY = 0x10 180 | }; 181 | enum class WATCHPT_LENGTH : uint32_t 182 | { 183 | DBREG_DR7_LEN_1 = 0x00, /* 1 byte length */ 184 | DBREG_DR7_LEN_2 = 0x01, 185 | DBREG_DR7_LEN_4 = 0x03, 186 | DBREG_DR7_LEN_8 = 0x02, 187 | }; 188 | enum class WATCHPT_BREAKTYPE : uint32_t 189 | { 190 | DBREG_DR7_EXEC = 0x00, /* break on execute */ 191 | DBREG_DR7_WRONLY = 0x01, /* break on write */ 192 | DBREG_DR7_RDWR = 0x03, /* break on read or write */ 193 | }; 194 | 195 | private: 196 | void SendCMDPacket(CMDS cmd, int32_t length, const std::vector &fields = {}); 197 | CMD_STATUS ReceiveStatus(); 198 | CMD_STATUS CheckStatus(); 199 | void CheckConnected(); 200 | void CheckDebugging(); 201 | void SendData(const std::vector &data, int32_t length); 202 | std::vector ReceiveData(int32_t length); 203 | 204 | 205 | public: 206 | PS4DBG(const std::string &ip); 207 | ~PS4DBG(); 208 | void Connect(); 209 | void Disconnect(); 210 | static std::string GetLibraryDebugVersion(); 211 | std::string GetConsoleDebugVersion(); 212 | bool IsConnected(); 213 | bool IsDebugging(); 214 | //proc 215 | ProcessList GetProcessList(); 216 | std::vector ReadMemory(int32_t pid, uint64_t address, int32_t length); 217 | void WriteMemory(int32_t pid, uint64_t address, const std::vector &data); 218 | ProcessMap GetProcessMaps(int32_t pid); 219 | uint64_t InstallRPC(int32_t pid); 220 | uint64_t Call(int32_t pid, uint64_t rpcstub, uint64_t address, const std::vector &args); 221 | void LoadElf(int32_t pid, const std::vector &elf); 222 | void LoadElf(int32_t pid, const std::string &filePath); 223 | void ChangeProtection(int32_t pid, uint64_t address, uint32_t length, VM_PROTECTIONS newProt); 224 | ProcessInfo GetProcessInfo(int32_t pid); 225 | uint64_t AllocateMemory(int32_t pid, int32_t length); 226 | void FreeMemory(int32_t pid, uint64_t address, int32_t length); 227 | 228 | //kernel 229 | uint64_t KernelBase(); 230 | std::vector KernelReadMemory(uint64_t address, int32_t length); 231 | void KernelWriteMemory(uint64_t address, const std::vector &data); 232 | 233 | //console 234 | void Reboot(); 235 | void Print(const std::string &str); 236 | void Notify(int32_t messageType, const std::string &message); 237 | //debug 238 | void AttachDebugger(int32_t pid, DebuggerInterruptCallback callback); 239 | void DetachDebugger(); 240 | void ProcessStop(); 241 | void ProcessKill(); 242 | void ProcessResume(); 243 | void ChangeBreakpoint(int32_t index, bool enabled, uint64_t address); 244 | void ChangeWatchpoint(int32_t index, bool enabled, WATCHPT_LENGTH length, WATCHPT_BREAKTYPE breaktype, uint64_t address); 245 | 246 | std::vector GetThreadList(); 247 | ThreadInfo GetThreadInfo(uint32_t lwpid); 248 | void StopThread(uint32_t lwpid); 249 | void ResumeThread(uint32_t lwpid); 250 | regs GetRegisters(uint32_t lwpid); 251 | void SetRegisters(uint32_t lwpid, regs regs); 252 | fpregs GetFloatRegisters(uint32_t lwpid); 253 | void SetFloatRegisters(uint32_t lwpid, fpregs fpregs); 254 | dbregs GetDebugRegisters(uint32_t lwpid); 255 | void SetDebugRegisters(uint32_t lwpid, dbregs dbregs); 256 | void SingleStep(); 257 | private: 258 | void DebuggerThread(DebuggerInterruptCallback obj); 259 | }; 260 | } 261 | 262 | -------------------------------------------------------------------------------- /libdebug/cpp/include/Platform.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(_WIN32) 4 | #define PLATFORM_WINDOWS 5 | #pragma comment(lib, "Ws2_32.lib") 6 | #include 7 | #include 8 | #define CloseSocket closesocket 9 | #define SocketAvailable ioctlsocket 10 | typedef SOCKET Socket; 11 | 12 | #elif defined(__linux__) 13 | #define PLATFORM_LINUX 14 | #include 15 | #include 16 | #include 17 | #include 18 | #define CloseSocket close 19 | #define SocketAvailable ioctl 20 | typedef int32_t Socket; 21 | 22 | #elif defined(__APPLE__) 23 | #define PLATFORM_APPLE 24 | #include 25 | #include 26 | #include 27 | #include 28 | #define CloseSocket close 29 | #define SocketAvailable ioctl 30 | typedef int32_t Socket; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /libdebug/cpp/include/Process.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace libdebug 9 | { 10 | class Process : public std::enable_shared_from_this 11 | { 12 | public: 13 | const std::string name; 14 | const int32_t pid; 15 | 16 | Process(const std::string &name, int32_t pid); 17 | }; 18 | 19 | class ProcessList : public std::enable_shared_from_this 20 | { 21 | public: 22 | std::vector> processes; 23 | 24 | ProcessList(int32_t number, const std::vector &names, const std::vector &pids); 25 | std::shared_ptr FindProcess(const std::string &name, bool contains = false); 26 | }; 27 | 28 | struct MemoryEntry 29 | { 30 | public: 31 | std::string name; 32 | uint64_t start; 33 | uint64_t end; 34 | uint64_t offset; 35 | uint32_t prot; 36 | }; 37 | 38 | class ProcessMap 39 | { 40 | public: 41 | const int32_t pid; 42 | const std::vector> entries; 43 | 44 | ProcessMap(int32_t pid, std::vector> entries); 45 | 46 | std::shared_ptr FindEntry(const std::string &name, bool contains = false); 47 | std::shared_ptr FindEntry(uint64_t size); 48 | }; 49 | 50 | struct ProcessInfo 51 | { 52 | int32_t pid; 53 | uint8_t name[40]; 54 | uint8_t path[64]; 55 | uint8_t titleid[16]; 56 | uint8_t contentid[64]; 57 | }; 58 | 59 | struct ThreadInfo 60 | { 61 | int32_t pid; 62 | int32_t priority; 63 | uint8_t name[32]; 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /libdebug/cpp/include/Registers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace libdebug 5 | { 6 | struct regs 7 | { 8 | uint64_t r_r15; 9 | uint64_t r_r14; 10 | uint64_t r_r13; 11 | uint64_t r_r12; 12 | uint64_t r_r11; 13 | uint64_t r_r10; 14 | uint64_t r_r9; 15 | uint64_t r_r8; 16 | uint64_t r_rdi; 17 | uint64_t r_rsi; 18 | uint64_t r_rbp; 19 | uint64_t r_rbx; 20 | uint64_t r_rdx; 21 | uint64_t r_rcx; 22 | uint64_t r_rax; 23 | uint32_t r_trapno; 24 | uint16_t r_fs; 25 | uint16_t r_gs; 26 | uint32_t r_err; 27 | uint16_t r_es; 28 | uint16_t r_ds; 29 | uint64_t r_rip; 30 | uint64_t r_cs; 31 | uint64_t r_rflags; 32 | uint64_t r_rsp; 33 | uint64_t r_ss; 34 | }; 35 | 36 | 37 | struct envxmm 38 | { 39 | uint16_t en_cw; /* control word (16bits) */ 40 | uint16_t en_sw; /* status word (16bits) */ 41 | uint8_t en_tw; /* tag word (8bits) */ 42 | uint8_t en_zero; 43 | uint16_t en_opcode; /* opcode last executed (11 bits ) */ 44 | uint64_t en_rip; /* floating point instruction pointer */ 45 | uint64_t en_rdp; /* floating operand pointer */ 46 | uint32_t en_mxcsr; /* SSE sontorol/status register */ 47 | uint32_t en_mxcsr_mask; /* valid bits in mxcsr */ 48 | }; 49 | 50 | struct acc 51 | { 52 | uint8_t fp_bytes[10]; 53 | private: 54 | uint8_t fp_pad[6]; 55 | }; 56 | 57 | struct xmmacc 58 | { 59 | uint8_t xmm_bytes[16]; 60 | }; 61 | 62 | struct ymmacc 63 | { 64 | uint8_t ymm_bytes[16]; 65 | }; 66 | 67 | struct xstate_hdr 68 | { 69 | uint64_t xstate_bv; 70 | private: 71 | uint8_t xstate_rsrv0[16]; 72 | uint8_t xstate_rsrv[40]; 73 | }; 74 | 75 | struct savefpu_xstate 76 | { 77 | xstate_hdr sx_hd; 78 | ymmacc sx_ymm[16]; 79 | }; 80 | 81 | struct fpregs 82 | { 83 | envxmm svn_env; 84 | acc sv_fp[8]; 85 | xmmacc sv_xmm[16]; 86 | private: 87 | uint8_t sv_pad[96]; 88 | public: 89 | savefpu_xstate sv_xstate; 90 | }; 91 | 92 | struct dbregs 93 | { 94 | uint64_t dr0; 95 | uint64_t dr1; 96 | uint64_t dr2; 97 | uint64_t dr3; 98 | uint64_t dr4; 99 | uint64_t dr5; 100 | uint64_t dr6; 101 | uint64_t dr7; 102 | uint64_t dr8; 103 | uint64_t dr9; 104 | uint64_t dr10; 105 | uint64_t dr11; 106 | uint64_t dr12; 107 | uint64_t dr13; 108 | uint64_t dr14; 109 | uint64_t dr15; 110 | }; 111 | } -------------------------------------------------------------------------------- /libdebug/cpp/source/Process.cpp: -------------------------------------------------------------------------------- 1 | #include "Process.hpp" 2 | 3 | namespace libdebug 4 | { 5 | Process::Process(const std::string &name, int32_t pid) : name(name), pid(pid) 6 | { 7 | 8 | } 9 | 10 | ProcessList::ProcessList(int32_t number, const std::vector &names, const std::vector &pids) 11 | { 12 | 13 | processes = std::vector>(number); 14 | for(int32_t i = 0; i < number; i++) 15 | { 16 | processes[i] = std::make_shared(names[i], pids[i]); 17 | } 18 | 19 | } 20 | 21 | std::shared_ptr ProcessList::FindProcess(const std::string &name, bool contains) 22 | { 23 | for(auto process : processes) 24 | { 25 | if(contains) 26 | { 27 | if(process->name.find(name) != std::string::npos) 28 | return process; 29 | } 30 | else 31 | { 32 | if(process->name == name) 33 | return process; 34 | } 35 | } 36 | return nullptr; 37 | } 38 | 39 | ProcessMap::ProcessMap(int32_t pid, std::vector> entries) : pid(pid), entries(std::move(entries)) 40 | { 41 | 42 | } 43 | 44 | std::shared_ptr ProcessMap::FindEntry(const std::string &name, bool contains) 45 | { 46 | for(auto entry : entries) 47 | { 48 | if(contains) 49 | { 50 | if(entry->name.find(name) != std::string::npos) 51 | return entry; 52 | } 53 | else 54 | { 55 | if(entry->name == name) 56 | return entry; 57 | } 58 | } 59 | return nullptr; 60 | } 61 | 62 | std::shared_ptr ProcessMap::FindEntry(uint64_t size) 63 | { 64 | for(auto entry : entries) 65 | { 66 | if(entry->end - entry->start == size) 67 | return entry; 68 | } 69 | return nullptr; 70 | } 71 | 72 | } -------------------------------------------------------------------------------- /libdebug/csharp/PS4DBG.Console.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace libdebug 4 | { 5 | public partial class PS4DBG 6 | { 7 | //console 8 | // packet sizes 9 | // send size 10 | private const int CMD_CONSOLE_PRINT_PACKET_SIZE = 4; 11 | private const int CMD_CONSOLE_NOTIFY_PACKET_SIZE = 8; 12 | 13 | 14 | // console 15 | // note: the disconnect command actually uses the console api to end the connection 16 | /// 17 | /// Reboot console 18 | /// 19 | public void Reboot() 20 | { 21 | CheckConnected(); 22 | 23 | SendCMDPacket(CMDS.CMD_CONSOLE_REBOOT, 0); 24 | IsConnected = false; 25 | } 26 | 27 | /// 28 | /// Print to serial port 29 | /// 30 | public void Print(string str) 31 | { 32 | CheckConnected(); 33 | 34 | string raw = str + "\0"; 35 | 36 | SendCMDPacket(CMDS.CMD_CONSOLE_PRINT, CMD_CONSOLE_PRINT_PACKET_SIZE, raw.Length); 37 | SendData(Encoding.ASCII.GetBytes(raw), raw.Length); 38 | CheckStatus(); 39 | } 40 | 41 | /// 42 | /// Notify console 43 | /// 44 | public void Notify(int messageType, string message) 45 | { 46 | CheckConnected(); 47 | 48 | string raw = message + "\0"; 49 | 50 | SendCMDPacket(CMDS.CMD_CONSOLE_NOTIFY, CMD_CONSOLE_NOTIFY_PACKET_SIZE, messageType, raw.Length); 51 | SendData(Encoding.ASCII.GetBytes(raw), raw.Length); 52 | CheckStatus(); 53 | } 54 | 55 | /// 56 | /// Console information 57 | /// 58 | public void GetConsoleInformation() 59 | { 60 | CheckConnected(); 61 | 62 | SendCMDPacket(CMDS.CMD_CONSOLE_INFO, 0); 63 | CheckStatus(); 64 | 65 | // TODO return the data 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /libdebug/csharp/PS4DBG.Debug.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Net.Sockets; 4 | using System.Runtime.InteropServices; 5 | using System.Threading; 6 | 7 | namespace libdebug 8 | { 9 | public partial class PS4DBG 10 | { 11 | //debug 12 | // packet sizes 13 | //send size 14 | private const int CMD_DEBUG_ATTACH_PACKET_SIZE = 4; 15 | private const int CMD_DEBUG_BREAKPT_PACKET_SIZE = 16; 16 | private const int CMD_DEBUG_WATCHPT_PACKET_SIZE = 24; 17 | private const int CMD_DEBUG_STOPTHR_PACKET_SIZE = 4; 18 | private const int CMD_DEBUG_RESUMETHR_PACKET_SIZE = 4; 19 | private const int CMD_DEBUG_GETREGS_PACKET_SIZE = 4; 20 | private const int CMD_DEBUG_SETREGS_PACKET_SIZE = 8; 21 | private const int CMD_DEBUG_STOPGO_PACKET_SIZE = 4; 22 | private const int CMD_DEBUG_THRINFO_PACKET_SIZE = 4; 23 | //receive size 24 | private const int DEBUG_INTERRUPT_SIZE = 0x4A0; 25 | private const int DEBUG_THRINFO_SIZE = 40; 26 | private const int DEBUG_REGS_SIZE = 0xB0; 27 | private const int DEBUG_FPREGS_SIZE = 0x340; 28 | private const int DEBUG_DBGREGS_SIZE = 0x80; 29 | 30 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 31 | public struct DebuggerInterruptPacket 32 | { 33 | public uint lwpid; 34 | public uint status; 35 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)] 36 | public string tdname; 37 | public regs reg64; 38 | public fpregs savefpu; 39 | public dbregs dbreg64; 40 | } 41 | /// 42 | /// Debugger interrupt callback 43 | /// 44 | /// Thread identifier 45 | /// status 46 | /// Thread name 47 | /// Registers 48 | /// Floating point registers 49 | /// Debug registers 50 | public delegate void DebuggerInterruptCallback(uint lwpid, uint status, string tdname, regs regs, fpregs fpregs, dbregs dbregs); 51 | private void DebuggerThread(object obj) 52 | { 53 | DebuggerInterruptCallback callback = (DebuggerInterruptCallback)obj; 54 | 55 | IPAddress ip = IPAddress.Parse("0.0.0.0"); 56 | IPEndPoint endpoint = new IPEndPoint(ip, PS4DBG_DEBUG_PORT); 57 | 58 | Socket server = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 59 | 60 | server.Bind(endpoint); 61 | server.Listen(0); 62 | 63 | IsDebugging = true; 64 | 65 | Socket cl = server.Accept(); 66 | 67 | cl.NoDelay = true; 68 | cl.Blocking = false; 69 | 70 | while (IsDebugging) 71 | { 72 | if (cl.Available == DEBUG_INTERRUPT_SIZE) 73 | { 74 | byte[] data = new byte[DEBUG_INTERRUPT_SIZE]; 75 | int bytes = cl.Receive(data, DEBUG_INTERRUPT_SIZE, SocketFlags.None); 76 | if (bytes == DEBUG_INTERRUPT_SIZE) 77 | { 78 | DebuggerInterruptPacket packet = (DebuggerInterruptPacket)GetObjectFromBytes(data, typeof(DebuggerInterruptPacket)); 79 | callback(packet.lwpid, packet.status, packet.tdname, packet.reg64, packet.savefpu, packet.dbreg64); 80 | } 81 | } 82 | 83 | Thread.Sleep(100); 84 | } 85 | 86 | server.Close(); 87 | } 88 | /// 89 | /// Attach the debugger 90 | /// 91 | /// Process ID 92 | /// DebuggerInterruptCallback implementation 93 | /// 94 | public void AttachDebugger(int pid, DebuggerInterruptCallback callback) 95 | { 96 | CheckConnected(); 97 | 98 | if (IsDebugging || debugThread != null) 99 | { 100 | throw new Exception("libdbg: debugger already running?"); 101 | } 102 | 103 | IsDebugging = false; 104 | 105 | debugThread = new Thread(DebuggerThread) {IsBackground = true}; 106 | debugThread.Start(callback); 107 | 108 | // wait until server is started 109 | while (!IsDebugging) 110 | { 111 | Thread.Sleep(100); 112 | } 113 | 114 | SendCMDPacket(CMDS.CMD_DEBUG_ATTACH, CMD_DEBUG_ATTACH_PACKET_SIZE, pid); 115 | CheckStatus(); 116 | } 117 | 118 | /// 119 | /// Detach the debugger 120 | /// 121 | /// 122 | public void DetachDebugger() 123 | { 124 | CheckConnected(); 125 | 126 | SendCMDPacket(CMDS.CMD_DEBUG_DETACH, 0); 127 | CheckStatus(); 128 | 129 | if (IsDebugging && debugThread != null) 130 | { 131 | IsDebugging = false; 132 | 133 | debugThread.Join(); 134 | debugThread = null; 135 | } 136 | } 137 | 138 | /// 139 | /// Stop the current process 140 | /// 141 | /// 142 | public void ProcessStop() 143 | { 144 | CheckConnected(); 145 | CheckDebugging(); 146 | 147 | SendCMDPacket(CMDS.CMD_DEBUG_STOPGO, CMD_DEBUG_STOPGO_PACKET_SIZE, 1); 148 | CheckStatus(); 149 | } 150 | 151 | /// 152 | /// Kill the current process, it will detach before doing so 153 | /// 154 | /// 155 | public void ProcessKill() 156 | { 157 | CheckConnected(); 158 | CheckDebugging(); 159 | 160 | SendCMDPacket(CMDS.CMD_DEBUG_STOPGO, CMD_DEBUG_STOPGO_PACKET_SIZE, 2); 161 | CheckStatus(); 162 | } 163 | 164 | /// 165 | /// Resume the current process 166 | /// 167 | /// 168 | public void ProcessResume() 169 | { 170 | CheckConnected(); 171 | CheckDebugging(); 172 | 173 | SendCMDPacket(CMDS.CMD_DEBUG_STOPGO, CMD_DEBUG_STOPGO_PACKET_SIZE, 0); 174 | CheckStatus(); 175 | } 176 | 177 | /// 178 | /// Change breakpoint, to remove said breakpoint send the same index but disable it (address is ignored) 179 | /// 180 | /// Index 181 | /// Enabled 182 | /// Address 183 | /// 184 | public void ChangeBreakpoint(int index, bool enabled, ulong address) 185 | { 186 | CheckConnected(); 187 | CheckDebugging(); 188 | 189 | if (index >= MAX_BREAKPOINTS) 190 | { 191 | throw new Exception("libdbg: breakpoint index out of range"); 192 | } 193 | 194 | SendCMDPacket(CMDS.CMD_DEBUG_BREAKPT, CMD_DEBUG_BREAKPT_PACKET_SIZE, index, Convert.ToInt32(enabled), address); 195 | CheckStatus(); 196 | } 197 | 198 | /// 199 | /// Change watchpoint 200 | /// 201 | /// Index 202 | /// Enabled 203 | /// Length 204 | /// Break type 205 | /// Address 206 | /// 207 | public void ChangeWatchpoint(int index, bool enabled, WATCHPT_LENGTH length, WATCHPT_BREAKTYPE breaktype, ulong address) 208 | { 209 | CheckConnected(); 210 | CheckDebugging(); 211 | 212 | if (index >= MAX_WATCHPOINTS) 213 | { 214 | throw new Exception("libdbg: watchpoint index out of range"); 215 | } 216 | 217 | SendCMDPacket(CMDS.CMD_DEBUG_WATCHPT, CMD_DEBUG_WATCHPT_PACKET_SIZE, index, Convert.ToInt32(enabled), (uint)length, (uint)breaktype, address); 218 | CheckStatus(); 219 | } 220 | 221 | /// 222 | /// Get a list of threads from the current process 223 | /// 224 | /// 225 | public uint[] GetThreadList() 226 | { 227 | CheckConnected(); 228 | CheckDebugging(); 229 | 230 | SendCMDPacket(CMDS.CMD_DEBUG_THREADS, 0); 231 | CheckStatus(); 232 | 233 | byte[] data = new byte[sizeof(int)]; 234 | sock.Receive(data, sizeof(int), SocketFlags.None); 235 | int number = BitConverter.ToInt32(data, 0); 236 | 237 | byte[] threads = ReceiveData(number * sizeof(uint)); 238 | uint[] thrlist = new uint[number]; 239 | for (int i = 0; i < number; i++) 240 | { 241 | thrlist[i] = BitConverter.ToUInt32(threads, i * sizeof(uint)); 242 | } 243 | 244 | return thrlist; 245 | } 246 | 247 | /// 248 | /// Get thread information 249 | /// 250 | /// 251 | /// Thread identifier 252 | public ThreadInfo GetThreadInfo(uint lwpid) 253 | { 254 | CheckConnected(); 255 | CheckDebugging(); 256 | 257 | SendCMDPacket(CMDS.CMD_DEBUG_THRINFO, CMD_DEBUG_THRINFO_PACKET_SIZE, lwpid); 258 | CheckStatus(); 259 | 260 | return (ThreadInfo)GetObjectFromBytes(ReceiveData(DEBUG_THRINFO_SIZE), typeof(ThreadInfo)); 261 | } 262 | 263 | /// 264 | /// Stop a thread from running 265 | /// 266 | /// Thread id 267 | /// 268 | public void StopThread(uint lwpid) 269 | { 270 | CheckConnected(); 271 | CheckDebugging(); 272 | 273 | SendCMDPacket(CMDS.CMD_DEBUG_STOPTHR, CMD_DEBUG_STOPTHR_PACKET_SIZE, lwpid); 274 | CheckStatus(); 275 | } 276 | 277 | /// 278 | /// Resume a thread from being stopped 279 | /// 280 | /// Thread id 281 | /// 282 | public void ResumeThread(uint lwpid) 283 | { 284 | CheckConnected(); 285 | CheckDebugging(); 286 | 287 | SendCMDPacket(CMDS.CMD_DEBUG_RESUMETHR, CMD_DEBUG_RESUMETHR_PACKET_SIZE, lwpid); 288 | CheckStatus(); 289 | } 290 | 291 | /// 292 | /// Get registers from thread 293 | /// 294 | /// Thread id 295 | /// 296 | public regs GetRegisters(uint lwpid) 297 | { 298 | CheckConnected(); 299 | CheckDebugging(); 300 | 301 | SendCMDPacket(CMDS.CMD_DEBUG_GETREGS, CMD_DEBUG_GETREGS_PACKET_SIZE, lwpid); 302 | CheckStatus(); 303 | 304 | return (regs)GetObjectFromBytes(ReceiveData(DEBUG_REGS_SIZE), typeof(regs)); 305 | } 306 | 307 | /// 308 | /// Set thread registers 309 | /// 310 | /// Thread id 311 | /// Register data 312 | /// 313 | public void SetRegisters(uint lwpid, regs regs) 314 | { 315 | CheckConnected(); 316 | CheckDebugging(); 317 | 318 | SendCMDPacket(CMDS.CMD_DEBUG_SETREGS, CMD_DEBUG_SETREGS_PACKET_SIZE, lwpid, DEBUG_REGS_SIZE); 319 | CheckStatus(); 320 | SendData(GetBytesFromObject(regs), DEBUG_REGS_SIZE); 321 | CheckStatus(); 322 | } 323 | 324 | /// 325 | /// Get floating point registers from thread 326 | /// 327 | /// Thread id 328 | /// 329 | public fpregs GetFloatRegisters(uint lwpid) 330 | { 331 | CheckConnected(); 332 | CheckDebugging(); 333 | 334 | SendCMDPacket(CMDS.CMD_DEBUG_GETFPREGS, CMD_DEBUG_GETREGS_PACKET_SIZE, lwpid); 335 | CheckStatus(); 336 | 337 | return (fpregs)GetObjectFromBytes(ReceiveData(DEBUG_FPREGS_SIZE), typeof(fpregs)); 338 | } 339 | 340 | /// 341 | /// Set floating point thread registers 342 | /// 343 | /// Thread id 344 | /// Floating point register data 345 | /// 346 | public void SetFloatRegisters(uint lwpid, fpregs fpregs) 347 | { 348 | CheckConnected(); 349 | CheckDebugging(); 350 | 351 | SendCMDPacket(CMDS.CMD_DEBUG_SETFPREGS, CMD_DEBUG_SETREGS_PACKET_SIZE, lwpid, DEBUG_FPREGS_SIZE); 352 | CheckStatus(); 353 | SendData(GetBytesFromObject(fpregs), DEBUG_FPREGS_SIZE); 354 | CheckStatus(); 355 | } 356 | 357 | /// 358 | /// Get debug registers from thread 359 | /// 360 | /// Thread id 361 | /// 362 | public dbregs GetDebugRegisters(uint lwpid) 363 | { 364 | CheckConnected(); 365 | CheckDebugging(); 366 | 367 | SendCMDPacket(CMDS.CMD_DEBUG_GETDBGREGS, CMD_DEBUG_GETREGS_PACKET_SIZE, lwpid); 368 | CheckStatus(); 369 | 370 | return (dbregs)GetObjectFromBytes(ReceiveData(DEBUG_DBGREGS_SIZE), typeof(dbregs)); 371 | } 372 | 373 | /// 374 | /// Set debug thread registers 375 | /// 376 | /// Thread id 377 | /// debug register data 378 | /// 379 | public void SetDebugRegisters(uint lwpid, dbregs dbregs) 380 | { 381 | CheckConnected(); 382 | CheckDebugging(); 383 | 384 | SendCMDPacket(CMDS.CMD_DEBUG_SETDBGREGS, CMD_DEBUG_SETREGS_PACKET_SIZE, lwpid, DEBUG_DBGREGS_SIZE); 385 | CheckStatus(); 386 | SendData(GetBytesFromObject(dbregs), DEBUG_DBGREGS_SIZE); 387 | CheckStatus(); 388 | } 389 | 390 | /// 391 | /// Executes a single instruction 392 | /// 393 | public void SingleStep() 394 | { 395 | CheckConnected(); 396 | CheckDebugging(); 397 | 398 | SendCMDPacket(CMDS.CMD_DEBUG_SINGLESTEP, 0); 399 | CheckStatus(); 400 | } 401 | } 402 | } -------------------------------------------------------------------------------- /libdebug/csharp/PS4DBG.Kernel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace libdebug 4 | { 5 | public partial class PS4DBG 6 | { 7 | // kernel 8 | //packet sizes 9 | //send size 10 | private const int CMD_KERN_READ_PACKET_SIZE = 12; 11 | private const int CMD_KERN_WRITE_PACKET_SIZE = 12; 12 | //receive size 13 | private const int KERN_BASE_SIZE = 8; 14 | 15 | 16 | /// 17 | /// Get kernel base address 18 | /// 19 | /// 20 | public ulong KernelBase() 21 | { 22 | CheckConnected(); 23 | 24 | SendCMDPacket(CMDS.CMD_KERN_BASE, 0); 25 | CheckStatus(); 26 | return BitConverter.ToUInt64(ReceiveData(KERN_BASE_SIZE), 0); 27 | } 28 | 29 | /// 30 | /// Read memory from kernel 31 | /// 32 | /// Memory address 33 | /// Data length 34 | /// 35 | public byte[] KernelReadMemory(ulong address, int length) 36 | { 37 | CheckConnected(); 38 | 39 | SendCMDPacket(CMDS.CMD_KERN_READ, CMD_KERN_READ_PACKET_SIZE, address, length); 40 | CheckStatus(); 41 | return ReceiveData(length); 42 | } 43 | 44 | /// 45 | /// Write memory in kernel 46 | /// 47 | /// Memory address 48 | /// Data 49 | public void KernelWriteMemory(ulong address, byte[] data) 50 | { 51 | CheckConnected(); 52 | 53 | SendCMDPacket(CMDS.CMD_KERN_WRITE, CMD_KERN_WRITE_PACKET_SIZE, address, data.Length); 54 | CheckStatus(); 55 | SendData(data, data.Length); 56 | CheckStatus(); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /libdebug/csharp/PS4DBG.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using System.Net.Sockets; 5 | using System.Runtime.InteropServices; 6 | using System.Text; 7 | using System.Threading; 8 | 9 | namespace libdebug 10 | { 11 | public partial class PS4DBG 12 | { 13 | private Socket sock = null; 14 | private IPEndPoint enp = null; 15 | 16 | public bool IsConnected { get; private set; } = false; 17 | 18 | public bool IsDebugging { get; private set; } = false; 19 | 20 | private Thread debugThread = null; 21 | 22 | // some global values 23 | private const string LIBRARY_VERSION = "1.2"; 24 | private const int PS4DBG_PORT = 744; 25 | private const int PS4DBG_DEBUG_PORT = 755; 26 | private const int NET_MAX_LENGTH = 8192; 27 | 28 | private const int BROADCAST_PORT = 1010; 29 | private const uint BROADCAST_MAGIC = 0xFFFFAAAA; 30 | 31 | // from protocol.h 32 | // each packet starts with the magic 33 | // each C# base type can translate into a packet field 34 | // some packets, such as write take an additional data whose length will be specified in the cmd packet data field structure specific to that cmd type 35 | // ushort - 2 bytes | uint - 4 bytes | ulong - 8 bytes 36 | private const uint CMD_PACKET_MAGIC = 0xFFAABBCC; 37 | 38 | // from debug.h 39 | //struct debug_breakpoint { 40 | // uint32_t valid; 41 | // uint64_t address; 42 | // uint8_t original; 43 | //}; 44 | public static uint MAX_BREAKPOINTS = 10; 45 | public static uint MAX_WATCHPOINTS = 4; 46 | 47 | // struct cmd_packet { 48 | // uint32_t magic; 49 | // uint32_t cmd; 50 | // uint32_t datalen; 51 | // // (field not actually part of packet, comes after) 52 | // uint8_t* data; 53 | // } 54 | // __attribute__((packed)); 55 | // #define CMD_PACKET_SIZE 12 56 | private const int CMD_PACKET_SIZE = 12; 57 | public enum CMDS : uint 58 | { 59 | CMD_VERSION = 0xBD000001, 60 | 61 | CMD_PROC_LIST = 0xBDAA0001, 62 | CMD_PROC_READ = 0xBDAA0002, 63 | CMD_PROC_WRITE = 0xBDAA0003, 64 | CMD_PROC_MAPS = 0xBDAA0004, 65 | CMD_PROC_INTALL = 0xBDAA0005, 66 | CMD_PROC_CALL = 0xBDAA0006, 67 | CMD_PROC_ELF = 0xBDAA0007, 68 | CMD_PROC_PROTECT = 0xBDAA0008, 69 | CMD_PROC_SCAN = 0xBDAA0009, 70 | CMD_PROC_INFO = 0xBDAA000A, 71 | CMD_PROC_ALLOC = 0xBDAA000B, 72 | CMD_PROC_FREE = 0xBDAA000C, 73 | 74 | CMD_DEBUG_ATTACH = 0xBDBB0001, 75 | CMD_DEBUG_DETACH = 0xBDBB0002, 76 | CMD_DEBUG_BREAKPT = 0xBDBB0003, 77 | CMD_DEBUG_WATCHPT = 0xBDBB0004, 78 | CMD_DEBUG_THREADS = 0xBDBB0005, 79 | CMD_DEBUG_STOPTHR = 0xBDBB0006, 80 | CMD_DEBUG_RESUMETHR = 0xBDBB0007, 81 | CMD_DEBUG_GETREGS = 0xBDBB0008, 82 | CMD_DEBUG_SETREGS = 0xBDBB0009, 83 | CMD_DEBUG_GETFPREGS = 0xBDBB000A, 84 | CMD_DEBUG_SETFPREGS = 0xBDBB000B, 85 | CMD_DEBUG_GETDBGREGS = 0xBDBB000C, 86 | CMD_DEBUG_SETDBGREGS = 0xBDBB000D, 87 | CMD_DEBUG_STOPGO = 0xBDBB0010, 88 | CMD_DEBUG_THRINFO = 0xBDBB0011, 89 | CMD_DEBUG_SINGLESTEP = 0xBDBB0012, 90 | 91 | CMD_KERN_BASE = 0xBDCC0001, 92 | CMD_KERN_READ = 0xBDCC0002, 93 | CMD_KERN_WRITE = 0xBDCC0003, 94 | 95 | CMD_CONSOLE_REBOOT = 0xBDDD0001, 96 | CMD_CONSOLE_END = 0xBDDD0002, 97 | CMD_CONSOLE_PRINT = 0xBDDD0003, 98 | CMD_CONSOLE_NOTIFY = 0xBDDD0004, 99 | CMD_CONSOLE_INFO = 0xBDDD0005, 100 | }; 101 | 102 | public enum CMD_STATUS : uint 103 | { 104 | CMD_SUCCESS = 0x80000000, 105 | CMD_ERROR = 0xF0000001, 106 | CMD_TOO_MUCH_DATA = 0xF0000002, 107 | CMD_DATA_NULL = 0xF0000003, 108 | CMD_ALREADY_DEBUG = 0xF0000004, 109 | CMD_INVALID_INDEX = 0xF0000005 110 | }; 111 | 112 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 113 | public struct CMDPacket 114 | { 115 | public uint magic; 116 | public uint cmd; 117 | public uint datalen; 118 | } 119 | 120 | // enums 121 | public enum VM_PROTECTIONS : uint 122 | { 123 | VM_PROT_NONE = 0x00, 124 | VM_PROT_READ = 0x01, 125 | VM_PROT_WRITE = 0x02, 126 | VM_PROT_EXECUTE = 0x04, 127 | VM_PROT_DEFAULT = (VM_PROT_READ | VM_PROT_WRITE), 128 | VM_PROT_ALL = (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE), 129 | VM_PROT_NO_CHANGE = 0x08, 130 | VM_PROT_COPY = 0x10, 131 | VM_PROT_WANTS_COPY = 0x10 132 | }; 133 | public enum WATCHPT_LENGTH : uint 134 | { 135 | DBREG_DR7_LEN_1 = 0x00, /* 1 byte length */ 136 | DBREG_DR7_LEN_2 = 0x01, 137 | DBREG_DR7_LEN_4 = 0x03, 138 | DBREG_DR7_LEN_8 = 0x02, 139 | }; 140 | public enum WATCHPT_BREAKTYPE : uint 141 | { 142 | DBREG_DR7_EXEC = 0x00, /* break on execute */ 143 | DBREG_DR7_WRONLY = 0x01, /* break on write */ 144 | DBREG_DR7_RDWR = 0x03, /* break on read or write */ 145 | }; 146 | 147 | // General helper functions, make code cleaner 148 | public static string ConvertASCII(byte[] data, int offset) 149 | { 150 | int length = Array.IndexOf(data, 0, offset) - offset; 151 | if (length < 0) 152 | { 153 | length = data.Length - offset; 154 | } 155 | 156 | return Encoding.ASCII.GetString(data, offset, length); 157 | } 158 | public static byte[] SubArray(byte[] data, int offset, int length) 159 | { 160 | byte[] bytes = new byte[length]; 161 | Buffer.BlockCopy(data, offset, bytes, 0, length); 162 | return bytes; 163 | } 164 | public static object GetObjectFromBytes(byte[] buffer, Type type) 165 | { 166 | int size = Marshal.SizeOf(type); 167 | 168 | IntPtr ptr = Marshal.AllocHGlobal(size); 169 | 170 | Marshal.Copy(buffer, 0, ptr, size); 171 | object r = Marshal.PtrToStructure(ptr, type); 172 | 173 | Marshal.FreeHGlobal(ptr); 174 | 175 | return r; 176 | } 177 | public static byte[] GetBytesFromObject(object obj) 178 | { 179 | int size = Marshal.SizeOf(obj); 180 | 181 | byte[] bytes = new byte[size]; 182 | IntPtr ptr = Marshal.AllocHGlobal(size); 183 | 184 | Marshal.StructureToPtr(obj, ptr, false); 185 | Marshal.Copy(ptr, bytes, 0, size); 186 | 187 | Marshal.FreeHGlobal(ptr); 188 | 189 | return bytes; 190 | } 191 | 192 | // General networking functions 193 | private static IPAddress GetBroadcastAddress(IPAddress address, IPAddress subnetMask) 194 | { 195 | byte[] ipAdressBytes = address.GetAddressBytes(); 196 | byte[] subnetMaskBytes = subnetMask.GetAddressBytes(); 197 | 198 | byte[] broadcastAddress = new byte[ipAdressBytes.Length]; 199 | for (int i = 0; i < broadcastAddress.Length; i++) 200 | { 201 | broadcastAddress[i] = (byte)(ipAdressBytes[i] | (subnetMaskBytes[i] ^ 255)); 202 | } 203 | 204 | return new IPAddress(broadcastAddress); 205 | } 206 | private void SendCMDPacket(CMDS cmd, int length, params object[] fields) 207 | { 208 | CMDPacket packet = new CMDPacket 209 | { 210 | magic = CMD_PACKET_MAGIC, 211 | cmd = (uint) cmd, 212 | datalen = (uint) length 213 | }; 214 | 215 | byte[] data = null; 216 | 217 | if (length > 0) 218 | { 219 | MemoryStream rs = new MemoryStream(); 220 | foreach (object field in fields) 221 | { 222 | byte[] bytes = null; 223 | 224 | switch (field) 225 | { 226 | case char c: 227 | bytes = BitConverter.GetBytes(c); 228 | break; 229 | case byte b: 230 | bytes = BitConverter.GetBytes(b); 231 | break; 232 | case short s: 233 | bytes = BitConverter.GetBytes(s); 234 | break; 235 | case ushort us: 236 | bytes = BitConverter.GetBytes(us); 237 | break; 238 | case int i: 239 | bytes = BitConverter.GetBytes(i); 240 | break; 241 | case uint u: 242 | bytes = BitConverter.GetBytes(u); 243 | break; 244 | case long l: 245 | bytes = BitConverter.GetBytes(l); 246 | break; 247 | case ulong ul: 248 | bytes = BitConverter.GetBytes(ul); 249 | break; 250 | case byte[] ba: 251 | bytes = ba; 252 | break; 253 | } 254 | 255 | if (bytes != null) rs.Write(bytes, 0, bytes.Length); 256 | } 257 | 258 | data = rs.ToArray(); 259 | rs.Dispose(); 260 | } 261 | 262 | SendData(GetBytesFromObject(packet), CMD_PACKET_SIZE); 263 | 264 | if (data != null) 265 | { 266 | SendData(data, length); 267 | } 268 | } 269 | private void SendData(byte[] data, int length) 270 | { 271 | int left = length; 272 | int offset = 0; 273 | int sent = 0; 274 | 275 | while (left > 0) 276 | { 277 | if (left > NET_MAX_LENGTH) 278 | { 279 | byte[] bytes = SubArray(data, offset, NET_MAX_LENGTH); 280 | sent = sock.Send(bytes, NET_MAX_LENGTH, SocketFlags.None); 281 | } 282 | else 283 | { 284 | byte[] bytes = SubArray(data, offset, left); 285 | sent = sock.Send(bytes, left, SocketFlags.None); 286 | } 287 | 288 | offset += sent; 289 | left -= sent; 290 | } 291 | } 292 | private byte[] ReceiveData(int length) 293 | { 294 | MemoryStream s = new MemoryStream(); 295 | 296 | int left = length; 297 | int recv = 0; 298 | while (left > 0) 299 | { 300 | byte[] b = new byte[NET_MAX_LENGTH]; 301 | recv = sock.Receive(b, NET_MAX_LENGTH, SocketFlags.None); 302 | s.Write(b, 0, recv); 303 | left -= recv; 304 | } 305 | 306 | byte[] data = s.ToArray(); 307 | 308 | s.Dispose(); 309 | GC.Collect(); 310 | 311 | return data; 312 | } 313 | private CMD_STATUS ReceiveStatus() 314 | { 315 | byte[] status = new byte[4]; 316 | sock.Receive(status, 4, SocketFlags.None); 317 | return (CMD_STATUS)BitConverter.ToUInt32(status, 0); 318 | } 319 | private void CheckStatus() 320 | { 321 | CMD_STATUS status = ReceiveStatus(); 322 | if (status != CMD_STATUS.CMD_SUCCESS) 323 | { 324 | throw new Exception("libdbg status " + ((uint)status).ToString("X")); 325 | } 326 | } 327 | 328 | private void CheckConnected() 329 | { 330 | if (!IsConnected) 331 | { 332 | throw new Exception("libdbg: not connected"); 333 | } 334 | } 335 | private void CheckDebugging() 336 | { 337 | if (!IsDebugging) 338 | { 339 | throw new Exception("libdbg: not debugging"); 340 | } 341 | } 342 | 343 | 344 | 345 | /// 346 | /// Initializes PS4DBG class 347 | /// 348 | /// PlayStation 4 address 349 | public PS4DBG(IPAddress addr) 350 | { 351 | enp = new IPEndPoint(addr, PS4DBG_PORT); 352 | sock = new Socket(enp.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 353 | } 354 | 355 | /// 356 | /// Initializes PS4DBG class 357 | /// 358 | /// PlayStation 4 ip address 359 | public PS4DBG(string ip) 360 | { 361 | IPAddress addr = null; 362 | try 363 | { 364 | addr = IPAddress.Parse(ip); 365 | } 366 | catch (FormatException ex) 367 | { 368 | throw ex; 369 | } 370 | 371 | enp = new IPEndPoint(addr, PS4DBG_PORT); 372 | sock = new Socket(enp.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 373 | } 374 | 375 | /// 376 | /// Find the playstation ip 377 | /// 378 | public static string FindPlayStation() 379 | { 380 | UdpClient uc = new UdpClient(); 381 | IPEndPoint server = new IPEndPoint(IPAddress.Any, 0); 382 | uc.EnableBroadcast = true; 383 | uc.Client.ReceiveTimeout = 4000; 384 | 385 | byte[] magic = BitConverter.GetBytes(BROADCAST_MAGIC); 386 | 387 | IPAddress addr = null; 388 | IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName()); 389 | foreach (IPAddress ip in host.AddressList) 390 | { 391 | if (ip.AddressFamily == AddressFamily.InterNetwork) 392 | { 393 | addr = ip; 394 | } 395 | } 396 | 397 | if (addr == null) 398 | { 399 | throw new Exception("libdbg broadcast error: could not get host ip"); 400 | } 401 | 402 | uc.Send(magic, magic.Length, new IPEndPoint(GetBroadcastAddress(addr, IPAddress.Parse("255.255.255.0")), BROADCAST_PORT)); 403 | 404 | byte[] resp = uc.Receive(ref server); 405 | if (BitConverter.ToUInt32(resp, 0) != BROADCAST_MAGIC) 406 | { 407 | throw new Exception("libdbg broadcast error: wrong magic on udp server"); 408 | } 409 | 410 | return server.Address.ToString(); 411 | } 412 | 413 | /// 414 | /// Connects to PlayStation 4 415 | /// 416 | public void Connect() 417 | { 418 | if (!IsConnected) 419 | { 420 | sock.NoDelay = true; 421 | sock.ReceiveBufferSize = NET_MAX_LENGTH; 422 | sock.SendBufferSize = NET_MAX_LENGTH; 423 | 424 | sock.ReceiveTimeout = 1000 * 10; 425 | 426 | sock.Connect(enp); 427 | IsConnected = true; 428 | } 429 | } 430 | 431 | /// 432 | /// Disconnects from PlayStation 4 433 | /// 434 | public void Disconnect() 435 | { 436 | SendCMDPacket(CMDS.CMD_CONSOLE_END, 0); 437 | sock.Shutdown(SocketShutdown.Both); 438 | sock.Close(); 439 | IsConnected = false; 440 | } 441 | 442 | /// 443 | /// Get current ps4debug version from library 444 | /// 445 | public string GetLibraryDebugVersion() 446 | { 447 | return LIBRARY_VERSION; 448 | } 449 | 450 | /// 451 | /// Get the current ps4debug version from console 452 | /// 453 | public string GetConsoleDebugVersion() 454 | { 455 | CheckConnected(); 456 | 457 | SendCMDPacket(CMDS.CMD_VERSION, 0); 458 | 459 | byte[] ldata = new byte[4]; 460 | sock.Receive(ldata, 4, SocketFlags.None); 461 | 462 | int length = BitConverter.ToInt32(ldata, 0); 463 | 464 | byte[] data = new byte[length]; 465 | sock.Receive(data, length, SocketFlags.None); 466 | 467 | return ConvertASCII(data, 0); 468 | } 469 | } 470 | } -------------------------------------------------------------------------------- /libdebug/csharp/Process.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace libdebug 4 | { 5 | public class Process 6 | { 7 | public string name; 8 | public int pid; 9 | 10 | /// 11 | /// Initializes Process class 12 | /// 13 | /// Process name 14 | /// Process ID 15 | /// 16 | public Process(string name, int pid) 17 | { 18 | this.name = name; 19 | this.pid = pid; 20 | } 21 | public override string ToString() 22 | { 23 | return $"[{pid}] {name}"; 24 | } 25 | } 26 | 27 | public class ProcessList 28 | { 29 | public Process[] processes; 30 | 31 | /// 32 | /// Initializes ProcessList class 33 | /// 34 | /// Number of processes 35 | /// Process names 36 | /// Process IDs 37 | /// 38 | public ProcessList(int number, string[] names, int[] pids) 39 | { 40 | processes = new Process[number]; 41 | for (int i = 0; i < number; i++) 42 | { 43 | processes[i] = new Process(names[i], pids[i]); 44 | } 45 | } 46 | 47 | /// 48 | /// Finds a process based off name 49 | /// 50 | /// Process name 51 | /// Condition to check if process name contains name 52 | /// 53 | public Process FindProcess(string name, bool contains = false) 54 | { 55 | foreach (Process p in processes) 56 | { 57 | if (contains) 58 | { 59 | if (p.name.Contains(name)) 60 | { 61 | return p; 62 | } 63 | } 64 | else 65 | { 66 | if (p.name == name) 67 | { 68 | return p; 69 | } 70 | } 71 | } 72 | 73 | return null; 74 | } 75 | } 76 | 77 | public class MemoryEntry 78 | { 79 | public string name; 80 | public ulong start; 81 | public ulong end; 82 | public ulong offset; 83 | public uint prot; 84 | } 85 | 86 | public class ProcessMap 87 | { 88 | public int pid; 89 | public MemoryEntry[] entries; 90 | 91 | /// 92 | /// Initializes ProcessMap class with memory entries and process ID 93 | /// 94 | /// Process ID 95 | /// Process memory entries 96 | /// 97 | public ProcessMap(int pid, MemoryEntry[] entries) 98 | { 99 | this.pid = pid; 100 | this.entries = entries; 101 | } 102 | 103 | /// 104 | /// Finds a virtual memory entry based off name 105 | /// 106 | /// Virtual memory entry name 107 | /// Condition to check if entry name contains name 108 | /// 109 | public MemoryEntry FindEntry(string name, bool contains = false) 110 | { 111 | foreach (MemoryEntry entry in entries) 112 | { 113 | if (contains) 114 | { 115 | if (entry.name.Contains(name)) 116 | { 117 | return entry; 118 | } 119 | } 120 | else 121 | { 122 | if (entry.name == name) 123 | { 124 | return entry; 125 | } 126 | } 127 | } 128 | 129 | return null; 130 | } 131 | 132 | /// 133 | /// Finds a virtual memory entry based off size 134 | /// 135 | /// Virtual memory entry size 136 | /// 137 | public MemoryEntry FindEntry(ulong size) 138 | { 139 | foreach (MemoryEntry entry in entries) 140 | { 141 | if ((entry.start - entry.end) == size) 142 | { 143 | return entry; 144 | } 145 | } 146 | 147 | return null; 148 | } 149 | } 150 | 151 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 152 | public struct ProcessInfo 153 | { 154 | public int pid; 155 | 156 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)] 157 | public string name; 158 | 159 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] 160 | public string path; 161 | 162 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] 163 | public string titleid; 164 | 165 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] 166 | public string contentid; 167 | } 168 | 169 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 170 | public struct ThreadInfo 171 | { 172 | public int pid; 173 | public int priority; 174 | 175 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] 176 | public string name; 177 | } 178 | } -------------------------------------------------------------------------------- /libdebug/csharp/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | [assembly: AssemblyTitle("libdebug")] 5 | [assembly: AssemblyDescription("")] 6 | [assembly: AssemblyConfiguration("")] 7 | [assembly: AssemblyCompany("")] 8 | [assembly: AssemblyProduct("libdebug")] 9 | [assembly: AssemblyCopyright("Copyright © 2018")] 10 | [assembly: AssemblyTrademark("")] 11 | [assembly: AssemblyCulture("")] 12 | [assembly: ComVisible(false)] 13 | [assembly: Guid("a2e25459-1ceb-4d75-82f7-f85874279da1")] 14 | [assembly: AssemblyVersion("1.2")] 15 | [assembly: AssemblyFileVersion("1.2")] 16 | -------------------------------------------------------------------------------- /libdebug/csharp/Registers.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace libdebug 4 | { 5 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 6 | public struct regs 7 | { 8 | public ulong r_r15; 9 | public ulong r_r14; 10 | public ulong r_r13; 11 | public ulong r_r12; 12 | public ulong r_r11; 13 | public ulong r_r10; 14 | public ulong r_r9; 15 | public ulong r_r8; 16 | public ulong r_rdi; 17 | public ulong r_rsi; 18 | public ulong r_rbp; 19 | public ulong r_rbx; 20 | public ulong r_rdx; 21 | public ulong r_rcx; 22 | public ulong r_rax; 23 | public uint r_trapno; 24 | public ushort r_fs; 25 | public ushort r_gs; 26 | public uint r_err; 27 | public ushort r_es; 28 | public ushort r_ds; 29 | public ulong r_rip; 30 | public ulong r_cs; 31 | public ulong r_rflags; 32 | public ulong r_rsp; 33 | public ulong r_ss; 34 | } 35 | 36 | [StructLayout(LayoutKind.Sequential)] 37 | public struct envxmm 38 | { 39 | public ushort en_cw; /* control word (16bits) */ 40 | public ushort en_sw; /* status word (16bits) */ 41 | public byte en_tw; /* tag word (8bits) */ 42 | public byte en_zero; 43 | public ushort en_opcode; /* opcode last executed (11 bits ) */ 44 | public ulong en_rip; /* floating point instruction pointer */ 45 | public ulong en_rdp; /* floating operand pointer */ 46 | public uint en_mxcsr; /* SSE sontorol/status register */ 47 | public uint en_mxcsr_mask; /* valid bits in mxcsr */ 48 | } 49 | 50 | [StructLayout(LayoutKind.Sequential)] 51 | public struct acc 52 | { 53 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] 54 | public byte[] fp_bytes; 55 | 56 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] 57 | private byte[] fp_pad; 58 | } 59 | 60 | [StructLayout(LayoutKind.Sequential)] 61 | public struct xmmacc 62 | { 63 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 64 | public byte[] xmm_bytes; 65 | } 66 | 67 | [StructLayout(LayoutKind.Sequential)] 68 | public struct ymmacc 69 | { 70 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 71 | public byte[] ymm_bytes; 72 | } 73 | 74 | [StructLayout(LayoutKind.Sequential)] 75 | public struct xstate_hdr 76 | { 77 | public ulong xstate_bv; 78 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 79 | private byte[] xstate_rsrv0; 80 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)] 81 | private byte[] xstate_rsrv; 82 | } 83 | 84 | [StructLayout(LayoutKind.Sequential)] 85 | public struct savefpu_xstate 86 | { 87 | public xstate_hdr sx_hd; 88 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 89 | public ymmacc[] sx_ymm; 90 | } 91 | 92 | [StructLayout(LayoutKind.Sequential, Pack = 64)] 93 | public struct fpregs 94 | { 95 | public envxmm svn_env; 96 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] 97 | public acc[] sv_fp; 98 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 99 | public xmmacc[] sv_xmm; 100 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 96)] 101 | private byte[] sv_pad; 102 | public savefpu_xstate sv_xstate; 103 | } 104 | 105 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 106 | public struct dbregs 107 | { 108 | public ulong dr0; 109 | public ulong dr1; 110 | public ulong dr2; 111 | public ulong dr3; 112 | public ulong dr4; 113 | public ulong dr5; 114 | public ulong dr6; 115 | public ulong dr7; 116 | public ulong dr8; 117 | public ulong dr9; 118 | public ulong dr10; 119 | public ulong dr11; 120 | public ulong dr12; 121 | public ulong dr13; 122 | public ulong dr14; 123 | public ulong dr15; 124 | } 125 | } -------------------------------------------------------------------------------- /libdebug/csharp/libdebug.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {A2E25459-1CEB-4D75-82F7-F85874279DA1} 8 | Library 9 | Properties 10 | libdebug 11 | libdebug 12 | v2.0 13 | 512 14 | true 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 7.1 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 7.1 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | PS4DBG.cs 45 | 46 | 47 | PS4DBG.cs 48 | 49 | 50 | PS4DBG.cs 51 | 52 | 53 | PS4DBG.cs 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /send.sh: -------------------------------------------------------------------------------- 1 | # golden 2 | # change the ip for different networks... 3 | 4 | socat -u FILE:ps4debug.bin TCP:192.168.1.141:9020 5 | --------------------------------------------------------------------------------