etaHEN 2.4B

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
This commit is contained in:
LightningMods
2025-12-01 19:53:57 -05:00
parent 7967c0a633
commit 0fe0407b3a
86 changed files with 33743 additions and 3123 deletions

View File

@@ -5,7 +5,7 @@
## 🚀 **Support the Project**
If you find this project useful and would like to support its continued development, consider buying me a coffee!
[![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/lightningmods)
[![GitHub Sponsers](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://github.com/sponsors/LightningMods)
## Building from Source
@@ -14,7 +14,7 @@ However I will not be providing instructions on how to build it since any dev sh
## Official PS5 exploit website
- https://tinyurl.com/PS5IPV6 (requires you to manually send the payload but has the best stability)
- https://ps5jb.pages.dev/ (auto loads the payload for you, id recommand the IPV6 exploit over UMTX)
- https://ps5jb.pages.dev/ (auto loads the payload for you, id recommend the IPV6 exploit over UMTX)
## Recommended self-host exploits
- [Modified IPV6 exploit for etaHEN support](https://github.com/LightningMods/PS5-IPV6-Kernel-Exploit)
@@ -60,6 +60,8 @@ Port: XXXX
- [Toolbox] Plugin / Payload ELF Menu with auto start options
- [Toolbox] External HDD Menu
- [Toolbox] TestKit Menu
- [Toolbox] Kstuff menu
- [Toolbox] Game Overlay Menu
- [Toolbox] Cheats Menu (WIP)
- [Toolbox] Controller Shortcuts
- [Toolbox] PS5 webMAN Games menu
@@ -101,7 +103,6 @@ More info [Here](https://github.com/LightningMods/etaHEN-SDK/blob/main/README.md
## Upcoming features
- [Toolbox] FPS Counter
- [Toolbox] On-Screen temps and other info (for retails)
- More userland patches
- Improved PS5 Game support (itemzflow)
- More (consider donating)
@@ -137,6 +138,13 @@ and is automatically created when you run etaHEN for the first time
| `Toolbox_shortcut_opt` | Multi-select option for toolbox shortcut | 0 (TOOLBOX_SC_OFF) |
| `Games_shortcut_opt` | Multi-select option for games shortcut | 0 (GAMES_SC_OFF) |
| `Kstuff_shortcut_opt` | Multi-select option for kstuff shortcut | 0 (KSTUFF_SC_OFF) |
| `auto_eject_disc` | 0 = disabled, 1 = enabled | 0 (disabled) |
| `overlay_ram` | 0 = disabled, 1 = enabled | 0 (disabled) |
| `overlay_cpu` | 0 = disabled, 1 = enabled | 0 (disabled) |
| `overlay_gpu` | 0 = disabled, 1 = enabled | 0 (disabled) |
| `overlay_ip` | 0 = disabled, 1 = enabled | 1 (enabled) |
| `overlay_kstuff` | 0 = disabled, 1 = enabled | 1 (enabled) |
| `Overlay_pos` | Multi-select option for game overlay | 0 (OVERLAY_POS_TOP_LEFT) |
## DPI API details for tool creators
etaHEN's Direct PKG Installer currently is very simple and is considered a WIP
@@ -154,7 +162,7 @@ the service flow is as follows
4. etaHEN will close the client socket after the return json is sent
## Jailbreaking an app (FPKG) using etaHEN (non-whitelist method, Network required)
## Jailbreaking an app (FPKG) using etaHEN (non-whitelist method, Network and Legacy CMD server toolbox setting required)
```
enum Commands : int {

View File

@@ -16,8 +16,10 @@ add_subdirectory(libNidResolver)
# add_subdirectory(libRPI)
add_subdirectory(libSelfDecryptor)
add_subdirectory(libNineS)
add_subdirectory(libelfldr)
add_subdirectory(shellui)
add_subdirectory(fps_elf)
add_subdirectory(daemon)
add_subdirectory(util)
add_subdirectory(bootstrapper)
add_subdirectory(unpacker)
add_subdirectory(unpacker)

View File

@@ -74,10 +74,12 @@ const uint8_t g_ypkg_iqmp[] =
0x28, 0xFD, 0x55, 0x56, 0x31, 0x94, 0x65, 0x05, 0xE7, 0xD3, 0x57, 0x6C, 0x0D, 0x1C, 0x67, 0x0B,
};
/* unused variable
const uint8_t g_FakeKeySeed[] =
{
0x46, 0x41, 0x4B, 0x45, 0x46, 0x41, 0x4B, 0x45, 0x46, 0x41, 0x4B, 0x45, 0x46, 0x41, 0x4B, 0x45,
};
*/
int npdrm_cmd_5_sceSblServiceMailbox(uint64_t handle, const NpDrmCmd5* input, NpDrmCmd5* output) {
//auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF);
@@ -436,83 +438,53 @@ void hex_dump(const char *name, uint8_t *buf, int len)
}
}
int sceSblServiceCryptAsync_hook(void *async_req)
{
struct ccp_common *msg;
struct ccp_common *next;
struct ccp_req* req;
int sceSblServiceCryptAsync_hook(void* async_req) {
struct ccp_common* msg;
struct ccp_common* next;
int idx = -1;
//auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF);
auto sceSblServiceCryptAsync = (int (*)(void *req)) kdlsym(KERNEL_SYM_SCE_SBL_SERVICE_CRYPT_ASYNC);
auto Sha256Hmac = (void (*)(void *hash, void *data, size_t data_sz, void *key, size_t key_size)) kdlsym(KERNEL_SYM_SHA256_HMAC);
msg = (struct ccp_common*)(*(uint64_t*)(async_req));
auto sceSblServiceCryptAsync = (int (*)(void* req)) kdlsym(KERNEL_SYM_SCE_SBL_SERVICE_CRYPT_ASYNC);
req = (struct ccp_req *) async_req;
msg = (struct ccp_common *) (*(uint64_t *) (async_req));
//printf("sceSblServiceCryptAsync_hook: msg = %p, before (msg->cmd = 0x%x) (first=%p, last=%p)\n", msg, msg->cmd, req->tqh_first, *req->tqh_last);
while (msg) {
next = (struct ccp_common *) (*(uint64_t *) ((uint64_t) (msg) + 0x140));
//printf("msg = %p (msg->cmd = 0x%x), next = %p \n", msg, msg->cmd, next);
next = (struct ccp_common*)(*(uint64_t*)((uint64_t)(msg)+0x140));
if ((msg->cmd & 0x7FFFFFFF) == 0x9132000) { // SHA256 HMAC with key handle
struct ccp_hmac *hmac_msg = (struct ccp_hmac *) msg;
if ((msg->cmd & 0x7FFFFFFF) == 0x9132000) {
// SHA256 HMAC with key handle
struct ccp_hmac* hmac_msg = (struct ccp_hmac*)msg;
idx = HANDLE_TO_IDX(hmac_msg->key_index);
//printf("sceSblServiceCryptAsync_hook: SHA256 hmac key idx = 0x%x\n", idx);
if (idx < 0) {
return sceSblServiceCryptAsync(async_req);
} else {
char hmac_key[0x40];
get_fake_key(idx, (char *) &hmac_key);
if (idx >= 0) {
char hmac_key[0x20];
get_fake_key(idx, (char*)&hmac_key);
// hex_dump("hmac ccp msg", (uint8_t *) hmac_msg, 0x200);
// hex_dump("hmac key", (uint8_t *) hmac_key, 0x40);
Sha256Hmac(hmac_msg->hash, hmac_msg->data, hmac_msg->data_size, hmac_key, 0x20);
// printf("hmac data=%p, data_size = 0x%lx\n", hmac_msg->data, hmac_msg->data_size);
// hex_dump("hmac input (first 0x20 bytes)", (uint8_t *) hmac_msg->data, 0x20);
// hex_dump("hmac hash output", (uint8_t *) hmac_msg->hash, 0x20);
memcpy(hmac_msg->key, hmac_key, 0x20);
msg->cmd &= ~0x100000; // key handle
msg->cmd &= ~0x80000000; // a53
}
} else if ((msg->cmd & 0x7FFFF7FF) == 0x2108000) { // AES-XTS with key handle
struct ccp_xts *xts_msg = (struct ccp_xts *) msg;
}
else if ((msg->cmd & 0x7FFFF7FF) == 0x2108000) {
// AES-XTS with key handle
struct ccp_xts* xts_msg = (struct ccp_xts*)msg;
idx = HANDLE_TO_IDX(xts_msg->key_index);
//printf("sceSblServiceCryptAsync_hook: AES-XTS key idx = 0x%x\n", idx);
if (idx < 0) {
return sceSblServiceCryptAsync(async_req);
} else {
char xts_key[0x40];
get_fake_key(idx, (char *) &xts_key);
if (idx >= 0) {
char xts_key[0x20];
get_fake_key(idx, (char*)&xts_key);
// printf("xts in=%p, out=%p (is_encrypt=%d)\n", xts_msg->in_data, xts_msg->out_data, ((xts_msg->common.cmd & 0x800) >> 11));
// printf("xts->start_sector = 0x%lx, num_sectors = 0x%lx\n", xts_msg->start_sector, xts_msg->num_sectors);
// hex_dump("xts ccp msg", (uint8_t *) xts_msg, 0x200);
// hex_dump("xts tweak/key", (uint8_t *) xts_key, 0x20);
// hex_dump("xta data", (uint8_t *) xts_msg->in_data, 0x20);
void *tweak = (void *) ((uint64_t) (xts_key) + 0x00);
void *key = (void *) ((uint64_t) (xts_key) + 0x10);
if (((xts_msg->common.cmd & 0x800) >> 11)) {
aes_xts_4096_dec(xts_msg->in_data, xts_msg->out_data, xts_msg->num_sectors, xts_msg->start_sector, key, tweak, 1);
} else {
aes_xts_4096_dec(xts_msg->in_data, xts_msg->out_data, xts_msg->num_sectors, xts_msg->start_sector, key, tweak, 0);
}
// hex_dump("xts decrypted output (first 0x20 bytes)", (uint8_t *) xts_msg->out_data, 0x20);
memcpy(xts_msg->key, xts_key + 0x10, 0x10);
memcpy(xts_msg->key + 0x10, xts_key, 0x10);
msg->cmd &= ~0x100000; // key handle
msg->cmd &= ~0x80000000; // a53
}
}
msg = next;
}
if (idx == -1) {
return sceSblServiceCryptAsync(async_req);
}
req->cb(req->args, 0);
return 0;
return sceSblServiceCryptAsync(async_req);
}
int sceSblPfsClearKey_sceSblServiceMailbox(uint64_t handle, const ClearKey* input, ClearKey* output)

View File

@@ -1,9 +1,3 @@
###################################################################################################
# PS5SDK - Example: pipe pirate
# Uses the read/write primitive to read and write some kernel data.
# @authors ChendoChap, Specter, Znullptr
###################################################################################################
cmake_minimum_required (VERSION 3.20)
set(basename "bootstrapper")
@@ -66,9 +60,16 @@ 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 SceShellUIUtil)
target_link_libraries (${PROJECT_NAME} PUBLIC NineS SceSystemService SceUserService kernel_sys elfldr sqlite3)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_dependencies(${PROJECT_NAME} daemon util shellui)
# Copy bootstrapper.elf as test.elf before processing
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${PROJECT_NAME}> ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test.elf
COMMENT "Copying ${PROJECT_NAME}.elf to test.elf"
)
# Add post-build command
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_OBJCOPY} --remove-section .debug_info --remove-section .debug_abbrev --remove-section .debug_line --remove-section .debug_str --remove-section .debug_loc --remove-section .debug_aranges --remove-section .debug_ranges --remove-section .debug_pubnames --remove-section .debug_pubtypes --remove-section .debug_frame --strip-unneeded $<TARGET_FILE:${PROJECT_NAME}>
@@ -83,4 +84,4 @@ add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND lzma -f -9 $<TARGET_FILE:${PROJECT_NAME}>
COMMENT "Compressing with lzma -9 (Max compression rate)"
)
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View File

@@ -60,4 +60,17 @@ __asm__(".intel_syntax noprefix\n"
".align 4\n"
"webman_icon_size:\n"
".int webman_icon_end - webman_icon_start\n"
".global kstuff_start\n"
".type kstuff_start, @object\n"
".align 16\n"
"kstuff_start:\n"
".incbin \"assets/kstuff.elf\"\n"
"kstuff_end:\n"
".global kstuff_size\n"
".type kstuff_size, @object\n"
".align 4\n"
"kstuff_size:\n"
".int kstuff_end - kstuff_start\n"
);

View File

@@ -41,6 +41,14 @@ along with this program; see the file COPYING. If not, see
#include <sys/un.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
/******************************************************************************
* Custom Header Includes
@@ -53,7 +61,17 @@ along with this program; see the file COPYING. If not, see
#include "faulthandler.h"
#include "hbldr.h"
#include "pt.h"
#include <ps5/klog.h>
#include <ps5/kernel.h>
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;
}
/******************************************************************************
@@ -220,7 +238,6 @@ along with this program; see the file COPYING. If not, see
char buff[255];
char **loaded_filenames = NULL;
jmp_buf g_catch_buf;
static int gAppId = 0;
FileDescriptor sock;
// Constants
@@ -246,11 +263,25 @@ static void cleanup(void);
/******************************************************************************
* 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 (!if_exists("/data/etaHEN/assets/store.png")) {
#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");
@@ -298,6 +329,68 @@ static void cleanup(void);
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;
@@ -504,104 +597,197 @@ bool is_elf_file(const void* buffer, size_t size) {
return memcmp(buffer, elf_magic, 4) == 0;
}
bool load_plugin(const char *path, const char* filename) {
bool load_plugin(const char *path, const char *filename)
{
int fd = open(path, O_RDONLY);
if (fd < 0) {
if (fd < 0)
{
perror("Failed to open file");
return false;
}
struct stat st;
if (fstat(fd, &st) != 0) {
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) {
if (!buf)
{
perror("Failed to allocate memory for Plugin file");
close(fd);
return false;
}
if (read(fd, buf, st.st_size) != st.st_size) {
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);
if (strstr(filename, ".elf") != NULL) {
// Handle ELF plugin loading
if (!is_elf_file(buf, st.st_size)) {
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;
}
pid_t pid = 0;
printf("seeing if elf is running\n");
while ((pid = find_pid(filename)) > 0) {
printf("killing pid %d\n", pid);
if (kill(pid, SIGKILL)) {
perror("kill");
}
break;
}
printf("loading elf %s\n", filename);
if (elfldr_spawn("/", sock.fd, buf, filename) >= 0) {
printf(" Launched!\n");
} else {
printf(" Already Running!\n");
}
free(buf), buf = NULL;
return true;
}
if (!is_valid_plugin(buf)) {
if (!is_valid_plugin(buf))
{
puts("Invalid plugin file.");
free(buf), buf = NULL;
return false;
}
const CustomPluginHeader *header = (const CustomPluginHeader *)buf;
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("=========================================");
// Get the address of the ELF header
snprintf(pbuf, sizeof(pbuf), "/system_tmp/%s.PID", header->titleID);
uint8_t *elf = get_elf_header_address(buf);
pid_t pid = gAppId = 0;
printf("seeing if plugin is running\n");
while ((pid = find_pid(header->titleID)) > 0) {
printf("killing pid %d\n", pid);
if (kill(pid, SIGKILL)) {
perror("kill");
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);
}
break;
}
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; // Do not load the plugin if it's EORR37000
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);
if (elfldr_spawn("/", sock.fd, elf, header->titleID) >= 0) {
pid = elfldr_spawn("/", sock.fd, elf, header->titleID);
if (pid >= 0)
printf(" Launched!\n");
} else {
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;
@@ -745,6 +931,13 @@ bool sceKernelIsTestKit() {
// 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);
@@ -757,7 +950,7 @@ int main(void) {
signal(SIGCHLD, SIG_IGN);
puts("Jailbreaking the boostrapper ...");
klog_puts("Jailbreaking the boostrapper ...");
// launch socksrv.elf in a new processes
if (elfldr_raise_privileges(getpid())) {
notify("Unable to raise privileges");
@@ -789,13 +982,13 @@ int main(void) {
#endif
printf(" Success!\n");
klog_printf(" Success!\n");
if(if_exists("/data/I_want_logging_for_etahen")){
printf("Redirecting stdout and stderr to logger ...");
klog_printf("Redirecting stdout and stderr to logger ...");
if(initStdout() >= 0)
puts(" Success!");
klog_puts(" Success!");
else
puts(" Failed!");
klog_puts(" Failed!");
}
@@ -834,7 +1027,7 @@ int main(void) {
sceKernelGetProsperoSystemSwVersion(&sys_ver);
if (sys_ver.version < 0x3000000 && !sceKernelIsGenuineDevKit()) {
printf("FW %s version has Byepervisor available, sstarting....\n", sys_ver.version_str);
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;
@@ -845,18 +1038,18 @@ int main(void) {
notify("[Bootstrapper] etaHEN is starting...\n DO NOT EXIT \nwait for "
"the etaHEN welcome message");
puts("============== Spawner (Bootstrapper) Started =================");
klog_puts("============== Spawner (Bootstrapper) Started =================");
mkdir("/data/etaHEN", 0777);
mkdir("/data/etaHEN/plugins", 0777);
mkdir("/data/etaHEN/payloads", 0777);
mkdir("/data/etaHEN/daemons", 0777);
printf("Registering signal handler ...");
klog_printf("Registering signal handler ...");
fault_handler_init(cleanup);
printf(" Success!\n");
klog_printf(" Success!\n");
printf("Remounting system partitions ...");
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");
@@ -867,13 +1060,13 @@ int main(void) {
notify("failed to mount /system\nif you see this reboot");
return -1;
}
printf(" Success!\n");
klog_printf(" Success!\n");
printf("Writing embedded assets ...");
klog_printf("Writing embedded assets ...");
write_embedded_assets();
printf(" Written!\n");
klog_printf(" Written!\n");
printf("Unmounting /update forcefully ...");
klog_printf("Unmounting /update forcefully ...");
// block updates
unlink("/update/PS5UPDATE.PUP");
unlink("/update/PS5UPDATE.PUP.net.temp");
@@ -882,9 +1075,49 @@ int main(void) {
unmount("/update", 0);
}
printf(" Success!\n");
klog_puts(" Success!");
printf("Starting Utility etaHEN services ...");
#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);
@@ -894,14 +1127,13 @@ int main(void) {
}
if (elfldr_spawn("/", sock.fd, util_start, "etaHEN Utility Daemon") >= 0) {
printf(" Launched!\n");
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");
@@ -910,19 +1142,19 @@ int main(void) {
// Close the file descriptor
close(fd);
} else {
printf("failed to launch utility daemon\n");
klog_printf("failed to launch utility daemon\n");
notify("failed to launch the etaHEN utility daemon");
return -2;
}
printf("Starting the main etaHEN daemon ...");
klog_printf("Starting the main etaHEN daemon ...");
if (elfldr_spawn("/", sock.fd, daemon_start, "etaHEN Critical services") >= 0) {
printf(" Launched!\n");
klog_printf(" Launched!\n");
} else {
printf("failed to launch main daemon\n");
notify("failed to launch the main etaHEN daemon");
return -2;
klog_printf("failed to launch main daemon\n");
notify("failed to launch the main etaHEN daemon");
return -2;
}
// return 0;
@@ -934,29 +1166,29 @@ int main(void) {
for (int i = 0; i < plugin_count; i++) {
// Skip loading elfldr.plugin in this loop
if (strstr(plugin_paths[i], "elfldr") == 0) {
printf("Loading plugin: %s\n", plugin_paths[i]);
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);
puts("FAILED!");
klog_puts("FAILED!");
continue;
}
puts("Loaded!");
klog_puts("Loaded!");
loaded_plugins++;
}
}
//(void)memset(buff, 0, sizeof(buff));
// snprintf(buff, sizeof(buff), "Successfully loaded %d plugins",
// loaded_plugins); notify(buff);
printf("Successfully loaded %d plugins\n", loaded_plugins);
klog_printf("Successfully loaded %d plugins\n", loaded_plugins);
free_plugin_files(plugin_paths);
}
// raise(SIGKILL, getpid());
// sceSystemServiceLoadExec("exit", NULL);
puts("============== Spawner (Bootstrapper) Finished =================");
klog_puts("============== Spawner (Bootstrapper) Finished =================");
return 0;
}

View File

@@ -61,8 +61,8 @@ 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")
add_dependencies(${PROJECT_NAME} NineS shellui hijacker SelfDecryptor)
target_link_libraries (${PROJECT_NAME} PUBLIC hijacker ScePad SceSystemService SceNet SceRegMgr SceSysmodule SceUserService SceNetCtl SceShellUIUtil SceSysCore kernel_sys SceAppInstUtil NineS SelfDecryptor)
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)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Add post-build command
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD

View File

@@ -143,7 +143,7 @@ bool GetFileContents(const char *path, char **buffer);
void notify(bool show_watermark, const char *text, ...);
bool rmtree(const char *path);
int get_ip_address(char *ip_address);
bool Get_Running_App_TID(std::string &title_id);
bool Get_Running_App_TID(std::string& title_id, int& BigAppid);
bool is_whitelisted_app(const std::string &tid);
void *Play_time_thread(void *args) noexcept;
bool enable_toolbox();
@@ -358,9 +358,9 @@ error:
return -1;
}
bool Get_Running_App_TID(std::string &title_id) {
bool Get_Running_App_TID(std::string &title_id, int &BigAppid) {
char tid[255];
int BigAppid = sceSystemServiceGetAppIdOfRunningBigApp();
BigAppid = sceSystemServiceGetAppIdOfRunningBigApp();
if (BigAppid < 0) {
return false;
}
@@ -380,7 +380,8 @@ bool is_whitelisted_app(const std::string &tid) {
"ITEM00001",
"NPXS39041",
"DUMP00000",
"PKGI13337"
"PKGI13337",
"TOOL00001",
};
// Check for exact matches
@@ -400,9 +401,10 @@ void *Play_time_thread(void *args) noexcept {
const char *filename = "/data/etaHEN/playtime.bin";
std::string tid;
uint64_t duration = 0;
int appid;
while (true) {
if (!Get_Running_App_TID(tid)) {
if (!Get_Running_App_TID(tid, appid)) {
continue;
}
@@ -550,7 +552,7 @@ bool Open_Utility_Elf(const char *path, uint8_t **buffer) {
*buffer = buf; // Pass the buffer back to the caller
return true;
}
bool cmd_enable_fps(int appid);
void *fifo_and_dumper_thread(void *args) noexcept {
char *json_str = nullptr;
constexpr uint32_t MAX_TOKENS = 256;
@@ -559,45 +561,50 @@ void *fifo_and_dumper_thread(void *args) noexcept {
int retries = 0;
bool fifo_found = false;
#define MAX_RETIRES 5
uint8_t *util_elf = nullptr;
#define MAX_RETIRES 5
uint8_t* util_elf = nullptr;
while (true) {
std::string sandbox_dir;
// restart the util services daemon if it crashes or exits
if (find_pid("etaHEN Utility") < 0 && retries < MAX_RETIRES) {
if (retries == 0 || !util_elf) {
notify(true, "etaHEN Utility is not running, restarting...");
if (!Open_Utility_Elf("/data/etaHEN/daemons/util.elf", &util_elf)) {
if (++retries >= MAX_RETIRES)
notify(true, "Failed to open etaHEN Utility, please resend the payload or restart the console");
continue;
}
}
if (++retries >= MAX_RETIRES) {
notify(true, "etaHEN Utility services failed to restart, please resend the payload or restart the console");
free(util_elf);
continue;
}
if (elfldr_spawn("/", STDOUT_FILENO, util_elf, "etaHEN Utility Daemon") >= 0) {
etaHEN_log(" Launched!");
notify(true, "etaHEN Utility services successfully restarted");
retries = 0;
} else {
etaHEN_log("failed to launch utility daemon, retry: %d", retries);
}
std::string sandbox_dir;
// restart the util services daemon if it crashes or exits
if (find_pid("etaHEN Utility") < 0 && retries < MAX_RETIRES) {
if (retries == 0 || !util_elf) {
notify(true, "etaHEN Utility is not running, restarting...");
if (!Open_Utility_Elf("/data/etaHEN/daemons/util.elf", &util_elf)) {
if (++retries >= MAX_RETIRES)
notify(true, "Failed to open etaHEN Utility, please resend the payload or restart the console");
continue;
}
}
free(util_elf);
}
if (++retries >= MAX_RETIRES) {
notify(true, "etaHEN Utility services failed to restart, please resend the payload or restart the console");
free(util_elf);
continue;
}
if (elfldr_spawn("/", STDOUT_FILENO, util_elf, "etaHEN Utility Daemon") >= 0) {
etaHEN_log(" Launched!");
notify(true, "etaHEN Utility services successfully restarted");
retries = 0;
}
else {
etaHEN_log("failed to launch utility daemon, retry: %d", retries);
}
free(util_elf);
}
pthread_mutex_lock(&jb_lock);
if (!Get_Running_App_TID(tid)) {
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 (is_dumper_enabled) {
if (strstr(tid.c_str(), "ITEM00001") != 0) {
pthread_mutex_unlock(&jb_lock);
@@ -712,6 +719,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();
// jailbreak_proc(reserved_value);
unlink(sandbox_dir.c_str());
}

View File

@@ -270,15 +270,6 @@ int decrypt_self(const char* path, const char* out_path) {
etaHEN_log("decrypt_self: path=[%s]", path);
OrbisKernelSwVersion sys_ver;
sceKernelGetProsperoSystemSwVersion(&sys_ver);
bool alt_method = (sys_ver.version > 0x3000000);
if(alt_method){
etaHEN_log("decrypt_self: using alt method");
return decrypt_self_no_bypass(out_path);
}
// Open SELF file
self_fd = open(path, O_RDONLY);
if (self_fd < 0) {
@@ -414,6 +405,15 @@ bool ends_with(const std::string& str, const std::string& suffix) {
}
#define SELF_ORBIS_MAGIC 0x1D3D154F
bool decrypt_dir(const std::string& inputPath, const std::string& outputPath) {
OrbisKernelSwVersion sys_ver;
sceKernelGetProsperoSystemSwVersion(&sys_ver);
bool alt_method = (sys_ver.version > 0x3000000);
if (alt_method) {
etaHEN_log("decrypt_self: using alt method");
return decrypt_all(inputPath.c_str(), outputPath.c_str()) == 0;
}
DIR* dir = opendir(inputPath.c_str());
if (!dir){
etaHEN_log("Failed to open directory %s", inputPath.c_str());

View File

@@ -1,17 +1,5 @@
__asm__(
".global kstuff_start\n"
".type kstuff_start, @object\n"
".align 16\n"
"kstuff_start:\n"
".incbin \"assets/kstuff.elf\"\n"
"kstuff_end:\n"
".global kstuff_size\n"
".type kstuff_size, @object\n"
".align 4\n"
"kstuff_size:\n"
".int kstuff_end - kstuff_start\n"
".global ps5debug_start\n"
".type ps5debug_start, @object\n"
@@ -38,4 +26,5 @@
"shellui_prx_size:\n"
".int shellui_elf_end - shellui_elf_start\n"
);

View File

@@ -33,6 +33,7 @@ along with this program; see the file COPYING. If not, see
#include <sys/_pthreadtypes.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <ps5/klog.h>
// Project includes
#include "../../include/backtrace.hpp"
@@ -90,9 +91,9 @@ extern "C" {
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 sceShellUIUtilInitialize(void);
int scePadClose(int handle);
int sceShellUIUtilLaunchByUri(const char *uri, SceShellUIUtilLaunchByUriParam *Param);
//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);
@@ -104,8 +105,6 @@ extern "C" {
#include <ps5/payload.h>
// External data
extern uint8_t kstuff_start[];
extern const unsigned int kstuff_size;
extern uint8_t ps5debug_start[];
extern const unsigned int ps5debug_size;
@@ -131,8 +130,6 @@ int ItemzLaunchByUri(const char *uri);
bool enable_toolbox();
void sig_handler(int signo);
uint8_t *get_kstuff_address(bool *need_cleanup);
bool is_elf_header(uint8_t *data);
bool if_exists(const char *path);
void *fifo_and_dumper_thread(void *args);
void *Play_time_thread(void *args) noexcept;
@@ -173,6 +170,7 @@ void etaHEN_log(const char *fmt, ...) {
}
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) {
@@ -238,7 +236,7 @@ void sig_handler(int signo) {
"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();
//printBacktraceForCrash();
exit(1);
}
@@ -268,14 +266,31 @@ bool sceKernelIsTestKit() {
return if_exists("/system/priv/lib/libSceDeci5Ttyp.sprx");
}
int ItemzLaunchByUri(const char *uri) {
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);
sceUserServiceGetForegroundUser((int*)&Param.userId); // DONT CARE
return sceShellUIUtilLaunchByUri(uri, &Param);
}
@@ -315,7 +330,7 @@ int main() {
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 >= 0x900);
bool toolbox_only = (fw_ver >= 0x10000);
bool no_ps5debug = (fw_ver >= 0x800);
@@ -337,46 +352,6 @@ int main() {
pthread_create(&msg_thr, nullptr, IPC_loop, nullptr);
etaHEN_log("is toolbox only: %s | ver: %x", toolbox_only ? "Yes" : "No", sys_ver.version);
sleep(15);
// 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(true, "kstuff loading disabled via file, homebrew and FPKGs will be disabled");
etaHEN_log("kstuff loading disabled in config.ini or no_kstuff file found");
}
if (!dont_load_kstuff && !has_hv_bypass && !is_lite && !toolbox_only) {
notify(true, "Loading kstuff ...");
bool cleanup_kstuff;
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(true, "Failed to load kstuff, kstuff will be unavailable");
break;
}
sleep(1);
}
if(!kstuff_not_loaded)
etaHEN_log("kstuff loaded");
}
else {
notify(true, "Failed to load kstuff, kstuff will be unavailable");
}
if (cleanup_kstuff) {
free(kstuff_address);
}
}
sleep(10);
// Initialize toolbox if needed
if (global_conf.toolbox_auto_start) {
cmd_enable_toolbox();
@@ -395,7 +370,7 @@ int main() {
// Display IP and service info
std::string dpi_url = "Direct Package Installer V2: http://" + std::string(buz) + ":12800";
notify(true,
"etaHEN 2.3b by LM (ko-fi.com/lightningmods)\n\nAIO HEN\n\nCurrent IP: %s\n\nFTP Port: "
"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() : "");
@@ -448,65 +423,3 @@ int main() {
puts("main thread ended");
return 0;
}
uint8_t *get_kstuff_address(bool *require_cleanup) {
const char *path = "/data/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(true, "Kstuff '%s' doesn't have ELF header.", path);
goto free_mem;
}
*require_cleanup = true;
notify(true, "Loading kstuff from: %s", path);
return address;
free_mem:
free(address);
close_fd:
close(fd);
embedded_kstuff:
*require_cleanup = false;
return kstuff_start;
}
bool is_elf_header(uint8_t *data)
{
uint8_t header[] = {0x7f, 'E', 'L', 'F'};
return !memcmp(data, header, 4);
}

View File

@@ -40,6 +40,10 @@ along with this program; see the file COPYING. If not, see
#include <vector>
#include "../../include/ini.h"
#include "dbg/dbg.hpp"
#include "elf/elf.hpp"
#include "hijacker/hijacker.hpp"
typedef struct app_info {
uint32_t app_id;
@@ -64,6 +68,7 @@ int32_t sceUserServiceGetForegroundUser(int32_t *new_id);
int32_t scePadSetProcessPrivilege(int32_t num);
int sceKernelMprotect(void *addr, size_t len, int prot);
int sceSystemServiceLoadExec(const char *path, const char *argv[]);
int sceSystemServiceGetAppIdOfRunningBigApp();
extern uint8_t ps5debug_start[];
extern const unsigned int ps5debug_size;
@@ -72,9 +77,13 @@ extern const unsigned int ps5debug_size;
extern uint8_t shellui_elf_start[];
extern const unsigned int shellui_elf_size;
extern uint8_t fps_elf_start[];
extern const unsigned int fps_elf_size;
bool Inject_Toolbox(int pid, uint8_t *elf);
int sceKernelGetAppInfo(int pid, app_info_t *title);
int sceKernelGetProcessName(int pid, char *name);
int _sceApplicationGetAppId(int pid, int* appid);
}
@@ -132,7 +141,7 @@ static bool remount(const char *dev, const char *path, int mnt_flag) {
}
bool pause_kstuff()
bool pause_resume_kstuff()
{
intptr_t sysentvec = 0;
intptr_t sysentvec_ps4 = 0;
@@ -209,20 +218,21 @@ bool pause_kstuff()
break;
case 0x9000000:
case 0x9050000:
case 0x9200000:
case 0x9400000:
case 0x9600000:
sysentvec = KERNEL_ADDRESS_DATA_BASE + 0xde0e18;
sysentvec_ps4 = KERNEL_ADDRESS_DATA_BASE + 0xde0f90;
break;
sysentvec = KERNEL_ADDRESS_DATA_BASE + 0xdba648;
sysentvec_ps4 = KERNEL_ADDRESS_DATA_BASE + 0xdba7c0;
break;
case 0x10000000:
case 0x10010000:
case 0x10200000:
case 0x10400000:
case 0x10600000:
sysentvec = KERNEL_ADDRESS_DATA_BASE + 0xde0ee8;
sysentvec_ps4 = KERNEL_ADDRESS_DATA_BASE + 0xde1060;
sysentvec = KERNEL_ADDRESS_DATA_BASE + 0xdba6d8;
sysentvec_ps4 = KERNEL_ADDRESS_DATA_BASE + 0xdba850;
break;
default:
@@ -232,7 +242,9 @@ bool pause_kstuff()
}
if(kernel_getshort(sysentvec_ps4 + 14) == 0xffff) {
etaHEN_log("already paused, doing nothing");
//etaHEN_log("already paused, doing nothing");
kernel_setshort(sysentvec + 14, 0xdeb7);
kernel_setshort(sysentvec_ps4 + 14, 0xdeb7);
} else {
kernel_setshort(sysentvec + 14, 0xffff);
kernel_setshort(sysentvec_ps4 + 14, 0xffff);
@@ -241,6 +253,99 @@ bool pause_kstuff()
return true;
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
int change_permissions_recursive(const char* path) {
struct stat statbuf;
struct dirent* entry;
DIR* dir;
int result = 0;
if (!path || strlen(path) == 0) {
etaHEN_log( "Invalid path provided");
return -1;
}
if (lstat(path, &statbuf) != 0) {
etaHEN_log( "Failed to stat '%s': %s", path, strerror(errno));
return -1;
}
if (S_ISLNK(statbuf.st_mode)) {
etaHEN_log("Skipping symbolic link: %s", path);
return 0;
}
// Skip special files (devices, pipes, sockets, etc.)
if (!S_ISREG(statbuf.st_mode) && !S_ISDIR(statbuf.st_mode)) {
etaHEN_log("Skipping special file: %s", path);
return 0;
}
if (!S_ISDIR(statbuf.st_mode)) {
if (chmod(path, 0777) != 0) {
etaHEN_log( "Failed to chmod '%s': %s", path, strerror(errno));
return -1;
}
return 0;
}
dir = opendir(path);
if (!dir) {
etaHEN_log( "Failed to open directory '%s': %s", path, strerror(errno));
return -1;
}
errno = 0;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
size_t path_len = strlen(path);
size_t name_len = strlen(entry->d_name);
if (path_len + name_len + 2 > PATH_MAX) {
etaHEN_log( "Path too long: %s/%s", path, entry->d_name);
result = -1;
continue;
}
char newpath[PATH_MAX];
int ret = snprintf(newpath, sizeof(newpath), "%s/%s", path, entry->d_name);
if (ret >= sizeof(newpath)) {
etaHEN_log( "Path truncated: %s/%s", path, entry->d_name);
result = -1;
continue;
}
if (change_permissions_recursive(newpath) != 0) {
result = -1;
}
}
if (errno != 0) {
etaHEN_log( "Error reading directory '%s': %s", path, strerror(errno));
result = -1;
}
closedir(dir);
if (chmod(path, 0777) != 0) {
etaHEN_log( "Failed to chmod directory '%s': %s", path, strerror(errno));
return -1;
}
return result;
}
void LoadSettings() {
if (if_exists("/data/etaHEN/config.ini")) {
IniParser parser;
@@ -487,6 +592,31 @@ int get_shellui_pid() {
return pid == -1 ? find_pid( "SceShellUI") : pid;
}
int get_game_pid() {
char proc_name[255] = { 0 };
int app_pid = -1;
int appid = sceSystemServiceGetAppIdOfRunningBigApp();
for (size_t j = 0; j <= 9999; j++) {
int bappid = 0;
if (_sceApplicationGetAppId(j, &bappid) < 0)
continue;
if (appid == bappid) {
app_pid = j; // APP PID NOT TO BE CONFUSED WITH APPID
if (sceKernelGetProcessName(app_pid, &proc_name[0]) < 0) {
etaHEN_log("sceKernelGetProcessName failed for (%d)", app_pid);
continue;
}
// cheat_log("Found %s (%d)", proc_name, app_pid);
break;
}
}
return app_pid;
}
extern "C" {
struct proc* get_proc_by_pid(pid_t pid);
uintptr_t set_proc_authid(pid_t pid, uintptr_t new_authid)
@@ -531,11 +661,211 @@ void ForceKillProc(int pid) {
set_proc_authid(getpid(), authid); // Restore original authid
}
extern "C" {
int32_t sceKernelPrepareToSuspendProcess(pid_t pid);
int32_t sceKernelSuspendProcess(pid_t pid);
int32_t sceKernelPrepareToResumeProcess(pid_t pid);
int32_t sceKernelResumeProcess(pid_t pid);
int32_t sceUserServiceInitialize(int32_t* priority);
int32_t sceUserServiceGetForegroundUser(int32_t* new_id);
int32_t sceSysmoduleLoadModuleInternal(uint32_t moduleId);
int32_t sceSysmoduleUnloadModuleInternal(uint32_t moduleId);
int32_t sceVideoOutOpen();
int32_t sceVideoOutConfigureOutput();
int32_t sceVideoOutIsOutputSupported();
int sceKernelLoadStartModule(const char* name, size_t argc, const void* argv, uint32_t flags, void* option, int* res);
}
static void SuspendApp(pid_t pid)
{
sceKernelPrepareToSuspendProcess(pid);
sceKernelSuspendProcess(pid);
}
static void ResumeApp(pid_t pid)
{
// we need to sleep the thread after suspension
// because this will cause a kernel panic when user quits the process after sometime
// the kernel will not be very happy with us.
usleep(1000);
sceKernelPrepareToResumeProcess(pid);
sceKernelResumeProcess(pid);
}
struct GameStuff {
uintptr_t scePadReadState;
uintptr_t debugout;
uintptr_t sceKernelLoadStartModule;
uintptr_t sceKernelDlsym;
uintptr_t sceKernelSendNotificationRequest;
uintptr_t anything;
uint64_t ASLR_Base = 0;
char prx_path[256];
int loaded = 0;
GameStuff(Hijacker& hijacker) noexcept
: debugout(hijacker.getLibKernelAddress(nid::sceKernelDebugOutText)),
sceKernelLoadStartModule(hijacker.getLibKernelAddress(nid::sceKernelLoadStartModule)),
sceKernelDlsym(hijacker.getLibKernelAddress(nid::sceKernelDlsym)),
sceKernelSendNotificationRequest(hijacker.getLibKernelAddress(nid::sceKernelSendNotificationRequest)) {
}
};
struct GameBuilder {
static constexpr size_t SHELLCODE_SIZE = 218;
static constexpr size_t EXTRA_STUFF_ADDR_OFFSET = 2;
uint8_t shellcode[SHELLCODE_SIZE];
void setExtraStuffAddr(uintptr_t addr) noexcept {
*reinterpret_cast<uintptr_t*>(shellcode + EXTRA_STUFF_ADDR_OFFSET) = addr;
}
};
static constexpr GameBuilder BUILDER_TEMPLATE{
0x48, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // MOV scePadReadState, RDX // 10
// Additional shellcode0x55, 0x41, 0x57, 0x41, 0x56, 0x41, 0x54, 0x53, 0x48, 0x83, 0xec, 0x60, 0x4c, 0x8b, 0x62, 0x20,0x55, 0x41, 0x57, 0x41, 0x56, 0x41, 0x54, 0x53, 0x48, 0x83, 0xec, 0x30, 0x4c, 0x8b, 0x62, 0x20,
0x55, 0x41, 0x57, 0x41, 0x56, 0x53, 0x48, 0x83, 0xec, 0x48, 0x48, 0xb8, 0x73, 0x68, 0x65, 0x6c,
0x6c, 0x6d, 0x61, 0x69, 0x48, 0xb9, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x75, 0x6c, 0x48, 0xc7,
0x44, 0x24, 0x08, 0x00, 0x00, 0x00, 0x00, 0x49, 0x89, 0xd6, 0x48, 0x89, 0xf3, 0x89, 0xfd, 0x48,
0x89, 0x44, 0x24, 0x30, 0x48, 0x89, 0x4c, 0x24, 0x38, 0x48, 0xc7, 0x44, 0x24, 0x40, 0x6c, 0x00,
0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x10, 0x48, 0xc7, 0x44, 0x24, 0x18, 0x6e, 0x00, 0x00, 0x00,
0x48, 0xc7, 0x44, 0x24, 0x20, 0x00, 0x00, 0x00, 0x00, 0xff, 0x12, 0x41, 0x89, 0xc7, 0x85, 0xed,
0x7e, 0x60, 0x45, 0x85, 0xff, 0x75, 0x5b, 0x80, 0x7b, 0x4c, 0x00, 0x74, 0x55, 0x41, 0x83, 0xbe,
0x38, 0x01, 0x00, 0x00, 0x00, 0x75, 0x4b, 0x49, 0x8d, 0x7e, 0x38, 0x31, 0xf6, 0x31, 0xd2, 0x31,
0xc9, 0x45, 0x31, 0xc0, 0x45, 0x31, 0xc9, 0x41, 0xff, 0x56, 0x10, 0x48, 0x8d, 0x74, 0x24, 0x10,
0x48, 0x8d, 0x54, 0x24, 0x08, 0x89, 0xc7, 0x41, 0xff, 0x56, 0x18, 0x48, 0x8b, 0x44, 0x24, 0x08,
0x48, 0x85, 0xc0, 0x74, 0x07, 0x4c, 0x89, 0xf7, 0xff, 0xd0, 0xeb, 0x0b, 0x48, 0x8d, 0x74, 0x24,
0x30, 0x31, 0xff, 0x41, 0xff, 0x56, 0x08, 0x41, 0xc7, 0x86, 0x38, 0x01, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x44, 0x89, 0xf8, 0x48, 0x83, 0xc4, 0x48, 0x5b, 0x41, 0x5e, 0x41, 0x5f, 0x5d, 0xc3,
};
bool HookGame(UniquePtr<Hijacker>& hijacker, uint64_t alsr_b) {
etaHEN_log("Patching Game Now");
GameBuilder builder = BUILDER_TEMPLATE;
GameStuff stuff{ *hijacker };
UniquePtr<SharedLib> lib = hijacker->getLib("libScePad.sprx");
if (lib.get() == nullptr) {
etaHEN_log("libScePad.sprx not found!");
return false;
}
etaHEN_log("libScePad.sprx addr: 0x%llx", lib->imagebase());
stuff.scePadReadState = hijacker->getFunctionAddress(lib.get(), nid::scePadReadState);
//libSceGnmDriver
UniquePtr<SharedLib> gnmlib = hijacker->getLib("libSceGnmDriverForNeoMode.sprx");
if (gnmlib.get() == nullptr) {
etaHEN_log("libSceGnmDriverForNeoMode.sprx not found!");
gnmlib = hijacker->getLib("libSceGnmDriver.sprx");
if (gnmlib.get() == nullptr) {
etaHEN_log("libSceGnmDriver.sprx not found!");
return false;
}
}
etaHEN_log("libSceGnmDriver.sprx addr: 0x%llx", gnmlib->imagebase());
stuff.anything = hijacker->getFunctionAddress(gnmlib.get(), nid::sceGnmSubmitAndFlipCommandBuffersForWorkload);
etaHEN_log("scePadReadState addr: 0x%llx", stuff.scePadReadState);
if (stuff.scePadReadState == 0) {
etaHEN_log("failed to locate scePadReadState");
return false;
}
stuff.ASLR_Base = alsr_b;
strcpy(stuff.prx_path, "/data/etaHEN/fps.prx");
auto code = hijacker->getTextAllocator().allocate(GameBuilder::SHELLCODE_SIZE);
etaHEN_log("shellcode addr: 0x%llx", code);
auto stuffAddr = hijacker->getDataAllocator().allocate(sizeof(GameStuff));
// static constexpr Nid printfNid{"hcuQgD53UxM"};
// static constexpr Nid amd64_set_fsbaseNid{"3SVaehJvYFk"};
auto meta = hijacker->getEboot()->getMetaData();
const auto& plttab = meta->getPltTable();
auto index = meta->getSymbolTable().getSymbolIndex(nid::scePadReadState);
for (const auto& plt : plttab) {
if (ELF64_R_SYM(plt.r_info) == index) {
builder.setExtraStuffAddr(stuffAddr);
hijacker->write(code, builder.shellcode);
hijacker->write(stuffAddr, stuff);
uintptr_t hook_adr = hijacker->getEboot()->imagebase() + plt.r_offset;
// write the hook
hijacker->write<uintptr_t>(hook_adr, code);
etaHEN_log("hook addr: 0x%llx", hook_adr);
hijacker.release();
return true;
}
}
return false;
}
int done_appid;
bool cmd_enable_fps(int appid) {
if(done_appid == appid){
// etaHEN_log("FPS already enabled for %x", appid);
return true;
}
SuspendApp(appid);
int bappid = 0, pid = 0;
for (size_t j = 0; j <= 9999; j++) {
if (_sceApplicationGetAppId(j, &bappid) < 0)
continue;
if (appid == bappid) {
pid = j;
etaHEN_log("Game is running, appid 0x%X, pid %i", appid, pid);
//printf_notification("Game is running, appid 0x%X, pid %i", appid, pid);
break;
}
}
UniquePtr<Hijacker> executable = Hijacker::getHijacker(pid);
uintptr_t text_base = 0;
uint64_t text_size = 0;
if (executable)
{
text_base = executable->getEboot()->getTextSection()->start();
text_size = executable->getEboot()->getTextSection()->sectionLength();
}
else
{
etaHEN_log("Failed to get hijacker for (%d)", pid);
// printf_notification("Failed to get hijacker for (%d), try re-running the plugin", pid);
return false;
}
if (text_base == 0 || text_size == 0)
{
etaHEN_log("text_base == 0 || text_size == 0");
//printf_notification("text_base == 0 || text_size == 0 (%d), try re-running the plugin", pid);
return false;
}
while (!HookGame(executable, text_base)) {
//etaHEN_log("Failed to patch the game");
sleep(1);
}
sleep(1);
ResumeApp(pid);
done_appid = appid;
return true;
}
bool cmd_enable_toolbox(){
int wait = 0;
char buz[100] = {0};
if(sceKernelMprotect(&buz[0], 100, 0x7) == 0){
if(pause_kstuff()){
if(pause_resume_kstuff()){
etaHEN_log("Paused kstuff...");
touch_file("/system_tmp/kstuff_paused");
}
@@ -552,11 +882,13 @@ bool cmd_enable_toolbox(){
int pid = get_shellui_pid();
if (pid < 0) {
pause_resume_kstuff();
notify(true, "Failed to get shellui pid");
return false;
}
if (!Inject_Toolbox(pid, shellui_elf_start)) {
pause_resume_kstuff();
ForceKillProc(pid);
notify(true, "Failed to inject toolbox");
return false;
@@ -567,6 +899,7 @@ bool cmd_enable_toolbox(){
sleep(1);
if(++wait >= 15){
ForceKillProc(pid);
pause_resume_kstuff();
notify(true, "Failed to load the etaHEN toolbox");
return false;
}
@@ -831,11 +1164,12 @@ void handleIPC(struct clientArgs *client, std::string &inputStr,
}
notify(true, "Loading PS5Debug...");
#if 1
if (elfldr_spawn("/", STDOUT_FILENO, ps5debug_start, "PS5Debug") < 0) {
notify(true, "PS5Debug is starting\nWait for the PS5Debug welcome message");
global_conf.PS5Debug = true;
}
#endif
reply(sender_app, false);
break;
@@ -871,6 +1205,19 @@ void handleIPC(struct clientArgs *client, std::string &inputStr,
reply(sender_app, false);
break;
}
case BREW_CHMOD_DIR: {
etaHEN_log("BREW_CHMOD_DIR called");
path = json_getPropertyValue(my_json, "path");
if(!path) {
etaHEN_log("Invalid path for chmod");
reply(sender_app, true);
break;
}
// kernel_set_ucred_authid(getpid(), 0x4801000000000013L);
change_permissions_recursive(path);
reply(sender_app, false);
break;
}
default:
notify(true, "Unknown command 0x%X", command);
reply(sender_app, true);

View File

@@ -0,0 +1,71 @@
cmake_minimum_required (VERSION 3.20)
set(basename "fps_elf")
project(${basename} C CXX ASM)
# Language Standard Defaults
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 20)
# Check for sub-project as part of main build or external build
if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
set(IS_SUBPROJECT TRUE)
else()
set(IS_SUBPROJECT FALSE)
endif()
message("IS_SUBPROJECT: ${IS_SUBPROJECT}")
set(D_CWD "${CMAKE_CURRENT_SOURCE_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${D_CWD}/../daemon/assets)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${D_CWD}/bin)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${D_CWD}/bin) # static libs are archive
set(D_SRC ${D_CWD}/src)
# Headers
include_directories (SYSTEM "${PS5_PAYLOAD_SDK}")
include_directories (SYSTEM "${PS5_PAYLOAD_SDK}/include")
add_executable(${PROJECT_NAME})
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "${PROJECT_NAME}.elf")
# Must build with clang
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "[Cc]lang")
set(IS_CLANG 1)
else()
message(FATAL_ERROR "${PROJECT_NAME} is meant to be built with clang! CompilerID: ${CMAKE_CXX_COMPILER_ID}")
endif()
# Finalize main target sources
target_compile_options(${PROJECT_NAME} PUBLIC
$<$<COMPILE_LANGUAGE:C>:${C_DEFS} ${C_FLAGS}>
$<$<COMPILE_LANGUAGE:CXX>:${CXX_DEFS} ${CXX_FLAGS}>
$<$<COMPILE_LANGUAGE:ASM>:${ASM_FLAGS}>
)
message("========== build: ${PROJECT_NAME} ==========")
file(GLOB SrcFiles ${D_SRC}/*.c ${D_SRC}/*.cpp ${D_SRC}/../include/*.h ${D_SRC}/../include/*.hpp ${D_SRC}/*.s ${D_SRC}/../../extern/tiny-json/*.cpp ${D_SRC}/../../extern/tiny-json/*.hpp ${D_SRC}/../../extern/cJSON/*.cpp ${D_SRC}/../../extern/cJSON/*.hpp ${D_SRC}/../../lib/backtrace.cpp)
set(CMAKE_C_FLAGS "--target=x86_64-sie-ps5 -DPPR -DPS5 -DPS5_FW_VERSION=${V_FW} ")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-nested-anon-types -Wno-gnu-anonymous-struct -Wno-zero-length-array -Wno-keyword-macro -fPIC -fPIE -march=znver2 -Wall -Werror -fstack-protector-all")
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -DDEBUG -gfull -gdwarf-2 -O0 -pedantic -pedantic-errors")
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 )
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Add post-build command
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_OBJCOPY} --remove-section .debug_info --remove-section .debug_abbrev --remove-section .debug_line --remove-section .debug_str --remove-section .debug_loc --remove-section .debug_aranges --remove-section .debug_ranges --remove-section .debug_pubnames --remove-section .debug_pubtypes --remove-section .debug_frame --strip-unneeded $<TARGET_FILE:${PROJECT_NAME}>
COMMENT "Stripping debugging information from ${PROJECT_NAME}.elf"
)

View File

@@ -0,0 +1,37 @@
/* 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/>. */
#pragma once
extern "C" {
#include "ucred.h"
#include "external_symbols.hpp"
#include "../lib/libmprotect.h"
#include <cstdint>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <unistd.h>
#include "ps5/mdbg.h"
}
#define HOOK_LENGTH 14
#define SYS_jitshm_create 0x215
#define SYS_jitshm_alias 0x216
void PatchInJump(uint64_t address, void* destination);
void* DetourFunction(uint64_t address, void* destination);
void WriteMemory(uint64_t address, void* buffer, int length);
int JITAlloc(size_t size, void** executableAddress, void** writableAddress);

View File

@@ -0,0 +1,29 @@
/* 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/>. */
#pragma once
#define PUBLIC_TEST 1
#define PRE_RELEASE 0
#define SHELL_DEBUG 1
#define etaHEN_VERSION "2.4"
#define libSceKernelHandle 0x2001
#define KERNEL_DLSYM(handle, sym) \
(*(void**)&sym=(void*)kernel_dynlib_dlsym(-1, handle, #sym))
typedef void* ScePthread;

View File

@@ -0,0 +1,554 @@
/* 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/>. */
#pragma once
#include <cstdint>
#include <sys/types.h>
#define SCE_OK 0
struct AppMessage {
static constexpr size_t PAYLOAD_SIZE = 8192;
uint32_t sender;
uint32_t msgType;
char payload[PAYLOAD_SIZE];
uint32_t payloadSize;
uint64_t timestamp;
};
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
#define SCE_NET_CTL_STATE_DISCONNECTED 0
#define SCE_NET_CTL_STATE_CONNECTING 1
#define SCE_NET_CTL_STATE_IPOBTAINING 2
#define SCE_NET_CTL_STATE_IPOBTAINED 3
/* event type */
#define SCE_NET_CTL_EVENT_TYPE_DISCONNECTED 1
#define SCE_NET_CTL_EVENT_TYPE_DISCONNECT_REQ_FINISHED 2
#define SCE_NET_CTL_EVENT_TYPE_IPOBTAINED 3
/* info code */
#define SCE_NET_CTL_INFO_DEVICE 1
#define SCE_NET_CTL_INFO_ETHER_ADDR 2
#define SCE_NET_CTL_INFO_MTU 3
#define SCE_NET_CTL_INFO_LINK 4
#define SCE_NET_CTL_INFO_BSSID 5
#define SCE_NET_CTL_INFO_SSID 6
#define SCE_NET_CTL_INFO_WIFI_SECURITY 7
#define SCE_NET_CTL_INFO_RSSI_DBM 8
#define SCE_NET_CTL_INFO_RSSI_PERCENTAGE 9
#define SCE_NET_CTL_INFO_CHANNEL 10
#define SCE_NET_CTL_INFO_IP_CONFIG 11
#define SCE_NET_CTL_INFO_DHCP_HOSTNAME 12
#define SCE_NET_CTL_INFO_PPPOE_AUTH_NAME 13
#define SCE_NET_CTL_INFO_IP_ADDRESS 14
#define SCE_NET_CTL_INFO_NETMASK 15
#define SCE_NET_CTL_INFO_DEFAULT_ROUTE 16
#define SCE_NET_CTL_INFO_PRIMARY_DNS 17
#define SCE_NET_CTL_INFO_SECONDARY_DNS 18
#define SCE_NET_CTL_INFO_HTTP_PROXY_CONFIG 19
#define SCE_NET_CTL_INFO_HTTP_PROXY_SERVER 20
#define SCE_NET_CTL_INFO_HTTP_PROXY_PORT 21
#define SCE_NET_CTL_INFO_RESERVED1 22
#define SCE_NET_CTL_INFO_RESERVED2 23
/* device */
#define SCE_NET_CTL_DEVICE_WIRED 0
#define SCE_NET_CTL_DEVICE_WIRELESS 1
/* link */
#define SCE_NET_CTL_LINK_DISCONNECTED 0
#define SCE_NET_CTL_LINK_CONNECTED 1
/* wifi_security */
#define SCE_NET_CTL_WIFI_SECURITY_NOAUTH 0
#define SCE_NET_CTL_WIFI_SECURITY_WEP 1
#define SCE_NET_CTL_WIFI_SECURITY_WPAPSK_WPA2PSK 2
#define SCE_NET_CTL_WIFI_SECURITY_WPAPSK_TKIP 3
#define SCE_NET_CTL_WIFI_SECURITY_WPAPSK_AES 4
#define SCE_NET_CTL_WIFI_SECURITY_WPA2PSK_TKIP 5
#define SCE_NET_CTL_WIFI_SECURITY_WPA2PSK_AES 6
#define SCE_NET_CTL_WIFI_SECURITY_UNSUPPORTED 7
/* ip_config */
#define SCE_NET_CTL_IP_DHCP 0
#define SCE_NET_CTL_IP_STATIC 1
#define SCE_NET_CTL_IP_PPPOE 2
/* http_proxy_config */
#define SCE_NET_CTL_HTTP_PROXY_OFF 0
#define SCE_NET_CTL_HTTP_PROXY_ON 1
#define SCE_NET_CTL_SSID_LEN (32 + 1)
#define SCE_NET_CTL_WIFI_SECURITY_KEY_LEN (64 + 1)
#define SCE_NET_CTL_AUTH_NAME_LEN (127 + 1)
#define SCE_NET_CTL_AUTH_KEY_LEN (127 + 1)
#define SCE_NET_CTL_HOSTNAME_LEN (255 + 1)
#define SCE_NET_CTL_IPV4_ADDR_STR_LEN (16)
#define SCE_NET_ETHER_ADDR_LEN 6
#define SCE_NET_ETHER_ADDRSTRLEN 18
typedef struct SceNetEtherAddr {
uint8_t data[SCE_NET_ETHER_ADDR_LEN];
} SceNetEtherAddr;
typedef void (*SceNetCtlCallback)(
int eventType, /* SCE_NET_CTL_EVENT_TYPE_XXX */
void *arg
);
typedef union SceNetCtlInfo {
uint32_t device;
SceNetEtherAddr ether_addr;
uint32_t mtu;
uint32_t link;
SceNetEtherAddr bssid;
char ssid[SCE_NET_CTL_SSID_LEN];
uint32_t wifi_security;
int32_t rssi_dbm;
uint8_t rssi_percentage;
uint8_t channel;
uint32_t ip_config;
char dhcp_hostname[SCE_NET_CTL_HOSTNAME_LEN];
char pppoe_auth_name[SCE_NET_CTL_AUTH_NAME_LEN];
char ip_address[SCE_NET_CTL_IPV4_ADDR_STR_LEN];
char netmask[SCE_NET_CTL_IPV4_ADDR_STR_LEN];
char default_route[SCE_NET_CTL_IPV4_ADDR_STR_LEN];
char primary_dns[SCE_NET_CTL_IPV4_ADDR_STR_LEN];
char secondary_dns[SCE_NET_CTL_IPV4_ADDR_STR_LEN];
uint32_t http_proxy_config;
char http_proxy_server[SCE_NET_CTL_HOSTNAME_LEN];
uint16_t http_proxy_port;
} SceNetCtlInfo;
// Token: 0x040002CA RID: 714
#define SCE_NET_SHOW_BUFFER_SIZE 8192
// Token: 0x040002CB RID: 715
#define SCE_NET_SHOW_NETSTAT_BUFFER_SIZE 65536
// Token: 0x040002CC RID: 716
#define SCE_NET_ADDR_STR_SIZE 18
// Token: 0x02000060 RID: 96
typedef enum SceNetIfName
{
// Token: 0x040002CE RID: 718
SCE_NET_IF_NAME_UNKNOWN = -2,
// Token: 0x040002CF RID: 719
SCE_NET_IF_NAME_NONE,
// Token: 0x040002D0 RID: 720
SCE_NET_IF_NAME_LO0,
// Token: 0x040002D1 RID: 721
SCE_NET_IF_NAME_PHYSICAL,
// Token: 0x040002D2 RID: 722
SCE_NET_IF_NAME_ETH0 = 1,
// Token: 0x040002D3 RID: 723
SCE_NET_IF_NAME_ETH1,
// Token: 0x040002D4 RID: 724
SCE_NET_IF_NAME_DBG0,
// Token: 0x040002D5 RID: 725
SCE_NET_IF_NAME_WLAN0,
// Token: 0x040002D6 RID: 726
SCE_NET_IF_NAME_WLAN1,
// Token: 0x040002D7 RID: 727
SCE_NET_IF_NAME_GBE0,
// Token: 0x040002D8 RID: 728
SCE_NET_IF_NAME_BT0,
// Token: 0x040002D9 RID: 729
SCE_NET_IF_NAME_PHONE0,
// Token: 0x040002DA RID: 730
SCE_NET_IF_NAME_VIRTUAL,
// Token: 0x040002DB RID: 731
SCE_NET_IF_NAME_PPPOE0 = 9,
// Token: 0x040002DC RID: 732
SCE_NET_IF_NAME_MAX
} SceNetIfName;
// Token: 0x02000061 RID: 97
typedef enum SceNetSockInfo
{
// Token: 0x040002DE RID: 734
SCE_NET_SOCKINFO_ALL = 1,
// Token: 0x040002DF RID: 735
SCE_NET_SOCKINFO_NAME = 2,
// Token: 0x040002E0 RID: 736
SCE_NET_SOCKINFO_EPOLL = 32,
// Token: 0x040002E1 RID: 737
SCE_NET_SOCKINFO_TIME_WAIT = 64,
// Token: 0x040002E2 RID: 738
SCE_NET_SOCKINFO_IP46 = 4096,
// Token: 0x040002E3 RID: 739
SCE_NET_SOCKINFO_SYSTEM = 65536,
// Token: 0x040002E4 RID: 740
SCE_NET_SOCKINFO_IPV6 = 131072,
// Token: 0x040002E5 RID: 741
SCE_NET_SOCKINFO_DEBUGGABLE_ONLY = 262144
} SceNetSockInfo;
// Token: 0x02000062 RID: 98
typedef enum SceNetIfListFlag
{
// Token: 0x040002E7 RID: 743
SCE_NET_IF_LIST_F_UP = 1U,
// Token: 0x040002E8 RID: 744
SCE_NET_IF_LIST_F_BROADCAST = 2U,
// Token: 0x040002E9 RID: 745
SCE_NET_IF_LIST_F_LOOPBACK = 8U,
// Token: 0x040002EA RID: 746
SCE_NET_IF_LIST_F_POINTOPOINT = 16U,
// Token: 0x040002EB RID: 747
SCE_NET_IF_LIST_F_RUNNING = 64U,
// Token: 0x040002EC RID: 748
SCE_NET_IF_LIST_F_MULTICAST = 32768U,
// Token: 0x040002ED RID: 749
SCE_NET_IF_LIST_F_STATIC = 8388608U,
// Token: 0x040002EE RID: 750
SCE_NET_IF_LIST_F_INTERNET = 16777216U
} SceNetIfListFlag;
// Token: 0x02000063 RID: 99
typedef enum SceNetIfListIn6Flag
{
// Token: 0x040002F0 RID: 752
SCE_NET_IF_LIST_IN6_IFF_TENTATIVE = 2U,
// Token: 0x040002F1 RID: 753
SCE_NET_IF_LIST_IN6_IFF_DUPLICATED = 4U,
// Token: 0x040002F2 RID: 754
SCE_NET_IF_LIST_IN6_IFF_ASSIGNED_BY_AUTOCONF = 268435456U,
// Token: 0x040002F3 RID: 755
SCE_NET_IF_LIST_IN6_IFF_RA_ENABLED = 536870912U,
// Token: 0x040002F4 RID: 756
SCE_NET_IF_LIST_IN6_IFF_RA_M_FLAG = 1073741824U,
// Token: 0x040002F5 RID: 757
SCE_NET_IF_LIST_IN6_IFF_RA_O_FLAG = 2147483648U
} SceNetIfListIn6Flag;
// Token: 0x02000064 RID: 100
typedef enum SceNetIfListType
{
// Token: 0x040002F7 RID: 759
SCE_NET_IF_LIST_TYPE_UNKNOWN,
// Token: 0x040002F8 RID: 760
SCE_NET_IF_LIST_TYPE_ETHERNET,
// Token: 0x040002F9 RID: 761
SCE_NET_IF_LIST_TYPE_WLAN,
// Token: 0x040002FA RID: 762
SCE_NET_IF_LIST_TYPE_BT,
// Token: 0x040002FB RID: 763
SCE_NET_IF_LIST_TYPE_PHONE
} SceNetIfListType;
// Token: 0x02000065 RID: 101
typedef enum SceNetConfigEtherLinkMode
{
// Token: 0x040002FD RID: 765
SCE_NET_CONFIG_ETHER_LINK_MODE_OFF = 0,
// Token: 0x040002FE RID: 766
SCE_NET_CONFIG_ETHER_LINK_MODE_ON = 1,
// Token: 0x040002FF RID: 767
SCE_NET_CONFIG_ETHER_LINK_MODE_FD = 2,
// Token: 0x04000300 RID: 768
SCE_NET_CONFIG_ETHER_LINK_MODE_AUTO = 4,
// Token: 0x04000301 RID: 769
SCE_NET_CONFIG_ETHER_LINK_MODE_10M = 16,
// Token: 0x04000302 RID: 770
SCE_NET_CONFIG_ETHER_LINK_MODE_100M = 32,
// Token: 0x04000303 RID: 771
SCE_NET_CONFIG_ETHER_LINK_MODE_1G = 64,
// Token: 0x04000304 RID: 772
SCE_NET_CONFIG_ETHER_LINK_MODE_2G5 = 128,
// Token: 0x04000305 RID: 773
SCE_NET_CONFIG_ETHER_LINK_MODE_5G = 256,
// Token: 0x04000306 RID: 774
SCE_NET_CONFIG_ETHER_LINK_MODE_10G = 512,
// Token: 0x04000307 RID: 775
SCE_NET_CONFIG_ETHER_LINK_MODE_10M_HD = 17,
// Token: 0x04000308 RID: 776
SCE_NET_CONFIG_ETHER_LINK_MODE_10M_FD = 19,
// Token: 0x04000309 RID: 777
SCE_NET_CONFIG_ETHER_LINK_MODE_100M_HD = 33,
// Token: 0x0400030A RID: 778
SCE_NET_CONFIG_ETHER_LINK_MODE_100M_FD = 35,
// Token: 0x0400030B RID: 779
SCE_NET_CONFIG_ETHER_LINK_MODE_1G_FD = 67,
// Token: 0x0400030C RID: 780
SCE_NET_CONFIG_ETHER_LINK_MODE_2G5_FD = 131,
// Token: 0x0400030D RID: 781
SCE_NET_CONFIG_ETHER_LINK_MODE_5G_FD = 259,
// Token: 0x0400030E RID: 782
SCE_NET_CONFIG_ETHER_LINK_MODE_10G_FD = 515,
// Token: 0x0400030F RID: 783
SCE_NET_CONFIG_ETHER_LINK_MODE_AUTO_10M_HD = 21,
// Token: 0x04000310 RID: 784
SCE_NET_CONFIG_ETHER_LINK_MODE_AUTO_10M_FD = 23,
// Token: 0x04000311 RID: 785
SCE_NET_CONFIG_ETHER_LINK_MODE_AUTO_100M_HD = 37,
// Token: 0x04000312 RID: 786
SCE_NET_CONFIG_ETHER_LINK_MODE_AUTO_100M_FD = 39,
// Token: 0x04000313 RID: 787
SCE_NET_CONFIG_ETHER_LINK_MODE_AUTO_1G_FD = 71,
// Token: 0x04000314 RID: 788
SCE_NET_CONFIG_ETHER_LINK_MODE_AUTO_ALL = 119
} SceNetConfigEtherLinkMode;
// Token: 0x02000067 RID: 103
typedef struct SceNetInAddr
{
// Token: 0x04000316 RID: 790
uint32_t s_addr;
} SceNetInAddr;
// Token: 0x02000068 RID: 104
typedef struct SceNetIfListAddr
{
// Token: 0x04000317 RID: 791
SceNetInAddr addr;
// Token: 0x04000318 RID: 792
SceNetInAddr dstaddr;
// Token: 0x04000319 RID: 793
SceNetInAddr broadaddr;
// Token: 0x0400031A RID: 794
SceNetInAddr netmask;
} SceNetIfListAddr;
// Token: 0x02000069 RID: 105
typedef struct SceNetIn6Addr
{
// Token: 0x0400031B RID: 795
uint8_t __u6_addr8[16];
} SceNetIn6Addr;
// Token: 0x0200006A RID: 106
typedef struct SceNetIfListAddr6
{
// Token: 0x0400031C RID: 796
SceNetIn6Addr addr;
} SceNetIfListAddr6;
// Token: 0x0200006B RID: 107
typedef struct SceNetIfListPacketStatistics
{
// Token: 0x0400031D RID: 797
uint64_t allBytes;
// Token: 0x0400031E RID: 798
uint64_t allPackets;
// Token: 0x0400031F RID: 799
uint64_t broadcastBytes;
// Token: 0x04000320 RID: 800
uint64_t broadcastPackets;
// Token: 0x04000321 RID: 801
uint64_t multicastBytes;
// Token: 0x04000322 RID: 802
uint64_t multicastPackets;
// Token: 0x04000323 RID: 803
uint64_t droppedPackets;
// Token: 0x04000324 RID: 804
uint64_t errorPackets;
} SceNetIfListPacketStatistics;
// Token: 0x0200006C RID: 108
typedef struct SceNetIfListStatistics
{
// Token: 0x04000325 RID: 805
SceNetIfListPacketStatistics tx;
// Token: 0x04000326 RID: 806
SceNetIfListPacketStatistics rx;
} SceNetIfListStatistics;
// Token: 0x0200006D RID: 109
typedef struct SceNetIfList
{
// Token: 0x04000327 RID: 807
uint8_t ifname[16];
// Token: 0x04000328 RID: 808
uint8_t dstifname[16];
// Token: 0x04000329 RID: 809
int ifindex;
// Token: 0x0400032A RID: 810
int dstifindex;
// Token: 0x0400032B RID: 811
SceNetIfListAddr addrs[2];
// Token: 0x0400032C RID: 812
SceNetIfListFlag ifflags;
// Token: 0x0400032D RID: 813
SceNetIfListType type;
// Token: 0x0400032E RID: 814
SceNetEtherAddr addr;
// Token: 0x0400032F RID: 815
int mtu;
// Token: 0x04000330 RID: 816
int maxmtu;
// Token: 0x04000331 RID: 817
SceNetIfListStatistics drv_statistics;
// Token: 0x04000332 RID: 818
SceNetIfListStatistics emu_statistics;
// Token: 0x04000333 RID: 819
SceNetConfigEtherLinkMode link_status;
// Token: 0x04000334 RID: 820
int reserved1;
// Token: 0x04000335 RID: 821
int total_use_timer;
// Token: 0x04000336 RID: 822
int tx_bps;
// Token: 0x04000337 RID: 823
int rx_bps;
// Token: 0x04000338 RID: 824
int max_tx_bps;
// Token: 0x04000339 RID: 825
int max_rx_bps;
// Token: 0x0400033A RID: 826
SceNetIfListAddr6 addrs6[2];
// Token: 0x0400033B RID: 827
uint32_t addrs6_plen[2];
// Token: 0x0400033C RID: 828
SceNetIfListIn6Flag addrs6_flags[2];
// Token: 0x0400033D RID: 829
uint8_t reserved[52];
} SceNetIfList;
typedef struct
{
uint64_t pad0;
char version_str[0x1C];
uint32_t version;
uint64_t pad1;
} OrbisKernelSwVersion;
enum Flag
{
Flag_None = 0,
SkipLaunchCheck = 1,
SkipResumeCheck = 1,
SkipSystemUpdateCheck = 2,
RebootPatchInstall = 4,
VRMode = 8,
NonVRMode = 16
};
typedef struct _LncAppParam
{
uint32_t sz;
uint32_t user_id;
uint32_t app_opt;
uint64_t crash_report;
enum Flag check_flag;
}
LncAppParam;
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;
typedef struct pkg_metadata {
const char* uri;
const char* ex_uri;
const char* playgo_scenario_id;
const char* content_id;
const char* content_name;
const char* icon_url;
} pkg_metadata_t;
typedef struct pkg_info {
char content_id[48];
int type;
int platform;
} pkg_info_t;
typedef struct playgo_info {
char lang[8][30];
char scenario_ids[3][64];
char content_ids[64];
long unknown[810];
} playgo_info_t;
typedef uint32_t(*SceLncUtilLaunchAppType)(const char* tid, const char* argv[], LncAppParam* param);
extern SceLncUtilLaunchAppType sceLncUtilLaunchApp_dyn;
uint32_t sceLncUtilLaunchApp(const char* tid, const char* argv[], LncAppParam* param);
/* ====================================== Dynamic SystemService Symbols ===================================*/
extern int (*sceSystemServiceGetAppIdOfRunningBigApp)(void);
/* ====================================== Remote Play Symbols ======================================*/
extern int (*sceRemoteplayInitialize)(void*, size_t);
extern int (*sceRemoteplayGeneratePinCode)(uint32_t*);
extern int (*sceSystemServiceGetAppTitleId)(int appid, char* titleid);
extern int (*sceRemoteplayConfirmDeviceRegist)(int*, int*);
extern int (*sceRemoteplayNotifyPinCodeError)(int);
/* ====================================== Dynamic Appmsg Symbols ===================================*/
extern uint32_t(*sceAppMessagingSendMsg)(uint32_t appId, uint32_t msgType, const void* msg, size_t msgLength, uint32_t flags);
extern int (*sceAppMessagingReceiveMsg)(const AppMessage* msg);
/* ====================================== Dynamic libkernel_sys Symbols ===================================*/
extern int (*sceKernelMprotect)(void* addr, size_t len, int prot);
extern int (*sceKernelDebugOutText)(int DBG_CHANNEL, const char* text);
extern int (*sceKernelSendNotificationRequest)(int unk1, OrbisNotificationRequest* req, int size, int unk2);
extern int (*sceKernelMkdir)(const char* path, int mode);
extern int (*sceKernelGetProsperoSystemSwVersion)(OrbisKernelSwVersion* sw);
extern int (*scePthreadCreate)(void* thread, const void* attr, void* (*entry) (void*), void* arg, const char* name);
extern int (*sceKernelGetAppInfo)(pid_t pid, app_info_t *info);
extern int (*sceKernelGetProcessName)(int pid, char* name);
extern int (*sceKernelJitCreateSharedMemory)(int flags, size_t size, int protection, int *destinationHandle);
extern int (*sceKernelJitCreateAliasOfSharedMemory)(int handle, int protection, int *destinationHandle);
extern int (*sceKernelJitMapSharedMemory)(int handle, int protection, void **destination);
extern int(*ioctl)(int, int, void*);
extern int (*sceRegMgrGetInt)(long, int*);
extern int (*sceShellUIUtilInitialize)(void);
extern int (*sceShellUIUtilLaunchByUri)(const char* uri, SceShellUIUtilLaunchByUriParam* Param);
/* WRAPPERS */
int sceSystemServiceGetAppId(const char * tid);
void KillAllWithName(const char * name, int signal);

View File

@@ -0,0 +1,116 @@
/*
* Hacker Disassembler Engine 64
* Copyright (c) 2008-2009, Vyacheslav Patkov.
* All rights reserved.
*
* hde64.h: C/C++ header file
*
*/
#ifndef _HDE64_H_
#define _HDE64_H_
/* stdint.h - C99 standard header
* http://en.wikipedia.org/wiki/stdint.h
*
* if your compiler doesn't contain "stdint.h" header (for
* example, Microsoft Visual C++), you can download file:
* http://www.azillionmonkeys.com/qed/pstdint.h
* and change next line to:
* #include "pstdint.h"
*/
//#include "pstdint.h"
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define F_MODRM 0x00000001
#define F_SIB 0x00000002
#define F_IMM8 0x00000004
#define F_IMM16 0x00000008
#define F_IMM32 0x00000010
#define F_IMM64 0x00000020
#define F_DISP8 0x00000040
#define F_DISP16 0x00000080
#define F_DISP32 0x00000100
#define F_RELATIVE 0x00000200
#define F_ERROR 0x00001000
#define F_ERROR_OPCODE 0x00002000
#define F_ERROR_LENGTH 0x00004000
#define F_ERROR_LOCK 0x00008000
#define F_ERROR_OPERAND 0x00010000
#define F_PREFIX_REPNZ 0x01000000
#define F_PREFIX_REPX 0x02000000
#define F_PREFIX_REP 0x03000000
#define F_PREFIX_66 0x04000000
#define F_PREFIX_67 0x08000000
#define F_PREFIX_LOCK 0x10000000
#define F_PREFIX_SEG 0x20000000
#define F_PREFIX_REX 0x40000000
#define F_PREFIX_ANY 0x7f000000
#define PREFIX_SEGMENT_CS 0x2e
#define PREFIX_SEGMENT_SS 0x36
#define PREFIX_SEGMENT_DS 0x3e
#define PREFIX_SEGMENT_ES 0x26
#define PREFIX_SEGMENT_FS 0x64
#define PREFIX_SEGMENT_GS 0x65
#define PREFIX_LOCK 0xf0
#define PREFIX_REPNZ 0xf2
#define PREFIX_REPX 0xf3
#define PREFIX_OPERAND_SIZE 0x66
#define PREFIX_ADDRESS_SIZE 0x67
#pragma pack(push,1)
typedef struct {
uint8_t len;
uint8_t p_rep;
uint8_t p_lock;
uint8_t p_seg;
uint8_t p_66;
uint8_t p_67;
uint8_t rex;
uint8_t rex_w;
uint8_t rex_r;
uint8_t rex_x;
uint8_t rex_b;
uint8_t opcode;
uint8_t opcode2;
uint8_t modrm;
uint8_t modrm_mod;
uint8_t modrm_reg;
uint8_t modrm_rm;
uint8_t sib;
uint8_t sib_scale;
uint8_t sib_index;
uint8_t sib_base;
union {
uint8_t imm8;
uint16_t imm16;
uint32_t imm32;
uint64_t imm64;
} imm;
union {
uint8_t disp8;
uint16_t disp16;
uint32_t disp32;
} disp;
uint32_t flags;
} hde64s;
#pragma pack(pop)
#ifdef __cplusplus
extern "C" {
#endif
/* __cdecl */
unsigned int hde64_disasm(const void *code, hde64s *hs);
#ifdef __cplusplus
}
#endif
#endif /* _HDE64_H_ */

View File

@@ -0,0 +1,521 @@
/* 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/>. */
#pragma once
#include <strings.h>
#ifndef IPC_HEADER_H
#define IPC_HEADER_H
#include <array>
#include <cstring>
#include <errno.h>
#include <fcntl.h>
#include <iostream>
#include <json.hpp>
#include <memory>
#include <msg.hpp>
#include <mutex>
#include <stdarg.h>
#include <stdexcept>
#include <string>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <unistd.h>
#include <vector>
#include <ps5/klog.h>
enum Cheat_Actions {
DOWNLOAD_CHEATS = 0,
RELOAD_CHEATS,
};
extern bool is_testkit, cheats_shortcut_activate;
pid_t find_pid(const char *name, bool needle, bool for_bigapp,
bool need_eboot = false);
static void game_log(const char *fmt, ...) {
char buffer[DAEMON_BUFF_MAX];
va_list args;
va_start(args, fmt);
int len = vsnprintf(buffer, DAEMON_BUFF_MAX, fmt, args);
va_end(args);
if (len >= 0 && len < DAEMON_BUFF_MAX - 2) {
// If vsnprintf succeeded and there's space for \n and null terminator
buffer[len] = '\n';
buffer[len + 1] = '\0';
} else {
// If the buffer was truncated, ensure it ends with \n and null terminator
buffer[DAEMON_BUFF_MAX - 2] = '\n';
buffer[DAEMON_BUFF_MAX - 1] = '\0';
}
klog_printf(buffer);
}
static int MainDaemonSocket = -1;
static int UtilDaemonSocket = -1;
class IPC_Client {
private:
public:
bool util_daemon = false;
// Socket Management
int OpenConnection(const char *path) {
sockaddr_un server;
int soc = socket(AF_UNIX, SOCK_STREAM, 0);
if (soc == -1) {
game_log("Failed to create socket");
return -1;
}
server.sun_family = AF_UNIX;
strncpy(server.sun_path, path, sizeof(server.sun_path) - 1);
if (connect(soc, (struct sockaddr *)&server, SUN_LEN(&server)) == -1) {
close(soc);
game_log("Failed to connect to socket");
return -1;
}
return soc;
}
// IPC Functions
bool IPCOpenConnection() {
util_daemon ? UtilDaemonSocket = OpenConnection(UTIL_IPC_SOC)
: MainDaemonSocket = OpenConnection(CRIT_IPC_SOC);
return util_daemon ? UtilDaemonSocket >= 0 : MainDaemonSocket >= 0;
}
bool IPCOpenIfNotConnected() {
if (util_daemon ? UtilDaemonSocket >= 0 : MainDaemonSocket >= 0) {
return true;
}
return IPCOpenConnection();
}
int IPCReceiveData(IPCMessage &msg, std::string &ipc_msg) {
// erase the old message
bzero(msg.msg, sizeof(msg.msg));
int timeout_ms = 10 * 1000;
// Set receive timeout
struct timeval tv;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
int socket_fd = util_daemon ? UtilDaemonSocket : MainDaemonSocket;
if (setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
return -1; // Error setting timeout
}
int ret = recv(socket_fd, reinterpret_cast<void*>(&msg), sizeof(msg), MSG_NOSIGNAL);
if (ret < 0) {
game_log("recv failed with: 0X%X", ret);
return ret;
}
game_log("Daemon returned: %i", msg.error);
if (msg.error != 0) {
game_log("Daemon returned an error: %i (strerror: %s)", msg.error, strerror(errno));
return msg.error;
}
if (strlen(msg.msg) <= 2) {
game_log("Daemon message is empty");
return -1;
}
nlohmann::json j;
// parse the json from the payload buffer
try {
j = nlohmann::json::parse(msg.msg);
} catch (
const std::exception &e) { // so if it can parse it doesnt crash shellui
game_log("Failed to parse json: %s", e.what());
return -1;
}
if (!j.contains("var")) {
game_log("Daemon message does not contain the return obj");
return -1;
}
ipc_msg = j["var"];
game_log("Daemon IPC return obj: %s", ipc_msg.c_str());
return msg.error;
}
int IPCSendData(const IPCMessage &msg) {
int ret =
send(util_daemon ? UtilDaemonSocket : MainDaemonSocket,
reinterpret_cast<const void *>(&msg), sizeof(msg), MSG_NOSIGNAL);
if (ret < 0) {
game_log("IPCSendData failed with: %s", strerror(errno));
}
game_log("IPCSendData sent %i bytes", ret);
return ret;
}
int IPCCloseConnection() {
if (util_daemon ? UtilDaemonSocket < 0 : MainDaemonSocket < 0) {
return -1;
}
close(util_daemon ? UtilDaemonSocket : MainDaemonSocket);
util_daemon ? UtilDaemonSocket = -1 : MainDaemonSocket = -1;
return 0;
}
bool IPCSendCommand(DaemonCommands cmd, std::string &ipc_msg1,
std::string ipc_msg2 = "") {
int ret = -1;
std::string json;
nlohmann::json j;
#if SHELL_DEBUG==1
game_log("Sending command to daemon: 0x%X", cmd);
#endif
IPCMessage msg;
msg.cmd = cmd;
if (cmd == BREW_REMOUNT_FOLDER) {
j["mount_src"] = ipc_msg1;
j["mount_dest"] = ipc_msg2;
json = j.dump();
}
else if (ipc_msg2.empty()) {
if (cmd == BREW_DAEMON_PID || cmd == BREW_UTIL_DAEMON_PID) {
json = "{\"pid\": 0 }";
} else {
json = "{\"msg_1\": 0}";
}
} else {
json = ipc_msg2;
}
// game_log("Json: %s", json.c_str());
if (!IPCOpenIfNotConnected()) {
game_log("Failed to open connection to daemon");
return false;
}
IPC_Ret error = IPC_Ret::INVALID;
snprintf(msg.msg, sizeof(msg.msg), "%s", json.c_str());
if ((ret = IPCSendData(msg)) < 0) {
game_log("Failed to send message to daemon");
// notify("Failed to send message to daemon");
IPCCloseConnection();
return false;
}
if(cmd == BREW_KILL_DAEMON) {
game_log("Daemon kill cmd sent");
return true;
}
// Get message back from daemon
error = (IPC_Ret)IPCReceiveData(msg, ipc_msg1);
if (error == IPC_Ret::NO_ERROR) {
game_log("[ItemzDaemon] Daemon returned NO ERROR");
return true;
} else {
game_log("[ItemzDaemon] Daemon returned an ERROR");
// notify("Daemon returned an ERROR");
return false;
}
return false;
}
// Deleted copy constructor and assignment operator to ensure only one
// instance
IPC_Client &operator=(const IPC_Client &) = delete;
// Static method to access the instance
static IPC_Client &getInstance(bool is_util_daemon) {
static IPC_Client
instance; // Lazy-loaded instance, guaranteed to be destroyed
instance.util_daemon = is_util_daemon;
return instance;
}
int GetDaemonPid() {
std::string ipc_msg;
if (!IPCSendCommand(util_daemon ? BREW_UTIL_DAEMON_PID : BREW_DAEMON_PID,
ipc_msg)) {
game_log("Failed to get daemon pid");
return -1;
} else {
game_log("Daemon pid: %s", ipc_msg.c_str());
return atoi(ipc_msg.c_str());
}
return -1;
}
IPC_Ret ToggleSetting(DaemonCommands cmd, bool turn_on) {
std::string ipc_msg;
std::string json = turn_on ? "{\"toggle\": 1}" : "{\"toggle\": 0}";
if (!IPCSendCommand(cmd, ipc_msg, json)) {
game_log("Failed to toggle setting 0x%X (%d)", cmd, cmd);
return IPC_Ret::OPERATION_FAILED;
}
game_log("Setting 0x%X (%d) toggled", cmd, cmd);
return IPC_Ret::NO_ERROR;
}
IPC_Ret DownloadTheStore() {
if (util_daemon) {
game_log("This IPC command is ONLY in the main daemon");
return IPC_Ret::INVALID;
}
std::string ipc_msg;
if (!IPCSendCommand(BREW_INSTALL_THE_STORE, ipc_msg)) {
game_log("Failed to BREW_INSTALL_THE_STORE");
return IPC_Ret::OPERATION_FAILED;
}
return IPC_Ret::NO_ERROR;
}
IPC_Ret DownloadKstuff() {
std::string ipc_msg;
if (!IPCSendCommand(BREW_UTIL_DOWNLOAD_KSTUFF, ipc_msg)) {
game_log("Failed to BREW_UTIL_DOWNLOAD_KSTUFF");
return IPC_Ret::OPERATION_FAILED;
}
return IPC_Ret::NO_ERROR;
}
void KillDaemon() {
std::string ipc_msg;
IPCSendCommand(BREW_KILL_DAEMON, ipc_msg);
}
void ForceKillPID(int pid) {
if(util_daemon) {
game_log("This IPC command is NOT in the util daemon");
return;
}
std::string ipc_msg;
std::string json = "{\"pid\": " + std::to_string(pid) + "}";
IPCSendCommand(BREW_FORCE_KILL_PID, ipc_msg, json);
}
//
IPC_Ret CopyFile(std::string src, std::string dest) {
if (util_daemon) {
game_log("This IPC command is NOT in the util daemon");
return IPC_Ret::INVALID;
}
std::string ipc_msg;
std::string json = "{\"path\": \"" + src + "\", \"dest\": \"" + dest + "\"}";
if (!IPCSendCommand(BREW_COPY_FILE, ipc_msg, json)) {
game_log("Failed to copy file");
return IPC_Ret::OPERATION_FAILED;
}
return IPC_Ret::NO_ERROR;
}
IPC_Ret LaunchPlugin(std::string plugin_path, std::string tid) {
if (!util_daemon) {
game_log("This IPC command is NOT in the main daemon");
return IPC_Ret::INVALID;
}
std::string ipc_msg;
std::string json = "{\"plugin_path\": \"" + plugin_path +
"\", \"title_id\": \"" + tid + "\"}";
if (!IPCSendCommand(BREW_UTIL_LAUNCH_PLUGIN, ipc_msg, json)) {
game_log("Failed to launch plugin");
return IPC_Ret::OPERATION_FAILED;
}
return IPC_Ret::NO_ERROR;
}
bool GameVerFromTid(std::string tid, std::string &out_ver) {
if (!util_daemon) {
game_log("This IPC command is NOT in the main daemon");
return false;
}
std::string json = "{\"tid\": \"" + tid + "\"}";
if (!IPCSendCommand(BREW_UTIL_GET_GAME_VER, out_ver, json)) {
game_log("Failed to get game name from tid");
return false;
}
return true;
}
bool Remount(const char* src, const char* dest) {
if (util_daemon) {
game_log("This IPC command is NOT in the util daemon");
return false;
}
// send jailbreak IPC command
std::string in = src;
if (!IPCSendCommand(BREW_REMOUNT_FOLDER, in, dest)) {
game_log("Failed to remount %s to %s", src, dest);
return false;
}
return true;
}
bool GetGameCheats(const std::string &tid, const std::string &ver,
std::string &cheats) {
if (!util_daemon) {
game_log("This IPC command is NOT in the main daemon");
return false;
}
std::string json =
R"({"tid": ")" + tid + R"(", "version": ")" + ver + R"("}")";
if (!IPCSendCommand(BREW_UTIL_GET_GAME_CHEAT, cheats, json)) {
game_log("Failed to get cheats for %s", tid.c_str());
return false;
}
return true;
}
bool ToggleGameCheat(int pid, const std::string &tid, int cheat_index,
std::string &cheat_enabled) {
if (!util_daemon) {
game_log("This IPC command is NOT in the main daemon");
return false;
}
std::string ipc_msg;
std::string json = R"({"tid": ")" + tid + R"(", "cheat_id" : )" +
std::to_string(cheat_index) + R"(, "pid" : )" +
std::to_string(pid) + "}";
if (!IPCSendCommand(BREW_UTIL_TOGGLE_CHEAT, cheat_enabled, json)) {
game_log("Failed to enable cheats for %s", tid.c_str());
return false;
}
return true;
}
void SendRestModeAction() {
if (!util_daemon) {
game_log("This IPC command is NOT in the main daemon");
return;
}
std::string ipc_msg;
std::string json;
if (!IPCSendCommand(BREW_UTIL_SHELLUI_ON_STANDBY, ipc_msg, json)) {
game_log("Failed to launch plugin");
}
}
bool IsTestKit() {
if (util_daemon) {
game_log("This IPC command is NOT in the util daemon");
return false;
}
std::string ipc_msg;
if (!IPCSendCommand(BREW_TESTKIT_CHECK, ipc_msg)) {
return false;
}
return true;
}
void Reload_Daemon_Settings() {
std::string ipc_msg;
if (!IPCSendCommand(BREW_RELOAD_SETTINGS, ipc_msg)) {
game_log("Failed to reload daemon settings");
} else {
game_log("Daemon settings reloaded successfully");
}
}
bool Launch_Elfldr() {
if (!util_daemon) {
game_log("This IPC command is NOT in the main daemon");
return false;
}
std::string ipc_msg;
if (!IPCSendCommand(BREW_UTIL_LAUNCH_ELFLDR, ipc_msg)) {
return false;
}
return true;
}
bool Toggle_ps5debug() {
if (util_daemon) {
game_log("This IPC command is NOT in the util daemon");
return false;
}
std::string ipc_msg;
if (!IPCSendCommand(BREW_TOGGLE_PS5DEBUG, ipc_msg)) {
return false;
}
return true;
}
bool Cheats_Action(Cheat_Actions act) {
DaemonCommands cmd;
if (!util_daemon) {
game_log("This IPC command is NOT in the main daemon");
return false;
}
switch (act) {
case DOWNLOAD_CHEATS:
cmd = BREW_UTIL_DOWNLOAD_CHEATS;
break;
case RELOAD_CHEATS:
cmd = BREW_UTIL_RELOAD_CHEATS;
break;
default:
game_log("Invalid action");
return false;
}
std::string ipc_msg;
if (!IPCSendCommand(cmd, ipc_msg)) {
return false;
}
return true;
}
bool ToggleDPI(bool turn_on, bool is_v2) {
if (!util_daemon) {
game_log("This IPC command is NOT in the main daemon");
return false;
}
std::string ipc_msg;
std::string json = "{\"toggle\": " + std::to_string(turn_on) +
", \"is_v2\": " + std::to_string(is_v2) + "}";
if (!IPCSendCommand(BREW_UTIL_TOGGLE_DPI, ipc_msg, json)) {
game_log("Failed to toggle DPI");
return false;
}
return true;
}
}; // namespace IPC
#endif // IPC_HEADER_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,83 @@
/* 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/>. */
#pragma once
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/syscall.h>
#include <unistd.h>
#include "freebsd-helper.h"
#include "ps5/payload.h"
#include "ps5/kernel.h"
#include <ps5/kernel.h>
#include <sys/sysctl.h>
#include <machine/param.h>
#include <sys/types.h>
#define MiB(x) ((x) / (1024.0 * 1024))
#define SYS_dynlib_get_info_ex 608
#define SYS_dl_get_list 0x217
#define SYS_dl_get_info_2 0x2cd
#define MODULE_INFO_NAME_LENGTH 128
#define MODULE_INFO_SANDBOXED_PATH_LENGTH 1024
#define MODULE_INFO_MAX_SECTIONS 4
#define FINGERPRINT_LENGTH 20
typedef struct {
uint64_t vaddr;
uint32_t size;
uint32_t prot;
} module_section_t;
typedef struct {
char filename[MODULE_INFO_NAME_LENGTH];
uint64_t handle;
uint8_t unknown0[32]; // NOLINT(readability-magic-numbers)
uint64_t init; // init
uint64_t fini; // fini
uint64_t eh_frame_hdr; // eh_frame_hdr
uint64_t eh_frame_hdr_sz; // eh_frame_hdr_sz
uint64_t eh_frame; // eh_frame
uint64_t eh_frame_sz; // eh_frame_sz
module_section_t sections[MODULE_INFO_MAX_SECTIONS];
uint8_t unknown7[1176]; // NOLINT(readability-magic-numbers)
uint8_t fingerprint[FINGERPRINT_LENGTH];
uint32_t unknown8;
char libname[MODULE_INFO_NAME_LENGTH];
uint32_t unknown9;
char sandboxed_path[MODULE_INFO_SANDBOXED_PATH_LENGTH];
uint64_t sdk_version;
} module_info_t;
struct proc* find_proc_by_name(const char* process_name);
struct proc* get_proc_by_pid(pid_t pid);
struct proc* get_proc_by_title_id(const char* title_id);
module_info_t* get_module_info(pid_t pid, const char* module_name);
int get_module_handle(pid_t pid, const char* module_name);
void list_all_proc_and_pid();
void list_proc_modules(struct proc* proc);

View File

@@ -0,0 +1,6 @@
#pragma once
#define SYS_dynlib_get_info_ex 608
#define SYS_dl_get_list 0x217
#define SYS_dl_get_info_2 0x2cd

View File

@@ -0,0 +1,74 @@
/*
* Hacker Disassembler Engine 64 C
* Copyright (c) 2008-2009, Vyacheslav Patkov.
* All rights reserved.
*
*/
#define C_NONE 0x00
#define C_MODRM 0x01
#define C_IMM8 0x02
#define C_IMM16 0x04
#define C_IMM_P66 0x10
#define C_REL8 0x20
#define C_REL32 0x40
#define C_GROUP 0x80
#define C_ERROR 0xff
#define PRE_ANY 0x00
#define PRE_NONE 0x01
#define PRE_F2 0x02
#define PRE_F3 0x04
#define PRE_66 0x08
#define PRE_67 0x10
#define PRE_LOCK 0x20
#define PRE_SEG 0x40
#define PRE_ALL 0xff
#define DELTA_OPCODES 0x4a
#define DELTA_FPU_REG 0xfd
#define DELTA_FPU_MODRM 0x104
#define DELTA_PREFIXES 0x13c
#define DELTA_OP_LOCK_OK 0x1ae
#define DELTA_OP2_LOCK_OK 0x1c6
#define DELTA_OP_ONLY_MEM 0x1d8
#define DELTA_OP2_ONLY_MEM 0x1e7
unsigned char hde64_table[] = {
0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5,
0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1,
0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea,
0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0,
0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab,
0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92,
0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90,
0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b,
0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,
0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc,
0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20,
0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff,
0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00,
0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01,
0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10,
0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00,
0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00,
0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00,
0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00,
0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40,
0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43,
0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40,
0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06,
0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07,
0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10,
0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00,
0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb,
0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff,
0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09,
0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff,
0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08,
0x00,0xf0,0x02,0x00
};

View File

@@ -0,0 +1,31 @@
/* 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/>. */
#pragma once
#include <stdint.h>
#include <unistd.h>
#include "proc.h"
#define DEBUG_AUTHID 0x4800000000000006
#define PTRACE_AUTHID 0x4800000000010003
#define UCRED_AUTHID_KERNEL_OFFSET
// uintptr_t get_current_ucred();
uintptr_t set_ucred_to_debugger();
uintptr_t set_proc_authid(pid_t pid, uintptr_t new_authid);
uint8_t* jailbreak_process(pid_t pid);
void jail_process(pid_t pid, uint8_t* ucred);

View File

@@ -0,0 +1,233 @@
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <cstring>
#include <thread>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/stat.h>
#include <arpa/inet.h>
class SimpleHTTPServer {
private:
int port;
std::string root_dir;
std::thread server_thread;
bool running;
std::string getMimeType(const std::string& path) {
if (path.find(".html") != std::string::npos) return "text/html";
if (path.find(".css") != std::string::npos) return "text/css";
if (path.find(".js") != std::string::npos) return "application/javascript";
if (path.find(".png") != std::string::npos) return "image/png";
if (path.find(".jpg") != std::string::npos ||
path.find(".jpeg") != std::string::npos) return "image/jpeg";
if (path.find(".mp4") != std::string::npos) return "video/mp4";
return "application/octet-stream";
}
long getFileSize(const std::string& path) {
struct stat stat_buf;
int rc = stat(path.c_str(), &stat_buf);
return rc == 0 ? stat_buf.st_size : -1;
}
void parseRange(const std::string& range_header, long file_size,
long& start, long& end) {
start = 0;
end = file_size - 1;
if (range_header.empty()) return;
std::string range = range_header.substr(6); // Remove "bytes="
size_t dash_pos = range.find('-');
if (dash_pos != std::string::npos) {
std::string start_str = range.substr(0, dash_pos);
std::string end_str = range.substr(dash_pos + 1);
if (!start_str.empty()) start = std::stol(start_str);
if (!end_str.empty()) end = std::stol(end_str);
}
if (end >= file_size) end = file_size - 1;
if (start > end) start = end;
}
void sendResponse(int client_socket, const std::string& file_path,
const std::string& range_header) {
std::ifstream file(file_path, std::ios::binary);
if (!file) {
std::string response = "HTTP/1.1 404 Not Found\r\n"
"Content-Length: 9\r\n\r\n"
"Not Found";
send(client_socket, response.c_str(), response.length(), 0);
return;
}
long file_size = getFileSize(file_path);
long start, end;
parseRange(range_header, file_size, start, end);
long content_length = end - start + 1;
std::string mime_type = getMimeType(file_path);
std::ostringstream response;
if (range_header.empty()) {
response << "HTTP/1.1 200 OK\r\n";
}
else {
response << "HTTP/1.1 206 Partial Content\r\n";
response << "Content-Range: bytes " << start << "-" << end
<< "/" << file_size << "\r\n";
}
response << "Content-Type: " << mime_type << "\r\n";
response << "Content-Length: " << content_length << "\r\n";
response << "Accept-Ranges: bytes\r\n";
response << "Connection: close\r\n";
response << "\r\n";
std::string header = response.str();
send(client_socket, header.c_str(), header.length(), 0);
file.seekg(start);
char buffer[8192];
long bytes_to_send = content_length;
while (bytes_to_send > 0 && file) {
long chunk_size = std::min(bytes_to_send, (long)sizeof(buffer));
file.read(buffer, chunk_size);
long bytes_read = file.gcount();
if (bytes_read > 0) {
send(client_socket, buffer, bytes_read, 0);
bytes_to_send -= bytes_read;
}
else {
break;
}
}
}
void handleRequest(int client_socket) {
char buffer[4096] = { 0 };
recv(client_socket, buffer, sizeof(buffer), 0);
std::string request(buffer);
std::istringstream iss(request);
std::string method, path, version;
iss >> method >> path >> version;
if (method != "GET") {
std::string response = "HTTP/1.1 405 Method Not Allowed\r\n"
"Content-Length: 18\r\n\r\n"
"Method Not Allowed";
send(client_socket, response.c_str(), response.length(), 0);
return;
}
std::string range_header;
size_t range_pos = request.find("Range: bytes=");
if (range_pos != std::string::npos) {
size_t end_pos = request.find("\r\n", range_pos);
if (end_pos != std::string::npos) {
range_header = request.substr(range_pos + 7,
end_pos - range_pos - 7);
}
}
if (path == "/") path = "/index.html";
std::string file_path = root_dir + path;
sendResponse(client_socket, file_path, range_header);
}
void serverLoop() {
int server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket < 0) {
std::cerr << "Failed to create socket\n";
return;
}
int opt = 1;
setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(port);
if (bind(server_socket, (struct sockaddr*)&server_addr,
sizeof(server_addr)) < 0) {
std::cerr << "Failed to bind socket\n";
close(server_socket);
return;
}
if (listen(server_socket, 10) < 0) {
std::cerr << "Failed to listen\n";
close(server_socket);
return;
}
running = true;
while (running) {
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_socket = accept(server_socket,
(struct sockaddr*)&client_addr,
&client_len);
if (client_socket >= 0) {
handleRequest(client_socket);
close(client_socket);
}
}
close(server_socket);
}
std::string getLocalIP() {
std::string ip_address = "127.0.0.1";
return ip_address;
}
public:
SimpleHTTPServer(int p, const std::string& root)
: port(p), root_dir(root), running(false) {
}
~SimpleHTTPServer() {
stop();
}
void start() {
if (!running) {
server_thread = std::thread(&SimpleHTTPServer::serverLoop, this);
}
}
void stop() {
if (running) {
running = false;
if (server_thread.joinable()) {
server_thread.join();
}
std::cout << "Server stopped.\n";
}
}
bool isRunning() const {
return running;
}
std::string getURL() {
return "http://" + getLocalIP() + ":" + std::to_string(port);
}
};

View File

@@ -0,0 +1,130 @@
PHDRS {
/*
* PF_X = 0x1
* PF_W = 0x2
* PF_R = 0x4
*/
phdr_text PT_LOAD FLAGS(0x5);
phdr_data PT_LOAD FLAGS(0x6);
phdr_rodata PT_LOAD FLAGS(0x4);
phdr_relro PT_LOAD FLAGS(0x4);
phdr_eh_frame PT_GNU_EH_FRAME FLAGS(0x4);
phdr_dynamic PT_DYNAMIC FLAGS(0x0);
}
SECTIONS {
PROVIDE (__payload_start = .);
.text : {
PROVIDE_HIDDEN(__text_start = .);
*(.text .text.*);
PROVIDE_HIDDEN(__text_stop = .);
} : phdr_text
.init : {
*(.init)
} : phdr_text
.fini : {
*(.fini)
} : phdr_text
.plt : {
*(.plt)
} : phdr_text
. = ALIGN(0x4000); /* move to a new page in memory */
.data : {
*(.data);
*(.data.*);
} : phdr_data
.bss (NOLOAD) : {
PROVIDE_HIDDEN (__bss_start = .);
*(.bss .bss.*);
*(COMMON)
PROVIDE_HIDDEN (__bss_end = .);
} : phdr_data
. = ALIGN(0x4000); /* move to a new page in memory */
.rodata : {
*(.rodata .rodata.*);
} : phdr_rodata
.gcc_except_table : {
*(.gcc_except_table*)
} : phdr_rodata
.hash : {
*(.hash);
} : phdr_rodata
. = ALIGN(0x4000); /* move to a new page in memory */
.eh_frame_hdr : ALIGN(0x4000) {
*(.eh_frame_hdr)
} : phdr_eh_frame
.eh_frame : ALIGN(0x10) {
*(.eh_frame)
} : phdr_eh_frame
. = ALIGN(0x4000); /* move to a new page in memory */
.data.rel.ro : {
*(.data.rel.ro .data.rel.ro.*);
} : phdr_relro
.preinit_array : {
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} : phdr_relro
.init_array : {
PROVIDE_HIDDEN(__init_array_start = .);
KEEP (*(.init_array .init_array.*));
PROVIDE_HIDDEN(__init_array_stop = .);
} : phdr_relro
.fini_array : {
PROVIDE_HIDDEN(__fini_array_start = .);
KEEP (*(.fini_array .fini_array.*));
PROVIDE_HIDDEN(__fini_array_stop = .);
} : phdr_relro
.got : {
*(.got);
} : phdr_relro
.got.plt : {
*(.got.plt);
} : phdr_relro
.rela.dyn : {
*(.rela.dyn) *(.rela);
} : phdr_relro
.rela.plt : {
*(rela.plt);
} : phdr_relro
PROVIDE (__payload_end = .);
/* this needs to be forced aligned to 0x4000 */
.dynamic : ALIGN(0x4000) {
PROVIDE_HIDDEN (_DYNAMIC = .);
*(.dynamic);
} : phdr_dynamic
.dynsym : {
*(.dynsym);
} : phdr_dynamic
.dynstr : {
*(.dynstr);
} : phdr_dynamic
}

View File

@@ -0,0 +1,126 @@
/* 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 "Detour.h"
#include <cstdint>
#include "hde64.h"
#include "ipc.hpp"
#include <machine/param.h>
#define ROUND_PG(x) (((x) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1))
extern bool has_hv_bypass;
void WriteJump(uint64_t address, uint64_t destination) {
*(uint8_t * )(address) = 0xFF;
*(uint8_t * )(address + 1) = 0x25;
*(uint8_t * )(address + 2) = 0x00;
*(uint8_t * )(address + 3) = 0x00;
*(uint8_t * )(address + 4) = 0x00;
*(uint8_t * )(address + 5) = 0x00;
*(uint64_t * )(address + 6) = destination;
}
void ReadMemory(uint64_t address, void * buffer, int length) {
memcpy(buffer, (void * ) address, length);
}
void WriteMemory(uint64_t address, void * buffer, int length) {
memcpy((void * ) address, buffer, length);
}
void LockJump(uint64_t address) {
*(uint8_t * )(address) = 0xE9;
*(uint8_t * )(address + 1) = 0xFB;
*(uint8_t * )(address + 2) = 0xFF;
*(uint8_t * )(address + 3) = 0xFF;
*(uint8_t * )(address + 4) = 0xFF;
}
void PatchInJump(uint64_t address, void * destination) {
if (!address || !destination)
return;
uint8_t JumpInstructions[] = {
0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xFF, 0xE0, // mov rax, <address>; jmp rax
};
union Uint64T {
uint64_t a;
char b[8];
}
uint64;
uint64.a = (uint64_t) destination;
memcpy(JumpInstructions + 2, uint64.b, 8);
WriteJump(address, (uint64_t)destination);
}
void * DetourFunction(uint64_t address, void * destination) {
if (!address || !destination)
return 0;
uint32_t InstructionSize = 0;
pid_t pid = getpid();
game_log("Hooking %#02lx => %p", address, destination);
// sceKernelMprotect((void*)address, 0x1000, 0x7);
uint8_t code[HOOK_LENGTH];
if (sceKernelMprotect((void*)address, PAGE_SIZE, PROT_EXEC | PROT_READ | PROT_WRITE) < 0){
kernel_mprotect(pid, (uint64_t) address, PAGE_SIZE, PROT_EXEC | PROT_READ | PROT_WRITE);
}
while (InstructionSize < HOOK_LENGTH) {
hde64s hs;
uint32_t temp = hde64_disasm((void * )(address + InstructionSize), & hs);
if (hs.flags & F_ERROR) {
return 0;
}
InstructionSize += temp;
memset(code, 0x00, HOOK_LENGTH);
}
game_log("InstructionSize: %i", InstructionSize);
if (InstructionSize < HOOK_LENGTH) {
game_log("DetourFunction: Hooking Requires a minimum of 14 bytes to write jump!");
return 0;
}
int stubLength = InstructionSize + HOOK_LENGTH;
void * executableAddress = NULL;
executableAddress = malloc(stubLength);
if (!executableAddress) {
game_log("Failed to allocate memory for stub");
return 0;
}
if (sceKernelMprotect(executableAddress, stubLength, PROT_EXEC | PROT_READ | PROT_WRITE) < 0) {
kernel_mprotect(pid, (uint64_t)executableAddress, stubLength, PROT_EXEC | PROT_READ | PROT_WRITE);
}
ReadMemory((uint64_t) address, executableAddress, InstructionSize);
// game_log("Read %d bytes from %p", InstructionSize, address);
PatchInJump((uint64_t) executableAddress + InstructionSize, (void * )(address + InstructionSize));
// game_log("Patched jump in stub");
PatchInJump(address, destination);
return (void * ) executableAddress;
}

View File

@@ -0,0 +1,59 @@
/* 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 "../include/external_symbols.hpp"
/* ====================================== Dynamic SystemService Symbols ===================================*/
int (*sceSystemServiceNavigateToGoHome)(void) = nullptr;
int (*sceSystemServiceGetAppIdOfRunningBigApp)(void) = nullptr;
// Global function pointers
SceLncUtilLaunchAppType sceLncUtilLaunchApp_dyn = nullptr;
int (*sceSystemServiceGetAppTitleId)(int appid, char* titleid) = nullptr;
/* ====================================== Remote Play Symbols ======================================*/
int (*sceRemoteplayNotifyPinCodeError)(int errorcode) = nullptr;
int (*sceRemoteplayInitialize)(void*, size_t) = nullptr;
int (*sceRemoteplayGeneratePinCode)(uint32_t*) = nullptr;
int (*sceRemoteplayConfirmDeviceRegist)(int*, int*) = nullptr;
/* ====================================== Dynamic Appmsg Symbols ===================================*/
uint32_t(*sceAppMessagingSendMsg)(uint32_t appId, uint32_t msgType, const void* msg, size_t msgLength, uint32_t flags) = nullptr;
int (*sceAppMessagingReceiveMsg)(const AppMessage* msg) = nullptr;
/* ====================================== Dynamic libkernel_sys Symbols ===================================*/
int (*sceKernelGetProcessName)(int pid, char* name) = nullptr;
int (*sceKernelMprotect)(void* addr, size_t len, int prot) = nullptr;
int (*sceKernelDebugOutText)(int DBG_CHANNEL, const char* text) = nullptr;
// int (*close_alt)(int fd) = nullptr;
int (*sceKernelSleep_alt)(int seconds) = nullptr;
// ssize_t (*write_alt)(int fd, const void* buf, size_t count) = nullptr;
int (*sceKernelMkdir)( const char* path,int mode) = nullptr;
int (*sceKernelSendNotificationRequest)(int unk1, OrbisNotificationRequest* req, int size, int unk2) = nullptr;
int (*sceKernelGetProsperoSystemSwVersion)(OrbisKernelSwVersion* sw) = nullptr;
int (*scePthreadCreate)(void* thread, const void* attr, void* (*entry) (void*), void* arg, const char* name) = nullptr;
int (*sceKernelJitCreateSharedMemory)(int flags, size_t size, int protection, int *destinationHandle) = nullptr;
int (*sceKernelJitCreateAliasOfSharedMemory)(int handle, int protection, int *destinationHandle) = nullptr;
int (*sceKernelJitMapSharedMemory)(int handle, int protection, void **destination) = nullptr;
int (*sceKernelGetAppInfo)(pid_t pid, app_info_t *info) = nullptr;
int(*ioctl)(int, int, void*) = nullptr;
int (*sceRegMgrGetInt)(long, int*) = nullptr;
int (*sceShellUIUtilInitialize)(void) = nullptr;
int (*sceShellUIUtilLaunchByUri)(const char* uri, SceShellUIUtilLaunchByUriParam* Param) = nullptr;

View File

@@ -0,0 +1,335 @@
/*
* Hacker Disassembler Engine 64 C
* Copyright (c) 2008-2009, Vyacheslav Patkov.
* All rights reserved.
*
*/
#if defined(_M_X64) || defined(__x86_64__)
// #include <kernel.h>
#include "../include/hde64.h"
#include "../include/table64.h"
unsigned int hde64_disasm(const void *code, hde64s *hs)
{
uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0;
uint8_t op64 = 0;
memset(hs, 0, sizeof(hde64s));
for (x = 16; x; x--)
switch (c = *p++) {
case 0xf3:
hs->p_rep = c;
pref |= PRE_F3;
break;
case 0xf2:
hs->p_rep = c;
pref |= PRE_F2;
break;
case 0xf0:
hs->p_lock = c;
pref |= PRE_LOCK;
break;
case 0x26: case 0x2e: case 0x36:
case 0x3e: case 0x64: case 0x65:
hs->p_seg = c;
pref |= PRE_SEG;
break;
case 0x66:
hs->p_66 = c;
pref |= PRE_66;
break;
case 0x67:
hs->p_67 = c;
pref |= PRE_67;
break;
default:
goto pref_done;
}
pref_done:
hs->flags = (uint32_t)pref << 23;
if (!pref)
pref |= PRE_NONE;
if ((c & 0xf0) == 0x40) {
hs->flags |= F_PREFIX_REX;
if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8)
op64++;
hs->rex_r = (c & 7) >> 2;
hs->rex_x = (c & 3) >> 1;
hs->rex_b = c & 1;
if (((c = *p++) & 0xf0) == 0x40) {
opcode = c;
goto error_opcode;
}
}
if ((hs->opcode = c) == 0x0f) {
hs->opcode2 = c = *p++;
ht += DELTA_OPCODES;
} else if (c >= 0xa0 && c <= 0xa3) {
op64++;
if (pref & PRE_67)
pref |= PRE_66;
else
pref &= ~PRE_66;
}
opcode = c;
cflags = ht[ht[opcode / 4] + (opcode % 4)];
if (cflags == C_ERROR) {
error_opcode:
hs->flags |= F_ERROR | F_ERROR_OPCODE;
cflags = 0;
if ((opcode & -3) == 0x24)
cflags++;
}
x = 0;
if (cflags & C_GROUP) {
uint16_t t;
t = *(uint16_t *)(ht + (cflags & 0x7f));
cflags = (uint8_t)t;
x = (uint8_t)(t >> 8);
}
if (hs->opcode2) {
ht = hde64_table + DELTA_PREFIXES;
if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
hs->flags |= F_ERROR | F_ERROR_OPCODE;
}
if (cflags & C_MODRM) {
hs->flags |= F_MODRM;
hs->modrm = c = *p++;
hs->modrm_mod = m_mod = c >> 6;
hs->modrm_rm = m_rm = c & 7;
hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
if (x && ((x << m_reg) & 0x80))
hs->flags |= F_ERROR | F_ERROR_OPCODE;
if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
uint8_t t = opcode - 0xd9;
if (m_mod == 3) {
ht = hde64_table + DELTA_FPU_MODRM + t*8;
t = ht[m_reg] << m_rm;
} else {
ht = hde64_table + DELTA_FPU_REG;
t = ht[t] << m_reg;
}
if (t & 0x80)
hs->flags |= F_ERROR | F_ERROR_OPCODE;
}
if (pref & PRE_LOCK) {
if (m_mod == 3) {
hs->flags |= F_ERROR | F_ERROR_LOCK;
} else {
uint8_t *table_end, op = opcode;
if (hs->opcode2) {
ht = hde64_table + DELTA_OP2_LOCK_OK;
table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
} else {
ht = hde64_table + DELTA_OP_LOCK_OK;
table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
op &= -2;
}
for (; ht != table_end; ht++)
if (*ht++ == op) {
if (!((*ht << m_reg) & 0x80))
goto no_lock_error;
else
break;
}
hs->flags |= F_ERROR | F_ERROR_LOCK;
no_lock_error:
;
}
}
if (hs->opcode2) {
switch (opcode) {
case 0x20: case 0x22:
m_mod = 3;
if (m_reg > 4 || m_reg == 1)
goto error_operand;
else
goto no_error_operand;
case 0x21: case 0x23:
m_mod = 3;
if (m_reg == 4 || m_reg == 5)
goto error_operand;
else
goto no_error_operand;
}
} else {
switch (opcode) {
case 0x8c:
if (m_reg > 5)
goto error_operand;
else
goto no_error_operand;
case 0x8e:
if (m_reg == 1 || m_reg > 5)
goto error_operand;
else
goto no_error_operand;
}
}
if (m_mod == 3) {
uint8_t *table_end;
if (hs->opcode2) {
ht = hde64_table + DELTA_OP2_ONLY_MEM;
table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM;
} else {
ht = hde64_table + DELTA_OP_ONLY_MEM;
table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
}
for (; ht != table_end; ht += 2)
if (*ht++ == opcode) {
if ((*ht++ & pref) && !((*ht << m_reg) & 0x80))
goto error_operand;
else
break;
}
goto no_error_operand;
} else if (hs->opcode2) {
switch (opcode) {
case 0x50: case 0xd7: case 0xf7:
if (pref & (PRE_NONE | PRE_66))
goto error_operand;
break;
case 0xd6:
if (pref & (PRE_F2 | PRE_F3))
goto error_operand;
break;
case 0xc5:
goto error_operand;
}
goto no_error_operand;
} else
goto no_error_operand;
error_operand:
hs->flags |= F_ERROR | F_ERROR_OPERAND;
no_error_operand:
c = *p++;
if (m_reg <= 1) {
if (opcode == 0xf6)
cflags |= C_IMM8;
else if (opcode == 0xf7)
cflags |= C_IMM_P66;
}
switch (m_mod) {
case 0:
if (pref & PRE_67) {
if (m_rm == 6)
disp_size = 2;
} else
if (m_rm == 5)
disp_size = 4;
break;
case 1:
disp_size = 1;
break;
case 2:
disp_size = 2;
if (!(pref & PRE_67))
disp_size <<= 1;
break;
}
if (m_mod != 3 && m_rm == 4) {
hs->flags |= F_SIB;
p++;
hs->sib = c;
hs->sib_scale = c >> 6;
hs->sib_index = (c & 0x3f) >> 3;
if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
disp_size = 4;
}
p--;
switch (disp_size) {
case 1:
hs->flags |= F_DISP8;
hs->disp.disp8 = *p;
break;
case 2:
hs->flags |= F_DISP16;
hs->disp.disp16 = *(uint16_t *)p;
break;
case 4:
hs->flags |= F_DISP32;
hs->disp.disp32 = *(uint32_t *)p;
break;
}
p += disp_size;
} else if (pref & PRE_LOCK)
hs->flags |= F_ERROR | F_ERROR_LOCK;
if (cflags & C_IMM_P66) {
if (cflags & C_REL32) {
if (pref & PRE_66) {
hs->flags |= F_IMM16 | F_RELATIVE;
hs->imm.imm16 = *(uint16_t *)p;
p += 2;
goto disasm_done;
}
goto rel32_ok;
}
if (op64) {
hs->flags |= F_IMM64;
hs->imm.imm64 = *(uint64_t *)p;
p += 8;
} else if (!(pref & PRE_66)) {
hs->flags |= F_IMM32;
hs->imm.imm32 = *(uint32_t *)p;
p += 4;
} else
goto imm16_ok;
}
if (cflags & C_IMM16) {
imm16_ok:
hs->flags |= F_IMM16;
hs->imm.imm16 = *(uint16_t *)p;
p += 2;
}
if (cflags & C_IMM8) {
hs->flags |= F_IMM8;
hs->imm.imm8 = *p++;
}
if (cflags & C_REL32) {
rel32_ok:
hs->flags |= F_IMM32 | F_RELATIVE;
hs->imm.imm32 = *(uint32_t *)p;
p += 4;
} else if (cflags & C_REL8) {
hs->flags |= F_IMM8 | F_RELATIVE;
hs->imm.imm8 = *p++;
}
disasm_done:
if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
hs->flags |= F_ERROR | F_ERROR_LENGTH;
hs->len = 15;
}
return (unsigned int)hs->len;
}
#endif // defined(_M_X64) || defined(__x86_64__)

View File

@@ -0,0 +1,156 @@
extern "C"{
#include "../include/proc.h"
}
struct proc* find_proc_by_name(const char* proc_name)
{
uint64_t next = 0;
kernel_copyout(KERNEL_ADDRESS_ALLPROC, &next, sizeof(uint64_t));
struct proc* proc = (struct proc*) malloc(sizeof(struct proc));
do
{
kernel_copyout(next, (void*) proc, sizeof(struct proc));
if (!strcmp(proc->p_comm, proc_name))
return proc;
kernel_copyout(next, &next, sizeof(uint64_t));
} while (next);
free(proc);
return NULL;
}
struct proc* get_proc_by_title_id(const char* title_id)
{
uint64_t next = 0;
kernel_copyout(KERNEL_ADDRESS_ALLPROC, &next, sizeof(uint64_t));
struct proc* proc = (struct proc*) malloc(sizeof(struct proc));
do
{
kernel_copyout(next, (void*) proc, sizeof(struct proc));
if (!strcmp(proc->title_id, title_id))
return proc;
kernel_copyout(next, &next, sizeof(uint64_t));
} while (next);
free(proc);
return NULL;
}
void list_all_proc_and_pid()
{
uint64_t next = 0;
kernel_copyout(KERNEL_ADDRESS_ALLPROC, &next, sizeof(uint64_t));
struct proc* proc = (struct proc*) malloc(sizeof(struct proc));
struct vmspace vmspace;
do
{
kernel_copyout(next, (void*) proc, sizeof(struct proc));
kernel_copyout((intptr_t) proc->p_vmspace, (void*) &vmspace, sizeof(vmspace));
printf("%s - %d\n", proc->p_comm, proc->pid);
kernel_copyout(next, &next, sizeof(uint64_t));
} while (next);
free(proc);
}
struct proc* get_proc_by_pid(pid_t pid)
{
uintptr_t next = 0;
kernel_copyout(KERNEL_ADDRESS_ALLPROC, &next, sizeof(uintptr_t));
struct proc* proc = (struct proc*) malloc(sizeof(struct proc));
do
{
kernel_copyout(next, proc, sizeof(struct proc));
if (proc->pid == pid)
return proc;
kernel_copyout(next, &next, sizeof(uint64_t));
} while (next);
free(proc);
return NULL;
}
//
// List process modules by using the sys_dynlib_get_info_ex syscall
//
void list_proc_modules(struct proc* proc)
{
size_t num_handles = 0;
syscall(SYS_dl_get_list, proc->pid, NULL, 0, &num_handles);
if (num_handles)
{
uintptr_t* handles = (uintptr_t*) calloc(num_handles, sizeof(uintptr_t));
syscall(SYS_dl_get_list, proc->pid, handles, num_handles, &num_handles);
for (int i = 0; i < num_handles; ++i)
{
module_info_t mod_info;
bzero(&mod_info, sizeof(mod_info));
syscall(SYS_dl_get_info_2, proc->pid, 1, handles[i], &mod_info);
printf("%s - ", mod_info.filename);
printf("%#02lx\n", mod_info.init);
}
free(handles);
}
}
module_info_t* get_module_info(pid_t pid, const char* module_name)
{
size_t num_handles = 0;
syscall(SYS_dl_get_list, pid, NULL, 0, &num_handles);
if (num_handles)
{
uintptr_t* handles = (uintptr_t*) calloc(num_handles, sizeof(uintptr_t));
syscall(SYS_dl_get_list, pid, handles, num_handles, &num_handles);
module_info_t* mod_info = (module_info_t*) malloc(sizeof(module_info_t));
for (int i = 0; i < num_handles; ++i)
{
bzero(mod_info, sizeof(module_info_t));
syscall(SYS_dl_get_info_2, pid, 1, handles[i], mod_info);
if (!strcmp(mod_info->filename, module_name))
{
return mod_info;
}
}
free(handles);
free(mod_info);
}
return NULL;
}
int get_module_handle(pid_t pid, const char* module_name)
{
module_info_t* mod_info = get_module_info(pid, module_name);
return mod_info ? mod_info->handle : 0;
}

View File

@@ -0,0 +1,137 @@
/* 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 "defs.h"
#include "Detour.h"
#include "ipc.hpp"
#include "proc.h"
#include "ps5/kernel.h"
#include "ucred.h"
#include <cstdint>
#include <iostream>
#include "webserver.hpp"
#include <unistd.h>
#include <util.hpp>
extern "C" long ptr_syscall = 0;
void __syscall() {
asm(".intel_syntax noprefix\n"
" mov rax, rdi\n"
" mov rdi, rsi\n"
" mov rsi, rdx\n"
" mov rdx, rcx\n"
" mov r10, r8\n"
" mov r8, r9\n"
" mov r9, qword ptr [rsp + 8]\n"
" call qword ptr [rip + ptr_syscall]\n"
" ret\n");
}
struct OrbisKernelTimespec {
int64_t tv_sec;
int64_t tv_nsec;
};
extern "C" {
int sceKernelGetSocSensorTemperature(int sensorId, int* soctime);
int get_page_table_stats(int vm, int type, int* total, int* free);
int sceKernelGetCpuUsage(struct Proc_Stats* out, int32_t* size);
int sceKernelGetThreadName(uint32_t id, char* out);
int sceKernelGetCpuTemperature(int* cputemp);
int sceKernelClockGettime(int clockId, OrbisKernelTimespec* tp);
}
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;
}
void notify(const char* text, ...)
{
OrbisNotificationRequest req;
memset(&req, 0, sizeof(OrbisNotificationRequest));
char buff[1024];
// printf("******************** text: %s\n", text);
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);
}
#define KERNEL_DLSYM(handle, sym) \
(*(void**)&sym=(void*)kernel_dynlib_dlsym(-1, handle, #sym))
int main(int argc, char const* argv[]) {
//OrbisKernelSwVersion sw;
notify("fps_elf loaded!");
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);
while (true) {
game_log("sleeping ....");
sleep(0x100000);
}
return 0;
}

View File

@@ -0,0 +1,83 @@
extern "C"{
#include "../include/ucred.h"
}
#define UCRED_SIZE 0x200
uintptr_t set_ucred_to_debugger()
{
return set_proc_authid(getpid(), DEBUG_AUTHID);
}
//
// Search process entr on the allproc linked list
// acquire the "ucred" structure and set it
uintptr_t set_proc_authid(pid_t pid, uintptr_t new_authid)
{
struct proc* proc = get_proc_by_pid(getpid());
if (proc)
{
//
// Read from kernel
//
uintptr_t authid = 0;
kernel_copyout((uintptr_t) proc->p_ucred + 0x58, &authid, sizeof(uintptr_t));
kernel_copyin(&new_authid, (uintptr_t) proc->p_ucred + 0x58, sizeof(uintptr_t));
free(proc);
return authid;
}
return 0;
}
uint8_t* jailbreak_process(pid_t pid)
{
uint8_t* backup_ucred = (uint8_t*) malloc(UCRED_SIZE);
if (!backup_ucred)
{
return NULL;
}
uintptr_t ucred = kernel_get_proc_ucred(pid);
//
// Backup it
//
kernel_copyout(ucred, backup_ucred, UCRED_SIZE);
uint32_t uid_store = 0;
uint32_t ngroups_store = 0;
int64_t caps_store = -1;
uint8_t attr_store[] = {0x80, 0, 0, 0, 0, 0, 0, 0};
kernel_copyin(&uid_store, ucred + 0x04, 0x4);
kernel_copyin(&uid_store, ucred + 0x08, 0x4);
kernel_copyin(&uid_store, ucred + 0x0C, 0x4);
kernel_copyin(&ngroups_store, ucred + 0x0C, 0x4);
kernel_copyin(&uid_store, ucred + 0x14, 0x4);
// Escalate sony privileges
// kernel_copyin(&authid_store, ucred + 0x58, 0x8); // cr_sceAuthID
kernel_copyin(&caps_store, ucred + 0x60, 0x8); // cr_sceCaps[0]
kernel_copyin(&caps_store, ucred + 0x68, 0x8); // cr_sceCaps[1]
kernel_copyin(attr_store, ucred + 0x83, 0x1); // cr_sceAttr[0]
return backup_ucred;
}
//
// Restore
//
void jail_process(pid_t pid, uint8_t* old_ucred)
{
uintptr_t ucred = kernel_get_proc_ucred(pid);
kernel_copyin(old_ucred, ucred, UCRED_SIZE);
}

View File

@@ -37,6 +37,7 @@ enum DaemonCommands : int {
BREW_LAST_RET,
BREW_TESTKIT_CHECK,
BREW_ENABLE_TOOLBOX,
BREW_CHMOD_DIR,
BREW_UTIL_TEST_CONNECTION = 0x8000000,
BREW_UTIL_RETURN_VALUE = 0x8000002,
@@ -52,6 +53,7 @@ enum DaemonCommands : int {
BREW_UTIL_DOWNLOAD_CHEATS,
BREW_UTIL_RELOAD_CHEATS,
BREW_UTIL_DOWNLOAD_KSTUFF,
BREW_UTIL_TOGGLE_LEGACY_CMD_SERVER,
// Special command to launch Johns elfldr for lite mode
BREW_UTIL_LAUNCH_ELFLDR = 0xE1F1D8, // not used if already running

View File

@@ -80,6 +80,15 @@ static inline constexpr Nid sceKernelDebugOutText("9JYNqN6jAKI");
static inline constexpr Nid sceKernelGetFsSandboxRandomWord("JGfTMBOdUJo");
static inline constexpr Nid open("wuCroIGjt2g");
static inline constexpr Nid ioctl("PfccT7qURYE");
static inline constexpr Nid getpid("HoLVWNanBBc");
static inline constexpr Nid gettimeofday("n88vx3C5nW8");
static inline constexpr Nid sceKernelSendNotificationRequest("zl7hupSO0C0");
static inline constexpr Nid sceGnmSubmitAndFlipCommandBuffersForWorkload("Ga6r7H6Y0RI");
static inline constexpr Nid mono_get_root_domain{"5a8b+s6HtaA"};
static inline constexpr Nid mono_property_get_get_method{"uzLsJUMjvLY"};
static inline constexpr Nid mono_property_get_set_method{"BhrEyM1kGW8"};
@@ -92,7 +101,7 @@ static inline constexpr Nid mono_domain_assembly_open{"dCeihPtadCM"};
static inline constexpr Nid mono_thread_attach{"qqUxjwJzc2I"};
static inline constexpr Nid mono_class_get_method_from_name{"H5IByLixeaI"};
static inline constexpr Nid scePadReadState{"YndgXqQVV7c"};
static inline constexpr Nid strlen{"j4ViWNHEgww"};
static inline constexpr Nid sceAppInstUtilInstallByPackage{"tDtjgaXYmuo"};

View File

@@ -23,7 +23,7 @@ void printBacktrace();
template <typename ...Types>
[[noreturn]] static void fatalf(const char *msg, Types... values) {
__builtin_printf(msg, values...);
printBacktrace();
//printBacktrace();
exit(0);
}
#else
@@ -31,7 +31,7 @@ template <typename ...Types>
template <typename ...Types>
static void fatalf(const char *msg, Types... values) {
__builtin_printf(msg, values...);
printBacktrace();
//printBacktrace();
}
#endif
#endif

Binary file not shown.

BIN
Source Code/lib/libelfldr.a Normal file

Binary file not shown.

View File

@@ -1,160 +1,4 @@
#pragma once
#include "ps5/kernel.h"
#include <ps5/klog.h>
static const unsigned long KERNEL_OFFSET_PROC_P_VMSPACE = 0x200;
static unsigned long KERNEL_OFFSET_VMSPACE_P_ROOT = 0x1c8;
//
// This function is from the latest SDK, etaHEN break it's execution with it. So while we don't fix it, let's place this useful function here
//
static int kernel_mprotect(int pid, unsigned long addr, unsigned long len, int prot)
{
unsigned long vm_map_entry_addr;
unsigned long vmspace_addr;
unsigned long proc_addr;
unsigned char vm_prot;
unsigned long start;
unsigned long end;
switch(kernel_get_fw_version() & 0xffff0000) {
case 0x1000000:
case 0x1010000:
case 0x1020000:
KERNEL_OFFSET_VMSPACE_P_ROOT = 0x1c0;
break;
case 0x1050000:
case 0x1100000:
case 0x1110000:
case 0x1120000:
case 0x1130000:
case 0x1140000:
KERNEL_OFFSET_VMSPACE_P_ROOT = 0x1c0;
break;
case 0x2000000:
KERNEL_OFFSET_VMSPACE_P_ROOT = 0x1c8;
break;
case 0x2200000:
case 0x2250000:
case 0x2260000:
case 0x2300000:
case 0x2500000:
case 0x2700000:
KERNEL_OFFSET_VMSPACE_P_ROOT = 0x1c8;
break;
case 0x3000000:
case 0x3100000:
case 0x3200000:
case 0x3210000:
KERNEL_OFFSET_VMSPACE_P_ROOT = 0x1c8;
break;
case 0x4020000:
KERNEL_OFFSET_VMSPACE_P_ROOT = 0x1c8;
break;
case 0x4000000:
case 0x4030000:
case 0x4500000:
case 0x4510000:
KERNEL_OFFSET_VMSPACE_P_ROOT = 0x1c8;
break;
case 0x5000000:
case 0x5020000:
case 0x5100000:
case 0x5500000:
KERNEL_OFFSET_VMSPACE_P_ROOT = 0x1c8;
break;
case 0x6000000:
case 0x6020000:
case 0x6500000:
KERNEL_OFFSET_VMSPACE_P_ROOT = 0x1d0;
break;
case 0x7000000:
case 0x7010000:
case 0x7200000:
case 0x7400000:
case 0x7600000:
case 0x7610000:
case 0x8000000:
case 0x8200000:
case 0x8400000:
case 0x8600000:
case 0x9000000:
case 0x9200000:
case 0x9400000:
case 0x9600000:
KERNEL_OFFSET_VMSPACE_P_ROOT = 0x1d0;
break;
default:
klog_printf("Unknown firmware: 0x%08x\n", kernel_get_fw_version());
return -1;
}
if(!(proc_addr=kernel_get_proc(pid))) {
return -1;
}
if(kernel_copyout(proc_addr + KERNEL_OFFSET_PROC_P_VMSPACE,
&vmspace_addr, sizeof(vmspace_addr))) {
return -1;
}
if(kernel_copyout(vmspace_addr + KERNEL_OFFSET_VMSPACE_P_ROOT, &vm_map_entry_addr, sizeof(vm_map_entry_addr))) {
return -1;
}
while(vm_map_entry_addr) {
if(kernel_copyout(vm_map_entry_addr + 0x20, &start, sizeof(start))) {
return -1;
}
if(kernel_copyout(vm_map_entry_addr + 0x28, &end, sizeof(end))) {
return -1;
}
if(addr < start) {
// left
if(kernel_copyout(vm_map_entry_addr + 0x10, &vm_map_entry_addr,
sizeof(vm_map_entry_addr))) {
return -1;
}
} else if(addr >= end) {
// right
if(kernel_copyout(vm_map_entry_addr + 0x18, &vm_map_entry_addr,
sizeof(vm_map_entry_addr))) {
return -1;
}
} else {
// protection
if(kernel_copyout(vm_map_entry_addr + 0x64, &vm_prot, sizeof(vm_prot))) {
return -1;
}
vm_prot |= prot;
if(kernel_copyin(&vm_prot, vm_map_entry_addr + 0x64, sizeof(vm_prot))) {
return -1;
}
// max_protection
if(kernel_copyout(vm_map_entry_addr + 0x65, &vm_prot, sizeof(vm_prot))) {
return -1;
}
vm_prot |= prot;
if(kernel_copyin(&vm_prot, vm_map_entry_addr + 0x65, sizeof(vm_prot))) {
return -1;
}
return 0;
}
}
return -1;
}
#include <ps5/klog.h>

View File

@@ -18,14 +18,39 @@ along with this program; see the file COPYING. If not, see
#include <unistd.h>
pid_t elfldr_find_pid(const char* name);
pid_t elfldr_spawn(const char* cwd, int stdio, uint8_t* elf, const char* name);
int elfldr_exec(pid_t pid, int stdio, uint8_t* elf);
// int elfldr_exec(pid_t pid, int stdio, uint8_t* elf);
intptr_t elfldr_load(pid_t pid, uint8_t *elf);
intptr_t elfldr_payload_args(pid_t pid);
int elfldr_prepare_exec(pid_t pid, uint8_t *elf);
int elfldr_sanity_check(uint8_t *elf, size_t elf_size);
int elfldr_raise_privileges(pid_t pid);
// /* Copyright (C) 2024 John Törnblom
// 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/>. */
// #pragma once
// #include <unistd.h>
// pid_t elfldr_find_pid(const char* name);
// pid_t elfldr_spawn(const char* progname, int stdio, uint8_t *elf);
// int elfldr_exec(pid_t pid, int stdio, uint8_t* elf);
// int elfldr_read(int fd, uint8_t** elf, size_t* elf_size);
// int elfldr_sanity_check(uint8_t *elf, size_t elf_size);
// int elfldr_raise_privileges(pid_t pid);

View File

@@ -0,0 +1,49 @@
/* Copyright (C) 2024 John Törnblom
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/>. */
#pragma once
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <ps5/klog.h>
#include "pt.h"
/**
* Log to stdout and klog
**/
#define LOG_PUTS(s) { \
puts(s); \
klog_puts(s); \
}
#define LOG_PRINTF(s, ...) { \
printf(s, __VA_ARGS__); \
klog_printf(s, __VA_ARGS__); \
}
#define LOG_PERROR(s) { \
printf("%s:%d:%s: %s\n", __FILE__, __LINE__, s, strerror(errno)); \
klog_printf("%s:%d:%s: %s\n", __FILE__, __LINE__, s, strerror(errno)); \
}
#define LOG_PT_PERROR(pid, s) { \
printf("%s:%d:%s: %s\n", __FILE__, __LINE__, s, strerror(pt_errno(pid))); \
klog_printf("%s:%d:%s: %s\n", __FILE__, __LINE__, s, strerror(pt_errno(pid))); \
}

View File

@@ -20,27 +20,30 @@ along with this program; see the file COPYING. If not, see
#include <sys/types.h>
#include <machine/reg.h>
int pt_trace_me(void);
int pt_attach(pid_t pid);
int pt_detach(pid_t pid);
int pt_detach(pid_t pid, int sig);
int pt_step(pid_t pid);
int pt_continue(pid_t pid, int sig);
int pt_getregs(pid_t pid, struct reg *r);
int pt_setregs(pid_t pid, const struct reg *r);
int pt_getint(pid_t pid, intptr_t addr);
int pt_copyin(pid_t pid, const void* buf, intptr_t addr, size_t len);
int pt_copyout(pid_t pid, intptr_t addr, void* buf, size_t len);
int pt_setchar(pid_t pid, intptr_t addr, char val);
int pt_setshort(pid_t pid, intptr_t addr, short val);
int pt_setint(pid_t pid, intptr_t addr, int val);
int pt_setlong(pid_t pid, intptr_t addr, long val);
char pt_getchar(pid_t pid, intptr_t addr);
short pt_getshort(pid_t pid, intptr_t addr);
int pt_getint(pid_t pid, intptr_t addr);
long pt_getlong(pid_t pid, intptr_t addr);
long pt_syscall(pid_t pid, int sysno, ...);
long pt_call(pid_t pid, intptr_t addr, ...);
long pt_call2(pid_t pid, intptr_t addr, ...);
intptr_t pt_resolve(pid_t pid, const char* nid);
int pt_backtrace(pid_t pid, char* addr2line, size_t size);
int pt_jitshm_create(pid_t pid, intptr_t name, size_t size, int flags);
int pt_jitshm_alias(pid_t pid, int fd, int flags);
intptr_t pt_mmap(pid_t pid, intptr_t addr, size_t len, int prot, int flags,
int fd, off_t off);
@@ -51,8 +54,7 @@ int pt_mprotect(pid_t pid, intptr_t addr, size_t len, int prot);
int pt_socket(pid_t pid, int domain, int type, int protocol);
int pt_setsockopt(pid_t pid, int fd, int level, int optname, intptr_t optval,
uint32_t optlen);
int pt_bind(pid_t pid, int sockfd, intptr_t addr, uint32_t addrlen);
int pt_bind(pid_t pid, int sockfd, intptr_t addr, uint32_t addrlen) ;
ssize_t pt_recvmsg(pid_t pid, int fd, intptr_t msg, int flags);
int pt_close(pid_t pid, int fd);
@@ -60,7 +62,10 @@ int pt_close(pid_t pid, int fd);
int pt_dup2(pid_t pid, int oldfd, int newfd);
int pt_rdup(pid_t pid, pid_t other_pid, int fd);
int pt_pipe(pid_t pid, intptr_t pipefd);
void pt_perror(pid_t pid, const char *s);
int pt_errno(pid_t pid);
intptr_t pt_sceKernelGetProcParam(pid_t pid);
intptr_t pt_getargv(pid_t pid);
long pt_call(pid_t pid, intptr_t addr, ...);
long pt_call2(pid_t pid, intptr_t addr, ...);
intptr_t pt_sceKernelGetProcParam(pid_t pid);

View File

@@ -27,7 +27,6 @@ along with this program; see the file COPYING. If not, see
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/signal.h>
#include <sys/sysctl.h>
#include <sys/un.h>
@@ -35,14 +34,11 @@ along with this program; see the file COPYING. If not, see
#include <sys/wait.h>
#include <ps5/kernel.h>
#include <ps5/klog.h>
#include <ps5/mdbg.h>
#include "../include/elfldr.h"
#include "../include/log.h"
#include "../include/pt.h"
#include "../../lib/libmprotect.h" // kernel_mprotect implementation
// extern int kernel_mprotect(int pid, unsigned long addr, unsigned long len, int prot);
#ifndef IPV6_2292PKTOPTIONS
#define IPV6_2292PKTOPTIONS 25
@@ -71,16 +67,6 @@ typedef struct elfldr_ctx {
void* base_mirror;
} elfldr_ctx_t;
/**
* Absolute path to the SceSpZeroConf eboot.
**/
static const char* SceSpZeroConf = "/system/vsh/app/NPXS40112/eboot.bin";
int sceKernelSpawn(int *pid, int dbg, const char *path, char *root, const char* argv[]);
/**
* Parse a R_X86_64_RELATIVE relocatable.
**/
@@ -99,7 +85,7 @@ r_relative(elfldr_ctx_t *ctx, Elf64_Rela* rela) {
* Parse a PT_LOAD program header.
**/
static int
pt_load(elfldr_ctx_t *ctx, Elf64_Phdr *phdr) {
data_load(elfldr_ctx_t *ctx, Elf64_Phdr *phdr) {
void* data = ctx->base_mirror + phdr->p_vaddr;
if(!phdr->p_memsz) {
@@ -116,32 +102,6 @@ pt_load(elfldr_ctx_t *ctx, Elf64_Phdr *phdr) {
}
int
elfldr_sanity_check(uint8_t *elf, size_t elf_size) {
Elf64_Ehdr *ehdr = (Elf64_Ehdr*)elf;
Elf64_Phdr *phdr;
if(elf_size < sizeof(Elf64_Ehdr) ||
elf_size < sizeof(Elf64_Phdr) + ehdr->e_phoff ||
elf_size < sizeof(Elf64_Shdr) + ehdr->e_shoff) {
return -1;
}
if(ehdr->e_ident[0] != 0x7f || ehdr->e_ident[1] != 'E' ||
ehdr->e_ident[2] != 'L' || ehdr->e_ident[3] != 'F') {
return -1;
}
phdr = (Elf64_Phdr*)(elf + ehdr->e_phoff);
for(int i=0; i<ehdr->e_phnum; i++) {
if(phdr[i].p_offset + phdr[i].p_filesz > elf_size) {
return -1;
}
}
return 0;
}
/**
* Load an ELF into the address space of a process with the given pid.
@@ -182,20 +142,20 @@ elfldr_load(pid_t pid, uint8_t *elf) {
ctx.base_addr = min_vaddr;
flags |= MAP_FIXED;
} else {
klog_puts("elfldr_load: ELF type not supported");
LOG_PUTS("elfldr_load: ELF type not supported");
return 0;
}
if(!(ctx.base_mirror=malloc(ctx.base_size))) {
LOG_PERROR("malloc");
return 0;
}
// Reserve an address space of sufficient size.
if((ctx.base_addr=pt_mmap(pid, ctx.base_addr, ctx.base_size, prot,
flags, -1, 0)) == -1) {
pt_perror(pid, "pt_mmap");
return 0;
}
if((ctx.base_mirror=mmap(0, ctx.base_size, prot, flags,
-1, 0)) == MAP_FAILED) {
pt_munmap(pid, ctx.base_addr, ctx.base_size);
klog_perror("mmap");
LOG_PT_PERROR(pid, "pt_mmap");
free(ctx.base_mirror);
return 0;
}
@@ -203,7 +163,7 @@ elfldr_load(pid_t pid, uint8_t *elf) {
for(int i=0; i<ehdr->e_phnum && !error; i++) {
switch(phdr[i].p_type) {
case PT_LOAD:
error = pt_load(&ctx, &phdr[i]);
error = data_load(&ctx, &phdr[i]);
break;
}
}
@@ -224,8 +184,8 @@ elfldr_load(pid_t pid, uint8_t *elf) {
}
}
if(mdbg_copyin(ctx.pid, ctx.base_mirror, ctx.base_addr, ctx.base_size)) {
klog_perror("mdbg_copyin");
if(pt_copyin(ctx.pid, ctx.base_mirror, ctx.base_addr, ctx.base_size)) {
LOG_PERROR("pt_copyin");
error = 1;
}
@@ -239,24 +199,25 @@ elfldr_load(pid_t pid, uint8_t *elf) {
if(kernel_mprotect(pid, ctx.base_addr + phdr[i].p_vaddr,
ROUND_PG(phdr[i].p_memsz),
PFLAGS(phdr[i].p_flags))) {
perror("kernel_mprotect");
LOG_PERROR("kernel_mprotect");
}
} else {
if(kernel_mprotect(pid, ctx.base_addr + phdr[i].p_vaddr,
if(pt_mprotect(pid, ctx.base_addr + phdr[i].p_vaddr,
ROUND_PG(phdr[i].p_memsz),
PFLAGS(phdr[i].p_flags))) {
pt_perror(pid, "pt_mprotect");
LOG_PT_PERROR(pid, "pt_mprotect");
error = 1;
}
}
}
if(pt_msync(pid, ctx.base_addr, ctx.base_size, MS_SYNC)) {
pt_perror(pid, "pt_msync");
LOG_PT_PERROR(pid, "pt_msync");
error = 1;
}
munmap(ctx.base_mirror, ctx.base_size);
free(ctx.base_mirror);
if(error) {
pt_munmap(pid, ctx.base_addr, ctx.base_size);
return 0;
@@ -279,48 +240,48 @@ elfldr_payload_args(pid_t pid) {
if((buf=pt_mmap(pid, 0, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)) == -1) {
pt_perror(pid, "pt_mmap");
LOG_PT_PERROR(pid, "pt_mmap");
return 0;
}
if((master_sock=pt_socket(pid, AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
pt_perror(pid, "pt_socket");
LOG_PT_PERROR(pid, "pt_socket");
return 0;
}
mdbg_setint(pid, buf+0x00, 20);
mdbg_setint(pid, buf+0x04, IPPROTO_IPV6);
mdbg_setint(pid, buf+0x08, IPV6_TCLASS);
mdbg_setint(pid, buf+0x0c, 0);
mdbg_setint(pid, buf+0x10, 0);
mdbg_setint(pid, buf+0x14, 0);
pt_setint(pid, buf+0x00, 20);
pt_setint(pid, buf+0x04, IPPROTO_IPV6);
pt_setint(pid, buf+0x08, IPV6_TCLASS);
pt_setint(pid, buf+0x0c, 0);
pt_setint(pid, buf+0x10, 0);
pt_setint(pid, buf+0x14, 0);
if(pt_setsockopt(pid, master_sock, IPPROTO_IPV6, IPV6_2292PKTOPTIONS, buf, 24)) {
pt_perror(pid, "pt_setsockopt");
LOG_PT_PERROR(pid, "pt_setsockopt");
return 0;
}
if((victim_sock=pt_socket(pid, AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
pt_perror(pid, "pt_socket");
LOG_PT_PERROR(pid, "pt_socket");
return 0;
}
mdbg_setint(pid, buf+0x00, 0);
mdbg_setint(pid, buf+0x04, 0);
mdbg_setint(pid, buf+0x08, 0);
mdbg_setint(pid, buf+0x0c, 0);
mdbg_setint(pid, buf+0x10, 0);
pt_setint(pid, buf+0x00, 0);
pt_setint(pid, buf+0x04, 0);
pt_setint(pid, buf+0x08, 0);
pt_setint(pid, buf+0x0c, 0);
pt_setint(pid, buf+0x10, 0);
if(pt_setsockopt(pid, victim_sock, IPPROTO_IPV6, IPV6_PKTINFO, buf, 20)) {
pt_perror(pid, "pt_setsockopt");
LOG_PT_PERROR(pid, "pt_setsockopt");
return 0;
}
if(kernel_overlap_sockets(pid, master_sock, victim_sock)) {
klog_puts("kernel_overlap_sockets failed");
LOG_PUTS("kernel_overlap_sockets failed");
return 0;
}
if(pt_pipe(pid, buf)) {
pt_perror(pid, "pt_pipe");
LOG_PT_PERROR(pid, "pt_pipe");
return 0;
}
pipe0 = pt_getint(pid, buf);
@@ -331,25 +292,19 @@ elfldr_payload_args(pid_t pid) {
intptr_t rwpair = buf + 0x200;
intptr_t kpipe_addr = kernel_get_proc_file(pid, pipe0);
intptr_t payloadout = buf + 0x300;
intptr_t getpid = pt_resolve(pid, "HoLVWNanBBc");
// sys_dynlib_dlsym is invoked at <sceKernelDlsym+4>: e8 xx xx xx xx ; call rel32
intptr_t dlsym = pt_resolve(pid, "LwG8g3niqwA") + 4;
int32_t rel32 = 0;
mdbg_copyout(pid, dlsym+1, &rel32, sizeof(rel32));
dlsym += rel32;
dlsym += 5; // length of the call instruction
mdbg_setlong(pid, args + 0x00, dlsym);
mdbg_setlong(pid, args + 0x08, rwpipe);
mdbg_setlong(pid, args + 0x10, rwpair);
mdbg_setlong(pid, args + 0x18, kpipe_addr);
mdbg_setlong(pid, args + 0x20, KERNEL_ADDRESS_DATA_BASE);
mdbg_setlong(pid, args + 0x28, payloadout);
mdbg_setint(pid, rwpipe + 0, pipe0);
mdbg_setint(pid, rwpipe + 4, pipe1);
mdbg_setint(pid, rwpair + 0, master_sock);
mdbg_setint(pid, rwpair + 4, victim_sock);
mdbg_setint(pid, payloadout, 0);
pt_setlong(pid, args + 0x00, getpid);
pt_setlong(pid, args + 0x08, rwpipe);
pt_setlong(pid, args + 0x10, rwpair);
pt_setlong(pid, args + 0x18, kpipe_addr);
pt_setlong(pid, args + 0x20, KERNEL_ADDRESS_DATA_BASE);
pt_setlong(pid, args + 0x28, payloadout);
pt_setint(pid, rwpipe + 0, pipe0);
pt_setint(pid, rwpipe + 4, pipe1);
pt_setint(pid, rwpair + 0, master_sock);
pt_setint(pid, rwpair + 4, victim_sock);
pt_setint(pid, payloadout, 0);
return args;
}
@@ -358,427 +313,37 @@ elfldr_payload_args(pid_t pid) {
/**
* Prepare registers of a process for execution of an ELF.
**/
int
elfldr_prepare_exec(pid_t pid, uint8_t *elf) {
uint16_t call_rax = 0xd0ff;
uint16_t org_inst;
intptr_t entry;
intptr_t args;
struct reg r;
if(pt_getregs(pid, &r)) {
klog_perror("pt_getregs");
return -1;
}
if(!(entry=elfldr_load(pid, elf))) {
klog_puts("elfldr_load failed");
return -1;
}
if(!(args=elfldr_payload_args(pid))) {
klog_puts("elfldr_payload_args failed");
return -1;
}
// backup next instruction
if(mdbg_copyout(pid, r.r_rip, &org_inst, sizeof(org_inst))) {
perror("mdbg_copyout");
kill(pid, SIGKILL);
pt_detach(pid);
return -1;
}
// replace next instruction with a call to rax
if(mdbg_copyin(pid, &call_rax, r.r_rip, sizeof(call_rax))) {
perror("mdbg_copyin");
kill(pid, SIGKILL);
pt_detach(pid);
return -1;
}
r.r_rax = entry;
r.r_rdi = args;
if(pt_setregs(pid, &r)) {
klog_perror("pt_setregs");
kill(pid, SIGKILL);
pt_detach(pid);
return -1;
}
// call entry pointed at from rax
if(pt_step(pid)) {
klog_perror("pt_step");
kill(pid, SIGKILL);
pt_detach(pid);
return -1;
}
// restore next instruction
if(mdbg_copyin(pid, &org_inst, r.r_rip, sizeof(org_inst))) {
perror("mdbg_copyin");
kill(pid, SIGKILL);
pt_detach(pid);
return -1;
}
return 0;
}
/**
* Escape jail and raise privileges.
**/
int
elfldr_raise_privileges(pid_t pid) {
static const uint8_t caps[16] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
intptr_t vnode;
if(!(vnode=kernel_get_root_vnode())) {
return -1;
}
if(kernel_set_proc_rootdir(pid, vnode)) {
return -1;
}
if(kernel_set_proc_jaildir(pid, 0)) {
return -1;
}
if(kernel_set_ucred_uid(pid, 0)) {
return -1;
}
if(kernel_set_ucred_caps(pid, caps)) {
return -1;
}
return 0;
}
/**
* Execute an ELF inside the process with the given pid.
**/
int elfldr_exec(pid_t pid, int stdio, uint8_t* elf) {
uint8_t caps[16];
intptr_t jaildir;
intptr_t rootdir;
uint64_t authid;
int error = 0;
// // backup privileges
jaildir = kernel_get_proc_jaildir(pid);
if(!(rootdir=kernel_get_proc_rootdir(pid))) {
klog_puts("kernel_get_proc_rootdir failed");
pt_detach(pid);
return -1;
}
if(kernel_get_ucred_caps(pid, caps)) {
klog_puts("kernel_get_ucred_caps failed");
pt_detach(pid);
return -1;
}
if(!(authid=kernel_get_ucred_authid(pid))) {
klog_puts("kernel_get_ucred_authid failed");
pt_detach(pid);
return -1;
}
if(elfldr_raise_privileges(pid)) {
klog_puts("Unable to raise privileges");
pt_detach(pid);
return -1;
}
if(stdio > 0) {
stdio = pt_rdup(pid, getpid(), stdio);
pt_close(pid, STDERR_FILENO);
pt_close(pid, STDOUT_FILENO);
pt_close(pid, STDIN_FILENO);
pt_dup2(pid, stdio, STDIN_FILENO);
pt_dup2(pid, stdio, STDOUT_FILENO);
pt_dup2(pid, stdio, STDERR_FILENO);
pt_close(pid, stdio);
}
if(elfldr_prepare_exec(pid, elf)) {
error = -1;
}
// restore privileges
if(kernel_set_proc_jaildir(pid, jaildir)) {
klog_puts("kernel_set_proc_jaildir failed");
error = -1;
}
if(kernel_set_proc_rootdir(pid, rootdir)) {
klog_puts("kernel_set_proc_rootdir failed");
error = -1;
}
if(kernel_set_ucred_caps(pid, caps)) {
klog_puts("kernel_set_ucred_caps failed");
error = -1;
}
if(kernel_set_ucred_authid(pid, authid)) {
klog_puts("kernel_set_ucred_authid failed");
error = -1;
}
if(pt_detach(pid)) {
klog_perror("pt_detach");
error = -1;
}
return error;
}
int
elfldr_set_stdio(pid_t pid, int stdio) {
int err = 0;
if(stdio >= 0) {
if((stdio=pt_rdup(pid, getpid(), stdio)) < 0) {
pt_perror(pid, "pt_rdup");
err = -1;
}
else if(pt_dup2(pid, stdio, STDOUT_FILENO) < 0) {
pt_perror(pid, "pt_dup2");
err = -1;
}
else if(pt_dup2(pid, stdio, STDERR_FILENO) < 0) {
pt_perror(pid, "pt_dup2");
err = -1;
}
else if (pt_close(pid, stdio) < 0) {
pt_perror(pid, "pt_close");
err = -1;
}
}
return err;
}
int
elfldr_set_cwd(pid_t pid, const char* cwd) {
intptr_t buf;
int err = 0;
if(!cwd) {
cwd = "/";
}
if((buf=pt_mmap(pid, 0, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)) == -1) {
pt_perror(pid, "pt_mmap");
return -1;
}
if(mdbg_copyin(pid, cwd, buf, strlen(cwd)+1)) {
puts("mdbg_copyin() failed");
err = -1;
}
else if (pt_syscall(pid, SYS_chdir, buf) < 0) {
pt_perror(pid, "chdir");
err = -1;
}
pt_msync(pid, buf, PAGE_SIZE, MS_SYNC);
pt_munmap(pid, buf, PAGE_SIZE);
return err;
}
/**
* Set the name of a process.
**/
int
elfldr_set_procname(pid_t pid, const char* name) {
intptr_t buf;
if((buf=pt_mmap(pid, 0, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)) == -1) {
pt_perror(pid, "pt_mmap");
return -1;
}
mdbg_copyin(pid, name, buf, strlen(name)+1);
pt_syscall(pid, SYS_thr_set_name, -1, buf);
pt_msync(pid, buf, PAGE_SIZE, MS_SYNC);
pt_munmap(pid, buf, PAGE_SIZE);
return 0;
}
int
elfldr_set_heap_size(pid_t pid, ssize_t size) {
intptr_t sceLibcHeapSize;
intptr_t sceLibcParam;
intptr_t sceProcParam;
intptr_t Need_sceLibc;
if(!(sceProcParam=pt_sceKernelGetProcParam(pid))) {
pt_perror(pid, "pt_sceKernelGetProcParam");
return -1;
}
if(mdbg_copyout(pid, sceProcParam+56, &sceLibcParam,
sizeof(sceLibcParam))) {
perror("mdbg_copyout");
return -1;
}
if(mdbg_copyout(pid, sceLibcParam+16, &sceLibcHeapSize,
sizeof(sceLibcHeapSize))) {
perror("mdbg_copyout");
return -1;
}
if(mdbg_setlong(pid, sceLibcHeapSize, size)) {
perror("mdbg_setlong");
return -1;
}
if(size != -1) {
return 0;
}
if(mdbg_copyout(pid, sceLibcParam+72, &Need_sceLibc,
sizeof(Need_sceLibc))) {
perror("mdbg_copyout");
return -1;
}
return mdbg_setlong(pid, sceLibcParam+32, Need_sceLibc);
}
/**
* Execute an ELF inside a new process.
**/
pid_t
elfldr_spawn(const char* cwd, int stdio, uint8_t* elf, const char* name) {
uint8_t int3instr = 0xcc;
intptr_t brkpoint;
uint8_t orginstr;
pid_t pid = -1;
const char* argv[] = { (char*)"Spawner", NULL };
if(sceKernelSpawn(&pid, 1, SceSpZeroConf, 0, argv)) {
perror("sceKernelSpawn");
return -1;
}
elfldr_raise_privileges(pid);
// The proc is now in the STOP state, with the instruction pointer pointing
// at the libkernel entry. Let the kernel assign process parameters accessed
// via sceKernelGetProcParam()
if(pt_syscall(pid, 599)) {
puts("sys_dynlib_process_needed_and_relocate failed");
pt_detach(pid);
kill(pid, SIGKILL);
return -1;
}
// Allow libc to allocate arbitrary amount of memory.
elfldr_set_heap_size(pid, -1);
//Insert a breakpoint at the eboot entry.
if(!(brkpoint=kernel_dynlib_entry_addr(pid, 0))) {
puts("kernel_dynlib_entry_addr failed");
pt_detach(pid);
kill(pid, SIGKILL);
return -1;
}
brkpoint += 58;// offset to invocation of main()
if(mdbg_copyout(pid, brkpoint, &orginstr, sizeof(orginstr))) {
perror("mdbg_copyout");
pt_detach(pid);
kill(pid, SIGKILL);
return -1;
}
if(mdbg_copyin(pid, &int3instr, brkpoint, sizeof(int3instr))) {
perror("mdbg_copyin");
pt_detach(pid);
kill(pid, SIGKILL);
return -1;
}
// Continue execution until we hit the breakpoint, then remove it.
if(pt_continue(pid, SIGCONT)) {
perror("pt_continue");
pt_detach(pid);
kill(pid, SIGKILL);
return -1;
}
if(waitpid(pid, 0, 0) == -1) {
perror("waitpid");
pt_detach(pid);
kill(pid, SIGKILL);
return -1;
}
if(mdbg_copyin(pid, &orginstr, brkpoint, sizeof(orginstr))) {
perror("mdbg_copyin");
pt_detach(pid);
kill(pid, SIGKILL);
return -1;
}
elfldr_set_procname(pid, name);
elfldr_set_cwd(pid, "/");
elfldr_set_stdio(pid, stdio);
// Execute the ELF
if(elfldr_exec(pid, stdio, elf)) {
kill(pid, SIGKILL);
return -1;
}
return pid;
}
/**
* Fint the pid of a process with the given name.
**/
pid_t
elfldr_find_pid(const char* name) {
int mib[4] = {1, 14, 8, 0};
pid_t mypid = getpid();
pid_t pid = -1;
size_t buf_size;
uint8_t *buf;
if(sysctl(mib, 4, 0, &buf_size, 0, 0)) {
klog_perror("sysctl");
return -1;
}
if(!(buf=malloc(buf_size))) {
klog_perror("malloc");
return -1;
}
if(sysctl(mib, 4, buf, &buf_size, 0, 0)) {
klog_perror("sysctl");
free(buf);
return -1;
}
for(uint8_t *ptr=buf; ptr<(buf+buf_size);) {
int ki_structsize = *(int*)ptr;
pid_t ki_pid = *(pid_t*)&ptr[72];
char *ki_tdname = (char*)&ptr[447];
ptr += ki_structsize;
if(!strcmp(name, ki_tdname) && ki_pid != mypid) {
pid = ki_pid;
}
}
free(buf);
return pid;
}
// static int
// elfldr_prepare_exec(pid_t pid, uint8_t *elf) {
// intptr_t entry;
// intptr_t args;
// struct reg r;
// if(pt_getregs(pid, &r)) {
// LOG_PERROR("pt_getregs");
// return -1;
// }
// if(!(entry=elfldr_load(pid, elf))) {
// LOG_PUTS("elfldr_load failed");
// return -1;
// }
// if(!(args=elfldr_payload_args(pid))) {
// LOG_PUTS("elfldr_payload_args failed");
// return -1;
// }
// pt_setlong(pid, r.r_rsp-8, r.r_rip);
// r.r_rsp -= 8;
// r.r_rip = entry;
// r.r_rdi = args;
// if(pt_setregs(pid, &r)) {
// LOG_PERROR("pt_setregs");
// pt_detach(pid, SIGKILL);
// return -1;
// }
// return 0;
// }

View File

@@ -1,4 +1,5 @@
#include "../include/injector.h"
#include "ps5/klog.h"
int attached = false;
intptr_t remote_malloc = 0;
@@ -7,9 +8,6 @@ void* remote_pthread_join = NULL;
SCEFunctions sce_functions = {0};
//
// Shellcode used for debugging, not so useful for ELF loading
//
int __attribute__((section(".stager_shellcode$1"))) stager(SCEFunctions* functions)
{
pthread_t thread;
@@ -69,79 +67,82 @@ void init_remote_function_pointers(pid_t pid)
sce_functions.sceKernelDebugOutText = (void*) pt_resolve(pid, nid);
sce_functions.pthread_create_ptr = (void*) remote_pthread_create;
}
int inject_elf(struct proc* proc, void* elf)
{
puts("[+] Elevating injector...[+]\n");
klog_puts("[+] Elevating injector...[+]");
set_ucred_to_debugger();
int status = true;
uint64_t sce_ptr_mem;
uint64_t shellcode_size = get_shellcode_size();
uint8_t* original_code = malloc(shellcode_size);
if (pt_attach(proc->pid) < 0)
{
printf("Error attaching into PID: %d\n", proc->pid);
klog_printf("Error attaching into PID: %d\n", proc->pid);
status = false;
goto exit;
}
printf("[+] Attached to %d! [+]\n", proc->pid);
klog_printf("[+] Attached to %d! [+]\n", proc->pid);
attached = true;
init_remote_function_pointers(proc->pid);
printf("[+] Loading ELF on %d...[+]\n", proc->pid);
klog_printf("[+] Loading ELF on %d...[+]\n", proc->pid);
intptr_t entry = elfldr_load(proc->pid, (uint8_t*) elf);
if (entry <= 0)
{
printf("[-] Failed to load ELF! [-]\n");
klog_printf("[-] Failed to load ELF! [-]\n");
goto detach;
}
intptr_t args = elfldr_payload_args(proc->pid);
printf("[+] ELF entrypoint: %#02lx [+]\n[+] Payload Args: %#02lx [+]\n", entry, args);
klog_printf("[+] ELF entrypoint: %#02lx [+]\n[+] Payload Args: %#02lx [+]\n", entry, args);
//
// Copy shellcode thread parameters
// Copy shellcode thread parameters & boot code
//
module_info_t* mod = get_module_handle(proc->pid, "eboot.bin");
sce_functions.elf_main = (void*) entry;
sce_functions.payload_args = (void*) args;
uint64_t bootstrap = pt_mmap(proc->pid, 0, shellcode_size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (!bootstrap)
{
klog_printf("Unable to allocate bootstrap code, injection aborted!\n");
goto detach;
}
//
// Store original .init code and overwrite with the stager
// Make it executable
//
mdbg_copyout(proc->pid, mod->init, original_code, shellcode_size);
mdbg_copyin(proc->pid, stager, mod->init, shellcode_size);
kernel_mprotect(proc->pid, bootstrap, shellcode_size, PROT_EXEC|PROT_WRITE|PROT_READ);
pt_copyin(proc->pid, stager, bootstrap, shellcode_size);
klog_printf("[+] Bootstrap code allocated at %#02lx [+]\n", bootstrap);
//
// Write the sce functions data
//
sce_ptr_mem = pt_call(proc->pid, remote_malloc, sizeof(SCEFunctions));
mdbg_copyin(proc->pid, &sce_functions, sce_ptr_mem, sizeof(SCEFunctions));
sce_ptr_mem = pt_mmap(proc->pid, 0, sizeof(sce_functions), PROT_READ|PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
pt_copyin(proc->pid, &sce_functions, sce_ptr_mem, sizeof(SCEFunctions));
puts("[+] Triggering entrypoint... [+]\n");
klog_puts("[+] Triggering entrypoint... [+]");
//
// Call until hit a breakpoint
//
pt_call2(proc->pid, mod->init, sce_ptr_mem);
// mdbg_copyin(proc->pid, original_code, mod->init, shellcode_size);
pt_call2(proc->pid, bootstrap, sce_ptr_mem);
pt_detach(proc->pid);
puts("[+] ELF injection finished! [+]");
free(mod);
free(original_code);
detach:
puts("[+] Detached [+]");
pt_detach(proc->pid, 0);
klog_puts("[+] ELF injection finished! [+]");
klog_puts("[+] Detached [+]");
exit:
return status;
@@ -175,7 +176,7 @@ module_info_t* load_remote_library(pid_t pid, const char* library_path, const ch
//
// Now we detach, sleep a little and attach again
//
pt_detach(pid);
pt_detach(pid, 0);
int retries = 0;
int max_retries = 100;

View File

@@ -27,41 +27,29 @@ along with this program; see the file COPYING. If not, see
#include <sys/mman.h>
#include <ps5/kernel.h>
#include <ps5/klog.h>
#include "../include/pt.h"
static int
sys_ptrace(int request, pid_t pid, caddr_t addr, int data) {
uint8_t privcaps[16] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
pid_t mypid = getpid();
uint8_t caps[16];
uint64_t authid;
int ret;
if(!(authid=kernel_get_ucred_authid(mypid))) {
return -1;
}
if(kernel_get_ucred_caps(mypid, caps)) {
return -1;
}
if(kernel_set_ucred_authid(mypid, 0x4800000000010003l)) {
return -1;
}
if(kernel_set_ucred_caps(mypid, privcaps)) {
return -1;
}
ret = (int)syscall(SYS_ptrace, request, pid, addr, data);
if(kernel_set_ucred_authid(mypid, authid)) {
return -1;
}
if(kernel_set_ucred_caps(mypid, caps)) {
return -1;
}
return ret;
}
@@ -71,10 +59,6 @@ intptr_t
pt_resolve(pid_t pid, const char* nid) {
intptr_t addr;
if((addr=kernel_dynlib_resolve(pid, 0x2, nid))) {
return addr;
}
if((addr=kernel_dynlib_resolve(pid, 0x1, nid))) {
return addr;
}
@@ -83,25 +67,23 @@ pt_resolve(pid_t pid, const char* nid) {
}
int
pt_trace_me(void) {
return sys_ptrace(PT_TRACE_ME, 0, 0, 0);
}
int
pt_attach(pid_t pid) {
if(sys_ptrace(PT_ATTACH, pid, 0, 0) == -1) {
return -1;
}
if(waitpid(pid, 0, 0) == -1) {
return -1;
}
return 0;
}
int
pt_detach(pid_t pid) {
if(sys_ptrace(PT_DETACH, pid, 0, 0) == -1) {
pt_detach(pid_t pid, int sig) {
if(sys_ptrace(PT_DETACH, pid, 0, sig) == -1) {
return -1;
}
@@ -139,6 +121,12 @@ pt_getint(pid_t pid, intptr_t addr) {
}
int
pt_setint(pid_t pid, intptr_t addr, int val) {
return sys_ptrace(PT_WRITE_D, pid, (caddr_t)addr, val);
}
int
pt_getregs(pid_t pid, struct reg *r) {
return sys_ptrace(PT_GETREGS, pid, (caddr_t)r, 0);
@@ -151,6 +139,76 @@ pt_setregs(pid_t pid, const struct reg *r) {
}
int
pt_copyin(pid_t pid, const void* buf, intptr_t addr, size_t len) {
struct ptrace_io_desc iod = {
.piod_op = PIOD_WRITE_D,
.piod_offs = (void*)addr,
.piod_addr = (void*)buf,
.piod_len = len};
return sys_ptrace(PT_IO, pid, (caddr_t)&iod, 0);
}
int
pt_setchar(pid_t pid, intptr_t addr, char val) {
return pt_copyin(pid, &val, addr, sizeof(val));
}
int
pt_setshort(pid_t pid, intptr_t addr, short val) {
return pt_copyin(pid, &val, addr, sizeof(val));
}
int
pt_setlong(pid_t pid, intptr_t addr, long val) {
return pt_copyin(pid, &val, addr, sizeof(val));
}
int
pt_copyout(pid_t pid, intptr_t addr, void* buf, size_t len) {
struct ptrace_io_desc iod = {
.piod_op = PIOD_READ_D,
.piod_offs = (void*)addr,
.piod_addr = buf,
.piod_len = len};
return sys_ptrace(PT_IO, pid, (caddr_t)&iod, 0);
}
char
pt_getchar(pid_t pid, intptr_t addr) {
char val = 0;
pt_copyout(pid, addr, &val, sizeof(val));
return val;
}
short
pt_getshort(pid_t pid, intptr_t addr) {
short val = 0;
pt_copyout(pid, addr, &val, sizeof(val));
return val;
}
long
pt_getlong(pid_t pid, intptr_t addr) {
long val = 0;
pt_copyout(pid, addr, &val, sizeof(val));
return val;
}
long
pt_call(pid_t pid, intptr_t addr, ...) {
struct reg jmp_reg;
@@ -186,7 +244,7 @@ pt_call(pid_t pid, intptr_t addr, ...) {
return -1;
}
}
// restore registers
if(pt_setregs(pid, &bak_reg)) {
return -1;
@@ -231,6 +289,7 @@ pt_call2(pid_t pid, intptr_t addr, ...)
return jmp_reg.r_rax;
}
long
pt_syscall(pid_t pid, int sysno, ...) {
intptr_t addr = pt_resolve(pid, "HoLVWNanBBc");
@@ -284,18 +343,6 @@ pt_syscall(pid_t pid, int sysno, ...) {
}
int
pt_jitshm_create(pid_t pid, intptr_t name, size_t size, int flags) {
return (int)pt_syscall(pid, 0x215, name, size, flags);
}
int
pt_jitshm_alias(pid_t pid, int fd, int flags) {
return (int)pt_syscall(pid, 0x216, fd, flags);
}
intptr_t
pt_mmap(pid_t pid, intptr_t addr, size_t len, int prot, int flags,
int fd, off_t off) {
@@ -334,8 +381,15 @@ pt_setsockopt(pid_t pid, int fd, int level, int optname, intptr_t optval,
optlen, 0);
}
int
pt_bind(pid_t pid, int sockfd, intptr_t addr, socklen_t addrlen) {
pt_close(pid_t pid, int fd) {
return (int)pt_syscall(pid, SYS_close, fd);
}
int
pt_bind(pid_t pid, int sockfd, intptr_t addr, uint32_t addrlen) {
return (int)pt_syscall(pid, SYS_bind, sockfd, addr, addrlen);
}
@@ -346,12 +400,6 @@ pt_recvmsg(pid_t pid, int fd, intptr_t msg, int flags) {
}
int
pt_close(pid_t pid, int fd) {
return (int)pt_syscall(pid, SYS_close, fd);
}
int
pt_dup2(pid_t pid, int oldfd, int newfd) {
return (int)pt_syscall(pid, SYS_dup2, oldfd, newfd);
@@ -371,17 +419,11 @@ pt_pipe(pid_t pid, intptr_t pipefd) {
}
void
pt_perror(pid_t pid, const char *s) {
int
pt_errno(pid_t pid) {
intptr_t faddr = pt_resolve(pid, "9BcDykPmo1I");
intptr_t addr = pt_call(pid, faddr);
int err = pt_getint(pid, addr);
char buf[255];
strcpy(buf, s);
strcat(buf, ": ");
strcat(buf, strerror(err));
puts(buf);
return pt_getint(pid, addr);
}
@@ -390,11 +432,4 @@ pt_sceKernelGetProcParam(pid_t pid) {
intptr_t faddr = pt_resolve(pid, "959qrazPIrg");
return pt_call(pid, faddr);
}
intptr_t
pt_getargv(pid_t pid) {
intptr_t faddr = pt_resolve(pid, "FJmglmTMdr4");
return pt_call(pid, faddr);
}
}

View File

@@ -1,4 +1,4 @@
#pragma once
int decrypt_self_no_bypass(const char* dest);
int decrypt_all(const char* src_game, const char* dst_game);
int decrypt_self_by_path(const char* input_file_path, const char* output_file_path, int* num_success, int* num_failed);

View File

@@ -0,0 +1,20 @@
#include <sys/types.h>
#include <sys/elf64.h>
// errors only
#define SELF_PAGER_DO_LOGGING 1
// these return the same values as mmap, but errno may be ENOSYS if the current firmware is not supported
void *mmap_self(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
void *map_self_segment(int fd, Elf64_Phdr *phdr, int segment_index);
// these are the return values for decrypt_self
#define DECRYPT_ERROR_IO -2
#define DECRYPT_ERROR_INTERNAL -3
#define DECRYPT_ERROR_UNSUPPORTED_FW -4
#define DECRYPT_ERROR_INPUT_NOT_SELF -5
// this happens if you try to decrypt an fself or a self with unavailable keys
#define DECRYPT_ERROR_FAILED_TO_DECRYPT_SEGMENT_DATA -6
// on success returns a pointer to the decrypted elf in out_data, you must free this with munmap
int decrypt_self(int input_file_fd, char **out_data, uint64_t *out_size);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,331 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <sys/mman.h>
#include <sys/elf64.h>
#include <sys/stat.h>
#include <ps5/kernel.h>
#include "selfpager.h"
#define SELF_ORBIS_MAGIC 0x1D3D154F
#define SELF_PROSPERO_MAGIC 0xEEF51454
#define PAGE_SIZE 0x4000
#define SUPERPAGE_SIZE 0x200000
#define PT_SCE_DYNLIBDATA 0x61000000
#define PT_SCE_RELRO 0x61000010
#define PT_SCE_COMMENT 0x6FFFFF00
#define PT_SCE_VERSION 0x6FFFFF01
#ifdef SELF_PAGER_DO_LOGGING
#define LOG_ERROR(...) \
do { \
fprintf(stderr, __VA_ARGS__); \
} while (0)
#else
#define LOG_ERROR(...)
#endif
// https://github.com/Cryptogenic/PS5-SELF-Decrypter/blob/def326f36c1f1b461030222daa9ea6124d4ce610/include/self.h#L21
struct sce_self_header {
uint32_t magic; // 0x00
uint8_t version; // 0x04
uint8_t mode; // 0x05
uint8_t endian; // 0x06
uint8_t attributes; // 0x07
uint32_t key_type; // 0x08
uint16_t header_size; // 0x0C
uint16_t metadata_size; // 0x0E
uint64_t file_size; // 0x10
uint16_t segment_count; // 0x18
uint16_t flags; // 0x1A
char pad_2[0x4]; // 0x1C
}; // Size: 0x20
struct sce_self_segment_header {
uint64_t flags; // 0x00
uint64_t offset; // 0x08
uint64_t compressed_size; // 0x10
uint64_t uncompressed_size; // 0x18
}; // Size: 0x20
static uint16_t fwver = 0;
static intptr_t pagertab_addr = 0;
static intptr_t vnodepagerops_addr = 0;
static intptr_t selfpagerops_addr = 0;
static const int pagertab_vnodepagerops_index = 2;
static const int pagertab_selfpagerops_index = 7;
static int init() {
if (pagertab_addr != 0) {
return 0;
}
fwver = kernel_get_fw_version() >> 16;
switch (fwver) {
case 0x100:
case 0x101:
case 0x102:
case 0x105:
case 0x110:
case 0x111:
case 0x112:
pagertab_addr = KERNEL_ADDRESS_DATA_BASE + 0xC27C40;
break;
case 0x113:
case 0x114:
pagertab_addr = KERNEL_ADDRESS_DATA_BASE + 0xC27CA0;
break;
case 0x200:
pagertab_addr = KERNEL_ADDRESS_DATA_BASE + 0xC4EF60;
break;
case 0x220:
case 0x225:
case 0x226:
pagertab_addr = KERNEL_ADDRESS_DATA_BASE + 0xC4EFA0;
break;
case 0x230:
case 0x250:
case 0x270:
pagertab_addr = KERNEL_ADDRESS_DATA_BASE + 0xC4F120;
break;
case 0x300:
case 0x310:
case 0x320:
case 0x321:
pagertab_addr = KERNEL_ADDRESS_DATA_BASE + 0xCAF8C0;
break;
case 0x400:
case 0x402:
case 0x403:
case 0x450:
case 0x451:
pagertab_addr = KERNEL_ADDRESS_DATA_BASE + 0xD20840;
break;
case 0x500:
case 0x502:
case 0x510:
case 0x550:
pagertab_addr = KERNEL_ADDRESS_DATA_BASE + 0xE0FEF0;
break;
case 0x600:
case 0x602:
case 0x650:
pagertab_addr = KERNEL_ADDRESS_DATA_BASE + 0xE30410;
break;
case 0x700:
case 0x701:
pagertab_addr = KERNEL_ADDRESS_DATA_BASE + 0xE310C0;
break;
case 0x720:
case 0x740:
case 0x760:
case 0x761:
pagertab_addr = KERNEL_ADDRESS_DATA_BASE + 0xE41180;
break;
case 0x800:
case 0x820:
case 0x840:
case 0x860:
pagertab_addr = KERNEL_ADDRESS_DATA_BASE + 0xE31250;
break;
case 0x900:
case 0x905:
case 0x920:
case 0x940:
case 0x960:
pagertab_addr = KERNEL_ADDRESS_DATA_BASE + 0xDE0420;
break;
case 0x1000:
case 0x1001:
pagertab_addr = KERNEL_ADDRESS_DATA_BASE + 0xDE04F0;
break;
default:
return ENOSYS;
}
vnodepagerops_addr = kernel_getlong(pagertab_addr + pagertab_vnodepagerops_index * 8);
selfpagerops_addr = kernel_getlong(pagertab_addr + pagertab_selfpagerops_index * 8);
return 0;
}
void *mmap_self(void *addr, size_t len, int prot, int flags, int fd, off_t offset) {
int init_res = init();
if (init_res != 0) {
errno = init_res;
return MAP_FAILED;
}
// make vnode pagerops point to selfpagerops
kernel_setlong(pagertab_addr + (pagertab_vnodepagerops_index * 8), selfpagerops_addr);
void *res = mmap(addr, len, prot, flags, fd, offset);
// restore vnode pagerops
kernel_setlong(pagertab_addr + (pagertab_vnodepagerops_index * 8), vnodepagerops_addr);
return res;
}
void *map_self_segment(int fd, Elf64_Phdr *phdr, int segment_index) {
off_t offset = ((uint64_t)segment_index) << 32;
if (fwver >= 0x900) {
// for example, for this segment:
// Index Type VirtAddr FileSize MemSize Align
// 8 PT_LOAD 0xedf7e10 0xce8b98 0xce8b98 0x4000
// the kernel expects 0x1f4000 in the lower 32 bits, by providing 0 it tells us in the klogs:
// self_pager.c(122) self_pager_seg_decode_pindex: off=0, diff=0x1f4000
uint64_t aligned_vaddr = phdr->p_vaddr & ~(phdr->p_align - 1);
offset |= aligned_vaddr & (SUPERPAGE_SIZE - 1);
}
return mmap_self(NULL, phdr->p_filesz, PROT_READ, MAP_PRIVATE | MAP_ALIGNED(phdr->p_align), fd, offset);
}
#include <ps5/klog.h>
int decrypt_self(int input_file_fd, char **out_data, uint64_t *out_size) {
klog_printf("line %d: decrypt_self called\n", __LINE__);
if (!out_data || !out_size) {
return DECRYPT_ERROR_INTERNAL;
}
*out_data = NULL;
*out_size = 0;
klog_printf("line %d: decrypt_self called\n", __LINE__);
struct sce_self_header self_header;
ssize_t pread_res = pread(input_file_fd, &self_header, sizeof(self_header), 0);
klog_printf("line %d: decrypt_self called\n", __LINE__);
if (pread_res == -1) {
LOG_ERROR("Failed to read self header | errno: %d (%s)\n", errno, strerror(errno));
return DECRYPT_ERROR_IO;
} else if (pread_res != sizeof(self_header)) {
// https://man.freebsd.org/cgi/man.cgi?query=pread&apropos=0&sektion=2&manpath=FreeBSD+11.4-RELEASE&arch=default&format=html
// The system guarantees to read the number of bytes requested if the descriptor
// references a normal file that has that many bytes left before the end-of-file
// the file is smaller than 0x20 bytes, so not a self
return DECRYPT_ERROR_INPUT_NOT_SELF;
}
klog_printf("line %d: decrypt_self called\n", __LINE__);
if (self_header.magic != SELF_ORBIS_MAGIC && self_header.magic != SELF_PROSPERO_MAGIC) {
return DECRYPT_ERROR_INPUT_NOT_SELF;
}
klog_printf("line %d: decrypt_self called\n", __LINE__);
Elf64_Ehdr elf_header;
int self_elf_header_offset = sizeof(struct sce_self_header) + (sizeof(struct sce_self_segment_header) * self_header.segment_count);
if (pread(input_file_fd, &elf_header, sizeof(elf_header), self_elf_header_offset) != sizeof(elf_header)) {
LOG_ERROR("Failed to read ELF header\n");
return DECRYPT_ERROR_IO;
}
klog_printf("line %d: decrypt_self called\n", __LINE__);
if (elf_header.e_ident[EI_MAG0] != ELFMAG0 || elf_header.e_ident[EI_MAG1] != ELFMAG1 ||
elf_header.e_ident[EI_MAG2] != ELFMAG2 || elf_header.e_ident[EI_MAG3] != ELFMAG3) {
LOG_ERROR("Failed to find ELF header offset\n");
return DECRYPT_ERROR_INTERNAL;
}
klog_printf("line %d: decrypt_self called\n", __LINE__);
Elf64_Phdr phdrs[elf_header.e_phnum];
int phdrs_size = elf_header.e_phnum * sizeof(Elf64_Phdr);
int self_elf_phdrs_offset = self_elf_header_offset + sizeof(elf_header);
if (pread(input_file_fd, phdrs, phdrs_size, self_elf_phdrs_offset) != phdrs_size) {
LOG_ERROR("Failed to read program headers\n");
return DECRYPT_ERROR_IO;
}
klog_printf("line %d: decrypt_self called\n", __LINE__);
uint64_t output_file_size = 0;
int version_segment_index = -1;
for (int i = 0; i < elf_header.e_phnum; i++) {
Elf64_Phdr *phdr = &phdrs[i];
if (phdr->p_offset + phdr->p_filesz > output_file_size) {
output_file_size = phdr->p_offset + phdr->p_filesz;
}
if (phdr->p_type == PT_SCE_VERSION) {
version_segment_index = i;
}
}
klog_printf("line %d: decrypt_self called\n", __LINE__);
if (output_file_size == 0) {
LOG_ERROR("Output file size is zero\n");
return DECRYPT_ERROR_INTERNAL;
}
klog_printf("line %d: decrypt_self called\n", __LINE__);
void *out_buf = mmap(NULL, output_file_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (out_buf == MAP_FAILED) {
LOG_ERROR("Failed to mmap output buffer | errno: %d (%s)\n", errno, strerror(errno));
return DECRYPT_ERROR_INTERNAL;
}
klog_printf("line %d: decrypt_self called\n", __LINE__);
for (int i = 0; i < elf_header.e_phnum; i++) {
Elf64_Phdr *phdr = &phdrs[i];
if ((phdr->p_type != PT_LOAD && phdr->p_type != PT_SCE_DYNLIBDATA && phdr->p_type != PT_SCE_RELRO && phdr->p_type != PT_SCE_COMMENT) || phdr->p_filesz == 0) {
continue;
}
void *mapped_segment = map_self_segment(input_file_fd, phdr, i);
if (mapped_segment == MAP_FAILED) {
if (errno == ENOSYS) {
LOG_ERROR("Unsupported firmware version\n");
munmap(out_buf, output_file_size);
return DECRYPT_ERROR_UNSUPPORTED_FW;
}
LOG_ERROR("Failed to mmap_self segment %d | errno: %d (%s)\n", i, errno, strerror(errno));
munmap(out_buf, output_file_size);
return DECRYPT_ERROR_INTERNAL;
}
if (mlock(mapped_segment, phdr->p_filesz)) {
LOG_ERROR("Failed to decrypt segment data | segment %d\n", i);
munmap(mapped_segment, phdr->p_filesz);
munmap(out_buf, output_file_size);
return DECRYPT_ERROR_FAILED_TO_DECRYPT_SEGMENT_DATA;
}
memcpy((uint8_t *)out_buf + phdr->p_offset, mapped_segment, phdr->p_filesz);
munmap(mapped_segment, phdr->p_filesz);
}
klog_printf("line %d: decrypt_self called\n", __LINE__);
if (version_segment_index != -1) {
Elf64_Phdr *phdr = &phdrs[version_segment_index];
struct stat input_file_stat;
if (fstat(input_file_fd, &input_file_stat)) {
LOG_ERROR("Failed to stat input file\n");
munmap(out_buf, output_file_size);
return DECRYPT_ERROR_IO;
} klog_printf("line %d: decrypt_self called\n", __LINE__);
int version_segment_self_offset = input_file_stat.st_size - phdr->p_filesz;
int version_segment_elf_offset = phdr->p_offset;
if (pread(input_file_fd, out_buf + version_segment_elf_offset, phdr->p_filesz, version_segment_self_offset) != (ssize_t)phdr->p_filesz) {
LOG_ERROR("Failed to read version segment from input file\n");
munmap(out_buf, output_file_size);
return DECRYPT_ERROR_IO;
}
klog_printf("line %d: decrypt_self called\n", __LINE__);
}
klog_printf("line %d: decrypt_self called\n", __LINE__);
// copy elf header
memcpy(out_buf, &elf_header, sizeof(elf_header));
memcpy(out_buf + sizeof(elf_header), phdrs, phdrs_size);
*out_data = out_buf;
*out_size = output_file_size;
return 0;
}

View File

@@ -0,0 +1,52 @@
###################################################################################################
# PS5SDK - Example: pipe pirate
# Uses the read/write primitive to read and write some kernel data.
# @authors ChendoChap, Specter, Znullptr
###################################################################################################
cmake_minimum_required (VERSION 3.20)
set(basename "elfldr")
project(${basename} C)
# Language Standard Defaults
set(CMAKE_C_STANDARD 17)
set(CMAKE_C_STANDARD_REQUIRED ON)
# Check for sub-project as part of main build or external build
if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
set(IS_SUBPROJECT TRUE)
else()
set(IS_SUBPROJECT FALSE)
endif()
message("IS_SUBPROJECT: ${IS_SUBPROJECT}")
set(D_CWD "${PROJECT_SOURCE_DIR}")
# Headers
include_directories (SYSTEM "${PS5_PAYLOAD_SDK}")
include_directories (SYSTEM "${PS5_PAYLOAD_SDK}/include")
set(D_SRC ${D_CWD}/src)
file(GLOB SrcFiles ${D_SRC}/*.c ${D_SRC}../include/*.h)
add_library(${PROJECT_NAME} STATIC ${SrcFiles})
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "${PROJECT_NAME}")
# Finalize main target sources
target_compile_options(${PROJECT_NAME} PUBLIC
$<$<COMPILE_LANGUAGE:C>:${C_DEFS} ${C_FLAGS}>
)
message("========== build: ${PROJECT_NAME} ==========")
set(CMAKE_C_FLAGS "--target=x86_64-sie-ps5 -march=znver2 -DPPR -DPS5 -DPS5_FW_VERSION=${V_FW} ")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_POSIX_SOURCE -D_POSIX_C_SOURCE=200112 -D__BSD_VISIBLE=1 -D__XSI_VISIBLE=500")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-builtin -nostdlib -Wall") # -nostartfiles
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -gfull -O3 -march=znver2 -Wall -Werror")
target_include_directories(${PROJECT_NAME} PRIVATE "${D_CWD}/include")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

View File

@@ -0,0 +1,30 @@
/* Copyright (C) 2024 John Törnblom
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/>. */
#pragma once
#include <unistd.h>
pid_t elfldr_find_pid(const char* name);
pid_t
elfldr_spawn(const char* cwd, int stdio, uint8_t* elf, const char* name);
int elfldr_exec(pid_t pid, int stdio, uint8_t* elf);
int elfldr_read(int fd, uint8_t** elf, size_t* elf_size);
int elfldr_sanity_check(uint8_t *elf, size_t elf_size);
int elfldr_raise_privileges(pid_t pid);

View File

@@ -0,0 +1,49 @@
/* Copyright (C) 2024 John Törnblom
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/>. */
#pragma once
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <ps5/klog.h>
#include "pt.h"
/**
* Log to stdout and klog
**/
#define LOG_PUTS(s) { \
puts(s); \
klog_puts(s); \
}
#define LOG_PRINTF(s, ...) { \
printf(s, __VA_ARGS__); \
klog_printf(s, __VA_ARGS__); \
}
#define LOG_PERROR(s) { \
printf("%s:%d:%s: %s\n", __FILE__, __LINE__, s, strerror(errno)); \
klog_printf("%s:%d:%s: %s\n", __FILE__, __LINE__, s, strerror(errno)); \
}
#define LOG_PT_PERROR(pid, s) { \
printf("%s:%d:%s: %s\n", __FILE__, __LINE__, s, strerror(pt_errno(pid))); \
klog_printf("%s:%d:%s: %s\n", __FILE__, __LINE__, s, strerror(pt_errno(pid))); \
}

View File

@@ -0,0 +1,67 @@
/* Copyright (C) 2024 John Törnblom
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/>. */
#pragma once
#include <stdint.h>
#include <sys/types.h>
#include <machine/reg.h>
int pt_attach(pid_t pid);
int pt_detach(pid_t pid, int sig);
int pt_step(pid_t pid);
int pt_continue(pid_t pid, int sig);
int pt_getregs(pid_t pid, struct reg *r);
int pt_setregs(pid_t pid, const struct reg *r);
int pt_copyin(pid_t pid, const void* buf, intptr_t addr, size_t len);
int pt_copyout(pid_t pid, intptr_t addr, void* buf, size_t len);
int pt_setchar(pid_t pid, intptr_t addr, char val);
int pt_setshort(pid_t pid, intptr_t addr, short val);
int pt_setint(pid_t pid, intptr_t addr, int val);
int pt_setlong(pid_t pid, intptr_t addr, long val);
char pt_getchar(pid_t pid, intptr_t addr);
short pt_getshort(pid_t pid, intptr_t addr);
int pt_getint(pid_t pid, intptr_t addr);
long pt_getlong(pid_t pid, intptr_t addr);
long pt_syscall(pid_t pid, int sysno, ...);
intptr_t pt_resolve(pid_t pid, const char* nid);
intptr_t pt_mmap(pid_t pid, intptr_t addr, size_t len, int prot, int flags,
int fd, off_t off);
int pt_msync(pid_t, intptr_t addr, size_t len, int flags);
int pt_munmap(pid_t pid, intptr_t addr, size_t len);
int pt_mprotect(pid_t pid, intptr_t addr, size_t len, int prot);
int pt_socket(pid_t pid, int domain, int type, int protocol);
int pt_setsockopt(pid_t pid, int fd, int level, int optname, intptr_t optval,
uint32_t optlen);
int pt_bind(pid_t pid, int sockfd, intptr_t addr, uint32_t addrlen) ;
ssize_t pt_recvmsg(pid_t pid, int fd, intptr_t msg, int flags);
int pt_close(pid_t pid, int fd);
int pt_dup2(pid_t pid, int oldfd, int newfd);
int pt_rdup(pid_t pid, pid_t other_pid, int fd);
int pt_pipe(pid_t pid, intptr_t pipefd);
int pt_errno(pid_t pid);
intptr_t pt_sceKernelGetProcParam(pid_t pid);

View File

@@ -0,0 +1,132 @@
/* this is only here so cmake can configure properly */
PHDRS {
/*
* PF_X = 0x1
* PF_W = 0x2
* PF_R = 0x4
*/
phdr_text PT_LOAD FLAGS(0x5);
phdr_data PT_LOAD FLAGS(0x6);
phdr_rodata PT_LOAD FLAGS(0x4);
phdr_relro PT_LOAD FLAGS(0x4);
phdr_eh_frame PT_GNU_EH_FRAME FLAGS(0x4);
phdr_dynamic PT_DYNAMIC FLAGS(0x0);
}
SECTIONS {
PROVIDE (__payload_start = .);
.text : {
PROVIDE_HIDDEN(__text_start = .);
*(.text .text.*);
PROVIDE_HIDDEN(__text_stop = .);
} : phdr_text
.init : {
*(.init)
} : phdr_text
.fini : {
*(.fini)
} : phdr_text
.plt : {
*(.plt)
} : phdr_text
. = ALIGN(0x4000); /* move to a new page in memory */
.data : {
*(.data);
*(.data.*);
} : phdr_data
.bss (NOLOAD) : {
PROVIDE_HIDDEN (__bss_start = .);
*(.bss .bss.*);
*(COMMON)
PROVIDE_HIDDEN (__bss_end = .);
} : phdr_data
. = ALIGN(0x4000); /* move to a new page in memory */
.rodata : {
*(.rodata .rodata.*);
} : phdr_rodata
.gcc_except_table : {
*(.gcc_except_table*)
} : phdr_rodata
.hash : {
*(.hash);
} : phdr_rodata
. = ALIGN(0x4000); /* move to a new page in memory */
.eh_frame_hdr : ALIGN(0x4000) {
*(.eh_frame_hdr)
} : phdr_eh_frame
.eh_frame : ALIGN(0x10) {
*(.eh_frame)
} : phdr_eh_frame
. = ALIGN(0x4000); /* move to a new page in memory */
.data.rel.ro : {
*(.data.rel.ro .data.rel.ro.*);
} : phdr_relro
.preinit_array : {
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} : phdr_relro
.init_array : {
PROVIDE_HIDDEN(__init_array_start = .);
KEEP (*(.init_array .init_array.*));
PROVIDE_HIDDEN(__init_array_stop = .);
} : phdr_relro
.fini_array : {
PROVIDE_HIDDEN(__fini_array_start = .);
KEEP (*(.fini_array .fini_array.*));
PROVIDE_HIDDEN(__fini_array_stop = .);
} : phdr_relro
.got : {
*(.got);
} : phdr_relro
.got.plt : {
*(.got.plt);
} : phdr_relro
.rela.dyn : {
*(.rela.dyn) *(.rela);
} : phdr_relro
.rela.plt : {
*(rela.plt);
} : phdr_relro
PROVIDE (__payload_end = .);
/* this needs to be forced aligned to 0x4000 */
.dynamic : ALIGN(0x4000) {
PROVIDE_HIDDEN (_DYNAMIC = .);
*(.dynamic);
} : phdr_dynamic
.dynsym : {
*(.dynsym);
} : phdr_dynamic
.dynstr : {
*(.dynstr);
} : phdr_dynamic
}

View File

@@ -0,0 +1,839 @@
/* Copyright (C) 2024 John Törnblom
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 <elf.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/sysctl.h>
#include <sys/un.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <ps5/kernel.h>
#include "elfldr.h"
#include "log.h"
#include "pt.h"
#ifndef IPV6_2292PKTOPTIONS
#define IPV6_2292PKTOPTIONS 25
#endif
/**
* Convenient macros.
**/
#define ROUND_PG(x) (((x) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1))
#define TRUNC_PG(x) ((x) & ~(PAGE_SIZE - 1))
#define PFLAGS(x) ((((x) & PF_R) ? PROT_READ : 0) | \
(((x) & PF_W) ? PROT_WRITE : 0) | \
(((x) & PF_X) ? PROT_EXEC : 0))
/**
* Context structure for the ELF loader.
**/
typedef struct elfldr_ctx {
uint8_t* elf;
pid_t pid;
intptr_t base_addr;
size_t base_size;
void* base_mirror;
} elfldr_ctx_t;
/**
* Absolute path to the SceSpZeroConf eboot.
**/
static const char* SceSpZeroConf = "/system/vsh/app/NPXS40112/eboot.bin";
/**
* Parse a R_X86_64_RELATIVE relocatable.
**/
static int
r_relative(elfldr_ctx_t *ctx, Elf64_Rela* rela) {
intptr_t* loc = ctx->base_mirror + rela->r_offset;
intptr_t val = ctx->base_addr + rela->r_addend;
*loc = val;
return 0;
}
/**
* Parse a PT_LOAD program header.
**/
static int
data_load(elfldr_ctx_t *ctx, Elf64_Phdr *phdr) {
void* data = ctx->base_mirror + phdr->p_vaddr;
if(!phdr->p_memsz) {
return 0;
}
if(!phdr->p_filesz) {
return 0;
}
memcpy(data, ctx->elf+phdr->p_offset, phdr->p_filesz);
return 0;
}
int
elfldr_sanity_check(uint8_t *elf, size_t elf_size) {
Elf64_Ehdr *ehdr = (Elf64_Ehdr*)elf;
Elf64_Phdr *phdr;
if(elf_size < sizeof(Elf64_Ehdr) ||
elf_size < sizeof(Elf64_Phdr) + ehdr->e_phoff ||
elf_size < sizeof(Elf64_Shdr) + ehdr->e_shoff) {
return -1;
}
if(ehdr->e_ident[0] != 0x7f || ehdr->e_ident[1] != 'E' ||
ehdr->e_ident[2] != 'L' || ehdr->e_ident[3] != 'F') {
return -1;
}
phdr = (Elf64_Phdr*)(elf + ehdr->e_phoff);
for(int i=0; i<ehdr->e_phnum; i++) {
if(phdr[i].p_offset + phdr[i].p_filesz > elf_size) {
return -1;
}
}
return 0;
}
/**
* Load an ELF into the address space of a process with the given pid.
**/
static intptr_t
elfldr_load(pid_t pid, uint8_t *elf) {
Elf64_Ehdr *ehdr = (Elf64_Ehdr*)elf;
Elf64_Phdr *phdr = (Elf64_Phdr*)(elf + ehdr->e_phoff);
Elf64_Shdr *shdr = (Elf64_Shdr*)(elf + ehdr->e_shoff);
elfldr_ctx_t ctx = {.elf = elf, .pid=pid};
size_t min_vaddr = -1;
size_t max_vaddr = 0;
int error = 0;
// Compute size of virtual memory region.
for(int i=0; i<ehdr->e_phnum; i++) {
if(phdr[i].p_vaddr < min_vaddr) {
min_vaddr = phdr[i].p_vaddr;
}
if(max_vaddr < phdr[i].p_vaddr + phdr[i].p_memsz) {
max_vaddr = phdr[i].p_vaddr + phdr[i].p_memsz;
}
}
min_vaddr = TRUNC_PG(min_vaddr);
max_vaddr = ROUND_PG(max_vaddr);
ctx.base_size = max_vaddr - min_vaddr;
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
int prot = PROT_READ | PROT_WRITE;
if(ehdr->e_type == ET_DYN) {
ctx.base_addr = 0;
} else if(ehdr->e_type == ET_EXEC) {
ctx.base_addr = min_vaddr;
flags |= MAP_FIXED;
} else {
LOG_PUTS("elfldr_load: ELF type not supported");
return 0;
}
if(!(ctx.base_mirror=malloc(ctx.base_size))) {
LOG_PERROR("malloc");
return 0;
}
// Reserve an address space of sufficient size.
if((ctx.base_addr=pt_mmap(pid, ctx.base_addr, ctx.base_size, prot,
flags, -1, 0)) == -1) {
LOG_PT_PERROR(pid, "pt_mmap");
free(ctx.base_mirror);
return 0;
}
// Parse program headers.
for(int i=0; i<ehdr->e_phnum && !error; i++) {
switch(phdr[i].p_type) {
case PT_LOAD:
error = data_load(&ctx, &phdr[i]);
break;
}
}
// Apply relocations.
for(int i=0; i<ehdr->e_shnum && !error; i++) {
if(shdr[i].sh_type != SHT_RELA) {
continue;
}
Elf64_Rela* rela = (Elf64_Rela*)(elf + shdr[i].sh_offset);
for(int j=0; j<shdr[i].sh_size/sizeof(Elf64_Rela); j++) {
switch(rela[j].r_info & 0xffffffffl) {
case R_X86_64_RELATIVE:
error = r_relative(&ctx, &rela[j]);
break;
}
}
}
if(pt_copyin(ctx.pid, ctx.base_mirror, ctx.base_addr, ctx.base_size)) {
LOG_PERROR("pt_copyin");
error = 1;
}
// Set protection bits on mapped segments.
for(int i=0; i<ehdr->e_phnum && !error; i++) {
if(phdr[i].p_type != PT_LOAD || phdr[i].p_memsz == 0) {
continue;
}
if(phdr[i].p_flags & PF_X) {
if(kernel_mprotect(pid, ctx.base_addr + phdr[i].p_vaddr,
ROUND_PG(phdr[i].p_memsz),
PFLAGS(phdr[i].p_flags))) {
LOG_PERROR("kernel_mprotect");
}
} else {
if(pt_mprotect(pid, ctx.base_addr + phdr[i].p_vaddr,
ROUND_PG(phdr[i].p_memsz),
PFLAGS(phdr[i].p_flags))) {
LOG_PT_PERROR(pid, "pt_mprotect");
error = 1;
}
}
}
if(pt_msync(pid, ctx.base_addr, ctx.base_size, MS_SYNC)) {
LOG_PT_PERROR(pid, "pt_msync");
error = 1;
}
free(ctx.base_mirror);
if(error) {
pt_munmap(pid, ctx.base_addr, ctx.base_size);
return 0;
}
return ctx.base_addr + ehdr->e_entry;
}
/**
* Create payload args in the address space of the process with the given pid.
**/
static intptr_t
elfldr_payload_args(pid_t pid) {
int victim_sock;
int master_sock;
intptr_t buf;
int pipe0;
int pipe1;
if((buf=pt_mmap(pid, 0, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)) == -1) {
LOG_PT_PERROR(pid, "pt_mmap");
return 0;
}
if((master_sock=pt_socket(pid, AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
LOG_PT_PERROR(pid, "pt_socket");
return 0;
}
pt_setint(pid, buf+0x00, 20);
pt_setint(pid, buf+0x04, IPPROTO_IPV6);
pt_setint(pid, buf+0x08, IPV6_TCLASS);
pt_setint(pid, buf+0x0c, 0);
pt_setint(pid, buf+0x10, 0);
pt_setint(pid, buf+0x14, 0);
if(pt_setsockopt(pid, master_sock, IPPROTO_IPV6, IPV6_2292PKTOPTIONS, buf, 24)) {
LOG_PT_PERROR(pid, "pt_setsockopt");
return 0;
}
if((victim_sock=pt_socket(pid, AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
LOG_PT_PERROR(pid, "pt_socket");
return 0;
}
pt_setint(pid, buf+0x00, 0);
pt_setint(pid, buf+0x04, 0);
pt_setint(pid, buf+0x08, 0);
pt_setint(pid, buf+0x0c, 0);
pt_setint(pid, buf+0x10, 0);
if(pt_setsockopt(pid, victim_sock, IPPROTO_IPV6, IPV6_PKTINFO, buf, 20)) {
LOG_PT_PERROR(pid, "pt_setsockopt");
return 0;
}
if(kernel_overlap_sockets(pid, master_sock, victim_sock)) {
LOG_PUTS("kernel_overlap_sockets failed");
return 0;
}
if(pt_pipe(pid, buf)) {
LOG_PT_PERROR(pid, "pt_pipe");
return 0;
}
pipe0 = pt_getint(pid, buf);
pipe1 = pt_getint(pid, buf+4);
intptr_t args = buf;
intptr_t rwpipe = buf + 0x100;
intptr_t rwpair = buf + 0x200;
intptr_t kpipe_addr = kernel_get_proc_file(pid, pipe0);
intptr_t payloadout = buf + 0x300;
intptr_t getpid = pt_resolve(pid, "HoLVWNanBBc");
pt_setlong(pid, args + 0x00, getpid);
pt_setlong(pid, args + 0x08, rwpipe);
pt_setlong(pid, args + 0x10, rwpair);
pt_setlong(pid, args + 0x18, kpipe_addr);
pt_setlong(pid, args + 0x20, KERNEL_ADDRESS_DATA_BASE);
pt_setlong(pid, args + 0x28, payloadout);
pt_setint(pid, rwpipe + 0, pipe0);
pt_setint(pid, rwpipe + 4, pipe1);
pt_setint(pid, rwpair + 0, master_sock);
pt_setint(pid, rwpair + 4, victim_sock);
pt_setint(pid, payloadout, 0);
return args;
}
/**
* Prepare registers of a process for execution of an ELF.
**/
static int
elfldr_prepare_exec(pid_t pid, uint8_t *elf) {
intptr_t entry;
intptr_t args;
struct reg r;
if(pt_getregs(pid, &r)) {
LOG_PERROR("pt_getregs");
return -1;
}
if(!(entry=elfldr_load(pid, elf))) {
LOG_PUTS("elfldr_load failed");
return -1;
}
if(!(args=elfldr_payload_args(pid))) {
LOG_PUTS("elfldr_payload_args failed");
return -1;
}
r.r_rsp &= ~0xfl;
pt_setlong(pid, r.r_rsp-8, r.r_rip);
r.r_rsp -= 8;
r.r_rip = entry;
r.r_rdi = args;
if(pt_setregs(pid, &r)) {
LOG_PERROR("pt_setregs");
pt_detach(pid, SIGKILL);
return -1;
}
return 0;
}
/**
* Set the name of a process.
**/
static int
elfldr_set_procname(pid_t pid, const char* name) {
intptr_t buf;
if((buf=pt_mmap(pid, 0, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)) == -1) {
LOG_PT_PERROR(pid, "pt_mmap");
return -1;
}
pt_copyin(pid, name, buf, strlen(name)+1);
pt_syscall(pid, SYS_thr_set_name, -1, buf);
pt_msync(pid, buf, PAGE_SIZE, MS_SYNC);
pt_munmap(pid, buf, PAGE_SIZE);
return 0;
}
/**
* Escape jail and raise privileges.
**/
int
elfldr_raise_privileges(pid_t pid) {
static const uint8_t caps[16] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
intptr_t vnode;
if(!(vnode=kernel_get_root_vnode())) {
return -1;
}
if(kernel_set_proc_rootdir(pid, vnode)) {
return -1;
}
if(kernel_set_proc_jaildir(pid, 0)) {
return -1;
}
if(kernel_set_ucred_uid(pid, 0)) {
return -1;
}
if(kernel_set_ucred_caps(pid, caps)) {
return -1;
}
return 0;
}
/**
* Execute an ELF inside the process with the given pid.
**/
int
elfldr_exec(pid_t pid, int stdio, uint8_t* elf) {
uint8_t caps[16];
intptr_t jaildir;
intptr_t rootdir;
uint64_t authid;
int error = 0;
// backup privileges
jaildir = kernel_get_proc_jaildir(pid);
if(!(rootdir=kernel_get_proc_rootdir(pid))) {
LOG_PUTS("kernel_get_proc_rootdir failed");
pt_detach(pid, 0);
return -1;
}
if(kernel_get_ucred_caps(pid, caps)) {
LOG_PUTS("kernel_get_ucred_caps failed");
pt_detach(pid, 0);
return -1;
}
if(!(authid=kernel_get_ucred_authid(pid))) {
LOG_PUTS("kernel_get_ucred_authid failed");
pt_detach(pid, 0);
return -1;
}
if(elfldr_raise_privileges(pid)) {
LOG_PUTS("Unable to raise privileges");
pt_detach(pid, 0);
return -1;
}
if(stdio > 0) {
stdio = pt_rdup(pid, getpid(), stdio);
pt_close(pid, STDERR_FILENO);
pt_close(pid, STDOUT_FILENO);
pt_close(pid, STDIN_FILENO);
pt_dup2(pid, stdio, STDIN_FILENO);
pt_dup2(pid, stdio, STDOUT_FILENO);
pt_dup2(pid, stdio, STDERR_FILENO);
pt_close(pid, stdio);
}
if(elfldr_prepare_exec(pid, elf)) {
error = -1;
}
// restore privileges
if(kernel_set_proc_jaildir(pid, jaildir)) {
LOG_PUTS("kernel_set_proc_jaildir failed");
error = -1;
}
if(kernel_set_proc_rootdir(pid, rootdir)) {
LOG_PUTS("kernel_set_proc_rootdir failed");
error = -1;
}
if(kernel_set_ucred_caps(pid, caps)) {
LOG_PUTS("kernel_set_ucred_caps failed");
error = -1;
}
if(kernel_set_ucred_authid(pid, authid)) {
LOG_PUTS("kernel_set_ucred_authid failed");
error = -1;
}
if(pt_detach(pid, 0)) {
LOG_PERROR("pt_detach");
error = -1;
}
return error;
}
/**
* Set the heap size for libc.
**/
static int
elfldr_set_heap_size(pid_t pid, ssize_t size) {
intptr_t sceLibcHeapSize;
intptr_t sceLibcParam;
intptr_t sceProcParam;
intptr_t Need_sceLibc;
if(!(sceProcParam=pt_sceKernelGetProcParam(pid))) {
LOG_PT_PERROR(pid, "pt_sceKernelGetProcParam");
return -1;
}
if(pt_copyout(pid, sceProcParam+56, &sceLibcParam,
sizeof(sceLibcParam))) {
LOG_PERROR("pt_copyout");
return -1;
}
if(pt_copyout(pid, sceLibcParam+16, &sceLibcHeapSize,
sizeof(sceLibcHeapSize))) {
LOG_PERROR("pt_copyout");
return -1;
}
if(pt_setlong(pid, sceLibcHeapSize, size)) {
LOG_PERROR("pt_setlong");
return -1;
}
if(size != -1) {
return 0;
}
if(pt_copyout(pid, sceLibcParam+72, &Need_sceLibc,
sizeof(Need_sceLibc))) {
LOG_PERROR("pt_copyout");
return -1;
}
return pt_setlong(pid, sceLibcParam+32, Need_sceLibc);
}
static int
sys_budget_set(long budget) {
return __syscall(0x23b, budget);
}
static int
elfldr_rfork_entry(void* progname) {
char* const argv[] = {(char*)progname, 0};
if(sys_budget_set(0)) {
klog_perror("sys_budget_set");
return -1;
}
if(open("/dev/deci_stdin", O_RDONLY) < 0) {
klog_perror("open");
return -1;
}
if(open("/dev/deci_stdout", O_WRONLY) < 0) {
klog_perror("open");
return -1;
}
if(open("/dev/deci_stderr", O_WRONLY) < 0) {
klog_perror("open");
return -1;
}
if(ptrace(PT_TRACE_ME, 0, 0, 0)) {
klog_perror("ptrace");
return -1;
}
execve(SceSpZeroConf, argv, 0);
klog_perror("execve");
return -1;
}
/**
* Execute an ELF inside a new process.
**/
/**
* Fint the pid of a process with the given name.
**/
pid_t
elfldr_find_pid(const char* name) {
int mib[4] = {1, 14, 8, 0};
pid_t mypid = getpid();
pid_t pid = -1;
size_t buf_size;
uint8_t *buf;
if(sysctl(mib, 4, 0, &buf_size, 0, 0)) {
LOG_PERROR("sysctl");
return -1;
}
if(!(buf=malloc(buf_size))) {
LOG_PERROR("malloc");
return -1;
}
if(sysctl(mib, 4, buf, &buf_size, 0, 0)) {
LOG_PERROR("sysctl");
free(buf);
return -1;
}
for(uint8_t *ptr=buf; ptr<(buf+buf_size);) {
int ki_structsize = *(int*)ptr;
pid_t ki_pid = *(pid_t*)&ptr[72];
char *ki_tdname = (char*)&ptr[447];
ptr += ki_structsize;
if(!strcmp(name, ki_tdname) && ki_pid != mypid) {
pid = ki_pid;
}
}
free(buf);
return pid;
}
/**
* Read an ELF from a given socket.
**/
int
elfldr_read(int fd, uint8_t** elf, size_t* elf_size) {
Elf64_Shdr *shdr;
Elf64_Ehdr ehdr;
uint8_t* buf;
uint8_t* bak;
size_t size;
off_t shend;
size_t rem;
if(recv(fd, &ehdr, sizeof(ehdr), MSG_WAITALL) != sizeof(ehdr)) {
return -1;
}
if(ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E' ||
ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F') {
errno = ENOEXEC;
return -1;
}
size = ehdr.e_shoff + ehdr.e_shnum * sizeof(Elf64_Ehdr);
if(!(buf=malloc(size))) {
return -1;
}
memcpy(buf, &ehdr, sizeof(ehdr));
rem = size - sizeof(ehdr);
if(recv(fd, buf + sizeof(ehdr), rem, MSG_WAITALL) != rem) {
free(buf);
return -1;
}
shend = 0;
shdr = (Elf64_Shdr*)(buf + ehdr.e_shoff);
for(int i=0; i<ehdr.e_shnum; i++) {
if(shdr[i].sh_type == SHT_NOBITS) {
continue;
}
size_t end = shdr[i].sh_offset + shdr[i].sh_size;
if(end > shend) {
shend = end;
}
}
// sections appear before section headers
if(shend <= size) {
*elf = buf;
*elf_size = size;
return 0;
}
bak = buf;
if(!(buf=realloc(buf, shend))) {
free(bak);
return -1;
}
rem = shend - size;
if(recv(fd, buf + size, rem, MSG_WAITALL) != rem) {
free(buf);
return -1;
}
*elf = buf;
*elf_size = shend;
return 0;
}
/**
* Execute an ELF inside a new process.
**/
pid_t
elfldr_spawn(const char* cwd, int stdio, uint8_t* elf, const char* name) {
uint8_t int3instr = 0xcc;
struct kevent evt;
intptr_t brkpoint;
uint8_t orginstr;
void *stack;
pid_t pid;
int kq;
if((kq=kqueue()) < 0) {
LOG_PERROR("kqueue");
return -1;
}
if(!(stack=malloc(PAGE_SIZE))) {
LOG_PERROR("malloc");
close(kq);
return -1;
}
if((pid=rfork_thread(RFPROC | RFCFDG | RFMEM, stack+PAGE_SIZE-8,
elfldr_rfork_entry, (void*)name)) < 0) {
LOG_PERROR("rfork_thread");
free(stack);
close(kq);
return -1;
}
EV_SET(&evt, pid, EVFILT_PROC, EV_ADD, NOTE_EXEC, 0, 0);
if(kevent(kq, &evt, 1, &evt, 1, 0) < 0) {
LOG_PERROR("kevent");
free(stack);
close(kq);
return -1;
}
if(waitpid(pid, 0, 0) < 0) {
LOG_PERROR("waitpid");
free(stack);
close(kq);
return -1;
}
free(stack);
close(kq);
// The proc is now in the STOP state, with the instruction pointer pointing
// at the libkernel entry. Let the kernel assign process parameters accessed
// via sceKernelGetProcParam()
if(pt_syscall(pid, 599)) {
LOG_PT_PERROR(pid, "sys_dynlib_process_needed_and_relocate");
pt_detach(pid, SIGKILL);
return -1;
}
// Allow libc to allocate arbitrary amount of memory.
elfldr_set_heap_size(pid, -1);
//Insert a breakpoint at the eboot entry.
if(!(brkpoint=kernel_dynlib_entry_addr(pid, 0))) {
LOG_PUTS("kernel_dynlib_entry_addr failed");
pt_detach(pid, SIGKILL);
return -1;
}
brkpoint += 58;// offset to invocation of main()
if(kernel_mprotect(pid, brkpoint, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC)) {
LOG_PUTS("kernel_mprotect failed");
pt_detach(pid, SIGKILL);
return -1;
}
if(pt_copyout(pid, brkpoint, &orginstr, sizeof(orginstr))) {
LOG_PERROR("pt_copyout");
pt_detach(pid, SIGKILL);
return -1;
}
if(pt_copyin(pid, &int3instr, brkpoint, sizeof(int3instr))) {
LOG_PERROR("pt_copyin");
pt_detach(pid, SIGKILL);
return -1;
}
// Continue execution until we hit the breakpoint, then remove it.
if(pt_continue(pid, SIGCONT)) {
LOG_PERROR("pt_continue");
pt_detach(pid, SIGKILL);
return -1;
}
if(waitpid(pid, 0, 0) == -1) {
LOG_PERROR("waitpid");
pt_detach(pid, SIGKILL);
return -1;
}
if(pt_copyin(pid, &orginstr, brkpoint, sizeof(orginstr))) {
LOG_PERROR("pt_copyin");
pt_detach(pid, SIGKILL);
return -1;
}
// Execute the ELF
elfldr_set_procname(pid, name);
if(elfldr_exec(pid, stdio, elf)) {
kill(pid, SIGKILL);
return -1;
}
return pid;
}

View File

@@ -0,0 +1,399 @@
/* Copyright (C) 2024 John Törnblom
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 <errno.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <ps5/kernel.h>
#include <ps5/klog.h>
#include "pt.h"
static int
sys_ptrace(int request, pid_t pid, caddr_t addr, int data) {
pid_t mypid = getpid();
uint64_t authid;
int ret;
if(!(authid=kernel_get_ucred_authid(mypid))) {
return -1;
}
if(kernel_set_ucred_authid(mypid, 0x4800000000010003l)) {
return -1;
}
ret = (int)syscall(SYS_ptrace, request, pid, addr, data);
if(kernel_set_ucred_authid(mypid, authid)) {
return -1;
}
return ret;
}
intptr_t
pt_resolve(pid_t pid, const char* nid) {
intptr_t addr;
if((addr=kernel_dynlib_resolve(pid, 0x1, nid))) {
return addr;
}
return kernel_dynlib_resolve(pid, 0x2001, nid);
}
int
pt_attach(pid_t pid) {
if(sys_ptrace(PT_ATTACH, pid, 0, 0) == -1) {
return -1;
}
if(waitpid(pid, 0, 0) == -1) {
return -1;
}
return 0;
}
int
pt_detach(pid_t pid, int sig) {
if(sys_ptrace(PT_DETACH, pid, 0, sig) == -1) {
return -1;
}
return 0;
}
int
pt_step(int pid) {
if(sys_ptrace(PT_STEP, pid, (caddr_t)1, 0)) {
return -1;
}
if(waitpid(pid, 0, 0) < 0) {
return -1;
}
return 0;
}
int
pt_continue(pid_t pid, int sig) {
if(sys_ptrace(PT_CONTINUE, pid, (caddr_t)1, sig) == -1) {
return -1;
}
return 0;
}
int
pt_getint(pid_t pid, intptr_t addr) {
return sys_ptrace(PT_READ_D, pid, (caddr_t)addr, 0);
}
int
pt_setint(pid_t pid, intptr_t addr, int val) {
return sys_ptrace(PT_WRITE_D, pid, (caddr_t)addr, val);
}
int
pt_getregs(pid_t pid, struct reg *r) {
return sys_ptrace(PT_GETREGS, pid, (caddr_t)r, 0);
}
int
pt_setregs(pid_t pid, const struct reg *r) {
return sys_ptrace(PT_SETREGS, pid, (caddr_t)r, 0);
}
int
pt_copyin(pid_t pid, const void* buf, intptr_t addr, size_t len) {
struct ptrace_io_desc iod = {
.piod_op = PIOD_WRITE_D,
.piod_offs = (void*)addr,
.piod_addr = (void*)buf,
.piod_len = len};
return sys_ptrace(PT_IO, pid, (caddr_t)&iod, 0);
}
int
pt_setchar(pid_t pid, intptr_t addr, char val) {
return pt_copyin(pid, &val, addr, sizeof(val));
}
int
pt_setshort(pid_t pid, intptr_t addr, short val) {
return pt_copyin(pid, &val, addr, sizeof(val));
}
int
pt_setlong(pid_t pid, intptr_t addr, long val) {
return pt_copyin(pid, &val, addr, sizeof(val));
}
int
pt_copyout(pid_t pid, intptr_t addr, void* buf, size_t len) {
struct ptrace_io_desc iod = {
.piod_op = PIOD_READ_D,
.piod_offs = (void*)addr,
.piod_addr = buf,
.piod_len = len};
return sys_ptrace(PT_IO, pid, (caddr_t)&iod, 0);
}
char
pt_getchar(pid_t pid, intptr_t addr) {
char val = 0;
pt_copyout(pid, addr, &val, sizeof(val));
return val;
}
short
pt_getshort(pid_t pid, intptr_t addr) {
short val = 0;
pt_copyout(pid, addr, &val, sizeof(val));
return val;
}
long
pt_getlong(pid_t pid, intptr_t addr) {
long val = 0;
pt_copyout(pid, addr, &val, sizeof(val));
return val;
}
long
pt_call(pid_t pid, intptr_t addr, ...) {
struct reg jmp_reg;
struct reg bak_reg;
va_list ap;
if(pt_getregs(pid, &bak_reg)) {
return -1;
}
memcpy(&jmp_reg, &bak_reg, sizeof(jmp_reg));
jmp_reg.r_rip = addr;
va_start(ap, addr);
jmp_reg.r_rdi = va_arg(ap, uint64_t);
jmp_reg.r_rsi = va_arg(ap, uint64_t);
jmp_reg.r_rdx = va_arg(ap, uint64_t);
jmp_reg.r_rcx = va_arg(ap, uint64_t);
jmp_reg.r_r8 = va_arg(ap, uint64_t);
jmp_reg.r_r9 = va_arg(ap, uint64_t);
va_end(ap);
if(pt_setregs(pid, &jmp_reg)) {
return -1;
}
// single step until the function returns
while(jmp_reg.r_rsp <= bak_reg.r_rsp) {
if(pt_step(pid)) {
return -1;
}
if(pt_getregs(pid, &jmp_reg)) {
return -1;
}
}
// restore registers
if(pt_setregs(pid, &bak_reg)) {
return -1;
}
return jmp_reg.r_rax;
}
long
pt_syscall(pid_t pid, int sysno, ...) {
intptr_t addr = pt_resolve(pid, "HoLVWNanBBc");
struct reg jmp_reg;
struct reg bak_reg;
va_list ap;
if(!addr) {
return -1;
} else {
addr += 0xa;
}
if(pt_getregs(pid, &bak_reg)) {
return -1;
}
memcpy(&jmp_reg, &bak_reg, sizeof(jmp_reg));
jmp_reg.r_rip = addr;
jmp_reg.r_rax = sysno;
va_start(ap, sysno);
jmp_reg.r_rdi = va_arg(ap, uint64_t);
jmp_reg.r_rsi = va_arg(ap, uint64_t);
jmp_reg.r_rdx = va_arg(ap, uint64_t);
jmp_reg.r_r10 = va_arg(ap, uint64_t);
jmp_reg.r_r8 = va_arg(ap, uint64_t);
jmp_reg.r_r9 = va_arg(ap, uint64_t);
va_end(ap);
if(pt_setregs(pid, &jmp_reg)) {
return -1;
}
// single step until the function returns
while(jmp_reg.r_rsp <= bak_reg.r_rsp) {
if(pt_step(pid)) {
return -1;
}
if(pt_getregs(pid, &jmp_reg)) {
return -1;
}
}
// restore registers
if(pt_setregs(pid, &bak_reg)) {
return -1;
}
return jmp_reg.r_rax;
}
intptr_t
pt_mmap(pid_t pid, intptr_t addr, size_t len, int prot, int flags,
int fd, off_t off) {
return pt_syscall(pid, SYS_mmap, addr, len, prot, flags, fd, off);
}
int
pt_msync(pid_t pid, intptr_t addr, size_t len, int flags) {
return pt_syscall(pid, SYS_msync, addr, len, flags);
}
int
pt_munmap(pid_t pid, intptr_t addr, size_t len) {
return pt_syscall(pid, SYS_munmap, addr, len);
}
int
pt_mprotect(pid_t pid, intptr_t addr, size_t len, int prot) {
return pt_syscall(pid, SYS_mprotect, addr, len, prot);
}
int
pt_socket(pid_t pid, int domain, int type, int protocol) {
return (int)pt_syscall(pid, SYS_socket, domain, type, protocol);
}
int
pt_setsockopt(pid_t pid, int fd, int level, int optname, intptr_t optval,
socklen_t optlen) {
return (int)pt_syscall(pid, SYS_setsockopt, fd, level, optname, optval,
optlen, 0);
}
int
pt_close(pid_t pid, int fd) {
return (int)pt_syscall(pid, SYS_close, fd);
}
int
pt_bind(pid_t pid, int sockfd, intptr_t addr, uint32_t addrlen) {
return (int)pt_syscall(pid, SYS_bind, sockfd, addr, addrlen);
}
ssize_t
pt_recvmsg(pid_t pid, int fd, intptr_t msg, int flags) {
return (int)pt_syscall(pid, SYS_recvmsg, fd, msg, flags);
}
int
pt_dup2(pid_t pid, int oldfd, int newfd) {
return (int)pt_syscall(pid, SYS_dup2, oldfd, newfd);
}
int
pt_rdup(pid_t pid, pid_t other_pid, int fd) {
return (int)pt_syscall(pid, 0x25b, other_pid, fd);
}
int
pt_pipe(pid_t pid, intptr_t pipefd) {
intptr_t faddr = pt_resolve(pid, "-Jp7F+pXxNg");
return (int)pt_call(pid, faddr, pipefd);
}
int
pt_errno(pid_t pid) {
intptr_t faddr = pt_resolve(pid, "9BcDykPmo1I");
intptr_t addr = pt_call(pid, faddr);
return pt_getint(pid, addr);
}
intptr_t
pt_sceKernelGetProcParam(pid_t pid) {
intptr_t faddr = pt_resolve(pid, "959qrazPIrg");
return pt_call(pid, faddr);
}

View File

@@ -70,7 +70,7 @@ target_sources(${PROJECT_NAME} PRIVATE ${SrcFiles})
add_dependencies(${PROJECT_NAME} run_encryptxml)
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 SceRegMgr SceSystemService SceNet SceSysmodule SceUserService SceNetCtl SceSysCore kernel_sys SceAppInstUtil SceShellUIUtil)
target_link_libraries (${PROJECT_NAME} PUBLIC hijacker ScePad SceRegMgr SceSystemService SceNet SceSysmodule SceUserService SceNetCtl SceSysCore kernel_sys SceAppInstUtil)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Add post-build command

View File

@@ -26,12 +26,11 @@
<setting_list id="id_donation_methods" title="Support the Project" second_title="Do you like the project? Consider Donating">
<label id="id_method_info" title="★ Donation Methods" style="center"/>
<label id="id_method_div" title="" style="center"/>
<label id="id_method_1" title="- Ko-fi @ https://ko-fi.com/lightningmods" style="center"/>
<label id="id_method_2" title="- PayPal @ https://tinyurl.com/etaHEN-Donate" style="center"/>
<label id="id_method_1" title="- GitHub Sponsors | https://github.com/sponsors/LightningMods" style="center"/>
</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.3" style="center"/>
<label id="id_etahen_creds_display" title="★ etaHEN Beta 2.4" 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

@@ -5,6 +5,9 @@
<setting_list id="id_debug_settings" title="★etaHEN Toolbox" initial_focus_to="id_game_package_installer">
<!-- PKG Installer -->
<link id="id_game_package_installer" title="Package Installer" file="PkgInstaller/data/pkginstaller.xml"/>
<link id="id_game_custom_package_installer" title="★ Custom Background Package Installer" file="custompkginstaller.xml"/>
<!-- Plugins -->
<link id="id_plugins" title="Plugins / Payload ELFs" file="plugins.xml"/>
@@ -21,15 +24,39 @@
<toggle_switch id="id_DPI_v2_service" title="Direct Package Installer V2" second_title="Direct PKG Installer V2 web Server on http://PS5_IP:12800" value="0"/>
</setting_list>
<!-- Settings -->
<setting_list id="id_utils" title="Settings" initial_focus_to="id_pause_kstuff">
<list id="id_pause_kstuff" title="(Beta) Pause Kstuff" second_title="Pausing kstuff will greatly improve overrall system performance but FPKGs will NOT work" confirm="PS4 FPKGs, PS5 FGs and any FPKG Homebrew apps will NOT work once paused depending on the option selected" confirm_phrase="OK, Cancel" >
<list_item id="id_pause_kstuff_1" title="Not Paused" value="0"/>
<list_item id="id_pause_kstuff_2" title="PS5 sysentvec Only" value="1"/>
<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>
<setting_list id="id_utils" title="Settings" initial_focus_to="id_overlay_opts">
<!-- Overlay menu -->
<setting_list id="id_overlay_opts" title="Game Overlay Menu" initial_focus_to="id_overlay_change_pos">
<list id="id_overlay_change_pos" title="Overlay Position" second_title="Change the position of the overlay on screen" >
<list_item id="id_overlay_pos_1" title="Top Left" value="0"/>
<list_item id="id_overlay_pos_2" title="Top Right" value="1"/>
<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_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"/>
<toggle_switch id="id_overlay_ram" title="RAM Section" description="Toggle the RAM Section from the game overlay" value="0"/>
<toggle_switch id="id_overlay_ip" title="IP Address Section" description="Toggle the IP Section from the game overlay" value="0"/>
<toggle_switch id="id_overlay_kstuff" title="Kstuff is Disabled Warning Overlay" description="Replaces the Kstuff is disabled notification with Red on-screen warning text | NOTE: NOT affected by overlay position setting" value="0"/>
</setting_list>
<button id="id_download_kstuff" title="Download latest Kstuff"/>
<!-- Kstuff menu -->
<setting_list id="id_kstuff_opts" title="Kstuff Menu" initial_focus_to="id_pause_kstuff">
<list id="id_pause_kstuff" title="Pause Kstuff" second_title="Pausing kstuff will greatly improve overrall system performance but FPKGs will NOT work" confirm="PS4 FPKGs, PS5 FGs and any FPKG Homebrew apps will NOT work once paused depending on the option selected" confirm_phrase="OK, Cancel" >
<list_item id="id_pause_kstuff_1" title="Not Paused" value="0"/>
<list_item id="id_pause_kstuff_2" title="PS5 sysentvec Only" value="1"/>
<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"/>
<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_sistro_ps5debug" title="Enable PS5Debug by Sistr0 and CTN" value="0"/>
@@ -42,6 +69,9 @@
<toggle_switch id="id_auto_eject" title="Auto Eject Disc on etaHEN Start" description="Automatically ejects the inserted disc after etaHEN fully starts, useful for BD-J or LUA exploits" confirm="Changes will be applied next reboot" value="0"/>
<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"/> -->
<!-- Debug setting extra 1 -->
<link id="id_licenseactivation" title="Blu-Ray (license) Activation" file="DebugSettings/data/debug_settings_licenseactivation.xml"/>
<link id="id_external_hdd" title="External HDD" file="DebugSettings/data/debug_settings_external_hdd.xml" />
@@ -65,6 +95,7 @@
<toggle_switch id="id_lite_mode" title="Lite Mode" second_title="Kills All etaHEN services and plugins (Kstuff or HEN ONLY mode)" confirm="This WILL forcefully kill any active services and plugins (excluding the elfldr for re-enabling), Homebrew requiring etaHEN will also not function and the lite menu will not survive rest mode" value="0"/>
<toggle_switch id="id_debug_jb" title="[Debug] App Jailbreak Notification" second_title="Display a Jailbreak notification when jailbreaking an app" value="0"/>
<toggle_switch id="id_debug_legacy_cmd" title="[Debug] Legacy Jailbreak CMD Server" second_title="Requires networking; Apps can Jailbreak via Socket" value="0"/>
<!-- TestKit Menu -->
<link id="id_testkit_menu" title="TestKit Menu" file="testkit_menu.xml"/>
@@ -127,12 +158,11 @@
<setting_list id="id_donation_methods" title="Support the Project" second_title="Do you like the project? Consider Donating">
<label id="id_method_info" title="★ Donation Methods" style="center"/>
<label id="id_method_1" title="- Ko-fi | https://ko-fi.com/lightningmods" style="center"/>
<label id="id_method_2" title="- PayPal | https://tinyurl.com/etaHEN-Donate" style="center"/>
<label id="id_method_1" title="- GitHub Sponsors | https://github.com/sponsors/LightningMods" style="center"/>
</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.3" style="center"/>
<label id="id_etahen_creds_display" title="★ etaHEN Beta 2.4" 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"/>
@@ -140,7 +170,7 @@
<label id="id_major_line_3" title="John tornblom - elfldr, etc" style="center"/>
<label id="id_99877777" title="For more info, updates or issues visit the GitHub Repo" style="center"/>
<label id="id_99555557" title="https://github.com/LightningMods/etaHEN" style="center"/>
<label id="id_8585858" title="Special Thanks to all the Ko-fi Supporters including the following:" style="center"/>
<label id="id_8585858" title="Special Thanks to all the Supporters including the following:" style="center"/>
<label id="id_60606066" title="MODDED WARFARE, Bucanero, Echo Stretch, CurrentGenGamesWithNick, Reo Auin, illusion, nanospeedgamer, Nomadic, Michael Crump, Br0ken4life, Mouuu, Newhouse-Estates, Dr Angry " style="left"/>
<label id="id_60888880" title="Richard Stoltz, Not So Typical Gamer, Doobie, MC, WWIII, dutchfavx, Pulsar, gorshco, illix, Ya Boi Michael, Nineof09, Lostferwords, Kevin, kUiTs, ram" style="left"/>
<label id="id_606064330" title="onstar, Mapleditch, pyksy, Puky70, TheBoySassy21, Arnooooo, Jacksun, William, MauricioRodriguez, Micaiah, Madmac, Grit, dIGIMAN/TRSI, xe, Priyesh Patel" style="left"/>

View File

@@ -71,6 +71,36 @@ enum TrailExpireOpt {
TRIAL_EXPIRED,
};
enum RemoveWidget {
REMOVE_GPU_OVERLAY,
REMOVE_CPU_OVERLAY,
REMOVE_RAM_OVERLAY,
REMOVE_FPS_OVERLAY,
REMOVE_IP_OVERLAY,
REMOVE_ALL_OVERLAYS,
REMOVE_KSTUFF_DISABLED
};
enum CreateWidget {
CREATE_GPU_OVERLAY,
CREATE_CPU_OVERLAY,
CREATE_RAM_OVERLAY,
CREATE_FPS_OVERLAY,
CREATE_IP_OVERLAY,
CREATE_ALL_OVERLAYS,
CREATE_KSTUFF_DISABLED
};
struct WidgetConfig {
const char* id;
float x, y;
const char* text;
int bold;
float r, g, b, a;
};
void RemoveGameWidget(RemoveWidget widget);
void CreateGameWidget(CreateWidget widget);
struct LaunchAppParam
{
@@ -157,6 +187,13 @@ enum Cheats_Shortcut{
KSTUFF_SINGLE_SHARE,
};
enum overlay_positions{
OVERLAY_POS_TOP_LEFT = 0,
OVERLAY_POS_TOP_RIGHT,
OVERLAY_POS_BOTTOM_LEFT,
OVERLAY_POS_BOTTOM_RIGHT
};
typedef struct etaHENSettings_t
{
bool FTP = true;
@@ -177,13 +214,22 @@ typedef struct etaHENSettings_t
bool disable_toolbox_auto_start_for_rest_mode = false;
bool display_tids = false;
bool debug_app_jb_msg = false;
bool debug_legacy_cmd_server = false;
bool etaHEN_game_opts = true;
bool auto_eject_disc = false;
bool overlay_gpu = true;
bool overlay_cpu = true;
bool overlay_ram = true;
bool overlay_fps = false;
bool overlay_ip = false;
bool overlay_kstuff = false;
bool overlay_kstuff_active = 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;
uint64_t rest_delay_seconds = 0;
// Shortcuts
Cheats_Shortcut cheats_shortcut_opt = CHEATS_SC_OFF;
@@ -191,6 +237,23 @@ typedef struct etaHENSettings_t
Games_Shortcut games_shortcut_opt = GAMES_SC_OFF;
Kstuff_Shortcut kstuff_shortcut_opt = KSTUFF_SC_OFF;
//floats for overlays
float overlay_gpu_x = 10.0f;
float overlay_gpu_y = 10.0f;
float overlay_cpu_x = 10.0f;
float overlay_cpu_y = 35.0f;
float overlay_ram_x = 10.0f;
float overlay_ram_y = 60.0f;
float overlay_fps_x = 10.0f;
float overlay_fps_y = 85.0f;
float overlay_ip_x = 10.0f;
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
} etaHENSettings;
@@ -337,6 +400,7 @@ void generate_plugin_xml(std::string& xml_buffer, bool plugins_xml);
void generate_remote_play_xml(std::string& xml_buffer);
void Patch_Main_thread_Check(MonoImage * image_core);
uint64_t Get_Address_of_Method(MonoImage* Assembly_Image, const char* Name_Space, const char* Class_Name, const char* Method_Name, int Param_Count);
uint64_t Get_Address_of_Method(MonoImage* Assembly_Image, MonoClass* klass, const char* Method_Name, int Param_Count);
uint64_t GetManifestResourceStream_Hook(uint64_t inst, MonoString* FileName);
uint64_t GetManifestResourceInternal_Hook(MonoObject* instance, MonoString* name, int* size, MonoObject& module);
MonoObject* New_Mono_XML_From_String(std::string xml_doc);
@@ -349,6 +413,148 @@ bool SetVersionString(const char* str);
int SendShelluiNotify();
void Terminate();
bool Start_Kit_Hooks();
extern 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);
template <typename result>
result Get_Property(MonoClass* Klass, MonoObject* Instance, const char* Property_Name)
{
if (Klass == 0)
{
return (result)0;
}
MonoProperty* Prop = mono_class_get_property_from_name(Klass, Property_Name);
if (Prop == 0)
{
return (result)0;
}
MonoMethod* Get_Method = mono_property_get_get_method(Prop);
if (Get_Method == 0)
{
return (result)0;
}
uint64_t Get_Method_Thunk = (uint64_t)mono_compile_method(Get_Method);
if (Get_Method_Thunk == 0)
{
return (result)0;
}
if (Instance != 0)
{
result(*Method)(MonoObject* Instance) = decltype(Method)(Get_Method_Thunk);
return Method(Instance);
}
else
{
result(*Method)() = decltype(Method)(Get_Method_Thunk);
return Method();
}
}
template <typename result>
result Get_Property(MonoImage* Assembly_Image, const char* Namespace, const char* Class_Name, MonoObject* Instance, const char* Property_Name)
{
return Get_Property<result>(mono_class_from_name(Assembly_Image, Namespace, Class_Name), Instance, Property_Name);
}
template <typename Param>
void Set_Property(MonoClass* Klass, MonoObject* Instance, const char* Property_Name, Param Value)
{
if (Klass == nullptr)
{
return;
}
if (Instance == nullptr)
{
return;
}
MonoProperty* Prop = mono_class_get_property_from_name(Klass, Property_Name);
if (Prop == nullptr)
{
return;
}
MonoMethod* Set_Method = mono_property_get_set_method(Prop);
if (Set_Method == nullptr)
{
return;
}
uint64_t Set_Method_Thunk = (uint64_t)mono_compile_method(Set_Method);
if (Set_Method_Thunk == 0)
{
return;
}
void(*Method)(MonoObject* Instance, Param Value) = decltype(Method)(Set_Method_Thunk);
Method(Instance, Value);
}
template <typename Param>
void Set_Property_Invoke(MonoClass* Klass, MonoObject* Instance, const char* Property_Name, Param Value)
{
if (Klass == nullptr)
{
return;
}
if (Instance == nullptr)
{
return;
}
MonoProperty* Prop = mono_class_get_property_from_name(Klass, Property_Name);
if (Prop == nullptr)
{
return;
}
MonoMethod* Set_Method = mono_property_get_set_method(Prop);
if (Set_Method == nullptr)
{
return;
}
mono_runtime_invoke(Set_Method, Instance, (void**)&Value, 0);
}
#define ARRAY_COUNT(arry) sizeof(arry) / sizeof(arry[0])
template <typename result, typename... Args>
result Invoke(MonoImage* Assembly_Image, MonoClass* klass, MonoObject* Instance, const char* Method_Name, Args... args)
{
void* Argsv[] = { &args... };
uint64_t ThunkAddress = Get_Address_of_Method(Assembly_Image, klass, Method_Name, ARRAY_COUNT(Argsv));
if (!ThunkAddress)
{
return (result)0;
}
if (Instance)
{
result(*Method)(MonoObject* Instance, Args... args) = decltype(Method)(ThunkAddress);
return Method(Instance, args...);
}
else //Static Call.
{
result(*Method)(Args... args) = decltype(Method)(ThunkAddress);
return Method(args...);
}
}
/* ================================= ORIG HOOKED MONO FUNCS ============================================= */
extern int (*oOnPress)(MonoObject* Instance, MonoObject* element, MonoObject* e);
@@ -374,7 +580,7 @@ extern int (*__sys_regmgr_call)(long, long, int*, int*, long);
/* ================================= HOOKED MONO FUNCS ============================================= */
extern std::vector<Plugins> plugins_list;
extern std::vector<Plugins> auto_list;
extern std::vector<Payloads_Apps> payloads_apps_list;
extern std::vector<Payloads_Apps> payloads_apps_list, custom_pkg_list;
extern std::string dec_xml_str;
extern std::string dec_list_xml_str;
extern std::string cheats_xml;
@@ -385,14 +591,24 @@ extern std::string uilib;
extern std::string Sysinfo;
extern std::string display_info;
extern std::string uilib_dll;
extern Payloads_Apps custom_pkg_path;
extern std::string plugin_xml;
extern std::string debug_settings_xml;
extern std::string remote_play_xml;
extern bool is_game_open;
extern bool is_current_game_open;
extern MonoImage* pui_img;
extern MonoImage* AppSystem_img;
extern MonoObject* Game;
MonoObject* CreateUIColor(float r, float g, float b, float a);
MonoObject* CreateUIFont(int size, int style, int weight);
MonoObject* CreateLabel(const char* name, float x, float y, const char* text, MonoObject* font, int horzAlign, int vertAlign, float r, float g, float b, float a);
void Widget_Append_Child(MonoObject* widget, MonoObject* child);
MonoObject* New_Object(MonoClass* Klass);
MonoString *GetString_Hook(MonoObject *Instance, MonoString *str);
void UpdateImposeStatusFlag_hook(MonoObject* scene, MonoObject* frontActiveScene);
int OnPress_Hook(MonoObject* Instance, MonoObject* element, MonoObject* e);
@@ -426,5 +642,6 @@ int rnps_decrypt_block(void* buffer, int size);
int ioctl_hook (int fd, unsigned long request, void *argp);
int LaunchApp(MonoString* titleId, uint64_t* args, int argsSize, LaunchAppParam *param);
int sceRegMgrGetInt_hook(long regid, int* out_val);
void generate_custom_pkg_xml(std::string& xml_buffer);
void createJson_hook(MonoObject* inst, MonoObject* array, MonoString* id, MonoString* label = nullptr, MonoString* actionUrl = nullptr, MonoString* actionId = nullptr, MonoString* messageId = nullptr, MonoObject* subMenu = nullptr, bool enable = true);
/* ================================= HOOKED MONO FUNCS ============================================= */

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.3"
#define etaHEN_VERSION "2.4"
#define libSceKernelHandle 0x2001
#define KERNEL_DLSYM(handle, sym) \

View File

@@ -29,6 +29,13 @@ struct AppMessage {
uint64_t timestamp;
};
typedef struct
{
unsigned int size;
uint32_t userId;
} SceShellUIUtilLaunchByUriParam;
typedef struct
{
int32_t type; // 0x00
@@ -476,8 +483,30 @@ typedef struct app_info {
char unknown2[0x3c];
} app_info_t;
typedef struct pkg_metadata {
const char* uri;
const char* ex_uri;
const char* playgo_scenario_id;
const char* content_id;
const char* content_name;
const char* icon_url;
} pkg_metadata_t;
typedef struct pkg_info {
char content_id[48];
int type;
int platform;
} pkg_info_t;
typedef struct playgo_info {
char lang[8][30];
char scenario_ids[3][64];
char content_ids[64];
long unknown[810];
} playgo_info_t;
typedef uint32_t(*SceLncUtilLaunchAppType)(const char* tid, const char* argv[], LncAppParam* param);
extern SceLncUtilLaunchAppType sceLncUtilLaunchApp_dyn;
uint32_t sceLncUtilLaunchApp(const char* tid, const char* argv[], LncAppParam* param);
@@ -568,7 +597,14 @@ extern MonoString *(*mono_object_to_string)(MonoObject *obj, MonoObject **exc);
extern void (*mono_raise_exception)(MonoObject *exception);
extern MonoString* (*getIpMacHost)(uint64_t inst, SceNetIfName name);
extern int (*sceShellUIUtilInitialize)(void);
extern int (*sceShellUIUtilLaunchByUri)(const char* uri, SceShellUIUtilLaunchByUriParam* Param);
/* WRAPPERS */
int sceSystemServiceGetAppId(const char * tid);
void KillAllWithName(const char * name, int signal);
extern "C" void pause_resume_kstuff(KstuffPauseStatus opt, bool notify_user);
extern "C" {
void pause_resume_kstuff(KstuffPauseStatus opt, bool notify_user);
int sceAppInstUtilInstallByPackage(pkg_metadata* arg1, pkg_info* pkg_info, playgo_info* arg2);
}

View File

@@ -37,6 +37,7 @@ along with this program; see the file COPYING. If not, see
#include <sys/un.h>
#include <unistd.h>
#include <vector>
#include <ps5/klog.h>
enum Cheat_Actions {
DOWNLOAD_CHEATS = 0,
@@ -63,7 +64,7 @@ static void shellui_log(const char *fmt, ...) {
buffer[DAEMON_BUFF_MAX - 1] = '\0';
}
if (!is_testkit)
sceKernelDebugOutText(0, buffer);
klog_printf(buffer);
else
printf("%s", buffer);
}
@@ -111,8 +112,19 @@ public:
// erase the old message
bzero(msg.msg, sizeof(msg.msg));
int ret = recv(util_daemon ? UtilDaemonSocket : MainDaemonSocket,
reinterpret_cast<void *>(&msg), sizeof(msg), MSG_NOSIGNAL);
int timeout_ms = 10 * 1000;
// Set receive timeout
struct timeval tv;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
int socket_fd = util_daemon ? UtilDaemonSocket : MainDaemonSocket;
if (setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
return -1; // Error setting timeout
}
int ret = recv(socket_fd, reinterpret_cast<void*>(&msg), sizeof(msg), MSG_NOSIGNAL);
if (ret < 0) {
shellui_log("recv failed with: 0X%X", ret);
return ret;
@@ -287,14 +299,14 @@ public:
}
IPC_Ret DownloadKstuff() {
std::string ipc_msg;
if (!IPCSendCommand(BREW_UTIL_DOWNLOAD_KSTUFF, ipc_msg)) {
shellui_log("Failed to BREW_UTIL_DOWNLOAD_KSTUFF");
return IPC_Ret::OPERATION_FAILED;
}
std::string ipc_msg;
if (!IPCSendCommand(BREW_UTIL_DOWNLOAD_KSTUFF, ipc_msg)) {
shellui_log("Failed to BREW_UTIL_DOWNLOAD_KSTUFF");
return IPC_Ret::OPERATION_FAILED;
}
return IPC_Ret::NO_ERROR;
}
return IPC_Ret::NO_ERROR;
}
void KillDaemon() {
std::string ipc_msg;

View File

@@ -0,0 +1,233 @@
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <cstring>
#include <thread>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/stat.h>
#include <arpa/inet.h>
class SimpleHTTPServer {
private:
int port;
std::string root_dir;
std::thread server_thread;
bool running;
std::string getMimeType(const std::string& path) {
if (path.find(".html") != std::string::npos) return "text/html";
if (path.find(".css") != std::string::npos) return "text/css";
if (path.find(".js") != std::string::npos) return "application/javascript";
if (path.find(".png") != std::string::npos) return "image/png";
if (path.find(".jpg") != std::string::npos ||
path.find(".jpeg") != std::string::npos) return "image/jpeg";
if (path.find(".mp4") != std::string::npos) return "video/mp4";
return "application/octet-stream";
}
long getFileSize(const std::string& path) {
struct stat stat_buf;
int rc = stat(path.c_str(), &stat_buf);
return rc == 0 ? stat_buf.st_size : -1;
}
void parseRange(const std::string& range_header, long file_size,
long& start, long& end) {
start = 0;
end = file_size - 1;
if (range_header.empty()) return;
std::string range = range_header.substr(6); // Remove "bytes="
size_t dash_pos = range.find('-');
if (dash_pos != std::string::npos) {
std::string start_str = range.substr(0, dash_pos);
std::string end_str = range.substr(dash_pos + 1);
if (!start_str.empty()) start = std::stol(start_str);
if (!end_str.empty()) end = std::stol(end_str);
}
if (end >= file_size) end = file_size - 1;
if (start > end) start = end;
}
void sendResponse(int client_socket, const std::string& file_path,
const std::string& range_header) {
std::ifstream file(file_path, std::ios::binary);
if (!file) {
std::string response = "HTTP/1.1 404 Not Found\r\n"
"Content-Length: 9\r\n\r\n"
"Not Found";
send(client_socket, response.c_str(), response.length(), 0);
return;
}
long file_size = getFileSize(file_path);
long start, end;
parseRange(range_header, file_size, start, end);
long content_length = end - start + 1;
std::string mime_type = getMimeType(file_path);
std::ostringstream response;
if (range_header.empty()) {
response << "HTTP/1.1 200 OK\r\n";
}
else {
response << "HTTP/1.1 206 Partial Content\r\n";
response << "Content-Range: bytes " << start << "-" << end
<< "/" << file_size << "\r\n";
}
response << "Content-Type: " << mime_type << "\r\n";
response << "Content-Length: " << content_length << "\r\n";
response << "Accept-Ranges: bytes\r\n";
response << "Connection: close\r\n";
response << "\r\n";
std::string header = response.str();
send(client_socket, header.c_str(), header.length(), 0);
file.seekg(start);
char buffer[8192];
long bytes_to_send = content_length;
while (bytes_to_send > 0 && file) {
long chunk_size = std::min(bytes_to_send, (long)sizeof(buffer));
file.read(buffer, chunk_size);
long bytes_read = file.gcount();
if (bytes_read > 0) {
send(client_socket, buffer, bytes_read, 0);
bytes_to_send -= bytes_read;
}
else {
break;
}
}
}
void handleRequest(int client_socket) {
char buffer[4096] = { 0 };
recv(client_socket, buffer, sizeof(buffer), 0);
std::string request(buffer);
std::istringstream iss(request);
std::string method, path, version;
iss >> method >> path >> version;
if (method != "GET") {
std::string response = "HTTP/1.1 405 Method Not Allowed\r\n"
"Content-Length: 18\r\n\r\n"
"Method Not Allowed";
send(client_socket, response.c_str(), response.length(), 0);
return;
}
std::string range_header;
size_t range_pos = request.find("Range: bytes=");
if (range_pos != std::string::npos) {
size_t end_pos = request.find("\r\n", range_pos);
if (end_pos != std::string::npos) {
range_header = request.substr(range_pos + 7,
end_pos - range_pos - 7);
}
}
if (path == "/") path = "/index.html";
std::string file_path = root_dir + path;
sendResponse(client_socket, file_path, range_header);
}
void serverLoop() {
int server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket < 0) {
std::cerr << "Failed to create socket\n";
return;
}
int opt = 1;
setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(port);
if (bind(server_socket, (struct sockaddr*)&server_addr,
sizeof(server_addr)) < 0) {
std::cerr << "Failed to bind socket\n";
close(server_socket);
return;
}
if (listen(server_socket, 10) < 0) {
std::cerr << "Failed to listen\n";
close(server_socket);
return;
}
running = true;
while (running) {
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_socket = accept(server_socket,
(struct sockaddr*)&client_addr,
&client_len);
if (client_socket >= 0) {
handleRequest(client_socket);
close(client_socket);
}
}
close(server_socket);
}
std::string getLocalIP() {
std::string ip_address = "127.0.0.1";
return ip_address;
}
public:
SimpleHTTPServer(int p, const std::string& root)
: port(p), root_dir(root), running(false) {
}
~SimpleHTTPServer() {
stop();
}
void start() {
if (!running) {
server_thread = std::thread(&SimpleHTTPServer::serverLoop, this);
}
}
void stop() {
if (running) {
running = false;
if (server_thread.joinable()) {
server_thread.join();
}
std::cout << "Server stopped.\n";
}
}
bool isRunning() const {
return running;
}
std::string getURL() {
return "http://" + getLocalIP() + ":" + std::to_string(port);
}
};

View File

@@ -21,7 +21,7 @@ along with this program; see the file COPYING. If not, see
#include <machine/param.h>
#define ROUND_PG(x) (((x) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1))
extern bool has_hv_bypess;
extern bool has_hv_bypass;
void WriteJump(uint64_t address, uint64_t destination) {
*(uint8_t * )(address) = 0xFF;
@@ -34,11 +34,7 @@ void WriteJump(uint64_t address, uint64_t destination) {
}
void ReadMemory(uint64_t address, void * buffer, int length) {
// memcpy(buffer, (void*)address, length);
if (has_hv_bypess)
memcpy(buffer, (void * ) address, length);
else
mdbg_copyout(getpid(), address, buffer, length);
memcpy(buffer, (void * ) address, length);
}
void WriteMemory(uint64_t address, void * buffer, int length) {
@@ -57,9 +53,6 @@ void PatchInJump(uint64_t address, void * destination) {
if (!address || !destination)
return;
if (!has_hv_bypess) {
pid_t pid = getpid();
uint8_t JumpInstructions[] = {
0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xFF, 0xE0, // mov rax, <address>; jmp rax
};
@@ -72,46 +65,7 @@ void PatchInJump(uint64_t address, void * destination) {
uint64.a = (uint64_t) destination;
memcpy(JumpInstructions + 2, uint64.b, 8);
mdbg_copyin(pid, (void * ) JumpInstructions, address, sizeof(JumpInstructions));
} else {
WriteJump(address, (uint64_t) destination);
}
}
//
// Alloc using JIT shm
//
int JITAlloc(size_t size, void ** executableAddress, void ** writableAddress) {
uint8_t * old_ucred = jailbreak_process(getpid());
int executableHandle = -1;
int writableHandle = -1;
sceKernelJitCreateSharedMemory(0, ROUND_PG(size), PROT_EXEC | PROT_READ | PROT_WRITE, & executableHandle);
if (executableHandle < 0) {
shellui_log("Failed to create JIT shared memory!");
return 0;
}
sceKernelJitCreateAliasOfSharedMemory(executableHandle, PROT_READ | PROT_WRITE, & writableHandle);
if (writableHandle < 0) {
shellui_log("Failed to create JIT shared memory!");
return 0;
}
* executableAddress = mmap(NULL, ROUND_PG(size), PROT_EXEC | PROT_READ, MAP_SHARED, executableHandle, 0);
* writableAddress = mmap(NULL, ROUND_PG(size), PROT_WRITE | PROT_READ, MAP_FIXED | MAP_PRIVATE, writableHandle, 0);
if (! * executableAddress) {
shellui_log("Failed to map executable address!\n");
}
jail_process(getpid(), old_ucred);
free(old_ucred);
// memset(*writableAddress, 0xCC, ROUND_PG(size));
return 1;
WriteJump(address, (uint64_t)destination);
}
void * DetourFunction(uint64_t address, void * destination) {
@@ -120,12 +74,12 @@ void * DetourFunction(uint64_t address, void * destination) {
uint32_t InstructionSize = 0;
pid_t pid = getpid();
shellui_log("Hooking %#02lx => %p\n", address, destination);
shellui_log("Hooking %#02lx => %p", address, destination);
// sceKernelMprotect((void*)address, 0x1000, 0x7);
uint8_t code[HOOK_LENGTH];
if (has_hv_bypess)
if (has_hv_bypass)
{
sceKernelMprotect((void * ) address, PAGE_SIZE, PROT_EXEC | PROT_READ | PROT_WRITE);
}
@@ -157,16 +111,16 @@ void * DetourFunction(uint64_t address, void * destination) {
int stubLength = InstructionSize + HOOK_LENGTH;
void * executableAddress = NULL;
if (has_hv_bypess) {
executableAddress = malloc(stubLength);
if (!executableAddress) {
executableAddress = malloc(stubLength);
if (!executableAddress) {
shellui_log("Failed to allocate memory for stub");
return 0;
}
}
if (has_hv_bypass) {
sceKernelMprotect(executableAddress, stubLength, PROT_EXEC | PROT_READ | PROT_WRITE);
} else {
executableAddress = mmap(0, stubLength, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
kernel_mprotect(pid, (uint64_t) executableAddress, stubLength, PROT_EXEC | PROT_READ | PROT_WRITE);
kernel_mprotect(pid, (uint64_t)executableAddress, stubLength, PROT_EXEC | PROT_READ | PROT_WRITE);
}
ReadMemory((uint64_t) address, executableAddress, InstructionSize);

File diff suppressed because it is too large Load Diff

View File

@@ -48,7 +48,8 @@ etaHENSettings global_conf;
std::vector<GameEntry> games_list;
std::vector<Plugins> plugins_list, auto_list;
std::vector<Payloads_Apps> payloads_apps_list;
std::vector<Payloads_Apps> payloads_apps_list, custom_pkg_list;
Payloads_Apps custom_pkg_path = { .path = "/data/etaHEN/pkgs" };
std::string running_tid;
bool is_game_open = true;
@@ -61,15 +62,7 @@ extern bool game_shortcut_activated_media;
// #include <user_service.h>
typedef struct
{
unsigned int size;
uint32_t userId;
} SceShellUIUtilLaunchByUriParam;
extern "C"{
int sceShellUIUtilInitialize(void);
int sceShellUIUtilLaunchByUri(const char *uri, SceShellUIUtilLaunchByUriParam *Param);
int sceShellCoreUtilIsUsbMassStorageMounted(int num);
}
@@ -190,6 +183,81 @@ MonoImage * getDLLimage(const char* dll_file){
return img;
}
MonoObject* New_Object(MonoClass* Klass)
{
if (Klass == nullptr)
{
return nullptr;
}
return mono_object_new(Root_Domain, Klass);
}
MonoObject* CreateUIColor(float r, float g, float b, float a)
{
MonoClass* uIColor = mono_class_from_name(pui_img, "Sce.PlayStation.PUI", "UIColor");
// Allocates memory for our new instance of a class.
MonoObject* uIColorInstance = New_Object(uIColor);
MonoObject* realInstance = (MonoObject*)mono_object_unbox(uIColorInstance);
Invoke<void>(pui_img, uIColor, realInstance, ".ctor", r, g, b, a);
return realInstance;
}
MonoObject* CreateUIFont(int size, int style, int weight)
{
MonoClass* uIFont = mono_class_from_name(pui_img, "Sce.PlayStation.PUI.UI2", "UIFont");
// Allocates memory for our new instance of a class.
MonoObject* uIFontInstance = New_Object(uIFont);
MonoObject* realInstance = (MonoObject*)mono_object_unbox(uIFontInstance);
Invoke<void>(pui_img, uIFont, realInstance, ".ctor", size, style, weight);
return realInstance;
}
MonoObject* CreateLabel(const char* name, float x, float y, const char* text, MonoObject* font, int horzAlign, int vertAlign, float r, float g, float b, float a)
{
MonoClass* labelClass = mono_class_from_name(pui_img, "Sce.PlayStation.PUI.UI2", "Label");
// Allocates memory for our new instance of a class.
MonoObject* labelInstance = New_Object(labelClass);
// Call Constructor.
mono_runtime_object_init(labelInstance);
Set_Property(labelClass, labelInstance, "Name", mono_string_new(Root_Domain, name));
Set_Property(labelClass, labelInstance, "X", x);
Set_Property(labelClass, labelInstance, "Y", y);
Set_Property(labelClass, labelInstance, "Text", mono_string_new(Root_Domain, text));
Set_Property_Invoke(labelClass, labelInstance, "Font", font);
Set_Property(labelClass, labelInstance, "HorizontalAlignment", horzAlign);
Set_Property(labelClass, labelInstance, "VerticalAlignment", vertAlign);
Set_Property_Invoke(labelClass, labelInstance, "TextColor", CreateUIColor(r, g, b, a));
Set_Property(labelClass, labelInstance, "FitWidthToText", true);
Set_Property(labelClass, labelInstance, "FitHeightToText", true);
return labelInstance;
}
void Widget_Append_Child(MonoObject* widget, MonoObject* child)
{
MonoClass* widgetClass = mono_class_from_name(pui_img, "Sce.PlayStation.PUI.UI2", "Widget");
MonoMethod* appendChild = mono_class_get_method_from_name(widgetClass, "AppendChild", 1);
void* args[1];
args[0] = child;
mono_runtime_invoke(appendChild, widget, args, nullptr);
}
int endswith(const char *string, const char *suffix)
{
size_t suffix_len = strlen(suffix);
@@ -509,6 +577,25 @@ uint64_t Get_Address_of_Method(MonoImage *Assembly_Image, const char *Name_Space
// return (uint64_t)mono_aot_get_method(Root_Domain, Method);
return mono_compile_method(Method);
}
uint64_t Get_Address_of_Method(MonoImage* Assembly_Image, MonoClass* klass, const char* Method_Name, int Param_Count)
{
if (!klass)
{
return 0;
}
MonoMethod* Method = mono_class_get_method_from_name(klass, Method_Name, Param_Count);
if (!Method)
{
return 0;
}
//return (uint64_t)mono_aot_get_method(mono_get_root_domain(), Method);
return mono_compile_method(Method);
}
MonoObject *Get_Instance(MonoClass *klass, const char *Instance)
{
@@ -570,9 +657,17 @@ 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");
// Check if the strings are not nullptr before converting
global_conf.overlay_kstuff = overlay_kstuff ? atoi(overlay_kstuff) : 0;
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;
@@ -594,6 +689,14 @@ bool LoadSettings()
global_conf.debug_app_jb_msg = jb_debug_msg_str ? atoi(jb_debug_msg_str) : 0;
global_conf.disable_toolbox_auto_start_for_rest_mode = disable_toolbox_auto_start_for_rest_mode ? atoi(disable_toolbox_auto_start_for_rest_mode) : 0;
global_conf.auto_eject_disc = auto_eject_disc_str ? atoi(auto_eject_disc_str) : 0;
global_conf.overlay_ram = overlay_ram ? atoi(overlay_ram) : 1;
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;
global_conf.overlay_ip = overlay_ip ? atoi(overlay_ip) : 0;
//apply ovelay pos values
// Shortcuts
const char *cheats_shortcut_opt = ini_parser_get(&parser, "Settings.Cheats_shortcut_opt", "0");
@@ -606,6 +709,63 @@ bool LoadSettings()
global_conf.games_shortcut_opt = games_shortcut_opt ? (Games_Shortcut)atoi(games_shortcut_opt) : GAMES_SC_OFF;
global_conf.kstuff_shortcut_opt = kstuff_shortcut_opt ? (Kstuff_Shortcut)atoi(kstuff_shortcut_opt) : KSTUFF_SC_OFF;
global_conf.overlay_pos = overlay_position ? (overlay_positions)atoi(overlay_position) : OVERLAY_POS_TOP_LEFT;
if (global_conf.overlay_pos == OVERLAY_POS_TOP_LEFT) {
global_conf.overlay_fps_x = 10.0f;
global_conf.overlay_fps_y = 10.0f;
global_conf.overlay_gpu_x = 10.0f;
global_conf.overlay_gpu_y = 35.0f;
global_conf.overlay_cpu_x = 10.0f;
global_conf.overlay_cpu_y = 60.0f;
global_conf.overlay_ram_x = 10.0f;
global_conf.overlay_ram_y = 85.0f;
global_conf.overlay_ip_x = 10.0f;
global_conf.overlay_ip_y = 110.0f;
}
else if (global_conf.overlay_pos == OVERLAY_POS_BOTTOM_LEFT) {
global_conf.overlay_ram_x = 10.0f;
global_conf.overlay_ram_y = 970.0f;
global_conf.overlay_cpu_x = 10.0f;
global_conf.overlay_cpu_y = 990.0f;
global_conf.overlay_gpu_x = 10.0f;
global_conf.overlay_gpu_y = 1010.0f;
global_conf.overlay_fps_x = 10.0f;
global_conf.overlay_fps_y = 1030.0f;
global_conf.overlay_ip_x = 10.0f;
global_conf.overlay_ip_y = 1050.0f;
}
else if (global_conf.overlay_pos == OVERLAY_POS_TOP_RIGHT) {
global_conf.overlay_fps_x = 1720.0f;
global_conf.overlay_fps_y = 10.0f;
global_conf.overlay_gpu_x = 1720.0f;
global_conf.overlay_gpu_y = 35.0f;
global_conf.overlay_cpu_x = 1720.0f;
global_conf.overlay_cpu_y = 60.0f;
global_conf.overlay_ram_x = 1720.0f;
global_conf.overlay_ram_y = 85.0f;
global_conf.overlay_ip_x = 1670.0f;
global_conf.overlay_ip_y = 110.0f;
}
else if (global_conf.overlay_pos == OVERLAY_POS_BOTTOM_RIGHT) {
global_conf.overlay_ram_x = 1720.0f;
global_conf.overlay_ram_y = 970.0f;
global_conf.overlay_cpu_x = 1720.0f;
global_conf.overlay_cpu_y = 990.0f;
global_conf.overlay_gpu_x = 1720.0f;
global_conf.overlay_gpu_y = 1010.0f;
global_conf.overlay_fps_x = 1720.0f;
global_conf.overlay_fps_y = 1030.0f;
global_conf.overlay_ip_x = 1670.0f;
global_conf.overlay_ip_y = 1050.0f;
}
// global_conf.FTP = FTP;
return true;
@@ -641,11 +801,20 @@ bool SaveSettings()
buff += "Display_tids=" + std::to_string(global_conf.display_tids) + "\n";
buff += "APP_JB_Debug_Msg=" + std::to_string(global_conf.debug_app_jb_msg) + "\n";
buff += "etaHEN_Game_Options=" + std::to_string(global_conf.etaHEN_game_opts) + "\n";
buff += "auto_eject_disc=" + std::to_string(global_conf.auto_eject_disc) + "\n";
buff += "overlay_ram=" + std::to_string(global_conf.overlay_ram) + "\n";
buff += "overlay_cpu=" + std::to_string(global_conf.overlay_cpu) + "\n";
buff += "overlay_gpu=" + std::to_string(global_conf.overlay_gpu) + "\n";
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";
//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";
buff += "Games_shortcut_opt=" + std::to_string(global_conf.games_shortcut_opt) + "\n";
buff += "Kstuff_shortcut_opt=" + std::to_string(global_conf.kstuff_shortcut_opt) + "\n";
buff += "Overlay_pos=" + std::to_string(global_conf.overlay_pos) + "\n";
// Open the file for writing
int fd = open(INI_PATH, O_WRONLY | O_CREAT | O_TRUNC, 0777);
if (fd >= 0)
@@ -856,6 +1025,72 @@ close:
// shellui_log("%s\n", xml_buffer.c_str());
}
void generate_custom_pkg_xml(std::string& xml_buffer)
{
std::string converted = custom_pkg_path.path;
// Replace /mnt/xxx with /xxx
size_t pos = converted.find("/mnt/");
if (pos != std::string::npos) {
converted.replace(pos, 5, "/"); // Replace "/mnt/" with "/"
}
// Replace /data with /user/data
pos = 0;
while ((pos = converted.find("/data", pos)) != std::string::npos) {
converted.replace(pos, 5, "/user/data");
pos += 10; // Skip past the replacement
}
custom_pkg_path.shellui_path = converted;
shellui_log("Custom PKG Path for ShellUI: %s", custom_pkg_path.shellui_path.c_str());
struct dirent* entry;
int pkg_id = 1;
int pkg_count = 0;
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=\"custom_pkg_install\" title=\"★ Custom PKG Installer ( " + custom_pkg_path.path + " )\">\n";
xml_buffer += "<text_field id=\"id_change_custom_pkg_path\" title=\"Custom PKG Search Path\" keyboard_type=\"url\" confirm=\"Back out and re-select to refresh\" min_length=\"1\" max_length=\"255\"/>\n";
DIR* dir = opendir(custom_pkg_path.shellui_path.c_str());
if (!dir) {
shellui_log("Failed to open custom PKG directory: %s", custom_pkg_path.shellui_path.c_str());
xml_buffer += "<label id=\"id_no_pkgs\" title=\"No PKGs found - Path: " + custom_pkg_path.path + "\"/>\n";
xml_buffer += "</setting_list>\n</system_settings>";
return;
}
while ((entry = readdir(dir)) != nullptr) {
if (strstr(entry->d_name, ".pkg") != nullptr) {
std::string pkg_path = std::string(custom_pkg_path.path) + "/" + entry->d_name;
std::string id = "id_pkg_" + std::to_string(pkg_id++);
xml_buffer += "<button id=\"" + id + "\" title=\"" + entry->d_name + "\" description=\"" + pkg_path + "\"/>\n";
pkg_count++;
Payloads_Apps new_pkg;
new_pkg.name = entry->d_name;
new_pkg.path = pkg_path;
new_pkg.shellui_path = std::string(custom_pkg_path.shellui_path) + "/" + entry->d_name;
new_pkg.id = id;
custom_pkg_list.push_back(new_pkg);
shellui_log("Found PKG: %s", pkg_path.c_str());
}
}
closedir(dir);
if (pkg_count == 0) {
xml_buffer += "<label id=\"id_no_pkgs\" title=\"No PKGs found - Path: " + custom_pkg_path.path + "\"/>\n";
}
xml_buffer += "</setting_list>\n</system_settings>";
}
void generate_plugin_xml(std::string &xml_buffer, bool plugins_xml)
{
struct dirent *entry;

View File

@@ -102,4 +102,7 @@ MonoClass* (*mono_object_get_class)(MonoObject* obj) = nullptr;
MonoObject* (*mono_vtable_get_static_field_data)(MonoVTable* vt) = nullptr;
void* (*mono_object_unbox)(MonoObject* obj) = nullptr;
int(*ioctl)(int, int, void*) = nullptr;
int (*sceRegMgrGetInt)(long, int*) = nullptr;
int (*sceRegMgrGetInt)(long, int*) = nullptr;
int (*sceShellUIUtilInitialize)(void) = nullptr;
int (*sceShellUIUtilLaunchByUri)(const char* uri, SceShellUIUtilLaunchByUriParam* Param) = nullptr;

View File

@@ -25,7 +25,7 @@ along with this program; see the file COPYING. If not, see
#include "ucred.h"
#include <cstdint>
#include <iostream>
#include "webserver.hpp"
#include <unistd.h>
#include <util.hpp>
@@ -45,10 +45,13 @@ std::string remote_play_xml;
std::string debug_settings_xml;
std::string cheats_xml;
MonoImage* pui_img = nullptr;
MonoImage* AppSystem_img = nullptr;
MonoObject* Game = nullptr;
MonoImage * react_common_img = nullptr;
bool hooked = false;
bool has_hv_bypess = false;
bool has_hv_bypass = false;
bool is_testkit = false;
extern "C" long ptr_syscall = 0;
@@ -66,6 +69,10 @@ void __syscall() {
" ret\n");
}
void (*OnRender_orig)(MonoObject* instance);
MonoObject* rootWidget = nullptr;
MonoObject* font = nullptr;
void (*Orig_ReloadApp)(MonoString *str) = nullptr;
void ReloadApp(MonoString *str){
@@ -75,6 +82,344 @@ void ReloadApp(MonoString *str){
Orig_ReloadApp(str);
}
//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;
int AppInstUtilInstallByPackage_Hook(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) {
std::string s_uri = mono_string_to_utf8(uri);
std::string s_ex_uri = mono_string_to_utf8(ex_uri);
std::string s_playgo_scenario_id = mono_string_to_utf8(playgo_scenario_id);
std::string s_content_id = mono_string_to_utf8(content_id);
std::string s_content_name = mono_string_to_utf8(content_name);
std::string s_icon_url = mono_string_to_utf8(icon_url);
shellui_log("AppInstUtilInstallByPackage_Hook called with:\n uri: %s\n ex_uri: %s\n playgo_scenario_id: %s\n content_id: %s\n content_name: %s\n icon_url: %s\n slot: %u\n is_playgo_enabled: %d",
s_uri.c_str(), s_ex_uri.c_str(), s_playgo_scenario_id.c_str(), s_content_id.c_str(), s_content_name.c_str(), s_icon_url.c_str(), slot, is_playgo_enabled);
notify("Installing package from:\n%s", s_uri.c_str());
int ret = Orig_AppInstUtilInstallByPackage(uri, ex_uri, playgo_scenario_id, content_id, content_name, icon_url, slot, is_playgo_enabled, pkg_info, languages, playgo_scenario_ids, content_ids);
shellui_log("AppInstUtilInstallByPackage_Hook returned: %d", ret);
notify("Installation finished with code: %d", ret);
return ret;
}
struct OrbisKernelTimespec {
int64_t tv_sec;
int64_t tv_nsec;
};
struct Proc_Stats
{
int32_t lo_data; //0x00
uint32_t td_tid; //0x04
OrbisKernelTimespec user_cpu_usage_time; //0x08
OrbisKernelTimespec system_cpu_usage_time; //0x18
}; //0x28
extern "C" {
int sceKernelGetSocSensorTemperature(int sensorId, int* soctime);
int get_page_table_stats(int vm, int type, int* total, int* free);
int sceKernelGetCpuUsage(struct Proc_Stats* out, int32_t* size);
int sceKernelGetThreadName(uint32_t id, char* out);
int sceKernelGetCpuTemperature(int* cputemp);
int sceKernelClockGettime(int clockId, OrbisKernelTimespec* tp);
}
struct Memory
{
int Used;
int Free;
int Total;
float Percentage;
};
struct thread_usages
{
OrbisKernelTimespec current_time; //0x00
int Thread_Count; //0x10
char padding0[0x4]; //0x14
Proc_Stats Threads[3072]; //0x18
};
int Thread_Count = 0;
float Usage[8] = { 0 };
float Average_Usage;
Memory RAM;
Memory VRAM;
Proc_Stats Stat_Data[3072];
thread_usages gThread_Data[2];
void Get_Page_Table_Stats(int vm, int type, int* Used, int* Free, int* Total)
{
int _Total = 0, _Free = 0;
if (get_page_table_stats(vm, type, &_Total, &_Free) == -1) {
shellui_log("get_page_table_stats() Failed.\n");
return;
}
if (Used)
*Used = (_Total - _Free);
if (Free)
*Free = _Free;
if (Total)
*Total = _Total;
}
void calc_usage(unsigned int idle_tid[8], thread_usages* cur, thread_usages* prev, float usage_out[8])
{
if (cur->Thread_Count <= 0 || prev->Thread_Count <= 0) //Make sure our banks have threads
return;
//Calculate the Current time difference from the last bank to the current bank.
float Current_Time_Total = ((prev->current_time.tv_sec + (prev->current_time.tv_nsec / 1000000000.0f)) - (cur->current_time.tv_sec + (cur->current_time.tv_nsec / 1000000000.0f)));
//Here this could use to be improved but essetially what its doing is finding the thread information for the idle threads using their thread Index stored from before.
struct Data_s
{
Proc_Stats* Cur;
Proc_Stats* Prev;
}Data[8];
for (int i = 0; i < cur->Thread_Count; i++)
{
for (int j = 0; j < 8; j++)
{
if (idle_tid[j] == cur->Threads[i].td_tid)
Data[j].Cur = &cur->Threads[i];
}
}
for (int i = 0; i < prev->Thread_Count; i++)
{
for (int j = 0; j < 8; j++)
{
if (idle_tid[j] == prev->Threads[i].td_tid)
Data[j].Prev = &prev->Threads[i];
}
}
//Here we loop through each core to calculate the total usage time as its split into user/sustem
for (int i = 0; i < 8; i++)
{
float Prev_Usage_Time = (Data[i].Prev->system_cpu_usage_time.tv_sec + (Data[i].Prev->system_cpu_usage_time.tv_nsec / 1000000.0f));
Prev_Usage_Time += (Data[i].Prev->user_cpu_usage_time.tv_sec + (Data[i].Prev->user_cpu_usage_time.tv_nsec / 1000000.0f));
float Cur_Usage_Time = (Data[i].Cur->system_cpu_usage_time.tv_sec + (Data[i].Cur->system_cpu_usage_time.tv_nsec / 1000000.0f));
Cur_Usage_Time += (Data[i].Cur->user_cpu_usage_time.tv_sec + (Data[i].Cur->user_cpu_usage_time.tv_nsec / 1000000.0f));
//We calculate the usage using usage time difference between the two samples divided by the current time difference.
float Idle_Usage = ((Prev_Usage_Time - Cur_Usage_Time) / Current_Time_Total);
if (Idle_Usage > 1.0f)
Idle_Usage = 1.0f;
if (Idle_Usage < 0.0f)
Idle_Usage = 0.0f;
//Get inverse of idle percentage and express in percent.
usage_out[i] = (1.0f - Idle_Usage) * 100.0f;
}
}
extern bool app_launched;
class AtomicString {
mutable std::mutex mtx;
std::string value;
public:
void store(const std::string& str) {
std::lock_guard<std::mutex> lock(mtx);
value = str;
}
std::string load() const {
std::lock_guard<std::mutex> lock(mtx);
return value;
}
};
AtomicString fps_string;
int get_ip_address(char* ip_address);
void OnRender_Hook(MonoObject* instance)
{
static bool Do_Once = false;
static unsigned int Idle_Thread_ID[8];
static int Current_Bank = 0;
// Separate labels for text and values
static MonoObject* gpu_temp_value = nullptr;
static MonoObject* gpu_usage_value = nullptr;
static MonoObject* cpu_temp_value = nullptr;
static MonoObject* cpu_usage_value = nullptr;
static MonoObject* ram_value = nullptr;
static MonoObject* fps_value = nullptr;
char GPU_TEMP[32];
char GPU_USAGE[32];
char CPU_TEMP[32];
char CPU_USAGE[120];
char RAM_STR[32];
static int wait = 0;
int SOC_temp = 0;
int CPU_temp = 0;
if (!Do_Once)
{
#if 0
fps_string.store("LOADING");
#else
fps_string.store("NOT SUPPORTED IN THIS BUILD");
#endif
// shellui_log("string %s", fps_string.load().c_str());
int Thread_Count = 3072;
if (!sceKernelGetCpuUsage((Proc_Stats*)&Stat_Data, (int*)&Thread_Count) && Thread_Count > 0)
{
char Thread_Name[0x40];
int Core_Count = 0;
for (int i = 0; i < Thread_Count; i++)
{
if (!sceKernelGetThreadName(Stat_Data[i].td_tid, Thread_Name) && sscanf(Thread_Name, "SceIdleCpu%d", &Core_Count) == 1 && Core_Count <= 7)
{
Idle_Thread_ID[Core_Count] = Stat_Data[i].td_tid;
}
}
}
rootWidget = Get_Property<MonoObject*>(pui_img, "Sce.PlayStation.PUI.UI2", "Scene", Game, "RootWidget");
font = CreateUIFont(22, 0, 0); // Regular font for values
// GPU row - Green label (BOLD), Orange values - Better spacing
if (global_conf.overlay_cpu) {
CreateGameWidget(CREATE_CPU_OVERLAY);
}
if (global_conf.overlay_ram) {
CreateGameWidget(CREATE_RAM_OVERLAY);
}
if (global_conf.overlay_gpu) {
CreateGameWidget(CREATE_GPU_OVERLAY);
}
if (global_conf.overlay_fps) {
CreateGameWidget(CREATE_FPS_OVERLAY);
}
if (global_conf.overlay_ip) {
CreateGameWidget(CREATE_IP_OVERLAY);
}
Do_Once = true;
}
if (wait <= 0) {
// Get CPU usage
while (global_conf.overlay_cpu || global_conf.all_cpu_usage) {
gThread_Data[Current_Bank].Thread_Count = 3072;
if (!sceKernelGetCpuUsage((Proc_Stats*)&gThread_Data[Current_Bank].Threads, &gThread_Data[Current_Bank].Thread_Count))
{
Thread_Count = gThread_Data[Current_Bank].Thread_Count;
sceKernelClockGettime(4, &gThread_Data[Current_Bank].current_time);
Current_Bank = !Current_Bank;
if (gThread_Data[Current_Bank].Thread_Count <= 0)
continue;
calc_usage(Idle_Thread_ID, &gThread_Data[!Current_Bank], &gThread_Data[Current_Bank], Usage);
if (global_conf.all_cpu_usage) {
snprintf(CPU_USAGE, sizeof(CPU_USAGE), "%2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%%",Usage[0], Usage[1], Usage[2], Usage[3], Usage[4], Usage[5], Usage[6], Usage[7]);
break;
}
// Calculate average CPU usage
float avg_cpu = 0;
for (int i = 0; i < 8; i++) {
avg_cpu += Usage[i];
}
avg_cpu /= 8.0f;
snprintf(CPU_USAGE, sizeof(CPU_USAGE), "%.0f%%", avg_cpu);
break;
}
}
// Get RAM info
if (global_conf.overlay_ram)
{
Get_Page_Table_Stats(1, 1, &RAM.Used, &RAM.Free, &RAM.Total);
snprintf(RAM_STR, sizeof(RAM_STR), "%u MB", RAM.Used);
}
// Get GPU usage (estimate based on VRAM usage)
if (global_conf.overlay_gpu)
{
// Get temperatures
sceKernelGetSocSensorTemperature(0, &SOC_temp);
snprintf(GPU_TEMP, sizeof(GPU_TEMP), "%dC", SOC_temp);
Get_Page_Table_Stats(1, 2, &VRAM.Used, &VRAM.Free, &VRAM.Total);
VRAM.Percentage = (((float)VRAM.Used / (float)VRAM.Total) * 100.0f);
snprintf(GPU_USAGE, sizeof(GPU_USAGE), "%.0f%%", VRAM.Percentage);
}
if(global_conf.overlay_ip)
{
char ip_address[64];
get_ip_address(&ip_address[0]);
MonoObject* ip_value = Invoke<MonoObject*>(pui_img, mono_class_from_name(pui_img, "Sce.PlayStation.PUI.UI2", "Widget"), Get_Property<MonoObject*>(pui_img, "Sce.PlayStation.PUI.UI2", "Scene", Game, "RootWidget"), "FindWidgetByName", mono_string_new(Root_Domain, "id_ip_value"));
Set_Property(mono_class_from_name(pui_img, "Sce.PlayStation.PUI.UI2", "Label"), ip_value, "Text", mono_string_new(Root_Domain, ip_address));
}
if (global_conf.overlay_gpu) {
// Update GPU values
gpu_temp_value = Invoke<MonoObject*>(pui_img, mono_class_from_name(pui_img, "Sce.PlayStation.PUI.UI2", "Widget"), Get_Property<MonoObject*>(pui_img, "Sce.PlayStation.PUI.UI2", "Scene", Game, "RootWidget"), "FindWidgetByName", mono_string_new(Root_Domain, "id_gpu_temp_value"));
Set_Property(mono_class_from_name(pui_img, "Sce.PlayStation.PUI.UI2", "Label"), gpu_temp_value, "Text", mono_string_new(Root_Domain, GPU_TEMP));
gpu_usage_value = Invoke<MonoObject*>(pui_img, mono_class_from_name(pui_img, "Sce.PlayStation.PUI.UI2", "Widget"), Get_Property<MonoObject*>(pui_img, "Sce.PlayStation.PUI.UI2", "Scene", Game, "RootWidget"), "FindWidgetByName", mono_string_new(Root_Domain, "id_gpu_usage_value"));
Set_Property(mono_class_from_name(pui_img, "Sce.PlayStation.PUI.UI2", "Label"), gpu_usage_value, "Text", mono_string_new(Root_Domain, GPU_USAGE));
}
if (global_conf.overlay_cpu || global_conf.all_cpu_usage) {
sceKernelGetCpuTemperature(&CPU_temp);
// Format temperature strings
snprintf(CPU_TEMP, sizeof(CPU_TEMP), "%dC", CPU_temp);
// Update CPU values
cpu_temp_value = Invoke<MonoObject*>(pui_img, mono_class_from_name(pui_img, "Sce.PlayStation.PUI.UI2", "Widget"), Get_Property<MonoObject*>(pui_img, "Sce.PlayStation.PUI.UI2", "Scene", Game, "RootWidget"), "FindWidgetByName", mono_string_new(Root_Domain, "id_cpu_temp_value"));
Set_Property(mono_class_from_name(pui_img, "Sce.PlayStation.PUI.UI2", "Label"), cpu_temp_value, "Text", mono_string_new(Root_Domain, CPU_TEMP));
cpu_usage_value = Invoke<MonoObject*>(pui_img, mono_class_from_name(pui_img, "Sce.PlayStation.PUI.UI2", "Widget"), Get_Property<MonoObject*>(pui_img, "Sce.PlayStation.PUI.UI2", "Scene", Game, "RootWidget"), "FindWidgetByName", mono_string_new(Root_Domain, "id_cpu_usage_value"));
Set_Property(mono_class_from_name(pui_img, "Sce.PlayStation.PUI.UI2", "Label"), cpu_usage_value, "Text", mono_string_new(Root_Domain, CPU_USAGE));
}
if(global_conf.overlay_ram)
{
// Update RAM value
ram_value = Invoke<MonoObject*>(pui_img, mono_class_from_name(pui_img, "Sce.PlayStation.PUI.UI2", "Widget"), Get_Property<MonoObject*>(pui_img, "Sce.PlayStation.PUI.UI2", "Scene", Game, "RootWidget"), "FindWidgetByName", mono_string_new(Root_Domain, "id_ram_value"));
Set_Property(mono_class_from_name(pui_img, "Sce.PlayStation.PUI.UI2", "Label"), ram_value, "Text", mono_string_new(Root_Domain, RAM_STR));
}
if (global_conf.overlay_fps) {
// Update FPS value
std::string current_fps = fps_string.load();
fps_value = Invoke<MonoObject*>(pui_img, mono_class_from_name(pui_img, "Sce.PlayStation.PUI.UI2", "Widget"), Get_Property<MonoObject*>(pui_img, "Sce.PlayStation.PUI.UI2", "Scene", Game, "RootWidget"), "FindWidgetByName", mono_string_new(Root_Domain, "id_fps_value"));
Set_Property(mono_class_from_name(pui_img, "Sce.PlayStation.PUI.UI2", "Label"), fps_value, "Text", mono_string_new(Root_Domain, current_fps.c_str()));
}
wait = 60; // Update every 60 frames
}
else {
wait--;
}
OnRender_orig(instance);
}
int main(int argc, char const *argv[]) {
OrbisKernelSwVersion sw;
char buz[100];
@@ -82,6 +427,9 @@ int main(int argc, char const *argv[]) {
return 0;
}
static ssize_t(*read)(int fd, void* buf, size_t count) = nullptr;
pid_t pid = getpid();
uintptr_t old_authid = set_ucred_to_debugger();
@@ -96,6 +444,7 @@ int main(int argc, char const *argv[]) {
KERNEL_DLSYM(libkernelsys_handle, sceKernelGetProsperoSystemSwVersion);
KERNEL_DLSYM(libkernelsys_handle, sceKernelGetAppInfo);
KERNEL_DLSYM(libkernelsys_handle, sceKernelGetProcessName);
KERNEL_DLSYM(libkernelsys_handle, read);
shellui_log("Starting ShellUI Module ....");
// int native_handle = get_module_handle(pid, "libNativeExtensions.sprx");
@@ -117,6 +466,11 @@ int main(int argc, char const *argv[]) {
ptr_syscall = getpid;
ptr_syscall += 0xa; // jump directly to the syscall instruction
int libshelluiutil_handle = get_module_handle(pid, "libSceShellUIUtil.sprx");
KERNEL_DLSYM(libshelluiutil_handle, sceShellUIUtilLaunchByUri);
KERNEL_DLSYM(libshelluiutil_handle, sceShellUIUtilInitialize);
//
// Mono is already loaded into the SceShellUI process
//
@@ -301,7 +655,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
@@ -355,12 +709,6 @@ int main(int argc, char const *argv[]) {
return -1;
}
MonoImage * appsystem_img = getDLLimage(appsystem_dll.c_str());
if (!appsystem_img) {
notify("Failed to get image 2.");
return -1;
}
MonoImage * capture_menu = getDLLimage(capture_menu_dll.c_str());
if (!capture_menu) {
notify("Failed to get image 3.");
@@ -378,7 +726,6 @@ int main(int argc, char const *argv[]) {
notify("Failed to get image 5.");
return -1;
}
MonoImage * ReactNativeShellAppReactNativeShellApp_img = getDLLimage("Sce.Vsh.ShellUI.ReactNativeShellApp.dll");
if (!ReactNativeShellAppReactNativeShellApp_img) {
@@ -386,23 +733,85 @@ int main(int argc, char const *argv[]) {
return -1;
}
Patch_Main_thread_Check(image_core);
// System.Reflection.RuntimeAssembly.GetManifestResourceStream
uint64_t method = Get_Address_of_Method(mscorelib_image, sys_reflection_dec.c_str(), is_3xx ? "Assembly" : RuntimeAssembly_dec.c_str(), GetManifestResourceStream_dec.c_str(), 1);
if (!method) {
notify("Failed to get master address");
MonoImage* AppInstallUtil_img = getDLLimage("Sce.Vsh.AppInstUtilWrapper.dll");
if(!AppInstallUtil_img) {
notify("Failed to get image 7.");
return -1;
}
}
shellui_log("Starting hooking...");
if (if_exists("/system_tmp/kstuff_paused")) {
shellui_log("Kstuff Paused, resuming kstuff");
pause_resume_kstuff(NOT_PAUSED, false);
unlink("/system_tmp/kstuff_paused");
}
pui_img = getDLLimage("Sce.PlayStation.PUI.dll");
if (!pui_img) {
notify("Failed to get pui image");
return -1;
}
if (1) {
MonoClass* LayerManager = mono_class_from_name(AppSystem_img, "Sce.Vsh.ShellUI.AppSystem", "LayerManager");
if (!LayerManager) {
notify("Failed to get LayerManager class");
return -1;
}
// Get the method - this should return MonoMethod*, not an address
MonoMethod* FindContainerSceneByPath = mono_class_get_method_from_name(LayerManager, "FindContainerSceneByPath", 1);
if (!FindContainerSceneByPath) {
notify("Failed to get FindContainerSceneByPath method");
return -1;
}
// Create the string argument
MonoString* pathArg = mono_string_new(mono_domain_get(), "Game");
// Prepare arguments array
void* args[1];
args[0] = pathArg;
// Invoke the method (static call since Instance is nullptr)
MonoObject* exception = nullptr;
Game = mono_runtime_invoke(FindContainerSceneByPath, nullptr, args, &exception);
if (exception) {
notify("Exception occurred while calling FindContainerSceneByPath");
return -1;
}
if (!Game) {
notify("Failed to get Game ContainerScene");
return -1;
}
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
uint64_t method = Get_Address_of_Method(mscorelib_image, sys_reflection_dec.c_str(), is_3xx ? "Assembly" : RuntimeAssembly_dec.c_str(), GetManifestResourceStream_dec.c_str(), 1);
if (!method) {
notify("Failed to get master address");
return -1;
}
shellui_log("Starting hooking...");
if (if_exists("/system_tmp/kstuff_paused")) {
shellui_log("Kstuff Paused, resuming kstuff");
pause_resume_kstuff(NOT_PAUSED, false);
unlink("/system_tmp/kstuff_paused");
}
has_hv_bypass = (sceKernelMprotect( & buz[0], 100, 0x7) == 0);
//SimpleHTTPServer server(1304, "/");
//server.start();
Patch_Main_thread_Check(image_core);
#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;
}
#endif
has_hv_bypess = (sceKernelMprotect( & buz[0], 100, 0x7) == 0);
if(sceRegMgrGetInt) {
sceRegMgrGetInt = (int( * )(long, int * )) DetourFunction((uintptr_t)sceRegMgrGetInt, (void *)&sceRegMgrGetInt_hook);
@@ -411,6 +820,10 @@ int main(int argc, char const *argv[]) {
return -1;
}
}
else{
notify("Failed to find sceRegMgrGetInt");
return -1;
}
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;
@@ -503,6 +916,18 @@ int main(int argc, char const *argv[]) {
notify("Failed to detour Func Set 10");
}
IPC_Client & main_ipc = IPC_Client::getInstance(false);
is_testkit = main_ipc.IsTestKit();
if (is_testkit) {
shellui_log("TestKit Detected, applying shellui testkit hooks");
Start_Kit_Hooks();
}
#if 0
Orig_ReloadApp = (void(*)(MonoString*))DetourFunction(Get_Address_of_Method(react_common_img, "ReactNative.Vsh.Common", "ReactApplicationSceneManager", "ReloadApp", 1), (void * )&ReloadApp);
if (!Orig_ReloadApp) {
notify("Failed to detour Func Set 11");
}
#endif
//
// Restore normal authid
//
@@ -513,6 +938,7 @@ int main(int argc, char const *argv[]) {
if(global_conf.display_tids)
ReloadRNPSApp("NPXS40002"); // home screen tid
// shellui_log("Decrypted Data: %s", dec_xml_str.c_str());
shellui_log("Performed Magic");

View File

@@ -18,10 +18,11 @@ along with this program; see the file COPYING. If not, see
#include <ps5/klog.h>
#include <stdint.h>
#include <sys/stat.h>
#include "elfldr.h"
#include "pt.h"
#include <stdbool.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stddef.h>
@@ -57,27 +58,9 @@ typedef struct {
char unkstr[1024]; // 0x82D
} OrbisNotificationRequest; // Size = 0xC30
typedef struct {
uint64_t pad0;
char version_str[0x1C];
uint32_t version;
uint64_t pad1;
} OrbisKernelSwVersion;
/**
* sceKernelSpawn() is not available in libkernel_web, which is what is used by
* the webkit exploit entry point. However, we do not actually use it initially,
* hence we just define an empty stub to silence the linker.
**/
int sceKernelSpawn(int *pid, int dbg, const char *path, char *root,
char *argv[]) {
return -1;
}
int sceKernelSendNotificationRequest(int32_t device,
OrbisNotificationRequest *req, size_t size,
int32_t blocking);
int sceKernelGetProsperoSystemSwVersion(OrbisKernelSwVersion *sw);
void notify(const char *text, ...) {
OrbisNotificationRequest req;
@@ -104,7 +87,7 @@ __asm__(".intel_syntax noprefix\n"
".type etahen_compressed, @object\n"
".align 16\n"
"etahen_compressed:\n"
".incbin \"../../bin/bootstrapper.elf.lzma\"\n"
".incbin \"../bin/bootstrapper.elf.lzma\"\n"
"etahen_compressed_end:\n"
".global etahen_compressed_size\n"
".type etahen_compressed_size, @object\n"
@@ -115,25 +98,67 @@ __asm__(".intel_syntax noprefix\n"
".type etahen_decompressed_size, @object\n"
".align 16\n"
"etahen_decompressed_size:\n"
".incbin \"../../bin/bootstrapper.elf.lzma.size\"\n");
".incbin \"../bin/bootstrapper.elf.lzma.size\"\n");
extern uint32_t etahen_compressed_size;
extern uint8_t etahen_compressed[];
extern uint8_t etahen_compressed_end[];
extern uint8_t etahen_decompressed_size[];
bool send_to_elfldr(const void* buffer, size_t buffer_size) {
int sockfd = -1;
struct sockaddr_in server_addr;
int bytes_sent = 0;
int total_sent = 0;
// Create socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
printf("Failed to create socket: %d\n", sockfd);
return false;
}
// Set socket options (optional - for faster reuse)
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
// Set up server address (always localhost)
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(9021);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
// Connect to server
if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
printf("Failed to connect to localhost:9021\n");
close(sockfd);
return false;
}
printf("Connected to localhost:9021\n");
// Send all data in the buffer
const char* data_ptr = (const char*)buffer;
while (total_sent < buffer_size) {
bytes_sent = send(sockfd, data_ptr + total_sent, buffer_size - total_sent, 0);
if (bytes_sent <= 0) {
printf("Failed to send data: %d\n", bytes_sent);
close(sockfd);
return false;
}
total_sent += bytes_sent;
}
printf("Successfully sent %d bytes to localhost:9021\n", total_sent);
// Close socket
close(sockfd);
return true;
}
int main() {
pid_t mypid = getpid();
uint8_t qa_flags[16];
uint8_t caps[16];
uint64_t authid;
intptr_t vnode;
pid_t vpid;
OrbisKernelSwVersion sys_ver;
sceKernelGetProsperoSystemSwVersion(&sys_ver);
if (etahen_compressed_size <= 0) {
printf("Invalid etaHEN payload! unable to unpack it!");
return 0;
@@ -181,69 +206,13 @@ int main() {
close(fd);
}
if ((sys_ver.version >> 16) < 0x700) {
// enable debugging with ptrace
if (kernel_get_qaflags(qa_flags)) {
notify("kernel_get_qa_flags failed");
return -1;
}
qa_flags[1] |= 0x03;
if (kernel_set_qaflags(qa_flags)) {
notify("kernel_set_qa_flags failed");
return -1;
}
}
// backup my privileges
if (!(vnode = kernel_get_proc_rootdir(mypid))) {
notify("kernel_get_proc_rootdir failed");
return -1;
}
if (kernel_get_ucred_caps(mypid, caps)) {
notify("kernel_get_ucred_caps failed");
return -1;
}
if (!(authid = kernel_get_ucred_authid(mypid))) {
notify("kernel_get_ucred_authid failed");
return -1;
}
// launch bootstrap.elf inside SceRedisServer
if ((vpid = elfldr_find_pid("SceRedisServer")) < 0) {
notify("elfldr_find_pid failed");
return -1;
} else if (elfldr_raise_privileges(mypid)) {
notify("Unable to raise privileges");
return -1;
} else if (pt_attach(vpid)) {
notify("pt_attach");
return -1;
} else {
if (elfldr_exec(vpid, STDOUT_FILENO, decompressed) != 0) {
notify("etaHEN failed to start: ELF");
return -1;
}
}
// restore my privileges
if (kernel_set_proc_jaildir(mypid, vnode)) {
notify("kernel_set_proc_jaildir failed");
return -1;
}
if (kernel_set_proc_rootdir(mypid, vnode)) {
notify("kernel_set_proc_rootdir failed");
return -1;
}
if (kernel_set_ucred_caps(mypid, caps)) {
notify("kernel_set_ucred_caps failed");
return -1;
}
if (kernel_set_ucred_authid(mypid, authid)) {
notify("kernel_set_ucred_authid failed");
if(!send_to_elfldr(decompressed, decompress_size)) {
notify("The elfldr on port 9021 is REQUIRED for etaHEN make sure its running and try again!");
free(decompressed);
return -1;
}
free(decompressed);
return 0;

View File

@@ -63,7 +63,33 @@ 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} hijacker NineS)
target_link_libraries (${PROJECT_NAME} PUBLIC hijacker SceLibcInternal SceSystemService SceNet SceSysmodule SceUserService SceNetCtl SceSysCore ScePad SceVideoOut kernel_sys SceAppInstUtil NineS SceHttp2 SceNet SceSsl z minizip microhttpd)
target_link_libraries(${PROJECT_NAME} PUBLIC
hijacker
SceLibcInternal
SceSystemService
SceNet
SceSysmodule
SceUserService
SceNetCtl
SceSysCore
ScePad
SceVideoOut
kernel_sys
SceAppInstUtil
elfldr
NineS
SceHttp2
SceSsl
z
curl
SelfDecryptor
minizip
microhttpd
psl # For PSL (Public Suffix List) functions
zstd # For ZSTD compression support
crypto # For OpenSSL crypto functions (EVP_*, MD5_*, DES_*)
ssl # For additional SSL functions
)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Add post-build command
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD

View File

@@ -97,6 +97,7 @@ struct CheatMemory
uint64_t Offset; // offset of the patch
ByteArray On; // Data that should be inserted when the cheat is enabled
ByteArray Off; // Data that should be inserted when the cheat is disabled
bool absolute; // New To support section bigger than 0 when ASLR is off // 09/10/2025 xZenithy
};
struct CheatInfo

View File

@@ -141,6 +141,8 @@ typedef struct
bool DPI_v2;
bool klog;
bool disable_toolbox_for_rest;
atomic_bool legacy_cmd_server;
atomic_bool legacy_cmd_server_exit;
uint64_t seconds;
} util_settings;

View File

@@ -19,39 +19,45 @@ along with this program; see the file COPYING. If not, see
#include <stdint.h>
#include <sys/types.h>
#include <machine/reg.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <ps5/kernel.h>
int pt_trace_me(void);
int pt_attach(pid_t pid);
int pt_detach(pid_t pid);
int pt_detach_proc(pid_t pid, int sig);
int pt_attach_proc(pid_t pid);
int pt_step(pid_t pid);
int pt_continue(pid_t pid, int sig);
int pt_getregs(pid_t pid, struct reg *r);
int pt_setregs(pid_t pid, const struct reg *r);
int pt_getregs(pid_t pid, struct reg* r);
int pt_setregs(pid_t pid, const struct reg* r);
int pt_getint(pid_t pid, intptr_t addr);
int pt_copyin(pid_t pid, const void* buf, intptr_t addr, size_t len);
int pt_copyout(pid_t pid, intptr_t addr, void* buf, size_t len);
int pt_setchar(pid_t pid, intptr_t addr, char val);
int pt_setshort(pid_t pid, intptr_t addr, short val);
int pt_setint(pid_t pid, intptr_t addr, int val);
int pt_setlong(pid_t pid, intptr_t addr, long val);
char pt_getchar(pid_t pid, intptr_t addr);
short pt_getshort(pid_t pid, intptr_t addr);
int pt_getint(pid_t pid, intptr_t addr);
long pt_getlong(pid_t pid, intptr_t addr);
long pt_syscall(pid_t pid, int sysno, ...);
long pt_call(pid_t pid, intptr_t addr, ...);
long pt_call2(pid_t pid, intptr_t addr, ...);
intptr_t pt_resolve(pid_t pid, const char* nid);
int pt_backtrace(pid_t pid, char* addr2line, size_t size);
int pt_jitshm_create(pid_t pid, intptr_t name, size_t size, int flags);
int pt_jitshm_alias(pid_t pid, int fd, int flags);
intptr_t pt_mmap(pid_t pid, intptr_t addr, size_t len, int prot, int flags,
int fd, off_t off);
int fd, off_t off);
int pt_msync(pid_t, intptr_t addr, size_t len, int flags);
int pt_munmap(pid_t pid, intptr_t addr, size_t len);
int pt_mprotect(pid_t pid, intptr_t addr, size_t len, int prot);
int pt_socket(pid_t pid, int domain, int type, int protocol);
int pt_setsockopt(pid_t pid, int fd, int level, int optname, intptr_t optval,
uint32_t optlen);
uint32_t optlen);
int pt_bind(pid_t pid, int sockfd, intptr_t addr, uint32_t addrlen);
ssize_t pt_recvmsg(pid_t pid, int fd, intptr_t msg, int flags);
@@ -60,7 +66,10 @@ int pt_close(pid_t pid, int fd);
int pt_dup2(pid_t pid, int oldfd, int newfd);
int pt_rdup(pid_t pid, pid_t other_pid, int fd);
int pt_pipe(pid_t pid, intptr_t pipefd);
void pt_perror(pid_t pid, const char *s);
int pt_errno(pid_t pid);
intptr_t pt_sceKernelGetProcParam(pid_t pid);
intptr_t pt_getargv(pid_t pid);
long pt_call(pid_t pid, intptr_t addr, ...);
long pt_call2(pid_t pid, intptr_t addr, ...);
intptr_t pt_sceKernelGetProcParam(pid_t pid);

View File

@@ -21,6 +21,8 @@ static GameCheat *currentGameCheat = nullptr;
bool monitorGameRunning = false;
pthread_t pthreadMonitor;
extern "C" void notify(bool show_watermark, const char *text, ...);
//
// This function is used to fix the mc4 decrypted xml file
//
@@ -508,6 +510,18 @@ GameCheat *CheatManager::LoadCheat(CheatMetadata *meta,
return gameCheats;
}
typedef struct
{
uint64_t pad0;
char version_str[0x1C];
uint32_t version;
uint64_t pad1;
} OrbisKernelSwVersion;
extern "C" {
int sceKernelGetProsperoSystemSwVersion(OrbisKernelSwVersion *version);
}
//
// Enable/Disable cheat based on the current cheat state
//
@@ -517,6 +531,10 @@ bool CheatManager::ToggleCheat(int pid, const std::string &title_id,
return false;
}
OrbisKernelSwVersion sys_ver;
sceKernelGetProsperoSystemSwVersion(&sys_ver);
int fw = (sys_ver.version >> 16);
if (cheat_index < 0 || cheat_index > currentGameCheat->cheats.size()) {
etaHEN_log("Cheat index %d is 0 or greater than the size", cheat_index);
return false;
@@ -524,8 +542,9 @@ bool CheatManager::ToggleCheat(int pid, const std::string &title_id,
bool status = true;
CheatInfo &cheat = currentGameCheat->cheats[cheat_index];
etaHEN_log("Toggling cheat %s", cheat.name.c_str());
module_info_t *target_mod = get_module_handle(pid, cheat.module_name.c_str());
etaHEN_log("Target module name: %s", cheat.module_name.c_str());
if (!target_mod) {
etaHEN_log("CheatManager::ToggleCheat: Unable to find %s of cheat %s",
cheat.module_name.c_str(), title_id.c_str());
@@ -546,6 +565,14 @@ bool CheatManager::ToggleCheat(int pid, const std::string &title_id,
free(ps2Lib);
}
int pt_ret = 0;
if (fw >= 0x840) {
if (pt_attach_proc(pid) < 0) {
etaHEN_log("Unable to ptrace into %d, aborting cheat...", pid);
return false;
}
}
//
// Used for Fixing master code references
//
@@ -586,12 +613,23 @@ bool CheatManager::ToggleCheat(int pid, const std::string &title_id,
//
// Search inside the mcPatch where the current cheat modification starts
//
uint64_t mcAddress = baseAddress + mcPatch.Offset;
uint64_t mcAddress = mcPatch.absolute ? mcPatch.Offset : baseAddress + mcPatch.Offset; // 09/10/2025 xZenithy
std::vector<uint8_t> vPatchedCode(mcPatch.On.size());
//
// Copy cheat master code
//
mdbg_copyout(pid, mcAddress, vPatchedCode.data(), mcPatch.On.size());
if (fw >= 0x840) {
etaHEN_log("Master code address: %#02lx", mcAddress);
kernel_mprotect(pid, mcAddress, mcPatch.On.size(), PROT_READ | PROT_WRITE | PROT_EXEC);
etaHEN_log("Copying master code...");
pt_ret = pt_copyout(pid, mcAddress, vPatchedCode.data(), mcPatch.On.size());
etaHEN_log("Master code copied... errno %d %d", pt_ret, pt_errno(pid));
}
else {
mdbg_copyout(pid, mcAddress, vPatchedCode.data(), mcPatch.On.size());
}
//
// Search the cheat inside the Master Code, the "Off" field holds the
// original MC code
@@ -622,16 +660,25 @@ bool CheatManager::ToggleCheat(int pid, const std::string &title_id,
//
// If the address is higher
//
uint64_t addr = isPS2 ? mod.Offset : baseAddress + mod.Offset;
uint64_t addr = (isPS2 || mod.absolute) ? mod.Offset : baseAddress + mod.Offset; // Absolute address controled by bolean variables // 09/10/2025 xZenithy
etaHEN_log("Offset: %#02lx\n", mod.Offset);
etaHEN_log("Addr: %#02lx\n", addr);
etaHEN_log("Offset: %#02lx", mod.Offset);
etaHEN_log("Addr: %#02lx", addr);
// etaHEN_log("Base address: %#02lx %s\n", baseAddress,
// target_mod->filename);
bool fixCodeCave = false;
// bool try_fix_asrl = false;
if (cheat.enabled) {
mdbg_copyin(pid, mod.Off.data(), addr, mod.Off.size());
etaHEN_log("Disabling cheat...");
if (fw >= 0x840) {
kernel_mprotect(pid, addr, patch_size, PROT_READ | PROT_WRITE | PROT_EXEC);
etaHEN_log("Restoring original data...");
pt_ret = pt_copyin(pid, mod.Off.data(), addr, mod.Off.size());
}
else {
mdbg_copyin(pid, mod.Off.data(), addr, mod.Off.size());
}
etaHEN_log("Cheat %s disabled, errno %d %d", cheat.name.c_str(), pt_ret, pt_errno(pid));
enabled = false;
} else {
uint8_t *patch_data = mod.On.data();
@@ -650,12 +697,13 @@ bool CheatManager::ToggleCheat(int pid, const std::string &title_id,
//
// Fix offset on code caves that don't exist due the process layout
//
// addr = baseAddress + mod.Offset;
if (pt_attach(pid) < 0) {
etaHEN_log("Unable to ptrace into %d, aborting cheat...", pid);
status = false;
break;
if (fw < 0x840) {
if (pt_attach_proc(pid) < 0) {
etaHEN_log("Unable to ptrace into %d, aborting cheat...", pid);
return false;
}
}
// addr = baseAddress + mod.Offset;
uint64_t mem = pt_mmap(pid, ROUND_PG_DOWN(addr),
ROUND_PG(mod.On.size()), PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYNMOUS, -1, 0);
@@ -669,12 +717,28 @@ bool CheatManager::ToggleCheat(int pid, const std::string &title_id,
etaHEN_log("Making it executable...");
kernel_mprotect(pid, mem, ROUND_PG(mod.On.size()),
PROT_READ | PROT_EXEC | PROT_WRITE);
pt_detach(pid);
if (fw < 0x840) {
pt_detach_proc(pid, 0);
}
etaHEN_log("Ready to continue...");
}
mdbg_copyin(pid, patch_data, addr, patch_size);
mdbg_copyout(pid, addr, dump_on, patch_size);
etaHEN_log("Enabling cheat %s...", cheat.name.c_str());
if (fw >= 0x840) {
kernel_mprotect(pid, addr, patch_size, PROT_READ | PROT_WRITE | PROT_EXEC);
etaHEN_log("Applying patch...");
pt_ret = pt_copyin(pid, patch_data, addr, patch_size);
etaHEN_log("Patch applied, verifying... errrno %d %d", pt_ret, pt_errno(pid));
kernel_mprotect(pid, addr, patch_size, PROT_READ | PROT_WRITE | PROT_EXEC);
etaHEN_log("Reading back patched data...");
pt_ret = pt_copyout(pid, addr, dump_on, patch_size);
etaHEN_log("Data read back, comparing... errrno %d %d", pt_ret, pt_errno(pid));
}
else {
mdbg_copyin(pid, patch_data, addr, patch_size);
mdbg_copyout(pid, addr, dump_on, patch_size);
}
enabled = true;
//
// Checking if patch was applied successfully
@@ -706,7 +770,12 @@ bool CheatManager::ToggleCheat(int pid, const std::string &title_id,
}
cheat.enabled = enabled;
// pt_continue(pid);
if (fw >= 0x840) {
pt_ret = pt_detach_proc(pid, 0);
etaHEN_log("Detached from process %d, errno %d %d", pid, pt_ret,
pt_errno(pid));
}
return status;
}
@@ -1016,7 +1085,7 @@ CheatManager::CheatManagerFormats::ParseXMLCheat(const std::string &xml,
std::string section = cheatLine.child("Section").text().as_string();
std::string on = cheatLine.child("ValueOn").text().as_string();
std::string off = cheatLine.child("ValueOff").text().as_string();
std::string absolute = cheatLine.child("Absolute").text().as_string(); // 09/10/2025 xZenithy
// etaHEN_log("Offset: %s\nSection: %s\nOn: %s\nOff: %s\n",
// offset.c_str(),
// section.c_str(),
@@ -1039,6 +1108,7 @@ CheatManager::CheatManagerFormats::ParseXMLCheat(const std::string &xml,
mem.Offset = strtol(offset.c_str(), NULL, 16);
mem.On = Converters::unhexlify(on);
mem.Off = Converters::unhexlify(off);
mem.absolute = !absolute.empty(); // false if missing, true absolute address // 09/10/2025 xZenithy
}
if (section.size()) {

View File

@@ -20,7 +20,8 @@ along with this program; see the file COPYING. If not, see
#include <sys/signal.h>
#include <freebsd-helper.h>
#include <libgen.h>
#include <ps5/klog.h>
#include "pt.h"
typedef struct app_info {
uint32_t app_id;
@@ -30,14 +31,13 @@ typedef struct app_info {
char unknown2[0x3c];
} app_info_t;
void *runCommandNControlServer(void *r);
int launchApp(const char *titleId);
int sceSystemServiceGetAppId(const char *title_id);
void free(void *ptr);
void *malloc(size_t size);
int elfldr_set_procname(pid_t pid, const char* name);
int sceKernelGetProcessName(int pid, char *name);
int sceKernelGetAppInfo(int pid, app_info_t *title);
pid_t elfldr_spawn(const char* cwd, int stdio, uint8_t* elf, const char* name);
@@ -63,7 +63,49 @@ atomic_bool not_connected = false;
);
static int
sys_ptrace(int request, pid_t pid, caddr_t addr, int data) {
pid_t mypid = getpid();
uint64_t authid;
int ret;
if (!(authid = kernel_get_ucred_authid(mypid))) {
return -1;
}
if (kernel_set_ucred_authid(mypid, 0x4800000000010003l)) {
return -1;
}
ret = (int)syscall(SYS_ptrace, request, pid, addr, data);
if (kernel_set_ucred_authid(mypid, authid)) {
return -1;
}
return ret;
}
int pt_detach_proc(pid_t pid, int sig) {
if (sys_ptrace(PT_DETACH, pid, 0, sig) == -1) {
return -1;
}
return 0;
}
int pt_attach_proc(pid_t pid) {
if (sys_ptrace(PT_ATTACH, pid, 0, 0) == -1) {
return -1;
}
if (waitpid(pid, 0, 0) == -1) {
return -1;
}
return 0;
}
int get_ip_address(char *ip_address)
{
@@ -105,6 +147,7 @@ void etaHEN_log(const char * fmt, ...) {
}
printf("[etaHEN utils]: %s", msg); // msg already includes a newline
klog_printf("%s", msg); // msg already includes a newline
int fd = open("/data/etaHEN/etaHEN_util_daemon.log", O_WRONLY | O_CREAT | O_APPEND, 0777);
if (fd < 0) {
@@ -221,9 +264,9 @@ static bool mkdir_if_necessary(const char *path) {
return true;
}
bool make_plugin_app(const char *tid, const void *start,
const unsigned int size) {
const unsigned int size)
{
// REDIS->NPXS40028
char sys_app[255];
static const char *json = "{\n"
@@ -238,9 +281,11 @@ bool make_plugin_app(const char *tid, const void *start,
"\"\n"
"}\n";
snprintf(sys_app, sizeof(sys_app), "/system_ex/app/%s", tid);
if (mkdir(sys_app, 0777) == -1) {
if (mkdir(sys_app, 0777) == -1)
{
const int err = errno;
if (err != EEXIST) {
if (err != EEXIST)
{
perror("make_plugin_app mkdir /system_ex/app/");
return false;
}
@@ -250,20 +295,23 @@ bool make_plugin_app(const char *tid, const void *start,
make_hb_elf(tid, start, size);
(void)memset(sys_app, 0, sizeof(sys_app));
snprintf(sys_app, sizeof(sys_app), "/system_ex/app/%s/eboot.bin", tid);
if (!copyFile("/system_ex/app/NPXS40028/eboot.bin", sys_app)) {
if (!copyFile("/system_ex/app/NPXS40028/eboot.bin", sys_app))
{
puts("failed to copy redis eboot.bin");
return false;
}
(void)memset(sys_app, 0, sizeof(sys_app));
snprintf(sys_app, sizeof(sys_app), "/system_ex/app/%s/sce_sys", tid);
if (!mkdir_if_necessary(sys_app)) {
if (!mkdir_if_necessary(sys_app))
{
return false;
}
(void)memset(sys_app, 0, sizeof(sys_app));
snprintf(sys_app, sizeof(sys_app), "/system_ex/app/%s/sce_sys/param.json",
tid);
FILE *fp = fopen(sys_app, "w+");
if (fp == NULL) {
if (fp == NULL)
{
perror("open failed");
return false;
}
@@ -277,96 +325,101 @@ bool make_plugin_app(const char *tid, const void *start,
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;
}
// 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;
}
}
// 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;
}
// 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;
}
}
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;
return true;
}
pid_t find_pid(const char * name) {
pid_t find_pid(const char *name)
{
int mib[4] = {
CTL_KERN,
KERN_PROC,
KERN_PROC_PROC,
0
};
CTL_KERN,
KERN_PROC,
KERN_PROC_PROC,
0};
app_info_t appinfo;
size_t buf_size;
void * buf;
void *buf;
int pid = -1;
// determine size of query response
if (sysctl(mib, 4, NULL,&buf_size, NULL, 0)) {
// size of query response
if (sysctl(mib, 4, NULL, &buf_size, NULL, 0))
{
etaHEN_log("sysctl failed: %s", strerror(errno));
return -1;
}
// allocate memory for query response
if (!(buf = malloc(buf_size))) {
if (!(buf = malloc(buf_size)))
{
etaHEN_log("malloc failed %s", strerror(errno));
return -1;
}
// query the kernel for proc info
if (sysctl(mib, 4, buf,&buf_size, NULL, 0)) {
if (sysctl(mib, 4, buf, &buf_size, NULL, 0))
{
etaHEN_log("sysctl failed: %s", strerror(errno));
free(buf);
return -1;
}
for(void *ptr=buf; ptr<(buf+buf_size);) {
struct kinfo_proc *ki = (struct kinfo_proc*)ptr;
for (void *ptr = buf; ptr < (buf + buf_size);)
{
struct kinfo_proc *ki = (struct kinfo_proc *)ptr;
ptr += ki->ki_structsize;
if (sceKernelGetAppInfo(ki->ki_pid,&appinfo)) {
if (sceKernelGetAppInfo(ki->ki_pid, &appinfo))
{
memset(&appinfo, 0, sizeof(appinfo));
}
if (strcmp(ki->ki_comm, name) == 0) {
if (strcmp(ki->ki_comm, name) == 0)
{
pid = ki->ki_pid;
break;
}
@@ -377,114 +430,207 @@ pid_t find_pid(const char * name) {
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 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) {
bool load_plugin(const char *path)
{
int fd = open(path, O_RDONLY);
if (fd < 0) {
if (fd < 0)
{
etaHEN_log("Failed to open file, %s (error %s)", path, strerror(errno));
return false;
}
struct stat st;
if (fstat(fd, & st) != 0) {
if (fstat(fd, &st) != 0)
{
etaHEN_log("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) {
uint8_t *buf = (uint8_t *)malloc(st.st_size);
if (!buf)
{
etaHEN_log("Failed to allocate memory for Plugin file");
close(fd);
return false;
}
if (read(fd, buf, st.st_size) != st.st_size) {
if (read(fd, buf, st.st_size) != st.st_size)
{
etaHEN_log("Failed to read Plugin file");
free(buf), buf = NULL;
free(buf);
close(fd);
return false;
}
close(fd);
const char* filename = basename(path);
if (strstr(filename, ".elf") != NULL) {
// Handle ELF plugin loading
if (!is_elf_file(buf, st.st_size)) {
etaHEN_log("Invalid ELF file.");
notify(true, "Invalid ELF file: %s", filename);
free(buf), buf = NULL;
return false;
}
const CustomPluginHeader *header = (const CustomPluginHeader *)buf;
const char *filename = basename(path);
pid_t pid = 0;
printf("seeing if elf is running\n");
while ((pid = find_pid(filename)) > 0) {
printf("killing pid %d\n", pid);
if (kill(pid, SIGKILL)) {
perror("kill");
}
break;
}
if (strstr(filename, ".elf") != NULL)
{
etaHEN_log("ELF detected: %s", filename);
printf("loading elf %s\n", filename);
if ((pid = elfldr_spawn("/", STDOUT_FILENO, buf, filename)) >= 0) {
printf(" Launched!\n");
} else {
printf(" Already Running!\n");
}
if (!is_elf_file(buf, st.st_size))
{
etaHEN_log("Invalid ELF file.");
notify(true, "Invalid ELF file: %s", filename);
free(buf);
return false;
}
free(buf), buf = NULL;
char pbuf[256];
snprintf(pbuf, sizeof(pbuf), "/system_tmp/%s.PID", header->titleID);
return true;
}
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 (!is_valid_plugin(buf)) {
if (pid > 0)
{
char name[32];
if (sceKernelGetProcessName(pid, name) < 0)
{
etaHEN_log("Stale plugin PID file detected for %s, removing", header->titleID);
unlink(pbuf);
pid = -1;
}
}
if (pid > 0)
{
etaHEN_log("killing pid %d (plugin: %s)", pid, header->titleID);
kill(pid, SIGKILL);
unlink(pbuf);
}
etaHEN_log("loading elf %s", filename);
pid = elfldr_spawn("/", STDOUT_FILENO, buf, header->titleID);
if (pid >= 0)
etaHEN_log(" Launched!");
else
etaHEN_log(" Already Running!");
free(buf);
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 (pid >= 0);
}
if (!is_valid_plugin(buf))
{
etaHEN_log("Invalid plugin file.");
free(buf), buf = NULL;
free(buf);
return false;
}
const CustomPluginHeader * header = (const CustomPluginHeader * ) buf;
etaHEN_log("============== Plugin info ===============");
etaHEN_log("Plugin Prefix: %s", header->prefix);
etaHEN_log("Plugin TitleID: %s", header->titleID);
etaHEN_log("Plugin Version: %s", header->plugin_version);
etaHEN_log("=========================================");
// Get the address of the ELF header
uint8_t * elf = get_elf_header_address(buf);
char pbuf[256];
snprintf(pbuf, sizeof(pbuf), "/system_tmp/%s.PID", header->titleID);
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)
{
etaHEN_log("Stale plugin PID file detected for %s, removing", header->titleID);
unlink(pbuf);
pid = -1;
}
}
etaHEN_log("seeing if plugin is running");
if (pid > 0)
{
etaHEN_log("killing pid %d (plugin: %s)", pid, header->titleID);
kill(pid, SIGKILL);
unlink(pbuf);
}
uint8_t *elf = get_elf_header_address(buf);
make_plugin_app(header->titleID, elf, st.st_size - sizeof(CustomPluginHeader));
pid_t pid = 0;
etaHEN_log("seeing if plugin is running");
while ((pid = find_pid(header->titleID)) > 0) {
etaHEN_log("killing pid %d", pid);
if (kill(pid, SIGKILL)) {
perror("kill");
}
break;
}
etaHEN_log("loading plugin %s", path);
bool success = false;
if ((success = elfldr_spawn("/", STDOUT_FILENO, elf, header->titleID) >= 0)) {
pid = elfldr_spawn("/", STDOUT_FILENO, elf, header->titleID);
bool success = (pid >= 0);
if (success)
etaHEN_log(" Launched!");
} else {
else
etaHEN_log(" Failed to launch plugin");
f = open(pbuf, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (f >= 0)
{
if (success)
{
char t[32];
int l = snprintf(t, sizeof(t), "%d", pid);
write(f, t, l);
}
else
{
unlink(pbuf);
}
close(f);
}
free(buf), buf = NULL;
free(buf);
return success;
}

View File

@@ -29,11 +29,16 @@ along with this program; see the file COPYING. If not, see
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <ps5/kernel.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
// External C declarations
extern "C" {
#include "common_utils.h"
#include "global.h"
#include "pt.h"
int sceUserServiceGetUserName(const int userId, char *userName, const size_t size);
int _sceApplicationGetAppId(int pid, int32_t *appId);
@@ -336,20 +341,20 @@ static uint32_t pattern_to_byte(const char *pattern, uint8_t *bytes) {
return count;
}
__attribute__((noinline)) static uint8_t *hexstrtochar2(const char *hexstr, size_t *size) {
__attribute__((noinline)) static uint8_t* hexstrtochar2(const char* hexstr, size_t* size) {
if (!hexstr || *hexstr == '\0' || !size || *size < 0) {
return nullptr;
}
uint32_t str_len = strlen(hexstr);
size_t data_len = ((str_len + 1) / 2) * sizeof(uint8_t);
*size = (str_len) * sizeof(uint8_t);
uint8_t *data = (uint8_t *)malloc(*size);
uint8_t* data = (uint8_t*)malloc(*size);
if (!data) {
return nullptr;
}
uint32_t j = 0; // hexstr position
uint32_t i = 0; // data position
@@ -360,7 +365,7 @@ __attribute__((noinline)) static uint8_t *hexstrtochar2(const char *hexstr, size
for (; j < str_len; j += 2, i++) {
data[i] = (uint8_t)(hex_lut[(uint8_t)hexstr[j]] << 4) |
hex_lut[(uint8_t)hexstr[j + 1]];
hex_lut[(uint8_t)hexstr[j + 1]];
}
*size = data_len;
@@ -370,18 +375,18 @@ __attribute__((noinline)) static uint8_t *hexstrtochar2(const char *hexstr, size
void write_bytes32(pid_t pid, uint64_t addr, const uint32_t val) {
etaHEN_log("addr: 0x%lx", addr);
etaHEN_log("val: 0x%08x", val);
dbg::write(pid, addr, (void *)&val, sizeof(uint32_t));
dbg::write(pid, addr, (void*)&val, sizeof(uint32_t));
}
void write_bytes(pid_t pid, uint64_t addr, const char *hexString) {
uint8_t *byteArray = nullptr;
void write_bytes(pid_t pid, uint64_t addr, const char* hexString) {
uint8_t* byteArray = nullptr;
size_t bytesize = 0;
byteArray = hexstrtochar2(hexString, &bytesize);
if (!byteArray) {
return;
}
etaHEN_log("addr: 0x%lx", addr);
dbg::write(pid, addr, byteArray, bytesize);
@@ -391,7 +396,6 @@ void write_bytes(pid_t pid, uint64_t addr, const char *hexString) {
free(byteArray);
}
}
uint8_t *PatternScan(const uint64_t module_base, const uint64_t module_size, const char *signature) {
etaHEN_log("module_base: 0x%lx module_size: 0x%lx", module_base, module_size);
if (!module_base || !module_size) {
@@ -425,211 +429,208 @@ uint8_t *PatternScan(const uint64_t module_base, const uint64_t module_size, con
return nullptr;
}
// Shell patch functions
bool patchShellCore() {
const UniquePtr<Hijacker> executable = Hijacker::getHijacker(get_shellcore_pid());
uintptr_t shellcore_base = 0;
uint64_t shellcore_size = 0;
if (executable) {
shellcore_base = executable->getEboot()->getTextSection()->start();
shellcore_size = executable->getEboot()->getTextSection()->sectionLength();
g_ShellCorePid = executable->getPid();
} else {
}
else {
notify(true, "SceShellCore not found");
return false;
}
bool status = false;
(void)memset(backupShellCoreBytes, 0, sizeof(backupShellCoreBytes));
shellcore_offset_patch = 0;
if (!shellcore_base || !shellcore_size) {
return false;
}
etaHEN_log("allocating 0x%lx bytes", shellcore_size);
char *shellcore_copy = (char *)malloc(shellcore_size);
char* shellcore_copy = (char*)malloc(shellcore_size);
etaHEN_log("shellcore_copy: 0x%p", shellcore_copy);
if (!shellcore_copy) {
etaHEN_log("shellcore_copy is nullptr");
return false;
}
if (dbg::read(g_ShellCorePid, shellcore_base, shellcore_copy, shellcore_size)) {
uint8_t *shellcore_offset_data1 = nullptr;
uint8_t *shellcore_offset_data2 = nullptr;
uint8_t * patch_checker_offset = 0;
uint8_t* shellcore_offset_data1 = nullptr;
uint8_t* shellcore_offset_data2 = nullptr;
uint8_t* patch_checker_offset = 0;
switch (getSystemSwVersion() & VERSION_MASK) {
case V200:
case V220:
case V225:
case V226:
case V230:
case V250:
case V270:
shellcore_offset_data1 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? ec 00 48 89 9d"
);
shellcore_offset_data2 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? b1 00 83 f8"
);
patch_checker_offset = PatternScan(
case V200:
case V220:
case V225:
case V226:
case V230:
case V250:
case V270:
shellcore_offset_data1 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? ec 00 48 89 9d"
);
shellcore_offset_data2 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? b1 00 83 f8"
);
patch_checker_offset = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"55 48 89 e5 41 57 41 56 41 55 41 54 53 48 83 e4 e0 48 81 ec 00 02 00 00 49"
);
break;
case V300:
case V310:
case V320:
case V321:
shellcore_offset_data1 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? 00 01 ?? 89 ?? 40"
);
shellcore_offset_data2 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? c5 00 83 f8 01 75 5f"
);
patch_checker_offset = PatternScan(
);
break;
case V300:
case V310:
case V320:
case V321:
shellcore_offset_data1 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? 00 01 ?? 89 ?? 40"
);
shellcore_offset_data2 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? c5 00 83 f8 01 75 5f"
);
patch_checker_offset = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"55 48 89 e5 41 57 41 56 41 55 41 54 53 48 83 e4 e0 48 81 ec 00 02 00 00 49"
);
break;
case V400:
case V402:
case V403:
case V450:
case V451:
shellcore_offset_data1 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? ?? ?? 4c 89 bd ?? ?? ?? ?? 48 89 9d ?? ?? ?? ??"
);
shellcore_offset_data2 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? ?? ?? 83 f8 01 75 ?? 41 80 3c 24 00"
);
patch_checker_offset = PatternScan(
);
break;
case V400:
case V402:
case V403:
case V450:
case V451:
shellcore_offset_data1 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? ?? ?? 4c 89 bd ?? ?? ?? ?? 48 89 9d ?? ?? ?? ??"
);
shellcore_offset_data2 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? ?? ?? 83 f8 01 75 ?? 41 80 3c 24 00"
);
patch_checker_offset = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"55 48 89 e5 41 57 41 56 41 55 41 54 53 48 83 e4 e0 48 81 ec 00 02 00 00 49"
);
break;
case V500:
case V502:
case V510:
case V550:
shellcore_offset_data1 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? fb 00 85 c0 75 0d e8 ?? ?? fb 00 85 c0 0f 84 47"
);
shellcore_offset_data2 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? c7 00 83 f8 01 75 5e"
);
patch_checker_offset = PatternScan(
);
break;
case V500:
case V502:
case V510:
case V550:
shellcore_offset_data1 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? fb 00 85 c0 75 0d e8 ?? ?? fb 00 85 c0 0f 84 47"
);
shellcore_offset_data2 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? c7 00 83 f8 01 75 5e"
);
patch_checker_offset = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"55 48 89 e5 41 57 41 56 41 55 41 54 53 48 83 e4 e0 48 81 ec e0 01 00 00 49"
);
break;
case V600:
case V602:
case V650:
shellcore_offset_data1 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? ?? 01 4c 89 a5 80"
);
shellcore_offset_data2 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? ?? 00 83 f8 01 75 66"
);
patch_checker_offset = PatternScan(
);
break;
case V600:
case V602:
case V650:
shellcore_offset_data1 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? ?? 01 4c 89 a5 80"
);
shellcore_offset_data2 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? ?? 00 83 f8 01 75 66"
);
patch_checker_offset = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"55 48 89 e5 41 57 41 56 41 55 41 54 53 48 83 e4 e0 48 81 ec e0 01 00 00 49"
);
break;
case V700: case V701: case V720: case V740: case V760: case V761:
shellcore_offset_data1 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? ?? 01 4c 89 b5 80"
);
shellcore_offset_data2 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? d7 00 83 f8 01 0f 85 cd"
);
patch_checker_offset = PatternScan(
);
break;
case V700: case V701: case V720: case V740: case V760: case V761:
shellcore_offset_data1 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? ?? 01 4c 89 b5 80"
);
shellcore_offset_data2 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? d7 00 83 f8 01 0f 85 cd"
);
patch_checker_offset = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"55 48 89 e5 41 57 41 56 41 55 41 54 53 48 83 e4 e0 48 81 ec e0 01 00 00 49 89 cd"
);
break;
case V800: case V820: case V840: case V860:
shellcore_offset_data1 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? ?? 01 85 c0 75 0d e8 ?? ?? ?? 01 85 c0 0f 84 c1"
);
shellcore_offset_data2 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? dc 00 83 f8 01 0f"
);
patch_checker_offset = PatternScan(
);
break;
case V800: case V820:
shellcore_offset_data1 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? ?? 01 85 c0 75 0d e8 ?? ?? ?? 01 85 c0 0f 84 c1"
);
shellcore_offset_data2 = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"e8 ?? ?? dc 00 83 f8 01 0f"
);
patch_checker_offset = PatternScan(
(uint64_t)shellcore_copy, shellcore_size,
"55 48 89 e5 41 57 41 56 41 55 41 54 53 48 81 ec c8 01 00 00 49 89 cd"
);
break;
default:
etaHEN_log("Unknown firmware: 0x%08x", getSystemSwVersion());
break;
}
);
break;
default:
etaHEN_log("Unknown firmware: 0x%08x", getSystemSwVersion());
break;
}
etaHEN_log("shellcore_offset_data1: 0x%p", shellcore_offset_data1);
etaHEN_log("shellcore_offset_data2: 0x%p", shellcore_offset_data2);
etaHEN_log("patch_checker_offset: 0x%p", patch_checker_offset);
// uint64_t addr = shellcore_base + (uint64_t)0x10C01F0;
// write_bytes(g_ShellCorePid, addr, "554889E5B8142618805DC3");
// uint64_t addr = shellcore_base + (uint64_t)0x10C01F0;
// write_bytes(g_ShellCorePid, addr, "554889E5B8142618805DC3");
if (shellcore_offset_data1 && shellcore_offset_data2) {
const uint64_t shellcore_offset_patch1 = shellcore_base +
((uint64_t)shellcore_offset_data1 - (uint64_t)shellcore_copy);
const uint64_t shellcore_offset_patch2 = shellcore_base +
((uint64_t)shellcore_offset_data2 - (uint64_t)shellcore_copy);
write_bytes(g_ShellCorePid, shellcore_offset_patch1, "b801000000");
write_bytes(g_ShellCorePid, shellcore_offset_patch2, "b801000000");
etaHEN_log("Patched shellcore for `/data` mount\n"
"g_ShellCorePid: 0x%08x\n"
"mkdir(\"/user/devbin\", 0777): 0x%08x\n"
"mkdir(\"/user/devlog\", 0777): 0x%08x",
g_ShellCorePid, mkdir("/user/devbin", 0777),
mkdir("/user/devlog", 0777));
"g_ShellCorePid: 0x%08x\n"
"mkdir(\"/user/devbin\", 0777): 0x%08x\n"
"mkdir(\"/user/devlog\", 0777): 0x%08x",
g_ShellCorePid, mkdir("/user/devbin", 0777),
mkdir("/user/devlog", 0777));
}
if(patch_checker_offset){
if (patch_checker_offset) {
shellcore_offset_patch = shellcore_base +
((uint64_t)patch_checker_offset - (uint64_t)shellcore_copy);
etaHEN_log("shellcore_offset_patch: 0x%lx", shellcore_offset_patch);
write_bytes(g_ShellCorePid, shellcore_offset_patch, "554889E5B8142618805DC3");
} else {
#if 1
notify(true, "shellcore offset is not found");
#endif
etaHEN_log("shellcore offset is not found");
}
}
if (shellcore_copy) {
etaHEN_log("freeing shellcore_copy from 0x%p", shellcore_copy);
free(shellcore_copy);
shellcore_copy = nullptr;
}
return status;
}
@@ -749,8 +750,11 @@ void *runCommandNControlServer(void *) {
return nullptr;
}
if(global_conf.legacy_cmd_server)
etaHEN_log("[Daemon LEGACY IPC] Server started on port 9028");
// Accept clients
while (true) {
while (!global_conf.legacy_cmd_server_exit) {
client = accept(s, 0, 0);
if (errno == 0xA3) {
pthread_mutex_lock(&jb_lock);
@@ -758,11 +762,11 @@ void *runCommandNControlServer(void *) {
pthread_mutex_unlock(&jb_lock);
break;
}
if (client > 0) {
if (client > 0 && global_conf.legacy_cmd_server) {
etaHEN_log("[Daemon IPC] Client connected");
while ((readSize = recv(client, reinterpret_cast<void *>(&cmd),
sizeof(cmd), MSG_NOSIGNAL)) > 0) {
if (cmd.magic == 0xDEADBEEF) {
if (cmd.magic == 0xDEADBEEF ) {
cmd_server(client, cmd);
} else {
etaHEN_log("[Daemon IPC] Invalid magic number");
@@ -778,6 +782,11 @@ void *runCommandNControlServer(void *) {
close(s), s = -1;
etaHEN_log("[Daemon IPC] Server stopped");
if (global_conf.legacy_cmd_server_exit) {
global_conf.legacy_cmd_server_exit = false;
return runCommandNControlServer(nullptr);
}
return nullptr;
}
@@ -877,5 +886,6 @@ void patch_checker() {
}
bool patchShellActi() {
return false;
return false;
}

View File

@@ -539,6 +539,7 @@ typedef struct
bool is_2xx = false;
int sceKernelGetProsperoSystemSwVersion(OrbisKernelSwVersion* sw);
int decrypt_self_ftp(const char* input_file_path, const char* output_file_path);
/// Reimplementation of missing functions --------------------------------------
static int decrypt_temp(struct client_info *client, char *file_path, char *buf,
size_t bufsize)
@@ -550,10 +551,6 @@ static int decrypt_temp(struct client_info *client, char *file_path, char *buf,
return -1;
}
if(!is_2xx){
etaHEN_log("Not 2xx so cant decrypt");
return -1;
}
mkdir("/user/temp", 0777);
// Create a unique file name.
@@ -570,7 +567,12 @@ static int decrypt_temp(struct client_info *client, char *file_path, char *buf,
etaHEN_log("Decrypting file \"%s\", using temporary file \"%s\"...",
file_path, temp_path);
decrypt_self(file_path, temp_path);
if (is_2xx)
decrypt_self(file_path, temp_path);
else
decrypt_self_ftp(file_path, temp_path);
strcpy(buf, temp_path);
return 0;
@@ -643,7 +645,7 @@ static int decrypt_rnps(struct client_info *client, char *file_path, char *buf,
// Decrypt the data
if (rnps_decrypt_block(file_buf, (unsigned int)bytes_read) != 0) {
etaHEN_log("Failed DECRYPTION OF %S", file_buf);
// etaHEN_log("Failed DECRYPTION OF %S", file_buf);
result = -4;
goto cleanup;
}
@@ -1797,7 +1799,7 @@ static void cmd_RETR(struct client_info *client) {
else
send_text_file(client, path);
#else
if (is_2xx && is_self(path)) {
if (is_self(path)) {
if ( decrypt_temp(client, path, temp_path, sizeof(temp_path))) {
send_ctrl_msg(client, RC_451);
return;

View File

@@ -28,271 +28,292 @@ along with this program; see the file COPYING. If not, see
#include "../extern/tiny-json/tiny-json.hpp"
#define TEST_USER_AGENT "etaHEN_Downloader"
#include <curl/curl.h>
#define NET_HEAP_SIZE (32 * 1024)
#define MAX_CONCURRENT_REQUEST (4)
#define PRIVATE_CA_CERT_NUM (0)
#define SSL_HEAP_SIZE ((((MAX_CONCURRENT_REQUEST-1) / 3) +1)*256*1024 + 4*1024*PRIVATE_CA_CERT_NUM)
#define HTTP2_HEAP_SIZE ((((MAX_CONCURRENT_REQUEST-1) / 3) +1)*256*1024)
#define COMMIT_HASH_FILE "/data/etaHEN/cheats/cheat_commit_hash.txt"
#define COMMIT_HASH_FILE "/data/etaHEN/cheat_commit_hash.txt"
#define GITHUB_API_URL "https://api.github.com/repos/etaHEN/PS5_Cheats/commits"
uint64_t sceKernelGetProcessTime(void);
int libnetMemId = 0, libsslCtxId = 0, libhttp2CtxId = 0;
// Structure for download progress tracking
struct download_progress {
int fd;
uint64_t last_notify_time;
const uint64_t notify_interval;
const char* filename;
};
int netInit(void) {
/* libnet */
int ret = sceNetInit();
ret = sceNetPoolCreate("simple", NET_HEAP_SIZE, 0);
libnetMemId = ret;
return libnetMemId;
}
// Structure for JSON download
struct json_data {
char* data;
size_t size;
size_t capacity;
};
bool IniliatizeHTTP() {
CURLcode res = curl_global_init(CURL_GLOBAL_DEFAULT);
if (res != CURLE_OK) {
etaHEN_log("curl_global_init() error: %s", curl_easy_strerror(res));
return false;
}
int ret = netInit();
if (ret < 0){
etaHEN_log("netInit() error: 0x%08X", ret);
return false;
}
ret = sceSslInit(SSL_HEAP_SIZE);
if (ret < 0){
etaHEN_log("sceSslInit() error: 0x%08X", ret);
return false;
}
libsslCtxId = ret;
etaHEN_log("libsslCtxId = %x", libsslCtxId);
ret = sceHttp2Init(libnetMemId, libsslCtxId, HTTP2_HEAP_SIZE, MAX_CONCURRENT_REQUEST);
if (ret < 0){
etaHEN_log("sceHttpInit() error: 0x%08X", ret);
return false;
}
libhttp2CtxId = ret;
return true;
etaHEN_log("cURL initialized successfully, version %s", curl_version());
return true;
}
static int skipSSLCallback(int libsslCtxId,
unsigned int verifyErr,
void * const sslCert[],
int certNum,
void *userArg
) {
// Callback function to write downloaded data to file
static size_t write_file_callback(void* contents, size_t size, size_t nmemb, void* userdata) {
struct download_progress* progress = (struct download_progress*)userdata;
size_t real_size = size * nmemb;
etaHEN_log("skipSSLCallback() called");
return 0;
ssize_t written = sceKernelWrite(progress->fd, contents, real_size);
if (written != real_size) {
etaHEN_log("sceKernelWrite() error: written %ld, expected %zu", written, real_size);
return 0; // This will cause curl to abort
}
return real_size;
}
bool download_file(const char* url, const char* dst)
{
int ret = -1;
int libhttp2TmplId = -1;
int reqId = -1;
int statusCode = -1;
int contentLengthType = -1;
uint64_t contentLength = 0;
// Progress callback for file downloads
static int progress_callback(void* clientp, curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow) {
struct download_progress* progress = (struct download_progress*)clientp;
uint64_t current_time = sceKernelGetProcessTime();
// Check if we should notify
if (current_time - progress->last_notify_time >= progress->notify_interval) {
char notifyMsg[256];
float dlnow_mb = (float)dlnow / (1024 * 1024);
if (dltotal > 0) {
float dltotal_mb = (float)dltotal / (1024 * 1024);
int percent = (int)(((float)dlnow / dltotal) * 100);
snprintf(notifyMsg, sizeof(notifyMsg),
"Downloading the cheats repo:..\n%.1f/%.1f MB (%d%%)",
dlnow_mb, dltotal_mb, percent);
}
else {
snprintf(notifyMsg, sizeof(notifyMsg),
"Downloading the cheats repo...\n%.1f MB Downloaded",
dlnow_mb);
}
notify(true, notifyMsg);
progress->last_notify_time = current_time;
}
return 0; // Return 0 to continue
}
bool download_file(const char* url, const char* dst) {
CURL* curl;
CURLcode res;
bool success = false;
// For notification timing
uint64_t last_notify_time = 0;
uint64_t current_time = 0;
const uint64_t notify_interval = 6 * 1000000; // 6 seconds in microseconds
char notifyMsg[1000];
const char* filename = strrchr(dst, '/');
filename = filename ? filename + 1 : dst; // Get just the filename without the path
// Remove destination file if it exists
unlink(dst);
// Create HTTP template
libhttp2TmplId = sceHttp2CreateTemplate(libhttp2CtxId, TEST_USER_AGENT,
SCE_HTTP2_VERSION_2_0, true);
if (libhttp2TmplId < 0) {
etaHEN_log("sceHttp2CreateTemplate() error: 0x%08X", libhttp2TmplId);
goto error;
}
// Disable SSL options if needed
ret = sceHttp2SetSslCallback(libhttp2TmplId, skipSSLCallback, NULL);
if (ret < 0) {
etaHEN_log("sceHttp2SslDisableOption() error: 0x%08X", ret);
goto error;
}
// Create HTTP request
ret = sceHttp2CreateRequestWithURL(libhttp2TmplId, "GET", url, 0);
if (ret < 0) {
etaHEN_log("sceHttp2CreateRequestWithURL() error: 0x%08X", ret);
goto error;
}
reqId = ret;
// Send the request
ret = sceHttp2SendRequest(reqId, NULL, 0);
if (ret < 0) {
etaHEN_log("sceHttp2SendRequest() error: 0x%08X", ret);
goto error;
}
// Get status code
ret = sceHttp2GetStatusCode(reqId, &statusCode);
if (ret < 0) {
etaHEN_log("sceHttp2GetStatusCode() error: 0x%08X", ret);
goto error;
}
etaHEN_log("Response status code: %d", statusCode);
if (statusCode != 200) {
etaHEN_log("HTTP error: unexpected status code %d", statusCode);
goto error;
}
// Get content length
ret = sceHttp2GetResponseContentLength(reqId, &contentLengthType, &contentLength);
if (ret < 0) {
etaHEN_log("sceHttp2GetResponseContentLength() error: 0x%08X", ret);
goto error;
}
if (contentLengthType == SCE_HTTP2_CONTENTLEN_EXIST) {
etaHEN_log("Content-Length: %llu bytes", contentLength);
} else {
etaHEN_log("Content-Length not available");
}
// Open file for writing
int fd = sceKernelOpen(dst, O_WRONLY | O_CREAT, 0777);
if (fd < 0) {
etaHEN_log("Failed to open destination file: %s (error: 0x%08X)", dst, fd);
goto error;
return false;
}
// Initialize progress display
etaHEN_log("Downloading %s to %s", url, dst);
etaHEN_log("Progress: 0%%");
// Initialize progress structure
struct download_progress progress = {
.fd = fd,
.last_notify_time = sceKernelGetProcessTime(),
.notify_interval = 6 * 1000000, // 6 seconds in microseconds
.filename = strrchr(dst, '/') ? strrchr(dst, '/') + 1 : dst
};
// Initialize curl
curl = curl_easy_init();
if (!curl) {
etaHEN_log("curl_easy_init() failed");
sceKernelClose(fd);
return false;
}
// Initial notification
char notifyMsg[256];
const char *filename = strrchr(dst, '/');
filename = filename ? filename + 1 : dst; // Get just the filename without the path
snprintf(notifyMsg, sizeof(notifyMsg), "Downloading '%s' ...", filename);
notify(true, notifyMsg);
// Get current time for notification timing
last_notify_time = sceKernelGetProcessTime();
// Read data and write to file
char buf[4096];
int total_read = 0;
while (true) {
int read = sceHttp2ReadData(reqId, buf, sizeof(buf));
if (read < 0) {
etaHEN_log("sceHttp2ReadData() error: 0x%08X", read);
sceKernelClose(fd);
goto error;
}
if (read == 0) {
// Download complete
etaHEN_log("Download complete: %d bytes", total_read);
break;
}
ret = sceKernelWrite(fd, buf, read);
if (ret < 0 || ret != read) {
etaHEN_log("sceKernelWrite() error: 0x%08X", ret);
sceKernelClose(fd);
goto error;
}
total_read += read;
// Get current time to check if we should notify
current_time = sceKernelGetProcessTime();
// Update progress and check for notification interval
if (current_time - last_notify_time >= notify_interval) {
// Format size in a readable way
float total_mb = (float)total_read / (1024 * 1024);
if (contentLengthType == SCE_HTTP2_CONTENTLEN_EXIST && contentLength > 0) {
float total_size_mb = (float)contentLength / (1024 * 1024);
int progress = (int)(((float)total_read / contentLength) * 100);
snprintf(notifyMsg, sizeof(notifyMsg),
"Downloading '%s':..\n%.1f/%.1f MB (%d%%)",
filename, total_mb, total_size_mb, progress);
} else {
snprintf(notifyMsg, sizeof(notifyMsg),
"Downloading '%s'...\n%.1f MB Downloaded",
filename, total_mb);
}
etaHEN_log("Downloading %s to %s", url, dst);
// Set curl options
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_file_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &progress);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_callback);
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &progress);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_USERAGENT, TEST_USER_AGENT);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // Skip SSL verification
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 300L); // 5 minute timeout
// Perform the request
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
etaHEN_log("curl_easy_perform() failed: %s", curl_easy_strerror(res));
notify(true, "Failed to download the %s!\n\nCheck your internet connection and try again.\nError: %s", filename, curl_easy_strerror(res));
}
else {
// Check HTTP response code
long response_code;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
etaHEN_log("Response status code: %ld", response_code);
if (response_code == 200) {
// Get download size info
curl_off_t download_size;
curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD_T, &download_size);
snprintf(notifyMsg, sizeof(notifyMsg),
"Successfully downloaded the %s\nTotal Size: %.1f MB", filename,
(float)download_size / (1024 * 1024));
notify(true, notifyMsg);
last_notify_time = current_time;
etaHEN_log("Download complete: %lld bytes", download_size);
success = true;
}
else {
etaHEN_log("HTTP error: unexpected status code %ld", response_code);
notify(true, "Failed to download the %s!\n\nServer returned an error.", filename);
}
}
// Final notification
snprintf(notifyMsg, sizeof(notifyMsg),
"Successfully downloaded '%s'\nTotal Size: %.1f MB",
filename, (float)total_read / (1024 * 1024));
notify(true, notifyMsg);
etaHEN_log("Download complete '%s': %d bytes", filename, total_read);
// Cleanup
curl_easy_cleanup(curl);
sceKernelClose(fd);
success = true;
error:
// Clean up resources
if (reqId > 0) {
int tmpRet = sceHttp2DeleteRequest(reqId);
if (tmpRet < 0) {
etaHEN_log("sceHttp2DeleteRequest() error: 0x%08X", tmpRet);
}
}
if (libhttp2TmplId > 0) {
int tmpRet = sceHttp2DeleteTemplate(libhttp2TmplId);
if (tmpRet < 0) {
etaHEN_log("sceHttp2DeleteTemplate() error: 0x%08X", tmpRet);
}
}
if (!success) {
// Notify on error
notify(true, "Failed to download [%s]!\n\nCheck your internet connection and try again.", filename);
}
return success;
}
// Callback function to write JSON data to memory
static size_t write_json_callback(void* contents, size_t size, size_t nmemb, void* userdata) {
struct json_data* json = (struct json_data*)userdata;
size_t real_size = size * nmemb;
// Resize buffer if needed
if (json->size + real_size >= json->capacity) {
size_t new_capacity = json->capacity * 2;
if (new_capacity < json->size + real_size + 1) {
new_capacity = json->size + real_size + 1;
}
char* new_data = realloc(json->data, new_capacity);
if (!new_data) {
etaHEN_log("Failed to reallocate memory for JSON data");
return 0; // This will cause curl to abort
}
json->data = new_data;
json->capacity = new_capacity;
}
// Copy data
memcpy(json->data + json->size, contents, real_size);
json->size += real_size;
json->data[json->size] = '\0'; // Null terminate
return real_size;
}
// Function to download JSON data from URL
static char* download_json(const char* url) {
CURL* curl;
CURLcode res;
char* result = NULL;
// Initialize JSON data structure
struct json_data json = {
.data = malloc(1024),
.size = 0,
.capacity = 1024
};
if (!json.data) {
etaHEN_log("Failed to allocate initial memory for JSON data");
return NULL;
}
json.data[0] = '\0';
// Initialize curl
curl = curl_easy_init();
if (!curl) {
etaHEN_log("curl_easy_init() failed");
free(json.data);
return NULL;
}
// Set curl options
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_json_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &json);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_USERAGENT, TEST_USER_AGENT);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // Skip SSL verification
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L); // 30 second timeout
// Perform the request
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
etaHEN_log("curl_easy_perform() failed: %s", curl_easy_strerror(res));
free(json.data);
}
else {
// Check HTTP response code
long response_code;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
if (response_code == 200) {
etaHEN_log("Downloaded %zu bytes of JSON data", json.size);
result = json.data; // Return the data
}
else {
etaHEN_log("HTTP error: unexpected status code %ld", response_code);
free(json.data);
}
}
// Cleanup
curl_easy_cleanup(curl);
return result;
}
// Function to create directory if it doesn't exist
static void ensure_directory(const char *path) {
struct stat st = {0};
static void ensure_directory(const char* path) {
struct stat st = { 0 };
if (stat(path, &st) == -1) {
mkdir(path, 0755);
}
}
// Simple function to extract a zip file
bool extract_zip(const char *zip_path, const char *extract_dir) {
bool extract_zip(const char* zip_path, const char* extract_dir) {
unzFile zip = unzOpen(zip_path);
if (!zip) {
etaHEN_log("Failed to open zip file: %s", zip_path);
notify(true, "Failed to open zip file");
return false;
}
ensure_directory(extract_dir);
// Go to the first file
if (unzGoToFirstFile(zip) != UNZ_OK) {
etaHEN_log("Empty zip file");
@@ -300,62 +321,62 @@ bool extract_zip(const char *zip_path, const char *extract_dir) {
notify(true, "Empty zip file");
return false;
}
// For notification timing
uint64_t last_notify_time = 0;
uint64_t current_time = 0;
const uint64_t notify_interval = 6 * 1000000; // 6 seconds in microseconds
// Count total files for progress reporting
int total_files = 0;
int processed_files = 0;
// First pass - count files
do {
total_files++;
} while (unzGoToNextFile(zip) == UNZ_OK);
// Reset to first file
unzGoToFirstFile(zip);
// Extract the zip filename for notifications
const char *zip_filename = strrchr(zip_path, '/');
const char* zip_filename = strrchr(zip_path, '/');
zip_filename = zip_filename ? zip_filename + 1 : zip_path;
// Initial notification
char notifyMsg[256];
snprintf(notifyMsg, sizeof(notifyMsg), "Preparing to extract the cheats repo (%d files)", total_files);
notify(true, notifyMsg);
etaHEN_log("%s", notifyMsg);
// Get current time for notification timing
last_notify_time = sceKernelGetProcessTime();
char filename[512];
char full_path[1024];
int skip_root = 1; // Flag to skip the root GitHub folder
char root_folder[256] = {0};
char root_folder[256] = { 0 };
int root_folder_len = 0;
// Get the root folder name (first entry)
unz_file_info file_info;
unzGetCurrentFileInfo(zip, &file_info, filename, sizeof(filename), NULL, 0, NULL, 0);
char *first_slash = strchr(filename, '/');
char* first_slash = strchr(filename, '/');
if (first_slash) {
root_folder_len = first_slash - filename + 1;
strncpy(root_folder, filename, root_folder_len);
root_folder[root_folder_len] = '\0';
etaHEN_log("Detected root folder: %s", root_folder);
}
// Reset to the first file
unzGoToFirstFile(zip);
do {
unzGetCurrentFileInfo(zip, &file_info, filename, sizeof(filename), NULL, 0, NULL, 0);
// Skip the root folder if needed
char *actual_filename = filename;
char* actual_filename = filename;
if (skip_root && root_folder_len > 0 && strncmp(filename, root_folder, root_folder_len) == 0) {
actual_filename = filename + root_folder_len;
if (strlen(actual_filename) == 0) {
@@ -363,10 +384,10 @@ bool extract_zip(const char *zip_path, const char *extract_dir) {
continue;
}
}
// Create the output path
snprintf(full_path, sizeof(full_path), "%s/%s", extract_dir, actual_filename);
// Check if this is a directory
if (filename[strlen(filename) - 1] == '/') {
etaHEN_log("Creating directory: %s", full_path);
@@ -374,23 +395,21 @@ bool extract_zip(const char *zip_path, const char *extract_dir) {
processed_files++;
continue;
}
// etaHEN_log("Extracting: %s", full_path);
// Create directories in the path
char *last_slash = strrchr(full_path, '/');
char* last_slash = strrchr(full_path, '/');
if (last_slash) {
*last_slash = '\0';
ensure_directory(full_path);
*last_slash = '/';
}
// Extract the file
if (unzOpenCurrentFile(zip) != UNZ_OK) {
etaHEN_log("Failed to open file in zip");
continue;
}
// Open with POSIX open() instead of fopen()
int out = open(full_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (out == -1) {
@@ -398,150 +417,44 @@ bool extract_zip(const char *zip_path, const char *extract_dir) {
unzCloseCurrentFile(zip);
continue;
}
char buffer[8192];
int bytes;
while ((bytes = unzReadCurrentFile(zip, buffer, sizeof(buffer))) > 0) {
// Use write() instead of fwrite()
write(out, buffer, bytes);
}
// Use close() instead of fclose()
close(out);
unzCloseCurrentFile(zip);
// Increment processed files count
processed_files++;
// Check if it's time to show a notification
current_time = sceKernelGetProcessTime();
if (current_time - last_notify_time >= notify_interval) {
int progress_percent = (processed_files * 100) / total_files;
snprintf(notifyMsg, sizeof(notifyMsg),
"Extracting the cheats: %d/%d files (%d%%)",
processed_files, total_files, progress_percent);
snprintf(notifyMsg, sizeof(notifyMsg),
"Extracting the cheats: %d/%d files (%d%%)",
processed_files, total_files, progress_percent);
notify(true, notifyMsg);
etaHEN_log("%s", notifyMsg);
last_notify_time = current_time;
}
} while (unzGoToNextFile(zip) == UNZ_OK);
// Final notification
snprintf(notifyMsg, sizeof(notifyMsg),
"Cheats Extraction complete (%d files)",
processed_files);
snprintf(notifyMsg, sizeof(notifyMsg),
"Cheats Extraction complete (%d files)",
processed_files);
notify(true, notifyMsg);
etaHEN_log("%s", notifyMsg);
unzClose(zip);
return true;
}
// Function to download JSON data from URL
static char* download_json(const char* url) {
int ret = -1;
int libhttp2TmplId = -1;
int reqId = -1;
int statusCode = -1;
char* json_data = NULL;
// Create HTTP template
libhttp2TmplId = sceHttp2CreateTemplate(libhttp2CtxId, TEST_USER_AGENT,
SCE_HTTP2_VERSION_2_0, true);
if (libhttp2TmplId < 0) {
etaHEN_log("sceHttp2CreateTemplate() error: 0x%08X", libhttp2TmplId);
goto error;
}
// Disable SSL callback
ret = sceHttp2SetSslCallback(libhttp2TmplId, skipSSLCallback, NULL);
if (ret < 0) {
etaHEN_log("sceHttp2SslDisableOption() error: 0x%08X", ret);
goto error;
}
// Create HTTP request
ret = sceHttp2CreateRequestWithURL(libhttp2TmplId, "GET", url, 0);
if (ret < 0) {
etaHEN_log("sceHttp2CreateRequestWithURL() error: 0x%08X", ret);
goto error;
}
reqId = ret;
// Send the request
ret = sceHttp2SendRequest(reqId, NULL, 0);
if (ret < 0) {
etaHEN_log("sceHttp2SendRequest() error: 0x%08X", ret);
goto error;
}
// Get status code
ret = sceHttp2GetStatusCode(reqId, &statusCode);
if (ret < 0) {
etaHEN_log("sceHttp2GetStatusCode() error: 0x%08X", ret);
goto error;
}
if (statusCode != 200) {
etaHEN_log("HTTP error: unexpected status code %d", statusCode);
goto error;
}
// Allocate buffer for JSON data (32KB should be enough for commit info)
const int buffer_size = 32768;
json_data = (char*)malloc(buffer_size);
if (!json_data) {
etaHEN_log("Failed to allocate memory for JSON data");
goto error;
}
// Read JSON data
char buf[4096];
int total_read = 0;
while (total_read < buffer_size - 1) {
int read = sceHttp2ReadData(reqId, buf, sizeof(buf));
if (read < 0) {
etaHEN_log("sceHttp2ReadData() error: 0x%08X", read);
free(json_data);
json_data = NULL;
goto error;
}
if (read == 0) {
break; // Download complete
}
// Make sure we don't overflow the buffer
if (total_read + read >= buffer_size - 1) {
read = buffer_size - 1 - total_read;
}
memcpy(json_data + total_read, buf, read);
total_read += read;
if (total_read >= buffer_size - 1) {
break;
}
}
json_data[total_read] = '\0';
etaHEN_log("Downloaded %d bytes of JSON data", total_read);
error:
// Clean up resources
if (reqId > 0) {
sceHttp2DeleteRequest(reqId);
}
if (libhttp2TmplId > 0) {
sceHttp2DeleteTemplate(libhttp2TmplId);
}
return json_data;
}
// Function to extract SHA from JSON response
static bool extract_commit_sha(const char* json_data, char* sha_buffer, size_t buffer_size) {
if (!json_data || !sha_buffer) {

View File

@@ -1220,7 +1220,7 @@ ftp_serve(uint16_t port) {
* Launch payload.
**/
void *start_j_ftp(void* args) {
uint16_t port = 2121;
uint16_t port = 1337;
printf("FTP server was compiled at %s %s\n", __DATE__, __TIME__);

View File

@@ -29,6 +29,8 @@ typedef struct app_info {
char unknown2[0x3c];
} app_info_t;
pthread_t cmd_server = 0;
extern "C" {
#define DEBUG_AUTHID 0x4800000000000006
@@ -136,7 +138,8 @@ void LoadSettings(void) {
const char* lite_mode = ini_parser_get(&parser, "Settings.LiteMode", "0");
const char* DPI_v2 = ini_parser_get(&parser, "Settings.DPI_v2", "0");
const char* Klog_str = ini_parser_get(&parser, "Settings.Klog", "0");
const char* toolbox_for_rest = ini_parser_get(&parser, "Settings.disable_toolbox_auto_start_for_rest_mode", "0");
const char* toolbox_for_rest = ini_parser_get(&parser, "Settings.disable_toolbox_auto_start_for_rest_mode", "0");\
const char* legacy_cmd_server_str = ini_parser_get(&parser, "Settings.legacy_cmd_server", "0");
global_conf.discord_rpc = discord_rpc_str ? atoi(discord_rpc_str) : 0;
global_conf.allow_data = allow_data_n_sandbox ? atoi(allow_data_n_sandbox) : 0;
@@ -148,6 +151,7 @@ void LoadSettings(void) {
global_conf.toolbox_auto_start = atoi(ini_parser_get(&parser, "Settings.toolbox_auto_start", "1"));
global_conf.klog = Klog_str ? atoi(Klog_str) : 0;
global_conf.disable_toolbox_for_rest = toolbox_for_rest ? atoi(toolbox_for_rest) : 0;
global_conf.legacy_cmd_server = legacy_cmd_server_str ? atoi(legacy_cmd_server_str) : 0;
if (if_exists("/mnt/usb0/toolbox_auto_start"))
global_conf.toolbox_auto_start = false;
@@ -166,7 +170,7 @@ bool sceKernelIsTestKit() {
bool patchShellCoreTEST();
int main(void) {
pthread_t cmd_server = 0, ipc_server = 0, cheat_cache = 0;//, j_ftp = 0;
pthread_t ipc_server = 0, cheat_cache = 0;//, j_ftp = 0;
char tmp_buf[200];
sceNetCtlInit();
@@ -196,6 +200,7 @@ int main(void) {
global_conf.toolbox_auto_start = true;
global_conf.DPI_v2 = false;
global_conf.klog = true;
global_conf.legacy_cmd_server_exit = false;
unlink("/data/etaHEN/etaHEN_util_daemon.log");
unlink("/data/etaHEN/etaHEN_util_crash.log");
@@ -206,16 +211,16 @@ int main(void) {
LoadSettings();
if(sceKernelIsTestKit()){
etaHEN_log("Kit detected, patching acti time...");
patchShellActi();
}
if (global_conf.allow_data) {
etaHEN_log("Allowing data in sandbox");
patchShellCore();
etaHEN_log("Patched shellcore");
}
if(sceKernelIsTestKit()){
etaHEN_log("Kit detected, patching acti time...");
patchShellActi();
}
start_ip_thread();
pthread_create(&ipc_server, NULL, IPC_loop, NULL);
@@ -276,7 +281,7 @@ int main(void) {
start_klog();
}
etaHEN_log("started klog thread...");
etaHEN_log("Starting CMD thread...");
pthread_create(&cmd_server, NULL, runCommandNControlServer, NULL);
etaHEN_log("loading settings...");
LoadSettings();

View File

@@ -46,6 +46,8 @@ extern bool is_handler_enabled;
#include <sfo.hpp>
#include <sstream>
extern pthread_t cmd_server;
void* runCommandNControlServer(void*);
// pop -Winfinite-recursion error for this func for clang
#define MB(x) ((size_t)(x) << 20)
@@ -407,7 +409,19 @@ void handleIPC(struct clientArgs *client, std::string &inputStr,
SfoReader sfo(sfo_data);
// VERSION key holds the original version, it doesn't change if updated
game_version = sfo.GetValueFor<std::string>("APP_VER");
try {
std::string version_str = sfo.GetValueFor<std::string>("VERSION");
std::string app_ver_str = sfo.GetValueFor<std::string>("APP_VER");
float version_val = std::stof(version_str);
float app_ver_val = std::stof(app_ver_str);
game_version = (version_val > app_ver_val) ? version_str : app_ver_str;
}
catch (const std::exception& e) {
// Fallback to APP_VER if there's an issue
game_version = sfo.GetValueFor<std::string>("APP_VER");
}
}
etaHEN_log("Version: %s", game_version.c_str());
@@ -518,10 +532,12 @@ void handleIPC(struct clientArgs *client, std::string &inputStr,
break;
}
case BREW_UTIL_LAUNCH_ELFLDR: {
#if 1
if (elfldr_spawn("/", STDOUT_FILENO, elfldr_start, "elfldr.elf") >= 0) {
reply(sender_app, false);
break;
}
#endif
reply(sender_app, true);
break;
}
@@ -531,6 +547,7 @@ void handleIPC(struct clientArgs *client, std::string &inputStr,
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",
"/data/etaHEN/cheats.zip")) {
etaHEN_log("Failed to download cheats");
@@ -551,24 +568,41 @@ void handleIPC(struct clientArgs *client, std::string &inputStr,
break;
}
case BREW_UTIL_DOWNLOAD_KSTUFF: {
notify(true, "Downloading kstuff");
if (!download_file("https://github.com/EchoStretch/kstuff/releases/latest/download/kstuff.elf",
"/data/kstuff.elf")) {
etaHEN_log("Failed to download kstuff");
reply(sender_app, true);
break;
}
notify(true, "Attempting to Download kstuff ...");
if (!download_file("https://github.com/EchoStretch/kstuff/releases/latest/download/kstuff.elf",
"/data/etaHEN/kstuff.elf")) {
unlink("/data/etaHEN/kstuff.elf");
etaHEN_log("Failed to download kstuff");
reply(sender_app, true);
break;
}
notify(true, "Successfully downloaded latest kstuff");
reply(sender_app, false);
break;
}
notify(true, "Successfully downloaded latest kstuff");
reply(sender_app, false);
break;
}
case BREW_UTIL_RELOAD_CHEATS: {
notify(true, "Reloading cheats cache");
ReloadCheatsCache(NULL);
reply(sender_app, false);
break;
}
case BREW_UTIL_TOGGLE_LEGACY_CMD_SERVER: {
bool turn_on = (bool)json_getInteger(json_getProperty(my_json, "toggle"));
etaHEN_log("Legacy Command Server toggle: %d", turn_on);
if (turn_on) {
notify(true, "Legacy Command Server Enabled");
global_conf.legacy_cmd_server = true;
global_conf.legacy_cmd_server_exit = true;
} else {
// dont exit server because its used to detect rest mode too
// just stop handling commands
global_conf.legacy_cmd_server = false;
notify(true, "Legacy Command Server Disabled");
}
reply(sender_app, false);
break;
}
case BREW_KILL_DAEMON:{
is_handler_enabled = false;
exit(1337);

BIN
etaHEN-2.4B.bin Normal file

Binary file not shown.