etaHEN 2.5B

This commit is contained in:
LM
2025-12-25 00:28:32 -05:00
parent 8860c0a603
commit 5061a85312
36 changed files with 27175 additions and 1275 deletions

View File

@@ -4,9 +4,9 @@ PS5_PORT ?= 9021
ELF := hen.elf
BIN := hen.bin
CFLAGS := -std=c++11 -Wall -Werror -D_KERNEL -I./include -O2 -fno-builtin -nostdlib -fno-stack-protector -fno-plt -fPIC -Wno-error=frame-address -Wno-unused-const-variable
CFLAGS := -std=c++11 -Wall -Werror -D_KERNEL -I./include -O2 -fno-builtin -nostartfiles -nostdlib -fno-stack-protector -fno-plt -fPIC -Wno-error=frame-address -I${PS5_PAYLOAD_SDK}include/freebsd -g3
#SFLAGS := -nostartfiles -nostdlib -fPIC
LFLAGS := -Xlinker -T ./link.x -Wl,--build-id=none -nostartfiles
LFLAGS := -Xlinker -T ./link.x -Wl,--build-id=none
ODIR := build
SDIR := src

View File

@@ -60,7 +60,7 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")
target_sources(${PROJECT_NAME} PRIVATE ${SrcFiles})
target_include_directories(${PROJECT_NAME} PRIVATE "${D_CWD}/include" "${D_SRC}/../Byepervisor/include" "${D_SRC}/../Byepervisor_DevKit/include" "${D_SRC}/../Byepervisor_DevKit/include/offsets")
target_link_directories (${PROJECT_NAME} PUBLIC "${PROJECT_ROOT}/lib")
target_link_libraries (${PROJECT_NAME} PUBLIC NineS SceSystemService SceUserService kernel_sys elfldr sqlite3)
target_link_libraries (${PROJECT_NAME} PUBLIC NineS SceSystemService SceUserService kernel_sys elfldr sqlite3 SceNotification)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_dependencies(${PROJECT_NAME} daemon util shellui)

Binary file not shown.

View File

@@ -73,4 +73,15 @@ __asm__(".intel_syntax noprefix\n"
"kstuff_size:\n"
".int kstuff_end - kstuff_start\n"
".global fps_prx_start\n"
".type fps_prx_start, @object\n"
".align 16\n"
"fps_prx_start:\n"
".incbin \"assets/fps.prx\"\n"
"fps_prx_end:\n"
".global fps_prx_size\n"
".type fps_prx_size, @object\n"
".align 4\n"
"fps_prx_size:\n"
".int fps_prx_end - fps_prx_start\n"
);

View File

@@ -72,7 +72,63 @@ along with this program; see the file COPYING. If not, see
extern uint8_t fps_prx_start[];
extern const unsigned int fps_prx_size;
int sceNotificationSend(int userId, bool isLogged, const char* payload);
}
const char json_payload[] =
"{\n"
" \"rawData\": {\n"
" \"viewTemplateType\": \"InteractiveToastTemplateB\",\n"
" \"channelType\": \"Downloads\",\n"
" \"useCaseId\": \"IDC\",\n"
" \"toastOverwriteType\": \"No\",\n"
" \"isImmediate\": true,\n"
" \"priority\": 100,\n"
" \"viewData\": {\n"
" \"icon\": {\n"
" \"type\": \"Url\",\n"
" \"parameters\": {\n"
" \"url\": \"/user/data/etaHEN/etahen.png\"\n"
" }\n"
" },\n"
" \"message\": {\n"
" \"body\": \"etaHEN is starting...\"\n"
" },\n"
" \"subMessage\": {\n"
" \"body\": \"Please Wait For The Welcome Message\"\n"
" },\n"
" \"actions\": [\n"
" {\n"
" \"actionName\": \"Go to Debug Settings\",\n"
" \"actionType\": \"DeepLink\",\n"
" \"defaultFocus\": true,\n"
" \"parameters\": {\n"
" \"actionUrl\": \"pssettings:play?function=debug_settings\"\n"
" }\n"
" }\n"
" ]\n"
" },\n"
" \"platformViews\": {\n"
" \"previewDisabled\": {\n"
" \"viewData\": {\n"
" \"icon\": {\n"
" \"type\": \"Predefined\",\n"
" \"parameters\": {\n"
" \"icon\": \"download\"\n"
" }\n"
" },\n"
" \"message\": {\n"
" \"body\": \"etaHEN is starting...\"\n"
" }\n"
" }\n"
" }\n"
" }\n"
" },\n"
" \"createdDateTime\": \"2025-12-14T03:14:51.473Z\",\n"
" \"localNotificationId\": \"588193127\"\n"
"}";
/******************************************************************************
* Macros and Constants
@@ -280,8 +336,22 @@ static void cleanup(void);
return;
}
close(fd);
#endif
if (!if_exists("/data/etaHEN/assets/store.png")) {
#endif
#if 0
/// if (!if_exists("/data/etaHEN/fps.prx")) {
int fd = open("/data/etaHEN/fps.prx", O_WRONLY | O_CREAT | O_TRUNC, 0777);
if (fd == -1) {
perror("open failed");
return;
}
if (write(fd, &fps_prx_start, fps_prx_size) == -1) {
perror("write failed");
}
close(fd);
// }
#endif
if (!if_exists("/data/etaHEN/assets/store.png")) {
int fd = open("/data/etaHEN/assets/store.png", O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd == -1) {
perror("open failed");
@@ -304,6 +374,18 @@ if (!if_exists("/data/etaHEN/assets/store.png")) {
}
close(fd);
}
if (!if_exists("/data/etaHEN/etahen.png")) {
int fd = open("/data/etaHEN/etahen.png", O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd == -1) {
perror("open failed");
return;
}
if (write(fd, & sicon_start, sicon_size) == -1) {
perror("write failed");
}
close(fd);
}
if (!if_exists("/system_ex/rnps/apps/NPXS40008/assets/src/modules/categoriesList/assets/texture/etahen_sicon.png")) {
int fd = open("/system_ex/rnps/apps/NPXS40008/assets/src/modules/categoriesList/assets/texture/etahen_sicon.png", O_WRONLY | O_CREAT | O_TRUNC, 0666);
@@ -932,9 +1014,9 @@ bool sceKernelIsTestKit() {
return if_exists("/system/priv/lib/libSceDeci5Ttyp.sprx");
}
#define PUBLIC_TEST 0
#define EXPIRE_YEAR 2025
#define EXPIRE_MONTH 12
#define EXPIRE_DAY 25
#define EXPIRE_YEAR 2026
#define EXPIRE_MONTH 1
#define EXPIRE_DAY 1
bool isPastBetaDate(int year, int month, int day);
@@ -1034,16 +1116,14 @@ int main(void) {
}
}
notify("[Bootstrapper] etaHEN is starting...\n DO NOT EXIT \nwait for "
"the etaHEN welcome message");
klog_puts("============== Spawner (Bootstrapper) Started =================");
mkdir("/data/etaHEN", 0777);
mkdir("/data/etaHEN/plugins", 0777);
mkdir("/data/etaHEN/payloads", 0777);
mkdir("/data/etaHEN/daemons", 0777);
mkdir("/data/etaHEN/assets", 0777);
mkdir("/data/etaHEN/games", 0777);
klog_printf("Registering signal handler ...");
fault_handler_init(cleanup);
@@ -1066,6 +1146,8 @@ int main(void) {
write_embedded_assets();
klog_printf(" Written!\n");
sceNotificationSend(0xFE, true, &json_payload[0]);
klog_printf("Unmounting /update forcefully ...");
// block updates
unlink("/update/PS5UPDATE.PUP");
@@ -1086,7 +1168,7 @@ int main(void) {
klog_puts("kstuff loading disabled in config.ini or no_kstuff file found");
}
if (!dont_load_kstuff && sys_ver.version >= 0x3000000) {
notify("Loading kstuff ...");
//notify("Loading kstuff ...");
bool cleanup_kstuff = false;
uint8_t* kstuff_address = get_kstuff_address(cleanup_kstuff);

View File

@@ -62,7 +62,7 @@ target_sources(${PROJECT_NAME} PRIVATE ${SrcFiles})
target_include_directories(${PROJECT_NAME} PRIVATE "${D_CWD}/include")
target_link_directories (${PROJECT_NAME} PUBLIC "${PROJECT_ROOT}/lib")
add_dependencies(${PROJECT_NAME} NineS shellui hijacker SelfDecryptor elfldr)
target_link_libraries (${PROJECT_NAME} PUBLIC hijacker ScePad SceSystemService SceNet SceRegMgr SceSysmodule SceUserService SceNetCtl SceSysCore kernel_sys SceAppInstUtil NineS elfldr SelfDecryptor)
target_link_libraries (${PROJECT_NAME} PUBLIC hijacker ScePad SceSystemService SceNotification SceNet SceRegMgr SceSysmodule SceUserService SceNetCtl SceSysCore kernel_sys SceAppInstUtil NineS elfldr SelfDecryptor)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Add post-build command
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD

View File

@@ -36,11 +36,14 @@ struct daemon_settings {
bool allow_data = true;
bool DPIv2 = false;
bool elf_loader = true;
bool enable_fan_speed = false;
bool toolbox_auto_start = true;
bool debug_app_jb_msg = false;
bool auto_eject_disc = false;
bool overlay_fps = false;
StartOpts start_opt = NONE;
int seconds = 0; // seconds to wait before starting toolbox
int fan_threshold = 77; // default fan threshold
};
extern struct daemon_settings global_conf;

View File

@@ -381,6 +381,7 @@ bool is_whitelisted_app(const std::string &tid) {
"NPXS39041",
"DUMP00000",
"PKGI13337",
"PKGI12345",
"TOOL00001",
};
@@ -553,6 +554,10 @@ bool Open_Utility_Elf(const char *path, uint8_t **buffer) {
return true;
}
bool cmd_enable_fps(int appid);
void LoadSettings();
extern bool is_800;
bool set_fan_threshold(int THRESHOLDTEMP);
bool cmd_enable_fps_new(int appid);
void *fifo_and_dumper_thread(void *args) noexcept {
char *json_str = nullptr;
constexpr uint32_t MAX_TOKENS = 256;
@@ -596,15 +601,25 @@ void *fifo_and_dumper_thread(void *args) noexcept {
}
pthread_mutex_lock(&jb_lock);
if(global_conf.enable_fan_speed)
set_fan_threshold(global_conf.fan_threshold);
int bappid;
if (!Get_Running_App_TID(tid, bappid)) {
pthread_mutex_unlock(&jb_lock);
continue;
}
#if 0
if(tid.rfind("CUSA") != std::string::npos || tid.rfind("SCUS") != std::string::npos)
cmd_enable_fps(bappid);
#endif
if( if_exists("/system_tmp/fps_enabled") && (tid.rfind("CUSA") != std::string::npos || tid.rfind("SCUS") != std::string::npos)){
// cmd_enable_fps(bappid);
if(is_800)
cmd_enable_fps_new(bappid);
else
cmd_enable_fps(bappid);
}
if (is_dumper_enabled) {
if (strstr(tid.c_str(), "ITEM00001") != 0) {
pthread_mutex_unlock(&jb_lock);
@@ -719,7 +734,7 @@ void *fifo_and_dumper_thread(void *args) noexcept {
notify(true, "App (PID %i) has been granted a jailbreak", reserved_value);
spawned->jailbreak(true);
spawned.release();
spawned.release();
// jailbreak_proc(reserved_value);
unlink(sandbox_dir.c_str());
}

View File

@@ -26,5 +26,28 @@
"shellui_prx_size:\n"
".int shellui_elf_end - shellui_elf_start\n"
".global fps_elf_start\n"
".type fps_elf_start, @object\n"
".align 16\n"
"fps_elf_start:\n"
".incbin \"assets/fps_elf.elf\"\n"
"fps_elf_end:\n"
".global fps_elf_size\n"
".type fps_elf_size, @object\n"
".align 4\n"
"fps_elf_size:\n"
".int fps_elf_end - fps_elf_start\n"
".global dumper_elf_start\n"
".type dumper_elf_start, @object\n"
".align 16\n"
"dumper_elf_start:\n"
".incbin \"assets/ps5-app-dumper.elf\"\n"
"dumper_elf_end:\n"
".global dumper_elf_size\n"
".type dumper_elf_size, @object\n"
".align 4\n"
"dumper_elf_size:\n"
".int dumper_elf_end - dumper_elf_start\n"
);

View File

@@ -107,6 +107,7 @@ extern "C" {
// External data
extern uint8_t ps5debug_start[];
extern const unsigned int ps5debug_size;
int sceNotificationSend(int userId, bool isLogged, const char* payload);
}
@@ -297,7 +298,7 @@ int ItemzLaunchByUri(const char* uri) {
bool cmd_enable_toolbox();
void LoadSettings();
bool is_800 = false;
int main() {
char buz[255];
pthread_t fifo_thr = nullptr;
@@ -332,6 +333,7 @@ int main() {
bool is_lite = if_exists("/system_tmp/lite_mode");
bool toolbox_only = (fw_ver >= 0x10000);
bool no_ps5debug = (fw_ver >= 0x800);
is_800 = (fw_ver >= 0x800);
LoadSettings();
@@ -366,13 +368,60 @@ int main() {
if (!elfldr_spawn("/", STDOUT_FILENO, ps5debug_start, "ps5debug"))
notify(true, "Failed to load PS5Debug");
}
// Display IP and service info
std::string dpi_url = "Direct Package Installer V2: http://" + std::string(buz) + ":12800";
notify(true,
"etaHEN 2.4b by LM\n\nAIO HEN\n\nCurrent IP: %s\n\nFTP Port: "
"1337\nKlog Port: 9081\n%s",
buz, global_conf.DPIv2 ? dpi_url.c_str() : "");
const char json_payload[] =
"{\n"
" \"rawData\": {\n"
" \"viewTemplateType\": \"InteractiveToastTemplateB\",\n"
" \"channelType\": \"Downloads\",\n"
" \"useCaseId\": \"IDC\",\n"
" \"toastOverwriteType\": \"No\",\n"
" \"isImmediate\": true,\n"
" \"priority\": 100,\n"
" \"viewData\": {\n"
" \"icon\": {\n"
" \"type\": \"Url\",\n"
" \"parameters\": {\n"
" \"url\": \"/user/data/etaHEN/etahen.png\"\n"
" }\n"
" },\n"
" \"message\": {\n"
" \"body\": \"etaHEN 2.5B AIO HEN By LM\"\n"
" },\n"
" \"subMessage\": {\n"
" \"body\": \"Welcome to etaHEN\"\n"
" },\n"
" \"actions\": [\n"
" {\n"
" \"actionName\": \"Go to the etaHEN Toolbox\",\n"
" \"actionType\": \"DeepLink\",\n"
" \"defaultFocus\": true,\n"
" \"parameters\": {\n"
" \"actionUrl\": \"pssettings:play?function=debug_settings\"\n"
" }\n"
" }\n"
" ]\n"
" },\n"
" \"platformViews\": {\n"
" \"previewDisabled\": {\n"
" \"viewData\": {\n"
" \"icon\": {\n"
" \"type\": \"Predefined\",\n"
" \"parameters\": {\n"
" \"icon\": \"download\"\n"
" }\n"
" },\n"
" \"message\": {\n"
" \"body\": \"etaHEN Running\"\n"
" }\n"
" }\n"
" }\n"
" }\n"
" },\n"
" \"createdDateTime\": \"2025-12-14T03:14:51.473Z\",\n"
" \"localNotificationId\": \"588193127\"\n"
"}";
sceNotificationSend(0xFE, true, &json_payload[0]);
etaHEN_log("StartUp thread created!! - welcome to etaHEN");

View File

@@ -24,6 +24,7 @@ along with this program; see the file COPYING. If not, see
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <strings.h>
#include <sys/_pthreadtypes.h>
#include <sys/_stdint.h>
@@ -80,6 +81,9 @@ extern const unsigned int shellui_elf_size;
extern uint8_t fps_elf_start[];
extern const unsigned int fps_elf_size;
extern uint8_t dumper_elf_start[];
extern const unsigned int dumper_elf_size;
bool Inject_Toolbox(int pid, uint8_t *elf);
int sceKernelGetAppInfo(int pid, app_info_t *title);
int sceKernelGetProcessName(int pid, char *name);
@@ -346,51 +350,94 @@ int change_permissions_recursive(const char* path) {
}
#include <sys/stat.h>
struct ConfigState {
time_t last_modified = 0;
};
ConfigState config_state;
void LoadSettings() {
if (if_exists("/data/etaHEN/config.ini")) {
IniParser parser;
if (ini_parser_load( & parser, "/data/etaHEN/config.ini")) {
const char * libhijacker_cheats_str =
ini_parser_get( & parser, "Settings.libhijacker_cheats", "0");
const char * PS5Debug_str =
ini_parser_get( & parser, "Settings.PS5Debug", "0");
const char * start_option =
ini_parser_get( & parser, "Settings.StartOption", "0");
const char * DPI_v2 = ini_parser_get( & parser, "Settings.DPI_v2", "0");
const char * auto_eject_disc = ini_parser_get( & parser, "Settings.auto_eject_disc", "0");
// Check if the std::strings are not nullptr before converting
global_conf.libhijacker_cheats =
libhijacker_cheats_str ? atoi(libhijacker_cheats_str) : 0;
global_conf.PS5Debug = PS5Debug_str ? atoi(PS5Debug_str) : 0;
global_conf.start_opt =
start_option ? (StartOpts) atoi(start_option) : NONE;
global_conf.DPIv2 = DPI_v2 ? atoi(DPI_v2) : 0;
global_conf.toolbox_auto_start = atoi(ini_parser_get( & parser, "Settings.toolbox_auto_start", "1"));
global_conf.seconds = atol(ini_parser_get( & parser, "Settings.Rest_Mode_Delay_Seconds", "0"));
global_conf.debug_app_jb_msg = atoi(ini_parser_get( & parser, "Settings.APP_JB_Debug_Msg", "0"));
global_conf.auto_eject_disc = auto_eject_disc ? atoi(auto_eject_disc) : 0;
if (if_exists("/mnt/usb0/toolbox_auto_start"))
global_conf.toolbox_auto_start = false;
} else {
notify(true, "Failed to Read the Settings file");
}
} else {
// Create default config if it doesn't exist
struct stat file_stat;
const char* config_path = "/data/etaHEN/config.ini";
// Check if file exists and get its modification time
if (stat(config_path, &file_stat) != 0) {
// File doesn't exist, create default config
etaHEN_log("[Daemon] Config file not found. Creating default...");
std::string ini_file(
"[Settings]\nPS5Debug=0\nFTP=1\nlaunch_itemzflow="
"0\ndiscord_rpc=0\nAllow_data_in_sandbox=1\nDPI=0\ntoolbox_auto_start=1\nDPI_v2=0\nKlog=0\nAPP_JB_Debug_Msg=0\nauto_eject_disc=0\n");
int fd = open("/data/etaHEN/config.ini", O_WRONLY | O_CREAT | O_TRUNC, 0777);
int fd = open(config_path, O_WRONLY | O_CREAT | O_TRUNC, 0777);
if (fd >= 0) {
write(fd, ini_file.c_str(), ini_file.length());
close(fd);
notify(true, "etaHEN config created! @ /data/etaHEN/config.ini");
config_state.last_modified = 0;
}
return;
}
// Only reload if file has been modified since last load
if (file_stat.st_mtime <= config_state.last_modified) {
return; // File hasn't changed, skip reload
}
// File has changed, proceed with loading
etaHEN_log("[Daemon] Loading Settings...");
IniParser parser;
if (ini_parser_load(&parser, config_path)) {
etaHEN_log("[Daemon] Reading Settings...");
const char * libhijacker_cheats_str =
ini_parser_get(&parser, "Settings.libhijacker_cheats", "0");
const char * PS5Debug_str =
ini_parser_get(&parser, "Settings.PS5Debug", "0");
const char * start_option =
ini_parser_get(&parser, "Settings.StartOption", "0");
const char * DPI_v2 = ini_parser_get(&parser, "Settings.DPI_v2", "0");
const char * auto_eject_disc =
ini_parser_get(&parser, "Settings.auto_eject_disc", "0");
const char* fan_threshold =
ini_parser_get(&parser, "Settings.fan_threshold", "77");
const char* enable_fan_speed =
ini_parser_get(&parser, "Settings.enable_fan_speed", "0");
const char* overlay_fps =
ini_parser_get(&parser, "Settings.overlay_fps", "0");
etaHEN_log("fan_threshold: %s", fan_threshold);
etaHEN_log("enable_fan_speed: %s", enable_fan_speed);
global_conf.fan_threshold = fan_threshold ? atoi(fan_threshold) : 77;
global_conf.enable_fan_speed = enable_fan_speed ? atoi(enable_fan_speed) : 0;
global_conf.overlay_fps = overlay_fps ? atoi(overlay_fps) : 0;
global_conf.libhijacker_cheats =
libhijacker_cheats_str ? atoi(libhijacker_cheats_str) : 0;
global_conf.PS5Debug = PS5Debug_str ? atoi(PS5Debug_str) : 0;
global_conf.start_opt =
start_option ? (StartOpts) atoi(start_option) : NONE;
global_conf.DPIv2 = DPI_v2 ? atoi(DPI_v2) : 0;
global_conf.toolbox_auto_start =
atoi(ini_parser_get(&parser, "Settings.toolbox_auto_start", "1"));
global_conf.seconds =
atol(ini_parser_get(&parser, "Settings.Rest_Mode_Delay_Seconds", "0"));
global_conf.debug_app_jb_msg =
atoi(ini_parser_get(&parser, "Settings.APP_JB_Debug_Msg", "0"));
global_conf.auto_eject_disc = auto_eject_disc ? atoi(auto_eject_disc) : 0;
if (if_exists("/mnt/usb0/toolbox_auto_start"))
global_conf.toolbox_auto_start = false;
// Update last modified time after successful load
config_state.last_modified = file_stat.st_mtime;
} else {
notify(true, "Failed to Read the Settings file");
}
}
static pid_t find_pid(const char *name) {
int mib[4] = {1, 14, 8, 0};
pid_t pid = -1;
@@ -806,12 +853,83 @@ bool HookGame(UniquePtr<Hijacker>& hijacker, uint64_t alsr_b) {
}
int done_appid;
extern "C" int sceKernelGetCurrentFanDuty(int *unk, int *duty);
bool set_fan_threshold(int THRESHOLDTEMP) {
if(THRESHOLDTEMP > 100){
THRESHOLDTEMP = 100;
}
int fd = open("/dev/icc_fan", O_RDONLY, 0);
if (fd <= 0) {
notify(true, "Unable to Open Fan Settings!");
return false;
}
char data[10] = {0x00, 0x00, 0x00, 0x00, 0x00, static_cast<char>(THRESHOLDTEMP), 0x00, 0x00, 0x00, 0x00};
if(ioctl(fd, 0xC01C8F07, data) < 0) {
notify(true, "Unable to Set Fan Speed!");
close(fd);
return false;
}
close(fd);
//etaHEN_log("Fan speed set to %d%% THRESHOLDTEMP", THRESHOLDTEMP);
return true;
}
bool cmd_enable_fps_new(int appid) {
if(done_appid == appid){
// etaHEN_log("FPS already enabled for %x", appid);
return true;
}
etaHEN_log("Enabling fps for appid %d", appid);
sleep(5);
SuspendApp(appid);
char buz[100] = { 0 };
if (sceKernelMprotect(&buz[0], 100, 0x7) == 0) {
if (pause_resume_kstuff()) {
etaHEN_log("Paused kstuff...");
touch_file("/system_tmp/kstuff_paused");
}
}
int pid = get_game_pid();
if (pid < 0) {
pause_resume_kstuff();
notify(true, "Failed to get game pid");
return false;
}
if (!Inject_Toolbox(pid, fps_elf_start)) {
pause_resume_kstuff();
ForceKillProc(pid);
notify(true, "Failed to inject fps");
return false;
}
pause_resume_kstuff();
sleep(1);
ResumeApp(pid);
done_appid = appid;
return true;
}
bool cmd_enable_fps(int appid) {
if(done_appid == appid){
// etaHEN_log("FPS already enabled for %x", appid);
return true;
}
}
SuspendApp(appid);
@@ -878,7 +996,7 @@ bool cmd_enable_toolbox(){
sleep(global_conf.seconds);
}
notify(true, "Loading the etaHEN ToolBox...");
//notify(true, "Loading the etaHEN ToolBox...");
int pid = get_shellui_pid();
if (pid < 0) {
@@ -1180,6 +1298,44 @@ void handleIPC(struct clientArgs *client, std::string &inputStr,
reply(sender_app, true);
break;
}
case BREW_LAUNCH_DUMPER:{
#if 1
if (elfldr_spawn("/", STDOUT_FILENO, dumper_elf_start, "Dumper") < 0) {
notify(true, "Dumper is starting\nPlease wait...");
}
#endif
reply(sender_app, false);
break;
}
case BREW_ADJUST_FAN_SPEED: {
int speed = json_getInteger(json_getProperty(my_json, "speed"));
int enabled = json_getInteger(json_getProperty(my_json, "enabled"));
etaHEN_log("Adjusting Fan Speed to: %d", speed);
if (speed < 0 || speed > 100) {
notify(true, "Invalid fan speed: %d. Must be between 0 and 100.", speed);
reply(sender_app, true);
break;
}
global_conf.enable_fan_speed = enabled;
if (!enabled) {
notify(true, "Fan speed adjustment is disabled.");
set_fan_threshold(77);
reply(sender_app, false);
break;
}
if (set_fan_threshold(speed)) {
notify(true, "Fan threshold adjusted to %i°C.", speed);
global_conf.fan_threshold = speed;
reply(sender_app, false);
} else {
notify(true, "Failed to adjust fan speed.");
reply(sender_app, true);
}
break;
}
case BREW_KILL_DAEMON:{
is_handler_enabled = false;
exit(1337);
@@ -1201,7 +1357,7 @@ void handleIPC(struct clientArgs *client, std::string &inputStr,
}
case BREW_RELOAD_SETTINGS: {
LoadSettings();
// notify(true, "Reloaded Settings");
notify(true, "Reloaded Settings");
reply(sender_app, false);
break;
}
@@ -1214,8 +1370,8 @@ void handleIPC(struct clientArgs *client, std::string &inputStr,
break;
}
// kernel_set_ucred_authid(getpid(), 0x4801000000000013L);
change_permissions_recursive(path);
reply(sender_app, false);
change_permissions_recursive(path);
reply(sender_app, false);
break;
}
default:

View File

@@ -60,7 +60,7 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 ")
target_sources(${PROJECT_NAME} PRIVATE ${SrcFiles})
target_include_directories(${PROJECT_NAME} PRIVATE "${D_CWD}/include")
target_link_directories (${PROJECT_NAME} PUBLIC "${PROJECT_ROOT}/lib")
target_link_libraries (${PROJECT_NAME} PUBLIC hijacker ScePad SceSystemService SceNet SceSysmodule SceUserService SceNetCtl kernel )
target_link_libraries (${PROJECT_NAME} PUBLIC kernel SceGnmDriver)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Add post-build command

View File

@@ -17,7 +17,7 @@ along with this program; see the file COPYING. If not, see
#pragma once
extern "C" {
#include "ucred.h"
#include "external_symbols.hpp"
#include "defs.h"
#include "../lib/libmprotect.h"
#include <cstdint>
#include <sys/mman.h>

View File

@@ -15,10 +15,10 @@ along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#pragma once
#define PUBLIC_TEST 1
#define PRE_RELEASE 0
#define SHELL_DEBUG 1
#define etaHEN_VERSION "2.4"
#include <stdint.h>
#include <stddef.h>
extern "C" int sceKernelMprotect(void *addr, size_t len, int prot);
#define libSceKernelHandle 0x2001
#define KERNEL_DLSYM(handle, sym) \

View File

@@ -516,6 +516,7 @@ public:
return true;
}
}; // namespace IPC
#endif // IPC_HEADER_H

View File

@@ -1,5 +1,6 @@
extern "C"{
#include "../include/proc.h"
#include <ps5/klog.h>
}
struct proc* find_proc_by_name(const char* proc_name)
{
@@ -92,21 +93,24 @@ void list_proc_modules(struct proc* proc)
{
size_t num_handles = 0;
syscall(SYS_dl_get_list, proc->pid, NULL, 0, &num_handles);
klog_printf("Number of modules: %zu\n", num_handles);
if (num_handles)
{
uintptr_t* handles = (uintptr_t*) calloc(num_handles, sizeof(uintptr_t));
klog_printf("Allocated handles array at %p\n", handles);
syscall(SYS_dl_get_list, proc->pid, handles, num_handles, &num_handles);
klog_printf("Retrieved module handles for PID %d\n", proc->pid);
for (int i = 0; i < num_handles; ++i)
{
module_info_t mod_info;
bzero(&mod_info, sizeof(mod_info));
klog_printf("Getting info for handle %p\n", (void*)handles[i]);
syscall(SYS_dl_get_info_2, proc->pid, 1, handles[i], &mod_info);
printf("%s - ", mod_info.filename);
printf("%#02lx\n", mod_info.init);
klog_printf("%s - ", mod_info.filename);
klog_printf("%#02lx\n", mod_info.init);
}
free(handles);

View File

@@ -23,12 +23,26 @@ along with this program; see the file COPYING. If not, see
#include <cstdint>
#include <iostream>
#include "webserver.hpp"
#include <chrono>
#include <unistd.h>
#include <util.hpp>
extern "C" long ptr_syscall = 0;
#define u32 uint32_t
#define s32 int32_t
extern "C" {
long ptr_syscall = 0;
int sceKernelLoadStartModule(const char *moduleFileName, int args, const void *argp, int flags, void *opt, int *pRes) ;
int sceKernelDlsym(int handle, const char *symbol, void **addrp);
s32 sceGnmSubmitAndFlipCommandBuffersForWorkload(
u32 workload, u32 count, u32* dcb_gpu_addrs[], u32* dcb_sizes_in_bytes, u32* ccb_gpu_addrs[],
u32* ccb_sizes_in_bytes, u32 vo_handle, u32 buf_idx, u32 flip_mode, u32 flip_arg);
}
void __syscall() {
asm(".intel_syntax noprefix\n"
" mov rax, rdi\n"
@@ -56,6 +70,8 @@ extern "C" {
int sceKernelClockGettime(int clockId, OrbisKernelTimespec* tp);
}
static int frame_count = 0;
bool touch_file(const char* destfile) {
static constexpr int FLAGS = 0777;
int fd = open(destfile, O_WRONLY | O_CREAT | O_TRUNC, FLAGS);
@@ -66,71 +82,110 @@ bool touch_file(const char* destfile) {
return false;
}
typedef struct {
int32_t type; // 0x00
int32_t req_id; // 0x04
int32_t priority; // 0x08
int32_t msg_id; // 0x0C
int32_t target_id; // 0x10
int32_t user_id; // 0x14
int32_t unk1; // 0x18
int32_t unk2; // 0x1C
int32_t app_id; // 0x20
int32_t error_num; // 0x24
int32_t unk3; // 0x28
char use_icon_image_uri; // 0x2C
char message[1024]; // 0x2D
char uri[1024]; // 0x42D
char unkstr[1024]; // 0x82D
} OrbisNotificationRequest; // Size = 0xC30
void notify(const char* text, ...)
extern "C" int sceKernelSendNotificationRequest(int userId, OrbisNotificationRequest *request, size_t requestSize, int flags);
void printf_notification(const char* fmt, ...)
{
OrbisNotificationRequest req;
memset(&req, 0, sizeof(OrbisNotificationRequest));
char buff[1024];
OrbisNotificationRequest noti_buffer{};
// printf("******************** text: %s\n", text);
va_list args{};
va_start(args, fmt);
int len = vsnprintf(noti_buffer.message, sizeof(noti_buffer.message), fmt, args);
va_end(args);
va_list args{};
va_start(args, text);
vsnprintf(buff, sizeof(buff), text, args);
va_end(args);
req.type = 0;
req.unk3 = 0;
req.use_icon_image_uri = 1;
req.target_id = -1;
strncpy(req.uri, "cxml://psnotification/tex_icon_system", 38);
strncpy(req.message, buff, 1024);
game_log("Sending notification: %s", req.message);
sceKernelSendNotificationRequest(0, &req, sizeof(req), 0);
// these dont do anything currently
// that or the structure has changed
// lets just copy messages for now
/*
noti_buffer.type = 0;
noti_buffer.unk3 = 0;
noti_buffer.use_icon_image_uri = 0;
noti_buffer.target_id = -1;
*/
// trim newline
if (noti_buffer.message[len - 1] == '\n')
{
noti_buffer.message[len - 1] = '\0';
}
sceKernelSendNotificationRequest(0, (OrbisNotificationRequest*)&noti_buffer, sizeof(noti_buffer), 0);
}
#define KERNEL_DLSYM(handle, sym) \
(*(void**)&sym=(void*)kernel_dynlib_dlsym(-1, handle, #sym))
void CalculateAndPrintFPS() {
auto current_time = std::chrono::high_resolution_clock::now();
static auto last_time = current_time;
auto delta = std::chrono::duration<double>(current_time - last_time).count();
frame_count++;
if (delta >= 1.0) {
double fps = frame_count / delta;
// Send FPS
printf_notification("FPS %.2f", fps);
frame_count = 0;
last_time = current_time;
}
}
s32 (*sceGnmSubmitAndFlipCommandBuffersForWorkload_orig)(
u32 workload, u32 count, u32* dcb_gpu_addrs[], u32* dcb_sizes_in_bytes, u32* ccb_gpu_addrs[],
u32* ccb_sizes_in_bytes, u32 vo_handle, u32 buf_idx, u32 flip_mode, u32 flip_arg) = nullptr;
s32 sceGnmSubmitAndFlipCommandBuffersForWorkload_hook(
u32 workload, u32 count, u32* dcb_gpu_addrs[], u32* dcb_sizes_in_bytes, u32* ccb_gpu_addrs[],
u32* ccb_sizes_in_bytes, u32 vo_handle, u32 buf_idx, u32 flip_mode, u32 flip_arg) {
//printf("sceGnmSubmitAndFlipCommandBuffersForWorkload_hook called!\n");
CalculateAndPrintFPS();
int ret = sceGnmSubmitAndFlipCommandBuffersForWorkload_orig(
workload, count, dcb_gpu_addrs, dcb_sizes_in_bytes, ccb_gpu_addrs,
ccb_sizes_in_bytes, vo_handle, buf_idx, flip_mode, flip_arg);
if(ret == 0x80D11081){
printf("sceGnmSubmitAndFlipCommandBuffersForWorkload returned BUSY\n");
}
else
if(ret != 0) {
printf("sceGnmSubmitAndFlipCommandBuffersForWorkload returned error: %d\n", ret);
}
return ret;
}
int main(int argc, char const* argv[]) {
//OrbisKernelSwVersion sw;
char buff[256];
klog_puts("============== fps_elf Started =================");
printf_notification("fps_counter loaded!");
notify("fps_elf loaded!");
while(sceKernelMprotect(&buff, sizeof(buff), PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
klog_puts("sceKernelMprotect failed, retrying...");
sleep(1);
}
pid_t pid = getpid();
uintptr_t old_authid = set_ucred_to_debugger();
int libkernelsys_handle = get_module_handle(pid, "libkernel.sprx");
KERNEL_DLSYM(libkernelsys_handle, sceKernelDebugOutText);
KERNEL_DLSYM(libkernelsys_handle, sceKernelMkdir);
KERNEL_DLSYM(libkernelsys_handle, scePthreadCreate);
KERNEL_DLSYM(libkernelsys_handle, sceKernelMprotect);
KERNEL_DLSYM(libkernelsys_handle, sceKernelSendNotificationRequest);
KERNEL_DLSYM(libkernelsys_handle, sceKernelGetProsperoSystemSwVersion);
KERNEL_DLSYM(libkernelsys_handle, sceKernelGetAppInfo);
KERNEL_DLSYM(libkernelsys_handle, sceKernelGetProcessName);
game_log("Starting game ELF ....");
KERNEL_DLSYM(libSceKernelHandle, ioctl);
// get the yscall address for the ioctl hook
static __attribute__((used)) long getpid = 0;
KERNEL_DLSYM(libSceKernelHandle, getpid);
ptr_syscall = getpid;
ptr_syscall += 0xa; // jump directly to the syscall instruction
// file to let the main daemon know that its finished loading
touch_file("/system_tmp/fps_online");
set_proc_authid(pid, old_authid);
klog_printf("sceGnmSubmitAndFlipCommandBuffersForWorkload addr: %p\n", &sceGnmSubmitAndFlipCommandBuffersForWorkload);
sceGnmSubmitAndFlipCommandBuffersForWorkload_orig = (decltype(sceGnmSubmitAndFlipCommandBuffersForWorkload_orig))DetourFunction((uint64_t)&sceGnmSubmitAndFlipCommandBuffersForWorkload, (void*)&sceGnmSubmitAndFlipCommandBuffersForWorkload_hook);
while (true) {
game_log("sleeping ....");
sleep(0x100000);
sleep(0x10000);
}
return 0;

View File

@@ -30,7 +30,7 @@
</setting_list>
<setting_list id="id_etahen_credits" title="etaHEN Credits" second_title="Credits and Supporters">
<label id="id_etahen_creds_display" title="★ etaHEN Beta 2.4" style="center"/>
<label id="id_etahen_creds_display" title="★ etaHEN Beta 2.5" style="center"/>
<label id="id_lead_devs" title="★ Lead Developer(s) ★" style="center"/>
<label id="id_lead_devs_2" title="- LM (X @LightningMods_, GitHub @LightningMods, Discord @lm_dev)" style="center"/>
<label id="id_ddkdkd" title="★ etaHEN Contributors ★" style="center"/>

View File

@@ -33,7 +33,7 @@
<list_item id="id_overlay_pos_3" title="Bottom Left" value="2"/>
<list_item id="id_overlay_pos_4" title="Bottom Right" value="3"/>
</list>
<!-- <toggle_switch id="id_overlay_fps" title="FPS Section" description="Toggle the FPS Section from the game overlay" value="0"/> -->
<toggle_switch id="id_overlay_fps" title="*Experimental* PS4 FPS Section" description="Toggle the FPS Section from the game overlay NOTE: not for regular use yet" value="0"/>
<toggle_switch id="id_overlay_gpu" title="GPU Section" description="Toggle the GPU Section from the game overlay" value="0"/>
<toggle_switch id="id_overlay_cpu" title="CPU Section" description="Toggle the CPU Section from the game overlay" value="0"/>
<toggle_switch id="id_all_cpu_usage" title="Show ALL CPU Core Usage" description="Toggle the advanced CPU usage from the game overlay" value="0"/>
@@ -51,12 +51,19 @@
<list_item id="id_pause_kstuff_3" title="PS4 sysentvec Only" value="2"/>
<list_item id="id_pause_kstuff_4" title="Pause Both PS5 and PS4 sysentvecs" value="3"/>
</list>
<button id="id_download_kstuff" title="Replace kstuff with the latest Kstuff via Github" description="Downloads and Installs the latest kstuff from EchoStretch's Github Repo, will replace the one etaHEN auto loads on startup"/>
<toggle_switch id="id_pause_kstuff_on_open" title="Pause Kstuff on Game Launch" description="This will pause Kstuff when launching games or apps after the provided delay" value="0"/>
<text_field id="id_pause_kstuff_on_open_secs" title="Kstuff pause delay" second_title="Delay in seconds used for auto pausing kstuff after app launch" keyboard_type="number" min_length="1" max_length="3"/>
<toggle_switch id="id_enable_kstuff_on_close" title="Unpause Kstuff on Game Close" description="This will unpause Kstuff when closing games or apps, Note: if not paused no action will be taken" value="0"/>
<button id="id_download_kstuff" title="Replace kstuff with the latest Kstuff via Github" description="Downloads and Installs the latest kstuff from EchoStretch's Github Repo to /data/etaHEN/kstuff.elf, will replace the one etaHEN auto loads on startup"/>
<button id="id_delete_kstuff" title="Delete Kstuff installed via Github" description="This will switch back to etaHENs built-in kstuff"/>
<toggle_switch id="id_kstuff_autoload" title="Auto load Kstuff on etaHEN startup" value="0"/>
</setting_list>
<toggle_switch id="id_enable_fan_speed" title="Enable Manual Fan Speed Threshold" value="0"/>
<text_field id="id_fan_speed" title="Adjust Fan Threshold" second_title="Adjust Fan Threshold in celsius" keyboard_type="number" min_length="2" max_length="2"/>
<toggle_switch id="id_sistro_ps5debug" title="Enable PS5Debug by Sistr0 and CTN" value="0"/>
@@ -70,7 +77,7 @@
<toggle_switch id="id_ftp_dev_access" title="Allow FTP access to the /dev directory" value="0"/>
<!-- <link id="id_whitelist_menu" title="Whitelisted Apps (SuperUser) Menu" file="superuser.xml"/> -->
<!-- <link id="id_whitelist_menu" title="Whitelisted Apps (SuperUser) Menu" file="superuser.xml"/> -->
<!-- Debug setting extra 1 -->
<link id="id_licenseactivation" title="Blu-Ray (license) Activation" file="DebugSettings/data/debug_settings_licenseactivation.xml"/>
@@ -162,7 +169,7 @@
</setting_list>
<setting_list id="id_etahen_credits" title="etaHEN Credits" second_title="Credits and Supporters">
<label id="id_etahen_creds_display" title="★ etaHEN Beta 2.4" style="center"/>
<label id="id_etahen_creds_display" title="★ etaHEN Beta 2.5" style="center"/>
<label id="id_lead_devs" title="★ Lead Developer(s) ★" style="center"/>
<label id="id_lead_devs_2" title="- LM (X @LightningMods_, GitHub @LightningMods, Discord @lm_dev)" style="center"/>
<label id="id_ddkdkd" title="★ etaHEN Contributors ★" style="center"/>

View File

@@ -194,6 +194,11 @@ enum Cheats_Shortcut{
OVERLAY_POS_BOTTOM_RIGHT
};
enum cheats_repo_source{
CHEATS_REPO_ETAHEN = 0,
CHEATS_REPO_GOLDHEN
};
typedef struct etaHENSettings_t
{
bool FTP = true;
@@ -224,12 +229,17 @@ typedef struct etaHENSettings_t
bool overlay_ip = false;
bool overlay_kstuff = false;
bool overlay_kstuff_active = false;
bool enable_kstuff_on_close = false;
bool pause_kstuff_on_open = false;
bool all_cpu_usage = false;
int start_option = 0;
int trial_soft_expire_time = 0;
int kit_panel_info = 0;
int kstuff_pause_opt = NOT_PAUSED;
uint64_t rest_delay_seconds = 0;
bool enable_fan_speed = false;
int fan_threshold = 77;
int pause_kstuff_on_open_secs = 0;
// Shortcuts
Cheats_Shortcut cheats_shortcut_opt = CHEATS_SC_OFF;
@@ -254,6 +264,7 @@ typedef struct etaHENSettings_t
float overlay_ip_y = 110.0f;
overlay_positions overlay_pos = OVERLAY_POS_TOP_LEFT; //0=top left, 1=top right, 2=bottom left, 3=bottom right
cheats_repo_source selected_cheats_repo = CHEATS_REPO_ETAHEN;
} etaHENSettings;

View File

@@ -18,7 +18,7 @@ along with this program; see the file COPYING. If not, see
#define PUBLIC_TEST 0
#define PRE_RELEASE 0
#define SHELL_DEBUG 0
#define etaHEN_VERSION "2.4"
#define etaHEN_VERSION "2.5"
#define libSceKernelHandle 0x2001
#define KERNEL_DLSYM(handle, sym) \

View File

@@ -38,6 +38,8 @@ along with this program; see the file COPYING. If not, see
#include <unistd.h>
#include <vector>
#include <ps5/klog.h>
#include <iostream>
#include <fstream>
enum Cheat_Actions {
DOWNLOAD_CHEATS = 0,
@@ -112,7 +114,7 @@ public:
// erase the old message
bzero(msg.msg, sizeof(msg.msg));
int timeout_ms = 10 * 1000;
int timeout_ms = 25 * 1000;
// Set receive timeout
struct timeval tv;
tv.tv_sec = timeout_ms / 1000;
@@ -124,6 +126,7 @@ public:
return -1; // Error setting timeout
}
shellui_log("Waiting for daemon response...");
int ret = recv(socket_fd, reinterpret_cast<void*>(&msg), sizeof(msg), MSG_NOSIGNAL);
if (ret < 0) {
shellui_log("recv failed with: 0X%X", ret);
@@ -478,7 +481,7 @@ public:
return true;
}
bool Cheats_Action(Cheat_Actions act) {
bool Cheats_Action(Cheat_Actions act, int repo) {
DaemonCommands cmd;
if (!util_daemon) {
shellui_log("This IPC command is NOT in the main daemon");
@@ -497,12 +500,28 @@ public:
}
std::string ipc_msg;
if (!IPCSendCommand(cmd, ipc_msg)) {
std::string json = "{\"repo\": " + std::to_string(repo) + "}";
if (!IPCSendCommand(cmd, ipc_msg, json)) {
return false;
}
return true;
}
bool Set_Fan_Threshold(int temp, bool enabled) {
if (util_daemon) {
shellui_log("This IPC command is NOT in the util daemon");
return false;
}
std::string ipc_msg;
//and enabled
std::string json = "{\"speed\": " + std::to_string(temp) + ", \"enabled\": " + std::to_string(enabled) + "}";
if (!IPCSendCommand(BREW_ADJUST_FAN_SPEED, ipc_msg, json)) {
shellui_log("Failed to adjust fan speed");
return false;
}
return true;
}
bool ToggleDPI(bool turn_on, bool is_v2) {
if (!util_daemon) {
shellui_log("This IPC command is NOT in the main daemon");
@@ -520,6 +539,73 @@ public:
return true;
}
void Launch_Dumper() {
if (util_daemon) {
shellui_log("This IPC command is in the main daemon");
return;
}
std::string ipc_msg;
if (!IPCSendCommand(BREW_LAUNCH_DUMPER, ipc_msg)) {
shellui_log("Failed to launch dumper");
}
}
static void generate_default_games_xml(std::string &xml_buffer, bool game_shortcut_activated) {
std::string list_id = game_shortcut_activated ? "id_debug_settings" : "id_ps5_backups";
xml_buffer = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
"<system_settings version=\"1.0\" plugin=\"debug_settings_plugin\">\n"
"\n";
xml_buffer += "<setting_list id=\"" + list_id + "\" title=\"(Beta) PS5 webMAN Games (ERROR)\">\n";
xml_buffer += "</setting_list>\n</system_settings> ";
}
bool GetGamesList(bool cheats_activated_shortcut, std::string &games_list) {
if (!util_daemon) {
shellui_log("This IPC command is in the util daemon");
generate_default_games_xml(games_list, cheats_activated_shortcut);
return false;
}
std::string json = "{\"shortcut\": " + std::to_string(cheats_activated_shortcut) + "}";
if (!IPCSendCommand(BREW_UTIL_GET_GAMES_LIST, games_list, json)) {
shellui_log("Failed to get games list");
generate_default_games_xml(games_list, cheats_activated_shortcut);
return false;
}
std::ifstream file("/user/data/etaHEN/games_list.xml");
if (file) {
std::string content((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
games_list = content;
file.close();
return true;
} else {
shellui_log("Failed to open games list file: %s", games_list.c_str());
return false;
}
shellui_log("Games list: %s", games_list.c_str());
return true;
}
bool Launch_Game_By_ID(const std::string& button_id) {
if (!util_daemon) {
shellui_log("This IPC command is in the util daemon");
return false;
}
std::string ipc_msg;
std::string json = "{\"button_id\": \"" + button_id + "\"}";
if (!IPCSendCommand(BREW_UTIL_LAUNCH_GAME_BY_BUTTON_ID, ipc_msg, json)) {
shellui_log("Failed to launch game by button id: %s", button_id.c_str());
return false;
}
return true;
}
}; // namespace IPC
#endif // IPC_HEADER_H

View File

@@ -59,15 +59,6 @@ typedef enum {
MONO_IMAGE_IMAGE_INVALID
} MonoImageOpenStatus;
typedef struct app_launch_ctx
{
int structsize;
int user_id;
int app_opt;
uint64_t crash_report;
int check_flag;
} app_launch_ctx_t;
typedef guint32 mono_array_size_t;
typedef gint32 mono_array_lower_bound_t;
@@ -395,7 +386,7 @@ extern "C" {
} while (0)
int replace_all(unsigned char * buffer, int * buffer_size, int buffer_capacity, const char * target, const char * replacement);
int sceSystemServiceLaunchApp(const char *, char **, app_launch_ctx_t *);
#ifdef __cplusplus
}
#endif

View File

@@ -35,6 +35,8 @@ along with this program; see the file COPYING. If not, see
extern "C"{
#include <ps5/kernel.h>
}
extern bool is_6xx, is_3xx;
/* ================================= ORIG HOOKED MONO FUNCS ============================================= */
int (*oOnPress)(MonoObject* Instance, MonoObject* element, MonoObject* e) = nullptr;
int (*oOnPreCreate)(MonoObject* Instance, MonoObject* element) = nullptr;
@@ -543,6 +545,16 @@ void pause_resume_kstuff(KstuffPauseStatus opt, bool notify_user)
}
void* kstuff_pause_thread(void* arg){
sleep(2);
sleep(global_conf.pause_kstuff_on_open_secs);
if(!if_exists("/user/data/etaHEN/no_kstuff") && !if_exists("/usb0/etaHEN/no_kstuff")){
pause_resume_kstuff(BOTH_PAUSED, true);
}
return nullptr;
}
extern "C" int sceKernelGetSocSensorTemperature(int numb, int *temp);
extern "C" int sceNetGetIfList(SceNetIfName ifName_num, SceNetIfList* ifListArray, int n);
@@ -940,7 +952,6 @@ void* switch_to_lite(void*) {
main_ipc.KillDaemon();
notify("Lite mode is active!");
pause_resume_kstuff(NOT_PAUSED, false);
pthread_exit(nullptr);
return nullptr;
@@ -1020,10 +1031,10 @@ void* download_cheats_thr(void*){
return nullptr;
}
cheat_action_in_progress = true;
notify("Preparing to download the cheats repo...");
notify("Preparing to download the %s cheats repo...", global_conf.selected_cheats_repo == CHEATS_REPO_ETAHEN ? "etaHEN PS5" : "GoldHEN PS4");
IPC_Client& util_ipc = IPC_Client::getInstance(true);
// daemon shows notification when done
util_ipc.Cheats_Action(DOWNLOAD_CHEATS);
util_ipc.Cheats_Action(DOWNLOAD_CHEATS, global_conf.selected_cheats_repo);
cheat_action_in_progress = false;
pthread_exit(nullptr);
@@ -1038,7 +1049,7 @@ void* reload_cheats_thr(void*){
}
cheat_action_in_progress = true;
IPC_Client& util_ipc = IPC_Client::getInstance(true);
if (util_ipc.Cheats_Action(RELOAD_CHEATS))
if (util_ipc.Cheats_Action(RELOAD_CHEATS, 0))
notify("The Cheats have been Cache and cheats list has been successfully reloaded");
cheat_action_in_progress = false;
@@ -1079,6 +1090,7 @@ int OnPress_Hook(MonoObject* Instance, MonoObject* element, MonoObject* e)
bool& DPI_v2 = global_conf.DPI_v2;
int& kstuff_pause_opt = global_conf.kstuff_pause_opt;
bool& dis_tids = global_conf.display_tids;
cheats_repo_source& selected_cheats_repo = global_conf.selected_cheats_repo;
// Define the array of IDs to exclude (you can put this at the top of your function or as a static/global)
const std::vector<std::string> excludedIds = {
@@ -1104,7 +1116,7 @@ int OnPress_Hook(MonoObject* Instance, MonoObject* element, MonoObject* e)
std::string value = GetPropertyValue(element, "Value");
std::string title = GetPropertyValue(element, "Title");
bool is_game = (id.rfind("id_game_") != std::string::npos);
bool is_game = (id.rfind("id_etahen_game_loader_") != std::string::npos);
bool is_cust_pkg = (id.rfind("id_pkg_") != std::string::npos);
if (id.rfind("id_cheat_") != std::string::npos && !is_current_game_open) {
@@ -1188,9 +1200,12 @@ int OnPress_Hook(MonoObject* Instance, MonoObject* element, MonoObject* e)
}
if (!atoi(value.c_str())) {
RemoveGameWidget(REMOVE_FPS_OVERLAY);
unlink("/system_tmp/fps_enabled");
}
else {
CreateGameWidget(CREATE_FPS_OVERLAY);
touch_file("/system_tmp/fps_enabled");
}
global_conf.overlay_fps = !global_conf.overlay_fps;
@@ -1310,10 +1325,19 @@ int OnPress_Hook(MonoObject* Instance, MonoObject* element, MonoObject* e)
CreateGameWidget(CREATE_IP_OVERLAY);
}
}
else if (id == "id_enable_kstuff_on_close"){
global_conf.enable_kstuff_on_close = atoi(value.c_str());
}
else if (id == "id_pause_kstuff_on_open"){
global_conf.pause_kstuff_on_open = atoi(value.c_str());
}
else if (id == "id_pause_kstuff_on_open_secs") {
global_conf.pause_kstuff_on_open_secs = atol(value.c_str());
}
else if (id == "id_kstuff_autoload") {
if(atoi(value.c_str()) == if_exists("/user/data/etaHEN/no_kstuff")) {
return oOnPress(Instance, element, e);
}
// if(atoi(value.c_str()) == if_exists("/user/data/etaHEN/no_kstuff")) {
// return oOnPress(Instance, element, e);
//}
if(atol(value.c_str())){
unlink("/user/data/etaHEN/no_kstuff");
notify("Kstuff will be loaded on next boot");
@@ -1341,11 +1365,16 @@ int OnPress_Hook(MonoObject* Instance, MonoObject* element, MonoObject* e)
{
if (plugin.id == id)
{
int pid = -1;
if(plugin.tid.rfind(".elf") != std::string::npos && (pid = sceSystemServiceGetAppId(plugin.tid.c_str())) > 0){
IPC_Client::getInstance(false).ForceKillPID(pid);
notify("killed payload %s", plugin.tid.c_str());
break;
}
char pbuf[256];
snprintf(pbuf, sizeof(pbuf), "/system_tmp/%s.PID", plugin.tid.c_str());
int f = open(pbuf, O_RDONLY);
int pid = -1;
if (f >= 0)
{
char t[32];
@@ -1380,6 +1409,7 @@ int OnPress_Hook(MonoObject* Instance, MonoObject* element, MonoObject* e)
unlink(pbuf);
notify("%s killed", plugin.tid.c_str());
break;
}
else if (pid <= 0 && atol(value.c_str()) == 1)
{
@@ -1402,8 +1432,8 @@ int OnPress_Hook(MonoObject* Instance, MonoObject* element, MonoObject* e)
shellui_log("[Clicked %s] %s path: %s", selected_pkgs.id.c_str(), selected_pkgs.name.c_str(), selected_pkgs.shellui_path.c_str());
#endif
std::string dl_url;
if (0)
dl_url = "http:///192.168.123.116:1304" + selected_pkgs.shellui_path;
if (is_6xx)
dl_url = "http://127.0.0.1:12800" + selected_pkgs.path;
else
dl_url = (selected_pkgs.path.rfind("/data") != std::string::npos) ? selected_pkgs.shellui_path : selected_pkgs.path;
@@ -1422,7 +1452,7 @@ int OnPress_Hook(MonoObject* Instance, MonoObject* element, MonoObject* e)
shellui_log("Installing package from: %s", metainfo.uri);
int num = sceAppInstUtilInstallByPackage(&metainfo, &pkginfo, &playgoinfo);
if (num != 0) {
notify("Failed to install %s\nError: 0x%X", selected_pkgs.name.c_str(), num);
notify("Failed to install %s\nError: 0x%X\nis DPIv2 enabled???", selected_pkgs.name.c_str(), num);
}
else
{
@@ -1432,21 +1462,9 @@ int OnPress_Hook(MonoObject* Instance, MonoObject* element, MonoObject* e)
}
}
else if (is_game) {
if (games_list.empty()){
return oOnPress(Instance, element, e);
}
for (auto game : games_list) {
if (game.id == id) {
#if SHELL_DEBUG==1
shellui_log("[Clicked %s] TID: %s title: %s version: %s path: %s", game.id.c_str(), game.tid.c_str(), game.title.c_str(), game.version.c_str(), game.path.c_str());
#endif
notify("Launching %s (%s)\nPath: %s", game.title.c_str(), game.tid.c_str(), game.path.c_str());
//const char *path, const char* title_id, const char* title
int res = Launch_FG_Game(game.path.c_str(), game.tid.c_str(), game.title.c_str());
if (res < 0 && res != SCE_LNC_UTIL_ERROR_ALREADY_RUNNING_KILL_NEEDED && res != SCE_LNC_UTIL_ERROR_ALREADY_RUNNING && res != SCE_LNC_UTIL_ERROR_ALREADY_RUNNING_SUSPEND_NEEDED) {
notify("Failed to launch %s (%s)\nError: 0x%X", game.title.c_str(), game.tid.c_str(), res);
}
}
if(IPC_Client::getInstance(true).Launch_Game_By_ID(id) && global_conf.pause_kstuff_on_open){
pthread_t thread;
pthread_create(&thread, nullptr, kstuff_pause_thread, nullptr);
}
}
else if (id.rfind("id_auto_plugin") != std::string::npos) {
@@ -1546,6 +1564,15 @@ int OnPress_Hook(MonoObject* Instance, MonoObject* element, MonoObject* e)
dis_tids = !dis_tids;
ReloadRNPSApp("NPXS40002");
}
else if (id == "id_enable_fan_speed") {
if (atol(value.c_str()) == global_conf.enable_fan_speed) {
shellui_log("Fan speed control already %s", global_conf.enable_fan_speed ? "Enabled" : "Disabled");
return oOnPress(Instance, element, e);
}
global_conf.enable_fan_speed = !global_conf.enable_fan_speed;
IPC_Client::getInstance(false).Set_Fan_Threshold(global_conf.fan_threshold, global_conf.enable_fan_speed);
}
else if (id == "id_lm_test")
{
shellui_log("LM's Test Button Pressed");
@@ -1667,6 +1694,17 @@ int OnPress_Hook(MonoObject* Instance, MonoObject* element, MonoObject* e)
Auto_ItemzFlow = false;
shellui_log("Start option: %d", StartOption);
}
else if (id == "id_selected_cheats_repo") {
selected_cheats_repo = static_cast<cheats_repo_source>(atoi(value.c_str()));
shellui_log("Selected cheats repo: %s", selected_cheats_repo == CHEATS_REPO_ETAHEN ? "etaHEN PS5" : "GoldHEN PS4");
}
else if (id == "id_lite_mode") {
if (atoi(value.c_str()) == lite_mode) {
shellui_log("Lite Mode already %s", lite_mode ? "Enabled" : "Disabled");
return oOnPress(Instance, element, e);
}
lite_mode = !lite_mode;
}
else if (id == "id_trial_soft") {
trial_expire = atoi(value.c_str());
}
@@ -1715,6 +1753,16 @@ int OnPress_Hook(MonoObject* Instance, MonoObject* element, MonoObject* e)
else if (id == "id_rest_1") {
delay_secs = atol(value.c_str());
}
else if (id == "id_fan_speed") {
int &fan_speed = global_conf.fan_threshold;
fan_speed = atoi(value.c_str());
if(!global_conf.enable_fan_speed){
notify("Manual Fan speed threshold is not enabled");
return oOnPress(Instance, element, e);
}
shellui_log("Setting fan speed to %d%%", fan_speed);
IPC_Client::getInstance(false).Set_Fan_Threshold(fan_speed, global_conf.enable_fan_speed);
}
else if (id == "id_rest_2") {
if (atoi(value.c_str()) == util_rest_kill) {
shellui_log("util_rest_kill already %s", util_rest_kill ? "Enabled" : "Disabled");
@@ -1938,7 +1986,6 @@ int OnPress_Hook(MonoObject* Instance, MonoObject* element, MonoObject* e)
notify("%s killed", plugin.tid.c_str());
}
}
pause_resume_kstuff(BOTH_PAUSED, false);
if(!Try_connect_to_host(9021) && !IPC_Client::getInstance(true).Launch_Elfldr()){
notify("Failed to Launch Johns Elfldr, failed to enter lite mode");
return oOnPress(Instance, element, e);
@@ -2094,7 +2141,8 @@ uint64_t GetManifestResourceStream_Hook(uint64_t inst, MonoString* FileName) {
// shellui_log("games found");
}
generate_games_xml(new_xml_string, game_shortcut_activated);
//generate_games_xml(new_xml_string, game_shortcut_activated);
IPC_Client::getInstance(true).GetGamesList(game_shortcut_activated, new_xml_string);
game_shortcut_activated = false;
}
else if (is_tk_menu) {
@@ -2299,9 +2347,21 @@ int OnPreCreate_Hook(MonoObject* Instance, MonoObject* element) {
else if (id == "id_kstuff_autoload") {
s_MonoText = mono_string_new(Root_Domain, !if_exists("/user/data/etaHEN/no_kstuff") ? "1" : "0");
}
else if (id == "id_enable_kstuff_on_close") {
s_MonoText = mono_string_new(Root_Domain, global_conf.enable_kstuff_on_close ? "1" : "0");
}
else if (id == "id_pause_kstuff_on_open"){
s_MonoText = mono_string_new(Root_Domain, global_conf.pause_kstuff_on_open ? "1" : "0");
}
else if (id == "id_pause_kstuff_on_open_secs"){
s_MonoText = mono_string_new(Root_Domain, std::to_string(global_conf.pause_kstuff_on_open_secs).c_str());
}
else if (id == "id_disp_titleids"){
s_MonoText = mono_string_new(Root_Domain, global_conf.display_tids ? "1" : "0");
}
else if (id == "id_enable_fan_speed"){
s_MonoText = mono_string_new(Root_Domain, global_conf.enable_fan_speed ? "1" : "0");
}
else if (id == "id_ftp_service") {
s_MonoText = mono_string_new(Root_Domain, FTP ? "1" : "0");
}
@@ -2314,6 +2374,9 @@ int OnPreCreate_Hook(MonoObject* Instance, MonoObject* element) {
else if (id == "id_DPI_v2_service") {
s_MonoText = mono_string_new(Root_Domain, DPI_v2 ? "1" : "0");
}
else if (id == "id_selected_cheats_repo") {
s_MonoText = mono_string_new(Root_Domain, global_conf.selected_cheats_repo ? "1" : "0");
}
else if (id == "id_start_opt") {
int opt = global_conf.start_option;
if (global_conf.launch_itemzflow && !global_conf.start_option) {
@@ -2339,6 +2402,9 @@ int OnPreCreate_Hook(MonoObject* Instance, MonoObject* element) {
else if (id == "id_rest_1") {
s_MonoText = mono_string_new(Root_Domain, std::to_string(global_conf.rest_delay_seconds).c_str());
}
else if (id == "id_fan_speed") {
s_MonoText = mono_string_new(Root_Domain, std::to_string(global_conf.fan_threshold).c_str());
}
else if (id == "id_rest_2") {
s_MonoText = mono_string_new(Root_Domain, global_conf.util_rest_kill ? "1" : "0");
}
@@ -2460,7 +2526,21 @@ bool handle_uri_boot_common(MonoString* uri, int opt, MonoString* titleIdForBoot
cheats_shortcut_activated_not_open = true;
return true;
}
else if (uri_string == "etaHEN?Dump") {
#if SHELL_DEBUG==1
shellui_log("Dump URI detected");
#endif
IPC_Client::getInstance(false).Launch_Dumper();
return true; // Signal to redirect
}
else if (uri_string == "etaHEN?DL_UPDATE") {
#if SHELL_DEBUG==1
shellui_log("DL_UPDATE URI detected");
#endif
return true; // Signal to redirect
}
return false; // No redirect needed
}
@@ -2471,6 +2551,11 @@ bool handle_uri_boot_common(MonoString* uri, int opt, MonoString* titleIdForBoot
notify("Lite mode is enabled, shortcuts are disabled");
return boot_orig(uri, opt, titleIdForBootAction);
}
std::string uri_string = Mono_to_String(uri);
if(uri_string == "etaHEN?Dump") {
return boot_orig(mono_string_new(Root_Domain, "pshomeui:navigateToHome?bootCondition=psButton"), opt, titleIdForBootAction);
}
// Redirect to debug settings
return boot_orig(mono_string_new(Root_Domain, "pssettings:play?mode=settings&function=debug_settings"), opt, titleIdForBootAction);
}
@@ -2489,6 +2574,12 @@ bool handle_uri_boot_common(MonoString* uri, int opt, MonoString* titleIdForBoot
notify("Lite mode is enabled, shortcuts are disabled");
return boot_orig_2(uri, opt);
}
std::string uri_string = Mono_to_String(uri);
if(uri_string == "etaHEN?Dump") {
return boot_orig_2(mono_string_new(Root_Domain, "pshomeui:navigateToHome?bootCondition=psButton"), opt);
}
return boot_orig_2(mono_string_new(Root_Domain, "pssettings:play?function=debug_settings"), opt);
}
@@ -2850,11 +2941,26 @@ bool app_launched = false;
int LaunchApp(MonoString* titleId, uint64_t* args, int argsSize, LaunchAppParam *param){
#if 1
if(!if_exists("/system_tmp/patch_plugin")) {
#if SHELL_DEBUG == 1
shellui_log("patch plugin not running .. returning with orig");
#endif
app_launched = true;
return LaunchApp_orig(titleId, args, argsSize, param);
#if SHELL_DEBUG == 1
shellui_log("patch plugin not running .. returning with orig");
#endif
unsigned int ret = LaunchApp_orig(titleId, args, argsSize, param);
if (ret < 0) {
#if SHELL_DEBUG == 1
notify("LaunchApp failed with error code: %d", ret);
#endif
return ret;
}
app_launched = true;
if(global_conf.pause_kstuff_on_open && Mono_to_String(titleId) != "ITEM00001" && Mono_to_String(titleId).rfind("NPXS") == std::string::npos){
pthread_t thread;
shellui_log("Pausing Kstuff on app launch for %s in %d seconds", mono_string_to_utf8(titleId), global_conf.pause_kstuff_on_open_secs);
pthread_create(&thread, nullptr, kstuff_pause_thread, nullptr);
}
return ret;
}
#endif
#if SHELL_DEBUG == 1
@@ -2870,6 +2976,13 @@ int LaunchApp(MonoString* titleId, uint64_t* args, int argsSize, LaunchAppParam
return ret;
}
app_launched = true;
if(global_conf.pause_kstuff_on_open && Mono_to_String(titleId) != "ITEM00001" && Mono_to_String(titleId).rfind("NPXS") == std::string::npos){
pthread_t thread;
shellui_log("Pausing Kstuff on app launch for %s in %d seconds", mono_string_to_utf8(titleId), global_conf.pause_kstuff_on_open_secs);
pthread_create(&thread, nullptr, kstuff_pause_thread, nullptr);
}
#if SHELL_DEBUG == 1
notify("LaunchApp returned: %d", ret);
#endif
@@ -2988,9 +3101,9 @@ void createJson_hook(MonoObject* inst, MonoObject* array, MonoString* id, MonoSt
shellui_log("Updated menu titleId: %s", current_menu_tid.c_str());
#endif
}
#if 0
if(id_str == "MENU_ID_SAVE_DATA_MANAGEMENT_PS4_MANUAL"){
createJson(inst, array, mono_string_new(Root_Domain, "MENU_ID_CUST_UPDATES"), mono_string_new(Root_Domain, "★ Game Updates"), mono_string_new(Root_Domain, "etaHEN?Pick_Update"), actionId, nullptr, subMenu, enable);
#if 1
if(id_str == "MENU_ID_SAVE_DATA_MANAGEMENT_PS4_MANUAL" || id_str == "MENU_ID_SAVE_DATA_MANAGEMENT_PS5_MANUAL" || (id_str == "MENU_ID_UPDATE_HISTORY" && 0)){
createJson(inst, array, mono_string_new(Root_Domain, "MENU_ID_CUST_UPDATES"), mono_string_new(Root_Domain, "★ (Beta) Dump Game/App"), mono_string_new(Root_Domain, "etaHEN?Dump"), actionId, nullptr, subMenu, enable);
return;
}
#endif
@@ -3000,6 +3113,12 @@ void createJson_hook(MonoObject* inst, MonoObject* array, MonoString* id, MonoSt
return;
}
if(id_str == "MENU_ID_INTELLECTUAL_PROPERTY_NOTICES"){
std::string uri = "psappinst:pat-uninstall?titleid=" + current_menu_tid;
createJson(inst, array, mono_string_new(Root_Domain, "MENU_ID_REMOVE_UPDATE"), mono_string_new(Root_Domain, "★ Delete"), mono_string_new(Root_Domain, uri.c_str()), actionId, nullptr, subMenu, enable);
return;
}
createJson(inst, array, id, label, actionUrl, actionId, messageId, subMenu, enable);
}
@@ -3022,5 +3141,6 @@ void Terminate() {
IPC_Client& ipc = IPC_Client::getInstance(true);
ipc.SendRestModeAction();
}
pause_resume_kstuff(NOT_PAUSED, true);
oTerminate();
}

View File

@@ -32,7 +32,6 @@ along with this program; see the file COPYING. If not, see
#include "../../extern/tiny-json/tiny-json.hpp"
#include "proc.h"
#include <json.hpp>
#include <fstream>
#include <ctime>
#include <iostream>
@@ -256,86 +255,6 @@ void Widget_Append_Child(MonoObject* widget, MonoObject* child)
mono_runtime_invoke(appendChild, widget, args, nullptr);
}
int endswith(const char *string, const char *suffix)
{
size_t suffix_len = strlen(suffix);
size_t string_len = strlen(string);
if (string_len < suffix_len)
{
return 0;
}
return strncmp(string + string_len - suffix_len, suffix, suffix_len) != 0;
}
int chmod_bins(const char *path)
{
char buf[PATH_MAX + 1];
struct dirent *entry;
struct stat st;
DIR *dir;
if (stat(path, &st) != 0)
{
return -1;
}
if (endswith(path, ".prx") || endswith(path, ".sprx") || endswith(path, "/eboot.bin"))
{
chmod(path, 0755);
}
if (S_ISDIR(st.st_mode))
{
dir = opendir(path);
while (1)
{
entry = readdir(dir);
if (entry == nullptr)
{
break;
}
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
{
continue;
}
sprintf(buf, "%s/%s", path, entry->d_name);
chmod_bins(buf);
}
closedir(dir);
}
return 0;
}
int Launch_FG_Game(const char *path, const char* title_id, const char* title){
app_launch_ctx_t ctx = {0};
char dst[PATH_MAX + 1];
strcpy(dst, "/system_ex/app/");
strcat(dst, title_id);
//mkdir(dst, 0777);
sceUserServiceInitialize(0);
sceUserServiceGetForegroundUser(&ctx.user_id);
IPC_Client& main_ipc = IPC_Client::getInstance(false);
if(!main_ipc.Remount(path, dst)){
// shellui_log("Failed to mount app");
return -1;
}
chmod_bins(path);
char *argv[] = {(char*)title, nullptr};
return sceSystemServiceLaunchApp(title_id, &argv[0], &ctx);
}
int find_and_replace(unsigned char * buffer, int buffer_size,
const char * target,
const char * replacement) {
@@ -657,17 +576,27 @@ bool LoadSettings()
const char *jb_debug_msg_str = ini_parser_get(&parser, "Settings.APP_JB_Debug_Msg", "0");
const char *game_opts_str = ini_parser_get(&parser, "Settings.etaHEN_Game_Options", "1");
const char *auto_eject_disc_str = ini_parser_get(&parser, "Settings.auto_eject_disc", "0");
const char* overlay_ram = ini_parser_get(&parser, "Settings.overlay_ram", "1");
const char* overlay_cpu = ini_parser_get(&parser, "Settings.overlay_cpu", "1");
const char* overlay_gpu = ini_parser_get(&parser, "Settings.overlay_gpu", "1");
const char* overlay_fps = ini_parser_get(&parser, "Settings.overlay_fps", "0");
const char* overlay_ip = ini_parser_get(&parser, "Settings.overlay_ip", "0");
const char* overlay_position = ini_parser_get(&parser, "Settings.Overlay_pos", "0"); // 0: Top-Left, 1: Top-Right, 2: Bottom-Left, 3: Bottom-Right
const char* overlay_kstuff = ini_parser_get(&parser, "Settings.overlay_kstuff", "0");
const char* overlay_ram = ini_parser_get(&parser, "Settings.overlay_ram", "1");
const char* overlay_cpu = ini_parser_get(&parser, "Settings.overlay_cpu", "1");
const char* overlay_gpu = ini_parser_get(&parser, "Settings.overlay_gpu", "1");
const char* overlay_fps = ini_parser_get(&parser, "Settings.overlay_fps", "0");
const char* overlay_ip = ini_parser_get(&parser, "Settings.overlay_ip", "0");
const char* overlay_position = ini_parser_get(&parser, "Settings.Overlay_pos", "0"); // 0: Top-Left, 1: Top-Right, 2: Bottom-Left, 3: Bottom-Right
const char* overlay_kstuff = ini_parser_get(&parser, "Settings.overlay_kstuff", "0");
const char* enable_kstuff_on_close = ini_parser_get(&parser, "Settings.enable_kstuff_on_close", "0");
const char* id_pause_kstuff_on_open = ini_parser_get(&parser, "Settings.pause_kstuff_on_open", "0");
const char* id_pause_kstuff_on_open_secs = ini_parser_get(&parser, "Settings.pause_kstuff_on_open_secs", "10");
const char* fan_threshold = ini_parser_get(&parser, "Settings.fan_threshold", "77");
const char* enable_fan_speed = ini_parser_get(&parser, "Settings.enable_fan_speed", "0");
// Check if the strings are not nullptr before converting
global_conf.overlay_kstuff = overlay_kstuff ? atoi(overlay_kstuff) : 0;
global_conf.enable_kstuff_on_close = enable_kstuff_on_close ? atoi(enable_kstuff_on_close) : 0;
global_conf.pause_kstuff_on_open = id_pause_kstuff_on_open ? atoi(id_pause_kstuff_on_open) : 0;
global_conf.pause_kstuff_on_open_secs = id_pause_kstuff_on_open_secs ? atoi(id_pause_kstuff_on_open_secs) : 10;
global_conf.enable_fan_speed = enable_fan_speed ? atoi(enable_fan_speed) : 0;
global_conf.overlay_kstuff = overlay_kstuff ? atoi(overlay_kstuff) : 0;
global_conf.fan_threshold = fan_threshold ? atoi(fan_threshold) : 77;
global_conf.FTP = FTP_str ? atoi(FTP_str) : 0;
global_conf.etaHEN_game_opts = game_opts_str ? atoi(game_opts_str) : 0;
global_conf.display_tids = dip_tid ? atoi(dip_tid) : 0;
@@ -693,6 +622,9 @@ bool LoadSettings()
global_conf.overlay_cpu = overlay_cpu ? atoi(overlay_cpu) : 1;
global_conf.overlay_gpu = overlay_gpu ? atoi(overlay_gpu) : 1;
global_conf.overlay_fps = overlay_fps ? atoi(overlay_fps) : 0;
if (global_conf.overlay_fps ){
touch_file("/system_tmp/fps_enabled");
}
global_conf.overlay_ip = overlay_ip ? atoi(overlay_ip) : 0;
//apply ovelay pos values
@@ -808,6 +740,11 @@ bool SaveSettings()
buff += "overlay_fps=" + std::to_string(global_conf.overlay_fps) + "\n";
buff += "overlay_ip=" + std::to_string(global_conf.overlay_ip) + "\n";
buff += "overlay_kstuff=" + std::to_string(global_conf.overlay_kstuff) + "\n";
buff += "enable_kstuff_on_close=" + std::to_string(global_conf.enable_kstuff_on_close) + "\n";
buff += "pause_kstuff_on_open=" + std::to_string(global_conf.pause_kstuff_on_open) + "\n";
buff += "enable_fan_speed=" + std::to_string(global_conf.enable_fan_speed) + "\n";
buff += "fan_threshold=" + std::to_string(global_conf.fan_threshold) + "\n";
buff += "pause_kstuff_on_open_secs=" + std::to_string(global_conf.pause_kstuff_on_open_secs) + "\n";
//shortcuts
buff += "Cheats_shortcut_opt=" + std::to_string(global_conf.cheats_shortcut_opt) + "\n";
buff += "Toolbox_shortcut_opt=" + std::to_string(global_conf.toolbox_shortcut_opt) + "\n";
@@ -1166,7 +1103,7 @@ void generate_plugin_xml(std::string &xml_buffer, bool plugins_xml)
}
else if(is_elf){
strncpy(header.prefix, "<elf>", 5);
strncpy(header.plugin_version, "?.??", 4);
strncpy(header.plugin_version, "", 4);
}
shellui_log("Valid plugin file.");
@@ -1181,11 +1118,13 @@ void generate_plugin_xml(std::string &xml_buffer, bool plugins_xml)
shown_path = (path.substr(0, 4) == "/usb") ? "/mnt" + path : shown_path;
std::string version_str = !is_elf ? "(v" + std::string(header.plugin_version) + ")" : "";
id = plugins_xml ? "id_plugin_" + std::to_string(toggle_switch_id++) : "id_auto_plugin_" + std::to_string(toggle_switch_id++);
if (plugins_xml)
toggle_switch = "<toggle_switch id=\"" + id + "\" title=\"" + entry->d_name + " (v" + header.plugin_version + ")\" second_title=\"Start/Stop " + entry->d_name + " (Path: " + shown_path + ") (" + (is_elf ? entry->d_name : header.titleID) + ")\" value=\"0\"/>\n";
toggle_switch = "<toggle_switch id=\"" + id + "\" title=\"" + entry->d_name + " " + version_str + "\" second_title=\"Start/Stop " + entry->d_name + " (Path: " + shown_path + ") (" + (is_elf ? entry->d_name : header.titleID) + ")\" value=\"0\"/>\n";
else
toggle_switch = "<toggle_switch id=\"" + id + "\" title=\"" + entry->d_name + " (v" + header.plugin_version + ")\" second_title=\"Enable/Disable auto start for " + entry->d_name + " (" + shown_path + ")\" value=\"0\"/>\n";
toggle_switch = "<toggle_switch id=\"" + id + "\" title=\"" + entry->d_name + " " + version_str + "\" second_title=\"Enable/Disable auto start for " + entry->d_name + " (" + shown_path + ")\" value=\"0\"/>\n";
xml_buffer += toggle_switch;
new_list.tid = (is_elf ? entry->d_name : header.titleID);
@@ -1372,213 +1311,6 @@ void escapeXML(std::string& input)
}
}
bool getContentInfofromJson(const std::string& file_path, std::string& tid, std::string& title, std::string &ver) {
try {
std::ifstream input_file(file_path);
if (!input_file.is_open()) {
shellui_log("Failed to open file for reading: %s", file_path.c_str());
return false;
}
json j;
input_file >> j;
input_file.close();
if (!j.contains("titleId")) {
shellui_log("JSON does not contain a required value");
return false;
}
tid = j["titleId"];
#if SHELL_DEBUG==1
shellui_log("getContentInfofromJson Title ID: %s", tid.c_str());
#endif
if (j.contains("localizedParameters") && j["localizedParameters"].contains("defaultLanguage")) {
std::string defaultLanguage = j["localizedParameters"]["defaultLanguage"];
if (j["localizedParameters"].contains(defaultLanguage) && j["localizedParameters"][defaultLanguage].contains("titleName")) {
title = j["localizedParameters"][defaultLanguage]["titleName"];
}
}
else
title = "App Title not found";
if (j.contains("contentVersion"))
ver = j["contentVersion"];
}
catch (const std::exception& e) {
shellui_log("Exception: %s", e.what());
return false;
}
return true;
}
int list_directories(const char *path) {
DIR *dir;
struct dirent *entry;
struct stat statbuf;
char fullpath[1024];
// Open the directory
if ((dir = opendir(path)) == NULL) {
perror("opendir");
return -1;
}
shellui_log("Directories in %s:\n", path);
// Read directory entries
while ((entry = readdir(dir)) != NULL) {
// Skip "." and ".." entries
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
// Construct the full path
snprintf(fullpath, sizeof(fullpath), "%s/%s", path, entry->d_name);
// Get information about the file
if (stat(fullpath, &statbuf) == -1) {
perror("stat");
continue;
}
// Check if it's a directory
if (S_ISDIR(statbuf.st_mode)) {
shellui_log("%s", entry->d_name);
}
}
closedir(dir);
return 0;
}
// Function to escape a string for XML
void generate_games_xml(std::string &xml_buffer, bool game_shortcut_activated)
{
struct dirent *entry;
// do outside func
// games_list.clear();
std::vector<std::string> directories = {
"/user/data/etaHEN/games",
"/usb0/etaHEN/games",
"/usb1/etaHEN/games",
"/usb2/etaHEN/games",
"/usb3/etaHEN/games",
"/mnt/ext1/etaHEN/games",
"/mnt/ext2/etaHEN/games",
"/mnt/ext0/etaHEN/games",
};
// list_directories("/mnt/sandbox/NPXS40087_000");
std::string list_id = game_shortcut_activated ? "id_debug_settings" : "id_ps5_backups";
xml_buffer = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
"<system_settings version=\"1.0\" plugin=\"debug_settings_plugin\">\n"
"\n";
xml_buffer += "<setting_list id=\"" + list_id + "\" title=\"(Beta) PS5 webMAN Games\">\n";
// Initialize random number generator
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> dist(1000, 9999);
for (const auto &directory : directories)
{
DIR *dir = opendir(directory.c_str());
// Open the directory
if (!dir)
{
#if SHELL_DEBUG==1
shellui_log("Failed to open directory: %s", directory.c_str());
#endif
continue;
}
// Iterate over each entry in the games directory
while ((entry = readdir(dir)) != nullptr)
{
// Skip . and .. directories
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
std::string game_dir = directory + "/" + entry->d_name;
// Check if this is a directory by trying to open it
struct stat st;
if (stat(game_dir.c_str(), &st) != 0 || !S_ISDIR(st.st_mode)) {
#if SHELL_DEBUG==1
shellui_log("Skipping non-directory: %s", game_dir.c_str());
#endif
continue;
}
std::string param_path = game_dir + "/sce_sys/param.json";
std::string icon_path = game_dir + "/sce_sys/icon0.png";
// Check if param.json exists
if (access(param_path.c_str(), F_OK) != 0) {
#if SHELL_DEBUG==1
shellui_log("No param.json found in: %s", game_dir.c_str());
#endif
continue;
}
#if SHELL_DEBUG==1
shellui_log("Found Game: %s", game_dir.c_str());
#endif
// Parse the JSON to get title_id, content_id, title, and version
std::string title_id, title, ver;
if (!getContentInfofromJson(param_path, title_id, title, ver)) {
#if SHELL_DEBUG==1
shellui_log("Failed to parse param.json in: %s", game_dir.c_str());
#endif
continue;
}
std::string shown_path = game_dir; // Initialize with the original path
const std::string prefix = "/user";
if (shown_path.find(prefix) == 0) { // Check if the path starts with "/user"
shown_path = shown_path.substr(prefix.length()); // Remove "/user"
}
shown_path = (game_dir.substr(0, 4) == "/usb") ? "/mnt" + game_dir : shown_path;
// Generate a random number for the ID
int random_num = dist(gen);
// Escape the icon path for XML
escapeXML(icon_path);
// Create and populate a GameEntry
GameEntry game;
game.tid = title_id;
game.title = title;
game.version = ver;
game.path = shown_path;
game.dir_name = entry->d_name;
game.icon_path = icon_path;
game.id = "id_game_" + title_id + "_" + std::to_string(random_num);
// Add to the games list
games_list.push_back(game);
// Format the button XML
std::string button = "<button id=\"" + game.id + "\" title=\"(" + title_id + ") " + title +
"\" icon=\"" + icon_path + "\" second_title=\"" + shown_path + " | Version: " + ver + "\"/>\n";
xml_buffer += button;
}
//shellui_log("cloaing dir %s", directory.c_str());
closedir(dir);
}
xml_buffer += "</setting_list>\n</system_settings> ";
}
void ReloadRNPSApp(const char* title_id){
void (*ReloadApp)(MonoString* tid) = (void(*)(MonoString*))Get_Address_of_Method(react_common_img, "ReactNative.Vsh.Common", "ReactApplicationSceneManager", "ReloadApp", 1);
@@ -1596,7 +1328,12 @@ void generate_cheats_xml(std::string &new_xml, std::string& not_open_tid, bool r
std::string list_id = running_as_debug_settings ? "id_debug_settings" : "id_cheat_title";
// buttons for if nothing is found
std::string dl_cheats = R"(<button id="id_dl_cheats" title="Download/Update Cheats" second_title="Downloads the latest cheats from the PS5_Cheats GitHub repo"/>)";
std::string dl_cheats = R"(<list id="id_selected_cheats_repo" title="Cheats Repo Source" >
<list_item id="id_selected_cheats_repo_1" title="etaHEN PS5 Cheats repo" value="0"/>
<list_item id="id_selected_cheats_repo_2" title="GoldHEN PS4 Cheats repo" value="1"/>
</list>
<button id="id_dl_cheats" title="Download/Update Cheats" second_title="Downloads the latest cheats from the selected GitHub repo"/>)";
std::string reload_cheats = R"(<button id="id_reload_cheats" title="Cache and reload Cheats list" second_title="New cheats added to /data/etaHEN/cheats/EXT_HERE will be cached and the cheats list will be reloaded"/>)";
//
@@ -1859,7 +1596,7 @@ void generate_plapps_xml(std::string& new_xml) {
game.dir_name = entry->d_name;
escapeXML(game.dir_name);
game.icon_path = icon_path;
game.id = "id_game_" + title_id + "_" + std::to_string(random_num);
game.id = "id_etahen_pl_loader_" + title_id + "_" + std::to_string(random_num);
// Add to the games list
games_list.push_back(game);

View File

@@ -82,6 +82,42 @@ void ReloadApp(MonoString *str){
Orig_ReloadApp(str);
}
#define PLAYGOSCENARIOID_SIZE 3
#define CONTENTID_SIZE 0x30
#define LANGUAGE_SIZE 8
typedef char playgo_scenario_id_t[PLAYGOSCENARIOID_SIZE];
typedef char language_t[LANGUAGE_SIZE];
typedef char content_id_t[CONTENTID_SIZE];
typedef struct
{
content_id_t content_id;
int content_type;
int content_platform;
} SceAppInstallPkgInfo;
typedef struct
{
const char* uri;
const char* ex_uri;
const char* playgo_scenario_id;
const char* content_id;
const char* content_name;
const char* icon_url;
} MetaInfo;
#define NUM_LANGUAGES 30
#define NUM_IDS 64
typedef struct {
language_t languages[NUM_LANGUAGES];
playgo_scenario_id_t playgo_scenario_ids[NUM_IDS];
content_id_t content_ids[NUM_IDS];
long unknown[810];
} PlayGoInfo;
//int _AppInstUtilInstallByPackage(string uri, string ex_uri, string playgo_scenario_id, string content_id, string content_name, string icon_url, uint slot, bool is_playgo_enabled, ref AppInstUtilWrapper.SceAppInstallPkgInfo pkg_info, string[] languages, string[] playgo_scenario_ids, string[] content_ids);
int (*Orig_AppInstUtilInstallByPackage)(MonoString* uri, MonoString* ex_uri, MonoString* playgo_scenario_id, MonoString* content_id, MonoString* content_name, MonoString* icon_url, uint32_t slot, bool is_playgo_enabled, MonoObject* pkg_info, MonoArray* languages, MonoArray* playgo_scenario_ids, MonoArray* content_ids) = nullptr;
@@ -150,6 +186,21 @@ Proc_Stats Stat_Data[3072];
thread_usages gThread_Data[2];
extern "C" int sceLncUtilKillAppWithReason(int appId, int reason);
void pause_resume_kstuff(KstuffPauseStatus opt, bool notify_user);
int KillAppWithReason_Hook(int appId, int reason)
{
// shellui_log("KillAppWithReason_Hook called with appId: %d, reason: %d", appId, reason);
//notify("Killing app %d", appId);
if(global_conf.enable_kstuff_on_close)
pause_resume_kstuff(NOT_PAUSED, true);
int ret = sceLncUtilKillAppWithReason(appId, reason);
//shellui_log("KillAppWithReason_Hook returned: %d", ret);
return ret;
}
void Get_Page_Table_Stats(int vm, int type, int* Used, int* Free, int* Total)
{
int _Total = 0, _Free = 0;
@@ -243,8 +294,94 @@ public:
}
};
AtomicString fps_string;
void* search_bytes(const void* haystack, size_t haystack_len,
const void* needle, size_t needle_len){
if (needle_len == 0 || needle_len > haystack_len) {
return NULL;
}
const unsigned char* h = (const unsigned char*)haystack;
const unsigned char* n = (const unsigned char*)needle;
for (size_t i = 0; i <= haystack_len - needle_len; i++) {
if (memcmp(&h[i], n, needle_len) == 0) {
return (void*)&h[i];
}
}
return NULL;
}
void ShellHexDump(const void* data, size_t size) {
const unsigned char* byteData = static_cast<const unsigned char*>(data);
char line[256];
for (size_t i = 0; i < size; i += 16) {
int pos = 0;
// Offset
pos += snprintf(line + pos, sizeof(line) - pos, "%08zx ", i);
// Hex bytes
for (size_t j = 0; j < 16; ++j) {
if (i + j < size) {
pos += snprintf(line + pos, sizeof(line) - pos, "%02x ",
byteData[i + j]);
} else {
pos += snprintf(line + pos, sizeof(line) - pos, " ");
}
}
pos += snprintf(line + pos, sizeof(line) - pos, " ");
// ASCII representation
for (size_t j = 0; j < 16; ++j) {
if (i + j < size) {
unsigned char c = byteData[i + j];
pos += snprintf(line + pos, sizeof(line) - pos, "%c",
isprint(c) ? c : '.');
}
}
shellui_log(line);
}
}
AtomicString fps_string;
ssize_t(*read_orig)(int fd, void *buf, size_t count) = nullptr;
ssize_t read_hook(int fd, void* buf, size_t count) {
ssize_t ret = read_orig(fd, buf, count);
// shellui_log("read_hook called: fd=%d, count=%zu, ret=%zd", fd, count, ret);
if (count == 65536) {
void* found = search_bytes(buf, 100, "FPS", 3);
if (found) {
const char* fps_ptr = (const char*)found;
// Skip "FPS" and any separators (: = space etc)
fps_ptr += 3; // Skip "FPS"
while (*fps_ptr && !isdigit(*fps_ptr)) {
fps_ptr++;
}
// Extract the number
std::string fps_value;
while (*fps_ptr && (isdigit(*fps_ptr) || *fps_ptr == '.')) {
fps_value += *fps_ptr;
fps_ptr++;
}
if (!fps_value.empty()) {
fps_string.store(fps_value);
// shellui_log("Captured FPS: %s", fps_value.c_str());
}
return -1;
}
}
return ret;
}
int get_ip_address(char* ip_address);
void OnRender_Hook(MonoObject* instance)
@@ -276,7 +413,7 @@ void OnRender_Hook(MonoObject* instance)
if (!Do_Once)
{
#if 0
#if 1
fps_string.store("LOADING");
#else
fps_string.store("NOT SUPPORTED IN THIS BUILD");
@@ -420,6 +557,145 @@ void OnRender_Hook(MonoObject* instance)
}
int (*sceAppInstUtilInstallByPackage_orig)(MetaInfo* arg1, SceAppInstallPkgInfo* pkg_info, PlayGoInfo* arg2) = nullptr;
void hex_dump(const char* label, const void* data, size_t size) {
const unsigned char* bytes = (const unsigned char*)data;
shellui_log("=== %s (size: %zu bytes) ===", label, size);
for (size_t i = 0; i < size; i += 16) {
char line[128];
int offset = 0;
// Print offset
offset += snprintf(line + offset, sizeof(line) - offset,
"%04zx: ", i);
// Print hex values
for (size_t j = 0; j < 16; j++) {
if (i + j < size) {
offset += snprintf(line + offset, sizeof(line) - offset,
"%02x ", bytes[i + j]);
}
else {
offset += snprintf(line + offset, sizeof(line) - offset,
" ");
}
}
// Print ASCII representation
offset += snprintf(line + offset, sizeof(line) - offset, " |");
for (size_t j = 0; j < 16 && i + j < size; j++) {
unsigned char c = bytes[i + j];
offset += snprintf(line + offset, sizeof(line) - offset,
"%c", (c >= 32 && c <= 126) ? c : '.');
}
offset += snprintf(line + offset, sizeof(line) - offset, "|");
shellui_log("%s", line);
}
}
extern "C" int sceAppInstUtilInitialize();
int sceAppInstUtilInstallByPackage_hook(MetaInfo* arg1,
SceAppInstallPkgInfo* pkg_info,
PlayGoInfo* arg2) {
shellui_log("========== sceAppInstUtilInstallByPackage_hook ==========");
sceAppInstUtilInitialize();
// Print MetaInfo
if (arg1) {
shellui_log("--- MetaInfo ---");
shellui_log("uri: %s", arg1->uri ? arg1->uri : "(null)");
shellui_log("ex_uri: %s", arg1->ex_uri ? arg1->ex_uri : "(null)");
shellui_log("playgo_scenario_id: %s",
arg1->playgo_scenario_id ? arg1->playgo_scenario_id : "(null)");
shellui_log("content_id: %s",
arg1->content_id ? arg1->content_id : "(null)");
shellui_log("content_name: %s",
arg1->content_name ? arg1->content_name : "(null)");
shellui_log("icon_url: %s",
arg1->icon_url ? arg1->icon_url : "(null)");
}
else {
shellui_log("MetaInfo: (null)");
}
// Print SceAppInstallPkgInfo
if (pkg_info) {
shellui_log("--- SceAppInstallPkgInfo ---");
shellui_log("content_id: %.*s", CONTENTID_SIZE, pkg_info->content_id);
shellui_log("content_type: %d", pkg_info->content_type);
shellui_log("content_platform: %d", pkg_info->content_platform);
}
else {
shellui_log("SceAppInstallPkgInfo: (null)");
}
// Print PlayGoInfo
if (arg2) {
shellui_log("--- PlayGoInfo ---");
// Print languages
shellui_log("Languages:");
for (int i = 0; i < NUM_LANGUAGES; i++) {
if (arg2->languages[i][0] != '\0') {
shellui_log(" [%d]: %.*s", i, LANGUAGE_SIZE,
arg2->languages[i]);
}
}
// Print playgo_scenario_ids
shellui_log("PlayGo Scenario IDs:");
for (int i = 0; i < NUM_IDS; i++) {
if (arg2->playgo_scenario_ids[i][0] != '\0') {
shellui_log(" [%d]: %.*s", i, PLAYGOSCENARIOID_SIZE,
arg2->playgo_scenario_ids[i]);
}
}
// Print content_ids
shellui_log("Content IDs:");
for (int i = 0; i < NUM_IDS; i++) {
if (arg2->content_ids[i][0] != '\0') {
shellui_log(" [%d]: %.*s", i, CONTENTID_SIZE,
arg2->content_ids[i]);
}
}
// Hex dump unknown portion
hex_dump("PlayGoInfo::unknown", arg2->unknown,
sizeof(arg2->unknown));
}
else {
shellui_log("PlayGoInfo: (null)");
}
shellui_log("========== Calling Original Function ==========");
notify("Installing package from:\n%s",
arg1 ? (arg1->uri ? arg1->uri : "(null)") : "(null)");
int ret = sceAppInstUtilInstallByPackage_orig(arg1, pkg_info, arg2);
shellui_log("sceAppInstUtilInstallByPackage_hook returned: %d", ret);
notify("Installation finished with code: %d", ret);
return ret;
}
bool is_6xx = false, is_3xx = false;
void* dialogue_thread(void* arg) {
while (true) {
sleep(1);
if(if_exists("/user/data/test.flag")){
unlink("/user/data/test.flag");
}
}
return nullptr;
}
int main(int argc, char const *argv[]) {
OrbisKernelSwVersion sw;
char buz[100];
@@ -428,10 +704,15 @@ int main(int argc, char const *argv[]) {
}
static ssize_t(*read)(int fd, void* buf, size_t count) = nullptr;
static int (*sceAppInstUtilInstallByPackage)(MetaInfo * arg1, SceAppInstallPkgInfo * pkg_info, PlayGoInfo * arg2) = nullptr;
pid_t pid = getpid();
uintptr_t old_authid = set_ucred_to_debugger();
int appinstaller_handle = get_module_handle(pid, "libSceAppInstUtil.sprx");
KERNEL_DLSYM(appinstaller_handle, sceAppInstUtilInstallByPackage);
int libkernelsys_handle = get_module_handle(pid, "libkernel_sys.sprx");
@@ -623,7 +904,8 @@ int main(int argc, char const *argv[]) {
std::string term = base64_decode("VGVybWluYXRl"); // "Terminate"
sceKernelGetProsperoSystemSwVersion(&sw);
bool is_3xx = (sw.version < 0x4000042);
is_3xx = (sw.version < 0x4000042);
is_6xx = (sw.version >= 0x6000000);
shellui_log("System Software Version: %s is_3xx: %s", sw.version_str, is_3xx ? "Yes" : "No");
#if 0
@@ -655,7 +937,7 @@ int main(int argc, char const *argv[]) {
dec_ver += etaHEN_VERSION;
std::string final_ver;
#if PUBLIC_TEST == 1
final_ver = dec_ver + " -PUBLIC_TEST" + " (" + sw.version_str + " )";
final_ver = dec_ver + "-PUBLIC_TEST" + " (" + sw.version_str + " )";
#elif PRE_RELEASE == 1
final_ver = dec_ver + " PRE_RELEASE" + " (" + sw.version_str + " )";
#else
@@ -779,8 +1061,6 @@ int main(int argc, char const *argv[]) {
}
shellui_log("Game ContainerScene: %p", Game);
OnRender_orig = (void(*)(MonoObject*)) DetourFunction(Get_Address_of_Method(pui_img, "Sce.PlayStation.PUI", "Application", "Update", 0), (void*)&OnRender_Hook);
}
// System.Reflection.RuntimeAssembly.GetManifestResourceStream
@@ -795,24 +1075,33 @@ int main(int argc, char const *argv[]) {
shellui_log("Kstuff Paused, resuming kstuff");
pause_resume_kstuff(NOT_PAUSED, false);
unlink("/system_tmp/kstuff_paused");
while(sceKernelMprotect(&buz, sizeof(buz), PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
klog_puts("sceKernelMprotect failed, retrying...");
sleep(1);
}
}
has_hv_bypass = (sceKernelMprotect( & buz[0], 100, 0x7) == 0);
//SimpleHTTPServer server(1304, "/");
//server.start();
Patch_Main_thread_Check(image_core);
OnRender_orig = (void(*)(MonoObject*)) DetourFunction(Get_Address_of_Method(pui_img, "Sce.PlayStation.PUI", "Application", "Update", 0), (void*)&OnRender_Hook);
#if 0
Orig_AppInstUtilInstallByPackage = (int (*)(MonoString * uri, MonoString * ex_uri, MonoString * playgo_scenario_id, MonoString * content_id, MonoString * content_name, MonoString * icon_url, uint32_t slot, bool is_playgo_enabled, MonoObject * pkg_info, MonoArray * languages, MonoArray * playgo_scenario_ids, MonoArray * content_ids)) DetourFunction(Get_Address_of_Method(AppInstallUtil_img, "Sce.Vsh", "AppInstUtilWrapper", "_AppInstUtilInstallByPackage", 12), (void*)&AppInstUtilInstallByPackage_Hook);
if (!Orig_AppInstUtilInstallByPackage) {
notify("Failed to hook AppInstUtilInstallByPackage");
return -1;
}
sceAppInstUtilInstallByPackage_orig = (int (*)(MetaInfo * arg1, SceAppInstallPkgInfo * pkg_info, PlayGoInfo * arg2)) DetourFunction((uintptr_t)sceAppInstUtilInstallByPackage, (void*)&sceAppInstUtilInstallByPackage_hook);
if (!sceAppInstUtilInstallByPackage_orig) {
notify("Failed to detour sceAppInstUtilInstallByPackage");
return -1;
}
#endif
if(sceRegMgrGetInt) {
sceRegMgrGetInt = (int( * )(long, int * )) DetourFunction((uintptr_t)sceRegMgrGetInt, (void *)&sceRegMgrGetInt_hook);
if (!sceRegMgrGetInt) {
@@ -825,6 +1114,14 @@ int main(int argc, char const *argv[]) {
return -1;
}
#if 1
read_orig = (ssize_t(*)(int fd, void *buf, size_t count)) DetourFunction((uintptr_t)read, (void*)&read_hook);
if (!read_orig) {
notify("Failed to detour read func");
return -1;
}
#endif
void* createJson_addr = DetourFunction(Get_Address_of_Method(ReactNativeShellAppReactNativeShellApp_img, "ReactNative.Modules.ShellUI.HomeUI", "OptionMenu", "createJson", 8), (void * )&createJson_hook);
createJson = (void( * )(MonoObject *, MonoObject * , MonoString * , MonoString * , MonoString * , MonoString * , MonoString * , MonoObject * , bool)) createJson_addr;
if (!createJson_addr) {
@@ -838,6 +1135,11 @@ int main(int argc, char const *argv[]) {
// return -1;
}
void* KillAppWithReason_orig = DetourFunction(Get_Address_of_Method(lnc_img, "Sce.Vsh.LncUtil", "LncUtilWrapper","KillAppWithReason", 2), (void *)&KillAppWithReason_Hook);
if (!KillAppWithReason_orig) {
notify("Failed to detour KillAppWithReason");
}
UpdateImposeStatusFlag_Orig = (void( * )(MonoObject * , MonoObject * )) DetourFunction(Get_Address_of_Method(AppSystem_img, appsystem_namespace.c_str(), layer_manager.c_str(), update_impose_flag.c_str(), 2), (void * )&UpdateImposeStatusFlag_hook);
if (!UpdateImposeStatusFlag_Orig) {
notify("Failed to detour Func Set -1");
@@ -943,6 +1245,8 @@ int main(int argc, char const *argv[]) {
shellui_log("Performed Magic");
hooked = true;
pthread_t thread_id;
scePthreadCreate(&thread_id, nullptr, dialogue_thread, nullptr, "dialogue_thread");
// file to let the main daemon know that its finished loading
touch_file("/system_tmp/toolbox_online");

View File

@@ -243,7 +243,7 @@ int32_t sceKernelSendNotificationRequest(int32_t device, OrbisNotificationReques
bool IniliatizeHTTP(void);
bool download_file(const char *url, const char *dst);
bool check_for_new_commit();
bool check_for_new_commit(int repo);
bool extract_zip(const char *zip_path, const char *extract_dir);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,434 @@
#include "json.hpp"
#include <string>
#include <vector>
#include <dirent.h>
#include <unordered_map>
extern "C" {
#include "common_utils.h"
typedef struct app_launch_ctx
{
int structsize;
int user_id;
int app_opt;
uint64_t crash_report;
int check_flag;
} app_launch_ctx_t;
int sceSystemServiceLaunchApp(const char *, char **, app_launch_ctx_t *);
#define SCE_LNC_UTIL_ERROR_ALREADY_RUNNING 0x8094000c
#define SCE_LNC_UTIL_ERROR_ALREADY_RUNNING_KILL_NEEDED 0x80940010
#define SCE_LNC_UTIL_ERROR_ALREADY_RUNNING_SUSPEND_NEEDED 0x80940011
}
#define SHELL_DEBUG 1
#include <sys/stat.h>
#include <fstream>
#include <ctime>
#include <iostream>
#include <random>
#include <sys/mount.h>
#include <sstream>
using json = nlohmann::json;
// Game Entry structure definition
struct GameEntry {
std::string tid; // Title ID
std::string title; // Game title
std::string version; // Game version
std::string path; // Displayed path
std::string dir_name; // Directory name
std::string icon_path; // Path to icon
std::string id; // Button ID
};
std::vector<GameEntry> games_list;
void escapePath(std::string& input)
{
std::unordered_map<std::string, std::string> escapeSequences =
{
{"&", "&amp;"},
{"<", "&lt;"},
{">", "&gt;"},
{"\"", "&quot;"},
{"/", "//"}
};
for (const auto& pair : escapeSequences)
{
size_t pos = 0;
while ((pos = input.find(pair.first, pos)) != std::string::npos)
{
input.replace(pos, pair.first.length(), pair.second);
pos += pair.second.length(); // Move past the replaced part
}
}
}
void escapeXML(std::string& input)
{
std::unordered_map<std::string, std::string> escapeSequences =
{
{"&", "&amp;"},
{"<", "&lt;"},
{">", "&gt;"},
{"\"", "&quot;"},
};
for (const auto& pair : escapeSequences)
{
size_t pos = 0;
while ((pos = input.find(pair.first, pos)) != std::string::npos)
{
input.replace(pos, pair.first.length(), pair.second);
pos += pair.second.length(); // Move past the replaced part
}
}
}
bool getContentInfofromJson(const std::string& file_path, std::string& tid, std::string& title, std::string &ver) {
try {
std::ifstream input_file(file_path);
if (!input_file.is_open()) {
etaHEN_log("Failed to open file for reading: %s", file_path.c_str());
return false;
}
json j;
input_file >> j;
input_file.close();
if (!j.contains("titleId")) {
etaHEN_log("JSON does not contain a required value");
return false;
}
tid = j["titleId"];
#if SHELL_DEBUG==1
etaHEN_log("getContentInfofromJson Title ID: %s", tid.c_str());
#endif
if (j.contains("localizedParameters") && j["localizedParameters"].contains("defaultLanguage")) {
std::string defaultLanguage = j["localizedParameters"]["defaultLanguage"];
if (j["localizedParameters"].contains(defaultLanguage) && j["localizedParameters"][defaultLanguage].contains("titleName")) {
title = j["localizedParameters"][defaultLanguage]["titleName"];
}
}
else
title = "App Title not found";
if (j.contains("contentVersion"))
ver = j["contentVersion"];
}
catch (const std::exception& e) {
etaHEN_log("Exception: %s", e.what());
return false;
}
return true;
}
// Helper function to check if path is from external storage
bool isExternalStorage(const std::string &path) {
return path.rfind("/mnt/ext") != std::string::npos;
}
// Helper function to copy files
bool copyFile(const std::string &src, const std::string &dst) {
std::ifstream source(src, std::ios::binary);
if (!source.is_open()) {
#if SHELL_DEBUG==1
etaHEN_log("Failed to open source file: %s", src.c_str());
#endif
return false;
}
std::ofstream dest(dst, std::ios::binary);
if (!dest.is_open()) {
#if SHELL_DEBUG==1
etaHEN_log("Failed to open destination file: %s", dst.c_str());
#endif
return false;
}
dest << source.rdbuf();
source.close();
dest.close();
return true;
}
// Main function
void generate_games_xml(std::string &xml_buffer, bool game_shortcut_activated)
{
struct dirent *entry;
unlink("/data/etaHEN/games_list.xml");
std::vector<std::string> directories = {
"/user/data/etaHEN/games",
"/mnt/usb0/etaHEN/games",
"/mnt/usb1/etaHEN/games",
"/mnt/usb2/etaHEN/games",
"/mnt/usb3/etaHEN/games",
"/mnt/ext1/etaHEN/games",
"/mnt/ext2/etaHEN/games",
"/mnt/ext0/etaHEN/games",
};
std::string list_id = game_shortcut_activated ? "id_debug_settings" : "id_ps5_backups";
xml_buffer = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
"<system_settings version=\"1.0\" plugin=\"debug_settings_plugin\">\n"
"\n";
xml_buffer += "<setting_list id=\"" + list_id + "\" title=\"(Beta) PS5 webMAN Games\">\n";
// Initialize random number generator
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> dist(1000, 9999);
// Create cache directory
mkdir("/data/etaHEN/cache", 0777);
for (const auto &directory : directories)
{
DIR *dir = opendir(directory.c_str());
if (!dir)
{
#if SHELL_DEBUG==1
etaHEN_log("Failed to open directory: %s error %s", directory.c_str(), strerror(errno));
#endif
continue;
}
while ((entry = readdir(dir)) != nullptr)
{
// Skip . and .. directories
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
std::string game_dir = directory + "/" + entry->d_name;
// Check if this is a directory
struct stat st;
if (stat(game_dir.c_str(), &st) != 0 || !S_ISDIR(st.st_mode)) {
#if SHELL_DEBUG==1
etaHEN_log("Skipping non-directory: %s", game_dir.c_str());
#endif
continue;
}
std::string param_path = game_dir + "/sce_sys/param.json";
std::string icon_path = game_dir + "/sce_sys/icon0.png";
// Check if param.json exists
if (access(param_path.c_str(), F_OK) != 0) {
#if SHELL_DEBUG==1
etaHEN_log("No param.json found in: %s", game_dir.c_str());
#endif
continue;
}
#if SHELL_DEBUG==1
etaHEN_log("Found Game: %s", game_dir.c_str());
#endif
// Parse JSON to get title_id, content_id, title, and version
std::string title_id, title, ver;
if (!getContentInfofromJson(param_path, title_id, title, ver)) {
#if SHELL_DEBUG==1
etaHEN_log("Failed to parse param.json in: %s", game_dir.c_str());
#endif
continue;
}
std::string shown_path = game_dir;
const std::string prefix = "/user";
if (shown_path.find(prefix) == 0) {
shown_path = shown_path.substr(prefix.length());
}
shown_path = (game_dir.substr(0, 4) == "/usb") ? "/mnt" + game_dir : shown_path;
// Generate a random number for the ID
int random_num = dist(gen);
// Handle icon path and caching
if (isExternalStorage(game_dir)) {
// Cache icon from external storage
// not /data but /user/data for shellui as it's not accessible from /data
std::string cached_icon_path = "/user/data/etaHEN/cache/" + title_id + ".png";
// Copy icon if it doesn't exist
if (access(cached_icon_path.c_str(), F_OK) != 0) {
if (!copyFile(icon_path, cached_icon_path)) {
#if SHELL_DEBUG==1
etaHEN_log("Failed to cache icon from: %s", icon_path.c_str());
#endif
cached_icon_path = icon_path; // Fallback to original
} else {
#if SHELL_DEBUG==1
etaHEN_log("Cached icon: %s", cached_icon_path.c_str());
#endif
}
}
icon_path = cached_icon_path;
} else if (icon_path.find("/mnt/usb") == 0) {
// Transform /mnt/usb... to /usb...
icon_path = icon_path.substr(4); // Remove "/mnt"
}
// Escape paths for XML
escapePath(icon_path);
escapeXML(title);
escapeXML(shown_path);
// Create and populate a GameEntry
GameEntry game;
game.tid = title_id;
game.title = title;
game.version = ver;
game.path = shown_path;
game.dir_name = entry->d_name;
game.icon_path = icon_path;
game.id = "id_etahen_game_loader_" + title_id + "_" + std::to_string(random_num);
// Add to the games list
games_list.push_back(game);
// Format the button XML
std::string button = "<button id=\"" + game.id + "\" title=\"(" + title_id + ") " + title +
"\" icon=\"" + icon_path + "\" second_title=\"" + shown_path + " | Version: " + ver + "\"/>\n";
xml_buffer += button;
}
closedir(dir);
}
xml_buffer += "</setting_list>\n</system_settings>";
}
#define IOVEC_ENTRY(x) {x ? (char *)x : 0, x ? strlen(x) + 1 : 0}
#define IOVEC_SIZE(x) (sizeof(x) / sizeof(struct iovec))
int mount_nullfs(const char *src, const char *dst)
{
struct iovec iov[] = {
IOVEC_ENTRY("fstype"),
IOVEC_ENTRY("nullfs"),
IOVEC_ENTRY("from"),
IOVEC_ENTRY(src),
IOVEC_ENTRY("fspath"),
IOVEC_ENTRY(dst),
};
return nmount(iov, IOVEC_SIZE(iov), 0);
}
int endswith(const char *string, const char *suffix)
{
size_t suffix_len = strlen(suffix);
size_t string_len = strlen(string);
if (string_len < suffix_len)
{
return 0;
}
return strncmp(string + string_len - suffix_len, suffix, suffix_len) != 0;
}
int chmod_bins(const char *path)
{
char buf[PATH_MAX + 1];
struct dirent *entry;
struct stat st;
DIR *dir;
if (stat(path, &st) != 0)
{
return -1;
}
if (endswith(path, ".prx") || endswith(path, ".sprx") || endswith(path, "/eboot.bin"))
{
chmod(path, 0755);
}
if (S_ISDIR(st.st_mode))
{
dir = opendir(path);
while (1)
{
entry = readdir(dir);
if (entry == nullptr)
{
break;
}
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
{
continue;
}
sprintf(buf, "%s/%s", path, entry->d_name);
chmod_bins(buf);
}
closedir(dir);
}
return 0;
}
int Launch_FG_Game(const char *path, const char* title_id, const char* title){
app_launch_ctx_t ctx = {0};
char dst[PATH_MAX + 1];
strcpy(dst, "/system_ex/app/");
strcat(dst, title_id);
mkdir(dst, 0777);
sceUserServiceInitialize(0);
sceUserServiceGetForegroundUser(&ctx.user_id);
mount_nullfs(path, dst);
chmod_bins(path);
char *argv[] = {(char*)title, nullptr};
return sceSystemServiceLaunchApp(title_id, &argv[0], &ctx);
}
bool Launch_Game_By_ID(const char* button_id){
if (games_list.empty()){
return false;
}
for (auto game : games_list) {
if (game.id == button_id) {
etaHEN_log("[Clicked %s] TID: %s title: %s version: %s path: %s", game.id.c_str(), game.tid.c_str(), game.title.c_str(), game.version.c_str(), game.path.c_str());
notify(true, "Launching %s (%s)\nPath: %s", game.title.c_str(), game.tid.c_str(), game.path.c_str());
//const char *path, const char* title_id, const char* title
int res = Launch_FG_Game(game.path.c_str(), game.tid.c_str(), game.title.c_str());
if (res < 0 && res != SCE_LNC_UTIL_ERROR_ALREADY_RUNNING_KILL_NEEDED && res != SCE_LNC_UTIL_ERROR_ALREADY_RUNNING && res != SCE_LNC_UTIL_ERROR_ALREADY_RUNNING_SUSPEND_NEEDED) {
notify(true, "Failed to launch %s (%s)\nError: 0x%X", game.title.c_str(), game.tid.c_str(), res);
return false;
}
}
}
return true;
}

View File

@@ -34,7 +34,8 @@ along with this program; see the file COPYING. If not, see
#define MAX_CONCURRENT_REQUEST (4)
#define PRIVATE_CA_CERT_NUM (0)
#define COMMIT_HASH_FILE "/data/etaHEN/cheat_commit_hash.txt"
#define GITHUB_API_URL "https://api.github.com/repos/etaHEN/PS5_Cheats/commits"
#define ETAHEN_GITHUB_API_URL "https://api.github.com/repos/etaHEN/PS5_Cheats/commits"
#define GOLDHEN_GITHUB_API_URL "https://api.github.com/repos/GoldHEN/GoldHEN_Cheat_Repository/commits"
uint64_t sceKernelGetProcessTime(void);
@@ -94,12 +95,12 @@ static int progress_callback(void* clientp, curl_off_t dltotal, curl_off_t dlnow
int percent = (int)(((float)dlnow / dltotal) * 100);
snprintf(notifyMsg, sizeof(notifyMsg),
"Downloading the cheats repo:..\n%.1f/%.1f MB (%d%%)",
"Downloading..\n%.1f/%.1f MB (%d%%)",
dlnow_mb, dltotal_mb, percent);
}
else {
snprintf(notifyMsg, sizeof(notifyMsg),
"Downloading the cheats repo...\n%.1f MB Downloaded",
"Downloading...\n%.1f MB Downloaded",
dlnow_mb);
}
@@ -237,11 +238,13 @@ static char* download_json(const char* url) {
// Initialize JSON data structure
struct json_data json = {
.data = malloc(1024),
.data = malloc(0x1000),
.size = 0,
.capacity = 1024
.capacity = 0x1000
};
etaHEN_log("Downloading JSON data from %s", url);
if (!json.data) {
etaHEN_log("Failed to allocate initial memory for JSON data");
return NULL;
@@ -556,7 +559,7 @@ static bool write_commit_hash(const char* hash) {
}
// Main function to check for new commits
bool check_for_new_commit() {
bool check_for_new_commit(int repo) {
char* json_data = NULL;
char latest_commit[64] = {0};
char stored_commit[64] = {0};
@@ -566,7 +569,7 @@ bool check_for_new_commit() {
notify(true, "Checking for updates to the cheats repo...");
// Download the latest commit information
json_data = download_json(GITHUB_API_URL);
json_data = download_json(repo ? GOLDHEN_GITHUB_API_URL : ETAHEN_GITHUB_API_URL);
if (!json_data) {
etaHEN_log("Failed to download commit information from GitHub API");
notify(true, "Failed to check the cheats repo for updates\nCheck your Connection and try again");

View File

@@ -25,7 +25,7 @@ extern "C" {
#include <sys/mount.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/ioctl.h>
int sceKernelMprotect(void *addr, size_t len, int prot);
pid_t elfldr_spawn(const char* cwd, int stdio, uint8_t* elf, const char* name);
@@ -48,7 +48,8 @@ extern bool is_handler_enabled;
extern pthread_t cmd_server;
void* runCommandNControlServer(void*);
void generate_games_xml(std::string &xml_buffer, bool game_shortcut_activated);
bool Launch_Game_By_ID(const char* button_id);
// pop -Winfinite-recursion error for this func for clang
#define MB(x) ((size_t)(x) << 20)
#define READ_SIZE 0x1024
@@ -542,13 +543,16 @@ void handleIPC(struct clientArgs *client, std::string &inputStr,
break;
}
case BREW_UTIL_DOWNLOAD_CHEATS: {
if(!check_for_new_commit()){
json_t const *target_repo_property = json_getProperty(my_json, "repo");
int repo = json_getInteger(target_repo_property);
if(!check_for_new_commit(repo)){
etaHEN_log("Failed to check for new commit or is up to date");
reply(sender_app, false);
break;
}
notify(true, "Downloading the latest etaHEN Cheats repo....");
if (!download_file("https://api.github.com/repos/etaHEN/PS5_Cheats/zipball",
notify(true, "Downloading the latest %s Cheats repo....", repo ? "GoldHEN PS4" : "etaHEN PS5");
if (!download_file(repo ? "https://api.github.com/repos/GoldHEN/GoldHEN_Cheat_Repository/zipball" : "https://api.github.com/repos/etaHEN/PS5_Cheats/zipball",
"/data/etaHEN/cheats.zip")) {
etaHEN_log("Failed to download cheats");
reply(sender_app, true);
@@ -603,6 +607,46 @@ void handleIPC(struct clientArgs *client, std::string &inputStr,
reply(sender_app, false);
break;
}
case BREW_UTIL_GET_GAMES_LIST:{
bool cheats_activated_shortcut = json_getInteger(json_getProperty(my_json, "shortcut"));
std::string games_list;
generate_games_xml(games_list, cheats_activated_shortcut);
std::string shm_path = "/user/data/etaHEN/games_list.xml";
//make file
int fd = open(shm_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0777);
if (fd >= 0) {
// Write the buffer to the file
if (write(fd, games_list.c_str(), games_list.length()) == -1) {
perror("write failed");
close(fd);
reply(sender_app, true);
break;
}
// Close the file descriptor
close(fd);
reply(sender_app, false, shm_path);
break;
} else {
notify(true, "Failed to create shared file for games list!");
// generate_default_games_xml(games_list, cheats_activated_shortcut);
reply(sender_app, true);
break;
}
break;
}
case BREW_UTIL_LAUNCH_GAME_BY_BUTTON_ID:{
std::string button_id = std::string(json_getPropertyValue(my_json, "button_id"));
etaHEN_log("Launching game with button id: %s", button_id.c_str());
int res = Launch_Game_By_ID(button_id.c_str());
if (res < 0) {
reply(sender_app, true);
break;
}
reply(sender_app, false);
break;
}
case BREW_KILL_DAEMON:{
is_handler_enabled = false;
exit(1337);

BIN
etaHEN-2.5B.bin Normal file

Binary file not shown.