From c19666c0a0068feff8bbb2f8075b69a39a4c7dcf Mon Sep 17 00:00:00 2001 From: Arksama-PHU Date: Sun, 24 May 2026 20:31:15 +0200 Subject: [PATCH] Initial release : Lapy JB Daemon v1.2 multi-firmware standalone payload (3.00 -> 12.00) Standalone homebrew daemon for PS5 that mimics etaHEN's jailbreak-on-demand API. Apps that write /download0/etahen_jailbreak from inside their sandbox get their ucred bumped (caps + authid + uid + sceAttr + sandbox escape via fd_rdir/jdir) the same way etaHEN does it. NO etaHEN required. Multi-fw via ps5-payload-sdk's runtime KERNEL_ADDRESS_* externs : the SDK auto-resolves kernel symbols per-fw at boot, so the binary works on every fw covered by the SDK + kstuff (3.00 -> 12.00) with no fw-specific code. Build : export PS5_PAYLOAD_SDK= && make Install : copy lapy_jb_daemon.elf + homebrew.js to /data/homebrew/lapy_jb/ Credits : libhijacker (illusion + LightingMod), ps5-payload-sdk (John Tornblom), offsets_v940 multi-fw module (Team PHU / Arksama). --- .gitignore | 24 + LICENSE | 38 + Makefile | 49 + README.txt | 108 +++ extern/libhijacker/include/Platform.hpp | 32 + extern/libhijacker/include/backtrace.hpp | 15 + extern/libhijacker/include/dbg.hpp | 3 + extern/libhijacker/include/dbg/args.hpp | 138 +++ extern/libhijacker/include/dbg/dbg.hpp | 629 ++++++++++++ extern/libhijacker/include/elf/elf.hpp | 64 ++ extern/libhijacker/include/elf/loader.hpp | 14 + extern/libhijacker/include/elf/nid/b64.hpp | 32 + extern/libhijacker/include/elf/nid/nid.hpp | 19 + extern/libhijacker/include/elf/nid/sha1.hpp | 306 ++++++ extern/libhijacker/include/hijacker.hpp | 16 + .../include/hijacker/allocator.hpp | 43 + .../libhijacker/include/hijacker/hijacker.hpp | 179 ++++ .../libhijacker/include/hijacker/memory.hpp | 79 ++ .../libhijacker/include/hijacker/spawner.hpp | 40 + extern/libhijacker/include/kernel.hpp | 23 + extern/libhijacker/include/kernel/frame.hpp | 194 ++++ extern/libhijacker/include/kernel/kernel.hpp | 234 +++++ extern/libhijacker/include/kernel/kthread.hpp | 27 + extern/libhijacker/include/kernel/proc.hpp | 206 ++++ extern/libhijacker/include/kernel/rtld.hpp | 558 +++++++++++ extern/libhijacker/include/mutex.hpp | 166 ++++ extern/libhijacker/include/nid.hpp | 104 ++ extern/libhijacker/include/notify.hpp | 34 + extern/libhijacker/include/offsets.hpp | 14 + extern/libhijacker/include/util.hpp | 894 ++++++++++++++++++ homebrew.js | 14 + lapy_jb_daemon.elf | Bin 0 -> 543792 bytes source/main.cpp | 194 ++++ source/offsets_v940.cpp | 37 + 34 files changed, 4527 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.txt create mode 100644 extern/libhijacker/include/Platform.hpp create mode 100644 extern/libhijacker/include/backtrace.hpp create mode 100644 extern/libhijacker/include/dbg.hpp create mode 100644 extern/libhijacker/include/dbg/args.hpp create mode 100644 extern/libhijacker/include/dbg/dbg.hpp create mode 100644 extern/libhijacker/include/elf/elf.hpp create mode 100644 extern/libhijacker/include/elf/loader.hpp create mode 100644 extern/libhijacker/include/elf/nid/b64.hpp create mode 100644 extern/libhijacker/include/elf/nid/nid.hpp create mode 100644 extern/libhijacker/include/elf/nid/sha1.hpp create mode 100644 extern/libhijacker/include/hijacker.hpp create mode 100644 extern/libhijacker/include/hijacker/allocator.hpp create mode 100644 extern/libhijacker/include/hijacker/hijacker.hpp create mode 100644 extern/libhijacker/include/hijacker/memory.hpp create mode 100644 extern/libhijacker/include/hijacker/spawner.hpp create mode 100644 extern/libhijacker/include/kernel.hpp create mode 100644 extern/libhijacker/include/kernel/frame.hpp create mode 100644 extern/libhijacker/include/kernel/kernel.hpp create mode 100644 extern/libhijacker/include/kernel/kthread.hpp create mode 100644 extern/libhijacker/include/kernel/proc.hpp create mode 100644 extern/libhijacker/include/kernel/rtld.hpp create mode 100644 extern/libhijacker/include/mutex.hpp create mode 100644 extern/libhijacker/include/nid.hpp create mode 100644 extern/libhijacker/include/notify.hpp create mode 100644 extern/libhijacker/include/offsets.hpp create mode 100644 extern/libhijacker/include/util.hpp create mode 100644 homebrew.js create mode 100644 lapy_jb_daemon.elf create mode 100644 source/main.cpp create mode 100644 source/offsets_v940.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..953107d --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Build artifacts +*.o +*.d +*.a + +# Python scripts (helpers, not part of release) +*.py +__pycache__/ + +# Backup files +*.bak +*.bak_* +*.orig +*~ + +# IDE / editor +.vscode/ +.idea/ +*.swp +.DS_Store + +# OS +Thumbs.db +desktop.ini diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3d1a687 --- /dev/null +++ b/LICENSE @@ -0,0 +1,38 @@ +MIT License + +Copyright (c) 2026 Arksama (Team PHU) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +Credits to original author when re-used in derivative works appreciated. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- + +DISCLAIMER + +This software is provided for educational and interoperability purposes only. +It is intended to be used on PS5 consoles owned by the user, on firmware +versions that have been publicly jailbroken via third-party tools. + +The daemon mimics etaHEN's jailbreak-on-demand API for homebrew apps that +expect that environment. It does not bypass any DRM or grant access to +copyrighted material. Use it only with software you have the right to run. + +Use of this software in ways that violate Sony's Terms of Service is at +your own risk. The authors take no responsibility for misuse. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b796fbd --- /dev/null +++ b/Makefile @@ -0,0 +1,49 @@ +# Lapy JB Daemon v1.2 — multi-firmware standalone payload. +# +# Build flow : +# - main.o + offsets_v940.o compiled from source/ +# - linked against vanilla libhijacker.a (place at extern/libhijacker/) +# - offsets_v940.o is listed BEFORE -lhijacker so the linker resolves the +# offsets:: namespace symbols from that object and skips libhijacker's +# vanilla offsets.cpp.o (which would hardcode fw 9.40 only). +# +# Result : a binary that works on every fw covered by ps5-payload-sdk + kstuff +# (3.00 -> 12.00), with no fw-specific code in this repo. + +PS5_HOST ?= 192.168.1.28 +PS5_PORT ?= 9021 + +ifndef PS5_PAYLOAD_SDK + $(error PS5_PAYLOAD_SDK undefined. Set to your ps5-payload-sdk path) +endif + +include $(PS5_PAYLOAD_SDK)/toolchain/prospero.mk + +ELF := lapy_jb_daemon.elf + +LIBHIJACKER_DIR := extern/libhijacker +LIBHIJACKER_INC := $(LIBHIJACKER_DIR)/include + +CXXFLAGS := -std=c++20 -Wall -O2 -fno-rtti -fno-exceptions +CXXFLAGS += -I$(LIBHIJACKER_INC) -Isource + +LDFLAGS := -L$(LIBHIJACKER_DIR) +LDLIBS := -lhijacker -lkernel_sys -lSceNotification + +OBJS := source/main.o source/offsets_v940.o + +all: $(ELF) + +source/%.o: source/%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +# offsets_v940.o is listed BEFORE -lhijacker in the link line so its symbols +# satisfy libhijacker's offsets:: refs before the archive's offsets.cpp.o +# can be pulled in. +$(ELF): $(OBJS) $(LIBHIJACKER_DIR)/libhijacker.a + $(CXX) $(CXXFLAGS) -o $@ $(OBJS) $(LDFLAGS) $(LDLIBS) + +clean: + rm -f $(ELF) $(OBJS) + +.PHONY: all clean diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..4b66336 --- /dev/null +++ b/README.txt @@ -0,0 +1,108 @@ +================================================================================ + Lapy JB Daemon — standalone homebrew payload for PS5-Xplorer / similar apps + v1.2 — multi-firmware (3.00 -> 12.00, every fw covered by ps5-payload-sdk) +================================================================================ + +WHAT IT DOES +------------ +Mimics etaHEN's jailbreak-on-demand daemon API for Sony app PRXes (= the +prx.cpp shipped with PS5-Xplorer / universalps5-style apps that depend on +etaHEN being active to unsandbox themselves). + +When this daemon runs, your PS5 app's PRX writes a request file to its +sandbox /download0/etahen_jailbreak with its PID. The daemon detects the +file, walks allproc, finds the process, bumps its ucred (caps + authID + +uid + attr) via libhijacker, then deletes the file. Same effect as etaHEN +doing it. + +NO etaHEN required. + +REQUIREMENTS +------------ + - PS5 jailbroken with kstuff active + - Homebrew Launcher (HBL) or autoload.txt configured + +INSTALL +------- + 1. Copy the entire `lapy_jb` folder to your PS5 at : + /data/homebrew/lapy_jb/ + (use FTP, USB, etc.) + + The folder must contain : + lapy_jb_daemon.elf + homebrew.js + + 2. Open HBL — you should see "lapy Jb daemon" in the list. + + 3. Tap to launch. Notification "Lapy JB Daemon active" will appear. + + 4. Now launch your app (e.g., PS5-Xplorer) — the daemon will detect its + jailbreak request and bump it automatically. + +OPTIONAL : auto-launch at boot +------------------------------- +Add to your /data/autoload.txt : + /data/homebrew/lapy_jb/lapy_jb_daemon.elf + +So the daemon launches at every PS5 boot, no manual HBL tap needed. + +KLOG (= debug) +-------------- +On launch : + [lapy_jb] Lapy JB Daemon v1.2 (multi-fw) + [lapy_jb] No etaHEN, no PHU required + [lapy_jb] kernel_base = 0x... + [lapy_jb] polling /mnt/sandbox/_/download0/etahen_jailbreak every 250ms + +When app launches : + [lapy_jb] request from _ : pid=N + [lapy_jb] jailbreak OK pid=N + (caps + authid + uid + sceAttr + sandbox escape via fd_rdir/jdir applied) + +If the first attempt fails ("getHijacker FAIL — process may have exited"), +just relaunch your app — second attempt usually succeeds (timing race). + +BUILD FROM SOURCE +----------------- +The repo ships libhijacker (headers + static library) under extern/, so +the only external dependency is the PS5 payload SDK : + + - ps5-payload-sdk (John Törnblom) : + https://github.com/ps5-payload-dev/sdk + Set environment variable PS5_PAYLOAD_SDK to the SDK root. + +Build : + export PS5_PAYLOAD_SDK=/path/to/ps5-payload-sdk + make + +Output : lapy_jb_daemon.elf + +About source/offsets_v940.cpp : +This file overrides libhijacker's vanilla offsets.cpp at link time. It's +what makes the binary multi-fw : ps5-payload-sdk already resolves kernel +symbols per-fw at boot via KERNEL_ADDRESS_* runtime externs, so +offsets_v940 just converts those absolute VAs to offsets the way +libhijacker's offsets:: namespace expects. The shipped extern/libhijacker/ +libhijacker.a has been prebuilt with this override already applied — if +you bring your own vanilla libhijacker.a, the standalone offsets_v940.o +takes precedence at link time and the vanilla offsets.cpp.o stays out. + +CREDITS +------- +Built on libhijacker by illusion + LightingMod. +Uses ps5-payload-sdk by John Törnblom. +Multi-fw offsets module (offsets_v940) by Team PHU / Arksama. + +CHANGELOG +--------- +v1.2 (2026-05-07) + - Multi-fw : works on every PS5 fw covered by ps5-payload-sdk + kstuff + (3.00 -> 12.00). Kernel symbols (allproc, rootvnode, security_flags, + qa_flags, utoken_flags) auto-resolved per-fw at boot via the SDK's + runtime KERNEL_ADDRESS_* externs (no hardcoded fw 9.40 path). + - Same libhijacker codepath as etaHEN's daemon : caps + authid + uid + + sceAttr at offset 0x83 + sandbox escape via fd_rdir/fd_jdir = + rootvnode. Identical effect to "etahen jailbreak true". + +v1.0 (initial) + - fw 9.40 only. diff --git a/extern/libhijacker/include/Platform.hpp b/extern/libhijacker/include/Platform.hpp new file mode 100644 index 0000000..88ef506 --- /dev/null +++ b/extern/libhijacker/include/Platform.hpp @@ -0,0 +1,32 @@ +#pragma once + +#if defined(_WIN32) +#define PLATFORM_WINDOWS +#pragma comment(lib, "Ws2_32.lib") +#include +#include +#define CloseSocket closesocket +#define SocketAvailable ioctlsocket +typedef SOCKET Socket; + +#elif defined(__linux__) +#define PLATFORM_LINUX +#include +#include +#include +#include +#define CloseSocket close +#define SocketAvailable ioctl +typedef int32_t Socket; + +#elif defined(__APPLE__) +#define PLATFORM_APPLE +#include +#include +#include +#include +#define CloseSocket close +#define SocketAvailable ioctl +typedef int32_t Socket; + +#endif diff --git a/extern/libhijacker/include/backtrace.hpp b/extern/libhijacker/include/backtrace.hpp new file mode 100644 index 0000000..40a61d3 --- /dev/null +++ b/extern/libhijacker/include/backtrace.hpp @@ -0,0 +1,15 @@ +#pragma once + +extern "C" { + #include +} + +struct Frame { + Frame *next; + uintptr_t addr; +}; +static auto constexpr CRASH_LOG_PATH = "/data/etaHEN/etaHEN_crash.log"; +const Frame *getFramePointer(); +void printBacktraceForCrash(); +void crash_log(const char *fmt, ...); +void printBacktraceForCrash(); \ No newline at end of file diff --git a/extern/libhijacker/include/dbg.hpp b/extern/libhijacker/include/dbg.hpp new file mode 100644 index 0000000..735cbe1 --- /dev/null +++ b/extern/libhijacker/include/dbg.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include "dbg/dbg.hpp" // IWYU pragma: export diff --git a/extern/libhijacker/include/dbg/args.hpp b/extern/libhijacker/include/dbg/args.hpp new file mode 100644 index 0000000..33f9dea --- /dev/null +++ b/extern/libhijacker/include/dbg/args.hpp @@ -0,0 +1,138 @@ +#pragma once + +extern "C" { + #include +} + +enum DbgCommand : uint64_t { + CREATE_SCRATCH_CMD = 0x3, + READ_CMD = 0x12, + WRITE_CMD = 0x13, + PROCESS_LIST_CMD = 0x14, + THREAD_LIST_CMD = 0x15, + PROCESS_INFO_CMD = 0x18, + THREAD_INFO_CMD = 0x19, + ARG2_CMD = 0x1e +}; + +// NOLINTBEGIN(*) + +// aggressively zero all dbg args +template +struct DbgArg { + DbgArg() { + // because of the stupid wrong pure attribute in the sdk headers + // __builtin_memset must be used + __builtin_memset(this, 0, size); + } +}; + +struct DbgArg1 : DbgArg<0x20> { + uint32_t type; + uint32_t pad1; + DbgCommand cmd; + + DbgArg1(uint32_t type, DbgCommand cmd) : DbgArg(), type(type), cmd(cmd){} +private: + uint8_t __attribute__((unused)) pad[0x10]; +}; + +static_assert(sizeof(DbgArg1) == 0x20, "sizeof(DbgArg1) != 0x20"); + +struct DbgArg2 : DbgArg<0x40> { +}; + +struct DbgReadArg : DbgArg2 { + int pid; + uintptr_t src; + void *dst; + uint64_t length; + DbgReadArg(int pid, uintptr_t src, void *dst, uint64_t length) + : pid(pid), src(src), dst(dst), length(length) {} +private: + unsigned char __attribute__((unused)) pad[0x20]; +}; + +static_assert(sizeof(DbgReadArg) == 0x40, "sizeof(DbgReadArg) != 0x40"); + +struct DbgKickProcessArg : DbgArg2 { + uint32_t pid; + uint32_t __attribute__((unused)) pad1; + const uint32_t cmd = 16; + uint32_t __attribute__((unused)) pad2; + const uint32_t value = 3; + DbgKickProcessArg(int pid) : pid(pid) {} +private: + unsigned char __attribute__((unused)) pad[0x2c]; +}; + +static_assert(sizeof(DbgKickProcessArg) == 0x40, "sizeof(DbgKickProcessArg) != 0x40"); + +struct DbgGetPidsArg : DbgArg2 { + uint64_t buf; + uint64_t length; + + template + DbgGetPidsArg(int(&buf)[size]) : buf((uint64_t) &buf), length(size) {} + DbgGetPidsArg(int *buf, unsigned long size) : buf((uint64_t) buf), length(size) {} +private: + unsigned char __attribute__((unused)) pad[0x30]; +}; + +static_assert(sizeof(DbgGetPidsArg) == 0x40, "sizeof(DbgGetPidsArg) != 0x40"); + +struct DbgGetTidsArg : DbgArg2 { + uint32_t pid; + uint64_t buf; + uint64_t length; + + template + DbgGetTidsArg(int pid, int(&buf)[size]) : pid(pid), buf((uint64_t) &buf), length(size) {} + DbgGetTidsArg(int pid, int *buf, unsigned long size) : pid(pid), buf((uint64_t) buf), length(size) {} +private: + unsigned char __attribute__((unused)) pad[0x28]; +}; + +static_assert(sizeof(DbgGetTidsArg) == 0x40, "sizeof(DbgGetTidsArg) != 0x40"); + +struct DbgGetProcInfoArg : DbgArg2 { + int pid; + uintptr_t buf; + uint64_t length; + + DbgGetProcInfoArg(int pid, void *buf, uint64_t length) + : pid(pid), buf((uintptr_t) buf), length(length) {} +private: + unsigned char __attribute__((unused)) pad[0x28]; +}; + +static_assert(sizeof(DbgGetProcInfoArg) == 0x40, "sizeof(DbgGetProcInfoArg) != 0x40"); + + +struct DbgGetThreadInfoArg : DbgArg2 { + uint32_t pid; + uint32_t __attribute__((unused)) pad1; + uint32_t tid; + uint64_t buf; + uint64_t length; + + DbgGetThreadInfoArg(int pid, int tid, void *buf, uint64_t length) + : pid(pid), tid(tid), buf((uintptr_t) buf), length(length) {} +private: + unsigned char __attribute__((unused)) pad[0x20]; +}; + +static_assert(sizeof(DbgGetThreadInfoArg) == 0x40, "sizeof(DbgGetThreadInfoArg) != 0x40"); + +struct DbgArg3 : DbgArg<0x20> { + int64_t err; + uint64_t length; + + explicit DbgArg3() : length() {} +private: + unsigned char __attribute__((unused)) pad[0x10]; +}; + +static_assert(sizeof(DbgArg3) == 0x20, "sizeof(DbgArg3) != 0x20"); + +// NOLINTEND(*) diff --git a/extern/libhijacker/include/dbg/dbg.hpp b/extern/libhijacker/include/dbg/dbg.hpp new file mode 100644 index 0000000..b44174d --- /dev/null +++ b/extern/libhijacker/include/dbg/dbg.hpp @@ -0,0 +1,629 @@ +#pragma once + +#include "util.hpp" +#include +#include +#include +#include +#include +#include +#include + +extern "C" { + int pthread_getthreadid_np(); + int getpid(); + size_t strnlen(const char *s, size_t maxlen); +} + +namespace dbg { + +static constexpr uint64_t DEBUGGER_AUTHID = 0x4800000000000006; +static constexpr uint64_t PTRACE_ID = 0x4800000000010003l; + +uint64_t setAuthId(uint64_t authid); + +class AuthidSwapper { + + uint64_t id; + static constexpr int AUTHID_OFFSET = 0x58; + +public: + AuthidSwapper(uint64_t authid) noexcept : id(setAuthId(authid)) { + } + AuthidSwapper(const AuthidSwapper&) = delete; + AuthidSwapper &operator=(const AuthidSwapper&) = delete; + AuthidSwapper(AuthidSwapper &&rhs) noexcept : id(rhs.id) { rhs.id = 0; } + AuthidSwapper &operator=(AuthidSwapper &&rhs) noexcept = delete; + ~AuthidSwapper() { + if (id != 0) { + setAuthId(id); + id = 0; + } + } +}; + +class IdArray { + int *ptr; + size_t size; + +public: + IdArray(decltype(nullptr)) : ptr(nullptr), size() {} + IdArray(const int *ptr, size_t length) : ptr(new int[length]), size(length) { + __builtin_memcpy(this->ptr, ptr, length * sizeof(int)); + } + IdArray(const IdArray&) = delete; + IdArray& operator=(const IdArray&) = delete; + IdArray(IdArray &&rhs) noexcept : ptr(rhs.ptr), size(rhs.size) { rhs.ptr = nullptr; } + IdArray& operator=(IdArray &&rhs) noexcept { + delete[] ptr; + ptr = rhs.ptr; + rhs.ptr = nullptr; + size = rhs.size; + return *this; + } + ~IdArray() { + delete[] ptr; + } + + int operator[](unsigned long i) const { + if (ptr == nullptr) { + return -1; + } + return ptr[i]; + } + + explicit operator bool() const { return ptr != nullptr; } + + size_t length() const { return size; } + + const int *begin() const { return ptr; } + const int *end() const { return ptr + size; } + bool contains(int value) const { + for (int id : *this) { + if (id == value) { + return true; + } + } + return false; + } +}; + +class ProcessInfo { + static constexpr unsigned int BUF_LENGTH = 0x51c; + static constexpr unsigned int NAME_OFFSET = 0x18; + static constexpr unsigned int NAME_LENGTH = 0x20; + static constexpr unsigned int PATH_OFFSET = 0x38; + static constexpr unsigned int PATH_LENGTH = 0x400; + + UniquePtr buf; + StringView _name; + StringView _path; + int _pid; + + void fillInfo(); + +public: + + ProcessInfo(int pid) : buf(new uint8_t[BUF_LENGTH]), _name(nullptr), _path(nullptr), _pid(pid) { + fillInfo(); + const char *str = reinterpret_cast(buf.get()); + size_t nameLength = strnlen(str + NAME_OFFSET, NAME_LENGTH); + _name = {str + NAME_OFFSET, nameLength}; + size_t pathLength = strnlen(str + PATH_OFFSET, PATH_LENGTH); + _path = {str + NAME_OFFSET, pathLength}; + } + ProcessInfo(const ProcessInfo&) = delete; + ProcessInfo &operator=(const ProcessInfo&) = delete; + ProcessInfo(ProcessInfo &&rhs) noexcept : buf(rhs.buf.release()), _name(rhs._name), _path(rhs._path), _pid(rhs._pid) {} + ProcessInfo &operator=(ProcessInfo &&rhs) noexcept { + buf = rhs.buf.release(); + _name = rhs._name; + _path = rhs._path; + _pid = rhs._pid; + return *this; + } + ~ProcessInfo() noexcept = default; + + const StringView &name() const { + return _name; + } + + const StringView &path() const { + return _path; + } + + int pid() const { + return _pid; + } +}; + + +class ThreadInfo { + static constexpr unsigned int BUF_LENGTH = 0x15c; + static constexpr unsigned int NAME_OFFSET = 0x64; + static constexpr unsigned int NAME_LENGTH = 0x20; + + UniquePtr buf; + StringView _name; + int _pid; + int _tid; + + void fillInfo(); + +public: + + ThreadInfo() : buf(new uint8_t[BUF_LENGTH]), _name(nullptr), _pid(getpid()), _tid(pthread_getthreadid_np()) { + fillInfo(); + const char *str = reinterpret_cast(buf.get()); + size_t nameLength = strnlen(str + NAME_OFFSET, NAME_LENGTH); + _name = {str + NAME_OFFSET, nameLength}; + } + + ThreadInfo(int tid) : buf(new uint8_t[BUF_LENGTH]), _name(nullptr), _pid(getpid()), _tid(tid) { + fillInfo(); + const char *str = reinterpret_cast(buf.get()); + size_t nameLength = strnlen(str + NAME_OFFSET, NAME_LENGTH); + _name = {str + NAME_OFFSET, nameLength}; + } + + ThreadInfo(int pid, int tid) : buf(new uint8_t[BUF_LENGTH]()), _name(nullptr), _pid(pid), _tid(tid) { + fillInfo(); + const char *str = reinterpret_cast(buf.get()); + size_t nameLength = strnlen(str + NAME_OFFSET, NAME_LENGTH); + _name = {str + NAME_OFFSET, nameLength}; + } + + ThreadInfo(const ThreadInfo&) = delete; + ThreadInfo &operator=(const ThreadInfo&) = delete; + ThreadInfo(ThreadInfo&&) noexcept = default; + ThreadInfo &operator=(ThreadInfo&&) noexcept = default; + ~ThreadInfo() noexcept = default; + + const StringView &name() const { + return _name; + } + + int pid() const { + return _pid; + } + + int tid() const { + return _tid; + } +}; + + +IdArray getAllPids(); +IdArray getAllTids(int pid); +void suspend(int pid); +void resume(int pid); + + +bool read(int pid, uintptr_t addr, void *dst, size_t length); +inline UniquePtr read(int pid, uintptr_t addr, size_t length) { + UniquePtr buf{new uint8_t[length]}; + if (!read(pid, addr, buf.get(), length)) + { + return nullptr; + } + return buf; +} + +bool write(int pid, uintptr_t dst, const void *src, size_t length); + +class ProcessInfoIterator { + + IdArray pids{getAllPids()}; + + class iterator { + + const int *ptr; + + public: + iterator(const int *ptr) : ptr(ptr) {} + + ProcessInfo operator*() { + return *ptr; + } + + iterator operator++(int) { + iterator it = ptr; + ptr++; + return it; + } + + iterator &operator++() { + ++ptr; + return *this; + } + + bool operator!=(const iterator &rhs) const { + return ptr != rhs.ptr; + } + }; + + public: + iterator begin() const { + return pids.begin(); + } + + iterator end() const { + return pids.end(); + } + + size_t length() const { + return pids.length(); + } +}; + +inline ProcessInfoIterator getProcesses() { + return {}; +} + +class ThreadInfoIterator { + + IdArray tids; + int pid; + + class iterator { + + const int *ptr; + int pid; + + public: + iterator(const int *ptr, int pid) : ptr(ptr), pid(pid) {} + + ThreadInfo operator*() { + return ThreadInfo{pid, *ptr}; + } + + iterator operator++(int) { + iterator it{ptr, pid}; + ptr++; + return it; + } + + iterator &operator++() { + ++ptr; + return *this; + } + + bool operator!=(const iterator &rhs) const { + return ptr != rhs.ptr; + } + }; + + public: + ThreadInfoIterator(int pid) : tids(getAllTids(pid)), pid(pid) {} + iterator begin() const { + return {tids.begin(), pid}; + } + + iterator end() const { + return {tids.end(), pid}; + } +}; + +inline ThreadInfoIterator getThreads(int pid) { + return {pid}; +} + +struct Registers : reg { // these are helpers as it is annoying that register_t is signed + uintptr_t rax() const noexcept { return r_rax; } + void rax(uintptr_t value) noexcept { r_rax = static_cast(value); } + uintptr_t rbx() const noexcept { return r_rbx; } + void rbx(uintptr_t value) noexcept { r_rbx = static_cast(value); } + uintptr_t rcx() const noexcept { return r_rcx; } + void rcx(uintptr_t value) noexcept { r_rcx = static_cast(value); } + uintptr_t rdx() const noexcept { return r_rdx; } + void rdx(uintptr_t value) noexcept { r_rdx = static_cast(value); } + uintptr_t rsi() const noexcept { return r_rsi; } + void rsi(uintptr_t value) noexcept { r_rsi = static_cast(value); } + uintptr_t rdi() const noexcept { return r_rdi; } + void rdi(uintptr_t value) noexcept { r_rdi = static_cast(value); } + uintptr_t rbp() const noexcept { return r_rbp; } + void rbp(uintptr_t value) noexcept { r_rbp = static_cast(value); } + uintptr_t rsp() const noexcept { return r_rsp; } + void rsp(uintptr_t value) noexcept { r_rsp = static_cast(value); } + uintptr_t rip() const noexcept { return r_rip; } + void rip(uintptr_t value) noexcept { r_rip = static_cast(value); } + uintptr_t r8() const noexcept { return r_r8; } + void r8(uintptr_t value) noexcept { r_r8 = static_cast(value); } + uintptr_t r9() const noexcept { return r_r9; } + void r9(uintptr_t value) noexcept { r_r9 = static_cast(value); } + uintptr_t r10() const noexcept { return r_r10; } + void r10(uintptr_t value) noexcept { r_r10 = static_cast(value); } + uintptr_t r11() const noexcept { return r_r11; } + void r11(uintptr_t value) noexcept { r_r11 = static_cast(value); } + uintptr_t r12() const noexcept { return r_r12; } + void r12(uintptr_t value) noexcept { r_r12 = static_cast(value); } + uintptr_t r13() const noexcept { return r_r13; } + void r13(uintptr_t value) noexcept { r_r13 = static_cast(value); } + uintptr_t r14() const noexcept { return r_r14; } + void r14(uintptr_t value) noexcept { r_r14 = static_cast(value); } + uintptr_t r15() const noexcept { return r_r15; } + void r15(uintptr_t value) noexcept { r_r15 = static_cast(value); } + uintptr_t cs() const noexcept { return r_cs; } + void cs(uintptr_t value) noexcept { r_cs = static_cast(value); } + uintptr_t ss() const noexcept { return r_ss; } + void ss(uintptr_t value) noexcept { r_ss = static_cast(value); } + uintptr_t rflags() const noexcept { return r_rflags; } + void rflags(uintptr_t value) noexcept { r_rflags = static_cast(value); } + uint32_t trapno() const noexcept { return r_trapno; } + void trapno(uint32_t value) noexcept { r_trapno = value; } + uint32_t err() const noexcept { return r_err; } + void err(uint32_t value) noexcept { r_err = value; } + uint16_t fs() const noexcept { return r_fs; } + void fs(uint16_t value) noexcept { r_fs = value; } + uint16_t gs() const noexcept { return r_gs; } + void gs(uint16_t value) noexcept { r_gs = value; } + uint16_t es() const noexcept { return r_es; } + void es(uint16_t value) noexcept { r_es = value; } + uint16_t ds() const noexcept { return r_ds; } + void ds(uint16_t value) noexcept { r_ds = value; } + + void setArgs(uintptr_t a) noexcept { + rdi(a); + } + void setArgs(uintptr_t a, uintptr_t b) noexcept { + rdi(a); rsi(b); + } + void setArgs(uintptr_t a, uintptr_t b, uintptr_t c) noexcept { + rdi(a); rsi(b); rdx(c); + } + void setArgs(uintptr_t a, uintptr_t b, uintptr_t c, uintptr_t d) noexcept { + rdi(a); rsi(b); rdx(c); rcx(d); + } + void setArgs(uintptr_t a, uintptr_t b, uintptr_t c, uintptr_t d, uintptr_t e) noexcept { + rdi(a); rsi(b); rdx(c); rcx(d); r8(e); + } + void setArgs(uintptr_t a, uintptr_t b, uintptr_t c, uintptr_t d, uintptr_t e, uintptr_t f) noexcept { + rdi(a); rsi(b); rdx(c); rcx(d); r8(e); r9(f); + } + void dump() const noexcept { + printf("rax: 0x%08llx\n", rax()); + printf("rbx: 0x%08llx\n", rbx()); + printf("rcx: 0x%08llx\n", rcx()); + printf("rdx: 0x%08llx\n", rdx()); + printf("rsi: 0x%08llx\n", rsi()); + printf("rdi: 0x%08llx\n", rdi()); + printf("r8: 0x%08llx\n", r8()); + printf("r9: 0x%08llx\n", r9()); + printf("r10: 0x%08llx\n", r10()); + printf("r11: 0x%08llx\n", r11()); + printf("r12: 0x%08llx\n", r12()); + printf("r13: 0x%08llx\n", r13()); + printf("r14: 0x%08llx\n", r14()); + printf("r15: 0x%08llx\n", r15()); + printf("rbp: 0x%08llx\n", rbp()); + printf("rsp: 0x%08llx\n", rsp()); + printf("rip: 0x%08llx\n", rip()); + } +}; + +class Tracer { + + static constexpr int JITSHM_CREATE = 533; + static constexpr int JITSHM_ALIAS = 534; + static constexpr int MMAP = 477; + static constexpr int MUNMAP = 73; + static constexpr int MPROTECT = 74; + static constexpr int CLOSE = 6; + static constexpr int SOCKET = 97; + static constexpr int PIPE = 42; + static constexpr int PIPE2 = 687; + static constexpr int SETSOCKOPT = 105; + + mutable uintptr_t syscall_addr; + mutable uintptr_t libkernel_base; + mutable uintptr_t errno_addr; + int pid; + + static int ptrace(int request, pid_t pid, caddr_t addr, int data) noexcept { + AuthidSwapper swapper{PTRACE_ID}; + return ::ptrace(request, pid, addr, data); + } + + uintptr_t call(uintptr_t addr, uintptr_t a) const noexcept { + const Registers backup = getRegisters(); + Registers jmp = backup; + jmp.rip(addr); + jmp.setArgs(a); + return call(backup, jmp); + } + uintptr_t call(uintptr_t addr, uintptr_t a, uintptr_t b) const noexcept { + const Registers backup = getRegisters(); + Registers jmp = backup; + jmp.rip(addr); + jmp.setArgs(a, b); + return call(backup, jmp); + } + uintptr_t call(uintptr_t addr, uintptr_t a, uintptr_t b, uintptr_t c) const noexcept { + const Registers backup = getRegisters(); + Registers jmp = backup; + jmp.rip(addr); + jmp.setArgs(a, b, c); + return call(backup, jmp); + } + uintptr_t call(uintptr_t addr, uintptr_t a, uintptr_t b, uintptr_t c, uintptr_t d) const noexcept { + const Registers backup = getRegisters(); + Registers jmp = backup; + jmp.rip(addr); + jmp.setArgs(a, b, c, d); + return call(backup, jmp); + } + uintptr_t call(uintptr_t addr, uintptr_t a, uintptr_t b, uintptr_t c, uintptr_t d, uintptr_t e) const noexcept { + const Registers backup = getRegisters(); + Registers jmp = backup; + jmp.rip(addr); + jmp.setArgs(a, b, c, d, e); + return call(backup, jmp); + } + uintptr_t call(uintptr_t addr, uintptr_t a, uintptr_t b, uintptr_t c, uintptr_t d, uintptr_t e, uintptr_t f) const noexcept { + const Registers backup = getRegisters(); + Registers jmp = backup; + jmp.rip(addr); + jmp.setArgs(a, b, c, d, e, f); + return call(backup, jmp); + } + // any remaining attempts to use the templated call will fail + + uintptr_t call(const Registers &backup, Registers &jmp) const noexcept; + uintptr_t syscall(const Registers &backup, Registers &jmp) const noexcept; + + public: + Tracer(int pid) noexcept : syscall_addr(0), libkernel_base(0), errno_addr(0), pid(pid) { + if (pid == getpid()) { + this->pid = 0; + } else { + if (ptrace(PT_ATTACH, pid, 0, 0) < 0) { + ::perror("ptrace PT_ATTACH Tracer::Tracer"); + this->pid = 0; + } else { + wait(); + } + } + } + Tracer(const Tracer&) = delete; + Tracer &operator=(const Tracer&) = delete; + Tracer(Tracer &&rhs) noexcept : syscall_addr(rhs.syscall_addr), libkernel_base(rhs.libkernel_base), errno_addr(rhs.errno_addr), pid(rhs.pid) { + rhs.syscall_addr = 0; + rhs.errno_addr = 0; + rhs.libkernel_base = 0; + rhs.pid = 0; + } + Tracer &operator=(Tracer &&rhs) noexcept { + if (pid != 0) [[unlikely]] { + if (ptrace(PT_DETACH, pid, 0, 0) < 0) { + ::perror("ptrace PT_DETACH Tracer::operator="); + } + } + syscall_addr = rhs.syscall_addr; + libkernel_base = rhs.libkernel_base; + errno_addr = rhs.errno_addr; + pid = rhs.pid; + rhs.syscall_addr = 0; + rhs.libkernel_base = 0; + rhs.errno_addr = 0; + rhs.pid = 0; + return *this; + } + ~Tracer() noexcept { + if (pid != 0) { + if (ptrace(PT_DETACH, pid, 0, 0) < 0) { + ::perror("ptrace PT_DETACH Tracer::~Tracer"); + } + } + } + + explicit operator bool() const noexcept { + return pid != 0; + } + + int wait(int options=0) const noexcept { + int status = 0; + if (waitpid(pid, &status, options) < 0) { + ::perror("waitpid"); + return -1; + } + return status; + } + + Registers getRegisters() const noexcept { + Registers r; + ptrace(PT_GETREGS, pid, reinterpret_cast(&r), 0); + return r; + } + + bool getRegisters(Registers &r) const noexcept { + return ptrace(PT_GETREGS, pid, reinterpret_cast(&r), 0) >= 0; + } + + bool setRegisters(const Registers ®s) const noexcept { + struct reg *r = const_cast(®s); // NOLINT(*) + return ptrace(PT_SETREGS, pid, reinterpret_cast(r), 0) >= 0; + } + + int step() const noexcept { + ptrace(PT_STEP, pid, reinterpret_cast(1), 0); + return wait(); + } + + int run(bool wait=true) const noexcept { // continue is a keyword :/ + ptrace(PT_CONTINUE, pid, reinterpret_cast(1), 0); + if (wait) { + return this->wait(); + } + return 0; + } + + int kill() noexcept { + int res = ptrace(PT_KILL, pid, 0, 0); + if (res < 0) { + ::perror("kill"); + return res; + } + pid = 0; + return 0; + } + + template + R call(uintptr_t addr, Args ...args) const noexcept { + const Registers backup = getRegisters(); + Registers jmp = backup; + jmp.rip(addr); + // using C cast since it isn't known what cast is required + jmp.setArgs(((uintptr_t) args)...); // NOLINT(*) + return (R) call(backup, jmp); // NOLINT(*) + } + + template + R syscall(int num, Args ...args) const noexcept { + const Registers backup = getRegisters(); + Registers jmp = backup; + jmp.rax(static_cast(num)); + // using C cast since it isn't known what cast is required + jmp.setArgs(((uintptr_t) args)...); // NOLINT(*) + jmp.r10(jmp.rcx()); + return (R) syscall(backup, jmp); // NOLINT(*) + } + + int jitshm_create(uintptr_t name, size_t size, int flags) const noexcept { + return syscall(JITSHM_CREATE, name, size, flags); + } + + int jitshm_alias(int fd, int flags) const noexcept { + return syscall(JITSHM_ALIAS, fd, flags); + } + + uintptr_t mmap(uintptr_t addr, size_t len, int prot, int flags, int fd, off_t off) const noexcept { + return syscall(MMAP, addr, len, prot, flags, fd, off); + } + + int munmap(uintptr_t addr, size_t len) const noexcept { + return syscall(MUNMAP, addr, len); + } + + int mprotect(uintptr_t addr, size_t len, int prot) const noexcept { + return syscall(MPROTECT, addr, len, prot); + } + + int close(int fd) const noexcept { + return syscall(CLOSE, fd); + } + + int socket(int domain, int type, int protocol) const noexcept { + return syscall(SOCKET, domain, type, protocol); + } + + int pipe(int *fildes) const noexcept; + int dynlib_load_prx(const char *path, int *handle) const noexcept; + int dynlib_dlsym(int handle, const char *name, void **address) const noexcept; + + + int setsockopt(int s, int level, int optname, const void *optval, unsigned int optlen) const noexcept; + + void perror(const char *msg) const noexcept; +}; + +} // dbg diff --git a/extern/libhijacker/include/elf/elf.hpp b/extern/libhijacker/include/elf/elf.hpp new file mode 100644 index 0000000..efe7c07 --- /dev/null +++ b/extern/libhijacker/include/elf/elf.hpp @@ -0,0 +1,64 @@ +#pragma once + +extern "C" { + #include + #include + #include +} + +#include "hijacker.hpp" +#include "util.hpp" + +class ManagedResolver; + +constexpr auto i = sizeof(Elf64_Dyn); + +class Elf : Elf64_Ehdr { + + public: + struct MappedMemory { + uintptr_t mem; + size_t len; + }; + + private: + dbg::Tracer tracer; + const Elf64_Phdr *__restrict phdrs; + const char *__restrict strtab; + size_t strtabLength; + const Elf64_Sym *__restrict symtab; + size_t symtabLength; + const Elf64_Rela *__restrict relatbl; + size_t relaLength; + const Elf64_Rela *__restrict plt; + size_t pltLength; + Hijacker *__restrict hijacker; + size_t textOffset; + uintptr_t imagebase; + uint8_t *data; + UniquePtr resolver; + Array mappedMemory; + int jitFd; + + bool processProgramHeaders() noexcept; + bool parseDynamicTable() noexcept; + bool processRelocations() noexcept; + bool processPltRelocations() noexcept; + bool load() noexcept; + bool start(uintptr_t args) noexcept; + uintptr_t setupKernelRW() noexcept; + uintptr_t getSymbolAddress(const Elf64_Rela *__restrict rel) const noexcept; + + public: + Elf(Hijacker *hijacker, uint8_t *data) noexcept; + Elf(const Elf&) = delete; + Elf &operator=(const Elf&) = delete; + Elf(Elf&&) noexcept = default; + Elf &operator=(Elf&&) noexcept = default; + ~Elf() noexcept; // external linkage to prevent undefined behavior + + bool launch() noexcept; + explicit operator bool() const noexcept { + return static_cast(tracer); + } +}; diff --git a/extern/libhijacker/include/elf/loader.hpp b/extern/libhijacker/include/elf/loader.hpp new file mode 100644 index 0000000..3fdc3f2 --- /dev/null +++ b/extern/libhijacker/include/elf/loader.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "../thread.hpp" + +struct ElfLoaderBase { + void run(); +}; + +class ElfLoader : public ElfLoaderBase, public JThread { + friend struct ElfLoaderBase; + + public: + void run(); +}; diff --git a/extern/libhijacker/include/elf/nid/b64.hpp b/extern/libhijacker/include/elf/nid/b64.hpp new file mode 100644 index 0000000..9276ebf --- /dev/null +++ b/extern/libhijacker/include/elf/nid/b64.hpp @@ -0,0 +1,32 @@ +#pragma once + +extern "C" { + #include +} + +#include "../../nid.hpp" + +// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers,cppcoreguidelines-pro-bounds-constant-array-index) +namespace { + +static inline constexpr char encoder[]{"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"}; + +} + +static inline constexpr void b64encode(char (&dest)[NID_LENGTH+1], const unsigned char *src) { + for (unsigned int i = 0, j = 0; j < NID_LENGTH;) { + uint32_t a = src[i++]; + uint32_t b = src[i++]; + uint32_t c = src[i++]; + + uint32_t abc = (a << 16) | (b << 8) | c; + + dest[j++] = encoder[(abc >> 18) & 0x3F]; + dest[j++] = encoder[(abc >> 12) & 0x3F]; + dest[j++] = encoder[(abc >> 6) & 0x3F]; + dest[j++] = encoder[abc & 0x3F]; + } + dest[NID_LENGTH] = 0; +} + +// NOLINTEND(cppcoreguidelines-avoid-magic-numbers,cppcoreguidelines-pro-bounds-constant-array-index) diff --git a/extern/libhijacker/include/elf/nid/nid.hpp b/extern/libhijacker/include/elf/nid/nid.hpp new file mode 100644 index 0000000..3e0cd5f --- /dev/null +++ b/extern/libhijacker/include/elf/nid/nid.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "b64.hpp" +#include "../../nid.hpp" +#include "sha1.hpp" +#include "util.hpp" +#include + +static inline constexpr void fillNid(Nid &buf, const StringView &sym) { + constexpr size_t NID_DIGEST_LENGTH = 8; + constexpr size_t NID_SHA_LENGTH = 20; + uint8_t encodedDigest[NID_DIGEST_LENGTH + 1]{}; + uint8_t sha1[NID_SHA_LENGTH]{}; + genSha1(sha1, sym); + for (size_t i = 0; i < NID_DIGEST_LENGTH; i++) { + encodedDigest[i] = sha1[NID_DIGEST_LENGTH - 1 - i]; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) + } + b64encode(buf.str, encodedDigest); +} diff --git a/extern/libhijacker/include/elf/nid/sha1.hpp b/extern/libhijacker/include/elf/nid/sha1.hpp new file mode 100644 index 0000000..dae65ca --- /dev/null +++ b/extern/libhijacker/include/elf/nid/sha1.hpp @@ -0,0 +1,306 @@ +#pragma once + +/* + SHA-1 in C + By Steve Reid + 100% Public Domain + */ + +extern "C" { +#include +} + +// NOLINTBEGIN(*) + +namespace { + +typedef struct +{ + uint32_t state[5]; + uint32_t count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ +/* #define SHA1HANDSOFF * Copies data before messing with it. */ + +#define SHA1HANDSOFF + +#include +#include + +/* for uint32_t */ +#include + + +#define rol __builtin_rotateleft32 + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) + +#define blk(i) (block->l[(i)&15] = rol(block->l[((i)+13)&15]^block->l[((i)+8)&15] \ + ^block->l[((i)+2)&15]^block->l[(i)&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=(((w)&((x)^(y)))^(y))+blk0(i)+0x5A827999+rol(v,5);(w)=rol(w,30); +#define R1(v,w,x,y,z,i) z+=(((w)&((x)^(y)))^(y))+blk(i)+0x5A827999+rol(v,5);(w)=rol(w,30); +#define R2(v,w,x,y,z,i) z+=((w)^(x)^(y))+blk(i)+0x6ED9EBA1+rol(v,5);(w)=rol(w,30); +#define R3(v,w,x,y,z,i) z+=((((w)|(x))&(y))|((w)&(x)))+blk(i)+0x8F1BBCDC+rol(v,5);(w)=rol(w,30); +#define R4(v,w,x,y,z,i) z+=((w)^(x)^(y))+blk(i)+0xCA62C1D6+rol(v,5);(w)=rol(w,30); + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +static inline void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) { + typedef union { + unsigned char c[64]; + uint32_t l[16]; + } CHAR64LONG16; + +#ifdef SHA1HANDSOFF + CHAR64LONG16 block[1]; /* use array to appear as a pointer */ + + __builtin_memcpy(block, buffer, 64); +#else + /* The following had better never be used because it causes the + * pointer-to-const buffer to be cast into a pointer to non-const. + * And the result is written through. I threw a "const" in, hoping + * this will cause a diagnostic. + */ + CHAR64LONG16 *block = (const CHAR64LONG16 *) buffer; +#endif + /* Copy context->state[] to working vars */ + uint32_t a = state[0]; + uint32_t b = state[1]; + uint32_t c = state[2]; + uint32_t d = state[3]; + uint32_t e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a, b, c, d, e, 0); + R0(e, a, b, c, d, 1); + R0(d, e, a, b, c, 2); + R0(c, d, e, a, b, 3); + R0(b, c, d, e, a, 4); + R0(a, b, c, d, e, 5); + R0(e, a, b, c, d, 6); + R0(d, e, a, b, c, 7); + R0(c, d, e, a, b, 8); + R0(b, c, d, e, a, 9); + R0(a, b, c, d, e, 10); + R0(e, a, b, c, d, 11); + R0(d, e, a, b, c, 12); + R0(c, d, e, a, b, 13); + R0(b, c, d, e, a, 14); + R0(a, b, c, d, e, 15); + R1(e, a, b, c, d, 16); + R1(d, e, a, b, c, 17); + R1(c, d, e, a, b, 18); + R1(b, c, d, e, a, 19); + R2(a, b, c, d, e, 20); + R2(e, a, b, c, d, 21); + R2(d, e, a, b, c, 22); + R2(c, d, e, a, b, 23); + R2(b, c, d, e, a, 24); + R2(a, b, c, d, e, 25); + R2(e, a, b, c, d, 26); + R2(d, e, a, b, c, 27); + R2(c, d, e, a, b, 28); + R2(b, c, d, e, a, 29); + R2(a, b, c, d, e, 30); + R2(e, a, b, c, d, 31); + R2(d, e, a, b, c, 32); + R2(c, d, e, a, b, 33); + R2(b, c, d, e, a, 34); + R2(a, b, c, d, e, 35); + R2(e, a, b, c, d, 36); + R2(d, e, a, b, c, 37); + R2(c, d, e, a, b, 38); + R2(b, c, d, e, a, 39); + R3(a, b, c, d, e, 40); + R3(e, a, b, c, d, 41); + R3(d, e, a, b, c, 42); + R3(c, d, e, a, b, 43); + R3(b, c, d, e, a, 44); + R3(a, b, c, d, e, 45); + R3(e, a, b, c, d, 46); + R3(d, e, a, b, c, 47); + R3(c, d, e, a, b, 48); + R3(b, c, d, e, a, 49); + R3(a, b, c, d, e, 50); + R3(e, a, b, c, d, 51); + R3(d, e, a, b, c, 52); + R3(c, d, e, a, b, 53); + R3(b, c, d, e, a, 54); + R3(a, b, c, d, e, 55); + R3(e, a, b, c, d, 56); + R3(d, e, a, b, c, 57); + R3(c, d, e, a, b, 58); + R3(b, c, d, e, a, 59); + R4(a, b, c, d, e, 60); + R4(e, a, b, c, d, 61); + R4(d, e, a, b, c, 62); + R4(c, d, e, a, b, 63); + R4(b, c, d, e, a, 64); + R4(a, b, c, d, e, 65); + R4(e, a, b, c, d, 66); + R4(d, e, a, b, c, 67); + R4(c, d, e, a, b, 68); + R4(b, c, d, e, a, 69); + R4(a, b, c, d, e, 70); + R4(e, a, b, c, d, 71); + R4(d, e, a, b, c, 72); + R4(c, d, e, a, b, 73); + R4(b, c, d, e, a, 74); + R4(a, b, c, d, e, 75); + R4(e, a, b, c, d, 76); + R4(d, e, a, b, c, 77); + R4(c, d, e, a, b, 78); + R4(b, c, d, e, a, 79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; +#ifdef SHA1HANDSOFF + __builtin_memset(block, '\0', sizeof(block)); +#endif +} + + +/* SHA1Init - Initialize new context */ + +static inline void SHA1Init(SHA1_CTX * context) { + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +static inline void SHA1Update(SHA1_CTX *__restrict context, const unsigned char *data, uint32_t len) { + uint32_t i; + + uint32_t j; + + j = context->count[0]; + context->count[0] += len << 3; + if (context->count[0] < j) + context->count[1]++; + context->count[1] += (len >> 29); + j = (j >> 3) & 63; + if ((j + len) > 63) + { + __builtin_memcpy(&context->buffer[j], data, (i = 64 - j)); + SHA1Transform(context->state, context->buffer); + for (; i + 63 < len; i += 64) + { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else + i = 0; + __builtin_memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ + +static inline void SHA1Final( + unsigned char *digest, + SHA1_CTX * context +) +{ + unsigned i; + + unsigned char finalcount[8]; + + unsigned char c; + +#if 0 /* untested "improvement" by DHR */ + /* Convert context->count to a sequence of bytes + * in finalcount. Second element first, but + * big-endian order within element. + * But we do it all backwards. + */ + unsigned char *fcp = &finalcount[8]; + + for (i = 0; i < 2; i++) + { + uint32_t t = context->count[i]; + + int j; + + for (j = 0; j < 4; t >>= 8, j++) + *--fcp = (unsigned char) t} +#else + for (i = 0; i < 8; i++) + { + finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */ + } +#endif + c = 0200; + SHA1Update(context, &c, 1); + while ((context->count[0] & 504) != 448) + { + c = 0000; + SHA1Update(context, &c, 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) + { + digest[i] = (unsigned char) + ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); + } + /* Wipe variables */ + __builtin_memset(context, '\0', sizeof(*context)); + __builtin_memset(&finalcount, '\0', sizeof(finalcount)); +} + +static inline constexpr uint8_t NID_KEY[]{ + (uint8_t) 0x51, (uint8_t) 0x8D, (uint8_t) 0x64, (uint8_t) 0xA6, + (uint8_t) 0x35, (uint8_t) 0xDE, (uint8_t) 0xD8, (uint8_t) 0xC1, + (uint8_t) 0xE6, (uint8_t) 0xB0, (uint8_t) 0x39, (uint8_t) 0xB1, + (uint8_t) 0xC3, (uint8_t) 0xE5, (uint8_t) 0x52, (uint8_t) 0x30 +}; + +} + +struct Sha1 { + uint8_t hash[20]; +}; + +#include "util.hpp" + +static inline void genSha1(uint8_t *res, const StringView &str) { + SHA1_CTX ctx; + + SHA1Init(&ctx); + SHA1Update(&ctx, (const unsigned char*)str.c_str(), str.length()); + SHA1Update(&ctx, NID_KEY, sizeof(NID_KEY)); + SHA1Final(res, &ctx); +} + +// NOLINTEND(*) diff --git a/extern/libhijacker/include/hijacker.hpp b/extern/libhijacker/include/hijacker.hpp new file mode 100644 index 0000000..66aa063 --- /dev/null +++ b/extern/libhijacker/include/hijacker.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "hijacker/hijacker.hpp" // IWYU pragma: export +#include "hijacker/spawner.hpp" // IWYU pragma: export + +class ScopedSuspender { + Hijacker *hijacker; + + public: + ScopedSuspender(Hijacker *hijacker) : hijacker(hijacker) { hijacker->suspend(); } + ScopedSuspender(const ScopedSuspender&) = delete; + ScopedSuspender(ScopedSuspender&&) = delete; + ScopedSuspender &operator=(const ScopedSuspender&) = delete; + ScopedSuspender &operator=(ScopedSuspender&&) = delete; + ~ScopedSuspender() { hijacker->resume(); } +}; diff --git a/extern/libhijacker/include/hijacker/allocator.hpp b/extern/libhijacker/include/hijacker/allocator.hpp new file mode 100644 index 0000000..e8ae962 --- /dev/null +++ b/extern/libhijacker/include/hijacker/allocator.hpp @@ -0,0 +1,43 @@ +#pragma once +#include "kernel.hpp" + +// "allocates" memory from another process out of EXISTING process memory +class ProcessMemoryAllocator { + static constexpr size_t ALIGNMENT = 0x10; + static constexpr size_t ALIGNMENT_MASK = 0xf; + const SharedLibSection *section; + size_t allocated; + + public: + ProcessMemoryAllocator(decltype(nullptr)) : section(nullptr), allocated() {} + ProcessMemoryAllocator(const SharedLibSection *section) : section(section), allocated() {} + + /** + * "Releases" all the allocated memory + */ + void release() { + allocated = 0; + } + + /** + * Allocated virtual memory from the end of the existing section. + * It is allocated from the end because this portion of memory is likely unused. + * @param size the size of memory to "allocate" + * @return the virtual address for the requested memory + */ + uintptr_t allocate(size_t size) { + if ((size & ALIGNMENT_MASK) != 0) { + size = (size & ~ALIGNMENT_MASK) + ALIGNMENT; + } + allocated += size; + return section->end() - allocated; + } + + operator bool() const { + return section != nullptr; + } + + bool operator==(decltype(nullptr)) const { + return section == nullptr; + } +}; diff --git a/extern/libhijacker/include/hijacker/hijacker.hpp b/extern/libhijacker/include/hijacker/hijacker.hpp new file mode 100644 index 0000000..fe39f35 --- /dev/null +++ b/extern/libhijacker/include/hijacker/hijacker.hpp @@ -0,0 +1,179 @@ +#pragma once + +#include "dbg.hpp" +#include "hijacker/allocator.hpp" +#include "memory.hpp" +#include "kernel.hpp" +#include "kernel/rtld.hpp" +#include "util.hpp" +#include "allocator.hpp" +#include + +class Hijacker { + +#ifndef LIBKERNEL_HANDLE + static constexpr int LIBKERNEL_HANDLE = 0x2001; +#endif + + UniquePtr obj; + + protected: + friend class Spawner; + ProcessMemoryAllocator textAllocator; + ProcessMemoryAllocator dataAllocator; + + private: + mutable UniquePtr libkernel; + mutable int mainThreadId = -1; + bool isMainThreadRunning = true; + + Hijacker(SharedObject *obj) : obj(obj), textAllocator(nullptr), dataAllocator(nullptr), libkernel(nullptr) { + auto eboot = this->obj->getEboot(); + while (eboot == nullptr) { + // this can happen when it is still loading + eboot = this->obj->getEboot(); + } + while (textAllocator == nullptr) { + textAllocator = ProcessMemoryAllocator(eboot->getTextSection()); + } + while (dataAllocator == nullptr) { + dataAllocator = ProcessMemoryAllocator(eboot->getDataSection()); + } + } + + RtldMeta *getLibKernelMetaData() const { + auto *meta = getLibKernel(); + return meta ? meta->getMetaData() : nullptr; + } + + public: + uintptr_t getLibKernelBase() const { + RtldMeta *meta = getLibKernelMetaData(); + return meta ? meta->imageBase : 0; + } + private: + int getMainThreadId() const; + + public: + static UniquePtr getHijacker(const StringView &processName); + static UniquePtr getHijacker(int pid) { + auto p = ::getProc(pid); + if (p == nullptr) [[unlikely]] { + return nullptr; + } + + auto obj = p->getSharedObject(); + + // obj may be a nullptr when racing process creation + return obj != nullptr ? new Hijacker{obj.release()} : nullptr; + } + + UniquePtr getProc() const { + return ::getProc(getPid()); + } + + void suspend() { + if (isMainThreadRunning) { + dbg::suspend(obj->pid); + isMainThreadRunning = false; + } + } + + void resume() { + if (!isMainThreadRunning) { + dbg::resume(obj->pid); + isMainThreadRunning = true; + } + } + + int getPid() const { + return obj->pid; + } + + SharedLib *getEboot() const { + return obj->getEboot(); + } + + uintptr_t imagebase() const { + auto eboot = obj->getEboot(); + return eboot ? eboot->imagebase() : 0; + } + + SharedLib *getLibKernel() const { + if (libkernel == nullptr) [[unlikely]] { + libkernel = obj->getLib(LIBKERNEL_HANDLE); + } + return libkernel.get(); + } + + UniquePtr getLib(int handle) const { + return obj->getLib(handle); + } + + UniquePtr getLib(const StringView &name) const { + return obj->getLib(name); + } + + SharedLibIterator getLibs() const { + return obj->getLibs(); + } + + UniquePtr getTrapFrame() const; + void jailbreak(bool escapeSandbox=true) const; + uintptr_t getFunctionAddress(const SharedLib *lib, const Nid &fname) const noexcept; + + uintptr_t getLibKernelFunctionAddress(const Nid &fname) const { + return getFunctionAddress(getLibKernel(), fname); + } + + uintptr_t getLibKernelAddress(const Nid &fname) const { + return getFunctionAddress(getLibKernel(), fname); + } + + ProcessMemoryAllocator &getDataAllocator() { + return dataAllocator; + } + + ProcessMemoryAllocator &getTextAllocator() { + return textAllocator; + } + + UniquePtr read(uintptr_t src, size_t size) { + return dbg::read(getPid(), src, size).release(); + } + + bool read(uintptr_t src, void *dst, size_t size) { + return dbg::read(getPid(), src, dst, size); + } + + template + T read(uintptr_t vaddr) { + T t; + read(vaddr, &t, sizeof(t)); + return t; + } + + template + bool write(uintptr_t vaddr, const uint8_t(&buf)[size]) { + return dbg::write(getPid(), vaddr, buf, size); + } + + bool write(uintptr_t vaddr, const void *src, size_t size) { + return dbg::write(getPid(), vaddr, src, size); + } + + template + bool write(uintptr_t vaddr, const T &value) { + return write(vaddr, &value, sizeof(value)); + } + + template + ProcessPointer getPointer(uintptr_t addr) const { + return {getPid(), addr}; + } + + void hexdump(uintptr_t addr, size_t size) { + auto buf = read(addr, size); + ::hexdump(buf.get(), size); + } +}; diff --git a/extern/libhijacker/include/hijacker/memory.hpp b/extern/libhijacker/include/hijacker/memory.hpp new file mode 100644 index 0000000..ab86069 --- /dev/null +++ b/extern/libhijacker/include/hijacker/memory.hpp @@ -0,0 +1,79 @@ +#pragma once + +extern "C" { + #include +} + +#include "dbg.hpp" + +template +class ProcessReference { + uintptr_t addr; + int pid; + + public: + ProcessReference() = default; + ProcessReference(int pid, uintptr_t addr) : addr(addr), pid(pid) {} + ProcessReference(const ProcessReference &rhs) : addr(rhs.addr), pid(rhs.pid) {} + ProcessReference(ProcessReference&&) noexcept = delete; + ProcessReference &operator=(const ProcessReference &rhs) { + addr = rhs.addr; + pid = rhs.pid; + return *this; + } + ProcessReference &operator=(ProcessReference&&) noexcept = delete; + ProcessReference &operator=(T value) { + dbg::write(pid, addr, &value, sizeof(value)); + return *this; + } + ~ProcessReference() noexcept = default; + operator T() const { + T value; + dbg::read(pid, addr, &value, sizeof(T)); + return value; + } +}; + +template <> +class ProcessReference { + uintptr_t addr; + int pid; + + public: + ProcessReference(int pid, uintptr_t addr) : addr(addr), pid(pid) {} + ProcessReference(const ProcessReference &rhs) : addr(rhs.addr), pid(rhs.pid) {} + ProcessReference(ProcessReference&&) noexcept = delete; + ProcessReference &operator=(const ProcessReference &rhs) { + addr = rhs.addr; + pid = rhs.pid; + return *this; + } + ProcessReference &operator=(bool value) { + dbg::write(pid, addr, &value, sizeof(value)); + return *this; + } + ProcessReference &operator=(ProcessReference&&) noexcept = delete; + ~ProcessReference() noexcept = default; + explicit operator bool() const { + bool value; // NOLINT(cppcoreguidelines-init-variables) + dbg::read(pid, addr, &value, sizeof(bool)); + return value; + } +}; + +template +class ProcessPointer { + uintptr_t addr; + int pid; + + public: + ProcessPointer() : addr(), pid() {} + ProcessPointer(int pid, uintptr_t addr) : addr(addr), pid(pid) {} + ProcessReference operator*() const { return {pid, addr}; } + T get() const { + T value{}; + dbg::read(pid, addr, &value, sizeof(T)); + return value; + } + uintptr_t address() const { return addr; } +}; diff --git a/extern/libhijacker/include/hijacker/spawner.hpp b/extern/libhijacker/include/hijacker/spawner.hpp new file mode 100644 index 0000000..83cfd61 --- /dev/null +++ b/extern/libhijacker/include/hijacker/spawner.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include "hijacker.hpp" +#include "hijacker/hijacker.hpp" +#include "hijacker/spawner.hpp" +#include "memory.hpp" +#include "util.hpp" +#include + +extern "C" { + #include + #include +} + +class Spawner { + dbg::IdArray pids; + uintptr_t nanosleepOffset; + int pid; + + static inline constexpr Nid _nanosleep{"NhpspxdjEKU"}; + + static uintptr_t getNanosleepOffset(const Hijacker &hijacker) { + uintptr_t addr = hijacker.getLibKernelFunctionAddress(_nanosleep); + return addr - hijacker.getLibKernelBase(); + } + + static uintptr_t getNanosleepOffset() { + auto hijacker = Hijacker::getHijacker(getpid()); + if (hijacker == nullptr) [[unlikely]] { + return 0; + } + return getNanosleepOffset(*hijacker); + } + + public: + explicit Spawner() : pids(dbg::getAllPids()), nanosleepOffset(getNanosleepOffset()), pid(getpid()) {} + Spawner(const Hijacker &ptr) : pids(dbg::getAllPids()), nanosleepOffset(getNanosleepOffset(ptr)), pid(ptr.getPid()) {} + UniquePtr bootstrap(Hijacker &hijacker); + UniquePtr spawn(); +}; diff --git a/extern/libhijacker/include/kernel.hpp b/extern/libhijacker/include/kernel.hpp new file mode 100644 index 0000000..a95c0bf --- /dev/null +++ b/extern/libhijacker/include/kernel.hpp @@ -0,0 +1,23 @@ +#pragma once + +// IWYU pragma: begin_exports + +#include "kernel/kernel.hpp" +#include "kernel/rtld.hpp" +#include "kernel/proc.hpp" +#include "kernel/frame.hpp" + +// IWYU pragma: end_exports + +#include "util.hpp" + +bool createReadWriteSockets(const UniquePtr &proc, const int *sockets) noexcept; + +inline bool createReadWriteSockets(int pid, const int *sockets) noexcept { + auto proc = getProc(pid); + if (proc == nullptr) { + puts("createReadWriteSockets proc == nullptr"); + return false; + } + return createReadWriteSockets(proc, sockets); +} diff --git a/extern/libhijacker/include/kernel/frame.hpp b/extern/libhijacker/include/kernel/frame.hpp new file mode 100644 index 0000000..fa86d5d --- /dev/null +++ b/extern/libhijacker/include/kernel/frame.hpp @@ -0,0 +1,194 @@ +#pragma once + +#include "kernel.hpp" +#include "kernel/kernel.hpp" + +namespace { + +static constexpr size_t TRAPFRAME_SIZE = 0x110; + +} + +class TrapFrame : public KernelObject { + + static constexpr size_t RAX_OFFSET = 0x30; + static constexpr size_t RBX_OFFSET = 0x38; + static constexpr size_t RCX_OFFSET = 0x18; + static constexpr size_t RDX_OFFSET = 0x10; + static constexpr size_t RSI_OFFSET = 0x08; + static constexpr size_t RDI_OFFSET = 0x00; + static constexpr size_t R8_OFFSET = 0x20; + static constexpr size_t R9_OFFSET = 0x28; + static constexpr size_t R10_OFFSET = 0x48; + static constexpr size_t R11_OFFSET = 0x50; + static constexpr size_t R12_OFFSET = 0x58; + static constexpr size_t R13_OFFSET = 0x60; + static constexpr size_t R14_OFFSET = 0x68; + static constexpr size_t R15_OFFSET = 0x70; + static constexpr size_t RBP_OFFSET = 0x40; + static constexpr size_t RSP_OFFSET = 0x100; + static constexpr size_t RIP_OFFSET = 0xe8; + + + + public: + TrapFrame(uintptr_t addr) : KernelObject(addr) {} + + TrapFrame &setFrame(const TrapFrame *frame) { + memcpy(buf, frame->buf, sizeof(buf)); + return *this; + } + + uint64_t getRax() { + return get(); + } + + TrapFrame &setRax(uint64_t rax) { + set(rax); + return *this; + } + + uint64_t getRbx() { + return get(); + } + + TrapFrame &setRbx(uint64_t rbx) { + set(rbx); + return *this; + } + + uint64_t getRcx() { + return get(); + } + + + TrapFrame &setRcx(uint64_t rcx) { + set(rcx); + return *this; + } + + uint64_t getRdx() { + return get(); + } + + TrapFrame &setRdx(uint64_t rdx) { + set(rdx); + return *this; + } + + uint64_t getRsi() { + return get(); + } + + TrapFrame &setRsi(uint64_t rsi) { + set(rsi); + return *this; + } + + uint64_t getRdi() { + return get(); + } + + TrapFrame &setRdi(uint64_t rdi) { + set(rdi); + return *this; + } + + uint64_t getR8() { + return get(); + } + + TrapFrame &setR8(uint64_t r8) { + set(r8); + return *this; + } + + uint64_t getR9() { + return get(); + } + + TrapFrame &setR9(uint64_t r9) { + set(r9); + return *this; + } + + uint64_t getR10() { + return get(); + } + + TrapFrame &setR10(uint64_t r10) { + set(r10); + return *this; + } + + uint64_t getR11() { + return get(); + } + + TrapFrame &setR11(uint64_t r11) { + set(r11); + return *this; + } + + uint64_t getR12() { + return get(); + } + TrapFrame &setR12(uint64_t r12) { + set(r12); + return *this; + } + + uint64_t getR13() { + return get(); + } + + TrapFrame &setR13(uint64_t r13) { + set(r13); + return *this; + } + + uint64_t getR14() { + return get(); + } + + TrapFrame &setR14(uint64_t r14) { + set(r14); + return *this; + } + + uint64_t getR15() { + return get(); + } + + TrapFrame &setR15(uint64_t r15) { + set(r15); + return *this; + } + + uint64_t getRbp() { + return get(); + } + + TrapFrame &setRbp(uint64_t rbp) { + set(rbp); + return *this; + } + + uint64_t getRsp() { + return get(); + } + + TrapFrame &setRsp(uint64_t rsp) { + set(rsp); + return *this; + } + + uint64_t getRip() { + return get(); + } + + TrapFrame &setRip(uint64_t rip) { + set(rip); + return *this; + } +}; diff --git a/extern/libhijacker/include/kernel/kernel.hpp b/extern/libhijacker/include/kernel/kernel.hpp new file mode 100644 index 0000000..bc5c887 --- /dev/null +++ b/extern/libhijacker/include/kernel/kernel.hpp @@ -0,0 +1,234 @@ +#pragma once + +#include "util.hpp" +#include + +extern "C" { + +#include +#include +#include +#include + +} + +namespace { + +static constexpr size_t UCRED_SIZE = 0x168; + +} + +template +void kread(uintptr_t addr, T *dst) { + kernel_copyout(addr, dst, sizeof(T)); +} + +template +T kread(uintptr_t addr) { + T dst{}; + kernel_copyout(addr, &dst, sizeof(T)); + return dst; +} + +template +void kread(uintptr_t addr, uint8_t(&buf)[length]) { + kernel_copyout(addr, buf, length); +} + +template +void kwrite(uintptr_t addr, const T& value) { + kernel_copyin(const_cast(&value), addr, sizeof(T)); // NOLINT(cppcoreguidelines-pro-type-const-cast) +} + +template +void kwrite(uintptr_t addr, const uint8_t(&buf)[length]) { + kernel_copyin(const_cast(buf), addr, length); // NOLINT(cppcoreguidelines-pro-type-const-cast) +} + +inline void kwrite(uintptr_t addr, const void *src, size_t length) { + kernel_copyin(const_cast(src), addr, length); // NOLINT(cppcoreguidelines-pro-type-const-cast) +} + +template +class KernelObject; + +template +concept SizedKernelObject = requires { T::length; }; + +template +concept DerivedKernelObject = requires (T t) { + static_cast>(t); +}; + +template +concept KernelObjectBase = SizedKernelObject && DerivedKernelObject; + +template +class KIterable; + +String getKernelString(uintptr_t addr); + +template +class KernelObject { + + uintptr_t addr; + + protected: + template + friend class KIterable; + uint8_t buf[__restrict size]; + explicit KernelObject() = default; + KernelObject(uintptr_t addr) : addr(addr) { // NOLINT(cppcoreguidelines-pro-type-member-init) + #ifdef DEBUG + if (addr == 0) [[unlikely]] { + fatalf("kernel nullpointer dereference attempted\n"); + volatile void **tmp = nullptr; + *tmp = nullptr; // NOLINT(clang-analyzer-core.NullDereference) + } + #endif + kernel_copyout(addr, buf, size); + } + + void reload() { + kernel_copyout(addr, buf, size); + } + + template + T get() const { + static_assert(offset < size, "offset >= size"); + return *(T *)(buf + offset); + } + + template + void set(T value) { + static_assert(offset < size, "offset >= size"); + *(T *)(buf + offset) = value; + } + + template + String getString() const { + uintptr_t addr = get(); + return getKernelString(addr); + } + + public: + static constexpr size_t length = size; + KernelObject(KernelObject &&rhs) noexcept = default; + KernelObject &operator=(KernelObject &&rhs) noexcept = default; + KernelObject(const KernelObject &rhs) = default; + KernelObject &operator=(const KernelObject &rhs) = default; + ~KernelObject() noexcept = default; + + explicit operator bool() const { + return addr; + } + + const void *data() const { + return buf; + } + + uintptr_t address() const { + return addr; + } + + void flush() const { + #ifdef DEBUG + if (!addr) [[unlikely]] { + fatalf("nullptr dereference\n"); + } + #endif + kernel_copyin(const_cast(buf), addr, size); // NOLINT(cppcoreguidelines-pro-type-const-cast) + } +}; + + +template +class KPointer { + + protected: + uintptr_t addr; + + public: + KPointer(decltype(nullptr)) noexcept : addr(0) {} + KPointer(uintptr_t addr) noexcept : addr(addr) {} + T operator*() const { + T t; + kernel_copyout(addr, &t, sizeof(T)); + return t; + } + + explicit operator bool() const { + return addr; + } + + bool operator==(const KPointer &rhs) const { return addr == rhs.addr; } +}; + +template +struct KIterator; + +template +class KIterable { + + friend struct KIterator; + + protected: + + uintptr_t addr; + + KIterable(decltype(nullptr)) : addr() {} + + public: + KIterable(uintptr_t addr) : addr(addr) {} + + UniquePtr operator*() { + return {new T{addr}}; + } + + bool operator!=(const KIterable &rhs) const { return addr != rhs.addr; } + + KIterable &operator++() { + #ifdef DEBUG + if (addr == 0) [[unlikely]] { + return *this; + } + #endif + uintptr_t ptr = 0; + kernel_copyout(addr, &ptr, sizeof(ptr)); + addr = ptr; + return *this; + } + + explicit operator bool() const { return addr; } +}; + +template +struct KIterator { + + uintptr_t addr; + + KIterator(uintptr_t addr) : addr(addr) {} + KIterable begin() const { + return addr; + } + KIterable end() const { + return nullptr; + } + +}; + +class KUcred : public KernelObject { + + static constexpr size_t AUTHID_OFFSET = 0x58; + + public: + KUcred(uintptr_t addr) : KernelObject(addr) {} + + uint64_t authid() const { + return get(); + } + + void authid(uint64_t value) { + set(value); + } +}; diff --git a/extern/libhijacker/include/kernel/kthread.hpp b/extern/libhijacker/include/kernel/kthread.hpp new file mode 100644 index 0000000..c6b91b8 --- /dev/null +++ b/extern/libhijacker/include/kernel/kthread.hpp @@ -0,0 +1,27 @@ +#pragma once +#include "kernel.hpp" +#include "frame.hpp" + +namespace { + +static constexpr size_t THREAD_SIZE = 0x680; + +} + +class KThread : public KernelObject { + + static constexpr size_t TID_OFFSET = 0x9c; + static constexpr size_t FRAME_OFFSET = 0x460; + + public: + KThread(uintptr_t addr) : KernelObject(addr) {} + + UniquePtr getFrame() { + uintptr_t ptr = get(); + return ptr ? new TrapFrame(ptr) : nullptr; + } + + int tid() const { + return get(); + } +}; diff --git a/extern/libhijacker/include/kernel/proc.hpp b/extern/libhijacker/include/kernel/proc.hpp new file mode 100644 index 0000000..1a252f9 --- /dev/null +++ b/extern/libhijacker/include/kernel/proc.hpp @@ -0,0 +1,206 @@ +#pragma once + +#include "kernel.hpp" +#include "kernel/kernel.hpp" +#include "rtld.hpp" +#include "kthread.hpp" +#include "../offsets.hpp" +#include "util.hpp" +#include + +extern "C" { + #include + extern int getpid(); + extern uint64_t kernel_base; +} + +namespace { + +static constexpr size_t SELFINFO_SIZE = 0x400; +static constexpr size_t SELFINFO_NAME_SIZE = 32; +static constexpr size_t SELFINFO_PATH_SIZE = 972; + +static constexpr size_t FILEDESCENT_SIZE = 0x30; +static constexpr size_t PROC_SIZE = 0xc90; + +} + +struct SelfInfo { + uint32_t type; + uint32_t ps4_sdk_version; + uint32_t ps5_sdk_version; + uint32_t beef_face; + uint32_t dbbcc; + char name[SELFINFO_NAME_SIZE]; + char path[SELFINFO_PATH_SIZE]; +}; + +static_assert(sizeof(SelfInfo) == SELFINFO_SIZE, "sizeof(SelfInfo) != 0x400"); + +class Filedescent : public KernelObject { + + static constexpr size_t FILE_OFFSET = 0; + static constexpr size_t FLAGS_OFFSET = 0x28; + static constexpr size_t SEQ_OFFSET = 0x2c; + + public: + Filedescent(uintptr_t addr) : KernelObject(addr) {} + uintptr_t file() const { + return get(); + } + + uint8_t flags() const { + return get(); + } + + uint32_t seq() const { + return get(); + } +}; + +class FdTbl { + uintptr_t addr; + size_t ntables; + + size_t checkIndex(size_t i) const { + #ifdef DEBUG + if (i >= ntables) [[unlikely]] { + fatalf("index %llu is out of bounds for length %llu\n", i, ntables); + } + #endif + return i; + } + + public: + FdTbl(uintptr_t addr) : addr(addr), ntables((uint32_t)kread(addr)) {} + + Filedescent operator[](size_t i) const { + return {addr + (checkIndex(i) * Filedescent::length) + sizeof(ntables)}; + } + + uintptr_t getFile(size_t i) const { + uintptr_t fp = addr + (checkIndex(i) * Filedescent::length) + sizeof(ntables); + return kread(fp); + } + + void setFile(size_t i, uintptr_t file) const { + uintptr_t fp = addr + (checkIndex(i) * Filedescent::length) + sizeof(ntables); + kwrite(fp, file); + } + + uintptr_t getFileData(size_t i) const { + return kread(getFile(i)); + } + + void setFileData(size_t i, uintptr_t data) const { + kwrite(getFile(i), data); + } + + size_t length() const { + return ntables; + } +}; + +class KProc : public KernelObject { + + static constexpr size_t UCRED_OFFSET = 0x40; + static constexpr size_t PATH_OFFSET = 0x3d8; + static constexpr size_t SHARED_OBJECT_OFFSET = 0x3e8; + static constexpr size_t PID_OFFSET = 0xbc; + static constexpr size_t THREADS_OFFSET = 0x10; + static constexpr size_t FD_OFFSET = 0x48; + static constexpr size_t TITLEID_OFFSET = 0x470; + static constexpr size_t SELFINFO_OFFSET = 0x588; + static constexpr size_t SELFINFO_NAME_OFFSET = 0x59C; + + public: + + KProc(uintptr_t addr) : KernelObject(addr) {} + uintptr_t p_ucred() const { + return get(); + } + + UniquePtr ucred() const { + return new KUcred{p_ucred()}; + } + + int p_pid() const { + return get(); + } + + int pid() const { + return p_pid(); + } + + UniquePtr getSharedObject() const { + auto obj = get(); + return obj != 0 ? new SharedObject{obj, pid()} : nullptr; + } + + String getPath() const { + return getString(); + } + + KIterator p_threads() const { + return address() + THREADS_OFFSET; + } + + KIterator getThreads() const { + return p_threads(); + } + + UniquePtr getThread(int tid) const { + for (auto td : getThreads()) { + if (tid == td->tid()) { + return td.release(); + } + } + return nullptr; + } + + uintptr_t p_fd() const { + return get(); + } + + FdTbl getFdTbl() const { + return {kread(p_fd())}; + } + + const SelfInfo *getSelfInfo() const { + return reinterpret_cast(buf + SELFINFO_OFFSET); + } + + // no flush required + void setName(const StringView &name, bool reload=false) { + const size_t length = name.length() < (SELFINFO_NAME_SIZE-1) ? name.length() : SELFINFO_NAME_SIZE; + kwrite(address() + SELFINFO_NAME_OFFSET, name.c_str(), length + 1); + if (reload) { + this->reload(); + } + } + + void setTID(const StringView &tid) { + const size_t length = tid.length() < (TITLEID_OFFSET-1) ? tid.length() : TITLEID_OFFSET; + kwrite(address() + TITLEID_OFFSET, tid.c_str(), length + 1); + } + + String getTitleId() const noexcept { + constexpr auto TITLE_ID_SIZE = 9; + return StringView{reinterpret_cast(buf) + TITLEID_OFFSET, TITLE_ID_SIZE}; + } + + String titleId() const + { + return getKernelString(address() + TITLEID_OFFSET); + } +}; + +inline KIterator getAllProcs() { + return {kernel_base + offsets::allproc()}; +} + +UniquePtr getProc(int pid); + +inline UniquePtr getProc() { + return getProc(getpid()); +} diff --git a/extern/libhijacker/include/kernel/rtld.hpp b/extern/libhijacker/include/kernel/rtld.hpp new file mode 100644 index 0000000..8188c81 --- /dev/null +++ b/extern/libhijacker/include/kernel/rtld.hpp @@ -0,0 +1,558 @@ +#pragma once + +#include "kernel.hpp" +#include "nid.hpp" +#include "util.hpp" +#include +#include +#include + +extern "C" { + #include +} + + +class RtldMeta; + +// namespace to hold these commonly named classes +// to prevent api conflict in the future +namespace rtld { + +class ElfSymbolTable; +class ElfSymbol; +class ElfStringTable; + +} + +namespace { + +static UniquePtr newRtldMeta(uintptr_t imageBase, uintptr_t addr); + +static UniquePtr newSymbolTable(const RtldMeta *meta); + +static UniquePtr newStringTable(const RtldMeta *meta); + +static constexpr size_t SHARED_LIB_SECTION_SIZE = 0x18; +static constexpr size_t SHARED_LIB_SIZE = 0x200; +static constexpr size_t SHARED_OBJECT_SIZE = 0x188; +static constexpr size_t RTLD_META_SIZE = 0x118; + +} + +enum class SectionType : uint32_t { + UNKNOWN = 0, + TEXT = 1, + XOTEXT = 2, + RODATA = 4, + RELRO = 8, + DATA = 16, + INVALID = (uint32_t)-1 +}; + +class SharedLibSection : public KernelObject { + + friend class SharedLib; + + static constexpr size_t TYPE_OFFSET = 8; + static constexpr size_t ADDRESS_OFFSET = 8; + static constexpr size_t LENGTH_OFFSET = 16; + + mutable SectionType _type; + + public: + SharedLibSection() = default; + SharedLibSection(uintptr_t addr) : KernelObject(addr), _type(SectionType::INVALID) {} + + SectionType type() const { + if (_type == SectionType::INVALID) { + _type = kread(get() + TYPE_OFFSET); + } + return _type; + } + + uintptr_t start() const { + return get(); + } + + uintptr_t end() const { + return start() + sectionLength(); + } + + size_t sectionLength() const { + return get(); + } +}; + +struct EhFrameInfo { + uintptr_t hdr; + size_t hdrSize; + uintptr_t frame; + size_t frameSize; +}; + +class SharedLib : public KernelObject { + + static constexpr size_t DYNLIB_OFFSET = 0x148; + static constexpr size_t HANDLE_OFFSET = 0x28; + static constexpr size_t PATH_OFFSET = 0x8; + static constexpr size_t NUM_SECTIONS_OFFSET = 0x48; + static constexpr size_t SECTIONS_OFFSET = 0x40; + static constexpr size_t IMAGEBASE_OFFSET = 0x30; + static constexpr size_t EHFRAME_OFFSET = 0xf8; + static constexpr size_t EHFRAME_HDR_SIZE_OFFSET = 0x100; + static constexpr size_t EHFRAME_HDR_OFFSET = 0x108; + static constexpr size_t EHFRAME_SIZE_OFFSET = 0x110; + + mutable String path; + mutable Array sections; + mutable UniquePtr meta; + + public: + int pid; + + SharedLib(uintptr_t addr, int pid) + : KernelObject(addr), path(nullptr), sections(nullptr), meta(nullptr), pid(pid) {} + + int handle() const { + return get(); + } + + StringView getPath() const { + if (path.length() == 0) [[unlikely]] { + path = getString(); + } + return {path.c_str(), path.length()}; + } + + const Array &getSections() const { + if (sections == nullptr) [[unlikely]] { + size_t numSections = get(); + uintptr_t ptr = get(); + sections = Array{numSections}; + for (size_t i = 0; i < numSections; i++) { + sections[i] = SharedLibSection{ptr + (i * SharedLibSection::length)}; + } + } + return sections; + } + + const SharedLibSection *getTextSection() const { + for (SharedLibSection §ion : getSections()) { + SectionType type = section.type(); + if (type == SectionType::XOTEXT || type == SectionType::TEXT) { + return §ion; + } + } + return nullptr; + } + + void setTextAddress(uintptr_t addr) { + const SharedLibSection *section = getTextSection(); + kwrite(section->address() + SharedLibSection::ADDRESS_OFFSET, addr); + } + + void setRoDataAddress(uintptr_t addr) { + const SharedLibSection *section = getRoDataSection(); + kwrite(section->address() + SharedLibSection::ADDRESS_OFFSET, addr); + } + + const SharedLibSection *getDataSection() const { + for (SharedLibSection §ion : getSections()) { + if (section.type() == SectionType::DATA) { + return §ion; + } + } + return nullptr; + } + + const SharedLibSection *getRoDataSection() const { + for (SharedLibSection §ion : getSections()) { + if (section.type() == SectionType::RODATA) { + return §ion; + } + } + return nullptr; + } + + uintptr_t imagebase() const { + return get(); + } + + void imagebase(uintptr_t base) { + kwrite(address() + IMAGEBASE_OFFSET, base); + } + + RtldMeta *getMetaData() const { + if (meta == nullptr) [[unlikely]] { + uintptr_t addr = getMetaDataAddress(); + if (addr) { + meta = newRtldMeta(imagebase(), addr); + } else { + puts("null metadata"); + } + } + return meta.get(); + } + + uintptr_t getMetaDataAddress() const { + return get(); + } + + EhFrameInfo getEhFrameInfo() const { + return get(); + } + + void setEhFrameInfo(const EhFrameInfo &info) const { + kwrite(address() + EHFRAME_OFFSET, info); + } + + uintptr_t getEhFrameHdr() const { + return get(); + } + + void setEhFrameHdr(uintptr_t value) { + set(value); + } + + size_t getEhFrameHdrSize() const { + return get(); + } + + void setEhFrameHdrSize(uintptr_t value) { + set(value); + } + + uintptr_t getEhFrame() const { + return get(); + } + + void setEhFrame(uintptr_t value) { + set(value); + } + + size_t getEhFrameSize() const { + return get(); + } + + void setEhFrameSize(uintptr_t value) { + set(value); + } +}; + +class SharedLibIterable { + + uintptr_t addr; + int pid; + + public: + SharedLibIterable(decltype(nullptr)) : addr(), pid() {} + SharedLibIterable(uintptr_t addr, int pid) : addr(addr), pid(pid) {} + bool operator!=(decltype(nullptr)) const { return addr != 0; } + UniquePtr operator*() { + return new SharedLib{addr, pid}; + } + SharedLibIterable &operator++() { + uintptr_t ptr = 0; + kernel_copyout(addr, &ptr, sizeof(ptr)); + addr = ptr; + return *this; + } + uintptr_t getAddress() const noexcept { + return addr; + } +}; + +struct SharedLibIterator { + + uintptr_t addr; + int pid; + + SharedLibIterator(uintptr_t addr, int pid) : addr(addr), pid(pid) {} + SharedLibIterable begin() const { + return {addr, pid}; + } + decltype(nullptr) end() const { + return nullptr; + } + +}; + +class SharedObject : KernelObject { + + static constexpr size_t EBOOT_OFFSET = 0; + + mutable UniquePtr eboot; + + public: + int pid; + + SharedObject(uintptr_t addr, int pid) + : KernelObject(addr), eboot(nullptr), pid(pid) {} + + SharedLibIterator getLibs() const { + return {get(), pid}; + } + + SharedLib *getEboot() const { + if (eboot == nullptr) [[unlikely]] { + const auto ptr = get(); + if (ptr == 0) [[unlikely]] { + return nullptr; + } + eboot = new SharedLib{ptr, pid}; + } + return eboot.get(); + } + + UniquePtr getLib(int handle) const { + for (auto lib : getLibs()) { + if (lib->handle() == handle) { + return lib.release(); + } + } + return nullptr; + } + + + UniquePtr getLib(const StringView &name) const { + String fullname = name; + if (!name.endswith(".sprx"_sv)) { + fullname += ".sprx"_sv; + } + for (auto lib : getLibs()) { + printf("lib: %s\n", lib->getPath().c_str()); + if (lib->getPath().endswith(fullname)) { + return lib.release(); + } + } + return nullptr; + } +}; + +class RtldMeta : public KernelObject { + + static constexpr size_t TOTAL_SIZE_OFFSET = 0x20; + static constexpr size_t SYMTAB_OFFSET = 0x28; + static constexpr size_t SYMTAB_SIZE_OFFSET = 0x30; + static constexpr size_t STRTAB_OFFSET = 0x38; + static constexpr size_t STRTAB_SIZE_OFFSET = 0x40; + static constexpr size_t PLTTAB_OFFSET = 0x48; + static constexpr size_t PLTTAB_SIZE_OFFSET = 0x50; + + // mutable members for caching + mutable UniquePtr symTable; + mutable UniquePtr strTable; + mutable Array pltTbl; + + public: + uintptr_t imageBase; + RtldMeta(uintptr_t imageBase, uintptr_t addr) : + KernelObject(addr), symTable(nullptr), strTable(nullptr), pltTbl(nullptr), imageBase(imageBase) {} + + size_t totalSize() const { + return get(); + } + + uintptr_t symtab() const { + return get(); + } + + size_t symtabSize() const { + return get(); + } + + size_t nSymbols() const { + return symtabSize() / sizeof(Elf64_Sym); + } + + uintptr_t strtab() const { + return get(); + } + + size_t strtabSize() const { + return get(); + } + + uintptr_t plttab() const { + return get(); + } + + size_t pltTblSize() const { + return get(); + } + + size_t nPlt() const { + return pltTblSize() / sizeof(Elf64_Rela); + } + + const rtld::ElfSymbolTable &getSymbolTable() const { + if (symTable == nullptr) { + symTable = newSymbolTable(this); + } + return *symTable; + } + + const rtld::ElfStringTable &getStringTable() const { + if (strTable == nullptr) { + strTable = newStringTable(this); + } + return *strTable; + } + + const Array &getPltTable() const { + if (pltTbl == nullptr) { + pltTbl = Array(nPlt()); + kernel_copyout(plttab(), pltTbl.begin(), pltTblSize()); + } + return pltTbl; + } +}; + +class rtld::ElfStringTable { + + size_t size; + UniquePtr tbl; + + public: + ElfStringTable(const RtldMeta *meta) : size(meta->strtabSize()), tbl(new char[size]) { + kernel_copyout(meta->strtab(), tbl.get(), size); + } + ElfStringTable(const ElfStringTable &) = delete; + ElfStringTable &operator=(const ElfStringTable &) = delete; + ElfStringTable(ElfStringTable&&) noexcept = default; + ElfStringTable &operator=(ElfStringTable&&) noexcept = default; + ~ElfStringTable() noexcept = default; + + StringView operator[](size_t offset) const { + #ifdef DEBUG + if (offset >= size) [[unlikely]] { + fatalf("offset %llu is out of bounds for size %llu\n", offset, size); + } + #endif + return tbl.get() + offset; + } + + 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 { + + static constexpr auto EXPORT_MASK = 0x30; + + const RtldMeta *meta; + + public: + ElfSymbol(decltype(nullptr)) : Elf64_Sym(), meta(nullptr) {} + ElfSymbol(const RtldMeta *meta, const Elf64_Sym &sym) : Elf64_Sym(sym), meta(meta) {} + + StringView name() const { + return meta->getStringTable()[st_name]; + } + + bool exported() const { + // exported if the binding is global or weak and shndx is not 0 + return (st_info & EXPORT_MASK) && st_shndx != 0; + } + + uintptr_t vaddr() const { + return meta->imageBase + st_value; + } + + Nid nid() const { + return meta->getStringTable().getNid(st_name); + } + + explicit operator bool() const { return meta; } + +}; + + +class rtld::ElfSymbolTable { + + const RtldMeta *meta; + UniquePtr symbols; + size_t size; + + Elf64_Sym *begin() const { + return symbols.get(); + } + + Elf64_Sym *end() const { + return symbols.get() + size; + } + + public: + ElfSymbolTable(const RtldMeta *meta) : meta(meta), symbols(new Elf64_Sym[meta->nSymbols()]), size(meta->nSymbols()) { + kernel_copyout(meta->symtab(), symbols.get(), size * sizeof(Elf64_Sym)); + } + + const ElfSymbol operator[](size_t i) const { + #ifdef DEBUG + if (i >= size) [[unlikely]] { + fatalf("index %llu is out of bounds for length %llu\n", i, size); + } + #endif + return {meta, symbols.get()[i]}; + } + + const Elf64_Sym *getSymbol(size_t i) const { + return symbols.get() + i; + } + + ssize_t getSymbolIndex(const Nid &nid) const { + const ssize_t len = static_cast(size); + for (ssize_t i = 0; i < len; i++) { + if (meta->getStringTable().getNid(symbols[i].st_name) == nid) { + return i; + } + } + return -1; + } + + const ElfSymbol operator[](const Nid &nid) const { + for (Elf64_Sym &esym : *this) { + ElfSymbol sym{meta, esym}; + if (!sym.exported()) { + continue; + } + if (sym.nid() == nid) { + return sym; + } + } + return nullptr; + } + + const ElfSymbol operator[](Nid &&nid) const { + return this->operator[](nid); + } + + size_t length() const { + return size; + } + + const Elf64_Sym *c_symbols() const noexcept { + return symbols.get(); + } +}; + +namespace { + +static inline UniquePtr newRtldMeta(uintptr_t imageBase, uintptr_t addr) { + return new RtldMeta(imageBase, addr); +} + +static inline UniquePtr newSymbolTable(const RtldMeta *meta) { + return new rtld::ElfSymbolTable(meta); +} + +static inline UniquePtr newStringTable(const RtldMeta *meta) { + return new rtld::ElfStringTable(meta); +} + +} diff --git a/extern/libhijacker/include/mutex.hpp b/extern/libhijacker/include/mutex.hpp new file mode 100644 index 0000000..bcf1910 --- /dev/null +++ b/extern/libhijacker/include/mutex.hpp @@ -0,0 +1,166 @@ +#pragma once + +#include + +template +concept MutexType = requires(T &t) { + { t.lock() }; + { t.unlock() }; +}; + +template +class LockGuard { + Mtx *mtx; + +public: + LockGuard(Mtx &mtx) noexcept : mtx(&mtx) { + mtx.lock(); + } + LockGuard(const LockGuard&) = delete; + LockGuard &operator=(const LockGuard&) = delete; + LockGuard(LockGuard &&rhs) noexcept : mtx(rhs.mtx) { rhs.mtx = nullptr; } + LockGuard &operator=(LockGuard &&rhs) noexcept { + if (mtx) { + mtx->unlock(); + } + mtx = rhs.mtx; + rhs.mtx = nullptr; + } + ~LockGuard() noexcept { + if (mtx) [[likely]] { + mtx->unlock(); + mtx = nullptr; + } + } +}; + +template < + typename native_handle_type, + typename attr_type, + int initializer(native_handle_type*, const attr_type*), + int destroyer(native_handle_type*), + int locker(native_handle_type*), + int try_locker(native_handle_type*), + int unlocker(native_handle_type*), + pthread_mutextype mutextype = pthread_mutextype(0) +> +class BaseMutex { + +protected: + native_handle_type handle; + + void init() noexcept { + if (handle) [[likely]] { + return; + } + attr_type attr = nullptr; + if constexpr(mutextype != 0) { + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, mutextype); + } + initializer(&handle, &attr); + if constexpr(mutextype != 0) { + pthread_mutexattr_destroy(&attr); + } + } + +public: + constexpr BaseMutex() noexcept : handle(nullptr) {} + BaseMutex(const BaseMutex&) = delete; + BaseMutex &operator=(const BaseMutex&) = delete; + constexpr BaseMutex(BaseMutex &&rhs) noexcept : handle(rhs.handle) { rhs.handle = nullptr; } + BaseMutex &operator=(BaseMutex &&rhs) noexcept { + if (handle) { + destroyer(&handle); + } + handle = rhs.handle; + return *this; + } + ~BaseMutex() noexcept { + if (handle) [[likely]] { + destroyer(&handle); + handle = nullptr; + } + } + + native_handle_type native_handle() noexcept { return handle; } + void lock() noexcept { + init(); + locker(&handle); + } + bool try_lock() noexcept { + init(); + return try_locker(&handle) == 0; + } + void unlock() noexcept { + unlocker(&handle); + } +}; + +class Mutex : + public BaseMutex< + pthread_mutex_t, + pthread_mutexattr_t, + pthread_mutex_init, + pthread_mutex_destroy, + pthread_mutex_lock, + pthread_mutex_trylock, + pthread_mutex_unlock + > +{}; + +class RecursiveMutex : + public BaseMutex< + pthread_mutex_t, + pthread_mutexattr_t, + pthread_mutex_init, + pthread_mutex_destroy, + pthread_mutex_lock, + pthread_mutex_trylock, + pthread_mutex_unlock, + PTHREAD_MUTEX_RECURSIVE + > +{}; + +class RWMutex : + public BaseMutex< + pthread_rwlock_t , + pthread_rwlockattr_t , + pthread_rwlock_init, + pthread_rwlock_destroy, + pthread_rwlock_wrlock, + pthread_rwlock_trywrlock, + pthread_rwlock_unlock + > { + + class RLocker { + pthread_rwlock_t *handle; + public: + RLocker(pthread_rwlock_t *handle) noexcept : handle(handle) {} + RLocker(const RLocker&) = delete; + RLocker &operator=(const RLocker&) = delete; + RLocker(RLocker &&rhs) noexcept : handle(rhs.handle) { rhs.handle = nullptr; } + RLocker &operator=(RLocker &&rhs) noexcept = delete; + ~RLocker() noexcept = default; + void lock() noexcept { + pthread_rwlock_rdlock(handle); + } + void unlock() noexcept { + pthread_rwlock_unlock(handle); + } + }; + +public: + void rdlock() noexcept { + init(); + pthread_rwlock_rdlock(&handle); + } + bool try_rdlock() noexcept { + init(); + return pthread_rwlock_tryrdlock(&handle) == 0; + } + RLocker rlocker() noexcept { + init(); + return &handle; + } +}; diff --git a/extern/libhijacker/include/nid.hpp b/extern/libhijacker/include/nid.hpp new file mode 100644 index 0000000..56ff360 --- /dev/null +++ b/extern/libhijacker/include/nid.hpp @@ -0,0 +1,104 @@ +#pragma once + +extern "C" { + #include + #include +} + +namespace { + +static constexpr size_t NID_LENGTH = 11; + +} + +union Nid { + + char str[NID_LENGTH + 1]; // 12th character is for NULL terminator to allow constexpr constructor + struct __attribute__((packed)) data_t { + int_fast64_t low; + int_fast32_t hi; + } data; + + Nid() noexcept = default; + + explicit constexpr Nid(const char *nid) noexcept : str{} { + __builtin_memcpy(str, nid, NID_LENGTH); + str[NID_LENGTH] = '\0'; + } + + constexpr int_fast64_t operator<=>(const Nid& rhs) const { + auto i = data.low - rhs.data.low; + if (i == 0) [[unlikely]] { + return data.hi - rhs.data.hi; + } + return i; + } + + constexpr bool operator==(const Nid &rhs) const { + return data.low == rhs.data.low && data.hi == rhs.data.hi; + } + + constexpr void setNullTerminator() { + str[NID_LENGTH] = '\0'; + } +}; + +namespace nid { + +static inline constexpr Nid get_authinfo{"igMefp4SAv0"}; +static inline constexpr Nid sceFsUmountGamePkg{"UQTSykySQ40"}; +static inline constexpr Nid abort{"L1SBTkC+Cvw"}; +static inline constexpr Nid strstr{"viiwFMaNamA"}; +static inline constexpr Nid sceSystemServiceGetAppStatus{"t5ShV0jWEFE"}; +static inline constexpr Nid sceSystemServiceAddLocalProcess{"0cl8SuwosPQ"}; +static inline constexpr Nid socketpair{"MZb0GKT3mo8"}; +static inline constexpr Nid usleep{"QcteRwbsnV0"}; +static inline constexpr Nid _errno{"9BcDykPmo1I"}; +static inline constexpr Nid sceSysmoduleLoadModuleInternal{"39iV5E1HoCk"}; +static inline constexpr Nid sceSysmoduleLoadModuleByNameInternal{"CU8m+Qs+HN4"}; +static inline constexpr Nid mmap{"BPE9s9vQQXo"}; +static inline constexpr Nid sceSysmoduleLoadModule{"g8cM39EUZ6o"}; +static inline constexpr Nid munmap{"UqDGjXA5yUM"}; +static inline constexpr Nid sceKernelJitCreateSharedMemory{"avvJ3J0H0EY"}; +static inline constexpr Nid sceKernelUnloadModule{"QKd0qM58Qes"}; +static inline constexpr Nid socket{"TU-d9PfIHPM"}; +static inline constexpr Nid pipe{"-Jp7F+pXxNg"}; +static inline constexpr Nid sceKernelDlsym{"LwG8g3niqwA"}; +static inline constexpr Nid setsockopt{"fFxGkxF2bVo"}; +static inline constexpr Nid execve{"kdguLiAheLI"}; +static inline constexpr Nid _nanosleep{"NhpspxdjEKU"}; +static inline constexpr Nid close{"bY-PO6JhzhQ"}; +static inline constexpr Nid connect{"XVL8So3QJUk"}; +static inline constexpr Nid send{"fZOeZIOEmLw"}; +static inline constexpr Nid recv{"Ez8xjo9UF4E"}; +static inline constexpr Nid rfork_thread{"bSDxEpGzmUE"}; +static inline constexpr Nid access{"8vE6Z6VEYyk"}; +static inline constexpr Nid sceKernelOpen{"1G3lF1Gg1k8"}; +static inline constexpr Nid mono_aot_get_method{"6t5G5dYpMVg"}; +static inline constexpr Nid sceKernelLoadStartModule{"wzvqT4UqKX8"}; +static inline constexpr Nid sceKernelDebugOutText("9JYNqN6jAKI"); +static inline constexpr Nid sceKernelGetFsSandboxRandomWord("JGfTMBOdUJo"); +static inline constexpr Nid open("wuCroIGjt2g"); + + +static inline constexpr Nid sceKernelSendNotificationRequest("zl7hupSO0C0"); + + +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"}; +static inline constexpr Nid mono_class_get_property_from_name{"KK8Cr0wE81M"}; +static inline constexpr Nid mono_class_from_name{"bzxTZSnnB38"}; +static inline constexpr Nid mono_runtime_invoke{"pre9BjkyDhs"}; +static inline constexpr Nid mono_string_new{"pXv-WCokNsY"}; +static inline constexpr Nid mono_assembly_get_image{"xP4EC4Sp9GI"}; +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"}; + +static inline constexpr Nid sceKernelIsDevelopmentMode{"UtO0OHMCgmI"}; +} diff --git a/extern/libhijacker/include/notify.hpp b/extern/libhijacker/include/notify.hpp new file mode 100644 index 0000000..7c622b5 --- /dev/null +++ b/extern/libhijacker/include/notify.hpp @@ -0,0 +1,34 @@ +#pragma once + +extern "C" +{ + #include + #include + #include + #include + #include + + 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 + + int32_t sceKernelSendNotificationRequest(int32_t device, OrbisNotificationRequest *req, size_t size, int32_t blocking); + +} + +void printf_notification(const char *fmt, ...); diff --git a/extern/libhijacker/include/offsets.hpp b/extern/libhijacker/include/offsets.hpp new file mode 100644 index 0000000..26fac05 --- /dev/null +++ b/extern/libhijacker/include/offsets.hpp @@ -0,0 +1,14 @@ + +extern "C" { + #include +} + +namespace offsets { + +size_t allproc(); +size_t security_flags(); +size_t qa_flags(); +size_t utoken_flags(); +size_t root_vnode(); + +} // offsets diff --git a/extern/libhijacker/include/util.hpp b/extern/libhijacker/include/util.hpp new file mode 100644 index 0000000..637c3c7 --- /dev/null +++ b/extern/libhijacker/include/util.hpp @@ -0,0 +1,894 @@ +#pragma once + +#include +extern "C" { + #include + #include + #include + #include + void *malloc(size_t length); + void free(void *ptr); + + void *realloc(void *ptr, size_t size); + +} + +// for things we need but can't have... yet... +// these are not identical to the standard ones and will have unexpected behavior + +#ifdef DEBUG +void printBacktrace(); +#ifdef CAN_EXIT +#pragma clang diagnostic ignored "-Wformat-security" +template +[[noreturn]] static void fatalf(const char *msg, Types... values) { + __builtin_printf(msg, values...); + printBacktrace(); + exit(0); +} +#else +#pragma clang diagnostic ignored "-Wformat-security" +template +static void fatalf(const char *msg, Types... values) { + __builtin_printf(msg, values...); + printBacktrace(); +} +#endif +#endif + +template +class UniquePtr { + + T *ptr; + + public: + explicit UniquePtr() : ptr(nullptr) {} + UniquePtr(decltype(nullptr)) : ptr(nullptr) {} + UniquePtr(T *ptr) : ptr(ptr) {} + UniquePtr(const UniquePtr &rhs) = delete; + UniquePtr &operator=(const UniquePtr &rhs) = delete; + UniquePtr(UniquePtr &&rhs) noexcept : ptr(rhs.ptr) { + rhs.ptr = nullptr; + } + UniquePtr &operator=(UniquePtr &&rhs) noexcept { + delete ptr; + ptr = rhs.ptr; + rhs.ptr = nullptr; + return *this; + } + ~UniquePtr() { delete ptr;} + + explicit operator bool() const { + return ptr != nullptr; + } + + T &operator*() { + #ifdef DEBUG + if (ptr == nullptr) [[unlikely]] { + fatalf("nullptr dereference\n"); + } + #endif + return *ptr; + } + + const T &operator*() const { + #ifdef DEBUG + if (ptr == nullptr) [[unlikely]] { + fatalf("nullptr dereference\n"); + } + #endif + return *ptr; + } + + T *operator->() const { + #ifdef DEBUG + if (ptr == nullptr) [[unlikely]] { + fatalf("nullptr dereference\n"); + } + #endif + return ptr; + } + + bool operator==(decltype(nullptr)) const { return ptr == nullptr; } + bool operator!=(decltype(nullptr)) const { return ptr != nullptr; } + + T *get() const { + return ptr; + } + + T *release() { + T *tmp = ptr; + ptr = nullptr; + return tmp; + } +}; + +template +class UniquePtr { + + T *ptr; + + public: + UniquePtr() = delete; + UniquePtr(decltype(nullptr)) : ptr(nullptr) {} + UniquePtr(T *ptr) : ptr(ptr) {} + UniquePtr(const UniquePtr &rhs) = delete; + UniquePtr &operator=(const UniquePtr &rhs) = delete; + UniquePtr(UniquePtr &&rhs) noexcept : ptr(rhs.ptr) { + rhs.ptr = nullptr; + } + UniquePtr &operator=(UniquePtr &&rhs) noexcept { + delete[] ptr; + ptr = rhs.ptr; + rhs.ptr = nullptr; + return *this; + } + ~UniquePtr() { delete[] ptr; } + + explicit operator bool() const { + return ptr; + } + + T &operator[](size_t i ) const { + #ifdef DEBUG + if (ptr == nullptr) [[unlikely]] { + fatalf("nullptr dereference\n"); + } + #endif + return ptr[i]; + } + + bool operator==(decltype(nullptr)) const { return ptr == nullptr; } + bool operator!=(decltype(nullptr)) const { return ptr != nullptr; } + + T *get() const { + #ifdef DEBUG + if (ptr == nullptr) [[unlikely]] { + fatalf("nullptr dereference\n"); + } + #endif + return ptr; + } + + T *release() { + T *tmp = ptr; + ptr = nullptr; + return tmp; + } +}; + + +class StringView { + const char * str; + size_t size; + + public: + constexpr StringView() : str(nullptr), size(0) {} + constexpr StringView(decltype(nullptr)) : str(nullptr), size(0) {} + + constexpr StringView(const char *str) : str(str), size(__builtin_strlen(str)) {} + + constexpr StringView(const char *str, unsigned long length) : str(str), size(length) {} + + constexpr char operator[](size_t i) const { + return str[i]; + } + + explicit operator bool() const { + return str; + } + + constexpr size_t length() const { + return size; + } + + operator const char*() const { + return str; + } + + constexpr const char *c_str() const { + return str; + } + + constexpr bool operator==(decltype(nullptr)) const { + return str == nullptr; + } + + constexpr bool operator==(const StringView &rhs) const { + if (size != rhs.size) { + return false; + } + if (str == rhs.str) { + return true; + } + if (str == nullptr || rhs.str == nullptr) { + return false; + } + return __builtin_memcmp(str, rhs.str, size) == 0; + } + + bool contains(const char *needle) const { + return __builtin_strstr(str, needle); + } + + constexpr bool endswith(const StringView &view) const { + const size_t sz = view.length(); + const char *buf = view.c_str(); + return sz > size ? false : __builtin_memcmp(str + (size - sz), buf, sz) == 0; + } + + constexpr bool startswith(const StringView &view) const { + const size_t sz = view.length(); + const char *buf = view.c_str(); + return sz > size ? false : __builtin_memcmp(str, buf, sz) == 0; + } + + constexpr int32_t operator<=>(const StringView &rhs) const { + return __builtin_strcmp(str, rhs.str); + } +}; + +constexpr StringView operator"" _sv(const char *str, unsigned long len) { return {str, len}; } + +// NOLINTBEGIN(cppcoreguidelines-owning-memory, cppcoreguidelines-pro-type-member-init) + +// +class String { + + static constexpr size_t SSO_MAX = 16; + + union StringBuf { + char *ptr; + char buf[SSO_MAX]; + }; + + StringBuf data; + size_t size; + size_t capacity; + + static constexpr size_t align(size_t x) { + auto r = x % SSO_MAX; + return r ? x + (SSO_MAX - r) : x; + } + + bool is_sso() const { return capacity == SSO_MAX; } + + void grow(size_t target) { + const size_t newCapacity = align(target); + if (capacity >= newCapacity) { + return; + } + if (is_sso()) { + char *tmp = new char[newCapacity]; + __builtin_memcpy(tmp, data.buf, size); + tmp[size] = '\0'; + data.ptr = tmp; + } else { + char *tmp = new char[newCapacity]; + __builtin_memcpy(tmp, data.ptr, size); + tmp[size] = '\0'; + delete[] data.ptr; + data.ptr = tmp; + } + capacity = newCapacity; + } + + char *buffer() { + return is_sso() ? data.buf : data.ptr; + } + + const char *buffer() const { + return is_sso() ? data.buf : data.ptr; + } + + public: + 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'; + } else { + data.ptr = new char[capacity]; + __builtin_memcpy(data.ptr, view.c_str(), size); + data.ptr[size] = '\0'; + } + } + String(const String &rhs) : size(rhs.size), capacity(rhs.capacity) { + if (is_sso()) { + __builtin_memcpy(data.buf, rhs.c_str(), size+1); + capacity = SSO_MAX; + } else { + data.ptr = new char[rhs.capacity]; + __builtin_memcpy(data.ptr, rhs.c_str(), size+1); + } + } + String &operator=(const String &rhs) { + size = rhs.size; + capacity = rhs.capacity; + if (is_sso()) { + __builtin_memcpy(data.buf, rhs.c_str(), size+1); + capacity = SSO_MAX; + } else { + data.ptr = new char[rhs.capacity]; + __builtin_memcpy(data.ptr, rhs.c_str(), size+1); + } + return *this; + } + String(String &&rhs) noexcept : size(rhs.size), capacity(rhs.capacity) { + if (is_sso()) { + __builtin_memcpy(data.buf, rhs.c_str(), size+1); + capacity = SSO_MAX; + } else { + capacity = rhs.capacity; + data.ptr = rhs.data.ptr; + rhs.data.ptr = nullptr; + } + } + String &operator=(String &&rhs) noexcept { + size = rhs.size; + capacity = rhs.capacity; + if (is_sso()) { + __builtin_memcpy(data.buf, rhs.c_str(), size+1); + capacity = SSO_MAX; + } else { + capacity = rhs.capacity; + data.ptr = rhs.data.ptr; + rhs.data.ptr = nullptr; + } + return *this; + } + ~String() { + if (!is_sso()) { + delete[] data.ptr; + } + } + + String &operator+=(const String &rhs) { + const size_t newsz = size + rhs.length(); + if (newsz >= capacity) { + grow(newsz + 1); // an additional character must be reserved for '\0' + } + char *__restrict ptr = buffer(); + __builtin_memcpy(ptr + size, rhs.c_str(), rhs.length()); + size = newsz; // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) + ptr[size] = '\0'; + return *this; // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) + } + + String &operator+=(const StringView &rhs) { + const size_t newsz = size + rhs.length(); + if (newsz >= capacity) { + grow(newsz + 1); // an additional character must be reserved for '\0' + } + char *__restrict ptr = buffer(); + __builtin_memcpy(ptr + size, rhs.c_str(), rhs.length()); + size = newsz; // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) + ptr[size] = '\0'; + return *this; // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) + } + + String operator+(const StringView &rhs) const noexcept { + String res = *this; + res += rhs; + return res; + } + + String &operator+=(const char c) { + const size_t newsz = size + 1; + if (newsz >= capacity) { + grow(newsz + 1); // an additional character must be reserved for '\0' + } + char *__restrict ptr = buffer(); + ptr[size++] = c; + ptr[size] = '\0'; + return *this; // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) + } + + bool operator==(const StringView &rhs) const { + if (size != rhs.length()) { + return false; + } + return __builtin_memcmp(buffer(), rhs.c_str(), size) == 0; + } + + const char *c_str() const { + return is_sso() ? data.buf : data.ptr; + } + + size_t length() const { + return size; + } + + bool contains(const char *needle) const { + return __builtin_strstr(buffer(), needle); + } + + bool endswith(const StringView &view) const { + const size_t sz = view.length(); + const char *buf = view.c_str(); + return sz > size ? false : __builtin_memcmp(buffer() + (size - sz), buf, sz) == 0; + } + + bool startswith(const StringView &view) const { + const size_t sz = view.length(); + const char *buf = view.c_str(); + return sz > size ? false : __builtin_memcmp(buffer(), buf, sz) == 0; + } + + operator StringView() const { + return {buffer(), size}; + } + + StringView subview(size_t from) const { + return subview(from, size); + } + + StringView subview(size_t from, size_t to) const { + return {buffer() + from, to - from}; + } + + String substring(size_t from) const { + return substring(from, size); + } + + String substring(size_t from, size_t to) const { + return StringView{buffer() + from, to - from}; + } + + ssize_t rfind(char c) const noexcept { + const char *ptr = strrchr(buffer(), c); + if (ptr == nullptr) { + return -1; + } + return ptr - buffer(); + } + + void reserve(size_t i) { + if (i > 0) [[likely]] { + 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) + +// +template +class Array { + + UniquePtr ptr; + size_t size; + + public: + Array(decltype(nullptr)) : ptr(nullptr), size(0) {} + Array(size_t size) : ptr(new T[size]), size(size) {} + Array(const Array &rhs) = delete; + Array &operator=(const Array &rhs) = delete; + Array(Array &&rhs) noexcept = default; + Array &operator=(Array &&rhs) noexcept = default; + ~Array() noexcept = default; + + size_t length() const { + return size; + } + T &operator[](size_t i) const { + #ifdef DEBUG + if (i >= size) [[unlikely]] { + fatalf("index %llu is out of bounds for length %llu\n", i, size); + } + #endif + return ptr[i]; + } + T *begin() const { + return ptr.get(); + } + T *end() const { + return ptr.get() + size; + } + explicit operator bool() const { + return (bool)ptr && size > 0; + } + bool operator==(decltype(nullptr)) const { + return ptr == nullptr; + } + T *data() { return ptr.get(); } + size_t shrink(size_t newSize) { + if (newSize < size) { + size = newSize; + } + return size; + } +}; + +template +class List; + +template +class _List_iterator; + +template +class _List_node { + friend class List; + friend class _List_iterator; + + UniquePtr<_List_node> next; + // don't need a doubly linked list + T value; + + public: + _List_node(T t) : next(nullptr), value(t) {} + _List_node(_List_node *next, T t) : next(next), value(t) {} + + template + _List_node(_List_node *next, Types ...values) : next(next), value(values...) {} + + T &operator*() { return value; } +}; + +template +class _List_iterator { + _List_node *it; + + public: + _List_iterator(decltype(nullptr)) :it(nullptr) {} + _List_iterator(_List_node *it) : it(it) {} + T &operator*() const { return **it; } + _List_iterator operator++(int) { + _List_iterator tmp = *this; + it = it->next; + return tmp; + } + _List_iterator &operator++() { + it = it->next.get(); + return *this; + } + bool operator!=(const _List_iterator &rhs) const { + // use reference equality of the nodes + return it != rhs.it; + } +}; + +template +class List { + UniquePtr<_List_node> head; + size_t size; + + public: + List() : head(nullptr), size(0) {} + + size_t length() const { return size; } + + template + T &emplace_front(Types ...values) { + // much cheaper to emplace in front + size++; + head = {new _List_node(head.release(), values...)}; + return head->value; + } + + T &push_front(const T &value) { + size++; + head = {new _List_node(head.release(), value)}; + return head->value; + } + + _List_iterator begin() const { + return head.get(); + } + + _List_iterator end() const { + return nullptr; + } + + const T& operator[](size_t i) const { + auto it = begin(); + for (size_t j = 0; j < i; j++) { + it++; + } + return *it; + } +}; + +template +class Vector { + + static constexpr size_t DEFAULT_CAPACITY = 16; + + T *first; + T *last; + T *eos; + + size_t available() const noexcept { + return eos - last; + } + + void grow(size_t cap) noexcept { + if (cap <= capacity()) { + return; + } + first = reallocate(first, cap); + eos = first + cap; + } + + constexpr void setSize(const size_t count, const size_t length, const T &value) noexcept { + if (length > count) { + if constexpr(!__is_trivially_destructible(T)) { + for (size_t i = count; i < length; i++) { + first[i].~T(); + } + } + } else { + grow(count); + for (size_t i = length; i < count; i++) { + first[i] = value; + } + } + last = first + count; + } + + static T *allocate(size_t n) noexcept { + return reinterpret_cast(malloc(n * sizeof(T))); // NOLINT + } + + static T *reallocate(T *ptr, size_t n) noexcept { + // if it fails we're screwed anyway + // no exceptions so we'll just run until fault + return reinterpret_cast(realloc(ptr, n * sizeof(T))); // NOLINT + } + + public: + Vector() noexcept : first(allocate(DEFAULT_CAPACITY)), last(first), eos(first + DEFAULT_CAPACITY) {} // NOLINT + + Vector(const Vector &rhs) noexcept : first(allocate(rhs.capacity())), last(first), eos(first + rhs.capacity()) { // NOLINT + if constexpr(__is_trivially_copyable(T)) { + __builtin_memcpy(first, rhs.first, rhs.size() * sizeof(T)); + } else { + const size_t length = rhs.size(); + for (size_t i = 0; i < length; i++) { + first[i] = rhs[i]; + } + } + } + + Vector &operator=(const Vector &rhs) noexcept { + if (this == &rhs) [[unlikely]] { + return *this; + } + + const size_t length = rhs.size(); + + if (capacity() < length) { + clear(); + } + + first = grow(rhs.capacity()); // NOLINT + last = first + length; + + if constexpr(__is_trivially_copyable(T)) { + __builtin_memcpy(first, rhs.first, length * sizeof(T)); + } else { + for (size_t i = 0; i < length; i++) { + first[i] = rhs[i]; + } + } + + return *this; + } + + Vector(Vector &&rhs) noexcept : first(rhs.first), last(rhs.last), eos(rhs.eos) { + rhs.first = nullptr; + } + + Vector &operator=(Vector &&rhs) noexcept { + free(first); + first = rhs.first; + last = rhs.last; + eos = rhs.eos; + rhs.first = nullptr; + return *this; + } + + ~Vector() noexcept { + free(first); + } + + constexpr T &at(size_t i) noexcept { + return first[i]; + } + + constexpr const T &at(size_t i) const noexcept { + return first[i]; + } + + constexpr T &operator[](size_t i) noexcept { + return first[i]; + } + + constexpr const T &operator[](size_t i) const noexcept { + return first[i]; + } + + constexpr T &front() noexcept { + return *first; + } + + constexpr const T &front() const noexcept { + return *first; + } + + constexpr T &back() noexcept { + return *last; + } + + constexpr const T &back() const noexcept { + return *last; + } + + constexpr T *data() noexcept { + return first; + } + + constexpr const T *data() const noexcept { + return first; + } + + constexpr T *begin() noexcept { + return first; + } + + constexpr const T *begin() const noexcept { + return first; + } + + constexpr const T *cbegin() const noexcept { + return first; + } + + constexpr T *end() noexcept { + return last; + } + + constexpr const T *end() const noexcept { + return last; + } + + constexpr const T *cend() const noexcept { + return last; + } + + constexpr bool empty() const noexcept { + return first == last; + } + + constexpr size_t size() const noexcept { + return last - first; + } + + constexpr void reserve(size_t length) noexcept { + if (length <= capacity()) { + return; + } + grow(length); + } + + constexpr size_t capacity() const noexcept { + return eos - first; + } + + constexpr void shrink_to_fit() noexcept { + if (size() <= capacity()) { + return; + } + first = reallocate(first, size()); + } + + constexpr void clear() noexcept { + if constexpr(!__is_trivially_destructible(T)) { + const size_t length = size(); + for (size_t i = 0; i < length; i++) { + first[i].~T(); + } + } + last = first; + } + + // ok I got lazy + + // + + constexpr T *erase(const T *pos) noexcept { + const size_t i = pos - first; + if constexpr(!__is_trivially_destructible(T)) { + first[i].~T(); + } + if (first + i != --last) { + __builtin_memcpy(last - i, first + i, size() * sizeof(T)); + } + return last; + } + + template + constexpr T &emplace_back(Args&&... args) noexcept { + return *last++ = T{args...}; + } + + constexpr void push_back(const T &value) noexcept { + *last++ = value; + } + + constexpr void push_back(T &&value) noexcept { + *last++ = static_cast(value); + } + + constexpr void pop_back() noexcept { + last--; + if constexpr(!__is_trivially_destructible(T)) { + last->~T(); /* patched: was '*last.~T()' (operator precedence bug) */ + } + } + + constexpr void resize(size_t count) noexcept { + const size_t length = size(); + if (length == count) { + return; + } + setSize(count, length, T()); + } + + constexpr void resize(size_t count, const T &value) noexcept { + const size_t length = size(); + if (length == count) { + return; + } + setSize(count, length, value); + } + + constexpr void swap(Vector &other) noexcept { + swap(*this, other); + } +}; + +// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers) + +// +[[maybe_unused]] static void hexdump(const void *ptr, size_t len) { + const uint8_t *buf = reinterpret_cast(ptr); + auto rows = len / 16; + for (size_t i = 0; i < rows; i++) { + auto j = i * 16; + __builtin_printf( + "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + buf[j], buf[j+1], buf[j+2], buf[j+3], buf[j+4], buf[j+5], buf[j+6], buf[j+7], + buf[j+8], buf[j+9], buf[j+10], buf[j+11], buf[j+12], buf[j+13], buf[j+14], buf[j+15] + ); + } + buf += rows * 16; + for (size_t i = 0; i < len % 16; i++) { + __builtin_printf("%02X ", buf[i]); + } + puts(""); +} + +#include +#include +#include +#include + + +// NOLINTEND(cppcoreguidelines-avoid-magic-numbers) diff --git a/homebrew.js b/homebrew.js new file mode 100644 index 0000000..e889ca0 --- /dev/null +++ b/homebrew.js @@ -0,0 +1,14 @@ +async function main() { + const PAYLOAD = window.workingDir + '/lapy_jb_daemon.elf'; + + return { + mainText: "lapy Jb daemon", + secondaryText: 'lapy Jb daemon', + onclick: async () => { + return { + path: PAYLOAD, + daemon: true + }; + } + }; +} diff --git a/lapy_jb_daemon.elf b/lapy_jb_daemon.elf new file mode 100644 index 0000000000000000000000000000000000000000..bccf85ef5770c1fe21ab42233413ea9f0061e56d GIT binary patch literal 543792 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 and populates KERNEL_ADDRESS_* extern + * globals (allproc, rootvnode, etc.) with the correct per-fw values. + * - The offsets_v940.cpp override (linked before -lhijacker) converts + * KERNEL_ADDRESS_* → relative offsets. Multi-fw transparent. + * - Compatible : every fw covered by ps5-payload-sdk's runtime tables + * (3.00 → 12.00 via kstuff/kstuff-lite + ps5-hen). + * + * Built with ps5-payload-sdk (John Törnblom). + * Credits : libhijacker (illusion + LightingMod), modified offsets by + * Team PHU / Arksama. + * ============================================================================ */ + +#include +#include +#include + +extern "C" { +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int klog_printf(const char *fmt, ...); +int sceNotificationSend(int userId, bool isLogged, const char *payload); +} + +/* libhijacker references kernel_base as extern "C" — the definition lives + * here as the standalone-payload entry point. Set from payload_args. */ +extern "C" uint64_t kernel_base = 0; + +#define LOG(fmt, ...) klog_printf("[lapy_jb] " fmt "\n", ##__VA_ARGS__) + +#define SANDBOX_BASE "/mnt/sandbox" +#define JB_FILE_RELPATH "/download0/etahen_jailbreak" +#define POLL_INTERVAL_US (250 * 1000) + +/* Modern Sony notification — kstuff-INDEPENDENT, libSceNotification IPC. */ +static void notif(const char *fmt, ...) { + char text[256]; + va_list ap; + va_start(ap, fmt); + vsnprintf(text, sizeof(text), fmt, ap); + va_end(ap); + char json[1024]; + snprintf(json, sizeof(json), + "{\"rawData\":{" + "\"viewTemplateType\":\"InteractiveToastTemplateB\"," + "\"channelType\":\"Downloads\"," + "\"useCaseId\":\"IDC\"," + "\"toastOverwriteType\":\"Yes\"," + "\"isImmediate\":true," + "\"priority\":100," + "\"viewData\":{" + "\"icon\":{\"type\":\"Predefined\",\"parameters\":{\"icon\":\"download\"}}," + "\"message\":{\"body\":\"%s\"}," + "\"subMessage\":{\"body\":\"Lapy JB Daemon\"}" + "}," + "\"platformViews\":{" + "\"previewDisabled\":{" + "\"viewData\":{" + "\"icon\":{\"type\":\"Predefined\",\"parameters\":{\"icon\":\"download\"}}," + "\"message\":{\"body\":\"%s\"}" + "}" + "}" + "}" + "}," + "\"localNotificationId\":\"LAPY_JB\"" + "}", + text, text); + sceNotificationSend(0xFE, true, json); +} + +/* ----- File helpers ------------------------------------------------------- */ +static ssize_t slurp_file(const char *path, char *buf, size_t buf_size) { + int fd = open(path, O_RDONLY); + if (fd < 0) return -1; + ssize_t n = read(fd, buf, buf_size - 1); + close(fd); + if (n < 0) return -1; + buf[n] = '\0'; + return n; +} + +/* Parse {"PID":""} JSON. Returns pid or -1. */ +static pid_t parse_pid_from_json(const char *json) { + const char *p = strstr(json, "\"PID\""); + if (!p) return -1; + p = strchr(p, ':'); + if (!p) return -1; + p++; + while (*p && (*p == ' ' || *p == '\t' || *p == '"')) p++; + if (!*p) return -1; + pid_t pid = (pid_t)atoi(p); + return pid > 0 ? pid : -1; +} + +/* Bump target's ucred via libhijacker (= jailbreak() : caps + authid + uid + + * sceAttr + sandbox escape via fd_rdir/jdir → rootvnode). Returns 0 on success. */ +static int do_jailbreak(pid_t target_pid) { + LOG("jailbreak attempt : pid=%d", target_pid); + auto hj = Hijacker::getHijacker(target_pid); + if (!hj) { + LOG("getHijacker(%d) FAIL — process likely exited", target_pid); + return -1; + } + /* libhijacker's jailbreak() does ALL of : + * - cr_uid / cr_ruid / cr_svuid = 0 + * - cr_ngroups = 0, cr_rgid = 0 + * - cr_sceCaps[0..1] = 0xFFFFFFFFFFFFFFFF + * - cr_sceAuthID = 0x4801000000000013 (jailbreak authid) + * - cr_sceAttr[0] = 0x80 at offset 0x83 (= unsandboxed) + * - fd_rdir / fd_jdir = rootvnode (= sandbox escape) + * Multi-fw via ps5-payload-sdk's runtime KERNEL_ADDRESS_*. */ + hj->jailbreak(/*escapeSandbox=*/ true); + LOG("jailbreak OK pid=%d", target_pid); + return 0; +} + +/* ----- Main loop ---------------------------------------------------------- */ +int main(void) { + LOG("======================================"); + LOG(" Lapy JB Daemon v1.2 (multi-fw)"); + LOG(" No etaHEN, no PHU required"); + LOG("======================================"); + + payload_args_t *args = payload_get_args(); + if (!args) { + LOG("FATAL : payload_get_args() returned NULL — must run via elfldr/HBL"); + notif("Lapy JB FATAL : needs elfldr launcher"); + return 1; + } + kernel_base = args->kdata_base_addr; + LOG("kernel_base = 0x%lx", (uintptr_t)kernel_base); + + notif("Lapy JB Daemon active — launch your app"); + LOG("polling %s/_%s every %dms", + SANDBOX_BASE, JB_FILE_RELPATH, POLL_INTERVAL_US / 1000); + + char buf[512]; + char path[512]; + while (true) { + DIR *d = opendir(SANDBOX_BASE); + if (!d) { usleep(POLL_INTERVAL_US); continue; } + struct dirent *de; + while ((de = readdir(d)) != NULL) { + if (de->d_name[0] == '.') continue; + int n = snprintf(path, sizeof(path), "%s/%s%s", + SANDBOX_BASE, de->d_name, JB_FILE_RELPATH); + if (n <= 0 || (size_t)n >= sizeof(path)) continue; + + struct stat st; + if (stat(path, &st) != 0 || st.st_size == 0) continue; + + ssize_t got = slurp_file(path, buf, sizeof(buf)); + if (got > 0) { + pid_t pid = parse_pid_from_json(buf); + if (pid > 0) { + LOG("request from %s : pid=%d", de->d_name, pid); + if (do_jailbreak(pid) == 0) { + notif("%s pid=%d unsandboxed", de->d_name, (int)pid); + } else { + notif("Jailbreak FAIL pid=%d", (int)pid); + } + } else { + LOG("could not parse PID from '%s' (%s)", buf, path); + } + } + unlink(path); /* signal to PRX : bump done */ + } + closedir(d); + usleep(POLL_INTERVAL_US); + } + return 0; +} diff --git a/source/offsets_v940.cpp b/source/offsets_v940.cpp new file mode 100644 index 0000000..7365cb3 --- /dev/null +++ b/source/offsets_v940.cpp @@ -0,0 +1,37 @@ +// Multi-fw libhijacker offsets override. +// +// libhijacker's vanilla offsets.cpp hardcodes fw 9.40 kernel-symbol offsets. +// This file replaces it with a multi-fw resolution path : ps5-payload-sdk +// already exposes the absolute kernel virtual addresses at runtime via the +// KERNEL_ADDRESS_* extern globals (auto-populated per-fw from kern.sdk_version, +// see ps5/kernel.h), so the only job here is converting absolute VA -> offset +// from kdata_base — which is what libhijacker's offsets:: namespace expects. +// +// Compile this .o BEFORE -lhijacker on the link line so the linker resolves +// the offsets:: symbols from here and skips the vanilla offsets.cpp.o that +// would otherwise be pulled from libhijacker.a. +// +// Covers every fw the SDK knows about (3.00 -> 12.00 via kstuff). On an +// unknown fw the SDK returns 0 and libhijacker fails cleanly with NULL +// attach — same graceful failure as the old 9.40-hardcoded path on wrong fw. + +extern "C" { +#include +#include +} + +namespace offsets { + +// Convert absolute kernel VA to offset from kernel_base. Signed-int +// subtraction so the high-half canonical addresses cancel cleanly. +static inline size_t rel(intptr_t absolute_va) { + return (size_t)(absolute_va - KERNEL_ADDRESS_DATA_BASE); +} + +size_t allproc() { return rel(KERNEL_ADDRESS_ALLPROC); } +size_t security_flags() { return rel(KERNEL_ADDRESS_SECURITY_FLAGS); } +size_t qa_flags() { return rel(KERNEL_ADDRESS_QA_FLAGS); } +size_t utoken_flags() { return rel(KERNEL_ADDRESS_UTOKEN_FLAGS); } +size_t root_vnode() { return rel(KERNEL_ADDRESS_ROOTVNODE); } + +}