diff --git a/.gitignore b/.gitignore index 2db84a1..c727078 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ CMakeCache.txt aerolib.csv stubber/main.exe stubber/out/ +assets/ +homebrew/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..d23f3c2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "libNidResolver"] + path = libNidResolver + url = https://github.com/astrelsky/libNidResolver.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ebf9ae..dac1fa4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,3 +12,15 @@ add_subdirectory(daemon) add_subdirectory(daemon_shim) add_subdirectory(libhijacker) add_subdirectory(spawner) +add_subdirectory(homebrew) + +# this was too complicated +#include(FetchContent) +#FetchContent_Declare( +# NidResolver +# GIT_REPOSITORY https://github.com/astrelsky/libNidResolver.git +# OVERRIDE_FIND_PACKAGE +#) +#FetchContent_MakeAvailable(NidResolver) + +add_subdirectory(libNidResolver) diff --git a/CMakePresets.json b/CMakePresets.json deleted file mode 100644 index 7143997..0000000 --- a/CMakePresets.json +++ /dev/null @@ -1,103 +0,0 @@ -{ - "buildPresets": [ - { - "hidden": false, - "verbose": true, - "name": "default-build-windows", - "displayName": "DefaultBuild", - "configurePreset": "ps5-base", - "description": "default build" - }, - { - "hidden": false, - "verbose": true, - "name": "default-build-nix", - "displayName": "DefaultBuild", - "configurePreset": "nix-base", - "description": "default build" - } - ], - "configurePresets": [ - { - "name": "ps5-base", - "hidden": true, - "generator": "Ninja", - "binaryDir": "${sourceDir}/build/${presetName}", - "installDir": "${sourceDir}/build/install/${presetName}", - "toolchainFile": "${env:PS5SDK}/cmake/toolchain-ps5.cmake", - "cacheVariables": { - "CMAKE_C_COMPILER": "clang.exe", - "CMAKE_CXX_COMPILER": "clang++.exe" - }, - "condition": { - "type": "equals", - "lhs": "${hostSystemName}", - "rhs": "Windows" - } - }, - { - "name": "nix-base", - "hidden": true, - "generator": "Ninja", - "binaryDir": "${sourceDir}/build/${presetName}", - "installDir": "${sourceDir}/build/install/${presetName}", - "toolchainFile": "${env:PS5SDK}/cmake/toolchain-ps5.cmake", - "cacheVariables": { - "CMAKE_C_COMPILER": "clang", - "CMAKE_CXX_COMPILER": "clang++" - }, - "condition": { - "type": "notEquals", - "lhs": "${hostSystemName}", - "rhs": "Windows" - } - }, - { - "name": "ps5-debug", - "displayName": "PS5 Debug", - "inherits": "ps5-base", - "architecture": { - "value": "x64", - "strategy": "external" - }, - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Debug" - } - }, - { - "name": "ps5-release", - "displayName": "PS5 Release", - "inherits": "ps5-debug", - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Release" - } - }, - { - "name": "linux-debug", - "displayName": "Linux Debug", - "inherits": "nix-base", - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Debug" - }, - "vendor": { - "microsoft.com/VisualStudioRemoteSettings/CMake/1.0": { - "sourceDir": "$env{HOME}/.vs/$ms{projectDirName}" - } - } - }, - { - "name": "macos-debug", - "displayName": "macOS Debug", - "inherits": "nix-base", - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Debug" - }, - "vendor": { - "microsoft.com/VisualStudioRemoteSettings/CMake/1.0": { - "sourceDir": "$env{HOME}/.vs/$ms{projectDirName}" - } - } - } - ], - "version": 3 -} diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 2b6b230..8e42a48 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -62,7 +62,7 @@ set(CMAKE_C_FLAGS "--target=x86_64-freebsd-pc-elf -DPPR -DPS5 -DPS5_FW_VERSION=$ 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 -fPIE -march=znver2 -Wall -Werror") -set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -O3 -pedantic -pedantic-errors") +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}) diff --git a/daemon/source/commands.cpp b/daemon/source/commands.cpp index 5b675b7..8bf9758 100644 --- a/daemon/source/commands.cpp +++ b/daemon/source/commands.cpp @@ -101,7 +101,7 @@ void CommandServer::run(TcpSocket &sock) { } static void __attribute__((constructor)) initUserService() { - static constexpr auto DEFAULT_PRIORITY = 256; + static constexpr auto DEFAULT_PRIORITY = 100; int priority = DEFAULT_PRIORITY; sceUserServiceInitialize(&priority); } diff --git a/daemon/source/elfserver.cpp b/daemon/source/elfserver.cpp deleted file mode 100644 index 3a01cf8..0000000 --- a/daemon/source/elfserver.cpp +++ /dev/null @@ -1,494 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dbg/dbg.hpp" -#include "elf/elf.hpp" -#include "fd.hpp" -#include "hijacker/hijacker.hpp" -#include "hijacker/spawner.hpp" -#include "launcher.hpp" -#include "servers.hpp" -#include "util.hpp" - -static constexpr auto json = R"({ - "applicationCategoryType": 33554432, - "localizedParameters": { - "defaultLanguage": "en-US", - "en-US": { - "titleName": "HomebrewDaemon" - } - }, -)"_sv; - -//static constexpr int STUPID_C_ERROR_VALUE = -1; -static constexpr uint32_t ELF_MAGIC = 0x464C457F; - -//static const char *EBOOT_PATH = "/app0/eboot.bin"; -//static const char *SPAWN_ARGS[] = {NULL}; - -struct AppStatus { - static constexpr auto PAD_SIZE = 28; - unsigned int id; - unsigned char pad[PAD_SIZE]; -}; - -struct LocalProcessArgs { - int fds[2]; - int a; - int b; - unsigned long long pad[2]; -}; - -extern "C" int sceSystemServiceGetAppStatus(AppStatus *status); -extern "C" uint64_t sceSystemServiceAddLocalProcess(unsigned int id, const char *path, const char **argv, LocalProcessArgs *args); -extern "C" int32_t sceSystemServiceGetAppId(const char *titleId); - -enum ProcessType : uint8_t { - INVALID, - DAEMON, - GAME -}; - -enum class ResponseType : int8_t { - OK, - ERROR = -1 -}; - -static bool exists(const char *path) noexcept { - struct stat st{}; - if (stat(path, &st) == -1) { - return false; - } - return S_ISDIR(st.st_mode); -} - -struct TitleId { - static constexpr size_t TITLEID_SIZE = 10; - char id[TITLEID_SIZE]{}; - operator StringView() const noexcept { - return {id, TITLEID_SIZE-1}; - } - explicit operator bool() const noexcept { - return id[0] != '\0'; - } - TitleId &operator++() noexcept { - ++id[TitleId::TITLEID_SIZE-2]; - return *this; - } - bool exists() const noexcept { - String path = "/system_ex/app/"_sv; - path += id; - return ::exists(path.c_str()); - } -}; - -static constexpr TitleId DEFAULT_HOMEBREW_ID{"BREW00000"}; -static constexpr TitleId ASTROS_PLAYGROUND_ID{"PPSA01325"}; - -static pid_t launchApp(const char *titleId, int *appId, ProcessType type); - -static TitleId getNextAvailableTitleId() noexcept { - static constexpr int MAX_HOMEBREW_APPS = 10; - TitleId res = DEFAULT_HOMEBREW_ID; - for (uint8_t i = 1; i < MAX_HOMEBREW_APPS; i++) { - auto appId = sceSystemServiceGetAppId((++res).id); - if (appId == -1) { - printf("Next id: %s\n", res.id); - return res; - } - } - return TitleId{}; -} - -static bool killApp(uint32_t appId) { - uint32_t res = sceLncUtilKillApp(appId); - printf("sceApplicationKill returned 0x%llx\n", res); - return true; -} - -static constexpr int STUPID_C_ERROR = -1; -static constexpr int MKDIR_FLAGS = 0666; - -// NOLINTBEGIN(cppcoreguidelines-owning-memory) - -static bool copyfile(const char *from, const char *to) { - struct stat st{}; - if (stat(from, &st) == STUPID_C_ERROR) { - puts(strerror(errno)); - return false; - } - UniquePtr buf = new uint8_t[st.st_size]; - FILE *fp = fopen(from, "rb"); - if (fp == nullptr) { - puts("open failed"); - puts(strerror(errno)); - return false; - } - fread(buf.get(), 1, st.st_size, fp); - fclose(fp); - fp = fopen(to, "wb+"); - if (fp == nullptr) { - puts("open failed"); - puts(strerror(errno)); - return false; - } - fwrite(buf.get(), 1, st.st_size, fp); - fclose(fp); - return true; -} - -static bool mkdir(const char *path) { - if (::mkdir(path, MKDIR_FLAGS) == STUPID_C_ERROR) { - const int err = errno; - if (err != EEXIST) { - puts(strerror(errno)); - return false; - } - } - return true; -} - -static bool makeHomebrewApp(const StringView &titleId) { - String path = "/system_ex/app/"_sv; - path += titleId; - if (mkdir(path.c_str(), MKDIR_FLAGS) == STUPID_C_ERROR) { - const int err = errno; - if (err != EEXIST) { - perror("makenewapp mkdir"); - return false; - } - return true; - } - String ebootPath = path + "/eboot.bin"; - if (!copyfile("/system_ex/app/NPXS40028/eboot.bin", ebootPath.c_str())) { - puts("failed to copy redis eboot.bin"); - return false; - } - - String sysPath = path + "/sce_sys"_sv; - if (!mkdir(sysPath.c_str())) { - return false; - } - - String newJsonPath = sysPath + "/param.json"_sv; - FILE *fp = fopen(newJsonPath.c_str(), "w+"); - if (fp == nullptr) { - perror("fopen failed"); - return false; - } - if (fwrite(json.c_str(), 1, json.length(), fp) != json.length()) { - puts("failed to write param.json"); - fclose(fp); - return false; - } - - static constexpr auto JSON_TITLE_ID = " \"titleId\": \""_sv; - if (fwrite(JSON_TITLE_ID, 1, JSON_TITLE_ID.length(), fp) != JSON_TITLE_ID.length()) { - puts("failed to write param.json"); - fclose(fp); - return false; - } - - if (fwrite(titleId, 1, titleId.length(), fp) != titleId.length()) { - puts("failed to write param.json"); - fclose(fp); - return false; - } - - static constexpr auto JSON_END = "\"\n}\n"_sv; - if (fwrite(JSON_END, 1, JSON_END.length(), fp) != JSON_END.length()) { - puts("failed to write param.json"); - fclose(fp); - return false; - } - - fclose(fp); - return true; -} - - -// NOLINTEND(cppcoreguidelines-owning-memory) - -void ElfServer::run(TcpSocket &sock) { - puts("ElfServer::run"); - constexpr auto MAX_NAME_SIZE = 32; - ResponseType response = ResponseType::ERROR; - ProcessType type = INVALID; - if (!sock.read(&type, sizeof(type))) { - puts("sock read failed"); - return; - } - - if (type != DAEMON && type != GAME) { - sock.write(&response, sizeof(response)); - puts("Unexpected process type"); - return; - } - - printf("elf type %d\n", type); - - char name[MAX_NAME_SIZE]{}; - if (!sock.read(name, sizeof(name))) { - return; - } - - printf("name: %s\n", name); - - size_t elfSize = 0; - if (!sock.read(&elfSize, sizeof(elfSize))) { - return; - } - - printf("elf size %llu\n", elfSize); - - UniquePtr buf = new uint8_t[elfSize]; - if (!sock.read(buf.get(), sizeof(elfSize))) { - return; - } - if (*reinterpret_cast(buf.get()) != ELF_MAGIC) { - sock.write(&response, sizeof(response)); - puts("invalid elf"); - return; - } - - TitleId id = type == GAME ? ASTROS_PLAYGROUND_ID : getNextAvailableTitleId(); - - if (type == DAEMON) { - // check if titleid exists and if not create it - if (!id) { - sock.write(&response, sizeof(response)); - puts("too many homebrew apps are already running"); - return; - } - - if (!id.exists()) { - - if (!makeHomebrewApp(id)) { - sock.write(&response, sizeof(response)); - puts("failed to create new homebrew app in /system_ex/app"); - return; - } - } - } - - int appId = 0; - pid_t pid = launchApp(id.id, &appId, type); - if (pid == 0) { - puts("spawn failed"); - sock.write(&response, sizeof(response)); - } - - auto hijacker = Hijacker::getHijacker(pid); - if (hijacker == nullptr) { - sock.write(&response, sizeof(response)); - puts("spawn failed"); - return; - } - - puts("setting process name"); - hijacker->getProc()->setName(name); - __builtin_printf("new process %s pid %d\n", hijacker->getProc()->getSelfInfo()->name, hijacker->getPid()); - puts("jailbreaking new process"); - hijacker->jailbreak(); - - Elf elf(hijacker.get(), buf.get()); - - if (!elf.launch()) { - sock.write(&response, sizeof(response)); - puts("failed to load elf"); - killApp(appId); - return; - } - - printf("successfully launched %s\n", name); - - response = ResponseType::OK; - - sock.write(&response, sizeof(response)); -} - -struct LaunchArgs { - const char *titleId; - uint32_t id; - int *appId; -}; - -static void *doLaunchApp(void *ptr) { - UniquePtr args = reinterpret_cast(ptr); - Flag flag = Flag_None; - LncAppParam param{sizeof(LncAppParam), args->id, 0, 0, flag}; - - int err = sceLncUtilLaunchApp(args->titleId, nullptr, ¶m); - printf("sceLncUtilLaunchApp returned 0x%llx\n", (uint32_t)err); - if (err >= 0) { - return nullptr; - } - switch ((uint32_t) err) { - case SCE_LNC_UTIL_ERROR_ALREADY_RUNNING: - printf("app %s is already running\n", args->titleId); - break; - case SCE_LNC_ERROR_APP_NOT_FOUND: - printf("app %s not found\n", args->titleId); - break; - default: - printf("unknown error 0x%llx\n", (uint32_t) err); - break; - } - return nullptr; -} - -static pthread_t launchAppThread(const char *titleId, int *appId) { - puts("launching app"); - uint32_t id = -1; - uint32_t res = sceUserServiceGetForegroundUser(&id); - if (res != 0) { - printf("sceUserServiceGetForegroundUser failed: 0x%llx\n", res); - return nullptr; - } - printf("user id %u\n", id); - - // the thread will clean this up - LaunchArgs *args = new LaunchArgs{titleId, id, appId}; // NOLINT(*) - pthread_t td = nullptr; - pthread_create(&td, nullptr, doLaunchApp, args); - return td; -} - -static int getNextPid(const int lastPid, ProcessType type) { - // get the pid of the new process as soon as it is created - int pid = lastPid; - while (pid == lastPid) { - usleep(1000); // NOLINT(*) - pid = dbg::getAllPids()[0]; - } - if (type == DAEMON) { - return pid; - } - if (dbg::ProcessInfo{pid}.name() == "ScePfs"_sv) { - puts("Skipping ScePfs"); - return getNextPid(pid, type); - } - return pid; -} - -static constexpr uintptr_t ENTRYPOINT_OFFSET = 0x70; - -struct LoopBuilder { - static constexpr size_t LOOB_BUILDER_SIZE = 39; - static constexpr size_t LOOP_BUILDER_TARGET_OFFSET = 2; - uint8_t data[LOOB_BUILDER_SIZE]; - - void setTarget(uintptr_t addr) { - *reinterpret_cast(data + LOOP_BUILDER_TARGET_OFFSET) = addr; - } -}; - -static inline constexpr LoopBuilder SLEEP_LOOP{ - // // 48 b8 xx xx xx xx xx xx xx xx 48 c7 c7 40 42 0f 00 ff d0 eb eb - //loop: - // MOV RAX, _nanosleep - 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // MOV RDI, 1000000000 // 1 second - 0x48, 0xc7, 0xc7, 0x00, 0xca, 0x9a, 0x3b, - // MOV RSI, 0 - 0x48, 0xc7, 0xc6, 0x00, 0x00, 0x00, 0x00, - // PUSH RDI - 0x57, - // PUSH RSI - 0x56, - // CALL RAX - 0xff, 0xd0, - // JMP loop - 0xeb, 0xe2 -}; - - -static uintptr_t getNanosleepOffset(int pid) { - auto hijacker = Hijacker::getHijacker(pid); - uintptr_t addr = hijacker->getLibKernelFunctionAddress(nid::_nanosleep); - return addr - hijacker->getLibKernelBase(); -} - -extern "C" int cpuset_setaffinity(cpulevel_t level, cpuwhich_t which, id_t id, size_t setsize, const void *mask); -extern "C" int rtprio_thread(int function, lwpid_t lwpid, void *rtp); - -static void setaffinity(int value) noexcept { - uint8_t mask[16]{}; - mask[1] = value; - uint16_t prio[]{2, 0x100}; - cpuset_setaffinity(3, 1, -1, 16, mask); - rtprio_thread(1, 0, prio); -} - -static pid_t launchApp(const char *titleId, int *appId, ProcessType type) { - //static constexpr size_t NANOSLEEP_OFFSET = 0x28D0; - setaffinity(1); - LoopBuilder loop = SLEEP_LOOP; - const uintptr_t nanosleepOffset = type == DAEMON ? getNanosleepOffset(getpid()) : 0; - - const int lastPid = dbg::getAllPids()[0]; - - pthread_t td = launchAppThread(titleId, appId); - if (td == nullptr) { - puts("failed to start thread"); - return false; - } - - puts("waiting for new process to spawn"); - - // get the pid of the new process as soon as it is created - int pid = getNextPid(lastPid, type); - - printf("found new pid %d\n", pid); - - UniquePtr spawned = nullptr; - { - // attach to the new process - dbg::Tracer tracer{pid}; - - // run until execve finishes and sends the signal - tracer.run(); - - while (spawned == nullptr) { - // this should grab it first try but I haven't confirmed yet - spawned = Hijacker::getHijacker(pid); - } - - uintptr_t base = 0; - while (base == 0) { - // this should also work first try but not confirmed - base = spawned->getLibKernelBase(); - } - - if (type == DAEMON) { - loop.setTarget(base + nanosleepOffset); - base = spawned->imagebase(); - - // force the entrypoint to an infinite loop so that it doesn't start until we're ready - dbg::write(pid, base + ENTRYPOINT_OFFSET, loop.data, sizeof(loop.data)); - } - - puts("joining"); - pthread_join(td, nullptr); - - puts("finished"); - printf("spawned imagebase 0x%08llx\n", base); - } - - //GameServer gs{pid}; - //gs.TcpServer::run(); - return true; - //sceLncUtilKillApp -} - diff --git a/daemon/source/main.cpp b/daemon/source/main.cpp index dcafbba..43b0339 100644 --- a/daemon/source/main.cpp +++ b/daemon/source/main.cpp @@ -93,7 +93,7 @@ static bool runElf(Hijacker *hijacker, uint8_t *data) { static bool load(UniquePtr &spawned, uint8_t *data) { puts("setting process name"); - spawned->getProc()->setName("HomebrewDaemon"_sv); + spawned->getProc()->setName("HomebrewApp"_sv); __builtin_printf("new process %s pid %d\n", spawned->getProc()->getSelfInfo()->name, spawned->getPid()); puts("jailbreaking new process"); spawned->jailbreak(false); @@ -217,6 +217,8 @@ static bool handleIpc(const int syscore, const int fd) noexcept { } } + puts("handling ipc"); + if (res.cmd != PROCESS_LAUNCHED) { printf("unexpected command %d\n", res.cmd); return result; @@ -320,7 +322,9 @@ class UnixSocket : public FileDescriptor { } }; -void dummy(int) {} +void dummy(int) { + puts("signal received"); +} static void *hookThread(void *args) noexcept { signal(SIGUSR1, dummy); @@ -372,9 +376,9 @@ int main() { pthread_kill(elfHandler, SIGUSR1); pthread_join(elfHandler, nullptr); puts("elf handler done"); - puts("stopping klog server"); - klogServer.stop(); - puts("klog server done"); + //puts("stopping klog server"); + //klogServer.stop(); + //puts("klog server done"); // TODO add elf loader with options for process name and type (daemon/game) // add whatever other crap people may want diff --git a/daemon/source/msg.cpp b/daemon/source/msg.cpp index a0ab5d4..50d01d1 100644 --- a/daemon/source/msg.cpp +++ b/daemon/source/msg.cpp @@ -149,6 +149,7 @@ bool notifyHandlers(const uint32_t prefix, const pid_t pid, const bool isHomebre if (isHomebrew) { // prefix handlers are notified first since they are responsible for loading the elf if applicable // listeners need not be notified + printf("homebrew launched %d\n", pid); return prefixHandlers.handle(prefix, pid); } launchListeners.handle(pid); diff --git a/daemon_shim/CMakeLists.txt b/daemon_shim/CMakeLists.txt index bc62699..c202441 100644 --- a/daemon_shim/CMakeLists.txt +++ b/daemon_shim/CMakeLists.txt @@ -62,7 +62,7 @@ set(CMAKE_C_FLAGS "--target=x86_64-freebsd-pc-elf -DPPR -DPS5 -DPS5_FW_VERSION=$ 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 -fPIE -march=znver2 -Wall -Werror -DMTRW_COMMAND") -set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -O3 -pedantic -pedantic-errors") +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}) diff --git a/daemon_shim/source/main.cpp b/daemon_shim/source/main.cpp index 04116cd..30667cd 100644 --- a/daemon_shim/source/main.cpp +++ b/daemon_shim/source/main.cpp @@ -19,7 +19,6 @@ extern int runCommandProcessor(void *unused); static constexpr int SUSPENDING_ERRNO = 0xa3; static constexpr int ELF_PORT = 9027; -static constexpr int KERNELRW_PORT = 9030; static constexpr int STUPID_C_ERROR_VALUE = -1; extern "C" ssize_t _read(int, void *, size_t); @@ -33,7 +32,7 @@ class Socket { ::close(fd); fd = -1; } -} + } public: Socket() = default; @@ -187,88 +186,6 @@ class FileDescriptor { void release() { fd = -1; } }; -extern "C" void *start_ftp(void*); - -static void *kernelRWHandler(void *unused) noexcept { - (void)unused; - FileDescriptor server = socket(AF_INET, SOCK_STREAM, 0); - if (server == STUPID_C_ERROR_VALUE) { - perror("kernelRWHandler socket"); - return nullptr; - } - int value = 1; - if (setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int)) == STUPID_C_ERROR_VALUE) { - perror("kernelRWHandler setsockopt"); - return nullptr; - } - - struct sockaddr_in server_addr{0, AF_INET, htons(KERNELRW_PORT), {inet_addr("127.0.0.1")}, {}}; - - if (bind(server, reinterpret_cast(&server_addr), sizeof(server_addr)) == STUPID_C_ERROR_VALUE) { - perror("kernelRWHandler bind"); - return nullptr; - } - - if (listen(server, 1) == STUPID_C_ERROR_VALUE) { - perror("kernelRWHandler listen"); - return nullptr; - } - - while (true) { - struct sockaddr client_addr{}; - socklen_t addr_len = sizeof(client_addr); - FileDescriptor conn = ::accept(server, &client_addr, &addr_len); - if (conn == STUPID_C_ERROR_VALUE) { - perror("kernelRWHandler accept"); - continue; - } - - int pid = 0; - int sockets[2]{}; - ssize_t n = read(conn, &pid, sizeof(pid)); - if (n == STUPID_C_ERROR_VALUE) { - if (errno == SUSPENDING_ERRNO) { - return nullptr; - } - perror("kernelRWHandler read"); - continue; - } - if (n != sizeof(pid)) { - puts("kernelRWHandler didn't read enough data for pid"); - continue; - } - n = read(conn, sockets, sizeof(sockets)); - if (n == STUPID_C_ERROR_VALUE) { - if (errno == SUSPENDING_ERRNO) { - return nullptr; - } - perror("kernelRWHandler read"); - continue; - } - if (n != sizeof(sockets)) { - puts("kernelRWHandler didn't read enough data for sockets"); - continue; - } - if (!createReadWriteSockets(pid, sockets)) { - printf("failed to create kernelrw sockets for pid %d\n", pid); - continue; - } - n = write(conn, &kernel_base, sizeof(kernel_base)); - if (n == STUPID_C_ERROR_VALUE) { - if (errno == SUSPENDING_ERRNO) { - return nullptr; - } - perror("kernelRWHandler write"); - continue; - } - if (n != sizeof(sockets)) { - puts("kernelRWHandler didn't write enough data for response"); - continue; - } - } - return nullptr; -} - static void *elfLoader(void *unused) noexcept { (void) unused; puts("starting elfLoader"); @@ -283,17 +200,16 @@ static void *elfLoader(void *unused) noexcept { } } +extern "C" void *start_ftp(void*); + int main() { static constexpr int ONE_SECOND = 1000000; while (true) { pthread_t ftp = nullptr; - pthread_t krw = nullptr; pthread_t elfldr = nullptr; pthread_create(&ftp, nullptr, start_ftp, nullptr); - pthread_create(&krw, nullptr, kernelRWHandler, nullptr); pthread_create(&elfldr, nullptr, elfLoader, nullptr); pthread_join(ftp, nullptr); - pthread_join(krw, nullptr); pthread_join(elfldr, nullptr); usleep(ONE_SECOND); } diff --git a/include/elf/elf.hpp b/include/elf/elf.hpp index e5d8ad1..efe9e25 100644 --- a/include/elf/elf.hpp +++ b/include/elf/elf.hpp @@ -7,19 +7,19 @@ extern "C" { } #include "hijacker.hpp" -#include +#include "util.hpp" -struct SymbolLookupTable; +class ManagedResolver; constexpr auto i = sizeof(Elf64_Dyn); class Elf : Elf64_Ehdr { public: - struct MappedMemory { - uintptr_t mem; - size_t len; - }; + struct MappedMemory { + uintptr_t mem; + size_t len; + }; private: dbg::Tracer tracer; @@ -36,7 +36,7 @@ class Elf : Elf64_Ehdr { size_t textOffset; uintptr_t imagebase; uint8_t *data; - Array libs; + UniquePtr resolver; Array mappedMemory; int jitFd; diff --git a/include/kernel/rtld.hpp b/include/kernel/rtld.hpp index c41a8ab..c9752c8 100644 --- a/include/kernel/rtld.hpp +++ b/include/kernel/rtld.hpp @@ -107,10 +107,6 @@ class SharedLib : public KernelObject { mutable Array sections; mutable UniquePtr meta; - uintptr_t getDynlibData() const { - return get(); - } - public: int pid; @@ -188,7 +184,7 @@ class SharedLib : public KernelObject { RtldMeta *getMetaData() const { if (meta == nullptr) [[unlikely]] { - uintptr_t addr = getDynlibData(); + uintptr_t addr = getMetaDataAddress(); if (addr) { meta = newRtldMeta(imagebase(), addr); } else { @@ -198,6 +194,10 @@ class SharedLib : public KernelObject { return meta.get(); } + uintptr_t getMetaDataAddress() const { + return get(); + } + EhFrameInfo getEhFrameInfo() const { return get(); } @@ -257,6 +257,9 @@ class SharedLibIterable { addr = ptr; return *this; } + uintptr_t getAddress() const noexcept { + return addr; + } }; struct SharedLibIterator { @@ -301,7 +304,7 @@ class SharedObject : KernelObject { return eboot.get(); } - UniquePtr getLib(int handle) { + UniquePtr getLib(int handle) const { for (auto lib : getLibs()) { if (lib->handle() == handle) { return lib.release(); @@ -430,6 +433,10 @@ class rtld::ElfStringTable { Nid getNid(size_t offset) const { return Nid{tbl.get() + offset}; } + + const char *c_str() const noexcept { + return tbl.get(); + } }; class rtld::ElfSymbol : public Elf64_Sym { @@ -526,6 +533,10 @@ class rtld::ElfSymbolTable { size_t length() const { return size; } + + const Elf64_Sym *c_symbols() const noexcept { + return symbols.get(); + } }; namespace { diff --git a/include/util.hpp b/include/util.hpp index 77344a6..f3a159d 100644 --- a/include/util.hpp +++ b/include/util.hpp @@ -40,7 +40,7 @@ class UniquePtr { T *ptr; public: - UniquePtr() = delete; + explicit UniquePtr() : ptr(nullptr) {} UniquePtr(decltype(nullptr)) : ptr(nullptr) {} UniquePtr(T *ptr) : ptr(ptr) {} UniquePtr(const UniquePtr &rhs) = delete; @@ -280,8 +280,12 @@ class String { } public: - explicit String() : data(), size(0), capacity(SSO_MAX) { data.buf[0] = '\0'; } - String(const StringView &view) : size(view.length()), capacity(align(view.length()+1)) { + explicit String() noexcept : data(), size(0), capacity(SSO_MAX) { data.buf[0] = '\0'; } + String(int v) noexcept : data(), size(snprintf(data.buf, SSO_MAX, "%d", v)), capacity(SSO_MAX) { + } + String(uint32_t v) noexcept : data(), size(snprintf(data.buf, SSO_MAX, "%u", v)), capacity(SSO_MAX) { + } + String(const StringView &view) noexcept : size(view.length()), capacity(align(view.length()+1)) { if (is_sso()) { __builtin_memcpy(data.buf, view.c_str(), size); *(data.buf + size) = '\0'; @@ -365,7 +369,7 @@ class String { return *this; // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) } - String operator+(const StringView &rhs) { + String operator+(const StringView &rhs) const noexcept { String res = *this; res += rhs; return res; @@ -446,8 +450,20 @@ class String { grow(i); } } + + String operator+(const String& rhs) const noexcept { + String cpy{*this}; + cpy += rhs; + return cpy; + } }; +inline String operator+(const StringView& lhs, const StringView& rhs) noexcept { + String cpy{lhs}; + cpy += rhs; + return cpy; +} + // NOLINTEND(cppcoreguidelines-owning-memory, cppcoreguidelines-pro-type-member-init) // diff --git a/libNidResolver b/libNidResolver new file mode 160000 index 0000000..02cdbea --- /dev/null +++ b/libNidResolver @@ -0,0 +1 @@ +Subproject commit 02cdbea417d5c792b40fa55e5cab48da5f7bd390 diff --git a/libhijacker/CMakeLists.txt b/libhijacker/CMakeLists.txt index 26d7047..8e76977 100644 --- a/libhijacker/CMakeLists.txt +++ b/libhijacker/CMakeLists.txt @@ -59,11 +59,15 @@ target_compile_options(${PROJECT_NAME} PUBLIC message("========== build: ${PROJECT_NAME} ==========") -set(CMAKE_C_FLAGS "--target=x86_64-freebsd-pc-elf -march=znver2 -mavx2 -DPPR -DPS5 -DPS5_FW_VERSION=${V_FW} ") +add_dependencies(${PROJECT_NAME} NidResolver) + +set(CMAKE_C_FLAGS "--target=x86_64-freebsd-pc-elf -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_CXX_FLAGS "${CMAKE_C_FLAGS} -O3 -march=znver2 -mavx2 -Wall -Wextra -Wmove -Wmost -Werror -pedantic -pedantic-errors -fno-exceptions") +set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -O3 -march=znver2 -Wall -Wextra -Wmove -Wmost -Werror -pedantic -pedantic-errors -fno-exceptions") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g0 -O0") target_include_directories(${PROJECT_NAME} PRIVATE "${D_CWD}/../include") +target_include_directories(${PROJECT_NAME} PRIVATE "${D_CWD}/../libNidResolver/include") +target_link_libraries(${PROJECT_NAME} libNidResolver.a) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/libhijacker/source/elf/elf.cpp b/libhijacker/source/elf/elf.cpp index 8a6a5af..2d4d672 100644 --- a/libhijacker/source/elf/elf.cpp +++ b/libhijacker/source/elf/elf.cpp @@ -32,6 +32,8 @@ extern "C" { extern const uint64_t _pipe_addr; } +#include "nid_resolver/resolver.h" + #ifndef IPV6_2292PKTOPTIONS #define IPV6_2292PKTOPTIONS 25 // NOLINT(*) #endif @@ -54,137 +56,6 @@ constexpr uintptr_t MAP_FAILED = ~0ULL; }; -struct NidKeyValue { - Nid nid; // packed to fit in 12 bytes - uint32_t index; // index into symtab (which is a 32 bit integer) - constexpr int_fast64_t operator<=>(const Nid &rhs) const { - return nid <=> rhs; - } -}; // total size is 16 bytes to allow a memcpy size of a multiple of 16 - -class NidMap { - // this implementation is stupid - // don't try this one at home - - friend struct SymbolLookupTable; - - UniquePtr nids; - uint_fast32_t size; - // there is no intention of ever growing this since the symtab size is known - - int_fast64_t binarySearch(const Nid &key) const { - int_fast64_t lo = 0; - int_fast64_t hi = static_cast(size) - 1; - - while (lo <= hi) { - const auto m = (lo + hi) >> 1; - const auto n = nids[m].nid <=> key; - - if (n == 0) [[unlikely]] { - return m; - } - - if (n < 0) - lo = m + 1; - else - hi = m - 1; - } - return -(lo + 1); - } - - static int_fast64_t toIndex(int_fast64_t i) { - return -(i + 1); - } - - NidKeyValue &insert(const Nid &key, uint_fast32_t i) { - if (size++ == i) [[unlikely]] { - // append - NidKeyValue &value = nids[i]; - value.nid = key; - return value; - } - __builtin_memcpy(nids.get() + i + 1, nids.get() + i, sizeof(NidKeyValue) * (size - i)); - NidKeyValue &value = nids[i]; - value.nid = key; - return value; - } - - NidKeyValue &insert(const Nid &key) { - auto index = binarySearch(key); - if (index < 0) { - return insert(key, toIndex(index)); - } - return nids[index]; - } - - NidMap(decltype(nullptr)) : nids(nullptr), size() {} - NidMap(uint_fast32_t capacity) : nids(new NidKeyValue[capacity]()), size(0) {} - NidMap &operator=(uint_fast32_t capacity) { - nids = new NidKeyValue[capacity](); - return *this; - } - uint_fast32_t length() const { return size; } - - const NidKeyValue *operator[](const Nid &key) const { - auto index = binarySearch(key); - if (index < 0) { - return nullptr; - } - return nids.get() + index; - } -}; - -struct SymbolLookupTable { - - NidMap nids; - UniquePtr lib; - - void fillTable() { - const rtld::ElfSymbolTable &symbols = lib->getMetaData()->getSymbolTable(); - const auto len = symbols.length(); - // remember to skip the first null symbol - for (size_t i = 1; i < len; i++) { - const auto sym = symbols[i]; - auto &kv = nids.insert(sym.nid()); - kv.index = i; - } - } - - public: - SymbolLookupTable() : nids(nullptr), lib(nullptr) {} - SymbolLookupTable(SharedLib *lib) : - // while not obvious, nchain == length of symtab - nids(lib->getMetaData()->nSymbols()), lib(lib){} - - SymbolLookupTable &operator=(SharedLib *lib) { - nids = lib->getMetaData()->nSymbols(); - this->lib = lib; - return *this; - } - - const rtld::ElfSymbol operator[](const Nid &nid) { - auto *value = nids[nid]; - if (value == nullptr) [[unlikely]] { - return nullptr; - } - return lib->getMetaData()->getSymbolTable()[value->index]; - } - - const rtld::ElfSymbol operator[](const char *sym) { - Nid nid; // NOLINT(cppcoreguidelines-pro-type-member-init) we're initializing it in fillNid - fillNid(nid, sym); - return (*this)[nid]; - } - - explicit operator bool() const { - return lib != nullptr; - } - - size_t length() const { - return nids.length(); - } -}; - Elf::~Elf() noexcept { // tracer detaches on destruction and the loaded elf runs } // must be defined after SymbolLookupTable @@ -194,12 +65,12 @@ Elf::Elf(Hijacker *hijacker, uint8_t *data) noexcept : phdrs(reinterpret_cast(data + e_phoff)), strtab(), strtabLength(), symtab(), symtabLength(), relatbl(), relaLength(), plt(), pltLength(), hijacker(hijacker), textOffset(), imagebase(), - data(data), libs(nullptr), mappedMemory(nullptr), jitFd(-1) { + data(data), resolver(nullptr), mappedMemory(nullptr), jitFd(-1) { // TODO check the elf magic stupid //hexdump(data, sizeof(Elf64_Ehdr)); } -bool loadLibraries(Hijacker &hijacker, const dbg::Tracer &tracer, const Array &paths, Array &libs, const size_t reserved) noexcept; +bool loadLibraries(Hijacker &hijacker, const dbg::Tracer &tracer, const Array &paths, ManagedResolver &resolver) noexcept; bool Elf::parseDynamicTable() noexcept { const Elf64_Dyn *__restrict dyntbl = nullptr; @@ -327,15 +198,8 @@ bool Elf::parseDynamicTable() noexcept { // remove unset values names.shrink(i); - libs = {handleCount + names.length()}; - - if (names.length() > 0) { - puts("loading libraries"); - if (!loadLibraries(*hijacker, tracer, names, libs, handleCount)) { - __builtin_printf("failed to load libraries\n"); - return false; - } - } + resolver = new ManagedResolver{}; + resolver->reserve_library_memory(handleCount + names.length()); puts("filling symbol tables"); for (auto i = 0; i < handleCount; i++) { @@ -344,8 +208,18 @@ bool Elf::parseDynamicTable() noexcept { printf("failed to get lib for 0x%x\n", (unsigned int) preLoadedHandles[i]); return false; } - SymbolLookupTable &lib = libs[i] = ptr.release(); - lib.fillTable(); + if (resolver->add_library_metadata(ptr->imagebase(), ptr->getMetaDataAddress()) != 0) { + printf("failed to add library metadata for 0x%x\n", (unsigned int) preLoadedHandles[i]); + return false; + } + } + + if (names.length() > 0) { + puts("loading libraries"); + if (!loadLibraries(*hijacker, tracer, names, *resolver)) { + __builtin_printf("failed to load libraries\n"); + return false; + } } puts("finished process dynamic table"); @@ -396,7 +270,7 @@ static constexpr int PROT_EXEC = 4; static constexpr int PROT_GPU_READ = 0x10; static constexpr int PROT_GPU_WRITE = 0x20; -static bool loadLibrariesInplace(Hijacker &hijacker, const Array &names, Array &libs, const size_t reserved) noexcept { +static bool loadLibrariesInplace(Hijacker &hijacker, const Array &names, ManagedResolver &resolver) noexcept { for (const auto &name : names) { const auto id = SYSMODULES[name]; int handle = id != 0 ? sceSysmoduleLoadModuleInternal(id) : @@ -414,16 +288,17 @@ static bool loadLibrariesInplace(Hijacker &hijacker, const Array &names, printf("failed to get lib handle for %s\n", names[i].c_str()); return false; } - - SymbolLookupTable &lib = libs[i + reserved] = ptr.release(); - lib.fillTable(); + if (resolver.add_library_metadata(ptr->imagebase(), ptr->getMetaDataAddress()) != 0) { + printf("failed to add library metadata for %s\n", names[i].c_str()); + return false; + } } return true; } -bool loadLibraries(Hijacker &hijacker, const dbg::Tracer &tracer, const Array &names, Array &libs, const size_t reserved) noexcept { +bool loadLibraries(Hijacker &hijacker, const dbg::Tracer &tracer, const Array &names, ManagedResolver &resolver) noexcept { if (hijacker.getPid() == getpid()) { - return loadLibrariesInplace(hijacker, names, libs, reserved); + return loadLibrariesInplace(hijacker, names, resolver); } static constexpr uint32_t INTERNAL_MASK = 0x80000000; @@ -494,8 +369,10 @@ bool loadLibraries(Hijacker &hijacker, const dbg::Tracer &tracer, const Arrayimagebase(), ptr->getMetaDataAddress()) != 0) { + printf("failed to add library metadata for %s\n", names[i].c_str()); + return false; + } } puts("finished loading libraries"); @@ -836,6 +713,7 @@ uintptr_t Elf::getSymbolAddress(const Elf64_Rela *__restrict rel) const noexcept if (symtab == nullptr || strtab == nullptr) [[unlikely]] { return true; } + const Elf64_Sym *__restrict sym = symtab + ELF64_R_SYM(rel->r_info); if (sym->st_value != 0) { // the symbol exists in our elf @@ -843,15 +721,16 @@ uintptr_t Elf::getSymbolAddress(const Elf64_Rela *__restrict rel) const noexcept // this was a mistake and I'm an idiot but it may be useful in the future return imagebase + sym->st_value; } - for (auto &lib : libs) { - auto libsym = lib[strtab + sym->st_name]; - if (libsym && libsym.exported()) { - return libsym.vaddr(); - } - } + if (ELF64_ST_BIND(sym->st_info) == STB_WEAK) { return -1; } + + const auto libsym = resolver->lookup_symbol(strtab + sym->st_name); + + if (libsym) { + return libsym; + } printf("symbol lookup for %s failed\n", strtab + sym->st_name); return 0; } diff --git a/send_elf.py b/send_elf.py index 256ea07..3a19053 100644 --- a/send_elf.py +++ b/send_elf.py @@ -247,11 +247,8 @@ async def has_homebrew_daemon(host: str) -> bool: async def logger_client(args: ParsedArgs): async with SEM: - async with open_connection(args.host, LOGGER_PORT) as (reader, writer): + async with open_connection(args.host, LOGGER_PORT) as (reader, _): reader._buffer = LineBuffer(reader._buffer) - writer.write(args.spawner.read_bytes()) - writer.write_eof() - await writer.drain() await log_task(reader, args.logger, args.silent) print('logger client finished') diff --git a/spawner/CMakeLists.txt b/spawner/CMakeLists.txt index d6f7e7c..4c12779 100644 --- a/spawner/CMakeLists.txt +++ b/spawner/CMakeLists.txt @@ -58,11 +58,11 @@ set(D_SRC ${D_CWD}/source) file(GLOB SrcFiles ${D_SRC}/*.c ${D_SRC}/*.cpp ${D_SRC}/**/*.cpp ${D_SRC}/*.h ${D_SRC}/*.hpp ${D_SRC}/**/*.hpp ${D_SRC}/*.s) -set(CMAKE_C_FLAGS "--target=x86_64-freebsd-pc-elf -O0 -march=znver2 -mavx2 -DPPR -DPS5 -DPS5_FW_VERSION=${V_FW} ") +set(CMAKE_C_FLAGS "--target=x86_64-freebsd-pc-elf -O0 -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_CXX_FLAGS "${CMAKE_C_FLAGS} -O3 -march=znver2 -mavx2 -Wall -Wextra -Wmove -Wmost -Werror -pedantic -pedantic-errors -fno-exceptions -Wno-unused-function") +set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -O3 -march=znver2 -Wall -Wextra -Wmove -Wmost -Werror -pedantic -pedantic-errors -fno-exceptions -Wno-unused-function") set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wno-unused-command-line-argument") target_sources(${PROJECT_NAME} PRIVATE ${SrcFiles}) diff --git a/spawner/source/main.cpp b/spawner/source/main.cpp index 2a790dc..e373509 100644 --- a/spawner/source/main.cpp +++ b/spawner/source/main.cpp @@ -11,8 +11,7 @@ #include "offsets.hpp" #include "util.hpp" #include -#include -#include +#include #include #include #include @@ -638,6 +637,11 @@ class UnixSocket : public FileDescriptor { } }; +static bool isProcessAlive(int pid) noexcept { + int mib[]{CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; + return sysctl(mib, 4, nullptr, nullptr, nullptr, 0) == 0; +} + static void *hookThread(void *args) noexcept { static constexpr int PING = 0; @@ -717,10 +721,15 @@ static void *hookThread(void *args) noexcept { puts("execve completed"); - while (helper->spawned == nullptr) { - usleep(100); // NOLINT + do { // NOLINT helper->spawned = Hijacker::getHijacker(pid); - } + if (helper->spawned == nullptr) { + if (isProcessAlive(pid)) { + puts("process died"); + return nullptr; + } + } + } while (helper->spawned == nullptr); uintptr_t base = helper->spawned->getLibKernelBase(); @@ -770,8 +779,6 @@ extern "C" int main() { pthread_t td = nullptr; pthread_create(&td, nullptr, hookThread, &helper); - usleep(100000); // NOLINT(*) - int appId = 0; if (!launchApp("BREW00000", &appId)) { // we're screwed diff --git a/spawner/source/start.c b/spawner/source/start.c index da95932..083ee85 100644 --- a/spawner/source/start.c +++ b/spawner/source/start.c @@ -104,6 +104,16 @@ int __attribute__ ((naked)) unlink(const char *path) { __asm__ volatile("jmp *f_unlink(%rip)"); } +static __attribute__ ((used)) void *f_realloc = nullptr; +void *__attribute__ ((naked)) realloc(void *ptr, size_t length) { + __asm__ volatile("jmp *f_realloc(%rip)"); +} + +static __attribute__ ((used)) void *f_perror = nullptr; +int __attribute__ ((naked)) perror(const char *msg) { + __asm__ volatile("jmp *f_perror(%rip)"); +} + STUB(sceUserServiceGetForegroundUser) STUB(getpid) STUB(getppid) @@ -123,6 +133,7 @@ STUB(open) STUB(mkdir) STUB(stat) STUB(printf) +STUB(snprintf) STUB(_ZdaPv) STUB(_Znam) STUB(_Znwm) @@ -137,7 +148,7 @@ STUB(__error) STUB(strerror) STUB(sceKernelPrintBacktraceWithModuleInfo) STUB(waitpid) -STUB(perror) +STUB(sysctl) STUB(pthread_create) STUB(pthread_join) @@ -195,6 +206,7 @@ void _start(struct payload_args *args) { LIBKERNEL_LINK(pthread_create); LIBKERNEL_LINK(pthread_join); LIBKERNEL_LINK(kill); + LIBKERNEL_LINK(sysctl); LIBC_LINK(_Znwm); @@ -209,7 +221,9 @@ void _start(struct payload_args *args) { LIBC_LINK(memcmp); LIBC_LINK(strcmp); LIBC_LINK(printf); + LIBC_LINK(snprintf); LIBC_LINK(perror); + LIBC_LINK(realloc); LIBC_LINK(strstr); LIBC_LINK(strlen); diff --git a/test_elf/CMakeLists.txt b/test_elf/CMakeLists.txt deleted file mode 100644 index d7ee2a7..0000000 --- a/test_elf/CMakeLists.txt +++ /dev/null @@ -1,77 +0,0 @@ -################################################################################################### -# 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 "test_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) - -if ("${CMAKE_CXX_STANDARD}" STREQUAL "") - set(CMAKE_CXX_STANDARD 20) -endif() - -# 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}/bin) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${D_CWD}/bin) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${D_CWD}/bin) # static libs are archive - -# Headers -include_directories (SYSTEM "${D_PS5SDK}") -include_directories (SYSTEM "${D_PS5SDK}/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 - $<$:${C_DEFS} ${C_FLAGS}> - $<$:${CXX_DEFS} ${CXX_FLAGS}> - $<$:${ASM_FLAGS}> -) - -message("========== build: ${PROJECT_NAME} ==========") - -set(D_SRC ${D_CWD}/source) - -file(GLOB SrcFiles ${D_SRC}/*.c ${D_SRC}/*.cpp ${D_SRC}/*.h ${D_SRC}/*.hpp ${D_SRC}/*.s) - -set(CMAKE_C_FLAGS "--target=x86_64-freebsd-pc-elf -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 -fPIE -march=znver2 -Wall -Werror") -set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -O3 -pedantic -pedantic-errors") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0") - -target_sources(${PROJECT_NAME} PRIVATE ${SrcFiles}) -target_link_directories (${PROJECT_NAME} PUBLIC ${D_CWD} ${D_CWD}/../lib) - -target_link_libraries (${PROJECT_NAME} PUBLIC ps5sdk_crt SceLibcInternal kernel_sys) -set(CMAKE_EXE_LINKER_FLAGS "-fuse-ld=lld -Xlinker -pie -Xlinker --gc-sections -Xlinker -zmax-page-size=16384 -Xlinker -zcommon-page-size=16384 -Xlinker -T ${CMAKE_CURRENT_SOURCE_DIR}/linker.x -Wl,--build-id=none -Wl,-z,norelro") -set (CMAKE_C_LINKER_WRAPPER_FLAG "-Xlinker" " ") -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/test_elf/build.bat b/test_elf/build.bat deleted file mode 100644 index 5abb63a..0000000 --- a/test_elf/build.bat +++ /dev/null @@ -1,2 +0,0 @@ -cmake -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_TOOLCHAIN_FILE=%PS5SDK%/cmake/toolchain-ps5.cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 . -ninja diff --git a/test_elf/build.sh b/test_elf/build.sh deleted file mode 100644 index 1f66d24..0000000 --- a/test_elf/build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -cmake -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_TOOLCHAIN_FILE=$PS5SDK/cmake/toolchain-ps5.cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 . -ninja diff --git a/test_elf/linker.x b/test_elf/linker.x deleted file mode 100644 index a9d4c69..0000000 --- a/test_elf/linker.x +++ /dev/null @@ -1,131 +0,0 @@ -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(0x10) { - *(.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 = .); - - . = ALIGN(0x4000); /* move to a new page in memory */ - - .dynamic : { - PROVIDE_HIDDEN (_DYNAMIC = .); - *(.dynamic); - } : phdr_dynamic - - .dynsym : { - *(.dynsym); - } : phdr_dynamic - - .dynstr : { - *(.dynstr); - } : phdr_dynamic -} diff --git a/test_elf/source/main.cpp b/test_elf/source/main.cpp deleted file mode 100644 index 41b0525..0000000 --- a/test_elf/source/main.cpp +++ /dev/null @@ -1,15 +0,0 @@ - -#include - -static void __attribute__((constructor)) test_constructor() { - puts("hello world"); -} - -static void __attribute__((destructor)) test_destructor() { - puts("goodbye world"); -} - -int main() { - puts("main entered"); - return 0; -}