-
-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
from https://github.com/hzhreal/PS4-save-utils based on cecie
- Loading branch information
Showing
6 changed files
with
365 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#ifndef INIT_H | ||
#define INIT_H | ||
|
||
#include <unistd.h> | ||
#include <sys/stat.h> | ||
#include <orbis/libkernel.h> | ||
#include <libjbc.h> | ||
|
||
#include "sd.h" | ||
#include "scall.h" | ||
|
||
int init_cred(void); | ||
int init_devices(void); | ||
|
||
#endif // INIT_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#ifndef SCALL_H | ||
#define SCALL_H | ||
|
||
#include <orbis/libkernel.h> | ||
|
||
int sys_open(const char *path, int flags, int mode); | ||
int sys_mknod(const char *path, mode_t mode, dev_t dev); | ||
|
||
#endif // SCALL_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#ifndef SD_H | ||
#define SD_H | ||
|
||
#include <stdio.h> | ||
#include <string.h> | ||
#include <stdint.h> | ||
#include <stdbool.h> | ||
#include <fcntl.h> | ||
#include <orbis/libkernel.h> | ||
#include <libjbc.h> | ||
#include "scall.h" | ||
|
||
#define ENC_SEALEDKEY_LEN 0x60 | ||
#define DEC_SEALEDKEY_LEN 0x20 | ||
#define MAX_PATH_LEN 256 | ||
|
||
#define UNUSED(x) (void)(x) | ||
|
||
typedef struct { | ||
int blockSize; | ||
uint8_t idk[2]; | ||
} CreatePfsSaveDataOpt; | ||
|
||
typedef struct { | ||
bool readOnly; | ||
char *budgetid; | ||
} MountSaveDataOpt; | ||
|
||
typedef struct { | ||
bool dummy; | ||
} UmountSaveDataOpt; | ||
|
||
int loadPrivLibs(void); | ||
int generateSealedKey(uint8_t data[ENC_SEALEDKEY_LEN]); | ||
int decryptSealedKey(uint8_t enc_key[ENC_SEALEDKEY_LEN], uint8_t dec_key[DEC_SEALEDKEY_LEN]); | ||
int decryptSealedKeyAtPath(const char *keyPath, uint8_t decryptedSealedKey[DEC_SEALEDKEY_LEN]); | ||
int mountSave(const char *folder, const char *saveName, const char *mountPath); | ||
int umountSave(const char *mountPath, int handle, bool ignoreErrors); | ||
uint16_t getMaxKeySet(void); | ||
|
||
#endif // SD_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
#include "init.h" | ||
|
||
int init_cred(void) { | ||
jbc_cred old_cred; | ||
jbc_cred cred; | ||
|
||
memset(&old_cred, 0, sizeof(jbc_cred)); | ||
memset(&cred, 0, sizeof(jbc_cred)); | ||
|
||
if (jbc_get_cred(&old_cred) != 0) { | ||
return -1; | ||
} | ||
old_cred.sonyCred = old_cred.sonyCred | 0x4000000000000000ULL; | ||
|
||
if (jbc_get_cred(&cred) != 0) { | ||
return -2; | ||
} | ||
cred.sonyCred = cred.sonyCred | 0x4000000000000000ULL; | ||
cred.sceProcType = 0x3801000000000013ULL; | ||
|
||
jbc_set_cred(&cred); | ||
setuid(0); | ||
|
||
return 0; | ||
} | ||
|
||
int init_devices(void) { | ||
struct stat s; | ||
memset(&s, 0, sizeof(struct stat)); | ||
|
||
// mount required devices into sandbox | ||
if (jbc_mount_in_sandbox("/dev/", "rootdev") != 0) { | ||
sceKernelDebugOutText(0, "Failed to mount devices\n"); | ||
return -1; | ||
} | ||
|
||
// create devices | ||
if (stat("/rootdev/pfsctldev", &s) == -1) { | ||
sceKernelDebugOutText(0, "err stat pfsctldev\n"); | ||
return -2; | ||
} | ||
else { | ||
if (sys_mknod("/dev/pfsctldev", S_IFCHR | 0777, s.st_dev) == -1) { | ||
sceKernelDebugOutText(0, "err mknod pfsctldev\n"); | ||
return -2; | ||
} | ||
} | ||
|
||
memset(&s, 0, sizeof(struct stat)); | ||
|
||
if (stat("/rootdev/lvdctl", &s) == -1) { | ||
sceKernelDebugOutText(0, "err stat lvdctl\n"); | ||
return -3; | ||
} | ||
else { | ||
if (sys_mknod("/dev/lvdctl", S_IFCHR | 0777, s.st_dev) == -1) { | ||
sceKernelDebugOutText(0, "err mknod lvdctl\n"); | ||
return -3; | ||
} | ||
} | ||
|
||
memset(&s, 0, sizeof(struct stat)); | ||
|
||
if (stat("/rootdev/sbl_srv", &s) == -1) { | ||
sceKernelDebugOutText(0, "err stat sbl_srv\n"); | ||
return -4; | ||
} | ||
else { | ||
if (sys_mknod("/dev/sbl_srv", S_IFCHR | 0777, s.st_dev) == -1) { | ||
sceKernelDebugOutText(0, "err mknod sbl_srv\n"); | ||
return -4; | ||
} | ||
} | ||
|
||
// now unmount devices | ||
if (jbc_unmount_in_sandbox("rootdev") != 0) { | ||
sceKernelDebugOutText(0, "Failed to unmount rootdev\n"); | ||
} | ||
|
||
// get max keyset that can be decrypted | ||
getMaxKeySet(); | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
#include "scall.h" | ||
|
||
int sys_open(const char *path, int flags, int mode) { | ||
int result; | ||
int err; | ||
|
||
asm volatile( | ||
".intel_syntax;" | ||
"mov rax, 5;" // System call number for open: 5 | ||
"syscall;" // Invoke syscall | ||
: "=a" (result), // Output operand: result | ||
"=@ccc" (err) // Output operand: err (clobbers condition codes) | ||
); | ||
|
||
return result; | ||
} | ||
|
||
int sys_mknod(const char *path, mode_t mode, dev_t dev) { | ||
int result; | ||
int err; | ||
|
||
asm volatile( | ||
".intel_syntax;" // Switches the assembly syntax to Intel syntax | ||
"mov rax, 14;" // Moves the value 14 into the RAX register (which typically holds the system call number) | ||
"mov r10, rcx;" // Moves the value of the RCX register into the R10 register | ||
"syscall;" // Executes a system call using the values in the registers | ||
: "=a"(result), // Output constraint: Tells the compiler that the result of the operation will be stored in the RAX register | ||
"=@ccc"(err) // Output constraint: Indicates that error information will be stored in the specified location | ||
); | ||
|
||
return result; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
#include <unistd.h> | ||
#include "sd.h" | ||
|
||
int (*sceFsUfsAllocateSaveData)(int fd, uint64_t imageSize, uint64_t imageFlags, int ext); | ||
int (*sceFsInitCreatePfsSaveDataOpt)(CreatePfsSaveDataOpt *opt); | ||
int (*sceFsCreatePfsSaveDataImage)(CreatePfsSaveDataOpt *opt, const char *volumePath, int idk, uint64_t volumeSize, uint8_t decryptedSealedKey[DEC_SEALEDKEY_LEN]); | ||
int (*sceFsInitMountSaveDataOpt)(MountSaveDataOpt *opt); | ||
int (*sceFsMountSaveData)(MountSaveDataOpt *opt, const char *volumePath, const char *mountPath, uint8_t decryptedSealedKey[DEC_SEALEDKEY_LEN]); | ||
int (*sceFsInitUmountSaveDataOpt)(UmountSaveDataOpt *opt); | ||
int (*sceFsUmountSaveData)(UmountSaveDataOpt *opt, const char *mountPath, int handle, bool ignoreErrors); | ||
void (*statfs)(); | ||
|
||
// must be loaded upon setup | ||
int loadPrivLibs(void) { | ||
const char privDir[] = "/system/priv/lib"; | ||
const char commonDir[] = "/system/common/lib"; | ||
int sys; | ||
int kernel_sys; | ||
|
||
if (jbc_mount_in_sandbox(privDir, "priv") != 0) { | ||
sceKernelDebugOutText(0, "Failed to mount system/priv/lib directory\n"); | ||
return -1; | ||
} | ||
|
||
sys = sceKernelLoadStartModule("/priv/libSceFsInternalForVsh.sprx", 0, NULL, 0, NULL, NULL); | ||
if (jbc_unmount_in_sandbox("priv") != 0) { | ||
sceKernelDebugOutText(0, "Failed to unmount priv\n"); | ||
} | ||
|
||
if (sys >= 0) { | ||
sceKernelDlsym(sys, "sceFsInitCreatePfsSaveDataOpt", (void **)&sceFsInitCreatePfsSaveDataOpt); | ||
sceKernelDlsym(sys, "sceFsCreatePfsSaveDataImage", (void **)&sceFsCreatePfsSaveDataImage); | ||
sceKernelDlsym(sys, "sceFsUfsAllocateSaveData", (void **)&sceFsUfsAllocateSaveData); | ||
sceKernelDlsym(sys, "sceFsInitMountSaveDataOpt", (void **)&sceFsInitMountSaveDataOpt); | ||
sceKernelDlsym(sys, "sceFsMountSaveData", (void **)&sceFsMountSaveData); | ||
sceKernelDlsym(sys, "sceFsInitUmountSaveDataOpt", (void **)&sceFsInitUmountSaveDataOpt); | ||
sceKernelDlsym(sys, "sceFsUmountSaveData", (void **)&sceFsUmountSaveData); | ||
} | ||
else { | ||
sceKernelDebugOutText(0, "Failed to load libSceFsInternalForVsh.sprx\n"); | ||
return -2; | ||
} | ||
|
||
if (jbc_mount_in_sandbox(commonDir, "common") != 0) { | ||
sceKernelDebugOutText(0, "Failed to mount /system/common/lib directory\n"); | ||
return -3; | ||
} | ||
kernel_sys = sceKernelLoadStartModule("/common/libkernel_sys.sprx", 0, NULL, 0, NULL, NULL); | ||
if (jbc_unmount_in_sandbox("common") != 0) { | ||
sceKernelDebugOutText(0, "Failed to unmount common\n"); | ||
} | ||
|
||
if (kernel_sys >= 0) { | ||
sceKernelDlsym(kernel_sys, "statfs", (void **)&statfs); | ||
} | ||
else { | ||
sceKernelDebugOutText(0, "Failed to load libkernel_sys.sprx\n"); | ||
return -4; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
int generateSealedKey(uint8_t data[ENC_SEALEDKEY_LEN]) { | ||
uint8_t dummy[0x30]; | ||
uint8_t sealedKey[ENC_SEALEDKEY_LEN]; | ||
int fd; | ||
|
||
UNUSED(dummy); | ||
|
||
memset(sealedKey, 0, sizeof(sealedKey)); | ||
|
||
if ((fd = open("/dev/sbl_srv", O_RDWR)) == -1) { | ||
sceKernelDebugOutText(0, "sbl_srv open fail!\n"); | ||
return -1; | ||
} | ||
|
||
if (ioctl(fd, 0x40845303, sealedKey) == -1) { | ||
close(fd); | ||
return -2; | ||
} | ||
|
||
memcpy(data, sealedKey, sizeof(sealedKey)); | ||
close(fd); | ||
|
||
return 0; | ||
} | ||
|
||
int decryptSealedKey(uint8_t enc_key[ENC_SEALEDKEY_LEN], uint8_t dec_key[DEC_SEALEDKEY_LEN]) { | ||
uint8_t dummy[0x10]; | ||
uint8_t data[ENC_SEALEDKEY_LEN + DEC_SEALEDKEY_LEN]; | ||
int fd; | ||
|
||
memset(data, 0, sizeof(data)); | ||
|
||
UNUSED(dummy); | ||
|
||
if ((fd = open("/dev/sbl_srv", O_RDWR)) == -1) { | ||
sceKernelDebugOutText(0, "sbl_srv open fail!\n"); | ||
return -1; | ||
} | ||
|
||
memcpy(data, enc_key, ENC_SEALEDKEY_LEN); | ||
|
||
if (ioctl(fd, 0xc0845302, data) == -1) { | ||
close(fd); | ||
return -2; | ||
} | ||
|
||
memcpy(dec_key, &data[ENC_SEALEDKEY_LEN], DEC_SEALEDKEY_LEN); | ||
|
||
close(fd); | ||
return 0; | ||
} | ||
|
||
int decryptSealedKeyAtPath(const char *keyPath, uint8_t decryptedSealedKey[DEC_SEALEDKEY_LEN]) { | ||
uint8_t sealedKey[ENC_SEALEDKEY_LEN]; | ||
// ssize_t bytesRead; | ||
int fd; | ||
|
||
if ((fd = sys_open(keyPath, O_RDONLY, 0)) == -1) { | ||
return -1; | ||
} | ||
|
||
if (read(fd, sealedKey, ENC_SEALEDKEY_LEN) != ENC_SEALEDKEY_LEN) { | ||
return -2; | ||
close(fd); | ||
} | ||
close(fd); | ||
|
||
if (decryptSealedKey(sealedKey, decryptedSealedKey) == -1) { | ||
return -3; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
int mountSave(const char *folder, const char *saveName, const char *mountPath) { | ||
char volumeKeyPath[MAX_PATH_LEN]; | ||
char volumePath[MAX_PATH_LEN]; | ||
char bid[] = "system"; | ||
int ret; | ||
uint8_t decryptedSealedKey[DEC_SEALEDKEY_LEN]; | ||
MountSaveDataOpt opt; | ||
|
||
memset(&opt, 0, sizeof(MountSaveDataOpt)); | ||
|
||
sprintf(volumeKeyPath, "%s/%s.bin", folder, saveName); | ||
sprintf(volumePath, "%s/%s", folder, saveName); | ||
|
||
if ((ret = decryptSealedKeyAtPath(volumeKeyPath, decryptedSealedKey)) < 0) { | ||
return ret; | ||
} | ||
|
||
sceFsInitMountSaveDataOpt(&opt); | ||
opt.budgetid = bid; | ||
|
||
if ((ret = sceFsMountSaveData(&opt, volumePath, mountPath, decryptedSealedKey)) < 0) { | ||
return ret; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
int umountSave(const char *mountPath, int handle, bool ignoreErrors) { | ||
UmountSaveDataOpt opt; | ||
sceFsInitUmountSaveDataOpt(&opt); | ||
return sceFsUmountSaveData(&opt, mountPath, handle, ignoreErrors); | ||
} | ||
|
||
uint16_t maxKeyset = 0; | ||
uint16_t getMaxKeySet(void) { | ||
if (maxKeyset > 0) { | ||
return maxKeyset; | ||
} | ||
|
||
uint8_t sampleSealedKey[ENC_SEALEDKEY_LEN]; | ||
if (generateSealedKey(sampleSealedKey) != 0) { | ||
return 0; | ||
} | ||
|
||
maxKeyset = (sampleSealedKey[9] << 8) + sampleSealedKey[8]; | ||
return maxKeyset; | ||
} |