/* 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
. */
/******************************************************************************
* Standard and System Header Includes
******************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/******************************************************************************
* Custom Header Includes
******************************************************************************/
#include
#include
extern "C" {
#include "elfldr.h"
#include "faulthandler.h"
#include "hbldr.h"
#include "pt.h"
#include
#include
pid_t elfldr_spawn(const char* cwd, int stdio, uint8_t* elf, const char* name);
int sceKernelMprotect(void* addr, size_t len, int prot);
extern uint8_t kstuff_start[];
extern const unsigned int kstuff_size;
extern uint8_t fps_prx_start[];
extern const unsigned int fps_prx_size;
}
/******************************************************************************
* Macros and Constants
******************************************************************************/
#define QAFLAGS_SIZE 16
#define USER_SERVICE_ID 0x80000011
#define SYSTEM_SERVICE_ID 0x80000010
#define LNC_UTIL_ERROR_ALREADY_RUNNING 0x8094000c
#define LNC_ERROR_APP_NOT_FOUND 0x80940031
#define ENTRYPOINT_OFFSET 0x70
#define PROCESS_LAUNCHED 1
#define LOOB_BUILDER_SIZE 21
#define LOOP_BUILDER_TARGET_OFFSET 3
#define USLEEP_NID "QcteRwbsnV0"
#define LOOKUP_SYMBOL(resolver, sym) \
resolver_lookup_symbol(resolver, sym, strlen(sym))
#define SET_FUNCTION_ADDRESS(resolver, function) \
*(void **)&(function) = \
(void *)LOOKUP_SYMBOL(resolver, #function) /* NOLINT */
#define BUILD_IOVEC(str) \
{ .iov_base = (str), .iov_length = __builtin_strlen(str) + 1 }
/******************************************************************************
* Type Definitions and Structures
******************************************************************************/
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
typedef enum {
Flag_None = 0,
SkipLaunchCheck = 1,
SkipResumeCheck = 1,
SkipSystemUpdateCheck = 2,
RebootPatchInstall = 4,
VRMode = 8,
NonVRMode = 16,
Pft = 32UL,
RaIsConfirmed = 64UL,
ShellUICheck = 128UL
} Flag;
typedef struct {
uint32_t sz;
int user_id;
uint32_t app_opt;
uint64_t crash_report;
Flag check_flag;
} LncAppParam;
typedef struct {
const void *iov_base;
size_t iov_length;
} iovec_t;
typedef struct FileDescriptors {
int fd = 1;
} FileDescriptor;
typedef struct {
uint64_t pad0;
char version_str[0x1C];
uint32_t version;
uint64_t pad1;
} OrbisKernelSwVersion;
typedef struct {
char prefix[14]; // "etaHEN_PLUGIN" + null terminator
char titleID[10]; // 4 uppercase letters, 5 numbers, and a null terminator
char plugin_version[5];
} CustomPluginHeader;
typedef struct app_info {
uint32_t app_id;
uint64_t unknown1;
uint32_t app_type;
char title_id[10];
char unknown2[0x3c];
} app_info_t;
/******************************************************************************
* External Declarations
******************************************************************************/
extern "C" {
int sceKernelSendNotificationRequest(int32_t device,
OrbisNotificationRequest *req,
size_t size, int32_t blocking);
int sceUserServiceGetForegroundUser(uint32_t *userId);
int sceLncUtilLaunchApp(const char *tid, const char *argv[],
LncAppParam *param);
uint32_t sceLncUtilKillApp(uint32_t appId);
int sceSystemServiceGetAppId(const char *titleId);
int sceUserServiceInitialize(void *param);
int sceKernelGetProsperoSystemSwVersion(OrbisKernelSwVersion *sw);
int unmount(const char *path, int flags);
int sceKernelGetAppInfo(int pid, app_info_t *title);
int sceKernelGetProcessName(int pid, char *name);
int sceKernelGetOpenPsIdForSystem(void *psid);
int sceKernelIsGenuineDevKit();
bool devkit_byepervisor(void);
void notify(const char *text, ...) {
OrbisNotificationRequest req;
va_list args;
memset(&req, 0, sizeof(OrbisNotificationRequest));
// Process args
va_start(args, text);
vsnprintf(req.message, sizeof(req.message), text, args);
va_end(args);
req.type = 0;
req.unk3 = 0;
req.use_icon_image_uri = 1;
req.target_id = -1;
snprintf(req.uri, sizeof(req.uri), "cxml://psnotification/tex_icon_system");
printf("Notify: %s\n", req.message);
sceKernelSendNotificationRequest(0, &req, sizeof(req), 0);
}
}
extern int _write(int fd, const void *, size_t); // NOLINT
extern ssize_t _read(int, void *, size_t); // NOLINT
extern const unsigned int daemon_size;
extern uint8_t daemon_start[];
extern uint8_t util_start[];
extern const unsigned int util_size;
extern uint8_t store_png_start;
extern const unsigned int store_png_size;
extern uint8_t sicon_start[];
extern const unsigned int sicon_size;
extern uint8_t webman_icon_start[];
extern const unsigned int webman_icon_size;
/******************************************************************************
* Global Variables
******************************************************************************/
int plugin_count = 0;
char buff[255];
char **loaded_filenames = NULL;
jmp_buf g_catch_buf;
FileDescriptor sock;
// Constants
static const int LOGGER_PORT = 9021;
static const int STDOUT = 1;
static const int STDERR = 2;
/******************************************************************************
* Function Prototypes
******************************************************************************/
void write_embedded_assets();
bool if_exists(const char *path);
void notify(const char *text, ...);
static void cleanup(void);
FileDescriptor FileDescriptor_init(int fd);
int initStdout();
void release(FileDescriptor *fd);
void patch_app_db(void);
bool is_valid_plugin(const unsigned char *file_buffer);
uint8_t *get_elf_header_address(unsigned char *file_buffer);
static bool remount(const char *dev, const char *path);
/******************************************************************************
* Function Implementations
******************************************************************************/
extern uint8_t shellui_prx_start[];
extern const unsigned int shellui_prx_size;
void write_embedded_assets() {
mkdir("/data/etaHEN/", 0777);
mkdir("/data/etaHEN/assets/", 0777);
#if 0
int fd = open("/system_ex/common_ex/lib/shell.prx", O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd == -1) {
perror("open failed");
return;
}
if (write(fd, &shellui_prx_start, shellui_prx_size) == -1) {
perror("write failed");
return;
}
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");
return;
}
if (write(fd, & store_png_start, store_png_size) == -1) {
perror("write failed");
}
close(fd);
}
if (!if_exists("/data/etaHEN/assets/webMAN.png")) {
int fd = open("/data/etaHEN/assets/webMAN.png", O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd == -1) {
perror("open failed");
return;
}
if (write(fd, & webman_icon_start, webman_icon_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);
if (fd == -1) {
perror("open failed");
return;
}
if (write(fd, & sicon_start, sicon_size) == -1) {
perror("write failed");
}
close(fd);
}
if (!if_exists("/mnt/rnps/apps/NPXS40008/assets/src/modules/categoriesList/assets/texture/etahen_sicon.png")) {
int fd = open("/mnt/rnps/apps/NPXS40008/assets/src/modules/categoriesList/assets/texture/etahen_sicon.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);
}
}
bool is_elf_header(uint8_t* data)
{
uint8_t header[] = { 0x7f, 'E', 'L', 'F' };
return !memcmp(data, header, 4);
}
uint8_t* get_kstuff_address(bool& require_cleanup) {
const char* path = "/data/etaHEN/kstuff.elf";
long offset = 0;
off_t size;
uint8_t* address;
int fd;
if (!if_exists(path)) {
goto embedded_kstuff;
}
fd = open(path, O_RDONLY);
if (fd <= 0) {
goto embedded_kstuff;
}
size = lseek(fd, 0, SEEK_END);
address = (uint8_t*)malloc(size);
if (!address) {
goto close_fd;
}
lseek(fd, 0, SEEK_SET);
while (offset != size) {
int n = read(fd, address + offset, size - offset);
if (n <= 0)
{
goto free_mem;
}
offset += n;
}
if (!is_elf_header(address)) {
notify( "Kstuff '%s' doesn't have ELF header.", path);
goto free_mem;
}
require_cleanup = true;
notify("Loading kstuff from: %s", path);
return address;
free_mem:
free(address);
close_fd:
close(fd);
embedded_kstuff:
require_cleanup = false;
return kstuff_start;
}
bool if_exists(const char *path) {
struct stat buffer;
return (stat(path, &buffer) == 0);
}
static bool remount(const char *dev, const char *path) {
iovec_t iov[] = {BUILD_IOVEC("fstype"), BUILD_IOVEC("exfatfs"),
BUILD_IOVEC("fspath"), BUILD_IOVEC(path),
BUILD_IOVEC("from"), BUILD_IOVEC(dev),
BUILD_IOVEC("large"), BUILD_IOVEC("yes"),
BUILD_IOVEC("timezone"), BUILD_IOVEC("static"),
BUILD_IOVEC("async"), {NULL, 0},
BUILD_IOVEC("ignoreacl"), {NULL, 0}};
return nmount((struct iovec *)iov, sizeof(iov) / sizeof(iov[0]),
MNT_UPDATE) == 0;
}
static void cleanup(void) {
if (sock.fd != -1) {
close(sock.fd);
sock.fd = -1;
}
// Notify user about cleanup
notify("etaHEN has been cleaned up.");
// Exit the program
exit(0);
}
// FileDescriptor methods implementations
FileDescriptor FileDescriptor_init(int fd) {
FileDescriptor newFd;
newFd.fd = fd;
return newFd;
}
void release(FileDescriptor *fd) {
fd->fd = -1;
}
// Stdout initialization logic
int initStdout() {
// Check for logging file existence logic here
// For simplicity, I'm assuming it always exists
char error_msg[500] = {0};
sock.fd = -1;
sock = FileDescriptor_init(socket(AF_INET, SOCK_STREAM, 0));
if (sock.fd == -1) {
snprintf(error_msg, sizeof(error_msg), "Failed to create socket: %s",
strerror(errno));
notify(error_msg);
return -1;
}
int value = 1;
if (setsockopt(sock.fd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)) < 0) {
snprintf(error_msg, sizeof(error_msg), "Failed to set socket options: %s",
strerror(errno));
notify(error_msg);
return -1;
}
struct sockaddr_in server_addr;
(void)memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(LOGGER_PORT);
server_addr.sin_addr.s_addr = 0;
if (bind(sock.fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) {
snprintf(error_msg, sizeof(error_msg), "Failed to bind socket: %s",
strerror(errno));
notify(error_msg);
return -1;
}
if (listen(sock.fd, 1) != 0) {
snprintf(error_msg, sizeof(error_msg), "Failed to listen on socket: %s",
strerror(errno));
notify(error_msg);
return -1;
}
struct sockaddr client_addr;
socklen_t addr_len = sizeof(client_addr);
int conn = accept(sock.fd, &client_addr, &addr_len);
if (conn != -1) {
dup2(conn, STDOUT);
dup2(conn, STDERR);
close(conn);
return conn;
}
snprintf(error_msg, sizeof(error_msg), "Failed to accept connection: %s",
strerror(errno));
notify(error_msg);
return -1;
}
// Function to check if the file buffer contains a valid custom plugin header
bool is_valid_plugin(const unsigned char *file_buffer) {
// Check if the prefix matches
if (strncmp((const char *)file_buffer, "etaHEN_PLUGIN", 13) != 0) {
puts("Plugin header prefix does not match");
return false;
}
// Validate the title ID format (4 uppercase letters followed by 4 numbers)
const CustomPluginHeader *header = (const CustomPluginHeader *)file_buffer;
for (int i = 0; i < 4; ++i) {
if (header->titleID[i] < 'A' || header->titleID[i] > 'Z') {
puts("Invalid plugin file: titleID must contain 4 uppercase letters as "
"the start");
return false;
}
}
for (int i = 4; i < 9; ++i) {
if (header->titleID[i] < '0' || header->titleID[i] > '9') {
puts("Invalid plugin file: titleID must contain 5 numbers as the end");
return false;
}
}
// Ensure the title ID is null-terminated
if (header->titleID[9] != '\0') {
puts("Invalid plugin file: titleID must be null-terminated");
return false;
}
for (int i = 0; i < 3; ++i) {
if (header->plugin_version[i] == '.') {
continue;
} else if (header->plugin_version[i] < '0' ||
header->plugin_version[i] > '9') {
puts(
"Invalid plugin file: version must be in the following format xx.xx");
return false;
}
}
return true;
}
// Function to return the address of the ELF header, skipping the custom plugin header
uint8_t *get_elf_header_address(unsigned char *file_buffer) {
// The ELF header should start right after the custom plugin header
return file_buffer + sizeof(CustomPluginHeader);
}
pid_t find_pid(const char * name) {
int mib[4] = {
CTL_KERN,
KERN_PROC,
KERN_PROC_PROC,
0
};
size_t buf_size;
void * buf;
int pid = -1;
// determine size of query response
if (sysctl(mib, 4, NULL,&buf_size, NULL, 0)) {
printf("sysctl failed: %s\n", strerror(errno));
return -1;
}
// allocate memory for query response
if (!(buf = malloc(buf_size))) {
printf("malloc failed %s\n", strerror(errno));
return -1;
}
// query the kernel for proc info
if (sysctl(mib, 4, buf,&buf_size, NULL, 0)) {
printf("sysctl failed: %s\n", strerror(errno));
free(buf);
return -1;
}
for (char * ptr = static_cast < char * > (buf); ptr < (static_cast < char * > (buf) + buf_size);) {
struct kinfo_proc * ki = reinterpret_cast < struct kinfo_proc * > (ptr);
ptr += ki->ki_structsize;
if(strlen(ki->ki_comm) < 2)
continue;
if (strstr(ki->ki_comm, name) != NULL) {
pid = ki->ki_pid;
break;
}
}
free(buf);
return pid;
}
bool is_elf_file(const void* buffer, size_t size) {
if (size < 4) return false;
const unsigned char elf_magic[] = {0x7F, 'E', 'L', 'F'};
return memcmp(buffer, elf_magic, 4) == 0;
}
bool load_plugin(const char *path, const char *filename)
{
int fd = open(path, O_RDONLY);
if (fd < 0)
{
perror("Failed to open file");
return false;
}
struct stat st;
if (fstat(fd, &st) != 0)
{
perror("Failed to get file stats");
close(fd);
return false;
}
// Allocate buffer and read the entire file.
uint8_t *buf = (uint8_t *)malloc(st.st_size);
if (!buf)
{
perror("Failed to allocate memory for Plugin file");
close(fd);
return false;
}
if (read(fd, buf, st.st_size) != st.st_size)
{
perror("Failed to read Plugin file");
free(buf), buf = NULL;
close(fd);
return false;
}
close(fd);
const CustomPluginHeader *header = (const CustomPluginHeader *)buf;
char pbuf[256];
snprintf(pbuf, sizeof(pbuf), "/system_tmp/%s.PID", header->titleID);
if (strstr(filename, ".elf") != NULL)
{
// Handle ELF plugin loading
if (!is_elf_file(buf, st.st_size))
{
free(buf), buf = NULL;
return false;
}
pid_t pid = -1;
int f = open(pbuf, O_RDONLY);
if (f >= 0)
{
char t[32];
int r = read(f, t, sizeof(t) - 1);
close(f);
if (r > 0)
{
t[r] = 0;
pid = atoi(t);
}
}
if (pid > 0)
{
char name[32];
if (sceKernelGetProcessName(pid, name) < 0)
{
printf("Stale plugin PID file detected for %s, removing\n", header->titleID);
unlink(pbuf);
pid = -1;
}
}
printf("seeing if elf is running\n");
if (pid > 0)
{
printf("killing pid %d\n", pid);
if (kill(pid, SIGKILL))
perror("kill");
unlink(pbuf);
}
printf("loading elf %s\n", filename);
pid = elfldr_spawn("/", sock.fd, buf, header->titleID);
if (pid >= 0)
printf(" Launched!\n");
else
printf(" Already Running!\n");
free(buf), buf = NULL;
f = open(pbuf, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (f >= 0)
{
if (pid >= 0)
{
char t[32];
int l = snprintf(t, sizeof(t), "%d", pid);
write(f, t, l);
}
else
{
unlink(pbuf);
}
close(f);
}
return true;
}
if (!is_valid_plugin(buf))
{
puts("Invalid plugin file.");
free(buf), buf = NULL;
return false;
}
puts("============== Plugin info ===============");
printf("Plugin Prefix: %s\n", header->prefix);
printf("Plugin TitleID: %s\n", header->titleID);
printf("Plugin Version: %s\n", header->plugin_version);
puts("=========================================");
snprintf(pbuf, sizeof(pbuf), "/system_tmp/%s.PID", header->titleID);
uint8_t *elf = get_elf_header_address(buf);
pid_t pid = -1;
int f = open(pbuf, O_RDONLY);
if (f >= 0)
{
char t[32];
int r = read(f, t, sizeof(t) - 1);
close(f);
if (r > 0)
{
t[r] = 0;
pid = atoi(t);
}
}
if (pid > 0)
{
char name[32];
if (sceKernelGetProcessName(pid, name) < 0)
{
printf("Stale plugin PID file detected for %s, removing\n", header->titleID);
unlink(pbuf);
pid = -1;
}
}
printf("seeing if plugin is running\n");
if (pid > 0)
{
printf("killing pid %d\n", pid);
if (kill(pid, SIGKILL))
perror("kill");
unlink(pbuf);
}
if (strcmp(header->titleID, "EORR37000") == 0)
{
notify("The Error disabler plugin is no longer required and has been auto deleted.");
unlink(path);
free(buf), buf = NULL;
return true;
}
printf("loading plugin %s\n", path);
pid = elfldr_spawn("/", sock.fd, elf, header->titleID);
if (pid >= 0)
printf(" Launched!\n");
else
printf(" Already Running!\n");
f = open(pbuf, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (f >= 0)
{
if (pid >= 0)
{
char t[32];
int l = snprintf(t, sizeof(t), "%d", pid);
write(f, t, l);
}
else
{
unlink(pbuf);
}
close(f);
}
free(buf), buf = NULL;
return true;
}
/*=================== LOAD PLUGINS =========================*/
char **find_plugin_files() {
const char *base_dirs[] = {
// Plugin directories
"/mnt/usb0/etahen/plugins", "/mnt/usb0/etaHEN/plugins",
"/mnt/usb1/etahen/plugins", "/mnt/usb2/etahen/plugins",
"/mnt/usb3/etahen/plugins", "/user/data/etaHEN/plugins",
"/user/data/etahen/plugins",
// Payload directories
"/mnt/usb0/etahen/payloads", "/mnt/usb0/etaHEN/payloads",
"/mnt/usb1/etahen/payloads", "/mnt/usb2/etahen/payloads",
"/mnt/usb3/etahen/payloads", "/user/data/etaHEN/payloads",
"/user/data/etahen/payloads"
};
int base_dirs_count = sizeof(base_dirs) / sizeof(base_dirs[0]);
char **plugin_paths = NULL;
char full_path[255];
char auto_start_path[255];
plugin_count = 0;
loaded_filenames = (char **)malloc(255 * sizeof(char *));
for (int i = 0; i < base_dirs_count; i++) {
DIR *dir = opendir(base_dirs[i]);
if (dir) {
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
(void)memset(full_path, 0, sizeof(full_path));
if (entry->d_type == DT_REG) { // Regular file
const char *ext = strrchr(entry->d_name, '.');
if (ext && (strcmp(ext, ".plugin") == 0 || strcmp(ext, ".elf") == 0)) {
bool skip = false;
// Construct full path
snprintf(full_path, sizeof(full_path), "%s/%s", base_dirs[i],
entry->d_name);
snprintf(auto_start_path, sizeof(auto_start_path),
"%s/%s.auto_start", base_dirs[i], entry->d_name);
if (!if_exists(auto_start_path)) {
printf("skipping auto start for plugin: %s\n", full_path);
continue;
}
for (int j = 0; j < plugin_count; j++) {
if (strcmp(loaded_filenames[j], entry->d_name) == 0) {
skip = true;
// Only print the message for /data/etaHEN/plugins/elfldr.plugin
// as per specific requirement
if ((strcmp(base_dirs[i], "/data/etaHEN/plugins") == 0) || (strcmp(entry->d_name, "/data/etaHEN/payloads") == 0)) {
printf("skipping duplicate plugin: %s | already loaded: %s\n",
full_path, loaded_filenames[j]);
}
break;
}
}
if (skip)
continue;
// Add to array
plugin_paths = (char **)realloc(plugin_paths, (plugin_count + 1) *
sizeof(char *));
plugin_paths[plugin_count] = strdup(full_path);
// Copy filename to loaded_filenames
loaded_filenames[plugin_count] =
strdup(entry->d_name); // Use strdup for simplicity
plugin_count++;
}
}
}
closedir(dir);
}
}
return plugin_paths;
}
void free_plugin_files(char **plugin_files) {
// Free memory for loaded_filenames
for (int i = 0; i < plugin_count; i++) {
free(loaded_filenames[i]);
}
free(loaded_filenames);
for (int i = 0; i < plugin_count; i++) {
free((void *)plugin_files[i]);
}
free((void *)plugin_files);
}
bool Byepervisor();
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]);
}
const char *whitelisted_psids[] = {
"b345df7d4c77618d40f19a90e438ad87",
"ab535275b7196e7e7d43f4f9e7806724",
"d376c7780b960e5182d326ba3aa2d7a3",
"a8d89ad976b5cb912837ad29b0cc4610",
"177e09480b40816a1caca5151565daa5",
};
#if 0
printf("PSID: %s\n", psid_buf);
char buff[300];
snprintf(buff, sizeof buff, "PSID: %s", psid_buf);
notify(buff);
#endif
for (int i = 0; i < sizeof(whitelisted_psids) / sizeof(whitelisted_psids[0]);
i++) {
if (strcmp(psid_buf, whitelisted_psids[i]) == 0) {
// printf("PSID (%s) whitelisted\n", psid_buf);
return false; // report not testkit if is whitelisted
}
}
// printf("PSID (%s) Not whitelisted\n", psid_buf);
return if_exists("/system/priv/lib/libSceDeci5Ttyp.sprx");
}
#define PUBLIC_TEST 0
#define EXPIRE_YEAR 2025
#define EXPIRE_MONTH 12
#define EXPIRE_DAY 25
bool isPastBetaDate(int year, int month, int day);
int main(void) {
// ptrace(PT_ATTACH, pid, 0, 0);
/// clearFramePointer();
int pid = -1;
#if BETA == 1
char out[1024];
#endif
signal(SIGCHLD, SIG_IGN);
klog_puts("Jailbreaking the boostrapper ...");
// launch socksrv.elf in a new processes
if (elfldr_raise_privileges(getpid())) {
notify("Unable to raise privileges");
return -1;
}
#if BETA == 1
printf("Get_code %d", GetDecryptedConsoleCode(
&out[0])); // ignore return value because we need to
// call is_console_whitelisted anyway
bool is_whitelisted = is_console_whitelisted(
&buffer[0], &out[0]); // gets PSID if its not whitelisted too
#endif
#if BETA == 1 || PUBLIC_TEST == 1
if (isPastBetaDate(EXPIRE_YEAR, EXPIRE_MONTH, EXPIRE_DAY)) {
notify("This etaHEN Beta version expired on %d-%d-%d", EXPIRE_YEAR,
EXPIRE_MONTH, EXPIRE_DAY);
return -1;
raise(SIGSEGV);
}
#endif
#if 0
if (sceKernelIsTestKit()) {
notify("support dropped for testkits if you donated to my ko-fi and are NOT andrew send me a message");
return 0;
}
#endif
klog_printf(" Success!\n");
if(if_exists("/data/I_want_logging_for_etahen")){
klog_printf("Redirecting stdout and stderr to logger ...");
if(initStdout() >= 0)
klog_puts(" Success!");
else
klog_puts(" Failed!");
}
#if BETA == 1
if (!is_whitelisted) {
notify("This console is NOT approved to use this etaHEN beta version\n\nIf "
"you are not yet approved send LM the pending_approval.bin file "
"from your USB for the etaHEN_approval.bin");
int fd = open("/mnt/usb0/pending_approval.bin", O_CREAT | O_TRUNC | O_RDWR,
0777);
if (fd < 0) {
fd = open("/mnt/usb1/pending_approval.bin", O_CREAT | O_TRUNC | O_RDWR,
0777);
if (fd < 0) {
fd = open("/mnt/usb2/pending_approval.bin", O_CREAT | O_TRUNC | O_RDWR,
0777);
}
if (fd >= 0) {
write(fd, buffer, strlen(buffer));
close(fd);
} else {
notify("No USB Found to save pending_approval.bin\n\nInsert a EXFAT USB "
"then re-run this payload");
}
return -1;
raise(SIGSEGV);
}
#endif
OrbisKernelSwVersion sys_ver;
sceKernelGetProsperoSystemSwVersion(&sys_ver);
if (sys_ver.version < 0x3000000 && !sceKernelIsGenuineDevKit()) {
klog_printf("FW %s version has Byepervisor available, sstarting....\n", sys_ver.version_str);
if (!Byepervisor()) {
printf("Byepervisor failed or is resume_nedded");
return 0;
}
}
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);
klog_printf("Registering signal handler ...");
fault_handler_init(cleanup);
klog_printf(" Success!\n");
klog_printf("Remounting system partitions ...");
if (!remount("/dev/ssd0.system_ex", "/system_ex")) {
perror("failed to mount /system_ex\nif you see this reboot");
notify("failed to mount /system_ex\nif you see this reboot");
return -1;
}
if (!remount("/dev/ssd0.system", "/system")) {
perror("failed to mount /system_\nif you see this reboot");
notify("failed to mount /system\nif you see this reboot");
return -1;
}
klog_printf(" Success!\n");
klog_printf("Writing embedded assets ...");
write_embedded_assets();
klog_printf(" Written!\n");
klog_printf("Unmounting /update forcefully ...");
// block updates
unlink("/update/PS5UPDATE.PUP");
unlink("/update/PS5UPDATE.PUP.net.temp");
// unlink("/update/PS4UPDATE.PUP.md5");
if ((int)unmount("/update", 0x80000LL) < 0) {
unmount("/update", 0);
}
klog_puts(" Success!");
#if 1
char buz[100] = { 0 };
// Load kstuff if needed
bool dont_load_kstuff = (if_exists("/mnt/usb0/no_kstuff") || if_exists("/data/etaHEN/no_kstuff"));
if (dont_load_kstuff) {
notify("kstuff loading disabled via file, non-payload homebrew and PS4 FPKGs will be disabled");
klog_puts("kstuff loading disabled in config.ini or no_kstuff file found");
}
if (!dont_load_kstuff && sys_ver.version >= 0x3000000) {
notify("Loading kstuff ...");
bool cleanup_kstuff = false;
uint8_t* kstuff_address = get_kstuff_address(cleanup_kstuff);
if (elfldr_spawn("/", STDOUT_FILENO, kstuff_address, "kstuff")) {
int wait = 0;
bool kstuff_not_loaded = false;
sleep(1);
while ((kstuff_not_loaded = sceKernelMprotect(&buz[0], 100, 0x7) < 0)) {
if (wait++ > 10) {
notify("Failed to load kstuff, kstuff will be unavailable");
break;
}
sleep(1);
}
if (!kstuff_not_loaded)
klog_puts("kstuff loaded");
if (cleanup_kstuff) {
free(kstuff_address);
}
}
else {
notify("Failed to load kstuff, kstuff will be unavailable");
}
}
sleep(1);
#endif
klog_printf("Starting Utility etaHEN services ...");
while ((pid = find_pid("etaHEN")) > 0) {
// printf("killing pid %d\n", pid);
if (kill(pid, SIGKILL)) {
perror("kill");
}
}
if (elfldr_spawn("/", sock.fd, util_start, "etaHEN Utility Daemon") >= 0) {
klog_printf(" Launched!\n");
// Open the file with write permission, create if not exist, truncate to zero if exists
int fd = open("/data/etaHEN/daemons/util.elf", O_WRONLY | O_CREAT | O_TRUNC, 0777);
if (fd == -1) {
perror("open failed");
return -1337;
}
// Write the buffer to the file
if (write(fd, util_start, util_size) == -1) {
perror("write failed");
}
// Close the file descriptor
close(fd);
} else {
klog_printf("failed to launch utility daemon\n");
notify("failed to launch the etaHEN utility daemon");
return -2;
}
klog_printf("Starting the main etaHEN daemon ...");
if (elfldr_spawn("/", sock.fd, daemon_start, "etaHEN Critical services") >= 0) {
klog_printf(" Launched!\n");
} else {
klog_printf("failed to launch main daemon\n");
notify("failed to launch the main etaHEN daemon");
return -2;
}
// return 0;
char **plugin_paths = find_plugin_files();
if (plugin_paths && plugin_count > 0) {
int loaded_plugins = 0;
// First, load all plugins except elfldr.plugin
for (int i = 0; i < plugin_count; i++) {
// Skip loading elfldr.plugin in this loop
if (strstr(plugin_paths[i], "elfldr") == 0) {
klog_printf("Loading plugin: %s\n", plugin_paths[i]);
if (!load_plugin(plugin_paths[i], loaded_filenames[i])) {
snprintf(buff, sizeof(buff),
"[etaHEN] Failed to load plugin!\nPath: %s",
plugin_paths[i]);
notify(buff);
klog_puts("FAILED!");
continue;
}
klog_puts("Loaded!");
loaded_plugins++;
}
}
//(void)memset(buff, 0, sizeof(buff));
// snprintf(buff, sizeof(buff), "Successfully loaded %d plugins",
// loaded_plugins); notify(buff);
klog_printf("Successfully loaded %d plugins\n", loaded_plugins);
free_plugin_files(plugin_paths);
}
// raise(SIGKILL, getpid());
// sceSystemServiceLoadExec("exit", NULL);
klog_puts("============== Spawner (Bootstrapper) Finished =================");
return 0;
}