├── .gitignore ├── Daemon-SystemState.h ├── LICENSE ├── Lnc_errors.h ├── README.md ├── ida_1.png ├── ida_2.png ├── ida_3.png └── writeup.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /Daemon-SystemState.h: -------------------------------------------------------------------------------- 1 | enum SystemState 2 | { 3 | INVALID = 0, 4 | INITIALIZING = 10, 5 | SHUTDOWN_ON_GOING = 100, 6 | POWER_SAVING = 200, 7 | SUSPEND_ON_GOING = 300, 8 | MAIN_ON_STANDBY = 500, 9 | WORKING = 1000 10 | }; 11 | 12 | enum TriggerCode 13 | { 14 | INVALID = 0, 15 | MISC = 1, 16 | HDMI_CEC = 2, 17 | REMOTE_PLAY = 100, 18 | COMPANION_APP = 101, 19 | REMOTE_PLAY_NP_PUSH = 102, 20 | UPDATER_SERVICE = 103, 21 | BGFT = 104, 22 | BG_DAILY_CHECK = 105, 23 | NP_EVENT_JOIN = 106, 24 | NP_EVENT_INFO_UPDATE = 107, 25 | SP_CONNECT = 108 26 | }; 27 | 28 | 29 | ///////////////////// USEFUL ////////////////// 30 | 31 | int sceSystemStateMgrGetCurrentState(void); 32 | int sceSystemStateMgrWakeUp(enum TriggerCode code); 33 | int sceSystemStateMgrEnterStandby(int a1); 34 | bool sceSystemStateMgrIsStandbyModeEnabled(void); 35 | int sceSystemStateMgrGetTriggerCode(void); 36 | 37 | /////////////////////////////////////////////// 38 | 39 | 40 | bool isRestMode() 41 | { 42 | return (unsigned int)sceSystemStateMgrGetCurrentState() == MAIN_ON_STANDBY; 43 | } 44 | 45 | bool IsOn() 46 | { 47 | return (unsigned int)sceSystemStateMgrGetCurrentState() == WORKING; 48 | } 49 | 50 | bool IsINITIALIZING() 51 | { 52 | return (unsigned int)sceSystemStateMgrGetCurrentState() == INITIALIZING; 53 | } 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 LightningMods 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Lnc_errors.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #define SCE_LNC_ERROR_APP_NOT_FOUND 0x80940031 // Usually happens if you try to launch an app not in app.db 5 | #define SCE_LNC_UTIL_ERROR_ALREADY_INITIALIZED 0x80940018 6 | #define SCE_LNC_UTIL_ERROR_ALREADY_RUNNING 0x8094000c 7 | #define SCE_LNC_UTIL_ERROR_ALREADY_RUNNING_KILL_NEEDED 0x80940010 8 | #define SCE_LNC_UTIL_ERROR_ALREADY_RUNNING_SUSPEND_NEEDED 0x80940011 9 | #define SCE_LNC_UTIL_ERROR_APP_ALREADY_RESUMED 0x8094001e 10 | #define SCE_LNC_UTIL_ERROR_APP_ALREADY_SUSPENDED 0x8094001d 11 | #define SCE_LNC_UTIL_ERROR_APP_NOT_IN_BACKGROUND 0x80940015 12 | #define SCE_LNC_UTIL_ERROR_APPHOME_EBOOTBIN_NOT_FOUND 0x80940008 13 | #define SCE_LNC_UTIL_ERROR_APPHOME_PARAMSFO_NOT_FOUND 0x80940009 14 | #define SCE_LNC_UTIL_ERROR_CANNOT_RESUME_INITIAL_USER_NEEDED 0x80940012 15 | #define SCE_LNC_UTIL_ERROR_DEVKIT_EXPIRED 0x8094000b 16 | #define SCE_LNC_UTIL_ERROR_IN_LOGOUT_PROCESSING 0x8094001a 17 | #define SCE_LNC_UTIL_ERROR_IN_SPECIAL_RESUME 0x8094001b 18 | #define SCE_LNC_UTIL_ERROR_INVALID_PARAM 0x80940005 19 | #define SCE_LNC_UTIL_ERROR_INVALID_STATE 0x80940019 20 | #define SCE_LNC_UTIL_ERROR_INVALID_TITLE_ID 0x8094001c 21 | #define SCE_LNC_UTIL_ERROR_LAUNCH_DISABLED_BY_MEMORY_MODE 0x8094000d 22 | #define SCE_LNC_UTIL_ERROR_NO_APP_INFO 0x80940004 23 | #define SCE_LNC_UTIL_ERROR_NO_LOGIN_USER 0x8094000a 24 | #define SCE_LNC_UTIL_ERROR_NO_SESSION_MEMORY 0x80940002 25 | #define SCE_LNC_UTIL_ERROR_NO_SFOKEY_IN_APP_INFO 0x80940014 26 | #define SCE_LNC_UTIL_ERROR_NO_SHELL_UI 0x8094000e 27 | #define SCE_LNC_UTIL_ERROR_NOT_ALLOWED 0x8094000f 28 | #define SCE_LNC_UTIL_ERROR_NOT_INITIALIZED 0x80940001 29 | #define SCE_LNC_UTIL_ERROR_OPTICAL_DISC_DRIVE 0x80940013 30 | #define SCE_LNC_UTIL_ERROR_SETUP_FS_SANDBOX 0x80940006 31 | #define SCE_LNC_UTIL_ERROR_SUSPEND_BLOCK_TIMEOUT 0x80940017 32 | #define SCE_LNC_UTIL_ERROR_VIDEOOUT_NOT_SUPPORTED 0x80940016 33 | #define SCE_LNC_UTIL_ERROR_WAITING_READY_FOR_SUSPEND_TIMEOUT 0x80940021 34 | #define SCE_SYSCORE_ERROR_LNC_INVALID_STATE 0x80aa000a 35 | #define SCE_LNC_UTIL_ERROR_NOT_INITIALIZED 0x80940001 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PS4-daemon-writeup 2 | How to run your own daemon 3 | 4 | 5 | View the writeup here 6 | https://github.com/LightningMods/PS4-daemon-writeup/blob/main/writeup.md 7 | -------------------------------------------------------------------------------- /ida_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LightningMods/PS4-daemon-writeup/dc404caac0cc0c8063f577a40996e929b3738552/ida_1.png -------------------------------------------------------------------------------- /ida_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LightningMods/PS4-daemon-writeup/dc404caac0cc0c8063f577a40996e929b3738552/ida_2.png -------------------------------------------------------------------------------- /ida_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LightningMods/PS4-daemon-writeup/dc404caac0cc0c8063f577a40996e929b3738552/ida_3.png -------------------------------------------------------------------------------- /writeup.md: -------------------------------------------------------------------------------- 1 | 2 | ## DAEMON Writeup ## 3 | 4 | Welcome to my writeup of how i found and implimented my own PS4 Daemon proc. 5 | 6 | 7 | ### Finding how Daemons work on PS4 ### 8 | 9 | when i first began i noticed when you call this functions from a game 10 | 11 | ```sceCommonDialogInitialize()``` 12 | 13 | you actually spawn a daemon of CDLG type 14 | 15 | ```[SceLncService] launchApp(NPXS22010) 16 | [SceLncService] category={gdg} VRMode={0,0} 17 | [SceLncService] hnm,psnf,pc,tk,ns={0,0,0,0,0} appBootMode={-1} 18 | [SceLncService] appType={SCE_LNC_APP_TYPE_CDLG} [] appVer={00.00} 19 | [SceLncService] Num. of logged-in users is 1 20 | [SceLncService] spawnApp 21 | [Syscore App] createApp NPXS22010 22 | 23 | [SceShellCore] FMEM 143.2/ 243.4 NPXS22010 SceCdlgApp 24 | ``` 25 | 26 | but how? good queston. 27 | 28 | The sub function incharge of spawning it is 29 | 30 | ``` 31 | sub_1020(...) 32 | 33 | ``` 34 | 35 | ![pic1](https://github.com/LightningMods/PS4-daemon-writeup/blob/main/ida_1.png) 36 | 37 | which calls many other check functions but also does 38 | 39 | ```sceLncUtilStartLaunchAppByTitleId("NPXS22010",....)``` 40 | 41 | as you imagine i was thinking but how.. 42 | 43 | first things first finding the structs which it seems to use 44 | after looking in shellui i found them! 45 | 46 | ``` 47 | 48 | enum Flag 49 | { 50 | Flag_None = 0, 51 | SkipLaunchCheck = 1, 52 | SkipResumeCheck = 1, 53 | SkipSystemUpdateCheck = 2, 54 | RebootPatchInstall = 4, 55 | VRMode = 8, 56 | NonVRMode = 16 57 | }; 58 | 59 | typedef struct _LncAppParam 60 | { 61 | u32 sz; 62 | u32 user_id; 63 | u32 app_opt; 64 | u64 crash_report; 65 | Flag check_flag; 66 | } 67 | LncAppParam; 68 | ``` 69 | 70 | An example of what ShellUI does in case anyone wants to hook it in mono via LNC class 71 | 72 | ``` 73 | 74 | LncUtil.LaunchAppParam launchAppParam = default(LncUtil.LaunchAppParam); 75 | 76 | byte[] array = new byte[3]; 77 | array[0] = 45; 78 | array[1] = 105; 79 | byte[] array2 = array; 80 | LncUtil.LaunchApp("NPXS21018", array2, array2.Length, ref launchAppParam); 81 | ``` 82 | 83 | just like sceSystemServiceLaunchApp these seem to have the same protos in the `libSceSystemService` module 84 | 85 | 86 | ![pic2](https://github.com/LightningMods/PS4-daemon-writeup/blob/main/ida_2.png) 87 | 88 | ``` 89 | int (*sceSystemServiceLaunchApp)(const char* titleId, const char* argv[], LncAppParam* param); 90 | int (*sceLncUtilStartLaunchAppByTitleId)(const char* titleId, const char* argv[], LncAppParam* param); 91 | //returns the Systems runetime app id 92 | u32 (*sceLncUtilLaunchApp)(const char* titleId, const char* argv[], LncAppParam* param); 93 | int(*sceSystemServiceRegisterDaemon)(void); // returns 0 for success 94 | int(*sceLncUtilRegisterDaemon)(void); 95 | int(*sceLncUtilUnregisterDaemon)(void); 96 | 97 | ``` 98 | 99 | `sceSystemServiceLaunchApp` calls `sceLncUtilStartLaunchApp` which then calls the IPC iirc 100 | 101 | 102 | 103 | after looking though other PS4 daemons, i noticed they are all similar and use gdd as their sfo catagory 104 | and they are installed to. 105 | 106 | (I'll save you the details on why that is) 107 | 108 | 109 | ```/system/vsh/app/TITLE_ID/``` 110 | 111 | Next we have to copy all our daemon files including eboot which is signed with System/GL Auth 112 | (which makes them limited on memory and forces you to manually load all modules) 113 | via the LoadInternal function flatz used for his GL app) 114 | 115 | You can find more info regarding internal module ids here... 116 | 117 | [Devwiki internal IDs](https://www.psdevwiki.com/ps4/Libraries#Internal_sysmodule_libraries) 118 | 119 | ``` 120 | make_fself.py --auth-info 010000000010003800000000001c004000ff00000000008000000000000000000000000000000000000000c000400040000000000000008000000000000000f00040ffff000000f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 cd.elf eboot.bin && copy eboot.bin I:\ 121 | 122 | ``` 123 | 124 | so next i did the following after i remounted the System partition as RW via nmount 125 | 126 | 127 | ``` 128 | /system/vsh/app/NPXS20119/sce_sys/param.sfo -> /system/vsh/app/LMSS0001/sce_sys/param.sfo 129 | eboot.bin -> /system/vsh/app/LMSS0001/eboot.bin 130 | etc 131 | ``` 132 | 133 | but when i tried running my function i had gotten 134 | 135 | ` 136 | SCE_LNC_UTIL_ERROR_NOT_INITIALIZED 137 | 0x80940001 138 | ` 139 | 140 | which can also be found where the ps4 keeps a list of errors 141 | 142 | so we need to first initialize it using 143 | 144 | ![pic3](https://github.com/LightningMods/PS4-daemon-writeup/blob/main/ida_3.png) 145 | 146 | 147 | 148 | ``` 149 | int (*sceLncUtilInitialize)(void); 150 | ``` 151 | which i found by backtracing shellcore to 152 | 153 | ``` 154 | sceSystemServiceInitializeForShellCore() 155 | ``` 156 | 157 | Note: you cannot call `sceSystemServiceInitializeForShellCore()` without being shellcore/having proper auth 158 | Or you will get EPERM. 159 | 160 | 161 | 162 | 163 | now we can finally run our daemon as follows 164 | 165 | Note: you can use LncUtil stubs instead with your SDK of choice to link these funcs 166 | But at the time I didn't make the stubs yet so I did it manually. 167 | 168 | Since all LNC Error begin with 0x8094XXXX just a simple math problem 169 | ``` 170 | 171 | bool IS_ERROR(uint32_t a1) 172 | { 173 | return a1 & 0x80000000; 174 | } 175 | ``` 176 | 177 | 178 | ``` 179 | 180 | sys_dynlib_load_prx("/system/common/lib/libSceSystemService.sprx", &libcmi); 181 | 182 | int serres = sys_dynlib_dlsym(libcmi, "sceSystemServiceLaunchApp", &sceSystemServiceLaunchApp_pointer); 183 | if (!serres) 184 | { 185 | klog("sceSystemServiceLaunchApp-pointer %p resolved from PRX\n", sceSystemServiceLaunchApp_pointer); 186 | 187 | sceLncUtilInitialize = (void*)(sceSystemServiceLaunchApp_pointer + 0x1110); 188 | 189 | klog("sceLncUtilInitialize %p resolved from PRX\n", sceLncUtilInitialize); 190 | sceLncUtilLaunchApp = (void*)(sceSystemServiceLaunchApp_pointer + 0x1130); 191 | 192 | klog("sceLncUtilLaunchApp %p resolved from PRX\n", sceLncUtilLaunchApp); 193 | 194 | if(!sceLncUtilInitialize || !sceLncUtilLaunchApp) 195 | goto fatal_error; 196 | 197 | OrbisUserServiceInitializeParams params; 198 | memset(¶ms, 0, sizeof(params)); 199 | params.priority = 700; 200 | 201 | klog("ret %x\n", sceUserServiceInitialize(¶ms)); 202 | 203 | OrbisUserServiceLoginUserIdList userIdList; 204 | 205 | klog("ret %x\n", sceUserServiceGetLoginUserIdList(&userIdList)); 206 | 207 | for (int i = 0; i < 4; i++) 208 | { 209 | if (userIdList.userId[i] != 0xFF) 210 | { 211 | klog("[%i] User ID 0x%x\n", i, userIdList.userId[i]); 212 | } 213 | } 214 | 215 | LncAppParam param; 216 | param.sz = sizeof(LncAppParam); 217 | param.user_id = userIdList.userId[0]; 218 | param.app_opt = 0; 219 | param.crash_report = 0; 220 | param.check_flag = 0; //Flag_None 221 | 222 | klog("sceLncUtilInitialize %x\n", sceLncUtilInitialize()); 223 | 224 | u32 res = sceLncUtilLaunchApp("LMSS00001", 0, ¶m) 225 | //Error handling 226 | if (IS_ERROR(res)) // app_ids start with 0x6XXXXXXX 227 | 228 | ``` 229 | since a daemon is a System proc. it has special needs 230 | 231 | - It needs to be linked with libkernel_sys 232 | - You need manually load all system modules (i.e UserService, SystemService, SceNet etc etc) 233 | using the `sceSysmoduleLoadModuleInternal` API `(Usage sceSysmoduleLoadModuleInternal(LIB_NUMBER))` 234 | replace LIB_NUMBER with the real number from here [!Psdevwiki Internal Libs](https://www.psdevwiki.com/ps4/Libraries#Internal_sysmodule_libraries) 235 | - **Optional** SystemState functions [!SystemState](https://github.com/LightningMods/PS4-daemon-writeup/blob/main/Daemon-SystemState.h) 236 | - **Optional** Register the Daemon with the PS4 by calling `sceSystemServiceRegisterDaemon(void)` 237 | - **Optional** Unregister the Daemon with the PS4 by calling `sceLncUtilUnregisterDaemon(void)` 238 | - **Optional** for Daemons to read or use the Controller you MUST add this after initiating 239 | The scePad library (`scePadInit()`) `scePadSetProcessPrivilege(1)` this sets Pad Proc Perms 240 | 241 | and after all our work Success! iv successfully launched my own daemon, mine took awhile to make as i have a RPC Server thats does ALOT. 242 | 243 | ``` 244 | 245 | [SceLncService] launchApp(LMSS0001) 246 | [SceLncService] category={gdd} VRMode={1,0} 247 | [SceLncService] hnm,psnf,pc,tk,ns={0,0,0,0,0} appBootMode={-1} 248 | [SceLncService] appType={SCE_LNC_APP_TYPE_DAEMON} [] appVer={00.00} 249 | [SceLncService] Num. of logged-in users is 1 250 | [SceLncService] spawnApp 251 | [Syscore App] createApp LMSS0001 252 | [DEBUG] Started Internal Module SCE_SYSMODULE_INTERNAL_SYSTEM_SERVICE 253 | [DEBUG] Started Internal Module SCE_SYSMODULE_INTERNAL_USER_SERVICE 254 | [DEBUG] Started Internal Module SCE_SYSMODULE_INTERNAL_NETCTL 255 | [DEBUG] Started Internal Module SCE_SYSMODULE_INTERNAL_NET 256 | [DEBUG] Started Internal Module SCE_SYSMODULE_INTERNAL_HTTP 257 | [DEBUG] Started Internal Module SCE_SYSMODULE_INTERNAL_SSL 258 | [DEBUG] Started Internal Module SCE_SYSMODULE_INTERNAL_SYS_CORE 259 | [DEBUG] Started Internal Module 0x80000018 260 | [DEBUG] Started Internal Module SCE_SYSMODULE_INTERNAL_NETCTL 261 | [DEBUG] Starting System FTP Process on Port 999 262 | Client list mutex UID: 0x802CD4E0 263 | Server thread started! 264 | Server thread UID: 0x812189C0 265 | Server socket fd: 5 266 | starting KLOG Thread on port 998 267 | sceNetBind(): 0x00000000 268 | sceNetListen(): 0x00000000 269 | Waiting for incoming connections... 270 | ``` 271 | ## 2nd way to launch a daemon wtihout writing to /system 272 | 273 | You can also launch a daemon using `sceSystemServiceAddLocalProcess` 274 | 275 | ``` 276 | sceSystemServiceAddLocalProcess(int AppId, const char* DAEMON_EBOOT, int param_size, const char* args[]); 277 | ``` 278 | 279 | Using the following method 280 | 281 | ``` 282 | const char* args[] = { 283 | "--CUSTOM_ARGS", 284 | NULL, 285 | }; 286 | 287 | //Your Apps AppId HERE 288 | int appID = sceSystemServiceGetAppIdOfMiniApp(); 289 | 290 | //DAEMON EBOOT Path 291 | char* path = "/data/eboot.bin"; 292 | 293 | //returns appId on successful launch (> 0) 294 | sceSystemServiceAddLocalProcess(appID, path, 0, &args); 295 | ``` 296 | 297 | after you see it works, only downside is if that AppId/App you gave it ever dies or crashes so will your daemon unlike the other way 298 | 299 | ``` 300 | [SceShellCore] FMEM 17.1/2591.5 ITEM00001 ItemzCore.self 301 | [SceShellCore] FMEM 4.0/ 31.1 ITEM00001 eboot.bin 302 | ``` 303 | 304 | Additonally you can kill Daemons using many functions, heres one 305 | 306 | ``` 307 | int sceSystemServiceKillApp(int appid, int how_to_kill, int kill_reason, bool core_dump ); 308 | 309 | if ((appid & ~0xFFFFFF) == 0x60000000) 310 | return sceSystemServiceKillApp(appid, -1, 0, 0); 311 | 312 | ``` 313 | 314 | (Also works for Launching Games) 315 | 316 | 317 | 318 | 319 | 320 | --------------------------------------------------------------------------------