mirror of
https://github.com/etaHEN/etaHEN.git
synced 2026-01-12 19:25:33 +08:00
etaHEN 2.4B etaHEN 2.4B Change log - Updated to support the latest PS5 Payload SDK - Fixed etaHEN and Cheats support for 8.40-10.01 - Added a Game Overlay menu to show CPU/GPU Temp and utilization, Local IP Address and other future states - Added a Kstuff menu for options like downloading the latest kstuff from github, turning off kstufff autoload and more - Added a Custom Background Package Installer for installing PKGs from internal storage from any directory (Requires DPIv2 enabled for 5.50+) - DPIv2 can now download local files via url example http://192.xxx.xxx.xxx:12800/data/etaHEN/etaHEN.log - Improved Cheats support, cheats with or without 0 sections are now supported - Added Fix by TheFlow to Improve 2.xx PS4 PKG speeds - Replaced the donation links in the etaHEN credits menu with ones to github sponsers - Removed the non-whitelist app jailbreak option and moved it to an optional Legacy CMD Server option in the etaHEN Settings off by default - Game Decryptor has been updated for the Itemzflow Dumper - Updated the Plugin loader System - The Payload SDK ELFLDR is now REQUIRED for etaHEN to load - Replaced HTTP2 with Curl for better compatibility - Added timeout for ShellUI to receive a response (will stop it from freezing if no response is given) small fix
426 lines
13 KiB
C++
426 lines
13 KiB
C++
/* Copyright (C) 2025 etaHEN / LightningMods
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by the
|
|
Free Software Foundation; either version 3, or (at your option) any
|
|
later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; see the file COPYING. If not, see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
// Include files
|
|
#include <cstdint>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include <string>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include <poll.h>
|
|
|
|
// System includes
|
|
#include <sys/stat.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <sys/sysctl.h>
|
|
#include <sys/_pthreadtypes.h>
|
|
#include <sys/signal.h>
|
|
#include <netinet/in.h>
|
|
#include <ps5/klog.h>
|
|
|
|
// Project includes
|
|
#include "../../include/backtrace.hpp"
|
|
#include "globalconf.hpp"
|
|
#include "launcher.hpp"
|
|
#include "ipc.hpp"
|
|
|
|
#define MSG_NOSIGNAL 0x20000 /* do not generate SIGPIPE on EOF. */
|
|
pthread_t cheat_thr = nullptr;
|
|
|
|
#define PAD_BUTTON_OPTIONS 0x00000008
|
|
|
|
// Structure definitions
|
|
typedef struct {
|
|
unsigned int size;
|
|
uint32_t userId;
|
|
} SceShellUIUtilLaunchByUriParam;
|
|
|
|
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
|
|
|
|
// External C declarations
|
|
extern "C" {
|
|
int sceKernelSendNotificationRequest(int32_t device,
|
|
OrbisNotificationRequest *req,
|
|
size_t size, int32_t blocking);
|
|
int sceSystemServiceNavigateToGoHome(void);
|
|
int sceUserServiceGetUserName(const int userId, char *userName, const size_t size);
|
|
uint64_t sceKernelGetProcessTime();
|
|
int sceSystemServiceGetAppId(const char *title_id);
|
|
int scePadSetProcessPrivilege(int priv);
|
|
pid_t elfldr_spawn(const char* cwd, int stdio, uint8_t* elf, const char* name);
|
|
int sceUserServiceGetForegroundUser(int *userId);
|
|
int sceLncUtilLaunchApp(const char *tid, const char *argv[], LncAppParam *param);
|
|
uint32_t _sceApplicationGetAppId(int pid, uint32_t *appId);
|
|
uint32_t sceLncUtilKillApp(uint32_t appId);
|
|
int sceSysmoduleLoadModuleInternal(int id);
|
|
int sceNetCtlInit();
|
|
int sceUserServiceInitialize(const int *);
|
|
int sceKernelLoadStartModule(const char *name, size_t argc, const void *argv,
|
|
uint32_t flags, void *unknown, int *result);
|
|
int sceKernelDlsym(uint32_t lib, const char *name, void **fun);
|
|
//int sceShellUIUtilInitialize(void);
|
|
int scePadClose(int handle);
|
|
//int sceShellUIUtilLaunchByUri(const char *uri, SceShellUIUtilLaunchByUriParam *Param);
|
|
int sceSystemStateMgrEnterStandby(void);
|
|
int sceKernelMprotect(void *addr, size_t len, int prot);
|
|
ssize_t _read(int, void *, size_t);
|
|
int sceKernelGetProcessName(int pid, char *name);
|
|
void free(void *);
|
|
int sceShellCoreUtilRequestEjectDevice(const char *path);
|
|
|
|
// PayloadAPI definitions
|
|
#include <ps5/payload.h>
|
|
|
|
// External data
|
|
extern uint8_t ps5debug_start[];
|
|
extern const unsigned int ps5debug_size;
|
|
|
|
}
|
|
|
|
// Global variables
|
|
uint64_t p_syscall = 0;
|
|
char _end[1] = {};
|
|
struct daemon_settings global_conf;
|
|
int fd = -1;
|
|
pthread_t klog_srv = nullptr;
|
|
static constexpr auto DEFAULT_PRIORITY = 256;
|
|
uintptr_t kernel_base = 0;
|
|
|
|
// Function declarations
|
|
void etaHEN_log(const char *fmt, ...);
|
|
void notify(bool show_watermark, const char *text, ...);
|
|
bool touch_file(const char *destfile);
|
|
int launchApp(const char *titleId);
|
|
int get_ip_address(char *ip_address);
|
|
bool sceKernelIsTestKit();
|
|
int ItemzLaunchByUri(const char *uri);
|
|
bool enable_toolbox();
|
|
void sig_handler(int signo);
|
|
|
|
bool if_exists(const char *path);
|
|
void *fifo_and_dumper_thread(void *args);
|
|
void *Play_time_thread(void *args) noexcept;
|
|
void patch_checker();
|
|
int elfldr_raise_privileges(pid_t pid);
|
|
extern void makenewapp();
|
|
|
|
// External function declarations
|
|
extern void *start_ftp(void *);
|
|
extern void *IPC_loop(void *);
|
|
extern bool is_handler_enabled;
|
|
|
|
// Whitelist for PSIDs
|
|
const char *whitelisted_psids[] = {
|
|
"b345df7d4c77618d40f19a90e438ad87",
|
|
"ab535275b7196e7e7d43f4f9e7806724",
|
|
"d376c7780b960e5182d326ba3aa2d7a3",
|
|
"a8d89ad976b5cb912837ad29b0cc4610",
|
|
"177e09480b40816a1caca5151565daa5"
|
|
};
|
|
|
|
// Function implementations
|
|
void etaHEN_log(const char *fmt, ...) {
|
|
char msg[0x1000];
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
__builtin_vsnprintf(msg, sizeof(msg), fmt, args);
|
|
va_end(args);
|
|
|
|
// Append newline at the end
|
|
size_t msg_len = strlen(msg);
|
|
if (msg_len < sizeof(msg) - 1) {
|
|
msg[msg_len] = '\n';
|
|
msg[msg_len + 1] = '\0';
|
|
} else {
|
|
msg[sizeof(msg) - 2] = '\n';
|
|
msg[sizeof(msg) - 1] = '\0';
|
|
}
|
|
|
|
printf("[etaHEN]: %s", msg); // msg already includes a newline
|
|
klog_printf("%s", msg); // msg already includes a newline
|
|
|
|
int fd = open("/data/etaHEN/etaHEN.log", O_WRONLY | O_CREAT | O_APPEND, 0777);
|
|
if (fd < 0) {
|
|
return;
|
|
}
|
|
write(fd, msg, strlen(msg));
|
|
close(fd);
|
|
}
|
|
|
|
bool touch_file(const char *destfile) {
|
|
static constexpr int FLAGS = 0777;
|
|
int fd = open(destfile, O_WRONLY | O_CREAT | O_TRUNC, FLAGS);
|
|
if (fd > 0) {
|
|
close(fd);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int launchApp(const char *titleId) {
|
|
int id = 0;
|
|
|
|
uint32_t res = sceUserServiceGetForegroundUser(&id);
|
|
if (res != 0) {
|
|
printf("sceUserServiceGetForegroundUser failed: 0x%x", res);
|
|
return res;
|
|
}
|
|
etaHEN_log("[LA] user id %u", id);
|
|
|
|
// the thread will clean this up
|
|
Flag flag = Flag_None;
|
|
LncAppParam param{sizeof(LncAppParam), id, 0, 0, flag};
|
|
|
|
puts("calling sceLncUtilLaunchApp");
|
|
int err = sceLncUtilLaunchApp(titleId, nullptr, ¶m);
|
|
etaHEN_log("sceLncUtilLaunchApp returned 0x%x", (uint32_t)err);
|
|
if (err >= 0) {
|
|
return err;
|
|
}
|
|
|
|
switch ((uint32_t)err) {
|
|
case SCE_LNC_UTIL_ERROR_ALREADY_RUNNING:
|
|
etaHEN_log("app %s is already running", titleId);
|
|
break;
|
|
case SCE_LNC_ERROR_APP_NOT_FOUND:
|
|
etaHEN_log("app %s not found", titleId);
|
|
notify(true, "app %s not found", titleId);
|
|
break;
|
|
default:
|
|
etaHEN_log("[LA] unknown error 0x%x", (uint32_t)err);
|
|
// notify(true, "unknown error 0x%llx", (uint32_t)err);
|
|
break;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
void sig_handler(int signo) {
|
|
if(!is_handler_enabled){
|
|
etaHEN_log("Signal handler is disabled, ignoring signal %d", signo);
|
|
return;
|
|
}
|
|
notify(true,
|
|
"etaHEN has crashed ...\n\nPlease send /data/etaHEN/etaHEN_crash.log "
|
|
"to the PKG-Zone discord: https://discord.gg/BduZHudWGj");
|
|
etaHEN_log("main etaHEN has crashed ...");
|
|
//printBacktraceForCrash();
|
|
exit(1);
|
|
}
|
|
|
|
bool sceKernelIsTestKit() {
|
|
uint8_t s_PsId[16] = {0};
|
|
|
|
size_t v2 = 16;
|
|
if (sysctlbyname("machdep.openpsid_for_sys", &s_PsId, &v2, 0, 0) < 0) {
|
|
printf("sceKernelGetOpenPsIdForSystem failed\n");
|
|
return true;
|
|
}
|
|
|
|
char psid_buf[255] = {0};
|
|
|
|
for (int i = 0; i < 16; i++) {
|
|
snprintf(psid_buf + strlen(psid_buf), 255 - strlen(psid_buf), "%02x",
|
|
s_PsId[i]);
|
|
}
|
|
|
|
for (int i = 0; i < sizeof(whitelisted_psids) / sizeof(whitelisted_psids[0]);
|
|
i++) {
|
|
if (strcmp(psid_buf, whitelisted_psids[i]) == 0) {
|
|
return false; // report not testkit if is whitelisted
|
|
}
|
|
}
|
|
|
|
return if_exists("/system/priv/lib/libSceDeci5Ttyp.sprx");
|
|
}
|
|
|
|
|
|
int (*sceShellUIUtilInitialize)(void) = nullptr;
|
|
int (*sceShellUIUtilLaunchByUri)(const char* uri, SceShellUIUtilLaunchByUriParam* Param) = nullptr;
|
|
#define KERNEL_DLSYM(handle, sym) \
|
|
(*(void**)&sym=(void*)kernel_dynlib_dlsym(-1, handle, #sym))
|
|
int ItemzLaunchByUri(const char* uri) {
|
|
int libcmi = -1;
|
|
|
|
if (!uri)
|
|
return -1;
|
|
|
|
if ((libcmi = sceKernelLoadStartModule("/system_ex/common_ex/lib/libSceShellUIUtil.sprx", 0, 0, 0, 0, 0)) < 0 || libcmi < 0)
|
|
return -1;
|
|
|
|
KERNEL_DLSYM(libcmi, sceShellUIUtilInitialize);
|
|
KERNEL_DLSYM(libcmi, sceShellUIUtilLaunchByUri);
|
|
if (!sceShellUIUtilInitialize || !sceShellUIUtilLaunchByUri) {
|
|
etaHEN_log("failed to load libSceShellUIUtil.sprx");
|
|
return -1;
|
|
}
|
|
//
|
|
SceShellUIUtilLaunchByUriParam Param;
|
|
Param.size = sizeof(SceShellUIUtilLaunchByUriParam);
|
|
sceShellUIUtilInitialize();
|
|
sceUserServiceGetForegroundUser((int*)&Param.userId); // DONT CARE
|
|
|
|
return sceShellUIUtilLaunchByUri(uri, &Param);
|
|
}
|
|
|
|
bool cmd_enable_toolbox();
|
|
void LoadSettings();
|
|
|
|
int main() {
|
|
char buz[255];
|
|
pthread_t fifo_thr = nullptr;
|
|
pthread_t pt_thr = nullptr;
|
|
pthread_t msg_thr = nullptr;
|
|
|
|
sceNetCtlInit();
|
|
sceUserServiceInitialize(&DEFAULT_PRIORITY);
|
|
puts("daemon entered");
|
|
|
|
OrbisKernelSwVersion sys_ver;
|
|
sceKernelGetProsperoSystemSwVersion(&sys_ver);
|
|
int fw_ver = (sys_ver.version >> 16);
|
|
|
|
// Set up signal handlers
|
|
struct sigaction new_SIG_action;
|
|
new_SIG_action.sa_handler = sig_handler;
|
|
sigemptyset(&new_SIG_action.sa_mask);
|
|
new_SIG_action.sa_flags = 0;
|
|
|
|
for (int i = 0; i < 12; i++)
|
|
sigaction(i, &new_SIG_action, NULL);
|
|
|
|
unlink("/data/etaHEN/etaHEN.log");
|
|
unlink("/data/etaHEN/etaHEN_crash.log");
|
|
|
|
payload_args_t *args = payload_get_args();
|
|
kernel_base = args->kdata_base_addr;
|
|
|
|
etaHEN_log("=========== starting etaHEN (0x%X) ... ===========", fw_ver);
|
|
bool has_hv_bypass = (sceKernelMprotect(&buz[0], 100, 0x7) == 0);
|
|
bool is_lite = if_exists("/system_tmp/lite_mode");
|
|
bool toolbox_only = (fw_ver >= 0x10000);
|
|
bool no_ps5debug = (fw_ver >= 0x800);
|
|
|
|
|
|
LoadSettings();
|
|
|
|
#if 0
|
|
// Check if running on a test kit
|
|
if (sceKernelIsTestKit()) {
|
|
etaHEN_log("no NO NO");
|
|
return -1;
|
|
raise(SIGSEGV);
|
|
}
|
|
#endif
|
|
|
|
// Start threads
|
|
get_ip_address(&buz[0]);
|
|
pthread_create(&fifo_thr, nullptr, fifo_and_dumper_thread, nullptr);
|
|
pthread_create(&pt_thr, nullptr, Play_time_thread, nullptr);
|
|
pthread_create(&msg_thr, nullptr, IPC_loop, nullptr);
|
|
|
|
etaHEN_log("is toolbox only: %s | ver: %x", toolbox_only ? "Yes" : "No", sys_ver.version);
|
|
// Initialize toolbox if needed
|
|
if (global_conf.toolbox_auto_start) {
|
|
cmd_enable_toolbox();
|
|
}
|
|
else if (!global_conf.toolbox_auto_start) {
|
|
notify(true, "the etaHEN Toolbox auto start is disabled in the config.ini\n\n"
|
|
"If you want to re-enable the toolbox go to ItemzFlow's settings menu");
|
|
}
|
|
|
|
// Load PS5Debug if needed
|
|
if (global_conf.PS5Debug && !no_ps5debug && !has_hv_bypass && !is_lite) {
|
|
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() : "");
|
|
|
|
|
|
etaHEN_log("StartUp thread created!! - welcome to etaHEN");
|
|
|
|
// Launch the appropriate app based on configuration
|
|
const char *URI = nullptr;
|
|
switch (global_conf.start_opt) {
|
|
case HOME_MENU: {
|
|
URI = "pshomeui:navigateToHome?bootCondition=psButton";
|
|
break;
|
|
}
|
|
case TOOLBOX: {
|
|
if (global_conf.toolbox_auto_start)
|
|
URI = "pssettings:play?mode=settings&function=debug_settings";
|
|
else
|
|
URI = "pshomeui:navigateToHome?bootCondition=psButton";
|
|
break;
|
|
}
|
|
case SETTINGS: {
|
|
URI = "pssettings:play?mode=settings";
|
|
break;
|
|
}
|
|
case ITEMZFLOW: {
|
|
launchApp("ITEM00001");
|
|
break;
|
|
}
|
|
default:
|
|
etaHEN_log("unknown opt %d", global_conf.start_opt);
|
|
break;
|
|
}
|
|
|
|
if (URI && !is_lite)
|
|
etaHEN_log("ret %d", ItemzLaunchByUri(URI));
|
|
|
|
if(global_conf.auto_eject_disc){
|
|
sceShellCoreUtilRequestEjectDevice("/dev/cd0");
|
|
}
|
|
|
|
unlink("/system_tmp/lite_mode");
|
|
|
|
// Main loop to keep the process running
|
|
while (true) {
|
|
pthread_join(msg_thr, NULL);
|
|
pthread_create(&msg_thr, nullptr, IPC_loop, nullptr);
|
|
sleep(1);
|
|
}
|
|
|
|
puts("main thread ended");
|
|
return 0;
|
|
}
|