From ee57a608f6ddd8923a79d29b3c3f141f009e4670 Mon Sep 17 00:00:00 2001
From: Li
Date: Fri, 16 Jun 2023 18:42:35 +1200
Subject: [PATCH 01/11] Add PspEmu Promote option to refresh.c
---
CMakeLists.txt | 1 +
package_installer.c | 21 +++++--
package_installer.h | 6 +-
pbp.c | 148 ++++++++++++++++++++++++++++++++++++++++++++
pbp.h | 96 ++++++++++++++++++++++++++++
refresh.c | 139 ++++++++++++++++++++++++++++++++++++++---
6 files changed, 395 insertions(+), 16 deletions(-)
create mode 100644 pbp.c
create mode 100644 pbp.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 44c00a3c..a9192ad8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -101,6 +101,7 @@ add_executable(VitaShell
network_download.c
context_menu.c
archive.c
+ pbp.c
psarc.c
photo.c
audioplayer.c
diff --git a/package_installer.c b/package_installer.c
index 20cf50a2..4b5e61ad 100644
--- a/package_installer.c
+++ b/package_installer.c
@@ -48,14 +48,14 @@ static int unloadScePaf() {
return sceSysmoduleUnloadModuleInternalWithArg(SCE_SYSMODULE_INTERNAL_PAF, 0, NULL, &buf);
}
-int promotePsm(const char *path, const char *titleid) {
+int promoteCma(const char *path, const char *titleid, int type) {
int res;
ScePromoterUtilityImportParams promoteArgs;
memset(&promoteArgs,0x00,sizeof(ScePromoterUtilityImportParams));
strncpy(promoteArgs.path,path,0x7F);
strncpy(promoteArgs.titleid,titleid,0xB);
- promoteArgs.type = SCE_PKG_TYPE_PSM;
+ promoteArgs.type = type;
promoteArgs.attribute = 0x1;
res = loadScePaf();
@@ -89,8 +89,11 @@ int promotePsm(const char *path, const char *titleid) {
return res;
}
-int promoteApp(const char *path) {
+// for some reason, psp only seems to work if you use PromotePkg, not PromotePkgWithRif.
+// and also only if you do an asyncronous promote
+int promotePsp(const char *path) {
int res;
+ int state = -1;
res = loadScePaf();
if (res < 0)
@@ -104,10 +107,17 @@ int promoteApp(const char *path) {
if (res < 0)
return res;
- res = scePromoterUtilityPromotePkgWithRif(path, 1);
+ res = scePromoterUtilityPromotePkg(path, 0);
if (res < 0)
return res;
+ // wait for promote to finish
+ while(state != 0){ scePromoterUtilityGetState(&state); };
+ scePromoterUtilityGetResult(&res);
+
+ if(res < 0)
+ return res;
+
res = scePromoterUtilityExit();
if (res < 0)
return res;
@@ -243,7 +253,7 @@ int makeHeadBin() {
getSfoString(sfo_buffer, "TITLE_ID", titleid, sizeof(titleid));
// Enforce TITLE_ID format
- if ((strlen(titleid) != 9) || (strncmp(titleid, strupr(titleid), 9) != 0))
+ if (TITLEID_FMT_CHECK(titleid))
return VITASHELL_ERROR_INVALID_TITLEID;
// Get content id
@@ -291,6 +301,7 @@ int makeHeadBin() {
return 0;
}
+
int installPackage(const char *file) {
int res;
diff --git a/package_installer.h b/package_installer.h
index 2a56e029..342855fe 100644
--- a/package_installer.h
+++ b/package_installer.h
@@ -24,12 +24,16 @@
#define PACKAGE_DIR "ux0:data/pkg"
#define HEAD_BIN PACKAGE_DIR "/sce_sys/package/head.bin"
+#define TITLEID_FMT_CHECK(x) (x == NULL) || (strlen(x) != 9) || (strncmp(x, strupr(x), 9) != 0)
+
typedef struct {
char *file;
} InstallArguments;
int promoteApp(const char *path);
-int promotePsm(const char *path, const char *titleid);
+int promoteCma(const char *path, const char *titleid, int type);
+int promotePsp(const char *path);
+
int deleteApp(const char *titleid);
int checkAppExist(const char *titleid);
diff --git a/pbp.c b/pbp.c
new file mode 100644
index 00000000..af1f3ce8
--- /dev/null
+++ b/pbp.c
@@ -0,0 +1,148 @@
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include "main.h"
+#include "pbp.h"
+#include "sfo.h"
+
+int read_content_id_data_psp(SceUID pbp_fd, char* content_id) {
+ DataPspHeader data_psp_header;
+
+ // read data.psp header
+ int read_sz = sceIoRead(pbp_fd, &data_psp_header, sizeof(DataPspHeader));
+ if(read_sz < sizeof(DataPspHeader)) return 0;
+
+ // copy the content id from data.psp header to this content_id buffer
+ strncpy(content_id, data_psp_header.content_id, sizeof(npumdimg_header.content_id));
+
+ return 0;
+}
+
+int read_content_id_npumdimg(SceUID pbp_fd, char* content_id) {
+ NpUmdImgHeader npumdimg_header;
+
+ // read npumd header
+ int read_sz = sceIoRead(pbp_fd, &npumdimg_header, sizeof(NpUmdImgHeader));
+ if(read_sz < sizeof(NpUmdImgHeader)) return 0;
+
+ // copy the content id from npumdimg_header to this content_id buffer
+ strncpy(content_id, npumdimg_header.content_id, sizeof(npumdimg_header.content_id));
+
+ return 1;
+}
+
+int read_data_psar_header(SceUID pbp_fd, char* content_id) {
+ PbpHeader pbp_header;
+ char data_psar_magic[0x8];
+
+ int read_sz = sceIoRead(pbp_fd, &pbp_header, sizeof(PbpHeader));
+ if(read_sz < sizeof(PbpHeader)) return 0;
+
+ // seek to data.psar
+ sceIoLseek(pbp_fd, pbp_header.data_psar_ptr, SCE_SEEK_SET);
+
+ // read magic value to determine pbp type
+ read_sz = sceIoRead(pbp_fd, data_psar_magic, sizeof(data_psar_magic));
+ if(read_sz < sizeof(data_psar_magic)) return 0;
+
+ if(memcmp(data_psar_magic, "NPUMDIMG") == 0) { // psp
+ // seek to start of npumdimg
+ sceIoLseek(pbp_fd, pbp_header.data_psar_ptr, SCE_SEEK_SET);
+
+ // read content_id from npumdimg
+ return read_content_id_data_psp(pbp_fd, &pbp_header, content_id);
+ }
+ else if(memcmp(data_psar_magic, "PSISOIMG") == 0 || memcmp(data_psar_magic, "PSTITLEI") == 0) { // ps1
+ sceIoLseek(pbp_fd, pbp_header.data_psp_ptr, SCE_SEEK_SET);
+ }
+ else{ // update package, homebrew, etc,
+ return 0;
+ }
+
+ if(read_sz < sizeof(PbpHeader)) return 0;
+}
+
+int read_sfo(SceUID pbp_fd, void** param_sfo_buffer){
+ PbpHeader pbp_header;
+ // read pbp header
+ int read_sz = sceIoRead(pbp_fd, &pbp_header, sizeof(PbpHeader));
+ if(read_sz < sizeof(PbpHeader)) return 0;
+
+ // get sfo size
+ int param_sfo_size = pbp_header.icon0_png_ptr - pbp_header.param_sfo_ptr;
+ if(param_sfo_size <= 0) return 0;
+
+ // allocate a buffer for the param.sfo file
+ *param_sfo_buffer = malloc(param_sfo_size);
+ if(*param_sfo_buffer == NULL) return 0;
+
+ // seek to the start of param.sfo
+ sceIoLseek(pbp_header.param_sfo_ptr, SCE_SEEK_SET);
+
+ // read the param.sfo file
+ read_sz = sceIoRead(pbp_fd, *param_sfo_buffer, param_sfo_size);
+ if(read_sz < param_sfo_size) {
+ free(*param_sfo_buffer);
+ *param_sfo_buffer = NULL;
+ return 0;
+ }
+
+ return param_sfo_size;
+}
+
+int get_pbp_sfo(const char pbp_file, void** param_sfo_buffer) {
+ PbpHeader pbp_header;
+
+ if(param_sfo_buffer == NULL) return;
+ *param_sfo_buffer = NULL;
+
+ int res = 0;
+
+ if(pbp_file != NULL) {
+ SceUID pbp_fd = sceIoOpen(pbp_file);
+ if(pbp_fd < 0) return NULL;
+
+ // read param.sfo from pbp
+ res = read_sfo(pbp_fd, param_sfo_buffer);
+
+ sceIoClose(pbp_fd);
+ }
+
+ return res;
+}
+
+int get_pbp_content_id(const char* pbp_file, char* content_id) {
+ int res = 0;
+
+ if(pbp_file != NULL && content_id != NULL) {
+ SceUID pbp_fd = sceIoOpen(pbp_file);
+ if(pbp_fd < 0) return 0;
+ res = read_content_id(pbp_fd, content_id);
+
+ // check the content id is valid
+ if(res) {
+ int content_id_len = strnlen(content_id, 0x30);
+ if(content_id_len != 0x24) res = 0;
+ }
+
+ sceIoClose(pbp_fd);
+ }
+
+ return res;
+
+}
\ No newline at end of file
diff --git a/pbp.h b/pbp.h
new file mode 100644
index 00000000..211d43e6
--- /dev/null
+++ b/pbp.h
@@ -0,0 +1,96 @@
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef __PBP_H__
+#define __PBP_H__
+
+// for PSISOIMG and PSTITLEIMG contents
+
+typedef struct DataPspHeader{
+ char magic[0x4];
+ char unk[0x7C];
+ char unk2[0x32];
+ char unk3[0xE];
+ char hash[0x14];
+ char reserved[0x58];
+ char unk4[0x434];
+ char content_id[0x30];
+} DataPspHeader;
+
+// for NPUMDIMG content
+typedef struct NpUmdImgBody {
+ SceUInt16 sector_size; // 0x0800
+ SceUInt16 unk_2; // 0xE000
+ SceUInt32 unk_4;
+ SceUInt32 unk_8;
+ SceUInt32 unk_12;
+ SceUInt32 unk_16;
+ SceUInt32 lba_start;
+ SceUInt32 unk_24;
+ SceUInt32 nsectors;
+ SceUInt32 unk_32;
+ SceUInt32 lba_end;
+ SceUInt32 unk_40;
+ SceUInt32 block_entry_offset;
+ char disc_id[0x10];
+ SceUInt32 header_start_offset;
+ SceUInt32 unk_68;
+ SceUInt8 unk_72;
+ SceUInt8 bbmac_param;
+ SceUInt8 unk_74;
+ SceUInt8 unk_75;
+ SceUInt32 unk_76;
+ SceUInt32 unk_80;
+ SceUInt32 unk_84;
+ SceUInt32 unk_88;
+ SceUInt32 unk_92;
+} NpUmdImgBody;
+
+typedef struct NpUmdImgHeader{
+ SceUInt8 magic[0x08]; // "NPUMDIMG"
+ SceUInt32 key_index; // usually 2, or 3.
+ SceUInt32 block_basis;
+ SceUInt8 content_id[0x30];
+ NpUmdImgBody body;
+ SceUInt8 header_key[0x10];
+ SceUInt8 data_key[0x10];
+ SceUInt8 header_hash[0x10];
+ SceUInt8 padding[0x8];
+ SceUInt8 ecdsa_sig[0x28];
+} NpUmdImgHeader;
+
+// generic eboot.pbp header
+
+typedef struct PbpHeader
+{
+ char magic[0x4];
+ SceUInt32 version;
+ SceUInt32 param_sfo_ptr;
+ SceUInt32 icon0_png_ptr;
+ SceUInt32 icon1_pmf_ptr;
+ SceUInt32 pic0_png_ptr;
+ SceUInt32 pic1_png_ptr;
+ SceUInt32 snd0_at3_ptr;
+ SceUInt32 data_psp_ptr;
+ SceUInt32 data_psar_ptr;
+} PbpHeader;
+
+int get_pbp_sfo(const char* pbp_file, void** param_sfo_buffer);
+int get_pbp_content_id(const char* pbp_file, char* content_id);
+
+#endif
\ No newline at end of file
diff --git a/refresh.c b/refresh.c
index 13100f1e..e02c27a8 100644
--- a/refresh.c
+++ b/refresh.c
@@ -31,6 +31,7 @@
#include "utils.h"
#include "rif.h"
#include "pfs.h"
+#include "pbp.h"
// Note: The promotion process is *VERY* sensitive to the directories used below
// Don't change them unless you know what you are doing!
@@ -39,6 +40,7 @@
#define PATCH_TEMP "ux0:temp/patch"
#define PSM_TEMP "ux0:temp/game"
#define THEME_TEMP "ux0:temp/theme"
+#define PSP_TEMP "ux0:pspemu/temp/game"
#define MAX_DLC_PER_TITLE 1024
@@ -63,6 +65,7 @@ int refreshNeeded(const char *app_path, const char* content_type) {
char sfo_path[MAX_PATH_LENGTH];
int mounted_appmeta;
char titleid[12], contentid[50], appver[8];
+
if(strcmp(content_type,"psm") == 0)
{
char contentid_path[MAX_PATH_LENGTH];
@@ -87,6 +90,45 @@ int refreshNeeded(const char *app_path, const char* content_type) {
free(cidFile);
}
+ else if(strcmp(content_type, "psp")) {
+ // read eboot.pbp
+ char ebootpbp_path[MAX_PATH_LENGTH];
+
+ // Initalize buffers
+ memset(titleid,0,12);
+ memset(contentid,0,50);
+ memset(appver,0,8);
+
+ // the vita actually uses the folder name as the title id in PSP case
+ // this is also important for e.g cloning trick
+ char* app_directory = getFilename(app_path);
+ if(TITLEID_FMT_CHECK(app_directory)){
+ if(app_directory != NULL)
+ free(app_directory);
+
+ return 0;
+ }
+
+ strncpy(titleid, app_directory, 12);
+ free(app_directory);
+
+ snprintf(ebootpbp_path, MAX_PATH_LENGTH, "%s/EBOOT.PBP", app_path);
+
+ // Get content_id
+ if(!get_pbp_content_id(ebootpbp_path, contentid))
+ return 0;
+
+
+ // Get param.sfo
+ void *sfo_buffer = NULL;
+ int sfo_size = get_pbp_sfo(ebootpbp_path, &sfo_buffer);
+ if(sfo_size <= 0)
+ return 0;
+
+ getSfoString(sfo_buffer, "APP_VER", appver, sizeof(appver));
+
+ free(sfo_buffer);
+ }
else {
// Read param.sfo
snprintf(sfo_path, MAX_PATH_LENGTH, "%s/sce_sys/param.sfo", app_path);
@@ -108,7 +150,7 @@ int refreshNeeded(const char *app_path, const char* content_type) {
// Check if app or dlc exists
- if (((strcmp(content_type, "app") == 0)||(strcmp(content_type, "dlc") == 0)||(strcmp(content_type,"psm") == 0))&&(checkAppExist(titleid))) {
+ if (((strcmp(content_type, "app") == 0)||(strcmp(content_type, "dlc") == 0) && (checkAppExist(titleid))) {
char rif_name[48];
char rif_path[MAX_PATH_LENGTH];
@@ -133,10 +175,7 @@ int refreshNeeded(const char *app_path, const char* content_type) {
if (checkFileExist(rif_path))
return 0;
- if(strcmp(content_type,"psm") == 0)
- return 0;
}
-
// Check if patch for installed app exists
else if (strcmp(content_type, "patch") == 0) {
if (!checkAppExist(titleid))
@@ -160,6 +199,13 @@ int refreshNeeded(const char *app_path, const char* content_type) {
return 0;
}
}
+ // license not needed to promote psp or psm contents
+ else if((strcmp(content_type, "psm" == 0) || (strcmp(content_type, "psp" == 0)) && (checkAppExist(titleid))) {
+ if(strcmp(content_type, "psp") == 0) {
+ // TODO: check __sce_ebootpbp
+ }
+ return 0;
+ }
return 1;
}
@@ -248,6 +294,7 @@ typedef struct {
uint8_t* rif;
} license_data_t;
+
void app_callback(void* data, const char* dir, const char* subdir) {
refresh_data_t *refresh_data = (refresh_data_t*)data;
char path[MAX_PATH_LENGTH];
@@ -354,15 +401,76 @@ void patch_callback(void* data, const char* dir, const char* subdir) {
}
}
-void psm_callback(void* data, const char* dir, const char* subdir) {
+void psp_callback(void* data, const char* dir, const char* subdir) {
refresh_data_t *refresh_data = (refresh_data_t*)data;
char path[MAX_PATH_LENGTH];
- if (strcasecmp(subdir, vitashell_titleid) == 0)
- return;
+ if (refresh_data->refresh_pass) {
+ snprintf(path, MAX_PATH_LENGTH, "%s/%s", dir, subdir);
+ if (refreshNeeded(path, "psp")){
+ removePath(PSP_TEMP, NULL);
+ char content_id[0x30];
+ char game_folder[MAX_PATH_LENGTH];
+
+ char eboot_pbp[MAX_PATH_LENGTH];
+ char license_rif[MAX_PATH_LENGTH];
+
+ // get path to executables
+ snprintf(game_folder, MAX_PATH_LENGTH, "%s/PSP/GAME/%s", path, subdir);
+ snprintf(eboot_pbp, MAX_PATH_LENGTH, "%s/EBOOT.PBP", game_folder, eboot_pbp);
+
+ if(get_pbp_content_id(eboot_pbp, contentid)){
+ // create directories
+ char promote_psp_folder[MAX_PATH_LENGTH];
+ char promote_psp_game_folder[MAX_PATH_LENGTH];
+ char promote_psp_license_folder[MAX_PATH_LENGTH];
+
+ char promote_license_rif[MAX_PATH_LENGTH];
+ char promote_game_folder[MAX_PATH_LENGTH];
+
+ snprintf(promote_psp_folder, "%s/PSP", PSP_TEMP);
+ snprintf(promote_psp_game_folder, "%s/PSP/GAME", PSP_TEMP);
+ snprintf(promote_psp_license_folder, "%s/PSP/LICENSE", PSP_TEMP);
+
+ snprintf(promote_license_rif, "%s/PSP/LICENSE/%s.rif", PSP_TEMP, contentid);
+ snprintf(promote_game_folder, "%s/PSP/GAME/%s", PSP_TEMP, subdir);
+
+ // get current rif location
+ snprintf(license_rif, MAX_PATH_LENGTH, "s/PSP/LICENSE/%s.rif", path, contentid);
+
+ // create the promote directories
+ sceIoMkdir(promote_psp_folder, 0006);
+ sceIoMkdir(promote_psp_game_folder, 0006);
+ sceIoMkdir(promote_psp_license_folder, 0006);
+
+ // copy the rif to the promote location
+ copyFile(license_rif, promote_license_rif, NULL);
+ sceIoRename(path, promote_game_folder);
+
+ // finally call promote
+ if (promoteCma(PSP_TEMP, subdir, SCE_PKG_TYPE_VITA) == 0)
+ refresh_data->refreshed++;
+ else
+ sceIoRename(promote_game_folder, path); // Restore folder on error
+ removePath(PSP_TEMP, NULL); // delete what was created
+ }
+ }
+
+
+ }
+ SetProgress(++refresh_data->processed, refresh_data->count);
+ } else {
+ refresh_data->count++;
+ }
+
+}
+
+void psm_callback(void* data, const char* dir, const char* subdir) {
+ refresh_data_t *refresh_data = (refresh_data_t*)data;
+ char path[MAX_PATH_LENGTH];
if (refresh_data->refresh_pass) {
- snprintf(path, MAX_PATH_LENGTH, "%s/%s", dir, subdir);
+ snprintf(path, MAX_PATH_LENGTH, "%s/%s", dir, subdir);
if (refreshNeeded(path, "psm")) {
char contentid_path[MAX_PATH_LENGTH];
snprintf(contentid_path, MAX_PATH_LENGTH, "%s/RW/System/content_id", path);
@@ -385,14 +493,14 @@ void psm_callback(void* data, const char* dir, const char* subdir) {
// Get promote path
char promote_path[MAX_PATH_LENGTH];
- snprintf(promote_path,MAX_PATH_LENGTH,"%s/%s",PSM_TEMP,titleid);
+ snprintf(promote_path,MAX_PATH_LENGTH,"%s/%s",PSM_TEMP, titleid);
// Move the directory to temp for installation
removePath(promote_path, NULL);
sceIoRename(path, promote_path);
// Finally call promote
- if (promotePsm(PSM_TEMP,titleid) == 0)
+ if (promoteCma(PSM_TEMP, titleid, SCE_PKG_TYPE_PSM) == 0)
refresh_data->refreshed++;
else
sceIoRename(promote_path, path); // Restore folder on error
@@ -429,15 +537,21 @@ int refresh_thread(SceSize args, void *argp) {
// Get the psm count
if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:psm", psm_callback, &refresh_data) < 0)
goto EXIT;
+
+ // Get the psp count
+ if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:pspemu/PSP/GAME", psp_callback, &refresh_data) < 0)
+ goto EXIT;
// Update thread
thid = createStartUpdateThread(refresh_data.count, 0);
// Make sure we have the temp directories we need
sceIoMkdir("ux0:temp", 0006);
+ sceIoMkdir("ux0:pspemu", 0006);
sceIoMkdir(DLC_TEMP, 0006);
sceIoMkdir(PATCH_TEMP, 0006);
sceIoMkdir(PSM_TEMP, 0006);
+ sceIoMkdir(PSP_TEMP, 0006);
refresh_data.refresh_pass = 1;
// Refresh apps
@@ -456,9 +570,14 @@ int refresh_thread(SceSize args, void *argp) {
if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:psm", psm_callback, &refresh_data) < 0)
goto EXIT;
+ // Refresh psp
+ if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:pspemu/PSP/GAME", psp_callback, &refresh_data) < 0)
+ goto EXIT;
+
sceIoRmdir(DLC_TEMP);
sceIoRmdir(PATCH_TEMP);
sceIoRmdir(PSM_TEMP);
+ sceIoRmdir(PSP_TEMP);
// Set progress to 100%
sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 100);
From 92c1d2bb779c47f5a1c6b703de7d080cee4aa602 Mon Sep 17 00:00:00 2001
From: Li
Date: Fri, 16 Jun 2023 18:55:52 +1200
Subject: [PATCH 02/11] fix build error on latest vitasdk
---
modules/kernel/main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/modules/kernel/main.c b/modules/kernel/main.c
index 69fbb181..1e7d029a 100644
--- a/modules/kernel/main.c
+++ b/modules/kernel/main.c
@@ -20,10 +20,10 @@
#include
#include
#include
+#include
#include
#include
-#include
#include
From 33c0a84bbfff15305bb8f568593b2cbe80cc5922 Mon Sep 17 00:00:00 2001
From: Li
Date: Fri, 16 Jun 2023 19:10:47 +1200
Subject: [PATCH 03/11] fix compile errors
---
CMakeLists.txt | 8 ++++----
refresh.c | 7 ++-----
2 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a9192ad8..d2b2f8e1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -22,10 +22,10 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c+ + 11 -fno-rtti -fno-exceptions")
set(VITA_MKSFOEX_FLAGS "${VITA_MKSFOEX_FLAGS} -d PARENTAL_LEVEL=1")
set(VITA_MAKE_FSELF_FLAGS "${VITA_MAKE_FSELF_FLAGS} -a 0x2808000000000000")
-add_subdirectory(modules/kernel)
-add_subdirectory(modules/user)
-add_subdirectory(modules/patch)
-add_subdirectory(modules/usbdevice)
+#add_subdirectory(modules/kernel)
+#add_subdirectory(modules/user)
+#add_subdirectory(modules/patch)
+#add_subdirectory(modules/usbdevice)
include_directories(
modules/kernel
diff --git a/refresh.c b/refresh.c
index e02c27a8..9ddb34c4 100644
--- a/refresh.c
+++ b/refresh.c
@@ -150,7 +150,7 @@ int refreshNeeded(const char *app_path, const char* content_type) {
// Check if app or dlc exists
- if (((strcmp(content_type, "app") == 0)||(strcmp(content_type, "dlc") == 0) && (checkAppExist(titleid))) {
+ if (((strcmp(content_type, "app") == 0) || (strcmp(content_type, "dlc") == 0)) && (checkAppExist(titleid)) {
char rif_name[48];
char rif_path[MAX_PATH_LENGTH];
@@ -454,10 +454,7 @@ void psp_callback(void* data, const char* dir, const char* subdir) {
sceIoRename(promote_game_folder, path); // Restore folder on error
removePath(PSP_TEMP, NULL); // delete what was created
}
- }
-
-
- }
+ }
SetProgress(++refresh_data->processed, refresh_data->count);
} else {
refresh_data->count++;
From ce105297fa6abdbb956137f8d5aea7039c7ee2b8 Mon Sep 17 00:00:00 2001
From: Li
Date: Fri, 16 Jun 2023 19:14:01 +1200
Subject: [PATCH 04/11] Fix if case
---
refresh.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/refresh.c b/refresh.c
index 9ddb34c4..4eb4067d 100644
--- a/refresh.c
+++ b/refresh.c
@@ -150,7 +150,7 @@ int refreshNeeded(const char *app_path, const char* content_type) {
// Check if app or dlc exists
- if (((strcmp(content_type, "app") == 0) || (strcmp(content_type, "dlc") == 0)) && (checkAppExist(titleid)) {
+ if(((strcmp(content_type, "app") == 0) || (strcmp(content_type, "dlc") == 0)) && (checkAppExist(titleid))) {
char rif_name[48];
char rif_path[MAX_PATH_LENGTH];
From 2637cd0c69c9b0cfb764c0b9d609bf7e059adb60 Mon Sep 17 00:00:00 2001
From: Li
Date: Fri, 16 Jun 2023 19:16:12 +1200
Subject: [PATCH 05/11] Fix if case
---
refresh.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/refresh.c b/refresh.c
index 4eb4067d..6ee043e4 100644
--- a/refresh.c
+++ b/refresh.c
@@ -200,7 +200,7 @@ int refreshNeeded(const char *app_path, const char* content_type) {
}
}
// license not needed to promote psp or psm contents
- else if((strcmp(content_type, "psm" == 0) || (strcmp(content_type, "psp" == 0)) && (checkAppExist(titleid))) {
+ else if((strcmp(content_type, "psm") == 0) || (strcmp(content_type, "psp") == 0) && (checkAppExist(titleid))) {
if(strcmp(content_type, "psp") == 0) {
// TODO: check __sce_ebootpbp
}
From c9d6f39e49408991ea0f10a82a9ce855f7b3dc27 Mon Sep 17 00:00:00 2001
From: Li
Date: Fri, 16 Jun 2023 19:17:47 +1200
Subject: [PATCH 06/11] fix contentid variable reference
---
refresh.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/refresh.c b/refresh.c
index 6ee043e4..926e1d56 100644
--- a/refresh.c
+++ b/refresh.c
@@ -409,7 +409,7 @@ void psp_callback(void* data, const char* dir, const char* subdir) {
snprintf(path, MAX_PATH_LENGTH, "%s/%s", dir, subdir);
if (refreshNeeded(path, "psp")){
removePath(PSP_TEMP, NULL);
- char content_id[0x30];
+ char contentid[0x30];
char game_folder[MAX_PATH_LENGTH];
char eboot_pbp[MAX_PATH_LENGTH];
From 210dc6ee652ebe0fb0b0d0c45d16c8ea0a4e4af0 Mon Sep 17 00:00:00 2001
From: Li
Date: Fri, 16 Jun 2023 20:59:27 +1200
Subject: [PATCH 07/11] Fix all build problems
---
main.h | 2 +-
package_installer.c | 14 +----
pbp.c | 25 ++++----
refresh.c | 142 ++++++++++++++++++++++++--------------------
4 files changed, 95 insertions(+), 88 deletions(-)
diff --git a/main.h b/main.h
index b080e657..280e6568 100644
--- a/main.h
+++ b/main.h
@@ -54,7 +54,7 @@
// VitaShell version major.minor
#define VITASHELL_VERSION_MAJOR 0x02
-#define VITASHELL_VERSION_MINOR 0x00
+#define VITASHELL_VERSION_MINOR 0x02
#define VITASHELL_VERSION ((VITASHELL_VERSION_MAJOR << 0x18) | (VITASHELL_VERSION_MINOR << 0x10))
diff --git a/package_installer.c b/package_installer.c
index 4b5e61ad..7fdee589 100644
--- a/package_installer.c
+++ b/package_installer.c
@@ -89,11 +89,8 @@ int promoteCma(const char *path, const char *titleid, int type) {
return res;
}
-// for some reason, psp only seems to work if you use PromotePkg, not PromotePkgWithRif.
-// and also only if you do an asyncronous promote
-int promotePsp(const char *path) {
+int promoteApp(const char *path) {
int res;
- int state = -1;
res = loadScePaf();
if (res < 0)
@@ -107,17 +104,10 @@ int promotePsp(const char *path) {
if (res < 0)
return res;
- res = scePromoterUtilityPromotePkg(path, 0);
+ res = scePromoterUtilityPromotePkgWithRif(path, 1);
if (res < 0)
return res;
- // wait for promote to finish
- while(state != 0){ scePromoterUtilityGetState(&state); };
- scePromoterUtilityGetResult(&res);
-
- if(res < 0)
- return res;
-
res = scePromoterUtilityExit();
if (res < 0)
return res;
diff --git a/pbp.c b/pbp.c
index af1f3ce8..6281d4b7 100644
--- a/pbp.c
+++ b/pbp.c
@@ -28,9 +28,9 @@ int read_content_id_data_psp(SceUID pbp_fd, char* content_id) {
if(read_sz < sizeof(DataPspHeader)) return 0;
// copy the content id from data.psp header to this content_id buffer
- strncpy(content_id, data_psp_header.content_id, sizeof(npumdimg_header.content_id));
+ strncpy(content_id, data_psp_header.content_id, sizeof(data_psp_header.content_id));
- return 0;
+ return (strlen(content_id) == 36);
}
int read_content_id_npumdimg(SceUID pbp_fd, char* content_id) {
@@ -43,7 +43,7 @@ int read_content_id_npumdimg(SceUID pbp_fd, char* content_id) {
// copy the content id from npumdimg_header to this content_id buffer
strncpy(content_id, npumdimg_header.content_id, sizeof(npumdimg_header.content_id));
- return 1;
+ return (strlen(content_id) == 36);
}
int read_data_psar_header(SceUID pbp_fd, char* content_id) {
@@ -60,15 +60,18 @@ int read_data_psar_header(SceUID pbp_fd, char* content_id) {
read_sz = sceIoRead(pbp_fd, data_psar_magic, sizeof(data_psar_magic));
if(read_sz < sizeof(data_psar_magic)) return 0;
- if(memcmp(data_psar_magic, "NPUMDIMG") == 0) { // psp
+ if(memcmp(data_psar_magic, "NPUMDIMG", 0x8) == 0) { // psp
// seek to start of npumdimg
sceIoLseek(pbp_fd, pbp_header.data_psar_ptr, SCE_SEEK_SET);
// read content_id from npumdimg
- return read_content_id_data_psp(pbp_fd, &pbp_header, content_id);
+ return read_content_id_npumdimg(pbp_fd, content_id);
}
- else if(memcmp(data_psar_magic, "PSISOIMG") == 0 || memcmp(data_psar_magic, "PSTITLEI") == 0) { // ps1
+ else if(memcmp(data_psar_magic, "PSISOIMG", 0x8) == 0 || memcmp(data_psar_magic, "PSTITLEI", 0x8) == 0) { // ps1
sceIoLseek(pbp_fd, pbp_header.data_psp_ptr, SCE_SEEK_SET);
+
+ // read content_id from data.psp
+ return read_content_id_data_psp(pbp_fd, content_id);
}
else{ // update package, homebrew, etc,
return 0;
@@ -92,7 +95,7 @@ int read_sfo(SceUID pbp_fd, void** param_sfo_buffer){
if(*param_sfo_buffer == NULL) return 0;
// seek to the start of param.sfo
- sceIoLseek(pbp_header.param_sfo_ptr, SCE_SEEK_SET);
+ sceIoLseek(pbp_fd, pbp_header.param_sfo_ptr, SCE_SEEK_SET);
// read the param.sfo file
read_sz = sceIoRead(pbp_fd, *param_sfo_buffer, param_sfo_size);
@@ -105,7 +108,7 @@ int read_sfo(SceUID pbp_fd, void** param_sfo_buffer){
return param_sfo_size;
}
-int get_pbp_sfo(const char pbp_file, void** param_sfo_buffer) {
+int get_pbp_sfo(const char* pbp_file, void** param_sfo_buffer) {
PbpHeader pbp_header;
if(param_sfo_buffer == NULL) return;
@@ -114,7 +117,7 @@ int get_pbp_sfo(const char pbp_file, void** param_sfo_buffer) {
int res = 0;
if(pbp_file != NULL) {
- SceUID pbp_fd = sceIoOpen(pbp_file);
+ SceUID pbp_fd = sceIoOpen(pbp_file, SCE_O_RDONLY, 0777);
if(pbp_fd < 0) return NULL;
// read param.sfo from pbp
@@ -130,9 +133,9 @@ int get_pbp_content_id(const char* pbp_file, char* content_id) {
int res = 0;
if(pbp_file != NULL && content_id != NULL) {
- SceUID pbp_fd = sceIoOpen(pbp_file);
+ SceUID pbp_fd = sceIoOpen(pbp_file, SCE_O_RDONLY, 0777);
if(pbp_fd < 0) return 0;
- res = read_content_id(pbp_fd, content_id);
+ res = read_data_psar_header(pbp_fd, content_id);
// check the content id is valid
if(res) {
diff --git a/refresh.c b/refresh.c
index 926e1d56..1a46af10 100644
--- a/refresh.c
+++ b/refresh.c
@@ -90,7 +90,7 @@ int refreshNeeded(const char *app_path, const char* content_type) {
free(cidFile);
}
- else if(strcmp(content_type, "psp")) {
+ else if(strcmp(content_type, "psp") == 0) {
// read eboot.pbp
char ebootpbp_path[MAX_PATH_LENGTH];
@@ -99,26 +99,21 @@ int refreshNeeded(const char *app_path, const char* content_type) {
memset(contentid,0,50);
memset(appver,0,8);
- // the vita actually uses the folder name as the title id in PSP case
- // this is also important for e.g cloning trick
- char* app_directory = getFilename(app_path);
- if(TITLEID_FMT_CHECK(app_directory)){
- if(app_directory != NULL)
- free(app_directory);
-
- return 0;
- }
-
- strncpy(titleid, app_directory, 12);
- free(app_directory);
-
+ // the vita actually uses the folder name as the title id in PSP case
+ // this is also important for e.g cloning trick
+ char* app_directory = getFilename(app_path);
+ if(TITLEID_FMT_CHECK(app_directory)){
+ if(app_directory != NULL) free(app_directory);
+ return 0;
+ }
+ strncpy(titleid, app_directory, 12);
+ free(app_directory);
snprintf(ebootpbp_path, MAX_PATH_LENGTH, "%s/EBOOT.PBP", app_path);
-
+
// Get content_id
if(!get_pbp_content_id(ebootpbp_path, contentid))
return 0;
-
// Get param.sfo
void *sfo_buffer = NULL;
int sfo_size = get_pbp_sfo(ebootpbp_path, &sfo_buffer);
@@ -127,6 +122,10 @@ int refreshNeeded(const char *app_path, const char* content_type) {
getSfoString(sfo_buffer, "APP_VER", appver, sizeof(appver));
+ // ps1 do not have APP_VER
+ if(strcmp(appver, "") == 0)
+ strcpy(appver, "01.00");
+
free(sfo_buffer);
}
else {
@@ -407,54 +406,69 @@ void psp_callback(void* data, const char* dir, const char* subdir) {
if (refresh_data->refresh_pass) {
snprintf(path, MAX_PATH_LENGTH, "%s/%s", dir, subdir);
- if (refreshNeeded(path, "psp")){
- removePath(PSP_TEMP, NULL);
- char contentid[0x30];
- char game_folder[MAX_PATH_LENGTH];
-
- char eboot_pbp[MAX_PATH_LENGTH];
- char license_rif[MAX_PATH_LENGTH];
-
- // get path to executables
- snprintf(game_folder, MAX_PATH_LENGTH, "%s/PSP/GAME/%s", path, subdir);
- snprintf(eboot_pbp, MAX_PATH_LENGTH, "%s/EBOOT.PBP", game_folder, eboot_pbp);
-
- if(get_pbp_content_id(eboot_pbp, contentid)){
- // create directories
- char promote_psp_folder[MAX_PATH_LENGTH];
- char promote_psp_game_folder[MAX_PATH_LENGTH];
- char promote_psp_license_folder[MAX_PATH_LENGTH];
-
- char promote_license_rif[MAX_PATH_LENGTH];
- char promote_game_folder[MAX_PATH_LENGTH];
-
- snprintf(promote_psp_folder, "%s/PSP", PSP_TEMP);
- snprintf(promote_psp_game_folder, "%s/PSP/GAME", PSP_TEMP);
- snprintf(promote_psp_license_folder, "%s/PSP/LICENSE", PSP_TEMP);
-
- snprintf(promote_license_rif, "%s/PSP/LICENSE/%s.rif", PSP_TEMP, contentid);
- snprintf(promote_game_folder, "%s/PSP/GAME/%s", PSP_TEMP, subdir);
-
- // get current rif location
- snprintf(license_rif, MAX_PATH_LENGTH, "s/PSP/LICENSE/%s.rif", path, contentid);
-
- // create the promote directories
- sceIoMkdir(promote_psp_folder, 0006);
- sceIoMkdir(promote_psp_game_folder, 0006);
- sceIoMkdir(promote_psp_license_folder, 0006);
-
- // copy the rif to the promote location
- copyFile(license_rif, promote_license_rif, NULL);
- sceIoRename(path, promote_game_folder);
-
- // finally call promote
- if (promoteCma(PSP_TEMP, subdir, SCE_PKG_TYPE_VITA) == 0)
- refresh_data->refreshed++;
- else
- sceIoRename(promote_game_folder, path); // Restore folder on error
- removePath(PSP_TEMP, NULL); // delete what was created
- }
- }
+ if (refreshNeeded(path, "psp")) {
+ char contentid[0x30];
+
+ char sce_ebootpbp[MAX_PATH_LENGTH];
+ char eboot_pbp[MAX_PATH_LENGTH];
+ char license_rif[MAX_PATH_LENGTH];
+
+ snprintf(eboot_pbp, MAX_PATH_LENGTH, "%s/EBOOT.PBP", path);
+ snprintf(sce_ebootpbp, MAX_PATH_LENGTH, "%s/__sce_ebootpbp", path);
+
+ // cache current __sce_ebootpbp signature file
+ void* sce_ebootpbp_sig_data = NULL;
+ int sce_ebootpbp_sz = allocateReadFile(sce_ebootpbp, &sce_ebootpbp_sig_data);
+
+ if(get_pbp_content_id(eboot_pbp, contentid)) {
+ // create directories
+ char promote_psp_folder[MAX_PATH_LENGTH];
+ char promote_psp_game_folder[MAX_PATH_LENGTH];
+ char promote_psp_license_folder[MAX_PATH_LENGTH];
+
+ char promote_license_rif[MAX_PATH_LENGTH];
+ char promote_game_folder[MAX_PATH_LENGTH];
+
+ snprintf(promote_psp_folder, MAX_PATH_LENGTH, "%s/PSP", PSP_TEMP);
+ snprintf(promote_psp_game_folder, MAX_PATH_LENGTH, "%s/PSP/GAME", PSP_TEMP);
+ snprintf(promote_psp_license_folder, MAX_PATH_LENGTH, "%s/PSP/LICENSE", PSP_TEMP);
+
+ snprintf(promote_license_rif, MAX_PATH_LENGTH, "%s/PSP/LICENSE/%s.rif", PSP_TEMP, contentid);
+ snprintf(promote_game_folder, MAX_PATH_LENGTH, "%s/PSP/GAME/%s", PSP_TEMP, subdir);
+
+ // get current rif location
+ snprintf(license_rif, MAX_PATH_LENGTH, "ux0:/pspemu/PSP/LICENSE/%s.rif", contentid);
+
+ // create the promote directories
+ sceIoMkdir(promote_psp_folder, 0006);
+ sceIoMkdir(promote_psp_game_folder, 0006);
+ sceIoMkdir(promote_psp_license_folder, 0006);
+
+ // copy the rif to the promote location
+ copyFile(license_rif, promote_license_rif, NULL);
+ sceIoRename(path, promote_game_folder);
+
+ // promote will fail if __sce_ebootpbp signature file is invalid (or for another account)
+ // the thing is, if you promote without this file present
+ // the vita will just generate a new one for your current account
+ // so here we force regeneration of it ..
+ sceIoRemove(sce_ebootpbp);
+
+ if (promoteCma(PSP_TEMP, subdir, SCE_PKG_TYPE_VITA) == 0) {
+ refresh_data->refreshed++;
+ }
+ else {
+ sceIoRename(promote_game_folder, path); // Restore folder on error
+ if(sce_ebootpbp_sz > 0)
+ WriteFile(sce_ebootpbp, sce_ebootpbp_sig_data, sce_ebootpbp_sz); // Restore __sce_ebootpbp
+
+ removePath(PSP_TEMP, NULL); // delete what was created
+ }
+ }
+
+ if(sce_ebootpbp_sig_data != NULL)
+ free(sce_ebootpbp_sig_data);
+ }
SetProgress(++refresh_data->processed, refresh_data->count);
} else {
refresh_data->count++;
From 869f77ca7616c0d3fe619ddba8d78c332a08b225 Mon Sep 17 00:00:00 2001
From: Li
Date: Sat, 17 Jun 2023 23:32:54 +1200
Subject: [PATCH 08/11] Regenerate __sce_ebootpbp and __sce_discinfo
---
CMakeLists.txt | 1 +
pbp.c | 153 ++++++++++++++++++++++++++++++++++++++++-------
pbp.h | 10 +++-
refresh.c | 137 +++++++++++++++++++++++++++++-------------
sha256.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++
sha256.h | 34 +++++++++++
6 files changed, 432 insertions(+), 61 deletions(-)
create mode 100644 sha256.c
create mode 100644 sha256.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d2b2f8e1..98ccc3ef 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -125,6 +125,7 @@ add_executable(VitaShell
utils.c
elf.c
sha1.c
+ sha256.c
minizip/zip.c
minizip/ioapi.c
bm.c
diff --git a/pbp.c b/pbp.c
index 6281d4b7..32038c02 100644
--- a/pbp.c
+++ b/pbp.c
@@ -15,7 +15,8 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-
+#include
+#include "sha256.h"
#include "main.h"
#include "pbp.h"
#include "sfo.h"
@@ -28,7 +29,7 @@ int read_content_id_data_psp(SceUID pbp_fd, char* content_id) {
if(read_sz < sizeof(DataPspHeader)) return 0;
// copy the content id from data.psp header to this content_id buffer
- strncpy(content_id, data_psp_header.content_id, sizeof(data_psp_header.content_id));
+ strncpy(content_id, data_psp_header.content_id, 0x30);
return (strlen(content_id) == 36);
}
@@ -41,43 +42,60 @@ int read_content_id_npumdimg(SceUID pbp_fd, char* content_id) {
if(read_sz < sizeof(NpUmdImgHeader)) return 0;
// copy the content id from npumdimg_header to this content_id buffer
- strncpy(content_id, npumdimg_header.content_id, sizeof(npumdimg_header.content_id));
+ strncpy(content_id, npumdimg_header.content_id, 0x30);
return (strlen(content_id) == 36);
}
-int read_data_psar_header(SceUID pbp_fd, char* content_id) {
- PbpHeader pbp_header;
+int determine_pbp_type(SceUID pbp_fd, PbpHeader* pbp_header) {
char data_psar_magic[0x8];
- int read_sz = sceIoRead(pbp_fd, &pbp_header, sizeof(PbpHeader));
+ int read_sz = sceIoRead(pbp_fd, pbp_header, sizeof(PbpHeader));
if(read_sz < sizeof(PbpHeader)) return 0;
// seek to data.psar
- sceIoLseek(pbp_fd, pbp_header.data_psar_ptr, SCE_SEEK_SET);
+ sceIoLseek(pbp_fd, pbp_header->data_psar_ptr, SCE_SEEK_SET);
// read magic value to determine pbp type
read_sz = sceIoRead(pbp_fd, data_psar_magic, sizeof(data_psar_magic));
if(read_sz < sizeof(data_psar_magic)) return 0;
- if(memcmp(data_psar_magic, "NPUMDIMG", 0x8) == 0) { // psp
+ if(memcmp(data_psar_magic, "NPUMDIMG", 0x8) == 0) { // psp
+ return PBP_TYPE_NPUMDIMG;
+ }
+ else if(memcmp(data_psar_magic, "PSISOIMG", 0x8) == 0) { // ps1 single disc
+ return PBP_TYPE_PSISOIMG;
+ }
+ else if(memcmp(data_psar_magic, "PSTITLEI", 0x8) == 0) { // ps1 multi disc
+ return PBP_TYPE_PSTITLEIMG;
+ }
+ else{ // update package, homebrew, etc,
+ return PBP_TYPE_UNKNOWN;
+ }
+
+ if(read_sz < sizeof(PbpHeader)) return PBP_TYPE_UNKNOWN;
+}
+
+int read_data_psar_header(SceUID pbp_fd, char* content_id) {
+ PbpHeader pbp_header;
+ int pbp_type = determine_pbp_type(pbp_fd, &pbp_header);
+ if(pbp_type == PBP_TYPE_NPUMDIMG) {
// seek to start of npumdimg
sceIoLseek(pbp_fd, pbp_header.data_psar_ptr, SCE_SEEK_SET);
// read content_id from npumdimg
return read_content_id_npumdimg(pbp_fd, content_id);
}
- else if(memcmp(data_psar_magic, "PSISOIMG", 0x8) == 0 || memcmp(data_psar_magic, "PSTITLEI", 0x8) == 0) { // ps1
+ else if(pbp_type == PBP_TYPE_PSISOIMG || pbp_type == PBP_TYPE_PSTITLEIMG) {
+ // seek to start of data.psp
sceIoLseek(pbp_fd, pbp_header.data_psp_ptr, SCE_SEEK_SET);
-
- // read content_id from data.psp
- return read_content_id_data_psp(pbp_fd, content_id);
+
+ // read content_id from data.psp
+ return read_content_id_data_psp(pbp_fd, content_id);
}
- else{ // update package, homebrew, etc,
+ else {
return 0;
- }
-
- if(read_sz < sizeof(PbpHeader)) return 0;
+ }
}
int read_sfo(SceUID pbp_fd, void** param_sfo_buffer){
@@ -100,9 +118,9 @@ int read_sfo(SceUID pbp_fd, void** param_sfo_buffer){
// read the param.sfo file
read_sz = sceIoRead(pbp_fd, *param_sfo_buffer, param_sfo_size);
if(read_sz < param_sfo_size) {
- free(*param_sfo_buffer);
- *param_sfo_buffer = NULL;
- return 0;
+ free(*param_sfo_buffer);
+ *param_sfo_buffer = NULL;
+ return 0;
}
return param_sfo_size;
@@ -111,7 +129,7 @@ int read_sfo(SceUID pbp_fd, void** param_sfo_buffer){
int get_pbp_sfo(const char* pbp_file, void** param_sfo_buffer) {
PbpHeader pbp_header;
- if(param_sfo_buffer == NULL) return;
+ if(param_sfo_buffer == NULL) return NULL;
*param_sfo_buffer = NULL;
int res = 0;
@@ -148,4 +166,99 @@ int get_pbp_content_id(const char* pbp_file, char* content_id) {
return res;
+}
+
+int hash_pbp(SceUID pbp_fd, char* out_hash) {
+ char wbuf[0x7c0];
+
+ // seek to the start of the eboot.pbp
+ sceIoLseek(pbp_fd, 0x00, SCE_SEEK_SET);
+
+ // inital read
+ int read_sz = sceIoRead(pbp_fd, wbuf, sizeof(wbuf));
+ if(read_sz < sizeof(PbpHeader)) return read_sz;
+
+ // calculate data hash size
+ size_t hash_sz = (((PbpHeader*)wbuf)->data_psar_ptr + 0x1C0000);
+
+ // initalize hash
+ SHA256_CTX ctx;
+ sha256_init(&ctx);
+
+ // first hash
+ sha256_update(&ctx, wbuf, read_sz);
+ size_t total_hashed = read_sz;
+
+ do {
+ read_sz = sceIoRead(pbp_fd, wbuf, sizeof(wbuf));
+
+ if((total_hashed + read_sz) > hash_sz)
+ read_sz = (hash_sz - total_hashed); // calculate remaining
+
+ sha256_update(&ctx, wbuf, read_sz);
+ total_hashed += read_sz;
+
+ if(read_sz < sizeof(wbuf)) // treat EOF as complete
+ total_hashed = hash_sz;
+
+ } while(total_hashed < hash_sz);
+
+ sha256_final(&ctx, out_hash);
+
+ return 1;
+}
+int _vshNpDrmEbootSigGenMultiDisc(const char *eboot_pbp_path, const void *sce_discinfo, void *eboot_signature, int *sw_version);
+
+int gen_sce_ebootpbp(const char* pbp_file, const char* psp_game_folder){
+ int res = 0;
+
+ char pbp_hash[0x20];
+ char sce_ebootpbp[0x200];
+ int sw_version = 0;
+ PbpHeader pbp_header;
+
+ void* sony_sce_discinfo = NULL;
+ int sony_sce_discinfo_sz = allocateReadFile("vs0:/NPXS10028/__sce_discinfo", &sony_sce_discinfo);
+
+ char sce_ebootpbp_path[MAX_PATH_LENGTH];
+ char sce_discinfo_path[MAX_PATH_LENGTH];
+
+ snprintf(sce_ebootpbp_path, MAX_PATH_LENGTH, "%s/__sce_ebootpbp", psp_game_folder);
+ snprintf(sce_discinfo_path, MAX_PATH_LENGTH, "%s/__sce_discinfo", psp_game_folder);
+
+ memset(pbp_hash, 0x00, sizeof(pbp_hash));
+ memset(sce_ebootpbp, 0x00, sizeof(pbp_hash));
+ sceClibPrintf("pbp_file: %s, psp_game_folder: %s\n", pbp_file, psp_game_folder);
+ if(pbp_file != NULL) {
+ SceUID pbp_fd = sceIoOpen(pbp_file, SCE_O_RDONLY, 0777);
+ if(pbp_fd < 0) return pbp_fd;
+
+ int pbp_type = determine_pbp_type(pbp_fd, &pbp_header); // determine pbp header
+ sceClibPrintf("pbp_type: %x\n", pbp_type);
+ if(pbp_type == PBP_TYPE_UNKNOWN) return res;
+
+ res = hash_pbp(pbp_fd, pbp_hash); // hash eboot.pbp
+
+ sceIoClose(pbp_fd);
+
+ // actually generate the __sce_ebootpbp or __sce_discinfo
+ if(pbp_type == PBP_TYPE_NPUMDIMG)
+ res = _vshNpDrmEbootSigGenPsp(pbp_file, pbp_hash, sce_ebootpbp, &sw_version);
+ else if(pbp_type == PBP_TYPE_PSISOIMG)
+ res = _vshNpDrmEbootSigGenPs1(pbp_file, pbp_hash, sce_ebootpbp, &sw_version);
+ else if(pbp_type == PBP_TYPE_PSTITLEIMG)
+ res = _vshNpDrmEbootSigGenMultiDisc(pbp_file, sony_sce_discinfo, sce_ebootpbp, &sw_version);
+
+ if(res >= 0) { // write __sce_ebootpbp
+ if(pbp_type == PBP_TYPE_NPUMDIMG || pbp_type == PBP_TYPE_PSISOIMG)
+ res = WriteFile(sce_ebootpbp_path, sce_ebootpbp, 0x200);
+ else if(pbp_type == PBP_TYPE_PSTITLEIMG)
+ res = WriteFile(sce_discinfo_path, sce_ebootpbp, 0x100);
+ }
+ }
+
+ if(sony_sce_discinfo != NULL)
+ free(sony_sce_discinfo);
+
+ return res;
}
\ No newline at end of file
diff --git a/pbp.h b/pbp.h
index 211d43e6..fdb94286 100644
--- a/pbp.h
+++ b/pbp.h
@@ -19,6 +19,14 @@
#ifndef __PBP_H__
#define __PBP_H__
+
+typedef enum PbpType{
+ PBP_TYPE_NPUMDIMG = 0,
+ PBP_TYPE_PSISOIMG = 1,
+ PBP_TYPE_PSTITLEIMG = 2,
+ PBP_TYPE_UNKNOWN = 3
+} PbpType;
+
// for PSISOIMG and PSTITLEIMG contents
typedef struct DataPspHeader{
@@ -92,5 +100,5 @@ typedef struct PbpHeader
int get_pbp_sfo(const char* pbp_file, void** param_sfo_buffer);
int get_pbp_content_id(const char* pbp_file, char* content_id);
-
+int gen_sce_ebootpbp(const char* pbp_file, const char* psp_game_folder);
#endif
\ No newline at end of file
diff --git a/refresh.c b/refresh.c
index 1a46af10..d8ac901b 100644
--- a/refresh.c
+++ b/refresh.c
@@ -59,6 +59,8 @@ int isCustomHomebrew(const char* path) {
+int _vshNpDrmEbootSigVerify(const char *eboot_pbp_path, const char *eboot_signature, long* unk0);
+
int refreshNeeded(const char *app_path, const char* content_type) {
char appmeta_path[MAX_PATH_LENGTH];
char appmeta_param[MAX_PATH_LENGTH];
@@ -201,7 +203,42 @@ int refreshNeeded(const char *app_path, const char* content_type) {
// license not needed to promote psp or psm contents
else if((strcmp(content_type, "psm") == 0) || (strcmp(content_type, "psp") == 0) && (checkAppExist(titleid))) {
if(strcmp(content_type, "psp") == 0) {
- // TODO: check __sce_ebootpbp
+ char eboot_signature[0x200];
+
+ // get path to eboot.pbp
+ char ebootpbp_path[MAX_PATH_LENGTH];
+ snprintf(ebootpbp_path, MAX_PATH_LENGTH, "%s/EBOOT.PBP", app_path);
+
+ // get path to __sce_ebootpbp
+ char sce_ebootpbp[MAX_PATH_LENGTH];
+ snprintf(sce_ebootpbp, MAX_PATH_LENGTH, "%s/__sce_ebootpbp", app_path);
+
+ // get path to __sce_discinfo
+ char sce_discinfo[MAX_PATH_LENGTH];
+ snprintf(sce_discinfo, MAX_PATH_LENGTH, "%s/__sce_discinfo", app_path);
+
+ // check EBOOT.PBP exists
+ if(getFileSize(ebootpbp_path) < 0)
+ return 0;
+
+ int sce_ebootpbp_exist = (getFileSize(sce_ebootpbp) >= 0);
+ int sce_discinfo_exist = (getFileSize(sce_discinfo) >= 0);
+
+ // verify __sce_ebootpbp
+ if(sce_ebootpbp_exist) {
+ int read_sz = ReadFile(sce_ebootpbp, eboot_signature, 0x200);
+
+ long unk0;
+ int verify = _vshNpDrmEbootSigVerify(ebootpbp_path, eboot_signature, &unk0);
+
+ if(verify < 0) // if signature is invalid, then needs refresh
+ return 1;
+
+ return 0;
+ }
+ else if(!sce_discinfo_exist) { // _vshNpDrmEbootSigVerify doesn't seem to work on these ..
+ return 1;
+ }
}
return 0;
}
@@ -410,15 +447,22 @@ void psp_callback(void* data, const char* dir, const char* subdir) {
char contentid[0x30];
char sce_ebootpbp[MAX_PATH_LENGTH];
+ char sce_discinfo[MAX_PATH_LENGTH];
char eboot_pbp[MAX_PATH_LENGTH];
char license_rif[MAX_PATH_LENGTH];
snprintf(eboot_pbp, MAX_PATH_LENGTH, "%s/EBOOT.PBP", path);
snprintf(sce_ebootpbp, MAX_PATH_LENGTH, "%s/__sce_ebootpbp", path);
+ snprintf(sce_discinfo, MAX_PATH_LENGTH, "%s/__sce_discinfo", path);
// cache current __sce_ebootpbp signature file
void* sce_ebootpbp_sig_data = NULL;
int sce_ebootpbp_sz = allocateReadFile(sce_ebootpbp, &sce_ebootpbp_sig_data);
+
+ // cache current __sce_ebootpbp signature file
+ void* sce_discinfo_sig_data = NULL;
+ int sce_discinfo_sz = allocateReadFile(sce_discinfo, &sce_discinfo_sig_data);
+
if(get_pbp_content_id(eboot_pbp, contentid)) {
// create directories
@@ -449,25 +493,36 @@ void psp_callback(void* data, const char* dir, const char* subdir) {
sceIoRename(path, promote_game_folder);
// promote will fail if __sce_ebootpbp signature file is invalid (or for another account)
- // the thing is, if you promote without this file present
- // the vita will just generate a new one for your current account
- // so here we force regeneration of it ..
+ // so we have to generate a new one ..
sceIoRemove(sce_ebootpbp);
-
- if (promoteCma(PSP_TEMP, subdir, SCE_PKG_TYPE_VITA) == 0) {
+ sceIoRemove(sce_discinfo);
+
+ int ebootgen = gen_sce_ebootpbp(eboot_pbp, path);
+ if (promoteCma(PSP_TEMP, subdir, SCE_PKG_TYPE_VITA) == 0 && ebootgen == 0) {
refresh_data->refreshed++;
}
else {
sceIoRename(promote_game_folder, path); // Restore folder on error
+ removePath(PSP_TEMP, NULL); // delete what was created
+ }
+
+ // if eboot signature generation was unsuccessful, write original signature back
+ if(ebootgen < 0) {
if(sce_ebootpbp_sz > 0)
- WriteFile(sce_ebootpbp, sce_ebootpbp_sig_data, sce_ebootpbp_sz); // Restore __sce_ebootpbp
+ WriteFile(sce_ebootpbp, sce_ebootpbp_sig_data, sce_ebootpbp_sz); // Restore __sce_ebootpbp on error
- removePath(PSP_TEMP, NULL); // delete what was created
+ if(sce_discinfo_sz > 0)
+ WriteFile(sce_ebootpbp, sce_discinfo_sig_data, sce_discinfo_sz); // Restore __sce_discinfo on error
}
+
}
+
if(sce_ebootpbp_sig_data != NULL)
free(sce_ebootpbp_sig_data);
+
+ if(sce_discinfo_sig_data != NULL)
+ free(sce_ebootpbp_sig_data);
}
SetProgress(++refresh_data->processed, refresh_data->count);
} else {
@@ -483,40 +538,42 @@ void psm_callback(void* data, const char* dir, const char* subdir) {
if (refresh_data->refresh_pass) {
snprintf(path, MAX_PATH_LENGTH, "%s/%s", dir, subdir);
if (refreshNeeded(path, "psm")) {
- char contentid_path[MAX_PATH_LENGTH];
- snprintf(contentid_path, MAX_PATH_LENGTH, "%s/RW/System/content_id", path);
-
- char titleid[12];
- void *cidFile = NULL;
-
- // Initalize Bufer
- memset(titleid,0,12);
-
- // Get content id
- allocateReadFile(contentid_path, &cidFile);
+ char contentid_path[MAX_PATH_LENGTH];
+ snprintf(contentid_path, MAX_PATH_LENGTH, "%s/RW/System/content_id", path);
+
+ char titleid[12];
+ void *cidFile = NULL;
+
+ // Initalize Bufer
+ memset(titleid,0,12);
- // Get title id from content id
- strncpy(titleid,cidFile+7,9);
-
- //free buffers
- free(cidFile);
-
-
- // Get promote path
- char promote_path[MAX_PATH_LENGTH];
- snprintf(promote_path,MAX_PATH_LENGTH,"%s/%s",PSM_TEMP, titleid);
-
- // Move the directory to temp for installation
- removePath(promote_path, NULL);
- sceIoRename(path, promote_path);
-
- // Finally call promote
- if (promoteCma(PSM_TEMP, titleid, SCE_PKG_TYPE_PSM) == 0)
- refresh_data->refreshed++;
- else
- sceIoRename(promote_path, path); // Restore folder on error
+ // Get content id
+ allocateReadFile(contentid_path, &cidFile);
+
+ // Get title id from content id
+ strncpy(titleid,cidFile+7,9);
+
+ //free buffers
+ free(cidFile);
+
+
+ // Get promote path
+ char promote_path[MAX_PATH_LENGTH];
+ snprintf(promote_path,MAX_PATH_LENGTH,"%s/%s",PSM_TEMP, titleid);
+
+ // Move the directory to temp for installation
+ removePath(promote_path, NULL);
+ sceIoRename(path, promote_path);
+
+ // Finally call promote
+ if (promoteCma(PSM_TEMP, titleid, SCE_PKG_TYPE_PSM) == 0) {
+ refresh_data->refreshed++;
+ }
+ else{
+ sceIoRename(promote_path, path); // Restore folder on error
+ }
+ SetProgress(++refresh_data->processed, refresh_data->count);
}
- SetProgress(++refresh_data->processed, refresh_data->count);
} else {
refresh_data->count++;
}
diff --git a/sha256.c b/sha256.c
new file mode 100644
index 00000000..eb9c5c07
--- /dev/null
+++ b/sha256.c
@@ -0,0 +1,158 @@
+/*********************************************************************
+* Filename: sha256.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Implementation of the SHA-256 hashing algorithm.
+ SHA-256 is one of the three algorithms in the SHA2
+ specification. The others, SHA-384 and SHA-512, are not
+ offered in this implementation.
+ Algorithm specification can be found here:
+ * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
+ This implementation uses little endian byte order.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include
+#include
+#include "sha256.h"
+
+/****************************** MACROS ******************************/
+#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
+#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
+
+#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
+#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
+#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
+#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
+#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
+
+/**************************** VARIABLES *****************************/
+static const WORD k[64] = {
+ 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
+ 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
+ 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
+ 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
+ 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
+ 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
+ 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
+ 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
+};
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
+{
+ WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
+
+ for (i = 0, j = 0; i < 16; ++i, j += 4)
+ m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
+ for ( ; i < 64; ++i)
+ m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
+
+ a = ctx->state[0];
+ b = ctx->state[1];
+ c = ctx->state[2];
+ d = ctx->state[3];
+ e = ctx->state[4];
+ f = ctx->state[5];
+ g = ctx->state[6];
+ h = ctx->state[7];
+
+ for (i = 0; i < 64; ++i) {
+ t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
+ t2 = EP0(a) + MAJ(a,b,c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + t1;
+ d = c;
+ c = b;
+ b = a;
+ a = t1 + t2;
+ }
+
+ ctx->state[0] += a;
+ ctx->state[1] += b;
+ ctx->state[2] += c;
+ ctx->state[3] += d;
+ ctx->state[4] += e;
+ ctx->state[5] += f;
+ ctx->state[6] += g;
+ ctx->state[7] += h;
+}
+
+void sha256_init(SHA256_CTX *ctx)
+{
+ ctx->datalen = 0;
+ ctx->bitlen = 0;
+ ctx->state[0] = 0x6a09e667;
+ ctx->state[1] = 0xbb67ae85;
+ ctx->state[2] = 0x3c6ef372;
+ ctx->state[3] = 0xa54ff53a;
+ ctx->state[4] = 0x510e527f;
+ ctx->state[5] = 0x9b05688c;
+ ctx->state[6] = 0x1f83d9ab;
+ ctx->state[7] = 0x5be0cd19;
+}
+
+void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
+{
+ WORD i;
+
+ for (i = 0; i < len; ++i) {
+ ctx->data[ctx->datalen] = data[i];
+ ctx->datalen++;
+ if (ctx->datalen == 64) {
+ sha256_transform(ctx, ctx->data);
+ ctx->bitlen += 512;
+ ctx->datalen = 0;
+ }
+ }
+}
+
+void sha256_final(SHA256_CTX *ctx, BYTE hash[])
+{
+ WORD i;
+
+ i = ctx->datalen;
+
+ // Pad whatever data is left in the buffer.
+ if (ctx->datalen < 56) {
+ ctx->data[i++] = 0x80;
+ while (i < 56)
+ ctx->data[i++] = 0x00;
+ }
+ else {
+ ctx->data[i++] = 0x80;
+ while (i < 64)
+ ctx->data[i++] = 0x00;
+ sha256_transform(ctx, ctx->data);
+ memset(ctx->data, 0, 56);
+ }
+
+ // Append to the padding the total message's length in bits and transform.
+ ctx->bitlen += ctx->datalen * 8;
+ ctx->data[63] = ctx->bitlen;
+ ctx->data[62] = ctx->bitlen >> 8;
+ ctx->data[61] = ctx->bitlen >> 16;
+ ctx->data[60] = ctx->bitlen >> 24;
+ ctx->data[59] = ctx->bitlen >> 32;
+ ctx->data[58] = ctx->bitlen >> 40;
+ ctx->data[57] = ctx->bitlen >> 48;
+ ctx->data[56] = ctx->bitlen >> 56;
+ sha256_transform(ctx, ctx->data);
+
+ // Since this implementation uses little endian byte ordering and SHA uses big endian,
+ // reverse all the bytes when copying the final state to the output hash.
+ for (i = 0; i < 4; ++i) {
+ hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
+ }
+}
diff --git a/sha256.h b/sha256.h
new file mode 100644
index 00000000..7123a30d
--- /dev/null
+++ b/sha256.h
@@ -0,0 +1,34 @@
+/*********************************************************************
+* Filename: sha256.h
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Defines the API for the corresponding SHA1 implementation.
+*********************************************************************/
+
+#ifndef SHA256_H
+#define SHA256_H
+
+/*************************** HEADER FILES ***************************/
+#include
+
+/****************************** MACROS ******************************/
+#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
+
+/**************************** DATA TYPES ****************************/
+typedef unsigned char BYTE; // 8-bit byte
+typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
+
+typedef struct {
+ BYTE data[64];
+ WORD datalen;
+ unsigned long long bitlen;
+ WORD state[8];
+} SHA256_CTX;
+
+/*********************** FUNCTION DECLARATIONS **********************/
+void sha256_init(SHA256_CTX *ctx);
+void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len);
+void sha256_final(SHA256_CTX *ctx, BYTE hash[]);
+
+#endif // SHA256_H
From 3de5a385a9a6291a5641e263b42d314ba2c19c20 Mon Sep 17 00:00:00 2001
From: Li
Date: Sun, 18 Jun 2023 02:18:23 +1200
Subject: [PATCH 09/11] Fix PSP Promotion
---
pbp.c | 134 +++++++++++++++++++++++++++++-------------------------
pbp.h | 2 +-
refresh.c | 31 ++++++++-----
3 files changed, 93 insertions(+), 74 deletions(-)
diff --git a/pbp.c b/pbp.c
index 32038c02..d0e39079 100644
--- a/pbp.c
+++ b/pbp.c
@@ -126,48 +126,6 @@ int read_sfo(SceUID pbp_fd, void** param_sfo_buffer){
return param_sfo_size;
}
-int get_pbp_sfo(const char* pbp_file, void** param_sfo_buffer) {
- PbpHeader pbp_header;
-
- if(param_sfo_buffer == NULL) return NULL;
- *param_sfo_buffer = NULL;
-
- int res = 0;
-
- if(pbp_file != NULL) {
- SceUID pbp_fd = sceIoOpen(pbp_file, SCE_O_RDONLY, 0777);
- if(pbp_fd < 0) return NULL;
-
- // read param.sfo from pbp
- res = read_sfo(pbp_fd, param_sfo_buffer);
-
- sceIoClose(pbp_fd);
- }
-
- return res;
-}
-
-int get_pbp_content_id(const char* pbp_file, char* content_id) {
- int res = 0;
-
- if(pbp_file != NULL && content_id != NULL) {
- SceUID pbp_fd = sceIoOpen(pbp_file, SCE_O_RDONLY, 0777);
- if(pbp_fd < 0) return 0;
- res = read_data_psar_header(pbp_fd, content_id);
-
- // check the content id is valid
- if(res) {
- int content_id_len = strnlen(content_id, 0x30);
- if(content_id_len != 0x24) res = 0;
- }
-
- sceIoClose(pbp_fd);
- }
-
- return res;
-
-}
-
int hash_pbp(SceUID pbp_fd, char* out_hash) {
char wbuf[0x7c0];
@@ -207,9 +165,51 @@ int hash_pbp(SceUID pbp_fd, char* out_hash) {
return 1;
}
-int _vshNpDrmEbootSigGenMultiDisc(const char *eboot_pbp_path, const void *sce_discinfo, void *eboot_signature, int *sw_version);
-int gen_sce_ebootpbp(const char* pbp_file, const char* psp_game_folder){
+
+int get_pbp_sfo(const char* pbp_file, void** param_sfo_buffer) {
+ PbpHeader pbp_header;
+
+ if(param_sfo_buffer == NULL) return NULL;
+ *param_sfo_buffer = NULL;
+
+ int res = 0;
+
+ if(pbp_file != NULL) {
+ SceUID pbp_fd = sceIoOpen(pbp_file, SCE_O_RDONLY, 0);
+ if(pbp_fd < 0) return NULL;
+
+ // read param.sfo from pbp
+ res = read_sfo(pbp_fd, param_sfo_buffer);
+
+ sceIoClose(pbp_fd);
+ }
+
+ return res;
+}
+
+int get_pbp_content_id(const char* pbp_file, char* content_id) {
+ int res = 0;
+
+ if(pbp_file != NULL && content_id != NULL) {
+ SceUID pbp_fd = sceIoOpen(pbp_file, SCE_O_RDONLY, 0);
+ if(pbp_fd < 0) return 0;
+ res = read_data_psar_header(pbp_fd, content_id);
+
+ // check the content id is valid
+ if(res) {
+ int content_id_len = strnlen(content_id, 0x30);
+ if(content_id_len != 0x24) res = 0;
+ }
+
+ sceIoClose(pbp_fd);
+ }
+
+ return res;
+
+}
+
+int gen_sce_ebootpbp(const char* psp_game_folder){
int res = 0;
char pbp_hash[0x20];
@@ -219,23 +219,34 @@ int gen_sce_ebootpbp(const char* pbp_file, const char* psp_game_folder){
void* sony_sce_discinfo = NULL;
int sony_sce_discinfo_sz = allocateReadFile("vs0:/NPXS10028/__sce_discinfo", &sony_sce_discinfo);
-
- char sce_ebootpbp_path[MAX_PATH_LENGTH];
- char sce_discinfo_path[MAX_PATH_LENGTH];
-
- snprintf(sce_ebootpbp_path, MAX_PATH_LENGTH, "%s/__sce_ebootpbp", psp_game_folder);
- snprintf(sce_discinfo_path, MAX_PATH_LENGTH, "%s/__sce_discinfo", psp_game_folder);
+ if(psp_game_folder != NULL) {
+ char ebootpbp_path[MAX_PATH_LENGTH];
+ char sce_ebootpbp_path[MAX_PATH_LENGTH];
+ char sce_discinfo_path[MAX_PATH_LENGTH];
+
+ snprintf(ebootpbp_path, MAX_PATH_LENGTH, "%s/EBOOT.PBP", psp_game_folder);
+ snprintf(sce_ebootpbp_path, MAX_PATH_LENGTH, "%s/__sce_ebootpbp", psp_game_folder);
+ snprintf(sce_discinfo_path, MAX_PATH_LENGTH, "%s/__sce_discinfo", psp_game_folder);
- memset(pbp_hash, 0x00, sizeof(pbp_hash));
- memset(sce_ebootpbp, 0x00, sizeof(pbp_hash));
- sceClibPrintf("pbp_file: %s, psp_game_folder: %s\n", pbp_file, psp_game_folder);
- if(pbp_file != NULL) {
- SceUID pbp_fd = sceIoOpen(pbp_file, SCE_O_RDONLY, 0777);
- if(pbp_fd < 0) return pbp_fd;
+ memset(pbp_hash, 0x00, sizeof(pbp_hash));
+ memset(sce_ebootpbp, 0x00, sizeof(pbp_hash));
+
+ SceUID pbp_fd = sceIoOpen(ebootpbp_path, SCE_O_RDONLY, 0);
+
+ if(pbp_fd < 0) {
+ if(sony_sce_discinfo != NULL)
+ free(sony_sce_discinfo);
+ return pbp_fd;
+ }
int pbp_type = determine_pbp_type(pbp_fd, &pbp_header); // determine pbp header
- sceClibPrintf("pbp_type: %x\n", pbp_type);
- if(pbp_type == PBP_TYPE_UNKNOWN) return res;
+
+ if(pbp_type == PBP_TYPE_UNKNOWN){
+ if(sony_sce_discinfo != NULL)
+ free(sony_sce_discinfo);
+ sceIoClose(pbp_fd);
+ return res;
+ }
res = hash_pbp(pbp_fd, pbp_hash); // hash eboot.pbp
@@ -243,12 +254,11 @@ int gen_sce_ebootpbp(const char* pbp_file, const char* psp_game_folder){
// actually generate the __sce_ebootpbp or __sce_discinfo
if(pbp_type == PBP_TYPE_NPUMDIMG)
- res = _vshNpDrmEbootSigGenPsp(pbp_file, pbp_hash, sce_ebootpbp, &sw_version);
+ res = _vshNpDrmEbootSigGenPsp(ebootpbp_path, pbp_hash, sce_ebootpbp, &sw_version);
else if(pbp_type == PBP_TYPE_PSISOIMG)
- res = _vshNpDrmEbootSigGenPs1(pbp_file, pbp_hash, sce_ebootpbp, &sw_version);
+ res = _vshNpDrmEbootSigGenPs1(ebootpbp_path, pbp_hash, sce_ebootpbp, &sw_version);
else if(pbp_type == PBP_TYPE_PSTITLEIMG)
- res = _vshNpDrmEbootSigGenMultiDisc(pbp_file, sony_sce_discinfo, sce_ebootpbp, &sw_version);
-
+ res = _vshNpDrmEbootSigGenMultiDisc(ebootpbp_path, sony_sce_discinfo, sce_ebootpbp, &sw_version);
if(res >= 0) { // write __sce_ebootpbp
if(pbp_type == PBP_TYPE_NPUMDIMG || pbp_type == PBP_TYPE_PSISOIMG)
res = WriteFile(sce_ebootpbp_path, sce_ebootpbp, 0x200);
diff --git a/pbp.h b/pbp.h
index fdb94286..8c118980 100644
--- a/pbp.h
+++ b/pbp.h
@@ -100,5 +100,5 @@ typedef struct PbpHeader
int get_pbp_sfo(const char* pbp_file, void** param_sfo_buffer);
int get_pbp_content_id(const char* pbp_file, char* content_id);
-int gen_sce_ebootpbp(const char* pbp_file, const char* psp_game_folder);
+int gen_sce_ebootpbp(const char* psp_game_folder);
#endif
\ No newline at end of file
diff --git a/refresh.c b/refresh.c
index d8ac901b..708c3132 100644
--- a/refresh.c
+++ b/refresh.c
@@ -19,6 +19,7 @@
along with this program. If not, see .
*/
+#include
#include "main.h"
#include "init.h"
#include "io_process.h"
@@ -57,10 +58,6 @@ int isCustomHomebrew(const char* path) {
return 1;
}
-
-
-int _vshNpDrmEbootSigVerify(const char *eboot_pbp_path, const char *eboot_signature, long* unk0);
-
int refreshNeeded(const char *app_path, const char* content_type) {
char appmeta_path[MAX_PATH_LENGTH];
char appmeta_param[MAX_PATH_LENGTH];
@@ -489,16 +486,29 @@ void psp_callback(void* data, const char* dir, const char* subdir) {
sceIoMkdir(promote_psp_license_folder, 0006);
// copy the rif to the promote location
- copyFile(license_rif, promote_license_rif, NULL);
- sceIoRename(path, promote_game_folder);
+ int res = copyFile(license_rif, promote_license_rif, NULL);
+ if(res < 0) {
+ // generate fake psp license
+ SceNpDrmLicense license;
+ memset(&license, 0x00, sizeof(SceNpDrmLicense));
+ license.account_id = 0x0123456789ABCDEFLL;
+ memset(license.ecdsa_signature, 0xFF, 0x28);
+ strncpy(license.content_id, contentid, 0x30);
+ WriteFile(promote_license_rif, &license, offsetof(SceNpDrmLicense, flags));
+ }
// promote will fail if __sce_ebootpbp signature file is invalid (or for another account)
// so we have to generate a new one ..
sceIoRemove(sce_ebootpbp);
sceIoRemove(sce_discinfo);
- int ebootgen = gen_sce_ebootpbp(eboot_pbp, path);
- if (promoteCma(PSP_TEMP, subdir, SCE_PKG_TYPE_VITA) == 0 && ebootgen == 0) {
+ int eboot_gen = gen_sce_ebootpbp(path);
+
+ // move path to promote folder
+ sceIoRename(path, promote_game_folder);
+
+ int promote = promoteCma(PSP_TEMP, subdir, SCE_PKG_TYPE_VITA);
+ if (promote == 0 && eboot_gen >= 0) {
refresh_data->refreshed++;
}
else {
@@ -507,16 +517,15 @@ void psp_callback(void* data, const char* dir, const char* subdir) {
}
// if eboot signature generation was unsuccessful, write original signature back
- if(ebootgen < 0) {
+ if(eboot_gen < 0) {
if(sce_ebootpbp_sz > 0)
WriteFile(sce_ebootpbp, sce_ebootpbp_sig_data, sce_ebootpbp_sz); // Restore __sce_ebootpbp on error
if(sce_discinfo_sz > 0)
- WriteFile(sce_ebootpbp, sce_discinfo_sig_data, sce_discinfo_sz); // Restore __sce_discinfo on error
+ WriteFile(sce_discinfo, sce_discinfo_sig_data, sce_discinfo_sz); // Restore __sce_discinfo on error
}
}
-
if(sce_ebootpbp_sig_data != NULL)
free(sce_ebootpbp_sig_data);
From 5bf9313223489bf220bc1b9f5bf18bbb2996a9c4 Mon Sep 17 00:00:00 2001
From: Li
Date: Thu, 22 Jun 2023 02:36:20 +1200
Subject: [PATCH 10/11] FIx multiple install at once
---
CMakeLists.txt | 16 ++--
pbp.c | 38 ++++++---
pbp.h | 1 +
refresh.c | 216 ++++++++++++++++++++++++++++++-------------------
4 files changed, 168 insertions(+), 103 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 98ccc3ef..e0c3d09a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -22,10 +22,10 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c+ + 11 -fno-rtti -fno-exceptions")
set(VITA_MKSFOEX_FLAGS "${VITA_MKSFOEX_FLAGS} -d PARENTAL_LEVEL=1")
set(VITA_MAKE_FSELF_FLAGS "${VITA_MAKE_FSELF_FLAGS} -a 0x2808000000000000")
-#add_subdirectory(modules/kernel)
-#add_subdirectory(modules/user)
-#add_subdirectory(modules/patch)
-#add_subdirectory(modules/usbdevice)
+add_subdirectory(modules/kernel)
+add_subdirectory(modules/user)
+add_subdirectory(modules/patch)
+add_subdirectory(modules/usbdevice)
include_directories(
modules/kernel
@@ -150,10 +150,10 @@ add_executable(VitaShell
)
add_dependencies(VitaShell vitashell_user_stubs)
-add_dependencies(VitaShell kernel.skprx)
-add_dependencies(VitaShell user.suprx)
-add_dependencies(VitaShell patch.skprx)
-add_dependencies(VitaShell usbdevice.skprx)
+add_dependencies(VitaShell kernel.skprx-self)
+add_dependencies(VitaShell user.suprx-self)
+add_dependencies(VitaShell patch.skprx-self)
+add_dependencies(VitaShell usbdevice.skprx-self)
target_link_libraries(VitaShell
${CMAKE_CURRENT_BINARY_DIR}/modules/user/libVitaShellUser_stub_weak.a
diff --git a/pbp.c b/pbp.c
index d0e39079..aeaee031 100644
--- a/pbp.c
+++ b/pbp.c
@@ -188,12 +188,29 @@ int get_pbp_sfo(const char* pbp_file, void** param_sfo_buffer) {
return res;
}
+int get_pbp_type(const char* pbp_file) {
+ int res = 0;
+ PbpHeader pbp_header;
+ if(pbp_file != NULL) {
+ SceUID pbp_fd = sceIoOpen(pbp_file, SCE_O_RDONLY, 0);
+ if(pbp_fd < 0)
+ return 0;
+
+ res = determine_pbp_type(pbp_fd, &pbp_header);
+
+ sceIoClose(pbp_fd);
+ }
+
+ return res;
+}
+
int get_pbp_content_id(const char* pbp_file, char* content_id) {
int res = 0;
if(pbp_file != NULL && content_id != NULL) {
SceUID pbp_fd = sceIoOpen(pbp_file, SCE_O_RDONLY, 0);
- if(pbp_fd < 0) return 0;
+ if(pbp_fd < 0)
+ return 0;
res = read_data_psar_header(pbp_fd, content_id);
// check the content id is valid
@@ -233,20 +250,13 @@ int gen_sce_ebootpbp(const char* psp_game_folder){
SceUID pbp_fd = sceIoOpen(ebootpbp_path, SCE_O_RDONLY, 0);
- if(pbp_fd < 0) {
- if(sony_sce_discinfo != NULL)
- free(sony_sce_discinfo);
- return pbp_fd;
- }
+ if(pbp_fd < 0)
+ goto EXIT;
int pbp_type = determine_pbp_type(pbp_fd, &pbp_header); // determine pbp header
- if(pbp_type == PBP_TYPE_UNKNOWN){
- if(sony_sce_discinfo != NULL)
- free(sony_sce_discinfo);
- sceIoClose(pbp_fd);
- return res;
- }
+ if(pbp_type == PBP_TYPE_UNKNOWN)
+ goto EXIT;
res = hash_pbp(pbp_fd, pbp_hash); // hash eboot.pbp
@@ -266,7 +276,9 @@ int gen_sce_ebootpbp(const char* psp_game_folder){
res = WriteFile(sce_discinfo_path, sce_ebootpbp, 0x100);
}
}
-
+
+EXIT:
+
if(sony_sce_discinfo != NULL)
free(sony_sce_discinfo);
diff --git a/pbp.h b/pbp.h
index 8c118980..c984cc76 100644
--- a/pbp.h
+++ b/pbp.h
@@ -98,6 +98,7 @@ typedef struct PbpHeader
SceUInt32 data_psar_ptr;
} PbpHeader;
+int get_pbp_type(const char* pbp_file);
int get_pbp_sfo(const char* pbp_file, void** param_sfo_buffer);
int get_pbp_content_id(const char* pbp_file, char* content_id);
int gen_sce_ebootpbp(const char* psp_game_folder);
diff --git a/refresh.c b/refresh.c
index 708c3132..b857bdb1 100644
--- a/refresh.c
+++ b/refresh.c
@@ -97,6 +97,8 @@ int refreshNeeded(const char *app_path, const char* content_type) {
memset(titleid,0,12);
memset(contentid,0,50);
memset(appver,0,8);
+
+ snprintf(ebootpbp_path, MAX_PATH_LENGTH, "%s/EBOOT.PBP", app_path);
// the vita actually uses the folder name as the title id in PSP case
// this is also important for e.g cloning trick
@@ -108,7 +110,11 @@ int refreshNeeded(const char *app_path, const char* content_type) {
strncpy(titleid, app_directory, 12);
free(app_directory);
snprintf(ebootpbp_path, MAX_PATH_LENGTH, "%s/EBOOT.PBP", app_path);
-
+
+ int pbp_type = get_pbp_type(ebootpbp_path);
+ if(pbp_type == PBP_TYPE_UNKNOWN)
+ return 0;
+
// Get content_id
if(!get_pbp_content_id(ebootpbp_path, contentid))
return 0;
@@ -119,13 +125,21 @@ int refreshNeeded(const char *app_path, const char* content_type) {
if(sfo_size <= 0)
return 0;
+ // always use real disc id from param.sfo for PS1 titles because
+ // if a ps1 game is installed to the wrong directory, will give
+ // "Failed to open the memory card" error message.
+ if(pbp_type == PBP_TYPE_PSISOIMG || pbp_type == PBP_TYPE_PSTITLEIMG)
+ getSfoString(sfo_buffer, "DISC_ID", titleid, sizeof(titleid));
+
getSfoString(sfo_buffer, "APP_VER", appver, sizeof(appver));
-
+
// ps1 do not have APP_VER
if(strcmp(appver, "") == 0)
strcpy(appver, "01.00");
- free(sfo_buffer);
+ // free sfo_buffer
+ if(sfo_buffer != NULL)
+ free(sfo_buffer);
}
else {
// Read param.sfo
@@ -451,88 +465,124 @@ void psp_callback(void* data, const char* dir, const char* subdir) {
snprintf(eboot_pbp, MAX_PATH_LENGTH, "%s/EBOOT.PBP", path);
snprintf(sce_ebootpbp, MAX_PATH_LENGTH, "%s/__sce_ebootpbp", path);
snprintf(sce_discinfo, MAX_PATH_LENGTH, "%s/__sce_discinfo", path);
-
- // cache current __sce_ebootpbp signature file
- void* sce_ebootpbp_sig_data = NULL;
- int sce_ebootpbp_sz = allocateReadFile(sce_ebootpbp, &sce_ebootpbp_sig_data);
-
- // cache current __sce_ebootpbp signature file
- void* sce_discinfo_sig_data = NULL;
- int sce_discinfo_sz = allocateReadFile(sce_discinfo, &sce_discinfo_sig_data);
-
-
- if(get_pbp_content_id(eboot_pbp, contentid)) {
- // create directories
- char promote_psp_folder[MAX_PATH_LENGTH];
- char promote_psp_game_folder[MAX_PATH_LENGTH];
- char promote_psp_license_folder[MAX_PATH_LENGTH];
-
- char promote_license_rif[MAX_PATH_LENGTH];
- char promote_game_folder[MAX_PATH_LENGTH];
+
+ // get pbp type
+ int pbp_type = get_pbp_type(eboot_pbp);
+ if(pbp_type != PBP_TYPE_UNKNOWN) {
+
+ // cache current __sce_ebootpbp signature file
+ void* sce_ebootpbp_sig_data = NULL;
+ int sce_ebootpbp_sz = allocateReadFile(sce_ebootpbp, &sce_ebootpbp_sig_data);
+
+ // cache current __sce_ebootpbp signature file
+ void* sce_discinfo_sig_data = NULL;
+ int sce_discinfo_sz = allocateReadFile(sce_discinfo, &sce_discinfo_sig_data);
+
- snprintf(promote_psp_folder, MAX_PATH_LENGTH, "%s/PSP", PSP_TEMP);
- snprintf(promote_psp_game_folder, MAX_PATH_LENGTH, "%s/PSP/GAME", PSP_TEMP);
- snprintf(promote_psp_license_folder, MAX_PATH_LENGTH, "%s/PSP/LICENSE", PSP_TEMP);
+ if(get_pbp_content_id(eboot_pbp, contentid)) {
+ // create directories
+ char promote_psp_folder[MAX_PATH_LENGTH];
+ char promote_psp_game_folder[MAX_PATH_LENGTH];
+ char promote_psp_license_folder[MAX_PATH_LENGTH];
+
+ char promote_license_rif[MAX_PATH_LENGTH];
+ char promote_game_folder[MAX_PATH_LENGTH];
+
+ snprintf(promote_psp_folder, MAX_PATH_LENGTH, "%s/PSP", PSP_TEMP);
+ snprintf(promote_psp_game_folder, MAX_PATH_LENGTH, "%s/PSP/GAME", PSP_TEMP);
+ snprintf(promote_psp_license_folder, MAX_PATH_LENGTH, "%s/PSP/LICENSE", PSP_TEMP);
+
+ snprintf(promote_license_rif, MAX_PATH_LENGTH, "%s/PSP/LICENSE/%s.rif", PSP_TEMP, contentid);
+
+ void *sfo_buffer = NULL;
+ int sfo_size = get_pbp_sfo(eboot_pbp, &sfo_buffer);
- snprintf(promote_license_rif, MAX_PATH_LENGTH, "%s/PSP/LICENSE/%s.rif", PSP_TEMP, contentid);
- snprintf(promote_game_folder, MAX_PATH_LENGTH, "%s/PSP/GAME/%s", PSP_TEMP, subdir);
-
- // get current rif location
- snprintf(license_rif, MAX_PATH_LENGTH, "ux0:/pspemu/PSP/LICENSE/%s.rif", contentid);
-
- // create the promote directories
- sceIoMkdir(promote_psp_folder, 0006);
- sceIoMkdir(promote_psp_game_folder, 0006);
- sceIoMkdir(promote_psp_license_folder, 0006);
+ if(sfo_size >= 0) {
+
+ char discid[12];
+
+ getSfoString(sfo_buffer, "DISC_ID", discid, sizeof(discid));
+
+ // maintain compatiblity with psp bubble cloning, and other tricks
+ // use folder name as disc id, *only* on npumdimg
+ if(pbp_type == PBP_TYPE_NPUMDIMG)
+ strncpy(discid, subdir, sizeof(discid));
+
+ // ensure its installing PS1 to the correct folder ..
+ // if ps1 installed to incorrect folder, will give
+ // 'cannot open the memory card' error message
+ snprintf(promote_game_folder, MAX_PATH_LENGTH, "%s/PSP/GAME/%s", PSP_TEMP, discid);
+ sceClibPrintf("promote_game_folder: %s\n", promote_game_folder);
+ sceClibPrintf("game_folder: %s\n", path);
+
+ // get current rif location
+ snprintf(license_rif, MAX_PATH_LENGTH, "ux0:/pspemu/PSP/LICENSE/%s.rif", contentid);
+
+ // create the promote directories
+
+ sceIoMkdir("ux0:pspemu", 0006);
+ sceIoMkdir("ux0:pspemu/temp", 0006);
+ sceIoMkdir(PSP_TEMP, 0006);
+ sceIoMkdir(promote_psp_folder, 0006);
+ sceIoMkdir(promote_psp_game_folder, 0006);
+ sceIoMkdir(promote_psp_license_folder, 0006);
+
+ // copy the rif to the promote location
+ int res = copyFile(license_rif, promote_license_rif, NULL);
+
+ if(res < 0) { // no rif found?
+ // generate fake psp license
+ SceNpDrmLicense license;
+ memset(&license, 0x00, sizeof(SceNpDrmLicense));
+ license.account_id = 0x0123456789ABCDEFLL;
+ memset(license.ecdsa_signature, 0xFF, 0x28);
+ strncpy(license.content_id, contentid, 0x30);
+ WriteFile(promote_license_rif, &license, offsetof(SceNpDrmLicense, flags));
+ }
+
+ // promote will fail if __sce_ebootpbp signature file is invalid (or for another account)
+ // so we have to generate a new one ..
+ sceIoRemove(sce_ebootpbp);
+ sceIoRemove(sce_discinfo);
+
+ int eboot_gen = gen_sce_ebootpbp(path);
+
+ // move path to promote folder
+ sceIoRename(path, promote_game_folder);
+
+ int promote = promoteCma(PSP_TEMP, discid, SCE_PKG_TYPE_PSP);
+
+ sceClibPrintf("eboot_gen: %x, promote %x\n", eboot_gen, promote);
+
+ if (promote == 0 && eboot_gen >= 0) {
+ refresh_data->refreshed++;
+ }
+ else {
+ sceIoRename(promote_game_folder, path); // Restore folder on error
+ removePath(PSP_TEMP, NULL); // delete what was created
+ }
+
+ // if eboot signature generation was unsuccessful, write original signature back
+ if(eboot_gen < 0) {
+ if(sce_ebootpbp_sz > 0)
+ WriteFile(sce_ebootpbp, sce_ebootpbp_sig_data, sce_ebootpbp_sz); // Restore __sce_ebootpbp on error
+
+ if(sce_discinfo_sz > 0)
+ WriteFile(sce_discinfo, sce_discinfo_sig_data, sce_discinfo_sz); // Restore __sce_discinfo on error
+ }
+ }
+ if(sfo_buffer != NULL)
+ free(sfo_buffer);
- // copy the rif to the promote location
- int res = copyFile(license_rif, promote_license_rif, NULL);
- if(res < 0) {
- // generate fake psp license
- SceNpDrmLicense license;
- memset(&license, 0x00, sizeof(SceNpDrmLicense));
- license.account_id = 0x0123456789ABCDEFLL;
- memset(license.ecdsa_signature, 0xFF, 0x28);
- strncpy(license.content_id, contentid, 0x30);
- WriteFile(promote_license_rif, &license, offsetof(SceNpDrmLicense, flags));
}
- // promote will fail if __sce_ebootpbp signature file is invalid (or for another account)
- // so we have to generate a new one ..
- sceIoRemove(sce_ebootpbp);
- sceIoRemove(sce_discinfo);
-
- int eboot_gen = gen_sce_ebootpbp(path);
-
- // move path to promote folder
- sceIoRename(path, promote_game_folder);
+ if(sce_ebootpbp_sig_data != NULL)
+ free(sce_ebootpbp_sig_data);
- int promote = promoteCma(PSP_TEMP, subdir, SCE_PKG_TYPE_VITA);
- if (promote == 0 && eboot_gen >= 0) {
- refresh_data->refreshed++;
- }
- else {
- sceIoRename(promote_game_folder, path); // Restore folder on error
- removePath(PSP_TEMP, NULL); // delete what was created
- }
-
- // if eboot signature generation was unsuccessful, write original signature back
- if(eboot_gen < 0) {
- if(sce_ebootpbp_sz > 0)
- WriteFile(sce_ebootpbp, sce_ebootpbp_sig_data, sce_ebootpbp_sz); // Restore __sce_ebootpbp on error
-
- if(sce_discinfo_sz > 0)
- WriteFile(sce_discinfo, sce_discinfo_sig_data, sce_discinfo_sz); // Restore __sce_discinfo on error
- }
-
- }
-
- if(sce_ebootpbp_sig_data != NULL)
- free(sce_ebootpbp_sig_data);
-
- if(sce_discinfo_sig_data != NULL)
- free(sce_ebootpbp_sig_data);
- }
+ if(sce_discinfo_sig_data != NULL)
+ free(sce_ebootpbp_sig_data);
+ }
+ }
SetProgress(++refresh_data->processed, refresh_data->count);
} else {
refresh_data->count++;
@@ -591,7 +641,7 @@ void psm_callback(void* data, const char* dir, const char* subdir) {
int refresh_thread(SceSize args, void *argp) {
SceUID thid = -1;
refresh_data_t refresh_data = { 0, 0, 0, 0 };
-
+
// Lock power timers
powerLock();
@@ -625,6 +675,7 @@ int refresh_thread(SceSize args, void *argp) {
// Make sure we have the temp directories we need
sceIoMkdir("ux0:temp", 0006);
sceIoMkdir("ux0:pspemu", 0006);
+ sceIoMkdir("ux0:pspemu/temp", 0006);
sceIoMkdir(DLC_TEMP, 0006);
sceIoMkdir(PATCH_TEMP, 0006);
sceIoMkdir(PSM_TEMP, 0006);
@@ -655,7 +706,7 @@ int refresh_thread(SceSize args, void *argp) {
sceIoRmdir(PATCH_TEMP);
sceIoRmdir(PSM_TEMP);
sceIoRmdir(PSP_TEMP);
-
+
// Set progress to 100%
sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 100);
sceKernelDelayThread(COUNTUP_WAIT);
@@ -671,7 +722,8 @@ int refresh_thread(SceSize args, void *argp) {
// Unlock power timers
powerUnlock();
-
+
+
return sceKernelExitDeleteThread(0);
}
From 66f317d56a568ad6b679c31862a2ad9a1ea2cbc3 Mon Sep 17 00:00:00 2001
From: Li
Date: Sun, 25 Jun 2023 12:57:39 +1200
Subject: [PATCH 11/11] Fix multi disc generation, and warnings!
---
pbp.c | 99 ++++++++++++++++++++++++++++++++++++-------------------
pbp.h | 18 +++++-----
refresh.c | 36 ++++++--------------
3 files changed, 85 insertions(+), 68 deletions(-)
diff --git a/pbp.c b/pbp.c
index aeaee031..44278af1 100644
--- a/pbp.c
+++ b/pbp.c
@@ -47,6 +47,27 @@ int read_content_id_npumdimg(SceUID pbp_fd, char* content_id) {
return (strlen(content_id) == 36);
}
+int is_psx_signed(SceUID pbp_fd, int data_psar_offset, int pbp_type) { // check psx eboot is signed.
+ char pgd_magic[0x4]; // this is to filter out psx2psp eboots, and other such tools.
+ // which could never work from the vita's LiveSpace.
+ // seek to iso header
+ if(pbp_type == PBP_TYPE_PSISOIMG)
+ sceIoLseek(pbp_fd, data_psar_offset+0x400, SCE_SEEK_SET);
+ else
+ sceIoLseek(pbp_fd, data_psar_offset+0x200, SCE_SEEK_SET);
+
+ // read magic
+ int read_len = sceIoRead(pbp_fd, pgd_magic, sizeof(pgd_magic));
+ if(read_len < sizeof(pgd_magic))
+ return PBP_TYPE_UNKNOWN;
+
+ // if is not PGD, then it is not a signed PSX PBP.
+ if(memcmp(pgd_magic, "\0PGD", sizeof(pgd_magic)) == 0)
+ return pbp_type;
+ else
+ return PBP_TYPE_UNKNOWN;
+}
+
int determine_pbp_type(SceUID pbp_fd, PbpHeader* pbp_header) {
char data_psar_magic[0x8];
@@ -60,14 +81,14 @@ int determine_pbp_type(SceUID pbp_fd, PbpHeader* pbp_header) {
read_sz = sceIoRead(pbp_fd, data_psar_magic, sizeof(data_psar_magic));
if(read_sz < sizeof(data_psar_magic)) return 0;
- if(memcmp(data_psar_magic, "NPUMDIMG", 0x8) == 0) { // psp
+ if(memcmp(data_psar_magic, "NPUMDIMG", 0x8) == 0) { // psp
return PBP_TYPE_NPUMDIMG;
}
else if(memcmp(data_psar_magic, "PSISOIMG", 0x8) == 0) { // ps1 single disc
- return PBP_TYPE_PSISOIMG;
+ return is_psx_signed(pbp_fd, pbp_header->data_psar_ptr, PBP_TYPE_PSISOIMG);
}
else if(memcmp(data_psar_magic, "PSTITLEI", 0x8) == 0) { // ps1 multi disc
- return PBP_TYPE_PSTITLEIMG;
+ return is_psx_signed(pbp_fd, pbp_header->data_psar_ptr, PBP_TYPE_PSTITLEIMG);
}
else{ // update package, homebrew, etc,
return PBP_TYPE_UNKNOWN;
@@ -98,6 +119,24 @@ int read_data_psar_header(SceUID pbp_fd, char* content_id) {
}
}
+void get_sce_discinfo_sig(char* sce_discinfo, char* disc_id) {
+ memset(sce_discinfo, 0x00, 0x100);
+ SceUID discinfo_fd = sceIoOpen("vs0:app/NPXS10028/__sce_discinfo", SCE_O_RDONLY, 0);
+
+ if(discinfo_fd < 0)
+ return;
+
+ int read_size = 0;
+ do{
+ read_size = sceIoRead(discinfo_fd, sce_discinfo, 0x100);
+ if(strncmp(sce_discinfo, disc_id, 0x9) == 0) {
+ break;
+ }
+ } while(read_size >= 0x100);
+
+ sceIoClose(discinfo_fd);
+}
+
int read_sfo(SceUID pbp_fd, void** param_sfo_buffer){
PbpHeader pbp_header;
// read pbp header
@@ -126,8 +165,8 @@ int read_sfo(SceUID pbp_fd, void** param_sfo_buffer){
return param_sfo_size;
}
-int hash_pbp(SceUID pbp_fd, char* out_hash) {
- char wbuf[0x7c0];
+int hash_pbp(SceUID pbp_fd, unsigned char* out_hash) {
+ unsigned char wbuf[0x7c0];
// seek to the start of the eboot.pbp
sceIoLseek(pbp_fd, 0x00, SCE_SEEK_SET);
@@ -170,14 +209,14 @@ int hash_pbp(SceUID pbp_fd, char* out_hash) {
int get_pbp_sfo(const char* pbp_file, void** param_sfo_buffer) {
PbpHeader pbp_header;
- if(param_sfo_buffer == NULL) return NULL;
+ if(param_sfo_buffer == NULL) return 0;
*param_sfo_buffer = NULL;
int res = 0;
if(pbp_file != NULL) {
SceUID pbp_fd = sceIoOpen(pbp_file, SCE_O_RDONLY, 0);
- if(pbp_fd < 0) return NULL;
+ if(pbp_fd < 0) return 0;
// read param.sfo from pbp
res = read_sfo(pbp_fd, param_sfo_buffer);
@@ -226,24 +265,22 @@ int get_pbp_content_id(const char* pbp_file, char* content_id) {
}
-int gen_sce_ebootpbp(const char* psp_game_folder){
+int gen_sce_ebootpbp(const char* psp_game_folder, char* disc_id) {
int res = 0;
- char pbp_hash[0x20];
+ unsigned char pbp_hash[0x20];
char sce_ebootpbp[0x200];
+ char sce_discinfo[0x100];
+
int sw_version = 0;
PbpHeader pbp_header;
- void* sony_sce_discinfo = NULL;
- int sony_sce_discinfo_sz = allocateReadFile("vs0:/NPXS10028/__sce_discinfo", &sony_sce_discinfo);
if(psp_game_folder != NULL) {
char ebootpbp_path[MAX_PATH_LENGTH];
char sce_ebootpbp_path[MAX_PATH_LENGTH];
- char sce_discinfo_path[MAX_PATH_LENGTH];
snprintf(ebootpbp_path, MAX_PATH_LENGTH, "%s/EBOOT.PBP", psp_game_folder);
snprintf(sce_ebootpbp_path, MAX_PATH_LENGTH, "%s/__sce_ebootpbp", psp_game_folder);
- snprintf(sce_discinfo_path, MAX_PATH_LENGTH, "%s/__sce_discinfo", psp_game_folder);
memset(pbp_hash, 0x00, sizeof(pbp_hash));
memset(sce_ebootpbp, 0x00, sizeof(pbp_hash));
@@ -251,36 +288,32 @@ int gen_sce_ebootpbp(const char* psp_game_folder){
SceUID pbp_fd = sceIoOpen(ebootpbp_path, SCE_O_RDONLY, 0);
if(pbp_fd < 0)
- goto EXIT;
+ return res;
int pbp_type = determine_pbp_type(pbp_fd, &pbp_header); // determine pbp header
- if(pbp_type == PBP_TYPE_UNKNOWN)
- goto EXIT;
-
- res = hash_pbp(pbp_fd, pbp_hash); // hash eboot.pbp
-
+ if(pbp_type == PBP_TYPE_PSISOIMG || pbp_type == PBP_TYPE_NPUMDIMG)
+ res = hash_pbp(pbp_fd, pbp_hash); // hash eboot.pbp
+ if(pbp_type == PBP_TYPE_PSTITLEIMG)
+ get_sce_discinfo_sig(sce_discinfo, disc_id); // read sce_discinfo
+
sceIoClose(pbp_fd);
+
+ if(pbp_type == PBP_TYPE_UNKNOWN)
+ return res;
+
- // actually generate the __sce_ebootpbp or __sce_discinfo
- if(pbp_type == PBP_TYPE_NPUMDIMG)
- res = _vshNpDrmEbootSigGenPsp(ebootpbp_path, pbp_hash, sce_ebootpbp, &sw_version);
+ // actually generate the __sce_ebootpbp
+ if(pbp_type == PBP_TYPE_NPUMDIMG)
+ res = _vshNpDrmEbootSigGenPsp(ebootpbp_path, pbp_hash, sce_ebootpbp, &sw_version);
else if(pbp_type == PBP_TYPE_PSISOIMG)
res = _vshNpDrmEbootSigGenPs1(ebootpbp_path, pbp_hash, sce_ebootpbp, &sw_version);
else if(pbp_type == PBP_TYPE_PSTITLEIMG)
- res = _vshNpDrmEbootSigGenMultiDisc(ebootpbp_path, sony_sce_discinfo, sce_ebootpbp, &sw_version);
+ res = _vshNpDrmEbootSigGenMultiDisc(ebootpbp_path, sce_discinfo, sce_ebootpbp, &sw_version);
+
if(res >= 0) { // write __sce_ebootpbp
- if(pbp_type == PBP_TYPE_NPUMDIMG || pbp_type == PBP_TYPE_PSISOIMG)
- res = WriteFile(sce_ebootpbp_path, sce_ebootpbp, 0x200);
- else if(pbp_type == PBP_TYPE_PSTITLEIMG)
- res = WriteFile(sce_discinfo_path, sce_ebootpbp, 0x100);
+ res = WriteFile(sce_ebootpbp_path, sce_ebootpbp, 0x200);
}
}
-
-EXIT:
-
- if(sony_sce_discinfo != NULL)
- free(sony_sce_discinfo);
-
return res;
}
\ No newline at end of file
diff --git a/pbp.h b/pbp.h
index c984cc76..1f02a501 100644
--- a/pbp.h
+++ b/pbp.h
@@ -30,13 +30,13 @@ typedef enum PbpType{
// for PSISOIMG and PSTITLEIMG contents
typedef struct DataPspHeader{
- char magic[0x4];
- char unk[0x7C];
- char unk2[0x32];
- char unk3[0xE];
- char hash[0x14];
- char reserved[0x58];
- char unk4[0x434];
+ SceUInt8 magic[0x4];
+ SceUInt8 unk[0x7C];
+ SceUInt8 unk2[0x32];
+ SceUInt8 unk3[0xE];
+ SceUInt8 hash[0x14];
+ SceUInt8 reserved[0x58];
+ SceUInt8 unk4[0x434];
char content_id[0x30];
} DataPspHeader;
@@ -73,7 +73,7 @@ typedef struct NpUmdImgHeader{
SceUInt8 magic[0x08]; // "NPUMDIMG"
SceUInt32 key_index; // usually 2, or 3.
SceUInt32 block_basis;
- SceUInt8 content_id[0x30];
+ char content_id[0x30];
NpUmdImgBody body;
SceUInt8 header_key[0x10];
SceUInt8 data_key[0x10];
@@ -101,5 +101,5 @@ typedef struct PbpHeader
int get_pbp_type(const char* pbp_file);
int get_pbp_sfo(const char* pbp_file, void** param_sfo_buffer);
int get_pbp_content_id(const char* pbp_file, char* content_id);
-int gen_sce_ebootpbp(const char* psp_game_folder);
+int gen_sce_ebootpbp(const char* psp_game_folder, char* disc_id);
#endif
\ No newline at end of file
diff --git a/refresh.c b/refresh.c
index b857bdb1..f9b39d96 100644
--- a/refresh.c
+++ b/refresh.c
@@ -107,7 +107,7 @@ int refreshNeeded(const char *app_path, const char* content_type) {
if(app_directory != NULL) free(app_directory);
return 0;
}
- strncpy(titleid, app_directory, 12);
+ strncpy(titleid, app_directory, 11);
free(app_directory);
snprintf(ebootpbp_path, MAX_PATH_LENGTH, "%s/EBOOT.PBP", app_path);
@@ -212,7 +212,7 @@ int refreshNeeded(const char *app_path, const char* content_type) {
}
}
// license not needed to promote psp or psm contents
- else if((strcmp(content_type, "psm") == 0) || (strcmp(content_type, "psp") == 0) && (checkAppExist(titleid))) {
+ else if((strcmp(content_type, "psm") == 0 || strcmp(content_type, "psp") == 0) && checkAppExist(titleid)) {
if(strcmp(content_type, "psp") == 0) {
char eboot_signature[0x200];
@@ -223,17 +223,12 @@ int refreshNeeded(const char *app_path, const char* content_type) {
// get path to __sce_ebootpbp
char sce_ebootpbp[MAX_PATH_LENGTH];
snprintf(sce_ebootpbp, MAX_PATH_LENGTH, "%s/__sce_ebootpbp", app_path);
-
- // get path to __sce_discinfo
- char sce_discinfo[MAX_PATH_LENGTH];
- snprintf(sce_discinfo, MAX_PATH_LENGTH, "%s/__sce_discinfo", app_path);
-
+
// check EBOOT.PBP exists
if(getFileSize(ebootpbp_path) < 0)
return 0;
int sce_ebootpbp_exist = (getFileSize(sce_ebootpbp) >= 0);
- int sce_discinfo_exist = (getFileSize(sce_discinfo) >= 0);
// verify __sce_ebootpbp
if(sce_ebootpbp_exist) {
@@ -247,9 +242,9 @@ int refreshNeeded(const char *app_path, const char* content_type) {
return 0;
}
- else if(!sce_discinfo_exist) { // _vshNpDrmEbootSigVerify doesn't seem to work on these ..
+ else {
return 1;
- }
+ }
}
return 0;
}
@@ -458,13 +453,11 @@ void psp_callback(void* data, const char* dir, const char* subdir) {
char contentid[0x30];
char sce_ebootpbp[MAX_PATH_LENGTH];
- char sce_discinfo[MAX_PATH_LENGTH];
char eboot_pbp[MAX_PATH_LENGTH];
char license_rif[MAX_PATH_LENGTH];
snprintf(eboot_pbp, MAX_PATH_LENGTH, "%s/EBOOT.PBP", path);
snprintf(sce_ebootpbp, MAX_PATH_LENGTH, "%s/__sce_ebootpbp", path);
- snprintf(sce_discinfo, MAX_PATH_LENGTH, "%s/__sce_discinfo", path);
// get pbp type
int pbp_type = get_pbp_type(eboot_pbp);
@@ -473,11 +466,7 @@ void psp_callback(void* data, const char* dir, const char* subdir) {
// cache current __sce_ebootpbp signature file
void* sce_ebootpbp_sig_data = NULL;
int sce_ebootpbp_sz = allocateReadFile(sce_ebootpbp, &sce_ebootpbp_sig_data);
-
- // cache current __sce_ebootpbp signature file
- void* sce_discinfo_sig_data = NULL;
- int sce_discinfo_sz = allocateReadFile(sce_discinfo, &sce_discinfo_sig_data);
-
+
if(get_pbp_content_id(eboot_pbp, contentid)) {
// create directories
@@ -506,7 +495,7 @@ void psp_callback(void* data, const char* dir, const char* subdir) {
// maintain compatiblity with psp bubble cloning, and other tricks
// use folder name as disc id, *only* on npumdimg
if(pbp_type == PBP_TYPE_NPUMDIMG)
- strncpy(discid, subdir, sizeof(discid));
+ strncpy(discid, subdir, sizeof(discid)-1);
// ensure its installing PS1 to the correct folder ..
// if ps1 installed to incorrect folder, will give
@@ -543,9 +532,8 @@ void psp_callback(void* data, const char* dir, const char* subdir) {
// promote will fail if __sce_ebootpbp signature file is invalid (or for another account)
// so we have to generate a new one ..
sceIoRemove(sce_ebootpbp);
- sceIoRemove(sce_discinfo);
- int eboot_gen = gen_sce_ebootpbp(path);
+ int eboot_gen = gen_sce_ebootpbp(path, discid);
// move path to promote folder
sceIoRename(path, promote_game_folder);
@@ -554,7 +542,7 @@ void psp_callback(void* data, const char* dir, const char* subdir) {
sceClibPrintf("eboot_gen: %x, promote %x\n", eboot_gen, promote);
- if (promote == 0 && eboot_gen >= 0) {
+ if (promote == 0) {
refresh_data->refreshed++;
}
else {
@@ -566,11 +554,9 @@ void psp_callback(void* data, const char* dir, const char* subdir) {
if(eboot_gen < 0) {
if(sce_ebootpbp_sz > 0)
WriteFile(sce_ebootpbp, sce_ebootpbp_sig_data, sce_ebootpbp_sz); // Restore __sce_ebootpbp on error
-
- if(sce_discinfo_sz > 0)
- WriteFile(sce_discinfo, sce_discinfo_sig_data, sce_discinfo_sz); // Restore __sce_discinfo on error
}
}
+
if(sfo_buffer != NULL)
free(sfo_buffer);
@@ -579,8 +565,6 @@ void psp_callback(void* data, const char* dir, const char* subdir) {
if(sce_ebootpbp_sig_data != NULL)
free(sce_ebootpbp_sig_data);
- if(sce_discinfo_sig_data != NULL)
- free(sce_ebootpbp_sig_data);
}
}
SetProgress(++refresh_data->processed, refresh_data->count);