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);