Files
etaHEN/Source Code/util/source/cpp_service.cpp
LightningMods 0fe0407b3a 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
2025-12-01 20:31:16 -05:00

892 lines
28 KiB
C++

/* Copyright (C) 2025 etaHEN / LightningMods
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#include <string>
#include <vector>
#include <unistd.h>
#include <atomic>
#include <pthread.h>
#include <sys/sysctl.h>
#include "dbg/dbg.hpp"
#include "elf/elf.hpp"
#include "hijacker/hijacker.hpp"
#include "ipc.hpp"
#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);
int sceSystemServiceGetAppTitleId(uint32_t appId, char *titleId);
int sceLncUtilGetAppStatusList(AppStatus *outStatusList, uint32_t numEntries, uint32_t *outEntries);
int sceKernelGetProcessName(int pid, char *out);
int sceKernelIsGenuineDevKit();
extern uint8_t shellui_elf_start[];
extern const unsigned int shellui_elf_size;
// Atomic state variables
atomic_bool rest_mode_action = false;
atomic_bool no_network_rest_mode_action = false;
atomic_bool no_network_patched = false;
atomic_bool real_rest_mode_detected = false;
}
// Types and Constants
enum write_flag : uint32_t {
no_flag = 0,
isOffsetConfigureOutput = 1 << 1,
isOffsetVideoModeSupported = 1 << 2,
};
struct Command {
unsigned int magic = 0;
Commands cmd = INVALID_CMD;
int PID = -1;
int ret = 0;
char msg1[0x500];
char msg2[0x500];
};
// Firmware version constants
static constexpr uint32_t VERSION_MASK = 0xffff0000;
static constexpr uint32_t V100 = 0x1000000;
static constexpr uint32_t V101 = 0x1010000;
static constexpr uint32_t V102 = 0x1020000;
static constexpr uint32_t V105 = 0x1050000;
static constexpr uint32_t V110 = 0x1100000;
static constexpr uint32_t V111 = 0x1110000;
static constexpr uint32_t V112 = 0x1120000;
static constexpr uint32_t V113 = 0x1130000;
static constexpr uint32_t V114 = 0x1140000;
static constexpr uint32_t V200 = 0x2000000;
static constexpr uint32_t V220 = 0x2200000;
static constexpr uint32_t V225 = 0x2250000;
static constexpr uint32_t V226 = 0x2260000;
static constexpr uint32_t V230 = 0x2300000;
static constexpr uint32_t V250 = 0x2500000;
static constexpr uint32_t V270 = 0x2700000;
static constexpr uint32_t V300 = 0x3000000;
static constexpr uint32_t V310 = 0x3100000;
static constexpr uint32_t V320 = 0x3200000;
static constexpr uint32_t V321 = 0x3210000;
static constexpr uint32_t V400 = 0x4000000;
static constexpr uint32_t V402 = 0x4020000;
static constexpr uint32_t V403 = 0x4030000;
static constexpr uint32_t V450 = 0x4500000;
static constexpr uint32_t V451 = 0x4510000;
static constexpr uint32_t V500 = 0x5000000;
static constexpr uint32_t V502 = 0x5020000;
static constexpr uint32_t V510 = 0x5100000;
static constexpr uint32_t V550 = 0x5500000;
static constexpr uint32_t V600 = 0x6000000;
static constexpr uint32_t V602 = 0x6020000;
static constexpr uint32_t V650 = 0x6500000;
static constexpr uint32_t V700 = 0x7000000;
static constexpr uint32_t V701 = 0x7010000;
static constexpr uint32_t V720 = 0x7200000;
static constexpr uint32_t V740 = 0x7400000;
static constexpr uint32_t V760 = 0x7600000;
static constexpr uint32_t V761 = 0x7610000;
//new
static constexpr uint32_t V800 = 0x8000000;
static constexpr uint32_t V820 = 0x8200000;
static constexpr uint32_t V840 = 0x8400000;
static constexpr uint32_t V860 = 0x8600000;
static constexpr uint32_t V900 = 0x9000000;
static constexpr uint32_t V905 = 0x9050000;
static constexpr uint32_t V920 = 0x9200000;
static constexpr uint32_t V940 = 0x9400000;
static constexpr uint32_t V960 = 0x9600000;
static constexpr uint32_t V1000 = 0x10000000;
static constexpr uint32_t V1001 = 0x10010000;
static constexpr uint32_t V1020 = 0x10200000;
static constexpr uint32_t V1040 = 0x10400000;
static constexpr uint32_t V1060 = 0x10600000;
// Global variables
char ip_address[40];
pid_t g_ShellCorePid = 0;
char backupShellCoreBytes[5] = {0};
uint64_t shellcore_offset_patch = 0;
int numb_of_tries = 0;
int retries = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t jb_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_t discordRpcServerThread = NULL;
pthread_t ftp = NULL;
pthread_t dpi_thread = NULL;
pthread_t kernelrw_thread = NULL;
extern atomic_bool not_connected;
// Function forward declarations
void *start_ftp(void *args);
void *klog(void *args);
void *krw_server(void *args);
bool RunDPIThread();
void etaHEN_log(const char *fmt, ...);
void notify(bool show_watermark, const char *text, ...);
bool if_exists(const char *path);
bool LoadSettings();
uint32_t getSystemSwVersion();
void check_addr_change(void);
int get_ip_address(char *ip_address);
// Hex lookup table for string-to-byte conversion
const uint8_t hex_lut[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
// Process management functions
static pid_t find_pid(const char *name) {
int mib[4] = {1, 14, 8, 0};
pid_t pid = -1;
size_t buf_size;
uint8_t *buf;
if (sysctl(mib, 4, 0, &buf_size, 0, 0)) {
perror("sysctl");
return -1;
}
if (!(buf = (uint8_t *)malloc(buf_size))) {
perror("malloc");
return -1;
}
if (sysctl(mib, 4, buf, &buf_size, 0, 0)) {
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(ki_tdname, name) == 0) {
printf("[MATCH] ki_pid: %d, ki_tdname: %s\n", ki_pid, ki_tdname);
pid = ki_pid;
break;
}
}
free(buf);
return pid;
}
int get_shellcore_pid() {
int pid = -1;
size_t NumbOfProcs = 9999;
for (int j = 0; j <= NumbOfProcs; j++) {
char tmp_buf[500];
memset(tmp_buf, 0, sizeof(tmp_buf));
sceKernelGetProcessName(j, tmp_buf);
if (strcmp( "SceShellCore", tmp_buf) == 0) {
pid = j;
break;
}
}
return pid == -1 ? find_pid("SceShellCore") : pid;
}
bool enable_toolbox() {
int wait = 0, DaemonSocket = 0;
const char *path = "/system_tmp/etaHEN_crit_service";
while (!if_exists(path)) {
sleep(1);
if (wait > 20) {
notify(true, "Failed to load the etaHEN toolbox");
return false;
}
wait++;
}
sockaddr_un server;
DaemonSocket = socket(AF_UNIX, SOCK_STREAM, 0);
if (DaemonSocket == -1) {
etaHEN_log("Failed to create socket");
return false;
}
server.sun_family = AF_UNIX;
strncpy(server.sun_path, path, sizeof(server.sun_path) - 1);
if (connect(DaemonSocket, (struct sockaddr *)&server, SUN_LEN(&server)) == -1) {
close(DaemonSocket);
etaHEN_log("Failed to connect to socket");
return false;
}
IPCMessage msg;
msg.cmd = BREW_ENABLE_TOOLBOX;
snprintf(msg.msg, sizeof(msg.msg), "{ \"titleId\": \"ETAH00002\" }");
if (send(DaemonSocket, reinterpret_cast<const void *>(&msg), sizeof(msg),
MSG_NOSIGNAL) < 0) {
close(DaemonSocket);
etaHEN_log("Failed to send message to daemon");
return false;
}
if (recv(DaemonSocket, reinterpret_cast<void *>(&msg), sizeof(msg),
MSG_NOSIGNAL) < 0) {
close(DaemonSocket);
etaHEN_log("Failed to receive message from daemon");
return false;
}
close(DaemonSocket);
return msg.error == 0;
}
bool isProcessAlive(int pid) noexcept {
int mib[]{CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
return sysctl(mib, 4, nullptr, nullptr, nullptr, 0) == 0;
}
bool isUserLoggedIn() {
bool isLoggedIn = false;
UserServiceLoginUserIdList userIdList;
(void)memset(&userIdList, 0, sizeof(UserServiceLoginUserIdList));
if (sceUserServiceGetLoginUserIdList(&userIdList) < 0) {
return false;
}
for (int i = 0; i < 4; i++) {
char username[500] = {0};
int userid = userIdList.user_id[i];
if (userid != -1) {
int ret = sceUserServiceGetUserName(userid, &username[0], sizeof(username));
etaHEN_log("sceUserServiceGetUserName returned %d", ret);
if (ret == 0) {
isLoggedIn = true;
break;
}
}
}
sleep(5);
return isLoggedIn;
}
// Pattern scanning and memory functions
static uint32_t pattern_to_byte(const char *pattern, uint8_t *bytes) {
uint32_t count = 0;
const char *start = pattern;
const char *end = pattern + strlen(pattern);
for (const char *current = start; current < end; ++current) {
if (*current == '?') {
++current;
if (*current == '?') {
++current;
}
bytes[count++] = -1;
} else {
bytes[count++] = strtoul(current, (char **)&current, 16);
}
}
return count;
}
__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);
if (!data) {
return nullptr;
}
uint32_t j = 0; // hexstr position
uint32_t i = 0; // data position
if (str_len % 2 == 1) {
data[i] = (uint8_t)(hex_lut[0] << 4) | hex_lut[(uint8_t)hexstr[j]];
j = ++i;
}
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]];
}
*size = data_len;
return data;
}
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));
}
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);
dbg::read(pid, addr, byteArray, bytesize);
if (byteArray) {
etaHEN_log("freeing byteArray at 0x%p", byteArray);
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) {
return nullptr;
}
uint8_t patternBytes[256];
(void)memset(patternBytes, 0, 256);
int32_t patternLength = pattern_to_byte(signature, patternBytes);
if (patternLength <= 0 || patternLength >= 256) {
etaHEN_log("Pattern length too large or invalid! %i (0x%08x)", patternLength, patternLength);
etaHEN_log("Input Pattern %s", signature);
return nullptr;
}
uint8_t *scanBytes = (uint8_t *)module_base;
for (uint64_t i = 0; i < module_size; ++i) {
bool found = true;
for (int32_t j = 0; j < patternLength; ++j) {
if (scanBytes[i + j] != patternBytes[j] && patternBytes[j] != 0xff) {
found = false;
break;
}
}
if (found) {
etaHEN_log("found pattern at 0x%p", &scanBytes[i]);
return &scanBytes[i];
}
}
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 {
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);
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;
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(
(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(
(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(
(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(
(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(
(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(
(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:
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;
}
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");
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));
}
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");
}
}
if (shellcore_copy) {
etaHEN_log("freeing shellcore_copy from 0x%p", shellcore_copy);
free(shellcore_copy);
shellcore_copy = nullptr;
}
return status;
}
// Command server functions
static void replyError(int sock) {
Command cmd;
cmd.ret = -1;
send(sock, reinterpret_cast<void *>(&cmd), sizeof(cmd), MSG_NOSIGNAL);
}
static void replyOk(int sock) {
const Command cmd{};
send(sock, &cmd, sizeof(cmd), MSG_NOSIGNAL);
}
void cmd_server(int sock, Command &cmd) {
pthread_mutex_lock(&jb_lock);
UniquePtr<Hijacker> spawned = nullptr;
etaHEN_log("command: %u", cmd.cmd);
if (cmd.cmd == 0) {
numb_of_tries++;
}
if (numb_of_tries > 40) {
numb_of_tries = 0;
}
switch (cmd.cmd) {
case JAILBREAK_CMD:
if (cmd.magic != 0xDEADBEEF) {
notify(true, "Jailbreak failed, magic is invaild");
replyError(sock);
break;
}
if (cmd.PID == -1 || !isProcessAlive(cmd.PID)) {
notify(true, "Jailbreak failed, PID is invaild");
replyError(sock);
break;
}
etaHEN_log("WRONG Jailbreak command received: jailbreaking...");
{
do {
spawned = Hijacker::getHijacker(cmd.PID);
if (spawned == nullptr) {
if (isProcessAlive(cmd.PID)) {
etaHEN_log("process died");
break;
}
retries++;
if (retries > 30) {
notify(true, "Jailbreak failed, PID is invaild");
etaHEN_log("Jailbreak failed, PID is invaild");
break;
}
}
etaHEN_log("is null for PID %d", cmd.PID);
} while (spawned == nullptr);
retries = 0;
notify(true, "[Legacy] App has been granted a jailbreak\n\nAn update for "
"this PKG is available");
spawned->jailbreak(true);
etaHEN_log("jailbroke app %s", cmd.msg1);
}
replyOk(sock);
break;
case INVALID_CMD:
puts("invalid command");
replyError(sock);
break;
default:
puts("default command");
notify(true, "Update the PKG you are using before continuing\nGot Command %i",
cmd.cmd);
replyError(sock);
break;
}
pthread_mutex_unlock(&jb_lock);
}
void *runCommandNControlServer(void *) {
int client = -1;
int s = -1;
int readSize = 0;
Command cmd;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1) {
notify(true, "Failed to create socket %s", strerror(errno));
return nullptr;
}
struct sockaddr_in sockaddr;
bzero(&sockaddr, sizeof(sockaddr));
int optval = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(9028);
sockaddr.sin_addr.s_addr = INADDR_ANY;
if (bind(s, (const struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) {
notify(true, "Failed to bind to port 9028 %s", strerror(errno));
return nullptr;
}
if (listen(s, 5) < 0) {
notify(true, "Failed to listen on port 9028 %s", strerror(errno));
return nullptr;
}
if(global_conf.legacy_cmd_server)
etaHEN_log("[Daemon LEGACY IPC] Server started on port 9028");
// Accept clients
while (!global_conf.legacy_cmd_server_exit) {
client = accept(s, 0, 0);
if (errno == 0xA3) {
pthread_mutex_lock(&jb_lock);
rest_mode_action = true;
pthread_mutex_unlock(&jb_lock);
break;
}
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 ) {
cmd_server(client, cmd);
} else {
etaHEN_log("[Daemon IPC] Invalid magic number");
}
}
}
}
if (client >= 0)
close(client), client = -1;
if (s >= 0)
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;
}
// Network monitoring and restart functionality
void check_addr_change(void) {
pthread_mutex_lock(&jb_lock);
char func_ip_address[40];
if (get_ip_address(&func_ip_address[0]) < 0) {
pthread_mutex_unlock(&jb_lock);
return;
}
if (get_ip_address(&ip_address[0]) < 0) {
pthread_mutex_unlock(&jb_lock);
return;
}
bool ip_changed = strcmp(&ip_address[0], &func_ip_address[0]) != 0;
if (ip_changed || rest_mode_action) {
if (ip_changed || !real_rest_mode_detected) {
notify(true, "IP Address changed to %s, restarting server(s)",
func_ip_address);
} else if (rest_mode_action && !no_network_patched && !not_connected &&
real_rest_mode_detected) {
LoadSettings();
etaHEN_log("sleeping for %lld secs", global_conf.seconds);
sleep(global_conf.seconds);
notify(true, "Coming out of Rest Mode detected, restarting server(s)");
etaHEN_log("waiting for logged in user");
while (!isUserLoggedIn()) {
sleep(2);
}
etaHEN_log("user is logged in");
etaHEN_log("Coming out rest mode, activating patches");
if (global_conf.toolbox_auto_start && !global_conf.disable_toolbox_for_rest && !enable_toolbox()) {
notify(true, "Failed to inject toolbox");
}
}
real_rest_mode_detected = not_connected = no_network_patched = rest_mode_action = false;
}
pthread_mutex_unlock(&jb_lock);
}
void *ip_thread(void *arg) {
(void)arg;
do {
sleep(1);
} while (get_ip_address(&ip_address[0]) < 0);
while (true) {
check_addr_change();
sleep(2);
}
}
void start_ip_thread(void) {
pthread_t ip_thread_thr;
pthread_create(&ip_thread_thr, NULL, ip_thread, NULL);
pthread_detach(ip_thread_thr);
}
// System recovery and patch checker
void patch_checker() {
if (!isUserLoggedIn()) {
etaHEN_log("User is not logged in yet, skipping...");
return;
}
LoadSettings();
if(global_conf.disable_toolbox_for_rest){
etaHEN_log("Toolbox auto start for rest mode is disabled");
return;
}
etaHEN_log("sleeping for %lld secs", global_conf.seconds);
sleep(global_conf.seconds);
notify(true, "(No Network) Coming out of Rest Mode detected\nre-activating "
"the etaHEN toolbox...");
etaHEN_log("************************************\n\nShellUI is not "
"patched\n\n************************************");
if (!enable_toolbox()) {
notify(true, "Failed to inject toolbox");
}
no_network_rest_mode_action = false;
no_network_patched = true;
real_rest_mode_detected = false;
}
bool patchShellActi() {
return false;
}