From 737b1d38242104f2c93347a3ebe2803cf5bab9c2 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 2 Nov 2024 19:39:20 -0400 Subject: [PATCH] Make code more robust. Added Injector and Fixed crashes on Linux Use same injector on all platforms. --- CMakeLists.txt | 3 +- RemoteInput/Injection/Injector.hxx | 2 - RemoteInput/Injection/Injector_Arm.cpp | 3 + RemoteInput/Injection/Injector_Darwin.cxx | 1 + RemoteInput/Injection/Injector_Linux.cpp | 3 + RemoteInput/JVM.cxx | 3 +- RemoteInput/Platform/Platform_Darwin.mm | 107 ++- RemoteInput/Platform/Platform_Linux.cxx | 99 +- RemoteInput/Platform/Platform_Windows.cxx | 40 +- RemoteInput/Plugin/Plugin.cxx | 6 +- RemoteInput/Thirdparty/CMakeLists.txt | 47 +- RemoteInput/Thirdparty/Hook.cxx | 15 +- RemoteInput/Thirdparty/Hook.hxx | 2 +- RemoteInput/Thirdparty/Injector.cxx | 57 ++ RemoteInput/Thirdparty/Injector.hxx | 31 + .../Thirdparty/kubo_injector/LICENSE_GPL.txt | 280 ++++++ .../Thirdparty/kubo_injector/LICENSE_LGPL.txt | 458 ++++++++++ .../Thirdparty/kubo_injector/README.md | 298 ++++++ .../kubo_injector/include/injector.h | 245 +++++ .../Thirdparty/kubo_injector/src/linux/elf.c | 619 +++++++++++++ .../kubo_injector/src/linux/injector.c | 389 ++++++++ .../src/linux/injector_internal.h | 193 ++++ .../kubo_injector/src/linux/ptrace.c | 149 +++ .../kubo_injector/src/linux/remote_call.c | 821 +++++++++++++++++ .../kubo_injector/src/linux/shellcode.S | 70 ++ .../Thirdparty/kubo_injector/src/linux/util.c | 82 ++ .../kubo_injector/src/macos/exc_handler.c | 314 +++++++ .../kubo_injector/src/macos/injector.c | 295 ++++++ .../src/macos/injector_internal.h | 121 +++ .../Thirdparty/kubo_injector/src/macos/mach.c | 112 +++ .../kubo_injector/src/macos/mach_exc.h | 330 +++++++ .../kubo_injector/src/macos/mach_excServer.c | 828 +++++++++++++++++ .../kubo_injector/src/macos/ptrace.c | 81 ++ .../kubo_injector/src/macos/remote_call.c | 228 +++++ .../Thirdparty/kubo_injector/src/macos/util.c | 155 ++++ .../kubo_injector/src/windows/injector.c | 859 ++++++++++++++++++ .../kubo_injector/src/windows/injector.def | 9 + 37 files changed, 7243 insertions(+), 112 deletions(-) create mode 100644 RemoteInput/Thirdparty/Injector.cxx create mode 100644 RemoteInput/Thirdparty/Injector.hxx create mode 100644 RemoteInput/Thirdparty/kubo_injector/LICENSE_GPL.txt create mode 100644 RemoteInput/Thirdparty/kubo_injector/LICENSE_LGPL.txt create mode 100644 RemoteInput/Thirdparty/kubo_injector/README.md create mode 100644 RemoteInput/Thirdparty/kubo_injector/include/injector.h create mode 100644 RemoteInput/Thirdparty/kubo_injector/src/linux/elf.c create mode 100644 RemoteInput/Thirdparty/kubo_injector/src/linux/injector.c create mode 100644 RemoteInput/Thirdparty/kubo_injector/src/linux/injector_internal.h create mode 100644 RemoteInput/Thirdparty/kubo_injector/src/linux/ptrace.c create mode 100644 RemoteInput/Thirdparty/kubo_injector/src/linux/remote_call.c create mode 100644 RemoteInput/Thirdparty/kubo_injector/src/linux/shellcode.S create mode 100644 RemoteInput/Thirdparty/kubo_injector/src/linux/util.c create mode 100644 RemoteInput/Thirdparty/kubo_injector/src/macos/exc_handler.c create mode 100644 RemoteInput/Thirdparty/kubo_injector/src/macos/injector.c create mode 100644 RemoteInput/Thirdparty/kubo_injector/src/macos/injector_internal.h create mode 100644 RemoteInput/Thirdparty/kubo_injector/src/macos/mach.c create mode 100644 RemoteInput/Thirdparty/kubo_injector/src/macos/mach_exc.h create mode 100644 RemoteInput/Thirdparty/kubo_injector/src/macos/mach_excServer.c create mode 100644 RemoteInput/Thirdparty/kubo_injector/src/macos/ptrace.c create mode 100644 RemoteInput/Thirdparty/kubo_injector/src/macos/remote_call.c create mode 100644 RemoteInput/Thirdparty/kubo_injector/src/macos/util.c create mode 100644 RemoteInput/Thirdparty/kubo_injector/src/windows/injector.c create mode 100644 RemoteInput/Thirdparty/kubo_injector/src/windows/injector.def diff --git a/CMakeLists.txt b/CMakeLists.txt index db39712..f967244 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,7 +67,8 @@ IF(WIN32) set(EXTRA_LIBRARIES user32 opengl32 - gdi32) + gdi32 + dbghelp) # Needed for ThirdParty/kubo/injector ELSEIF(APPLE) find_library(FOUNDATION Foundation) find_library(COCOA Cocoa) diff --git a/RemoteInput/Injection/Injector.hxx b/RemoteInput/Injection/Injector.hxx index 5fff30c..0f15f0f 100644 --- a/RemoteInput/Injection/Injector.hxx +++ b/RemoteInput/Injection/Injector.hxx @@ -5,10 +5,8 @@ #ifndef REMOTEINPUT_INJECTOR_HXX #define REMOTEINPUT_INJECTOR_HXX -#include #include #include -#include class Injector { diff --git a/RemoteInput/Injection/Injector_Arm.cpp b/RemoteInput/Injection/Injector_Arm.cpp index 1f97cd5..dc99245 100644 --- a/RemoteInput/Injection/Injector_Arm.cpp +++ b/RemoteInput/Injection/Injector_Arm.cpp @@ -419,6 +419,9 @@ bool Injector::Inject(std::string module_path, std::int32_t pid, void* bootstrap ptrace(PTRACE_DETACH, pid, nullptr, nullptr); return false; } + + ptrace(PTRACE_DETACH, pid, nullptr, nullptr); + return true; } ptrace(PTRACE_DETACH, pid, nullptr, nullptr); diff --git a/RemoteInput/Injection/Injector_Darwin.cxx b/RemoteInput/Injection/Injector_Darwin.cxx index c309e97..389c492 100644 --- a/RemoteInput/Injection/Injector_Darwin.cxx +++ b/RemoteInput/Injection/Injector_Darwin.cxx @@ -7,6 +7,7 @@ #if defined(__APPLE__) #include #include +#include #include #include #include diff --git a/RemoteInput/Injection/Injector_Linux.cpp b/RemoteInput/Injection/Injector_Linux.cpp index 22e3568..8b52cef 100644 --- a/RemoteInput/Injection/Injector_Linux.cpp +++ b/RemoteInput/Injection/Injector_Linux.cpp @@ -391,6 +391,9 @@ bool Injector::Inject(std::string module_path, std::int32_t pid, void* bootstrap ptrace(PTRACE_DETACH, pid, nullptr, nullptr); return false; } + + ptrace(PTRACE_DETACH, pid, nullptr, nullptr); + return true; } ptrace(PTRACE_DETACH, pid, nullptr, nullptr); diff --git a/RemoteInput/JVM.cxx b/RemoteInput/JVM.cxx index 8a59d18..5e9e9cb 100644 --- a/RemoteInput/JVM.cxx +++ b/RemoteInput/JVM.cxx @@ -40,7 +40,6 @@ JVM::JVM() noexcept : vm(nullptr), createdVM(false), loadedJNI(false), module(nu } #endif - this->createdVM = false; jint num_vms = 0; const jint max_vms = 1; JavaVM* vms[max_vms] = {0}; @@ -48,7 +47,7 @@ JVM::JVM() noexcept : vm(nullptr), createdVM(false), loadedJNI(false), module(nu { for (int i = 0; i < num_vms; ++i) { - if (vms[i] != NULL) + if (vms[i] != nullptr) { this->vm = vms[i]; break; diff --git a/RemoteInput/Platform/Platform_Darwin.mm b/RemoteInput/Platform/Platform_Darwin.mm index 531225c..b26119e 100644 --- a/RemoteInput/Platform/Platform_Darwin.mm +++ b/RemoteInput/Platform/Platform_Darwin.mm @@ -13,14 +13,24 @@ #endif #include -#include +#if defined(CUSTOM_INJECTOR) +#include "Injection/Injector.hxx" +#else +#include "Thirdparty/Injector.hxx" +#endif #include #include #include #include +#include #endif // defined #if defined(__APPLE__) +std::string StripPath(const std::string& path_to_strip) +{ + return std::filesystem::path(path_to_strip).filename().string(); +} + void GetDesktopResolution(int &width, int &height) noexcept { auto get_screen_resolution = [&]{ @@ -117,10 +127,35 @@ bool IsThreadAlive(std::int32_t tid) noexcept std::string path = std::string(PATH_MAX, '\0'); if (realpath(info.dli_fname, &path[0])) { - if (Injector::Inject(info.dli_fname, pid, nullptr)) + #if defined(CUSTOM_INJECTOR) + if (Injector::Inject(path.c_str(), pid, nullptr)) { return pid; } + #else + extern std::vector> injectors; + + for (auto& injector : injectors) + { + if (injector && injector->get_pid() == pid) + { + if (injector->is_injected()) + { + return pid; + } + + return injector->Inject(path.c_str()) ? pid : -1; + } + } + + std::unique_ptr injector = std::make_unique(pid); + if (injector) + { + bool result = injector->Inject(path.c_str()); + injectors.push_back(std::move(injector)); + return result ? pid : -1; + } + #endif } } return -1; @@ -163,9 +198,13 @@ bool IsThreadAlive(std::int32_t tid) noexcept for (std::uint32_t i = 0; i < count; ++i) { const char* name = _dyld_get_image_name(i); - if (!strcasestr(name, partial_module_name)) + if (name) { - result.push_back(name); + std::string module_name = StripPath(name); + if (!strcasestr(module_name.c_str(), partial_module_name)) + { + result.push_back(name); + } } } @@ -178,43 +217,47 @@ bool IsThreadAlive(std::int32_t tid) noexcept for (std::uint32_t i = 0; i < count; ++i) { const char* name = _dyld_get_image_name(i); - if (strcasestr(name, module_name)) + if (name) { - return dlopen(name, RTLD_NOLOAD); - - /*const struct mach_header* header = _dyld_get_image_header(i); - //std::intptr_t offset = _dyld_get_image_vmaddr_slide(i); - - const struct load_command* cmd = reinterpret_cast(reinterpret_cast(header) + sizeof(struct mach_header)); - if (header->magic == MH_MAGIC_64) + std::string stripped_name = StripPath(name); + if (strcasestr(stripped_name.c_str(), module_name)) { - cmd = reinterpret_cast(reinterpret_cast(header) + sizeof(struct mach_header_64)); - } + return dlopen(name, RTLD_NOLOAD); - for (std::uint32_t j = 0; j < header->ncmds; ++j) - { - if (cmd->cmd == LC_SEGMENT) - { - const struct segment_command* seg = reinterpret_cast(cmd); - void* base_addr = reinterpret_cast(seg->vmaddr); //seg->vmaddr + offset; + /*const struct mach_header* header = _dyld_get_image_header(i); + //std::intptr_t offset = _dyld_get_image_vmaddr_slide(i); - Dl_info info = {0}; - dladdr(base_addr, &info); - return dlopen(info.dli_fname, RTLD_NOLOAD); + const struct load_command* cmd = reinterpret_cast(reinterpret_cast(header) + sizeof(struct mach_header)); + if (header->magic == MH_MAGIC_64) + { + cmd = reinterpret_cast(reinterpret_cast(header) + sizeof(struct mach_header_64)); } - if (cmd->cmd == LC_SEGMENT_64) + for (std::uint32_t j = 0; j < header->ncmds; ++j) { - const struct segment_command_64* seg = reinterpret_cast(cmd); - void* base_addr = reinterpret_cast(seg->vmaddr); //seg->vmaddr + offset; + if (cmd->cmd == LC_SEGMENT) + { + const struct segment_command* seg = reinterpret_cast(cmd); + void* base_addr = reinterpret_cast(seg->vmaddr); //seg->vmaddr + offset; - Dl_info info = {0}; - dladdr(base_addr, &info); - return dlopen(info.dli_fname, RTLD_NOLOAD); - } + Dl_info info = {0}; + dladdr(base_addr, &info); + return dlopen(info.dli_fname, RTLD_NOLOAD); + } + + if (cmd->cmd == LC_SEGMENT_64) + { + const struct segment_command_64* seg = reinterpret_cast(cmd); + void* base_addr = reinterpret_cast(seg->vmaddr); //seg->vmaddr + offset; + + Dl_info info = {0}; + dladdr(base_addr, &info); + return dlopen(info.dli_fname, RTLD_NOLOAD); + } - cmd = reinterpret_cast(reinterpret_cast(cmd) + cmd->cmdsize); - }*/ + cmd = reinterpret_cast(reinterpret_cast(cmd) + cmd->cmdsize); + }*/ + } } } return dlopen(module_name, RTLD_NOLOAD); diff --git a/RemoteInput/Platform/Platform_Linux.cxx b/RemoteInput/Platform/Platform_Linux.cxx index 945af3b..b165d30 100644 --- a/RemoteInput/Platform/Platform_Linux.cxx +++ b/RemoteInput/Platform/Platform_Linux.cxx @@ -1,7 +1,12 @@ #include "Platform.hxx" #if defined(__linux__) +#if defined(CUSTOM_INJECTOR) #include "Injection/Injector.hxx" +#else +#include "Thirdparty/Injector.hxx" +#endif + #include #include #include @@ -23,9 +28,15 @@ #include #include #include +#include #endif // defined #if defined(__linux__) +std::string StripPath(const std::string& path_to_strip) +{ + return std::filesystem::path(path_to_strip).filename().string(); +} + void GetDesktopResolution(int &width, int &height) noexcept { Display* display = XOpenDisplay(nullptr); @@ -191,10 +202,35 @@ std::int32_t InjectProcess(std::int32_t pid) noexcept std::string path = std::string(PATH_MAX, '\0'); if (realpath(info.dli_fname, &path[0])) { - if (Injector::Inject(info.dli_fname, pid, nullptr)) + #if defined(CUSTOM_INJECTOR) + if (Injector::Inject(path.c_str(), pid, nullptr)) { return pid; } + #else + extern std::vector> injectors; + + for (auto& injector : injectors) + { + if (injector && injector->get_pid() == pid) + { + if (injector->is_injected()) + { + return pid; + } + + return injector->Inject(path.c_str()) ? pid : -1; + } + } + + std::unique_ptr injector = std::make_unique(pid); + if (injector) + { + bool result = injector->Inject(path.c_str()); + injectors.push_back(std::move(injector)); + return result ? pid : -1; + } + #endif } } return -1; @@ -419,10 +455,10 @@ std::vector GetLoadedModuleNames(const char* partial_module_name) n if (info && info->dlpi_name) { Module* module_info = static_cast(data); - if (strcasestr(info->dlpi_name, module_info->module_name)) + std::string module_name = StripPath(info->dlpi_name); + if (strcasestr(module_name.c_str(), module_info->module_name)) { module_info->result.push_back(info->dlpi_name); - return 1; } } return 0; @@ -441,15 +477,16 @@ void* GetModuleHandle(const char* module_name) noexcept if (info && info->dlpi_name) { Module* module_info = static_cast(data); - if (strcasestr(info->dlpi_name, module_info->module_name)) + std::string module_name = StripPath(info->dlpi_name); + if (strcasestr(module_name.c_str(), module_info->module_name)) { module_info->result = dlopen(module_info->module_name, RTLD_NOLOAD); - return 1; + return module_info->result ? 1 : 0; } } return 0; - }, reinterpret_cast(&module_info)); - return module_info.result ?: dlopen(module_name, RTLD_NOLOAD); + }, &module_info); + return module_info.result ? module_info.result : dlopen(module_name, RTLD_NOLOAD); } #endif @@ -551,50 +588,6 @@ std::unique_ptr GetNativeReflector() noexcept { std::unique_ptr reflection; bool hasReflection = TimeOut(20, [&]{ - jclass cls = env->FindClass("java/awt/Frame"); - if (!cls) - { - return false; - } - - jmethodID method = env->GetStaticMethodID(cls, "getFrames", "()[Ljava/awt/Frame;"); - if (!method) - { - return false; - } - - jobjectArray frames = static_cast(env->CallStaticObjectMethod(cls, method)); - env->DeleteLocalRef(cls); - if (!frames) - { - return false; - } - - jsize size = env->GetArrayLength(frames); - for (jsize i = 0; i < size; ++i) - { - jobject frame = env->GetObjectArrayElement(frames, i); - if (frame) - { - if (IsValidFrame(env, frame)) - { - reflection = Reflection::Create(frame); - if (reflection) - { - env->DeleteLocalRef(frames); - return true; - } - } - - env->DeleteLocalRef(frame); - } - } - - env->DeleteLocalRef(frames); - return false; - }); - - bool hasReflection2 = !hasReflection && TimeOut(20, [&]{ if (!ModuleLoaded("libawt_xawt.so")) { return false; @@ -610,7 +603,7 @@ std::unique_ptr GetNativeReflector() noexcept void* windowFrame = reinterpret_cast(GetMainWindow()); if (windowFrame) { - jobject frame = awt_GetComponent(reflection->getEnv(), windowFrame); //java.awt.Frame + jobject frame = awt_GetComponent(env, windowFrame); //java.awt.Frame if (frame) { if (IsValidFrame(env, frame)) @@ -627,7 +620,7 @@ std::unique_ptr GetNativeReflector() noexcept }); }); - if (hasReflection || hasReflection2) + if (hasReflection) { return reflection; } diff --git a/RemoteInput/Platform/Platform_Windows.cxx b/RemoteInput/Platform/Platform_Windows.cxx index db615eb..426ade0 100644 --- a/RemoteInput/Platform/Platform_Windows.cxx +++ b/RemoteInput/Platform/Platform_Windows.cxx @@ -1,10 +1,15 @@ #include "Platform.hxx" + +#if defined(_WIN32) || defined(_WIN64) #include #include #include "Thirdparty/Hook.hxx" +#if defined(CUSTOM_INJECTOR) #include "Injection/Injector.hxx" +#else +#include "Thirdparty/Injector.hxx" +#endif -#if defined(_WIN32) || defined(_WIN64) #include #include #include @@ -270,16 +275,41 @@ bool InjectSelf(std::int32_t pid) noexcept { if (IsProcessAlive(pid)) { - std::string File; - File.resize(MAX_PATH); + std::string file; + file.resize(MAX_PATH); extern HMODULE module; - if (GetModuleFileName(module, &File[0], MAX_PATH) == 0) + if (GetModuleFileName(module, &file[0], MAX_PATH) == 0) { return false; } - return Injector::Inject(File, pid, nullptr); + #if defined(CUSTOM_INJECTOR) + return Injector::Inject(file, pid, nullptr); + #else + extern std::vector> injectors; + + for (auto& injector : injectors) + { + if (injector && injector->get_pid() == pid) + { + if (injector->is_injected()) + { + return true; + } + + return injector->Inject(file);; + } + } + + std::unique_ptr injector = std::make_unique(pid); + if (injector) + { + bool result = injector->Inject(file); + injectors.push_back(std::move(injector)); + return true; + } + #endif } return false; } diff --git a/RemoteInput/Plugin/Plugin.cxx b/RemoteInput/Plugin/Plugin.cxx index 370a5db..7f1ac6e 100644 --- a/RemoteInput/Plugin/Plugin.cxx +++ b/RemoteInput/Plugin/Plugin.cxx @@ -16,11 +16,13 @@ #include "EIOS.hxx" #include "DebugConsole.hxx" #include "Thirdparty/Hook.hxx" +#include "Thirdparty/Injector.hxx" #if defined(_WIN32) || defined(_WIN64) HMODULE module = nullptr; #endif +std::vector> injectors; std::unique_ptr control_center; std::unique_ptr console; @@ -140,10 +142,6 @@ void __exit_process(int exit_code) void* this_module = dlopen(this_info.dli_fname, RTLD_LAZY);*/ std::thread([&] { - #if defined(DEBUG) - console = std::make_unique(); - #endif - auto main_reflector = GetNativeReflector(); if (main_reflector) { diff --git a/RemoteInput/Thirdparty/CMakeLists.txt b/RemoteInput/Thirdparty/CMakeLists.txt index 367ea3b..9bc92d3 100644 --- a/RemoteInput/Thirdparty/CMakeLists.txt +++ b/RemoteInput/Thirdparty/CMakeLists.txt @@ -4,6 +4,9 @@ project(THIRD_PARTY_LIBRARIES VERSION 1.0.0 DESCRIPTION "Third Party") set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) +# ----------------------- ENABLE ASSEMBLY CODE ----------------------- +enable_language(ASM) + # ----------------------- INCLUDE_DIRECTORIES ----------------------- @@ -11,21 +14,28 @@ IF(WIN32) set(INCLUDE_DIRECTORIES min_hook/include min_hook/src - min_hook/src/hde) + min_hook/src/hde + kubo_injector/include + kubo_injector/src/windows) ELSEIF(APPLE) set(INCLUDE_DIRECTORIES rd_route/include - mach_inject/include) + mach_inject/include + kubo_injector/include + kubo_injector/src/macos) ELSE() set(INCLUDE_DIRECTORIES - linux_detours/include) + linux_detours/include + kubo_injector/include + kubo_injector/src/linux) ENDIF() # ----------------------------- LINKER ----------------------------- IF(WIN32) set(LIBRARIES_LIST - kernel32) + kernel32 + dbghelp) ELSEIF(APPLE) set(LIBRARIES_LIST dl @@ -52,11 +62,23 @@ IF(WIN32) min_hook/src/buffer.h min_hook/src/hook.c min_hook/src/trampoline.c - min_hook/src/trampoline.h) + min_hook/src/trampoline.h + kubo_injector/include/injector.h + kubo_injector/src/windows/injector.c) ELSEIF(APPLE) set(LIB_SRC_LIST rd_route/include/rd_route.h - rd_route/src/rd_route.c) + rd_route/src/rd_route.c + kubo_injector/include/injector.h + kubo_injector/src/macos/exc_handler.c + kubo_injector/src/macos/injector.c + kubo_injector/src/macos/injector_internal.h + kubo_injector/src/macos/mach.c + kubo_injector/src/macos/mach_exc.h + kubo_injector/src/macos/mach_excServer.c + kubo_injector/src/macos/ptrace.c + kubo_injector/src/macos/remote_call.c + kubo_injector/src/macos/util.c) ELSE() set(LIB_SRC_LIST linux_detours/include/detours.h @@ -68,13 +90,22 @@ ELSE() linux_detours/src/disasm.cpp linux_detours/src/plthook_elf.cpp linux_detours/src/trampoline_x86.cpp - linux_detours/src/trampoline_arm.cpp) + linux_detours/src/trampoline_arm.cpp + kubo_injector/src/linux/shellcode.S + kubo_injector/src/linux/elf.c + kubo_injector/src/linux/injector.c + kubo_injector/src/linux/injector_internal.h + kubo_injector/src/linux/ptrace.c + kubo_injector/src/linux/remote_call.c + kubo_injector/src/linux/util.c) ENDIF() set(SRC_LIST ${LIB_SRC_LIST} Hook.hxx - Hook.cxx) + Hook.cxx + Injector.cxx + Injector.hxx) # ---------------------------- COMPILE ---------------------------- diff --git a/RemoteInput/Thirdparty/Hook.cxx b/RemoteInput/Thirdparty/Hook.cxx index e2dfbae..ec8f47e 100644 --- a/RemoteInput/Thirdparty/Hook.cxx +++ b/RemoteInput/Thirdparty/Hook.cxx @@ -29,16 +29,18 @@ Hook::Hook(void* original, void* detour) : original(original), detour(detour), t MH_CreateHook(original, detour, &trampoline); } -Hook::Hook(Hook&& other) : original(nullptr), detour(nullptr), trampoline(nullptr), data() +Hook::Hook(Hook&& other) noexcept : original(other.original), detour(other.detour), trampoline(other.trampoline), data() { other.original = nullptr; other.detour = nullptr; other.trampoline = nullptr; + std::memcpy(&data[0], &other.data[0], sizeof(data)); std::memset(&other.data[0], 0, sizeof(data)); } Hook::~Hook() { + remove(); MH_Uninitialize(); } @@ -71,16 +73,18 @@ Hook::Hook(void* original, void* detour) : original(original), detour(detour), t } } -Hook::Hook(Hook&& other) : original(nullptr), detour(nullptr), trampoline(nullptr), data() +Hook::Hook(Hook&& other) noexcept : original(other.original), detour(other.detour), trampoline(other.trampoline), data() { other.original = nullptr; other.detour = nullptr; other.trampoline = nullptr; + std::memcpy(&data[0], &other.data[0], sizeof(data)); std::memset(&other.data[0], 0, sizeof(data)); } Hook::~Hook() { + remove(); trampoline = nullptr; } @@ -113,16 +117,19 @@ Hook::Hook(void *original, void *detour) : original(original), detour(detour), t std::memset(&data[0], 0, sizeof(data)); } -Hook::Hook(Hook&& other) : original(other.original), detour(other.detour), trampoline(other.trampoline), data() +Hook::Hook(Hook&& other) noexcept : original(other.original), detour(other.detour), trampoline(other.trampoline), data() { other.original = nullptr; other.detour = nullptr; other.trampoline = nullptr; + std::memcpy(&data[0], &other.data[0], sizeof(data)); std::memset(&other.data[0], 0, sizeof(data)); } Hook::~Hook() { + remove(); + delete static_cast(trampoline); trampoline = nullptr; } @@ -136,6 +143,6 @@ void Hook::apply() void Hook::remove() { - DetourUninstallHook(reinterpret_cast(&data[0])); + DetourUninstallHook(reinterpret_cast(trampoline)); } #endif diff --git a/RemoteInput/Thirdparty/Hook.hxx b/RemoteInput/Thirdparty/Hook.hxx index 96cca9c..a6cc4ae 100644 --- a/RemoteInput/Thirdparty/Hook.hxx +++ b/RemoteInput/Thirdparty/Hook.hxx @@ -20,7 +20,7 @@ private: public: Hook(void* original, void* detour); Hook(const Hook& other) = delete; - Hook(Hook&& other); + Hook(Hook&& other) noexcept; ~Hook(); Hook& operator = (const Hook& other) = delete; diff --git a/RemoteInput/Thirdparty/Injector.cxx b/RemoteInput/Thirdparty/Injector.cxx new file mode 100644 index 0000000..fc585ad --- /dev/null +++ b/RemoteInput/Thirdparty/Injector.cxx @@ -0,0 +1,57 @@ +// +// Created by brandon on 04/11/24. +// + +#include "Injector.hxx" +#include "kubo_injector/include/injector.h" + +Injector::Injector(std::int32_t pid) : pid(pid), injector(nullptr), handle(nullptr) +{ + if (injector_attach(reinterpret_cast(&injector), pid) != 0) + { + injector = nullptr; + } +} + +Injector::~Injector() +{ + if (injector) + { + injector_detach(reinterpret_cast(injector)); + } + + handle = nullptr; + injector = nullptr; +} + +bool Injector::Inject(std::string module_path) noexcept +{ + if (injector && !handle) + { + return injector_inject(static_cast(injector), module_path.c_str(), &handle) == 0; + } + return false; +} + +bool Injector::UnInject() noexcept +{ + if (injector && handle) + { + if (injector_uninject(static_cast(injector), handle) == 0) + { + handle = nullptr; + return true; + } + } + return false; +} + +std::int32_t Injector::get_pid() const noexcept +{ + return pid; +} + +bool Injector::is_injected() const noexcept +{ + return injector && handle; +} \ No newline at end of file diff --git a/RemoteInput/Thirdparty/Injector.hxx b/RemoteInput/Thirdparty/Injector.hxx new file mode 100644 index 0000000..b85282e --- /dev/null +++ b/RemoteInput/Thirdparty/Injector.hxx @@ -0,0 +1,31 @@ +// +// Created by brandon on 04/11/24. +// + +#ifndef INJECTOR_HXX +#define INJECTOR_HXX + +#include +#include + +class Injector +{ +private: + std::int32_t pid; + void* injector; + void* handle; + +public: + Injector(std::int32_t pid); + ~Injector(); + + bool Inject(std::string module_path) noexcept; + bool UnInject() noexcept; + + std::int32_t get_pid() const noexcept; + bool is_injected() const noexcept; +}; + + + +#endif //INJECTOR_HXX diff --git a/RemoteInput/Thirdparty/kubo_injector/LICENSE_GPL.txt b/RemoteInput/Thirdparty/kubo_injector/LICENSE_GPL.txt new file mode 100644 index 0000000..d8cf7d4 --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/LICENSE_GPL.txt @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/RemoteInput/Thirdparty/kubo_injector/LICENSE_LGPL.txt b/RemoteInput/Thirdparty/kubo_injector/LICENSE_LGPL.txt new file mode 100644 index 0000000..e9ab0b3 --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/LICENSE_LGPL.txt @@ -0,0 +1,458 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/RemoteInput/Thirdparty/kubo_injector/README.md b/RemoteInput/Thirdparty/kubo_injector/README.md new file mode 100644 index 0000000..3fd59c7 --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/README.md @@ -0,0 +1,298 @@ +# Injector + +[![tests](https://github.com/kubo/injector/actions/workflows/test.yml/badge.svg)](https://github.com/kubo/injector/actions/workflows/test.yml) +[![Static Badge](https://img.shields.io/badge/docs-API_reference-blue)](http://www.jiubao.org/injector/injector_8h.html) + +**Library for injecting a shared library into a Linux, Windows and MacOS process** + +## Linux + +> **Warning** +> Don't use this in production environments. It may stop target processes forever. See [Caveats](#caveats). + +I was inspired by [`linux-inject`][] and the basic idea came from it. +However the way to call `__libc_dlopen_mode` in `libc.so.6` is +thoroughly different. + +* `linux-inject` writes about 80 bytes of code to the target process + on x86_64. This writes only 4 ~ 16 bytes. +* `linux-inject` writes code at the firstly found executable region + of memory, which may be referred by other threads. This writes it + at [the entry point of `libc.so.6`][libc_main], which will be referred by + nobody unless the libc itself is executed as a program. + +[libc_main]: https://sourceware.org/git/?p=glibc.git;a=blob;f=csu/version.c;h=8c0ed79c01223e1f12b54d19f90b5e5b7dd78d27;hb=c804cd1c00adde061ca51711f63068c103e94eef#l67 + +## Windows + +Windows version is also here. It uses well-known [`CreateRemoteThread+LoadLibrary`] +technique to load a DLL into another process with some improvements. + +1. It gets Win32 error messages when `LoadLibrary` fails by copying assembly + code into the target process. +2. It can inject a 32-bit dll into a 32-bit process from x64 processes + by checking the export entries in 32-bit kernel32.dll. + +**Note:** It may work on Windows on ARM though I have not tested it because +I have no ARM machines. Let me know if it really works. + +## MacOS +The injector connects to the target process using task_for_pid and creates a mach-thread. If dlopen is called in this thread, the target process will fail with an error, however, it is possible to create another thread using pthread_create_from_mach_thread function for Mac >= 10.12 or pthread_create otherwise. In the created thread, the code for loading the library is executed. The second thread is created when injector_inject is called and terminated when injector_detach is called. +# Compilation + +## Linux + +```shell +$ git clone https://github.com/kubo/injector.git +$ cd injector +$ make +``` + +The `make` command creates: + +| filename | - | +|---|---| +|`src/linux/libinjector.a` |a static library| +|`src/linux/libinjector.so` |a shared library| +|`cmd/injector` |a command line program linked with the static library| + +## Windows (MSVC) + +Open a Visual Studio command prompt and run the following commands: + +```shell +$ git clone https://github.com/kubo/injector.git # Or use any other tool +$ cd injector +$ nmake -f Makefile.win32 +``` + +The `nmake` command creates: + +| filename | - | +|---|---| +|`src/windows/injector-static.lib` |a static library (release build) +|`src/windows/injector.dll` |a shared library (release build) +|`src/windows/injector.lib` |an import library for `injector.dll` +|`src/windows/injectord-static.lib` |a static library (debug build) +|`src/windows/injectord.dll` |a shared library (debug build) +|`src/windows/injectord.lib` |an import library for `injectord.dll` +|`cmd/injector.exe` |a command line program linked the static library (release build)| + +## Windows (mingw-w64) + +On MSYS2: + +```shell +$ git clone https://github.com/kubo/injector.git +$ cd injector +$ CC=gcc make +``` + +Cross-compilation on Linux: + +```shell +$ git clone https://github.com/kubo/injector.git +$ cd injector +$ CC=x86_64-w64-mingw32-gcc OS=Windows_NT make +``` + +The environment variable `OS=Windows_NT` must be set on Linux. + +## MacOS + +```shell +$ git clone https://github.com/TheOiseth/injector.git +$ cd injector +$ make +``` + +The `make` command creates: + +| filename | - | +|---|---| +|`src/macos/libinjector.a` |a static library| +|`src/macos/libinjector.dylib` |a shared library| +|`cmd/injector` |a command line program linked with the static library| + +**Important:** in order for the injector process to connect to another process using task_for_pid, it is necessary to [`disable SIP`][] or sign the injector with a self-signed certificate with debugging permission, for this: +```shell +$ cd cmd/macos-sign +$ chmod +x genkey.sh +$ ./genkey.sh +$ chmod +x sign.sh +$ ./sign.sh +``` +If injector still does not work after signing, reboot the system. + +# Usage + +## C API + +```c +#include + +... + + injector_t *injector; + void *handle; + + /* attach to a process whose process id is 1234. */ + if (injector_attach(&injector, 1234) != 0) { + printf("ATTACH ERROR: %s\n", injector_error()); + return; + } + /* inject a shared library into the process. */ + if (injector_inject(injector, "/path/to/shared/library", NULL) != 0) { + printf("INJECT ERROR: %s\n", injector_error()); + } + /* inject another shared library. */ + if (injector_inject(injector, "/path/to/another/shared/library", &handle) != 0) { + printf("INJECT ERROR: %s\n", injector_error()); + } + +... + + /* uninject the second shared library. */ + if (injector_uninject(injector, handle) != 0) { + printf("UNINJECT ERROR: %s\n", injector_error()); + } + + /* cleanup */ + injector_detach(injector); +``` + +## Command line program + +See [`Usage` section and `Sample` section in linux-inject][`inject`] and substitute +`inject` with `injector` in the page. + +# Tested Architectures + +## Linux + +x86_64: + +injector process \ target process | x86_64 | i386 | x32(*1) +---|---|---|--- +**x86_64** | :smiley: success(*2) | :smiley: success(*3) | :smiley: success(*6) +**i386** | :skull: failure(*4) | :smiley: success(*3) | :skull: failure(*5) +**x32**(*1) | :skull: failure(*4) | :smiley: success(*6) | :skull: failure(*5) + +*1: [x32 ABI](https://en.wikipedia.org/wiki/X32_ABI) +*2: tested on github actions with both glibc and musl. +*3: tested on github actions with glibc. +*4: failure with `64-bit target process isn't supported by 32-bit process`. +*5: failure with `x32-ABI target process is supported only by x86_64`. +*6: tested on a local machine. `CONFIG_X86_X32` isn't enabled in github actions. + +ARM: + +injector process \ target process | arm64 | armhf | armel +---|---|---|--- +**arm64** | :smiley: success | :smiley: success | :smiley: success +**armhf** | :skull: failure(*1) | :smiley: success | :smiley: success +**armel** | :skull: failure(*1) | :smiley: success | :smiley: success + +*1: failure with `64-bit target process isn't supported by 32-bit process`. + +MIPS: + +injector process \ target process | mips64el | mipsel (n32) | mipsel (o32) +---|---|---|--- +**mips64el** | :smiley: success (*1) | :smiley: success (*1) | :smiley: success (*1) +**mipsel (n32)** | :skull: failure(*2) | :smiley: success (*1) | :smiley: success (*1) +**mipsel (o32)** | :skull: failure(*2) | :smiley: success (*1) | :smiley: success (*1) + +*1: tested on [debian 11 mips64el](https://www.debian.org/releases/bullseye/mips64el/ch02s01.en.html#idm271) on [QEMU](https://www.qemu.org/). +*2: failure with `64-bit target process isn't supported by 32-bit process`. + +PowerPC: + +* **ppc64le** (tested on [alpine 3.16.2 ppc64le](https://dl-cdn.alpinelinux.org/alpine/v3.16/releases/ppc64le/) on [QEMU](https://www.qemu.org/)) +* **powerpc (big endian)** (tested on [ubuntu 16.04 powerpc](https://old-releases.ubuntu.com/releases/xenial/) on [QEMU](https://www.qemu.org/) + +RISC-V: + +* **riscv64** (tested on [Ubuntu 22.04.1 riscv64 on QEMU](https://wiki.ubuntu.com/RISC-V#Booting_with_QEMU)) + +## Windows + +Windows x64: + +injector process \ target process | x64 | x86 +---|---|--- +**x64** | :smiley: success(*2) | :smiley: success(*2) +**x86** | :skull: failure(*1) | :smiley: success(*2) + +*1: failure with `x64 target process isn't supported by x86 process`. +*2: tested on github actions + +Windows 11 on Arm: + +injector process \ target process | arm64 | arm64ec | x64 | x86 | arm32 +---|---|---|---|---|--- +**arm64** | :smiley: success | :skull: failure | :skull: failure | :skull: failure | :smiley: success +**arm64ec** | :skull: failure | :smiley: success | :smiley: success | :skull: failure | :skull: failure +**x64** | :skull: failure | :smiley: success | :smiley: success | :skull: failure | :skull: failure +**x86** | :skull: failure | :skull: failure | :skull: failure | :smiley: success | :skull: failure +**arm32** | :skull: failure | :skull: failure | :skull: failure | :skull: failure | :smiley: success + +[Wine](https://www.winehq.org/) (on Linux x86_64): + +injector process \ target process | x64 | x86 +---|---|--- +**x64** | :smiley: success | :skull: failure +**x86** | :skull: failure | :smiley: success + +## MacOS + +injector process \ target process | x64 | arm64 +---|---|--- +**x64** | :smiley: success(*1) | :skull: failure(*2) +**arm64** | :skull: failure(*3) | :smiley: success + +*1: failure with `x86_64 target process isn't supported by x86_64 process on ARM64 machine`. Tested on github actions. +*2: failure with `arm64 target process isn't supported by x86_64 process.` +*3: failure with `x86_64 target process isn't supported by arm64 process.` + +# Caveats + +**The following restrictions are only on Linux.** + +Injector doesn't work where `ptrace()` is disallowed. + +* Non-children processes (See [Caveat about `ptrace()`][]) +* Docker containers on docker version < 19.03 or linux kernel version < 4.8. You need to pass [`--cap-add=SYS_PTRACE`](https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities) +to `docker run` to allow it in the environments. +* Linux inside of UserLAnd (Android App) (See [here](https://github.com/kubo/injector/issues/17#issuecomment-1113990177)) + +Injector calls functions inside of a target process interrupted by `ptrace()`. +If the target process is interrupted while holding a non-reentrant lock and +injector calls a function requiring the same lock, the process stops forever. +If the lock type is reentrant, the status guarded by the lock may become inconsistent. +As far as I checked, `dlopen()` internally calls `malloc()` requiring non-reentrant +locks. `dlopen()` also uses a reentrant lock to guard information about loaded files. + +On Linux x86_64 `injector_inject_in_cloned_thread` in place of `injector_inject` +may be a solution of the locking issue. It calls `dlopen()` in a thread created by +[`clone()`]. Note that no wonder there are unexpected pitfalls because some resources +allocated in [`pthread_create()`] lack in the `clone()`-ed thread. Use it at +your own risk. + +# License + +Files under [`include`][] and [`src`][] are licensed under LGPL 2.1 or later. +Files under [`cmd`][] are licensed under GPL 2 or later. +Files under [`util`][] are licensed under 2-clause BSD. + +[`linux-inject`]: https://github.com/gaffe23/linux-inject +[Caveat about `ptrace()`]: https://github.com/gaffe23/linux-inject#caveat-about-ptrace +[`inject`]: https://github.com/gaffe23/linux-inject#usage +[`clone()`]: https://man7.org/linux/man-pages/man2/clone.2.html +[`cmd`]: cmd +[`include`]: include +[`pthread_create()`]: https://man7.org/linux/man-pages/man3/pthread_create.3.html +[`src`]: src +[`util`]: util +[`CreateRemoteThread+LoadLibrary`]: https://www.google.com/search?&q=CreateRemoteThread+LoadLIbrary +[`disable SIP`]: https://developer.apple.com/documentation/security/disabling_and_enabling_system_integrity_protection diff --git a/RemoteInput/Thirdparty/kubo_injector/include/injector.h b/RemoteInput/Thirdparty/kubo_injector/include/injector.h new file mode 100644 index 0000000..55158d6 --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/include/injector.h @@ -0,0 +1,245 @@ +/* -*- indent-tabs-mode: nil -*- + * + * injector - Library for injecting a shared library into a Linux process + * + * URL: https://github.com/kubo/injector + * + * ------------------------------------------------------ + * + * Copyright (C) 2018-2023 Kubo Takehiro + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/*! + * \file injector.h + * \brief Library for injecting a shared library into a Linux, Windows and macOS process + */ +#ifndef INJECTOR_H +#define INJECTOR_H + +#if defined(_WIN32) +#include +typedef DWORD injector_pid_t; +#else +#include + +/*! + * \brief Platform-dependent process id type (\c pid_t on Unix. \c DWORD on Windows) + */ +typedef pid_t injector_pid_t; +#endif + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +#define INJERR_SUCCESS 0 /* linux, windows, macos */ +#define INJERR_OTHER -1 /* linux, windows, macos */ +#define INJERR_NO_MEMORY -2 /* linux, windows, macos */ +#define INJERR_NO_PROCESS -3 /* linux, windows, macos */ +#define INJERR_NO_LIBRARY -4 /* linux */ +#define INJERR_NO_FUNCTION -4 /* linux */ +#define INJERR_ERROR_IN_TARGET -5 /* linux, windows, macos */ +#define INJERR_FILE_NOT_FOUND -6 /* linux, windows, macos */ +#define INJERR_INVALID_MEMORY_AREA -7 /* linux, macos */ +#define INJERR_PERMISSION -8 /* linux, windows, macos */ +#define INJERR_UNSUPPORTED_TARGET -9 /* linux, windows, macos */ +#define INJERR_INVALID_ELF_FORMAT -10 /* linux */ +#define INJERR_WAIT_TRACEE -11 /* linux */ +#define INJERR_FUNCTION_MISSING -12 /* linux, windows, macos */ + +typedef struct injector injector_t; + +/*! + * \brief Attach to the specified process. + * \param[out] injector the address where the newly created injector handle will be stored + * \param[in] pid the process id to be attached + * \return zero on success. Otherwise, error code + */ +int injector_attach(injector_t **injector, injector_pid_t pid); + +/*! + * \brief Detach from the attached process and destroy the specified handle. + * \param[in] injector the injector handle to destroy + * \return zero on success. Otherwise, error code + */ +int injector_detach(injector_t *injector); + +/*! + * \brief Inject the specified shared library into the target process. + * \param[in] injector the injector handle specifying the target process + * \param[in] path the path name of the shared library + * \param[out] handle the address where the newly created module handle will be stored + * \return zero on success. Otherwise, error code + * + * Note on Linux: + * This calls functions inside of the target process interrupted by \c ptrace(). + * If the target process is interrupted while holding a non-reentrant lock and + * injector calls a function requiring the same lock, the process stops forever. + * If the lock type is reentrant, the status guarded by the lock may become inconsistent. + * As far as I checked, \c dlopen() internally calls \c malloc() requiring non-reentrant + * locks. \c dlopen() also uses a reentrant lock to guard information about loaded files. + */ +int injector_inject(injector_t *injector, const char *path, void **handle); + +/*! + * \brief Uninject the shared library specified by \c handle. + * \param[in] injector the injector handle specifying the target process + * \param[in] handle the module handle created by \c injector_inject + * \return zero on success. Otherwise, error code + * \remarks This fearute isn't supported for musl-libc processes. + * See [Functional differences from glibc](https://wiki.musl-libc.org/functional-differences-from-glibc.html#Unloading_libraries). + */ +int injector_uninject(injector_t *injector, void *handle); + +#if defined(INJECTOR_DOC) || defined(__linux__) || defined(__APPLE__) +/*! + * \brief Call the specified function taking no arguments in the target process (Linux and macOS only) + * \param[in] injector the injector handle specifying the target process + * \param[in] handle the module handle created by \c injector_inject or special-handles such as \c RTLD_DEFAULT + * \param[in] name the function name + * + * The \c handle and \c name arguments are passed to \c dlsym ([Linux](https://man7.org/linux/man-pages/man3/dlvsym.3.html), [macOS](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dlsym.3.html)) and then the return value of \c dlsym is called without arguments in the target process. + * + * This is same with the combination of injector_remote_func_addr() and injector_remote_call() without extra arguments. + * + * \note + * (Linux only) + * If the function in the target process internally calls non-[async-signal-safe]((https://man7.org/linux/man-pages/man7/signal-safety.7.html)) + * functions, it may stop the target process or cause unexpected behaviour. + * \sa injector_remote_func_addr(), injector_remote_call(), injector_remote_vcall() + */ +int injector_call(injector_t *injector, void *handle, const char* name); +#endif + +/*! + * \brief Get the message of the last error. + * \remarks The message is updated only when \c injector functions return non-zero. + */ +const char *injector_error(void); + +#if defined(INJECTOR_DOC) || defined(__linux__) || defined(_WIN32) +#define INJECTOR_HAS_REMOTE_CALL_FUNCS 1 +#include +#include + +/*! + * \brief Get the function address in the target process (Linux and Windows only) + * \param[in] injector the injector handle specifying the target process + * \param[in] handle the module handle created by \c injector_inject or special-handles such as \c RTLD_DEFAULT + * \param[in] name the function name + * \param[out] func_addr_out the address where the function address in the target process will be stored + * \return zero on success. Otherwise, error code + * + * \b Example + * + * Inject libfoo.so and then call foo_func(1, 2, 3) in it. + * \code + * void *handle; + * // inject libfoo.so and get the handle + * if (injector_inject(injector, "libfoo.so", &handle) != 0) { + * return; + * } + * size_t func_addr; + * // get the address of foo_func in the handle + * if (injector_remote_func_addr(injector, handle, "foo_func", &func_addr) != 0) { + * return; + * } + * intptr_t retval; + * // call foo_func + * if (injector_remote_call(injector, &retval, func_addr, 1, 2, 3) != 0) { + * return; + * } + * printf("The return value of foo_func(1, 2, 3) is %ld.\n", retval); + * \endcode + */ +int injector_remote_func_addr(injector_t *injector, void *handle, const char* name, size_t *func_addr_out); + +/*! + * \brief Call the function in the target process (Linux and Windows only) + * \param[in] injector the injector handle specifying the target process + * \param[out] retval \c NULL or the address where the return value of the function call will be stored + * \param[in] func_addr the function address in the target process + * \param[in] ... arguments passed to the function + * \return zero on success. Otherwise, error code + * \remarks + * The types of the arguments must be integer or pointer. + * If it is a pointer, it must point to a valid address in the target process. + * The number of arguments must be less than or equal to six. + * \note + * If the function in the target process internally calls non-[async-signal-safe]((https://man7.org/linux/man-pages/man7/signal-safety.7.html)) + * functions, it may stop the target process or cause unexpected behaviour. + * \sa injector_remote_func_addr(), injector_remote_vcall() + */ +int injector_remote_call(injector_t *injector, intptr_t *retval, size_t func_addr, ...); + +/*! + * \brief Call the function in the target process (Linux and Windows only) + * \param[in] injector the injector handle specifying the target process + * \param[out] retval \c NULL or the address where the return value of the function call will be stored + * \param[in] func_addr the function address in the target process + * \param[in] ap arguments passed to the function + * \return zero on success. Otherwise, error code + * \remarks + * The types of the arguments must be integer or pointer. + * If it is a pointer, it must point to a valid address in the target process. + * The number of arguments must be less than or equal to six. + * \note + * If the function in the target process internally calls non-[async-signal-safe]((https://man7.org/linux/man-pages/man7/signal-safety.7.html)) + * functions, it may stop the target process or cause unexpected behaviour. + * \sa injector_remote_func_addr(), injector_remote_call() + */ +int injector_remote_vcall(injector_t *injector, intptr_t *retval, size_t func_addr, va_list ap); +#endif + +#if defined(INJECTOR_DOC) || defined(_WIN32) +/*! + * \brief Same with \c injector_inject except the type of the \c path argument. (Windows only) + * \param[in] injector the injector handle specifying the target process + * \param[in] path the path name of the shared library + * \param[out] handle the address where the newly created module handle will be stored + * \return zero on success. Otherwise, error code + */ +int injector_inject_w(injector_t *injector, const wchar_t *path, void **handle); +#endif + +#if defined(INJECTOR_DOC) || (defined(__linux__) && defined(__x86_64__)) +#define INJECTOR_HAS_INJECT_IN_CLONED_THREAD 1 // feature test macro +/*! + * \brief Inject the specified shared library into the target process by the \c clone system call. (Linux x86_64 only) + * \param[in] injector the injector handle specifying the target process + * \param[in] path the path name of the shared library + * \param[out] handle the address where the newly created module handle will be stored + * \return zero on success. Otherwise, error code + * + * This calls `dlopen()` in a thread created by \c [clone()](https://man7.org/linux/man-pages/man2/clone.2.html). Note that no wonder there are unexpected + * pitfalls because some resources allocated in \c [pthread_create()](https://man7.org/linux/man-pages/man3/pthread_create.3.html) lack in the \c clone()-ed thread. + * Use it at your own risk. + */ +int injector_inject_in_cloned_thread(injector_t *injector, const char *path, void **handle); +#endif + +#if 0 +{ +#endif +#ifdef __cplusplus +}; /* extern "C" */ +#endif + +#endif diff --git a/RemoteInput/Thirdparty/kubo_injector/src/linux/elf.c b/RemoteInput/Thirdparty/kubo_injector/src/linux/elf.c new file mode 100644 index 0000000..88c30d5 --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/src/linux/elf.c @@ -0,0 +1,619 @@ +/* -*- indent-tabs-mode: nil -*- + * + * injector - Library for injecting a shared library into a Linux process + * + * URL: https://github.com/kubo/injector + * + * ------------------------------------------------------ + * + * Copyright (C) 2018 Kubo Takehiro + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "injector_internal.h" + +#ifdef __LP64__ +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#else +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#endif + +// #define INJECTOR_DEBUG_ELF_C 1 + +#ifdef INJECTOR_DEBUG_ELF_C +#undef DEBUG +#define DEBUG(...) fprintf(stderr, __VA_ARGS__) +#else +#undef DEBUG +#define DEBUG(...) do {} while(0) +#endif + +typedef struct { + int dlfunc_type; /* -1, DLFUNC_POSIX or DLFUNC_INTERNAL */ + FILE *fp; + size_t libc_addr; + size_t str_offset; + size_t str_size; + size_t sym_offset; + size_t sym_num; + size_t sym_entsize; +} param_t; + +static int search_and_open_libc(FILE **fp_out, pid_t pid, size_t *addr, libc_type_t *libc_type); +static int open_libc(FILE **fp_out, const char *path, pid_t pid, dev_t dev, ino_t ino); +static FILE *fopen_with_ino(const char *path, dev_t dev, ino_t ino); +static int read_elf_ehdr(FILE *fp, Elf_Ehdr *ehdr); +static int read_elf_shdr(FILE *fp, Elf_Shdr *shdr, size_t shdr_size); +static int read_elf_sym(FILE *fp, Elf_Sym *sym, size_t sym_size); +static int find_symbol_addr(size_t *addr, param_t *prm, const char *posix_name, const char *internal_name); +static size_t find_strtab_offset(const param_t *prm, const char *name); + +int injector__collect_libc_information(injector_t *injector) +{ + pid_t pid = injector->pid; + FILE *fp; + Elf_Ehdr ehdr; + Elf_Shdr shdr; + param_t prm = {-1, }; + size_t shstrtab_offset; + int idx; + int rv; + + rv = search_and_open_libc(&fp, pid, &prm.libc_addr, &injector->libc_type); + if (rv != 0) { + return rv; + } + rv = read_elf_ehdr(fp, &ehdr); + if (rv != 0) { + goto cleanup; + } + fseek(fp, ehdr.e_shoff + ehdr.e_shstrndx * ehdr.e_shentsize, SEEK_SET); + rv = read_elf_shdr(fp, &shdr, ehdr.e_shentsize); + if (rv != 0) { + goto cleanup; + } + shstrtab_offset = shdr.sh_offset; + + fseek(fp, ehdr.e_shoff, SEEK_SET); + for (idx = 0; idx < ehdr.e_shnum; idx++) { + fpos_t pos; + char buf[8]; + + rv = read_elf_shdr(fp, &shdr, ehdr.e_shentsize); + if (rv != 0) { + goto cleanup; + } + switch (shdr.sh_type) { + case SHT_STRTAB: + fgetpos(fp, &pos); + fseek(fp, shstrtab_offset + shdr.sh_name, SEEK_SET); + fgets(buf, sizeof(buf), fp); + fsetpos(fp, &pos); + if (strcmp(buf, ".dynstr") == 0) { + prm.str_offset = shdr.sh_offset; + prm.str_size = shdr.sh_size; + } + break; + case SHT_DYNSYM: + fgetpos(fp, &pos); + fseek(fp, shstrtab_offset + shdr.sh_name, SEEK_SET); + fgets(buf, sizeof(buf), fp); + fsetpos(fp, &pos); + if (strcmp(buf, ".dynsym") == 0) { + prm.sym_offset = shdr.sh_offset; + prm.sym_entsize = shdr.sh_entsize; + prm.sym_num = shdr.sh_size / shdr.sh_entsize; + } + break; + } + if (prm.sym_offset != 0 && prm.str_offset != 0) { + break; + } + } + if (idx == ehdr.e_shnum) { + injector__set_errmsg("failed to find the .dynstr and .dynsym sections."); + rv = INJERR_INVALID_ELF_FORMAT; + goto cleanup; + } + + prm.fp = fp; + + rv = find_symbol_addr(&injector->dlopen_addr, &prm, "dlopen", "__libc_dlopen_mode"); + if (rv != 0) { + goto cleanup; + } + + rv = find_symbol_addr(&injector->dlclose_addr, &prm, "dlclose", "__libc_dlclose"); + if (rv != 0) { + goto cleanup; + } + + rv = find_symbol_addr(&injector->dlsym_addr, &prm, "dlsym", "__libc_dlsym"); + if (rv != 0) { + goto cleanup; + } + + if (prm.dlfunc_type != DLFUNC_INTERNAL) { + rv = find_symbol_addr(&injector->dlerror_addr, &prm, "dlerror", NULL); + if (rv != 0) { + goto cleanup; + } + } else { + injector->dlerror_addr = 0; + } + +#ifdef INJECTOR_HAS_INJECT_IN_CLONED_THREAD + rv = find_symbol_addr(&injector->clone_addr, &prm, "clone", "clone"); + if (rv != 0) { + goto cleanup; + } +#endif + + rv = find_symbol_addr(NULL, &prm, "gnu_get_libc_release", "gnu_get_libc_release"); + if (rv == 0) { + /* GNU libc */ + injector->libc_type = LIBC_TYPE_GNU; + } + + injector->dlfunc_type = prm.dlfunc_type; + injector->code_addr = prm.libc_addr + ehdr.e_entry; + + switch (ehdr.e_machine) { + case EM_X86_64: + if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { + /* LP64 */ + injector->arch = ARCH_X86_64; + injector->sys_mmap = 9; + injector->sys_mprotect = 10; + injector->sys_munmap = 11; + } else { + /* ILP32 */ + injector->arch = ARCH_X86_64_X32; + injector->sys_mmap = 0x40000000 + 9; + injector->sys_mprotect = 0x40000000 + 10; + injector->sys_munmap = 0x40000000 + 11; + } + break; + case EM_386: + injector->arch = ARCH_I386; + injector->sys_mmap = 192; + injector->sys_mprotect = 125; + injector->sys_munmap = 91; + break; + case EM_AARCH64: + injector->arch = ARCH_ARM64; + injector->sys_mmap = 222; + injector->sys_mprotect = 226; + injector->sys_munmap = 215; + break; + case EM_ARM: + if (EF_ARM_EABI_VERSION(ehdr.e_flags) == 0) { + injector__set_errmsg("ARM OABI target process isn't supported."); + rv = INJERR_UNSUPPORTED_TARGET; + goto cleanup; + } + if (injector->code_addr & 1u) { + injector->code_addr &= ~1u; + injector->arch = ARCH_ARM_EABI_THUMB; + } else { + injector->arch = ARCH_ARM_EABI; + } + injector->sys_mmap = 192; + injector->sys_mprotect = 125; + injector->sys_munmap = 91; + break; + case EM_MIPS: + if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { + /* MIPS 64 */ + injector->arch = ARCH_MIPS_64; + injector->sys_mmap = 5000 + 9; + injector->sys_mprotect = 5000 + 10; + injector->sys_munmap = 5000 + 11; + } else if (ehdr.e_flags & EF_MIPS_ABI2) { + /* MIPS N32 */ + injector->arch = ARCH_MIPS_N32; + injector->sys_mmap = 6000 + 9; + injector->sys_mprotect = 6000 + 10; + injector->sys_munmap = 6000 + 11; + } else { + /* MIPS O32 */ + injector->arch = ARCH_MIPS_O32; + injector->sys_mmap = 4000 + 90; + injector->sys_mprotect = 4000 + 125; + injector->sys_munmap = 4000 + 91; + } + break; + case EM_PPC64: + injector->arch = ARCH_POWERPC_64; + injector->sys_mmap = 90; + injector->sys_mprotect = 125; + injector->sys_munmap = 91; + break; + case EM_PPC: + injector->arch = ARCH_POWERPC; + injector->sys_mmap = 90; + injector->sys_mprotect = 125; + injector->sys_munmap = 91; + break; +#ifdef EM_RISCV + case EM_RISCV: + if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { + injector->arch = ARCH_RISCV_64; + } else { + injector->arch = ARCH_RISCV_32; + } + injector->sys_mmap = 222; + injector->sys_mprotect = 226; + injector->sys_munmap = 215; + break; +#endif + default: + injector__set_errmsg("Unknown target process architecture: 0x%04x", ehdr.e_machine); + rv = INJERR_UNSUPPORTED_TARGET; + goto cleanup; + } + rv = 0; +cleanup: + fclose(fp); + return rv; +} + +static int search_and_open_libc(FILE **fp_out, pid_t pid, size_t *addr, libc_type_t *libc_type) +{ + char buf[512]; + FILE *fp = NULL; + regex_t reg; + regmatch_t match; + + sprintf(buf, "/proc/%d/maps", pid); + fp = fopen(buf, "r"); + if (fp == NULL) { + injector__set_errmsg("failed to open %s. (error: %s)", buf, strerror(errno)); + return INJERR_OTHER; + } + DEBUG("Open %s\n", buf); + /* /libc.so.6 or /libc-2.{DIGITS}.so or /ld-musl-{arch}.so.1 */ + if (regcomp(®, "/libc(\\.so\\.6|-2\\.[0-9]+\\.so)|/ld-musl-.+?\\.so\\.1", REG_EXTENDED) != 0) { + injector__set_errmsg("regcomp failed!"); + return INJERR_OTHER; + } + while (fgets(buf, sizeof(buf), fp) != NULL) { + unsigned long saddr, eaddr; + unsigned long long offset, inode; + unsigned int dev_major, dev_minor; + DEBUG(" %s", buf); + if (sscanf(buf, "%lx-%lx %*s %llx %x:%x %llu", &saddr, &eaddr, &offset, &dev_major, &dev_minor, &inode) != 6) { + continue; + } + if (offset != 0) { + continue; + } + if (regexec(®, buf, 1, &match, 0) != 0) { + continue; + } + char *p = buf + match.rm_eo; + if (strcmp(p, " (deleted)\n") == 0) { + injector__set_errmsg("The C library when the process started was removed"); + fclose(fp); + regfree(®); + return INJERR_NO_LIBRARY; + } + if (strcmp(p, "\n") != 0) { + continue; + } + fclose(fp); + *addr = saddr; + if (strstr(buf, "/ld-musl-") != NULL) { + *libc_type = LIBC_TYPE_MUSL; + } else { + *libc_type = LIBC_TYPE_GNU; + } + regfree(®); + *p = '\0'; + p = strchr(buf, '/'); + DEBUG(" libc in /proc/PID/maps: '%s'\n", p); + return open_libc(fp_out, p, pid, makedev(dev_major, dev_minor), inode); + } + fclose(fp); + injector__set_errmsg("Could not find libc"); + regfree(®); + return INJERR_NO_LIBRARY; +} + +static int open_libc(FILE **fp_out, const char *path, pid_t pid, dev_t dev, ino_t ino) +{ + FILE *fp = fopen_with_ino(path, dev, ino); + + if (fp != NULL) { + goto found; + } + + /* workaround for LXD */ + const char *p = strstr(path, "/rootfs/"); + if (p != NULL) { + fp = fopen_with_ino(p + 7, dev, ino); + if (fp != NULL) { + goto found; + } + } + + // workaround for Flatpak (https://flatpak.org/) + // + // libc is under /proc//root. + // The idea came from https://github.com/kubo/injector/pull/36. + char buf[PATH_MAX]; + snprintf(buf, sizeof(buf), "/proc/%d/root%s", pid, path); + buf[sizeof(buf) - 1] = '\0'; + fp = fopen_with_ino(buf, dev, ino); + if (fp != NULL) { + goto found; + } + + // workaround for Snap + // + // libc is in a base snap (https://snapcraft.io/docs/base-snaps), + glob_t globbuf; + if (glob("/snap/core*/*", GLOB_NOSORT, NULL, &globbuf) == 0) { + size_t idx; + for (idx = 0; idx < globbuf.gl_pathc; idx++) { + char buf[512]; + snprintf(buf, sizeof(buf), "%s%s", globbuf.gl_pathv[idx], path); + buf[sizeof(buf) - 1] = '\0'; + fp = fopen_with_ino(buf, dev, ino); + if (fp != NULL) { + globfree(&globbuf); + goto found; + } + } + globfree(&globbuf); + } + injector__set_errmsg("failed to open %s. (dev:0x%" PRIx64 ", ino:%lu)", path, dev, ino); + return INJERR_NO_LIBRARY; +found: + *fp_out = fp; + return 0; +} + +static inline int is_on_overlay_fs(int fd) +{ + struct statfs sbuf; + if (fstatfs(fd, &sbuf) != 0) { + DEBUG(" fstatfs() error %s\n", strerror(errno)); + return -1; + } +#ifndef OVERLAYFS_SUPER_MAGIC +#define OVERLAYFS_SUPER_MAGIC 0x794c7630 +#endif + return (sbuf.f_type == OVERLAYFS_SUPER_MAGIC) ? 1 : 0; +} + +static FILE *fopen_with_ino(const char *path, dev_t dev, ino_t ino) +{ + DEBUG(" checking: '%s' ...", path); + struct stat sbuf; + FILE *fp = fopen(path, "r"); + + if (fp == NULL) { + DEBUG(" fopen() error %s\n", strerror(errno)); + return NULL; + } + + if (fstat(fileno(fp), &sbuf) != 0) { + DEBUG(" fstat() error %s\n", strerror(errno)); + goto cleanup; + } + if (sbuf.st_ino != ino) { + DEBUG(" unexpected inode number: expected %llu but %llu\n", + (unsigned long long)ino, (unsigned long long)sbuf.st_ino); + goto cleanup; + } + if (sbuf.st_dev != dev) { + int rv = is_on_overlay_fs(fileno(fp)); + if (rv < 0) { + goto cleanup; + } + if (rv != 1) { + DEBUG(" unexpected device number: expected %llu but %llu\n", + (unsigned long long)dev, (unsigned long long)sbuf.st_dev); + goto cleanup; + } + DEBUG(" ignore device number mismatch (expected %llu but %llu) on overlay file system ... ", + (unsigned long long)dev, (unsigned long long)sbuf.st_dev); + } + + DEBUG(" OK\n"); + return fp; +cleanup: + fclose(fp); + return NULL; +} + +static int read_elf_ehdr(FILE *fp, Elf_Ehdr *ehdr) +{ + if (fread(ehdr, sizeof(*ehdr), 1, fp) != 1) { + injector__set_errmsg("failed to read ELF header. (error: %s)", strerror(errno)); + return INJERR_INVALID_ELF_FORMAT; + } + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) { + injector__set_errmsg("Invalid ELF header: 0x%02x,0x%02x,0x%02x,0x%02x", + ehdr->e_ident[0], ehdr->e_ident[1], ehdr->e_ident[2], ehdr->e_ident[3]); + return INJERR_INVALID_ELF_FORMAT; + } + switch (ehdr->e_ident[EI_CLASS]) { + case ELFCLASS32: +#ifdef __LP64__ + { + Elf32_Ehdr *ehdr32 = (Elf32_Ehdr *)ehdr; + /* copy from last */ + ehdr->e_shstrndx = ehdr32->e_shstrndx; + ehdr->e_shnum = ehdr32->e_shnum; + ehdr->e_shentsize = ehdr32->e_shentsize; + ehdr->e_phnum = ehdr32->e_phnum; + ehdr->e_phentsize = ehdr32->e_phentsize; + ehdr->e_ehsize = ehdr32->e_ehsize; + ehdr->e_flags = ehdr32->e_flags; + ehdr->e_shoff = ehdr32->e_shoff; + ehdr->e_phoff = ehdr32->e_phoff; + ehdr->e_entry = ehdr32->e_entry; + ehdr->e_version = ehdr32->e_version; + ehdr->e_machine = ehdr32->e_machine; + ehdr->e_type = ehdr32->e_type; + } +#endif + break; + case ELFCLASS64: +#ifndef __LP64__ + injector__set_errmsg("64-bit target process isn't supported by 32-bit process."); + return INJERR_UNSUPPORTED_TARGET; +#endif + break; + default: + injector__set_errmsg("Invalid ELF class: 0x%x", ehdr->e_ident[EI_CLASS]); + return INJERR_UNSUPPORTED_TARGET; + } + return 0; +} + +static int read_elf_shdr(FILE *fp, Elf_Shdr *shdr, size_t shdr_size) +{ + if (fread(shdr, shdr_size, 1, fp) != 1) { + injector__set_errmsg("failed to read a section header. (error: %s)", strerror(errno)); + return INJERR_INVALID_ELF_FORMAT; + } +#ifdef __LP64__ + if (shdr_size == sizeof(Elf32_Shdr)) { + Elf32_Shdr shdr32 = *(Elf32_Shdr *)shdr; + shdr->sh_name = shdr32.sh_name; + shdr->sh_type = shdr32.sh_type; + shdr->sh_flags = shdr32.sh_flags; + shdr->sh_addr = shdr32.sh_addr; + shdr->sh_offset = shdr32.sh_offset; + shdr->sh_size = shdr32.sh_size; + shdr->sh_link = shdr32.sh_link; + shdr->sh_info = shdr32.sh_info; + shdr->sh_addralign = shdr32.sh_addralign; + shdr->sh_entsize = shdr32.sh_entsize; + } +#endif + return 0; +} + +static int read_elf_sym(FILE *fp, Elf_Sym *sym, size_t sym_size) +{ + if (fread(sym, sym_size, 1, fp) != 1) { + injector__set_errmsg("failed to read a symbol table entry. (error: %s)", strerror(errno)); + return INJERR_INVALID_ELF_FORMAT; + } +#ifdef __LP64__ + if (sym_size == sizeof(Elf32_Sym)) { + Elf32_Sym sym32 = *(Elf32_Sym *)sym; + sym->st_name = sym32.st_name; + sym->st_value = sym32.st_value; + sym->st_size = sym32.st_size; + sym->st_info = sym32.st_info; + sym->st_other = sym32.st_other; + sym->st_shndx = sym32.st_shndx; + } +#endif + return 0; +} + +static int find_symbol_addr(size_t *addr, param_t *prm, const char *posix_name, const char *internal_name) +{ + size_t st_name; + + switch (prm->dlfunc_type) { + case -1: + st_name = find_strtab_offset(prm, posix_name); + if (st_name != 0) { + prm->dlfunc_type = DLFUNC_POSIX; + } else { + prm->dlfunc_type = DLFUNC_INTERNAL; + st_name = find_strtab_offset(prm, internal_name); + } + break; + case DLFUNC_POSIX: + st_name = find_strtab_offset(prm, posix_name); + break; + case DLFUNC_INTERNAL: + st_name = find_strtab_offset(prm, internal_name); + break; + } + + if (addr == NULL) { + return st_name != 0 ? 0 : INJERR_NO_FUNCTION; + } + + if (st_name != 0) { + Elf_Sym sym; + int idx; + int rv; + + fseek(prm->fp, prm->sym_offset, SEEK_SET); + for (idx = 0; idx < prm->sym_num; idx++) { + rv = read_elf_sym(prm->fp, &sym, prm->sym_entsize); + if (rv != 0) { + return rv; + } + if (sym.st_name == st_name) { + *addr = prm->libc_addr + sym.st_value; + return 0; + } + } + } + injector__set_errmsg("failed to find %s%s%s in the .dynstr section.", + posix_name, internal_name ? "/" : "", + internal_name ? internal_name : ""); + return INJERR_NO_FUNCTION; +} + +static size_t find_strtab_offset(const param_t *prm, const char *name) +{ + size_t off; + size_t idx = 0; + + fseek(prm->fp, prm->str_offset, SEEK_SET); + for (off = 0; off < prm->str_size; off++) { + int c = fgetc(prm->fp); + if (c == EOF) { + return 0; + } + if (c == name[idx]) { + if (c == 0) { + return off - idx; + } + idx++; + } else { + idx = 0; + } + } + return 0; +} diff --git a/RemoteInput/Thirdparty/kubo_injector/src/linux/injector.c b/RemoteInput/Thirdparty/kubo_injector/src/linux/injector.c new file mode 100644 index 0000000..3b7d887 --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/src/linux/injector.c @@ -0,0 +1,389 @@ +/* -*- indent-tabs-mode: nil -*- + * + * injector - Library for injecting a shared library into a Linux process + * + * URL: https://github.com/kubo/injector + * + * ------------------------------------------------------ + * + * Copyright (C) 2018-2023 Kubo Takehiro + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "injector_internal.h" + +static inline size_t remote_mem_size(injector_t *injector) { + return 2 * injector->data_size + injector->stack_size; +} + +int injector_attach(injector_t **injector_out, pid_t pid) +{ + injector_t *injector; + int status; + intptr_t retval; + int prot; + int rv = 0; + + injector__errmsg_is_set = 0; + + injector = calloc(1, sizeof(injector_t)); + if (injector == NULL) { + injector__set_errmsg("malloc error: %s", strerror(errno)); + return INJERR_NO_MEMORY; + } + injector->pid = pid; + rv = injector__attach_process(injector); + if (rv != 0) { + goto error_exit; + } + injector->attached = 1; + + do { + rv = waitpid(pid, &status, 0); + } while (rv == -1 && errno == EINTR); + if (rv == -1) { + injector__set_errmsg("waitpid error while attaching: %s", strerror(errno)); + rv = INJERR_WAIT_TRACEE; + goto error_exit; + } + + rv = injector__collect_libc_information(injector); + if (rv != 0) { + goto error_exit; + } + rv = injector__get_regs(injector, &injector->regs); + if (rv != 0) { + goto error_exit; + } + rv = injector__read(injector, injector->code_addr, &injector->backup_code, sizeof(injector->backup_code)); + if (rv != 0) { + goto error_exit; + } + + injector->data_size = sysconf(_SC_PAGESIZE); + injector->stack_size = 2 * 1024 * 1024; + + rv = injector__call_syscall(injector, &retval, injector->sys_mmap, 0, + remote_mem_size(injector), PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0); + if (rv != 0) { + goto error_exit; + } + if (retval == -1) { + injector__set_errmsg("mmap error: %s", strerror(errno)); + rv = INJERR_ERROR_IN_TARGET; + goto error_exit; + } + injector->mmapped = 1; + injector->data = (size_t)retval; + injector->stack = (size_t)retval + 2 * injector->data_size; +#ifdef INJECTOR_HAS_INJECT_IN_CLONED_THREAD + injector->shellcode = (size_t)retval + 1 * injector->data_size; + prot = PROT_READ | PROT_EXEC; +#else + prot = PROT_NONE; +#endif + rv = injector__call_syscall(injector, &retval, injector->sys_mprotect, + injector->data + injector->data_size, injector->data_size, + prot); + if (rv != 0) { + goto error_exit; + } + if (retval != 0) { + injector__set_errmsg("mprotect error: %s", strerror(errno)); + rv = INJERR_ERROR_IN_TARGET; + goto error_exit; + } +#ifdef INJECTOR_HAS_INJECT_IN_CLONED_THREAD + rv = injector__write(injector, injector->shellcode, &injector_shellcode, injector_shellcode_size); + if (rv != 0) { + return rv; + } +#endif + + *injector_out = injector; + return 0; +error_exit: + injector_detach(injector); + return rv; +} + +int injector_inject(injector_t *injector, const char *path, void **handle) +{ + char abspath[PATH_MAX]; + int dlflags = RTLD_LAZY; + size_t len; + int rv; + intptr_t retval; + + injector__errmsg_is_set = 0; + + if (path[0] == '/') { + len = strlen(path) + 1; + } else if (realpath(path, abspath) != NULL) { + path = abspath; + len = strlen(abspath) + 1; + } else { + injector__set_errmsg("failed to get the full path of '%s': %s", + path, strerror(errno)); + return INJERR_FILE_NOT_FOUND; + } + + if (len > injector->data_size) { + injector__set_errmsg("too long file path: %s", path); + return INJERR_FILE_NOT_FOUND; + } + + rv = injector__write(injector, injector->data, path, len); + if (rv != 0) { + return rv; + } + if (injector->dlfunc_type == DLFUNC_INTERNAL) { +#define __RTLD_DLOPEN 0x80000000 // glibc internal flag + dlflags |= __RTLD_DLOPEN; + } + rv = injector__call_function(injector, &retval, injector->dlopen_addr, injector->data, dlflags); + if (rv != 0) { + return rv; + } + if (retval == 0) { + char buf[256 + 1] = {0,}; + if (injector->dlerror_addr != 0) { + rv = injector__call_function(injector, &retval, injector->dlerror_addr); + if (rv == 0 && retval != 0) { + injector__read(injector, retval, buf, sizeof(buf) - 1); + } + } + if (buf[0] != '\0') { + injector__set_errmsg("dlopen failed: %s", buf); + } else { + injector__set_errmsg("dlopen failed"); + } + return INJERR_ERROR_IN_TARGET; + } + if (handle != NULL) { + *handle = (void*)retval; + } + return 0; +} + +#ifdef INJECTOR_HAS_INJECT_IN_CLONED_THREAD +int injector_inject_in_cloned_thread(injector_t *injector, const char *path, void **handle_out) +{ + void *data; + injector_shellcode_arg_t *arg; + const size_t file_path_offset = offsetof(injector_shellcode_arg_t, file_path); + void * const invalid_handle = (void*)-3; + char abspath[PATH_MAX]; + size_t pathlen; + int rv; + intptr_t retval; + + injector__errmsg_is_set = 0; + + if (injector->arch != ARCH_X86_64) { + injector__set_errmsg("injector_inject_in_cloned_thread doesn't support %s.", + injector__arch2name(injector->arch)); + return INJERR_UNSUPPORTED_TARGET; + } + + if (realpath(path, abspath) == NULL) { + injector__set_errmsg("failed to get the full path of '%s': %s", + path, strerror(errno)); + return INJERR_FILE_NOT_FOUND; + } + pathlen = strlen(abspath) + 1; + + if (file_path_offset + pathlen > injector->data_size) { + injector__set_errmsg("too long path name: %s", path); + return INJERR_FILE_NOT_FOUND; + } + + data = alloca(injector->data_size); + memset(data, 0, injector->data_size); + arg = (injector_shellcode_arg_t *)data; + + arg->handle = invalid_handle; + arg->dlopen_addr = injector->dlopen_addr; + arg->dlerror_addr = injector->dlerror_addr; + arg->dlflags = RTLD_LAZY; + if (injector->dlfunc_type == DLFUNC_INTERNAL) { + arg->dlflags |= __RTLD_DLOPEN; + } + memcpy(arg->file_path, abspath, pathlen); + + rv = injector__write(injector, injector->data, data, injector->data_size); + if (rv != 0) { + return rv; + } + rv = injector__call_function(injector, &retval, injector->clone_addr, + injector->shellcode, injector->stack + injector->stack_size - 4096, + //CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, + CLONE_VM, + injector->data); + if (rv != 0) { + return rv; + } + if (retval == -1) { + injector__set_errmsg("clone error: %s", strerror(errno)); + return INJERR_ERROR_IN_TARGET; + } + const struct timespec ts = {0, 100000000}; /* 0.1 second */ + void *handle; + int cnt = 0; + +retry: + nanosleep(&ts, NULL); + rv = injector__read(injector, injector->data, &handle, sizeof(handle)); + if (rv != 0) { + return rv; + } + if (handle == invalid_handle) { + int max_retyr_cnt = 50; + if (++cnt <= max_retyr_cnt) { + goto retry; + } + injector__set_errmsg("dlopen doesn't return in %d seconds.", max_retyr_cnt / 10); + return INJERR_ERROR_IN_TARGET; + } + if (handle_out != NULL) { + *handle_out = handle; + } + if (handle == NULL) { + arg->file_path[0] = '\0'; + injector__read(injector, injector->data, data, injector->data_size); + if (arg->file_path[0] != '\0') { + injector__set_errmsg("%s", arg->file_path); + } else { + injector__set_errmsg("dlopen error"); + } + return INJERR_ERROR_IN_TARGET; + } + return 0; +} +#endif + +int injector_remote_func_addr(injector_t *injector, void *handle, const char* name, size_t *func_addr_out) +{ + int rv; + intptr_t retval; + size_t len = strlen(name) + 1; + + injector__errmsg_is_set = 0; + + if (len > injector->data_size) { + injector__set_errmsg("too long function name: %s", name); + return INJERR_FUNCTION_MISSING; + } + rv = injector__write(injector, injector->data, name, len); + if (rv != 0) { + return rv; + } + rv = injector__call_function(injector, &retval, injector->dlsym_addr, handle, injector->data); + if (rv != 0) { + return rv; + } + if (retval == 0) { + injector__set_errmsg("function not found: %s", name); + return INJERR_FUNCTION_MISSING; + } + *func_addr_out = (size_t)retval; + return 0; +} + +int injector_remote_call(injector_t *injector, intptr_t *retval, size_t func_addr, ...) +{ + va_list ap; + int rv; + injector__errmsg_is_set = 0; + va_start(ap, func_addr); + rv = injector__call_function_va_list(injector, retval, func_addr, ap); + va_end(ap); + return rv; +} + +int injector_remote_vcall(injector_t *injector, intptr_t *retval, size_t func_addr, va_list ap) +{ + injector__errmsg_is_set = 0; + return injector__call_function_va_list(injector, retval, func_addr, ap); +} + +int injector_call(injector_t *injector, void *handle, const char* name) +{ + size_t func_addr; + int rv = injector_remote_func_addr(injector, handle, name, &func_addr); + if (rv != 0) { + return rv; + } + return injector__call_function(injector, NULL, func_addr); +} + +int injector_uninject(injector_t *injector, void *handle) +{ + int rv; + intptr_t retval; + + injector__errmsg_is_set = 0; + if (injector->libc_type == LIBC_TYPE_MUSL) { + /* Assume that libc is musl. */ + injector__set_errmsg("Cannot uninject libraries under musl libc. See: https://wiki.musl-libc.org/functional-differences-from-glibc.html#Unloading_libraries"); + return INJERR_UNSUPPORTED_TARGET; + } + + rv = injector__call_function(injector, &retval, injector->dlclose_addr, handle); + if (rv != 0) { + return rv; + } + if (retval != 0) { + injector__set_errmsg("dlclose failed"); + return INJERR_ERROR_IN_TARGET; + } + return 0; +} + +int injector_detach(injector_t *injector) +{ + injector__errmsg_is_set = 0; + + if (injector->mmapped) { + injector__call_syscall(injector, NULL, injector->sys_munmap, injector->data, remote_mem_size(injector)); + } + if (injector->attached) { + injector__detach_process(injector); + } + free(injector); + return 0; +} + +const char *injector_error(void) +{ + return injector__errmsg; +} diff --git a/RemoteInput/Thirdparty/kubo_injector/src/linux/injector_internal.h b/RemoteInput/Thirdparty/kubo_injector/src/linux/injector_internal.h new file mode 100644 index 0000000..993cc51 --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/src/linux/injector_internal.h @@ -0,0 +1,193 @@ +/* -*- indent-tabs-mode: nil -*- + * + * injector - Library for injecting a shared library into a Linux process + * + * URL: https://github.com/kubo/injector + * + * ------------------------------------------------------ + * + * Copyright (C) 2018-2023 Kubo Takehiro + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef INJECTOR_INTERNAL_H +#define INJECTOR_INTERNAL_H 1 +#include +#include +#include +#include +#include +#include +#include +#include "injector.h" + +#ifdef __LP64__ +#define SIZE_T_FMT "l" +#else +#define SIZE_T_FMT "" +#endif + +#ifdef __arm__ +#define user_regs_struct user_regs +#endif + +#ifdef __mips__ +#include +#define user_regs_struct pt_regs +#endif + +#ifdef __powerpc__ +#include +#define user_regs_struct pt_regs +#endif + +#ifdef __riscv +#include +#endif + +#define PTRACE_OR_RETURN(request, injector, addr, data) do { \ + int rv = injector__ptrace(request, injector->pid, addr, data, #request); \ + if (rv != 0) { \ + return rv; \ + } \ +} while (0) + +typedef enum { + /* use dlopen/dlsym/dlclose (glibc 2.34 or later) */ + DLFUNC_POSIX, + /* use __libc_dlopen_mode/__libc_dlsym/__libc_dlclose" (glibc 2.33 or earlier) */ + DLFUNC_INTERNAL, +} dlfunc_type_t; + +typedef enum { + LIBC_TYPE_UNKNOWN = 0, + LIBC_TYPE_GNU, + LIBC_TYPE_MUSL, +} libc_type_t; + +typedef enum { + ARCH_X86_64, + ARCH_X86_64_X32, + ARCH_I386, + ARCH_ARM64, + ARCH_ARM_EABI_THUMB, + ARCH_ARM_EABI, + ARCH_MIPS_64, + ARCH_MIPS_N32, + ARCH_MIPS_O32, + ARCH_POWERPC_64, + ARCH_POWERPC, + ARCH_RISCV_64, + ARCH_RISCV_32, +} arch_t; + +typedef union { +#if defined(__x86_64__) || defined(__i386__) + uint8_t u8[sizeof(long)]; +#elif defined(__aarch64__) || defined(__arm__) + uint16_t u16[4]; + uint32_t u32[2]; +#elif defined(__mips__) + uint32_t u32[4]; +#elif defined(__powerpc__) + uint32_t u32[2]; +#elif defined(__riscv) + uint32_t u32[2]; +#endif + long dummy; +} code_t; + +struct injector { + pid_t pid; + uint8_t attached; + uint8_t mmapped; + arch_t arch; + libc_type_t libc_type; + struct user_regs_struct regs; + dlfunc_type_t dlfunc_type; + size_t dlopen_addr; + size_t dlclose_addr; + size_t dlsym_addr; + size_t dlerror_addr; +#ifdef INJECTOR_HAS_INJECT_IN_CLONED_THREAD + size_t clone_addr; +#endif + size_t code_addr; /* address where instructions are written */ + code_t backup_code; + long sys_mmap; + long sys_mprotect; + long sys_munmap; + + /* memory layout allocated in the target process + * + * high +----------------------+ + * | stack area | + * | size: 2MB | + * |----------------------| + * | inaccessible area | + * | size: 4096 | + * |----------------------| + * | data area | + * | size: 4096 | + * low +----------------------+ + */ + size_t data; /* read-write region */ + size_t data_size; /* page size */ + size_t stack; /* stack area */ + size_t stack_size; /* 2MB */ +#ifdef INJECTOR_HAS_INJECT_IN_CLONED_THREAD + size_t shellcode; +#endif +}; + +/* elf.c */ +int injector__collect_libc_information(injector_t *injector); + +/* ptrace.c */ +int injector__ptrace(int request, pid_t pid, long addr, long data, const char *request_name); +int injector__attach_process(const injector_t *injector); +int injector__detach_process(const injector_t *injector); +int injector__get_regs(const injector_t *injector, struct user_regs_struct *regs); +int injector__set_regs(const injector_t *injector, const struct user_regs_struct *regs); +int injector__read(const injector_t *injector, size_t addr, void *buf, size_t len); +int injector__write(const injector_t *injector, size_t addr, const void *buf, size_t len); +int injector__continue(const injector_t *injector); + +/* remote_call.c - call functions and syscalls in the target process */ +int injector__call_syscall(const injector_t *injector, intptr_t *retval, long syscall_number, ...); +int injector__call_function(const injector_t *injector, intptr_t *retval, long function_addr, ...); +int injector__call_function_va_list(const injector_t *injector, intptr_t *retval, long function_addr, va_list ap); + +/* util.c */ +extern char injector__errmsg[]; +extern char injector__errmsg_is_set; +void injector__set_errmsg(const char *format, ...) __attribute__((format (printf, 1, 2))); +const char *injector__arch2name(arch_t arch); + +/* shellcode.S */ +#ifdef INJECTOR_HAS_INJECT_IN_CLONED_THREAD +typedef struct { + void *handle; + size_t dlopen_addr; + size_t dlerror_addr; + int dlflags; + char file_path[0]; // dummy size. +} injector_shellcode_arg_t; + +void *injector_shellcode(injector_shellcode_arg_t *arg); +extern int injector_shellcode_size; +#endif + +#endif diff --git a/RemoteInput/Thirdparty/kubo_injector/src/linux/ptrace.c b/RemoteInput/Thirdparty/kubo_injector/src/linux/ptrace.c new file mode 100644 index 0000000..43b5083 --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/src/linux/ptrace.c @@ -0,0 +1,149 @@ +/* -*- indent-tabs-mode: nil -*- + * + * injector - Library for injecting a shared library into a Linux process + * + * URL: https://github.com/kubo/injector + * + * ------------------------------------------------------ + * + * Copyright (C) 2018 Kubo Takehiro + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "injector_internal.h" + +#if defined(__aarch64__) || defined(__riscv) +#define USE_REGSET +#include /* for NT_PRSTATUS */ +#include /* for struct iovec */ +#endif + +static int set_ptrace_error(const char *request_name) +{ + int err = errno; + injector__set_errmsg("%s error : %s", request_name, strerror(errno)); + switch (err) { + case EFAULT: + return INJERR_INVALID_MEMORY_AREA; + case EPERM: + return INJERR_PERMISSION; + case ESRCH: + return INJERR_NO_PROCESS; + } + return INJERR_OTHER; +} + +int injector__ptrace(int request, pid_t pid, long addr, long data, const char *request_name) +{ + if (ptrace(request, pid, addr, data) != 0) { + return set_ptrace_error(request_name); + } + return 0; +} + +int injector__attach_process(const injector_t *injector) +{ + PTRACE_OR_RETURN(PTRACE_ATTACH, injector, 0, 0); + return 0; +} + +int injector__detach_process(const injector_t *injector) +{ + PTRACE_OR_RETURN(PTRACE_DETACH, injector, 0, 0); + return 0; +} + +int injector__get_regs(const injector_t *injector, struct user_regs_struct *regs) +{ +#ifdef USE_REGSET + struct iovec iovec = { regs, sizeof(*regs) }; + PTRACE_OR_RETURN(PTRACE_GETREGSET, injector, NT_PRSTATUS, (long)&iovec); +#else + PTRACE_OR_RETURN(PTRACE_GETREGS, injector, 0, (long)regs); +#endif + return 0; +} + +int injector__set_regs(const injector_t *injector, const struct user_regs_struct *regs) +{ +#ifdef USE_REGSET + struct iovec iovec = { (void*)regs, sizeof(*regs) }; + PTRACE_OR_RETURN(PTRACE_SETREGSET, injector, NT_PRSTATUS, (long)&iovec); +#else + PTRACE_OR_RETURN(PTRACE_SETREGS, injector, 0, (long)regs); +#endif + return 0; +} + +int injector__read(const injector_t *injector, size_t addr, void *buf, size_t len) +{ + pid_t pid = injector->pid; + long word; + char *dest = (char *)buf; + + errno = 0; + while (len >= sizeof(long)) { + word = ptrace(PTRACE_PEEKTEXT, pid, addr, 0); + if (word == -1 && errno != 0) { + return set_ptrace_error("PTRACE_PEEKTEXT"); + } + *(long*)dest = word; + addr += sizeof(long); + dest += sizeof(long); + len -= sizeof(long); + } + if (len != 0) { + char *src = (char *)&word; + word = ptrace(PTRACE_PEEKTEXT, pid, addr, 0); + if (word == -1 && errno != 0) { + return set_ptrace_error("PTRACE_PEEKTEXT"); + } + while (len--) { + *(dest++) = *(src++); + } + } + return 0; +} + +int injector__write(const injector_t *injector, size_t addr, const void *buf, size_t len) +{ + pid_t pid = injector->pid; + const char *src = (const char *)buf; + + while (len >= sizeof(long)) { + PTRACE_OR_RETURN(PTRACE_POKETEXT, injector, addr, *(long*)src); + addr += sizeof(long); + src += sizeof(long); + len -= sizeof(long); + } + if (len != 0) { + long word = ptrace(PTRACE_PEEKTEXT, pid, addr, 0); + char *dest = (char*)&word; + if (word == -1 && errno != 0) { + return set_ptrace_error("PTRACE_PEEKTEXT"); + } + while (len--) { + *(dest++) = *(src++); + } + PTRACE_OR_RETURN(PTRACE_POKETEXT, injector, addr, word); + } + return 0; +} + +int injector__continue(const injector_t *injector) +{ + PTRACE_OR_RETURN(PTRACE_CONT, injector, 0, 0); + return 0; +} diff --git a/RemoteInput/Thirdparty/kubo_injector/src/linux/remote_call.c b/RemoteInput/Thirdparty/kubo_injector/src/linux/remote_call.c new file mode 100644 index 0000000..3afeb83 --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/src/linux/remote_call.c @@ -0,0 +1,821 @@ +/* -*- indent-tabs-mode: nil -*- + * + * injector - Library for injecting a shared library into a Linux process + * + * URL: https://github.com/kubo/injector + * + * ------------------------------------------------------ + * + * Copyright (C) 2018-2023 Kubo Takehiro + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#if defined __linux__ +/* Detect musl libc. See https://stackoverflow.com/a/70211227/985524 */ +#define _GNU_SOURCE +#include +#ifndef __USE_GNU +#define MUSL_LIBC +#endif // __USE_GNU +#endif // __linux__ + +#include +#include +#include +#include +#include "injector_internal.h" + +// #define INJECTOR_DEBUG_REMOTE_CALL 1 + +#ifdef INJECTOR_DEBUG_REMOTE_CALL +#undef DEBUG +#define DEBUG(...) fprintf(stderr, __VA_ARGS__) +#else +#undef DEBUG +#define DEBUG(...) do {} while(0) +#endif + +#ifdef __x86_64__ +#define eip rip +#define ebp rbp +#define esp rsp +#define eax rax +#define ebx rbx +#define ecx rcx +#define edx rdx +#define esi rsi +#define edi rdi +#define ebp rbp +#endif + +#if defined(__arm__) +#define reg32_return reg_return +#define uregs regs.uregs +#endif + +#define THUMB_MODE_BIT (1u << 5) +#define BREAKINST_THUMB 0xde01 /* in linux-source-tree/arch/arm/kernel/ptrace.c */ +#define BREAKINST_ARM 0xe7f001f0 /* in linux-source-tree/arch/arm/kernel/ptrace.c */ +#define BREAKINST_ARM64 0xd4200000 /* asm("brk #0") */ + +#ifdef __mips__ +#define REG_V0 2 +#define REG_A0 4 +#define REG_A1 5 +#define REG_A2 6 +#define REG_A3 7 +#define REG_A4 8 +#define REG_A5 9 +#define REG_T4 12 +#define REG_T9 25 +#define REG_SP 29 +#define REG_FP 30 +#define REG_RA 31 + +static void print_regs(const injector_t *injector, const struct pt_regs *regs) +{ + DEBUG(" Registers:\n"); + DEBUG(" -- at v0 v1: %016"PRIx64" %016"PRIx64" %016"PRIx64" %016"PRIx64"\n", + regs->regs[0], regs->regs[1], regs->regs[2], regs->regs[3]); + DEBUG(" a0 a1 a2 a3: %016"PRIx64" %016"PRIx64" %016"PRIx64" %016"PRIx64"\n", + regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); + DEBUG(" %s: %016"PRIx64" %016"PRIx64" %016"PRIx64" %016"PRIx64"\n", + (injector->arch != ARCH_MIPS_O32) ? "a4 a5 a6 a7" : "t0 t1 t2 t3", + regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]); + DEBUG(" t4 t5 t6 t7: %016"PRIx64" %016"PRIx64" %016"PRIx64" %016"PRIx64"\n", + regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]); + DEBUG(" s0 s1 s2 s3: %016"PRIx64" %016"PRIx64" %016"PRIx64" %016"PRIx64"\n", + regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]); + DEBUG(" s4 s5 s6 s7: %016"PRIx64" %016"PRIx64" %016"PRIx64" %016"PRIx64"\n", + regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]); + DEBUG(" t8 t9 k0 k1: %016"PRIx64" %016"PRIx64" %016"PRIx64" %016"PRIx64"\n", + regs->regs[24], regs->regs[25], regs->regs[26], regs->regs[27]); + DEBUG(" gp sp s8 ra: %016"PRIx64" %016"PRIx64" %016"PRIx64" %016"PRIx64"\n", + regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]); + DEBUG(" lo hi epc: %016"PRIx64" %016"PRIx64" %016"PRIx64"\n", + regs->lo, regs->hi, regs->cp0_epc); + DEBUG(" badvaddr status cause: %016"PRIx64" %016"PRIx64" %016"PRIx64"\n", + regs->cp0_badvaddr, regs->cp0_status, regs->cp0_cause); +} +#define PRINT_REGS(injector, regs) print_regs((injector), (regs)) +#endif /* __mips__ */ + + +#ifdef __powerpc__ +static void print_regs(const injector_t *injector, const struct pt_regs *regs) +{ +#undef WIDTH +#ifdef __LP64__ +#define WIDTH "016" +#define softe_or_mq_str "softe" +#define softe_or_mq softe +#else +#define WIDTH "08" +#define softe_or_mq_str "mq " +#define softe_or_mq mq +#endif + DEBUG(" Registers:\n"); + DEBUG(" gpr0 gpr1 gpr2 gpr3 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->gpr[0], regs->gpr[1], regs->gpr[2], regs->gpr[3]); + DEBUG(" gpr4 gpr5 gpr6 gpr7 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->gpr[4], regs->gpr[5], regs->gpr[6], regs->gpr[7]); + DEBUG(" gpr8 gpr9 gpr10 gpr11 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->gpr[8], regs->gpr[9], regs->gpr[10], regs->gpr[11]); + DEBUG(" gpr12 gpr13 gpr14 gpr15 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->gpr[12], regs->gpr[13], regs->gpr[14], regs->gpr[15]); + DEBUG(" gpr16 gpr17 gpr18 gpr19 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->gpr[16], regs->gpr[17], regs->gpr[18], regs->gpr[19]); + DEBUG(" gpr20 gpr21 gpr22 gpr23 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->gpr[20], regs->gpr[21], regs->gpr[22], regs->gpr[23]); + DEBUG(" gpr24 gpr25 gpr26 gpr27 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]); + DEBUG(" gpr28 gpr29 gpr30 gpr31 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]); + DEBUG(" nip msr orig_gpr3 ctr : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->nip, regs->msr, regs->orig_gpr3, regs->ctr); + DEBUG(" link xer ccr "softe_or_mq_str" : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->link, regs->xer, regs->ccr, regs->softe_or_mq); + DEBUG(" trap dar dsisr result : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->trap, regs->dar, regs->dsisr, regs->result); +#undef WIDTH +} +#define PRINT_REGS(injector, regs) print_regs((injector), (regs)) +#endif + +#ifdef __riscv +#define REG_RA 1 +#define REG_T1 6 +#ifdef __LP64__ +#define WIDTH "016" +#else +#define WIDTH "08" +#endif +static void print_regs(const injector_t *injector, const struct user_regs_struct *regs) +{ + DEBUG(" Registers:\n"); + DEBUG(" pc ra sp gp : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->pc, regs->ra, regs->sp, regs->gp); + DEBUG(" tp t0 t1 t2 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->tp, regs->t0, regs->t1, regs->t2); + DEBUG(" s0 s1 a0 a1 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->s0, regs->s1, regs->a0, regs->a1); + DEBUG(" a2 a3 a4 a5 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->a2, regs->a3, regs->a4, regs->a5); + DEBUG(" a6 a7 s2 s3 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->a6, regs->a7, regs->s2, regs->s3); + DEBUG(" s4 s5 s6 s7 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->s4, regs->s5, regs->s6, regs->s7); + DEBUG(" s8 s9 s10 s11 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->s8, regs->s9, regs->s10, regs->s11); + DEBUG(" t3 t4 t5 t6 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->t3, regs->t4, regs->t5, regs->t6); +} +#define PRINT_REGS(injector, regs) print_regs((injector), (regs)) +#endif + +/* register type used in struct user_regs_struct */ +#if defined(__mips__) +typedef uint64_t user_reg_t; +#elif defined(__riscv) +typedef unsigned long user_reg_t; +#elif defined(__LP64__) && !defined(MUSL_LIBC) +typedef unsigned long long user_reg_t; +#elif defined(__i386__) +typedef long user_reg_t; +#else +typedef unsigned long user_reg_t; +#endif + +static int kick_then_wait_sigtrap(const injector_t *injector, struct user_regs_struct *regs, code_t *code, size_t code_size); + +#ifndef PRINT_REGS +#define PRINT_REGS(injector, regs) do {} while (0) +#endif + +/* + * Call the specified system call in the target process. + * + * The arguments after syscall_number must be integer types and + * the size must not be greater than the size of long. + */ +int injector__call_syscall(const injector_t *injector, intptr_t *retval, long syscall_number, ...) +{ + struct user_regs_struct regs = injector->regs; + code_t code; + size_t code_size; + long arg1, arg2, arg3, arg4, arg5, arg6; + va_list ap; + int rv; +#if !defined(__mips__) && !defined(__powerpc__) + user_reg_t *reg_return = NULL; +#if defined(__aarch64__) + uint32_t *reg32_return = NULL; + uint32_t *uregs = (uint32_t *)®s; +#endif +#endif + + va_start(ap, syscall_number); + arg1 = va_arg(ap, long); + arg2 = va_arg(ap, long); + arg3 = va_arg(ap, long); + arg4 = va_arg(ap, long); + arg5 = va_arg(ap, long); + arg6 = va_arg(ap, long); + va_end(ap); + + DEBUG("injector__call_syscall:\n"); + DEBUG(" args: %ld, %lx, %lx, %lx, %lx, %lx, %lx\n", syscall_number, arg1, arg2, arg3, arg4, arg5, arg6); + +#if !(defined(__x86_64__) && defined(__LP64__)) + if (injector->arch == ARCH_X86_64_X32) { + injector__set_errmsg("x32-ABI target process is supported only by x86_64."); + return INJERR_UNSUPPORTED_TARGET; + } +#endif + + switch (injector->arch) { +#if defined(__x86_64__) && defined(__LP64__) + case ARCH_X86_64: + case ARCH_X86_64_X32: + /* setup instructions */ + code.u8[0] = 0x0f; + code.u8[1] = 0x05; /* 0f 05 : syscall */ + code.u8[2] = 0xcc; /* cc : int3 */ + memset(&code.u8[3], 0x90, sizeof(long) - 3); /* fill the rests with `nop` */ + code_size = sizeof(long); + /* setup registers */ + regs.rip = injector->code_addr; + regs.rax = syscall_number; + regs.rdi = arg1; + regs.rsi = arg2; + regs.rdx = arg3; + regs.r10 = arg4; + regs.r8 = arg5; + regs.r9 = arg6; + reg_return = ®s.rax; + break; +#endif +#if defined(__x86_64__) || defined(__i386__) + case ARCH_I386: + /* setup instructions */ + code.u8[0] = 0xcd; + code.u8[1] = 0x80; /* cd 80 : int $80 */ + code.u8[2] = 0xcc; /* cc : int3 */ + memset(&code.u8[3], 0x90, sizeof(long) - 3); /* fill the rests with `nop` */ + code_size = sizeof(long); + /* setup registers */ + regs.eip = injector->code_addr; + regs.eax = syscall_number; + regs.ebx = arg1; + regs.ecx = arg2; + regs.edx = arg3; + regs.esi = arg4; + regs.edi = arg5; + regs.ebp = arg6; + reg_return = ®s.eax; + break; +#endif +#if defined(__aarch64__) + case ARCH_ARM64: + /* setup instructions */ + code.u32[0] = 0xd4000001; /* svc #0 */ + code.u32[1] = BREAKINST_ARM64; + code_size = 2 * 4; + /* setup registers */ + regs.pc = injector->code_addr; + regs.regs[8] = syscall_number; + regs.regs[0] = arg1; + regs.regs[1] = arg2; + regs.regs[2] = arg3; + regs.regs[3] = arg4; + regs.regs[4] = arg5; + regs.regs[5] = arg6; + reg_return = ®s.regs[0]; + break; +#endif +#if defined(__aarch64__) || defined(__arm__) + case ARCH_ARM_EABI_THUMB: + /* setup instructions */ + code.u16[0] = 0xdf00; /* svc #0 */ + code.u16[1] = BREAKINST_THUMB; +#ifdef __LP64__ + code.u16[2] = 0x46c0; /* nop (mov r8, r8) */ + code.u16[3] = 0x46c0; /* nop (mov r8, r8) */ +#endif + code_size = sizeof(long); + /* setup registers */ + uregs[16] |= THUMB_MODE_BIT; + uregs[15] = injector->code_addr; + uregs[7] = syscall_number; + uregs[0] = arg1; + uregs[1] = arg2; + uregs[2] = arg3; + uregs[3] = arg4; + uregs[4] = arg5; + uregs[5] = arg6; + reg32_return = &uregs[0]; + break; + case ARCH_ARM_EABI: + /* setup instructions */ + code.u32[0] = 0xef000000; /* svc #0 */ + code.u32[1] = BREAKINST_ARM; + code_size = 2 * 4; + /* setup registers */ + uregs[16] &= ~THUMB_MODE_BIT; + uregs[15] = injector->code_addr; + uregs[7] = syscall_number; + uregs[0] = arg1; + uregs[1] = arg2; + uregs[2] = arg3; + uregs[3] = arg4; + uregs[4] = arg5; + uregs[5] = arg6; + reg32_return = &uregs[0]; + break; +#endif +#if defined(__mips__) + case ARCH_MIPS_64: + case ARCH_MIPS_N32: + case ARCH_MIPS_O32: + /* setup instructions */ + if (syscall_number > 0xffff) { + injector__set_errmsg("too large system call number: %d", syscall_number); + return INJERR_OTHER; + } + code.u32[0] = 0x00000025 | (REG_A3 << 11) | (REG_T4 << 21); /* or $a3, $t4, $zero; move $a3, $t4 */ + code.u32[1] = 0x24000000 | (REG_V0 << 16) | syscall_number; /* addiu $v0, $zero, syscall_number */ + code.u32[2] = 0x0000000c; /* syscall */ + code.u32[3] = 0x0000000d; /* break */ + code_size = 4 * 4; + DEBUG(" Code: %08"PRIx32" %08"PRIx32" %08"PRIx32" %08"PRIx32"\n", + code.u32[0], code.u32[1], code.u32[2], code.u32[3]); + /* setup registers */ + regs.cp0_epc = injector->code_addr; + regs.regs[REG_A0] = arg1; + regs.regs[REG_A1] = arg2; + regs.regs[REG_A2] = arg3; + // Use the combination of "regs.regs[REG_T4] = arg4" and "move $a3, $t4" + // instead of "regs.regs[REG_A3] = arg4". I don't know why the latter + // doesn't work. + regs.regs[REG_T4] = arg4; + if (injector->arch != ARCH_MIPS_O32) { + /* ARCH_MIPS_64 or ARCH_MIPS_N32 */ + regs.regs[REG_A4] = arg5; + regs.regs[REG_A5] = arg6; + } else { + /* ARCH_MIPS_O32 */ + regs.regs[REG_SP] -= 32; + PTRACE_OR_RETURN(PTRACE_POKETEXT, injector, regs.regs[REG_SP] + 16, arg5); + PTRACE_OR_RETURN(PTRACE_POKETEXT, injector, regs.regs[REG_SP] + 20, arg6); + } + break; +#endif +#if defined(__powerpc__) +#ifdef __LP64__ + case ARCH_POWERPC_64: +#endif + case ARCH_POWERPC: + /* setup instructions */ + code.u32[0] = 0x44000002; /* sc */ + code.u32[1] = 0x7fe00008; /* trap */ + code_size = 2 * 4; + /* setup registers */ + regs.nip = injector->code_addr; + regs.gpr[PT_R0] = syscall_number; + regs.gpr[PT_R3] = arg1; + regs.gpr[PT_R4] = arg2; + regs.gpr[PT_R5] = arg3; + regs.gpr[PT_R6] = arg4; + regs.gpr[PT_R7] = arg5; + regs.gpr[PT_R8] = arg6; + break; +#endif +#if defined(__riscv) +#ifdef __LP64__ + case ARCH_RISCV_64: +#endif + case ARCH_RISCV_32: + /* setup instructions */ + code.u32[0] = 0x00000073; /* ecall */ + code.u32[1] = 0x00100073; /* ebreak */ + code_size = 2 * 4; + DEBUG(" Code: %08"PRIx32" %08"PRIx32"\n", + code.u32[0], code.u32[1]); + /* setup registers */ + regs.pc = injector->code_addr; + regs.a0 = arg1; + regs.a1 = arg2; + regs.a2 = arg3; + regs.a3 = arg4; + regs.a4 = arg5; + regs.a5 = arg6; + regs.a7 = syscall_number; + reg_return = ®s.a0; + break; +#endif + default: + injector__set_errmsg("Unexpected architecture: %s", injector__arch2name(injector->arch)); + return INJERR_UNSUPPORTED_TARGET; + } + + PRINT_REGS(injector, ®s); + rv = kick_then_wait_sigtrap(injector, ®s, &code, code_size); + if (rv != 0) { + return rv; + } + PRINT_REGS(injector, ®s); + + if (retval != NULL) { +#if defined(__mips__) + if (regs.regs[REG_A3] == 0) { + *retval = (intptr_t)regs.regs[REG_V0]; + } else { + errno = (int)regs.regs[REG_V0]; + *retval = -1; + } +#elif defined(__powerpc__) + /* https://github.com/strace/strace/blob/v5.19/src/linux/powerpc/get_error.c#L21-L26 */ + if (regs.ccr & 0x10000000) { + errno = (int)regs.gpr[PT_R3]; + *retval = -1; + } else { + *retval = (intptr_t)regs.gpr[PT_R3]; + } +#else +#if defined(__aarch64__) + if (reg32_return != NULL) { + if (*reg32_return <= -4096u) { + *retval = (intptr_t)*reg32_return; + } else { + errno = -((int)*reg32_return); + *retval = -1; + } + } else { +#endif + if ((unsigned long)*reg_return <= -4096ul) { + *retval = (intptr_t)*reg_return; + } else { + errno = -((int)*reg_return); + *retval = -1; + } +#if defined(__aarch64__) + } +#endif +#endif /* defined(__mips__) */ + } + return 0; +} + +/* + * Call the function at the specified address in the target process. + * + * The arguments after function_addr must be integer types and + * the size must not be greater than the size of long. + */ +int injector__call_function(const injector_t *injector, intptr_t *retval, long function_addr, ...) +{ + va_list ap; + int rv; + va_start(ap, function_addr); + rv = injector__call_function_va_list(injector, retval, function_addr, ap); + va_end(ap); + return rv; +} + +/* + * Call the function at the specified address in the target process. + * + * The arguments after function_addr must be integer types and + * the size must not be greater than the size of long. + */ +int injector__call_function_va_list(const injector_t *injector, intptr_t *retval, long function_addr, va_list ap) +{ + struct user_regs_struct regs = injector->regs; + code_t code; + size_t code_size; + long arg1, arg2, arg3, arg4, arg5, arg6; + int rv; + user_reg_t *reg_return = NULL; +#if defined(__aarch64__) + uint32_t *reg32_return = NULL; + uint32_t *uregs = (uint32_t *)®s; +#endif + + arg1 = va_arg(ap, long); + arg2 = va_arg(ap, long); + arg3 = va_arg(ap, long); + arg4 = va_arg(ap, long); + arg5 = va_arg(ap, long); + arg6 = va_arg(ap, long); + + DEBUG("injector__call_function:\n"); + DEBUG(" args: %lx, %lx, %lx, %lx, %lx, %lx, %lx\n", function_addr, arg1, arg2, arg3, arg4, arg5, arg6); + + switch (injector->arch) { +#if defined(__x86_64__) && defined(__LP64__) + case ARCH_X86_64: + case ARCH_X86_64_X32: + /* setup instructions */ + code.u8[0] = 0xff; + code.u8[1] = 0xd0; /* ff d0 : callq *%rax */ + code.u8[2] = 0xcc; /* cc : int3 */ + memset(&code.u8[3], 0x90, sizeof(long) - 3); /* fill the rests with `nop` */ + code_size = sizeof(long); + /* setup registers */ + regs.rip = injector->code_addr; + regs.rbp = injector->stack + injector->stack_size - 16; + /* rsp must be aligned to a 16-byte boundary. */ + regs.rsp = injector->stack + injector->stack_size - (2 * 16); + regs.rax = function_addr; + regs.rdi = arg1; + regs.rsi = arg2; + regs.rdx = arg3; + regs.rcx = arg4; + regs.r8 = arg5; + regs.r9 = arg6; + reg_return = ®s.rax; + break; +#endif +#if defined(__x86_64__) || defined(__i386__) + case ARCH_I386: + /* setup instructions */ + code.u8[0] = 0xff; + code.u8[1] = 0xd0; /* ff d0 : call *%eax */ + code.u8[2] = 0xcc; /* cc : int3 */ + memset(&code.u8[3], 0x90, sizeof(long) - 3); /* fill the rests with `nop` */ + code_size = sizeof(long); + /* setup registers */ + regs.eip = injector->code_addr; + regs.ebp = injector->stack + injector->stack_size - 16; + /* esp should be at 16-byte boundary after call instruction.*/ + regs.esp = injector->stack + injector->stack_size - (3 * 16) + 4; + regs.eax = function_addr; + PTRACE_OR_RETURN(PTRACE_POKETEXT, injector, regs.esp + 0, arg1); + PTRACE_OR_RETURN(PTRACE_POKETEXT, injector, regs.esp + 4, arg2); + PTRACE_OR_RETURN(PTRACE_POKETEXT, injector, regs.esp + 8, arg3); + PTRACE_OR_RETURN(PTRACE_POKETEXT, injector, regs.esp + 12, arg4); + PTRACE_OR_RETURN(PTRACE_POKETEXT, injector, regs.esp + 16, arg5); + PTRACE_OR_RETURN(PTRACE_POKETEXT, injector, regs.esp + 20, arg6); + reg_return = ®s.eax; + break; +#endif +#if defined(__aarch64__) + case ARCH_ARM64: + /* setup instructions */ + code.u32[0] = 0xd63f00c0; /* blr x6 */ + code.u32[1] = BREAKINST_ARM64; + code_size = 2 * 4; + /* setup registers */ + regs.pc = injector->code_addr; + regs.sp = injector->stack + injector->stack_size - 16; + regs.regs[6] = function_addr; + regs.regs[0] = arg1; + regs.regs[1] = arg2; + regs.regs[2] = arg3; + regs.regs[3] = arg4; + regs.regs[4] = arg5; + regs.regs[5] = arg6; + reg_return = ®s.regs[0]; + break; +#endif +#if defined(__aarch64__) || defined(__arm__) + case ARCH_ARM_EABI_THUMB: + /* setup instructions */ + code.u16[0] = 0x47a0; /* blx r4 */ + code.u16[1] = BREAKINST_THUMB; +#ifdef __LP64__ + code.u16[2] = 0x46c0; /* nop (mov r8, r8) */ + code.u16[3] = 0x46c0; /* nop (mov r8, r8) */ +#endif + code_size = sizeof(long); + /* setup registers */ + uregs[16] |= THUMB_MODE_BIT; + uregs[15] = injector->code_addr; + uregs[13] = injector->stack + injector->stack_size - 16; + uregs[4] = function_addr; + uregs[0] = arg1; + uregs[1] = arg2; + uregs[2] = arg3; + uregs[3] = arg4; + PTRACE_OR_RETURN(PTRACE_POKETEXT, injector, uregs[13] + 0, arg5); + PTRACE_OR_RETURN(PTRACE_POKETEXT, injector, uregs[13] + 4, arg6); + reg32_return = &uregs[0]; + break; + case ARCH_ARM_EABI: + /* setup instructions */ + code.u32[0] = 0xe12fff34; /* blx r4 */ + code.u32[1] = BREAKINST_ARM; + code_size = 2 * 4; + /* setup registers */ + uregs[16] &= ~THUMB_MODE_BIT; + uregs[15] = injector->code_addr; + uregs[13] = injector->stack + injector->stack_size - 16; + uregs[4] = function_addr; + uregs[0] = arg1; + uregs[1] = arg2; + uregs[2] = arg3; + uregs[3] = arg4; + PTRACE_OR_RETURN(PTRACE_POKETEXT, injector, uregs[13] + 0, arg5); + PTRACE_OR_RETURN(PTRACE_POKETEXT, injector, uregs[13] + 4, arg6); + reg32_return = &uregs[0]; + break; +#endif +#if defined(__mips__) + case ARCH_MIPS_64: + case ARCH_MIPS_N32: + case ARCH_MIPS_O32: + /* setup instructions */ + code.u32[0] = 0x00000009 | (REG_RA << 11) | (REG_T9 << 21); /* jalr $t9; */ + code.u32[1] = 0x00000025 | (REG_A3 << 11) | (REG_T4 << 21); /* or $a3, $t4, $zero; in a delay slot */ + code.u32[2] = 0x0000000d; /* break */ + code.u32[3] = 0x00000000; /* nop */ + code_size = 4 * 4; + DEBUG(" Code: %08"PRIx32" %08"PRIx32" %08"PRIx32" %08"PRIx32"\n", + code.u32[0], code.u32[1], code.u32[2], code.u32[3]); + /* setup registers */ + regs.cp0_epc = injector->code_addr; + regs.regs[REG_FP] = injector->stack + injector->stack_size - 32; + regs.regs[REG_SP] = injector->stack + injector->stack_size - 64; + regs.regs[REG_T9] = function_addr; + regs.regs[REG_A0] = arg1; + regs.regs[REG_A1] = arg2; + regs.regs[REG_A2] = arg3; + regs.regs[REG_T4] = arg4; + if (injector->arch != ARCH_MIPS_O32) { + /* ARCH_MIPS_64 or ARCH_MIPS_N32 */ + regs.regs[REG_A4] = arg5; + regs.regs[REG_A5] = arg6; + } else { + /* ARCH_MIPS_O32 */ + PTRACE_OR_RETURN(PTRACE_POKETEXT, injector, regs.regs[REG_SP] + 16, arg5); + PTRACE_OR_RETURN(PTRACE_POKETEXT, injector, regs.regs[REG_SP] + 20, arg6); + } + reg_return = ®s.regs[REG_V0]; + break; +#endif +#if defined(__powerpc__) +#ifdef __LP64__ + case ARCH_POWERPC_64: +#endif + case ARCH_POWERPC: + /* setup instructions */ + code.u32[0] = 0x4e800421; /* bctrl */ + code.u32[1] = 0x7fe00008; /* trap */ + code_size = 2 * 4; + /* setup registers */ + regs.nip = injector->code_addr; + regs.gpr[PT_R1] = injector->stack + injector->stack_size - 256; + regs.ctr = function_addr; + regs.gpr[PT_R3] = arg1; + regs.gpr[PT_R4] = arg2; + regs.gpr[PT_R5] = arg3; + regs.gpr[PT_R6] = arg4; + regs.gpr[PT_R7] = arg5; + regs.gpr[PT_R8] = arg6; + regs.gpr[PT_R12] = function_addr; + reg_return = ®s.gpr[PT_R3]; + break; +#endif +#if defined(__riscv) +#ifdef __LP64__ + case ARCH_RISCV_64: +#endif + case ARCH_RISCV_32: + /* setup instructions */ + code.u32[0] = 0x00000067 | (REG_RA << 7) | (REG_T1 << 15) ; /* jalr t1 */ + code.u32[1] = 0x00100073; /* ebreak */ + code_size = 2 * 4; + DEBUG(" Code: %08"PRIx32" %08"PRIx32"\n", + code.u32[0], code.u32[1]); + /* setup registers */ + regs.pc = injector->code_addr; + regs.sp = injector->stack + injector->stack_size - 16; + regs.t1 = function_addr; + regs.a0 = arg1; + regs.a1 = arg2; + regs.a2 = arg3; + regs.a3 = arg4; + regs.a4 = arg5; + regs.a5 = arg6; + reg_return = ®s.a0; + break; +#endif + default: + injector__set_errmsg("Unexpected architecture: %s", injector__arch2name(injector->arch)); + return -1; + } + + PRINT_REGS(injector, ®s); + rv = kick_then_wait_sigtrap(injector, ®s, &code, code_size); + if (rv != 0) { + return rv; + } + PRINT_REGS(injector, ®s); + + if (retval != NULL) { +#if defined(__aarch64__) + if (reg32_return != NULL) { + *retval = (long)*reg32_return; + } else { + *retval = (long)*reg_return; + } +#else + *retval = (long)*reg_return; +#endif + } + return 0; +} + +static int kick_then_wait_sigtrap(const injector_t *injector, struct user_regs_struct *regs, code_t *code, size_t code_size) +{ + int status; + int rv; + + rv = injector__set_regs(injector, regs); + if (rv != 0) { + return rv; + } + rv = injector__write(injector, injector->code_addr, code, code_size); + if (rv != 0) { + injector__set_regs(injector, &injector->regs); + return rv; + } + + rv = injector__continue(injector); + if (rv != 0) { + goto cleanup; + } + while (1) { + pid_t pid = waitpid(injector->pid, &status, 0); + if (pid == -1) { + if (errno == EINTR) { + continue; + } + injector__set_errmsg("waitpid error: %s", strerror(errno)); + rv = INJERR_WAIT_TRACEE; + goto cleanup; + } + if (WIFSTOPPED(status)) { +#if defined(PT_GETSIGINFO) + siginfo_t si = {0,}; +#endif + switch (WSTOPSIG(status)) { + case SIGTRAP: + goto got_sigtrap; + case SIGSTOP: + rv = injector__continue(injector); + if (rv != 0) { + goto cleanup; + } + break; +#if defined(PT_GETSIGINFO) + case SIGSYS: + PTRACE_OR_RETURN(PT_GETSIGINFO, injector, 0, (long)&si); + if (si.si_signo == SIGSYS && si.si_code == 1) { + injector__set_errmsg("Got SIGSYS. System call %d at address %p might be blocked by seccomp.", + si.si_syscall, (void*)si.si_call_addr); + rv = INJERR_OTHER; + goto cleanup; + } + // FALL THROUGH */ +#endif + default: + injector__set_errmsg("The target process unexpectedly stopped by signal %d.", WSTOPSIG(status)); + rv = INJERR_OTHER; + goto cleanup; + } + } else if (WIFEXITED(status)) { + injector__set_errmsg("The target process unexpectedly terminated with exit code %d.", WEXITSTATUS(status)); + rv = INJERR_OTHER; + goto cleanup; + } else if (WIFSIGNALED(status)) { + injector__set_errmsg("The target process unexpectedly terminated by signal %d.", WTERMSIG(status)); + rv = INJERR_OTHER; + goto cleanup; + } else { + /* never reach here */ + injector__set_errmsg("Unexpected waitpid status: 0x%x", status); + rv = INJERR_OTHER; + goto cleanup; + } + } +got_sigtrap: + /* success */ + rv = injector__get_regs(injector, regs); +cleanup: + injector__set_regs(injector, &injector->regs); + injector__write(injector, injector->code_addr, &injector->backup_code, code_size); + return rv; +} diff --git a/RemoteInput/Thirdparty/kubo_injector/src/linux/shellcode.S b/RemoteInput/Thirdparty/kubo_injector/src/linux/shellcode.S new file mode 100644 index 0000000..6704606 --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/src/linux/shellcode.S @@ -0,0 +1,70 @@ +#if defined(__x86_64__) +#define handle_offset 0 +#define dlopen_addr_offset 8 +#define dlerror_addr_offset 16 +#define dlflags_offset 24 +#define file_path_offset 28 +#define page_size 4096 + .text + .global injector_shellcode + .hidden injector_shellcode + .type injector_shellcode, @function + // void *injector_shellcode(injector_shellcode_arg_t *arg) { +injector_shellcode: + // // prolog + pushq %rbx + movq %rdi, %rbx + // int dlflags = arg->dlflags; + movl dlflags_offset(%rbx), %esi + // const char *file_path = arg->file_path; + leaq file_path_offset(%rbx), %rdi + // void *handle = dlopen(file_path, dlflags); + call *dlopen_addr_offset(%rbx) + // arg->handle = handle; + movq %rax, handle_offset(%rbx) + // arg->file_path[0] = '\0'; + movb $0, file_path_offset(%rbx) + // if (handle != NULL) return; + test %rax, %rax + jnz .exit + // if (arg->dlerror_addr == 0) return; + cmpq $0, dlerror_addr_offset(%rbx) + je .exit + // char *errmsg = dlerror(); + call *dlerror_addr_offset(%rbx) + // if (errmsg == NULL) return; + test %rax, %rax + jz .exit + // char *dest = arg->file_path + leaq file_path_offset(%rbx), %rdi + // char *end = (char*)arg + page_size; + leaq page_size(%rbx), %rcx +.loop: + // char c = *(errmsg++); + movb (%rax), %dl + addq $1, %rax + // *(dest++) = c; + movb %dl, (%rdi) + addq $1, %rdi + // if (c == 0) return; + testb %dl, %dl + jz .exit + // if (dest < end) goto loop; + cmpq %rdi, %rcx + ja .loop +.exit: + // // epilog + popq %rbx + ret + // } + .size injector_shellcode, . - injector_shellcode + + .balign 4 + .global injector_shellcode_size + .hidden injector_shellcode_size + .type injector_shellcode_size, @object + .size injector_shellcode_size, 4 +injector_shellcode_size: + // distance from injector_shellcode to current. + .int . - injector_shellcode +#endif diff --git a/RemoteInput/Thirdparty/kubo_injector/src/linux/util.c b/RemoteInput/Thirdparty/kubo_injector/src/linux/util.c new file mode 100644 index 0000000..3146743 --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/src/linux/util.c @@ -0,0 +1,82 @@ +/* -*- indent-tabs-mode: nil -*- + * + * injector - Library for injecting a shared library into a Linux process + * + * URL: https://github.com/kubo/injector + * + * ------------------------------------------------------ + * + * Copyright (C) 2018 Kubo Takehiro + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include "injector_internal.h" + +char injector__errmsg[512]; +char injector__errmsg_is_set; + +void injector__set_errmsg(const char *format, ...) +{ + va_list ap; + int rv; + + /* prevent the error message from being overwritten. */ + if (injector__errmsg_is_set) { + return; + } + injector__errmsg_is_set = 1; + + va_start(ap, format); + rv = vsnprintf(injector__errmsg, sizeof(injector__errmsg), format, ap); + va_end(ap); + if (rv == -1 || rv >= sizeof(injector__errmsg)) { + injector__errmsg[sizeof(injector__errmsg) - 1] = '\0'; + } +} + +const char *injector__arch2name(arch_t arch) +{ + switch (arch) { + case ARCH_X86_64: + return "x86_64"; + case ARCH_X86_64_X32: + return "x86_64 x32-ABI"; + case ARCH_I386: + return "i386"; + case ARCH_ARM64: + return "ARM64"; + case ARCH_ARM_EABI_THUMB: + return "ARM EABI thumb"; + case ARCH_ARM_EABI: + return "ARM EABI"; + case ARCH_MIPS_64: + return "MIPS 64"; + case ARCH_MIPS_N32: + return "MIPS N32 ABI"; + case ARCH_MIPS_O32: + return "MIPS O32 ABI"; + case ARCH_POWERPC_64: + return "PowerPC 64-bit"; + case ARCH_POWERPC: + return "PowerPC"; + case ARCH_RISCV_64: + return "RISC-V 64"; + case ARCH_RISCV_32: + return "RISC-V 32"; + } + return "?"; +} diff --git a/RemoteInput/Thirdparty/kubo_injector/src/macos/exc_handler.c b/RemoteInput/Thirdparty/kubo_injector/src/macos/exc_handler.c new file mode 100644 index 0000000..1dd10d7 --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/src/macos/exc_handler.c @@ -0,0 +1,314 @@ +/* -*- indent-tabs-mode: nil -*- + * + * injector - Library for injecting a shared library into a Linux process + * + * URL: https://github.com/kubo/injector + * + * ------------------------------------------------------ + * + * Copyright (C) 2022 TheOiseth + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "injector_internal.h" +#include +#include +#include +#include +#include +#define HANDLE_EXC EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT | EXC_MASK_CRASH | EXC_MASK_CORPSE_NOTIFY +boolean_t mach_exc_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP); +int injector__create_exc_handler(injector_t *injector) { + mach_port_name_t exc_port = 0; + mach_msg_type_number_t exception_types_count; + int rv; + injector->exc_port = 0; + injector->saved_exception_types_count = 0; + rv = task_get_exception_ports(injector->remote_task, + EXC_MASK_ALL, + injector->saved_masks, + &exception_types_count, + injector->saved_ports, + injector->saved_behaviors, + injector->saved_flavors); + + injector->saved_exception_types_count = exception_types_count; + if(rv != 0){ + injector__set_errmsg("%s error : %s", "EXC_GET_PORTS", mach_error_string(rv)); + return INJERR_OTHER; + } + + rv = mach_port_allocate(mach_task_self(), + MACH_PORT_RIGHT_RECEIVE, + &exc_port); + injector->exc_port = exc_port; + if(rv != 0){ + injector__set_errmsg("%s error : %s", "EXC_PORT_ALLOCATE", mach_error_string(rv)); + rv = INJERR_OTHER; + goto cleanup; + } + rv = mach_port_insert_right(mach_task_self(), + exc_port, + exc_port, + MACH_MSG_TYPE_MAKE_SEND); + if(rv != 0){ + injector__set_errmsg("%s error : %s", "EXC_INSERT_RIGHTS", mach_error_string(rv)); + rv = INJERR_OTHER; + goto cleanup; + } + + rv = task_set_exception_ports(injector->remote_task, + HANDLE_EXC, + exc_port, + EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, + THREAD_STATE_NONE); + if(rv != 0){ + injector__set_errmsg("%s error : %s", "EXC_SET_PORTS", mach_error_string(rv)); + rv = INJERR_OTHER; + goto cleanup; + } + + return 0; +cleanup: + injector__release_exc_handler(injector); +return rv; +} +int injector__handle_exc(injector_t *injector) { + char req[128], rpl[128]; + mach_msg_header_with_injector *mmhwi; + int rv; + + mmhwi = (mach_msg_header_with_injector*)req; + mmhwi->injector = injector; + rv = mach_msg((mach_msg_header_t *)req, MACH_RCV_MSG, 0, sizeof(req), injector->exc_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + if (rv != KERN_SUCCESS) { + injector__set_errmsg("%s error : %s", "EXC_RECV_MACH_MSG", mach_error_string(rv)); + return INJERR_OTHER; + } +/* suspend all threads in the process after an exception was received */ + + task_suspend(injector->remote_task); + + boolean_t message_parsed_correctly = mach_exc_server((mach_msg_header_t *)req, (mach_msg_header_t *)rpl); + if (! message_parsed_correctly) { + + size_t parse_exc = ((mig_reply_error_t *)rpl)->RetCode; + if(parse_exc != 0 ){ + injector__set_errmsg("%s error : %s", "mach_exc_server", mach_error_string(parse_exc)); + } + } + task_resume(injector->remote_task); + mach_msg_size_t send_sz = ((mach_msg_header_t *)rpl)->msgh_size; + + rv = mach_msg((mach_msg_header_t *)rpl, MACH_SEND_MSG, send_sz, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + if (rv != KERN_SUCCESS) { + injector__set_errmsg("%s error : %s", "EXC_SEND_MACH_MSG", mach_error_string(rv)); + return INJERR_OTHER; + } + return 0; +} + +static bool isSIGSTOP(exception_type_t exception_type, mach_exception_data_t codes){ + return exception_type == EXC_SOFTWARE && codes[0] == EXC_SOFT_SIGNAL && codes[1] == SIGSTOP; +} + +kern_return_t catch_mach_exception_raise( + mach_port_t exception_port, + mach_port_t thread_port, + mach_port_t task_port, + exception_type_t exception_type, + mach_exception_data_t codes, + mach_msg_type_number_t num_codes, + injector_t *injector) +{ + injector->handle_err = 0; + bool bad_exc = true; + int rv; + switch (injector->handle_action) + { + case STOP_CONTINUE: + if(isSIGSTOP(exception_type, codes)){ + bad_exc = false; + injector__ptrace_update(injector, thread_port); + } + break; + case STOP_DETACH: + if(isSIGSTOP(exception_type, codes)){ + bad_exc = false; + injector__ptrace_detach(injector); + } + break; + case TRAP_GETREGS: + if(exception_type == EXC_BREAKPOINT){ + bad_exc = false; +#if defined(__arm64__) || defined(__aarch64__) + mach_msg_type_number_t thread_state_count = ARM_THREAD_STATE64_COUNT; + arm_thread_state64_t state; + rv = thread_get_state(thread_port, ARM_THREAD_STATE64, (thread_state_t)&state, &thread_state_count); + if (rv == KERN_SUCCESS) { + injector->retval = state.__x[0]; + } else { + injector__set_errmsg("%s error : %s", "GET_THREAD_STATE", mach_error_string(rv)); + injector->handle_err = INJERR_ERROR_IN_TARGET; + } +#else + mach_msg_type_number_t thread_state_count = x86_THREAD_STATE64_COUNT; + x86_thread_state64_t state; + rv = thread_get_state(thread_port, x86_THREAD_STATE64, (thread_state_t)&state, &thread_state_count); + if (rv == KERN_SUCCESS) { + injector->retval = state.__rax; + } else { + injector__set_errmsg("%s error : %s", "GET_THREAD_STATE", mach_error_string(rv)); + injector->handle_err = INJERR_ERROR_IN_TARGET; + } +#endif + if (injector->mach_thread != 0){ + rv = thread_terminate(injector->mach_thread); + injector->mach_thread = 0; + } + rv = thread_suspend(thread_port); + if(rv != KERN_SUCCESS){ + injector__set_errmsg("%s error : %s", "THREAD_SUSPEND", mach_error_string(rv)); + injector->handle_err = INJERR_ERROR_IN_TARGET; + } + //we don't need to continue since we already called task_resume and mach_msg later + //rv = injector__ptrace_continue(injector); + + } + break; + case TRAP_SETREGS: + if(exception_type == EXC_BREAKPOINT){ + bad_exc = false; + bool thread_init = false; + if(thread_port != injector->mach_thread){ + thread_init = injector->remote_thread == 0; + injector->remote_thread = thread_port; + } +#if defined(__arm64__) || defined(__aarch64__) + mach_msg_type_number_t thread_state_count = ARM_THREAD_STATE64_COUNT; + arm_thread_state64_t state; + rv = thread_get_state(thread_port, ARM_THREAD_STATE64, (thread_state_t)&state, &thread_state_count); + if (rv != KERN_SUCCESS) { + injector__set_errmsg("%s error : %s", "GET_THREAD_STATE", mach_error_string(rv)); + injector->handle_err = INJERR_ERROR_IN_TARGET; + goto exit; + } + if(thread_init){ + memcpy(&injector->remote_thread_saved_state, &state, sizeof(state)); + injector->state_saved = 1; + } + state.__x[0] = injector->arg1; + state.__x[1] = injector->arg2; + state.__x[2] = injector->arg3; + state.__x[3] = injector->arg4; + state.__x[4] = injector->arg5; + state.__x[5] = injector->arg6; + state.__x[8] = injector->func_addr; + state.__sp = injector->stack; + state.__pc = injector->code2_addr + 4; + rv = thread_set_state(thread_port, ARM_THREAD_STATE64, (thread_state_t)&state, ARM_THREAD_STATE64_COUNT); + if (rv != KERN_SUCCESS) { + injector__set_errmsg("%s error : %s", "SET_THREAD_STATE", mach_error_string(rv)); + injector->handle_err = INJERR_ERROR_IN_TARGET; + } +#else + mach_msg_type_number_t thread_state_count = x86_THREAD_STATE64_COUNT; + x86_thread_state64_t state; + + rv = thread_get_state(thread_port, x86_THREAD_STATE64, (thread_state_t)&state, &thread_state_count); + if (rv != KERN_SUCCESS) { + injector__set_errmsg("%s error : %s", "GET_THREAD_STATE", mach_error_string(rv)); + injector->handle_err = INJERR_ERROR_IN_TARGET; + goto exit; + } + if(thread_init){ + memcpy(&injector->remote_thread_saved_state, &state, sizeof(state)); + injector->state_saved = 1; + } + state.__rax = injector->func_addr; + state.__rdi = injector->arg1; + state.__rsi = injector->arg2; + state.__rdx = injector->arg3; + state.__rcx = injector->arg4; + state.__r8 = injector->arg5; + state.__r9 = injector->arg6; + state.__rsp = injector->stack; + state.__rbp = injector->stack; + rv = thread_set_state(thread_port, x86_THREAD_STATE64, (thread_state_t)&state, x86_THREAD_STATE64_COUNT); + if (rv != KERN_SUCCESS) { + injector__set_errmsg("%s error : %s", "SET_THREAD_STATE", mach_error_string(rv)); + injector->handle_err = INJERR_ERROR_IN_TARGET; + } +#endif + //we don't need to continue since we already called task_resume and mach_msg later + //rv = injector__ptrace_continue(injector); + + } + break; + } + + if(bad_exc){ + if(exception_type == EXC_SOFTWARE){ + injector__set_errmsg("The target process got an unexpected signal %i.", codes[1]); + } else { + injector__set_errmsg("Got unhandled exception %i.", exception_type); + } + injector->handle_err = INJERR_OTHER; + } +exit: + return KERN_SUCCESS; +} + +kern_return_t catch_mach_exception_raise_state( + mach_port_t exception_port, + exception_type_t exception, + const mach_exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + const thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt) +{ + return MACH_RCV_INVALID_TYPE; +} + +kern_return_t catch_mach_exception_raise_state_identity( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt) +{ + return MACH_RCV_INVALID_TYPE; +} + +int injector__release_exc_handler(injector_t *injector) { + for (int i = 0; i < injector->saved_exception_types_count; i++) { + task_set_exception_ports(injector->remote_task, injector->saved_masks[i], injector->saved_ports[i], injector->saved_behaviors[i], injector->saved_flavors[i]); + } + injector->saved_exception_types_count = 0; + if (injector->exc_port != 0){ + mach_port_deallocate(mach_task_self(), injector->exc_port); + injector->exc_port = 0; + } + return 0; +} \ No newline at end of file diff --git a/RemoteInput/Thirdparty/kubo_injector/src/macos/injector.c b/RemoteInput/Thirdparty/kubo_injector/src/macos/injector.c new file mode 100644 index 0000000..3711022 --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/src/macos/injector.c @@ -0,0 +1,295 @@ +/* -*- indent-tabs-mode: nil -*- + * + * injector - Library for injecting a shared library into a Linux process + * + * URL: https://github.com/kubo/injector + * + * ------------------------------------------------------ + * + * Copyright (C) 2022 TheOiseth + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "injector_internal.h" +#include +#include +#include +#include +#include + +#define STACK_SIZE 2 * 1024 * 1024 +#define CODE_SIZE 512 +int injector_attach(injector_t **injector_out, pid_t pid) +{ + injector_t *injector; + arch_t self_arch, target_arch; + int rv = 0; + + injector__errmsg_is_set = 0; + + injector = calloc(1, sizeof(injector_t)); + if (injector == NULL) { + injector__set_errmsg("malloc error: %s", strerror(errno)); + return INJERR_NO_MEMORY; + } + injector->pid = pid; + rv = injector__get_process_arch(getpid(), &self_arch); + if (rv != 0) { + goto error_exit; + } + rv = injector__get_process_arch(pid, &target_arch); + if (rv != 0) { + goto error_exit; + } + arch_t sys_arch = injector__get_system_arch(); + + if(self_arch != ARCH_UNKNOWN && target_arch != ARCH_UNKNOWN){ + if(self_arch != target_arch){ + injector__set_errmsg("%s target process isn't supported by %s process.", injector__arch2name(target_arch), injector__arch2name(self_arch)); + rv = INJERR_UNSUPPORTED_TARGET; + goto error_exit; + } + if(sys_arch == ARCH_ARM64 && self_arch != ARCH_ARM64){ + injector__set_errmsg("%s target process isn't supported by %s process on ARM64 machine.", injector__arch2name(target_arch), injector__arch2name(self_arch)); + rv = INJERR_UNSUPPORTED_TARGET; + goto error_exit; + } + } + + rv = injector__task_pid(injector); + if (rv != 0) { + goto error_exit; + } + injector->attached = 1; + + rv = injector__create_exc_handler(injector); + + if (rv != 0) { + goto error_exit; + } + rv = injector__ptrace_attach(injector); + if(rv != 0){ + return rv; + } + injector->handle_action = STOP_CONTINUE; + injector->handle_err = 0; + do{ + injector__handle_exc(injector); + } while(injector->handle_err != 0); + + injector->ptrace_attached = 1; + + injector->text_size = sysconf(_SC_PAGESIZE); + injector->stack_size = STACK_SIZE; + injector->code_size = CODE_SIZE; + + size_t alloc_size = injector->text_size + injector->stack_size; + + mach_vm_address_t addr = (vm_address_t)NULL; + rv = injector__allocate(injector, &addr, alloc_size, VM_FLAGS_ANYWHERE); + if (rv != 0) { + goto error_exit; + } + + mach_vm_address_t code_addr = (vm_address_t)NULL; + rv = injector__allocate(injector, &code_addr, CODE_SIZE, VM_FLAGS_ANYWHERE); + if (rv != 0) { + goto error_exit; + } + + injector->allocated = 1; + injector->text = (size_t)addr; + injector->stack = injector->text + injector->text_size + injector->stack_size / 2; + injector->stack &= 0xFFFFFFFFFFFFFFF0; //alignment + injector->code_addr = (size_t)code_addr; + + rv = injector__protect(injector, addr, alloc_size, FALSE, VM_PROT_READ | VM_PROT_WRITE); + if (rv != 0) { + goto error_exit; + } + + rv = injector__protect(injector, code_addr, CODE_SIZE, FALSE, VM_PROT_READ | VM_PROT_WRITE); + if (rv != 0) { + goto error_exit; + } + *injector_out = injector; + return 0; +error_exit: + injector_detach(injector); + return rv; +} + +int injector_inject(injector_t *injector, const char *path, void **handle) +{ + char abspath[PATH_MAX]; + int dlflags = RTLD_LAZY; + size_t len; + int rv; + long retval; + injector__errmsg_is_set = 0; + if (realpath(path, abspath) == NULL) { + injector__set_errmsg("failed to get the full path of '%s': %s", + path, strerror(errno)); + return INJERR_FILE_NOT_FOUND; + } + len = strlen(abspath) + 1; + if (len > injector->text_size) { + injector__set_errmsg("too long file path: %s", path); + return INJERR_FILE_NOT_FOUND; + } + + rv = injector__write(injector, injector->text, abspath, len); + if (rv != 0) { + return rv; + } + + rv = injector__call_function(injector, &retval, (long)dlopen, injector->text, dlflags); + if (rv != 0) { + return rv; + } + if (retval == 0) { + char buf[256 + 1] = {0,}; + rv = injector__call_function(injector, &retval, (long)dlerror); + if (rv == 0 && retval != 0) { + injector__read(injector, retval, buf, sizeof(buf) - 1); + } + + if (buf[0] != '\0') { + injector__set_errmsg("dlopen failed: %s", buf); + } else { + injector__set_errmsg("dlopen failed"); + } + + return INJERR_ERROR_IN_TARGET; + } + if (handle != NULL) { + *handle = (void*)retval; + } + return 0; +} + +int injector_call(injector_t *injector, void *handle, const char* name) +{ + int rv; + long retval; + size_t len = strlen(name) + 1; + + injector__errmsg_is_set = 0; + + if (len > injector->text_size) { + injector__set_errmsg("too long function name: %s", name); + return INJERR_FUNCTION_MISSING; + } + rv = injector__write(injector, injector->text, name, len); + if (rv != 0) { + return rv; + } + rv = injector__call_function(injector, &retval, (long)dlsym, handle, injector->text); + if (retval == 0) { + injector__set_errmsg("function not found: %s", name); + return INJERR_FUNCTION_MISSING; + } + return injector__call_function(injector, &retval, retval); +} + +int injector_uninject(injector_t *injector, void *handle) +{ + int rv; + long retval; + + injector__errmsg_is_set = 0; + + rv = injector__call_function(injector, &retval, (long)dlclose, handle); + if (rv != 0) { + return rv; + } + if (retval != 0) { + injector__set_errmsg("dlclose failed"); + return INJERR_ERROR_IN_TARGET; + } + return 0; +} + +int injector_detach(injector_t *injector) +{ + int rv = 0; + injector__errmsg_is_set = 0; + if (injector->remote_thread != 0) { + //For some reasons on MacOS ARM64 (tested on 12.0.1) thread_terminate() returns unknown error, so let it end by itslef + if(injector->state_saved){ +#if defined(__arm64__) || defined(__aarch64__) + injector->remote_thread_saved_state.__pc = injector->code2_addr + 12; + rv = thread_set_state(injector->remote_thread, ARM_THREAD_STATE64, (thread_state_t)&injector->remote_thread_saved_state, ARM_THREAD_STATE64_COUNT); + if (rv != KERN_SUCCESS) { + injector__set_errmsg("%s error : %s", "GET_THREAD_STATE", mach_error_string(rv)); + rv = INJERR_ERROR_IN_TARGET; + } +#else + injector->remote_thread_saved_state.__rip = injector->code2_addr + 4; + rv = thread_set_state(injector->remote_thread, x86_THREAD_STATE64, (thread_state_t)&injector->remote_thread_saved_state, x86_THREAD_STATE64_COUNT); + if (rv != KERN_SUCCESS) { + injector__set_errmsg("%s error : %s", "GET_THREAD_STATE", mach_error_string(rv)); + rv = INJERR_ERROR_IN_TARGET; + } +#endif + rv = thread_resume(injector->remote_thread); + if(rv != 0){ + injector__set_errmsg("Remote thread resume error: %s\n", mach_error_string(rv)); + rv = INJERR_ERROR_IN_TARGET; + } + + //wait thread for end +#if defined(__arm64__) || defined(__aarch64__) + thread_state_flavor_t flavor = ARM_THREAD_STATE64; +#else + thread_state_flavor_t flavor = x86_THREAD_STATE64; +#endif + mach_msg_type_number_t state_count; + int counter = 0; + while(thread_get_state(injector->remote_thread, flavor, (thread_state_t)&injector->remote_thread_saved_state, &state_count) == 0){ + counter++; + usleep(10); + if(counter > 1000){ + break; + } + } + } + } + + if (injector->ptrace_attached) { + injector->handle_action = STOP_DETACH; + kill(injector->pid, SIGSTOP); + injector->handle_err = 0; + do{ + injector__handle_exc(injector); + } while(injector->handle_err != 0); + injector__release_exc_handler(injector); + } + + if (injector->allocated) { + injector__deallocate(injector, injector->text, injector->text_size + injector->stack_size); + injector__deallocate(injector, injector->code_addr, injector->code_size); + } + if (injector->attached) { + mach_port_deallocate(mach_task_self(), injector->remote_task); + } + + free(injector); + return rv; +} +const char *injector_error(void) +{ + return injector__errmsg; +} \ No newline at end of file diff --git a/RemoteInput/Thirdparty/kubo_injector/src/macos/injector_internal.h b/RemoteInput/Thirdparty/kubo_injector/src/macos/injector_internal.h new file mode 100644 index 0000000..5129db6 --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/src/macos/injector_internal.h @@ -0,0 +1,121 @@ +/* -*- indent-tabs-mode: nil -*- + * + * injector - Library for injecting a shared library into a Linux process + * + * URL: https://github.com/kubo/injector + * + * ------------------------------------------------------ + * + * Copyright (C) 2022 TheOiseth + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "injector.h" +#include +#include +#include +#include +#include + +typedef enum { + STOP_CONTINUE, + STOP_DETACH, + TRAP_SETREGS, + TRAP_GETREGS +} handle_action_t; + +struct injector { + pid_t pid; + uint8_t attached; + uint8_t allocated; + uint8_t ptrace_attached; + uint8_t shellcode_writed; + task_t remote_task; + size_t code_addr; + size_t code2_addr; + size_t code_size; + size_t text; + size_t text_size; + size_t stack; + size_t stack_size; + + thread_act_t mach_thread; + thread_act_t remote_thread; +#if defined(__arm64__) || defined(__aarch64__) + arm_thread_state64_t remote_thread_saved_state; +#else + x86_thread_state64_t remote_thread_saved_state; +#endif + uint8_t state_saved; + long func_addr; + long arg1; + long arg2; + long arg3; + long arg4; + long arg5; + long arg6; + mach_port_name_t exc_port; + exception_mask_t saved_masks[EXC_TYPES_COUNT]; + mach_port_t saved_ports[EXC_TYPES_COUNT]; + exception_behavior_t saved_behaviors[EXC_TYPES_COUNT]; + thread_state_flavor_t saved_flavors[EXC_TYPES_COUNT]; + mach_msg_type_number_t saved_exception_types_count; + handle_action_t handle_action; + long retval; + int handle_err; + +}; + +typedef struct{ + char stub[120]; + injector_t *injector; +} mach_msg_header_with_injector; + +typedef enum { + ARCH_X86_64, + ARCH_I386, + ARCH_ARM64, + ARCH_POWERPC_64, + ARCH_POWERPC, + ARCH_UNKNOWN +} arch_t; + + + +typedef int (*pcfmt_t)(pthread_t* ,pthread_attr_t* ,void *, void*); + +int injector__task_pid(injector_t *injector); +int injector__allocate(const injector_t *injector, mach_vm_address_t *address, mach_vm_size_t size, int flags); +int injector__deallocate(const injector_t *injector, mach_vm_address_t address, mach_vm_size_t size); +int injector__protect(const injector_t *injector, mach_vm_address_t address, mach_vm_size_t size, boolean_t set_maximum, vm_prot_t new_protection); +int injector__write(const injector_t *injector, size_t addr, const void *buf, size_t len); +int injector__read(const injector_t *injector, size_t addr, void *buf, size_t len); +int injector__ptrace_attach(const injector_t *injector); +int injector__ptrace_detach(const injector_t *injector); +int injector__ptrace_continue(const injector_t *injector); +int injector__ptrace_update(const injector_t *injector, long thread_port); + +int injector__create_exc_handler(injector_t *injector); +int injector__release_exc_handler(injector_t *injector); +int injector__handle_exc(injector_t *injector); + +int injector__call_function(injector_t *injector, long *retval, long function_addr, ...); +/* util.c */ +extern char injector__errmsg[]; +extern char injector__errmsg_is_set; +void injector__set_errmsg(const char *format, ...); +const char *injector__arch2name(arch_t arch); +int injector__get_process_arch(pid_t pid, arch_t *arch); +arch_t injector__get_system_arch(); \ No newline at end of file diff --git a/RemoteInput/Thirdparty/kubo_injector/src/macos/mach.c b/RemoteInput/Thirdparty/kubo_injector/src/macos/mach.c new file mode 100644 index 0000000..3d5f43f --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/src/macos/mach.c @@ -0,0 +1,112 @@ +/* -*- indent-tabs-mode: nil -*- + * + * injector - Library for injecting a shared library into a Linux process + * + * URL: https://github.com/kubo/injector + * + * ------------------------------------------------------ + * + * Copyright (C) 2022 TheOiseth + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "injector_internal.h" +#include +#include +static int set_mach_error(const char *request_name, int err) +{ + injector__set_errmsg("%s error : %s", request_name, mach_error_string(err)); + switch (err) { + case KERN_INVALID_ADDRESS: + return INJERR_INVALID_MEMORY_AREA; + case KERN_NO_ACCESS: + return INJERR_PERMISSION; + } + return INJERR_OTHER; +} + +static int set_error(const char *request_name) +{ + int err = errno; + injector__set_errmsg("%s error : %s", request_name, strerror(errno)); + switch (err) { + case EFAULT: + return INJERR_INVALID_MEMORY_AREA; + case EPERM: + return INJERR_PERMISSION; + case ESRCH: + return INJERR_NO_PROCESS; + } + return INJERR_OTHER; +} + +int injector__task_pid(injector_t *injector) +{ + int rv = kill(injector->pid, 0); + if(rv != 0){ + return set_error("TASK_FOR_PID"); + } + task_t remote_task; + rv = task_for_pid(mach_task_self(), injector->pid, &remote_task); + + if (rv != KERN_SUCCESS) { + return set_mach_error("TASK_FOR_PID", rv); + } + injector->remote_task = remote_task; + return 0; +} + +int injector__allocate(const injector_t *injector, mach_vm_address_t *address, mach_vm_size_t size, int flags) +{ + int rv = mach_vm_allocate(injector->remote_task, address, size, flags); + if (rv != KERN_SUCCESS) { + return set_mach_error("ALLOCATE", rv); + } + return 0; +} + +int injector__deallocate(const injector_t *injector, mach_vm_address_t address, mach_vm_size_t size){ + int rv = mach_vm_deallocate(injector->remote_task, address, size); + if (rv != KERN_SUCCESS) { + return set_mach_error("DEALLOCATE", rv); + } + return 0; +} + +int injector__protect(const injector_t *injector, mach_vm_address_t address, mach_vm_size_t size, boolean_t set_maximum, vm_prot_t new_protection) +{ + int rv = mach_vm_protect(injector->remote_task, address, size, set_maximum, new_protection); + if (rv != KERN_SUCCESS) { + return set_mach_error("PROTECT", rv); + } + return 0; +} + +int injector__write(const injector_t *injector, size_t addr, const void *buf, size_t len) { + int rv = mach_vm_write(injector->remote_task, addr, (vm_offset_t)buf, len); + if (rv != KERN_SUCCESS) { + return set_mach_error("WRITE", rv); + } + return 0; +} +int injector__read(const injector_t *injector, size_t addr, void *buf, size_t len){ + mach_vm_size_t readed; + int rv = mach_vm_read_overwrite(injector->remote_task, addr, len, (mach_vm_address_t)buf, &readed); + if (rv != KERN_SUCCESS) { + return set_mach_error("READ", rv); + } + return 0; +} + diff --git a/RemoteInput/Thirdparty/kubo_injector/src/macos/mach_exc.h b/RemoteInput/Thirdparty/kubo_injector/src/macos/mach_exc.h new file mode 100644 index 0000000..b4123f9 --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/src/macos/mach_exc.h @@ -0,0 +1,330 @@ +/* -*- indent-tabs-mode: nil -*- + * + * injector - Library for injecting a shared library into a Linux process + * + * URL: https://github.com/kubo/injector + * + * ------------------------------------------------------ + * + * this code is generated automatically by mig + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef _mach_exc_user_ +#define _mach_exc_user_ + +/* Module mach_exc */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* BEGIN VOUCHER CODE */ + +#ifndef KERNEL +#if defined(__has_include) +#if __has_include() +#ifndef USING_VOUCHERS +#define USING_VOUCHERS +#endif +#ifndef __VOUCHER_FORWARD_TYPE_DECLS__ +#define __VOUCHER_FORWARD_TYPE_DECLS__ +#ifdef __cplusplus +extern "C" { +#endif + extern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import)); +#ifdef __cplusplus +} +#endif +#endif // __VOUCHER_FORWARD_TYPE_DECLS__ +#endif // __has_include() +#endif // __has_include +#endif // !KERNEL + +/* END VOUCHER CODE */ + + +/* BEGIN MIG_STRNCPY_ZEROFILL CODE */ + +#if defined(__has_include) +#if __has_include() +#ifndef USING_MIG_STRNCPY_ZEROFILL +#define USING_MIG_STRNCPY_ZEROFILL +#endif +#ifndef __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ +#define __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ +#ifdef __cplusplus +extern "C" { +#endif + extern int mig_strncpy_zerofill(char *dest, const char *src, int len) __attribute__((weak_import)); +#ifdef __cplusplus +} +#endif +#endif /* __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ */ +#endif /* __has_include() */ +#endif /* __has_include */ + +/* END MIG_STRNCPY_ZEROFILL CODE */ + + +#ifdef AUTOTEST +#ifndef FUNCTION_PTR_T +#define FUNCTION_PTR_T +typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t); +typedef struct { + char *name; + function_ptr_t function; +} function_table_entry; +typedef function_table_entry *function_table_t; +#endif /* FUNCTION_PTR_T */ +#endif /* AUTOTEST */ + +#ifndef mach_exc_MSG_COUNT +#define mach_exc_MSG_COUNT 3 +#endif /* mach_exc_MSG_COUNT */ + +#include +#include +#include +#include + +#ifdef __BeforeMigUserHeader +__BeforeMigUserHeader +#endif /* __BeforeMigUserHeader */ + +#include +__BEGIN_DECLS + + +/* Routine mach_exception_raise */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +kern_return_t mach_exception_raise +( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t codeCnt +); + +/* Routine mach_exception_raise_state */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +kern_return_t mach_exception_raise_state +( + mach_port_t exception_port, + exception_type_t exception, + const mach_exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + const thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt +); + +/* Routine mach_exception_raise_state_identity */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +kern_return_t mach_exception_raise_state_identity +( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt +); + +__END_DECLS + +/********************** Caution **************************/ +/* The following data types should be used to calculate */ +/* maximum message sizes only. The actual message may be */ +/* smaller, and the position of the arguments within the */ +/* message layout may vary from what is presented here. */ +/* For example, if any of the arguments are variable- */ +/* sized, and less than the maximum is sent, the data */ +/* will be packed tight in the actual message to reduce */ +/* the presence of holes. */ +/********************** Caution **************************/ + +/* typedefs for all requests */ + +#ifndef __Request__mach_exc_subsystem__defined +#define __Request__mach_exc_subsystem__defined + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + } __Request__mach_exception_raise_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[614]; + } __Request__mach_exception_raise_state_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[614]; + } __Request__mach_exception_raise_state_identity_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif +#endif /* !__Request__mach_exc_subsystem__defined */ + +/* union of all requests */ + +#ifndef __RequestUnion__mach_exc_subsystem__defined +#define __RequestUnion__mach_exc_subsystem__defined +union __RequestUnion__mach_exc_subsystem { + __Request__mach_exception_raise_t Request_mach_exception_raise; + __Request__mach_exception_raise_state_t Request_mach_exception_raise_state; + __Request__mach_exception_raise_state_identity_t Request_mach_exception_raise_state_identity; +}; +#endif /* !__RequestUnion__mach_exc_subsystem__defined */ +/* typedefs for all replies */ + +#ifndef __Reply__mach_exc_subsystem__defined +#define __Reply__mach_exc_subsystem__defined + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + } __Reply__mach_exception_raise_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[614]; + } __Reply__mach_exception_raise_state_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[614]; + } __Reply__mach_exception_raise_state_identity_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif +#endif /* !__Reply__mach_exc_subsystem__defined */ + +/* union of all replies */ + +#ifndef __ReplyUnion__mach_exc_subsystem__defined +#define __ReplyUnion__mach_exc_subsystem__defined +union __ReplyUnion__mach_exc_subsystem { + __Reply__mach_exception_raise_t Reply_mach_exception_raise; + __Reply__mach_exception_raise_state_t Reply_mach_exception_raise_state; + __Reply__mach_exception_raise_state_identity_t Reply_mach_exception_raise_state_identity; +}; +#endif /* !__RequestUnion__mach_exc_subsystem__defined */ + +#ifndef subsystem_to_name_map_mach_exc +#define subsystem_to_name_map_mach_exc \ + { "mach_exception_raise", 2405 },\ + { "mach_exception_raise_state", 2406 },\ + { "mach_exception_raise_state_identity", 2407 } +#endif + +#ifdef __AfterMigUserHeader +__AfterMigUserHeader +#endif /* __AfterMigUserHeader */ + +#endif /* _mach_exc_user_ */ diff --git a/RemoteInput/Thirdparty/kubo_injector/src/macos/mach_excServer.c b/RemoteInput/Thirdparty/kubo_injector/src/macos/mach_excServer.c new file mode 100644 index 0000000..b1a20e8 --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/src/macos/mach_excServer.c @@ -0,0 +1,828 @@ +/* -*- indent-tabs-mode: nil -*- + * + * injector - Library for injecting a shared library into a Linux process + * + * URL: https://github.com/kubo/injector + * + * ------------------------------------------------------ + * + * this code is generated automatically by mig + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +/* + * IDENTIFICATION: + * stub generated Mon Nov 7 09:48:39 2022 + * with a MiG generated by bootstrap_cmds-117 + * OPTIONS: + */ + +/* Module mach_exc */ + +#define __MIG_check__Request__mach_exc_subsystem__ 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "injector_internal.h" +/* BEGIN VOUCHER CODE */ + +#ifndef KERNEL +#if defined(__has_include) +#if __has_include() +#ifndef USING_VOUCHERS +#define USING_VOUCHERS +#endif +#ifndef __VOUCHER_FORWARD_TYPE_DECLS__ +#define __VOUCHER_FORWARD_TYPE_DECLS__ +#ifdef __cplusplus +extern "C" { +#endif + extern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import)); +#ifdef __cplusplus +} +#endif +#endif // __VOUCHER_FORWARD_TYPE_DECLS__ +#endif // __has_include() +#endif // __has_include +#endif // !KERNEL + +/* END VOUCHER CODE */ + + +/* BEGIN MIG_STRNCPY_ZEROFILL CODE */ + +#if defined(__has_include) +#if __has_include() +#ifndef USING_MIG_STRNCPY_ZEROFILL +#define USING_MIG_STRNCPY_ZEROFILL +#endif +#ifndef __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ +#define __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ +#ifdef __cplusplus +extern "C" { +#endif + extern int mig_strncpy_zerofill(char *dest, const char *src, int len) __attribute__((weak_import)); +#ifdef __cplusplus +} +#endif +#endif /* __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ */ +#endif /* __has_include() */ +#endif /* __has_include */ + +/* END MIG_STRNCPY_ZEROFILL CODE */ + + +#include +#include +#include +#include + +#ifndef mig_internal +#define mig_internal static __inline__ +#endif /* mig_internal */ + +#ifndef mig_external +#define mig_external +#endif /* mig_external */ + +#if !defined(__MigTypeCheck) && defined(TypeCheck) +#define __MigTypeCheck TypeCheck /* Legacy setting */ +#endif /* !defined(__MigTypeCheck) */ + +#if !defined(__MigKernelSpecificCode) && defined(_MIG_KERNEL_SPECIFIC_CODE_) +#define __MigKernelSpecificCode _MIG_KERNEL_SPECIFIC_CODE_ /* Legacy setting */ +#endif /* !defined(__MigKernelSpecificCode) */ + +#ifndef LimitCheck +#define LimitCheck 0 +#endif /* LimitCheck */ + +#ifndef min +#define min(a,b) ( ((a) < (b))? (a): (b) ) +#endif /* min */ + +#if !defined(_WALIGN_) +#define _WALIGN_(x) (((x) + 3) & ~3) +#endif /* !defined(_WALIGN_) */ + +#if !defined(_WALIGNSZ_) +#define _WALIGNSZ_(x) _WALIGN_(sizeof(x)) +#endif /* !defined(_WALIGNSZ_) */ + +#ifndef UseStaticTemplates +#define UseStaticTemplates 0 +#endif /* UseStaticTemplates */ + +#ifndef MIG_SERVER_ROUTINE +#define MIG_SERVER_ROUTINE +#endif + +#ifndef __DeclareRcvRpc +#define __DeclareRcvRpc(_NUM_, _NAME_) +#endif /* __DeclareRcvRpc */ + +#ifndef __BeforeRcvRpc +#define __BeforeRcvRpc(_NUM_, _NAME_) +#endif /* __BeforeRcvRpc */ + +#ifndef __AfterRcvRpc +#define __AfterRcvRpc(_NUM_, _NAME_) +#endif /* __AfterRcvRpc */ + +#ifndef __DeclareRcvSimple +#define __DeclareRcvSimple(_NUM_, _NAME_) +#endif /* __DeclareRcvSimple */ + +#ifndef __BeforeRcvSimple +#define __BeforeRcvSimple(_NUM_, _NAME_) +#endif /* __BeforeRcvSimple */ + +#ifndef __AfterRcvSimple +#define __AfterRcvSimple(_NUM_, _NAME_) +#endif /* __AfterRcvSimple */ + +#define novalue void + +#define msgh_request_port msgh_local_port +#define MACH_MSGH_BITS_REQUEST(bits) MACH_MSGH_BITS_LOCAL(bits) +#define msgh_reply_port msgh_remote_port +#define MACH_MSGH_BITS_REPLY(bits) MACH_MSGH_BITS_REMOTE(bits) + +#define MIG_RETURN_ERROR(X, code) {\ + ((mig_reply_error_t *)X)->RetCode = code;\ + ((mig_reply_error_t *)X)->NDR = NDR_record;\ + return;\ + } + +/* typedefs for all requests */ + +#ifndef __Request__mach_exc_subsystem__defined +#define __Request__mach_exc_subsystem__defined + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + } __Request__mach_exception_raise_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[614]; + } __Request__mach_exception_raise_state_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[614]; + } __Request__mach_exception_raise_state_identity_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif +#endif /* !__Request__mach_exc_subsystem__defined */ + +/* typedefs for all replies */ + +#ifndef __Reply__mach_exc_subsystem__defined +#define __Reply__mach_exc_subsystem__defined + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + } __Reply__mach_exception_raise_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[614]; + } __Reply__mach_exception_raise_state_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[614]; + } __Reply__mach_exception_raise_state_identity_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif +#endif /* !__Reply__mach_exc_subsystem__defined */ + + +/* union of all replies */ + +#ifndef __ReplyUnion__catch_mach_exc_subsystem__defined +#define __ReplyUnion__catch_mach_exc_subsystem__defined +union __ReplyUnion__catch_mach_exc_subsystem { + __Reply__mach_exception_raise_t Reply_mach_exception_raise; + __Reply__mach_exception_raise_state_t Reply_mach_exception_raise_state; + __Reply__mach_exception_raise_state_identity_t Reply_mach_exception_raise_state_identity; +}; +#endif /* __ReplyUnion__catch_mach_exc_subsystem__defined */ +/* Forward Declarations */ + + +mig_internal novalue _Xmach_exception_raise + (mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP); + +mig_internal novalue _Xmach_exception_raise_state + (mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP); + +mig_internal novalue _Xmach_exception_raise_state_identity + (mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP); + + +#if ( __MigTypeCheck ) +#if __MIG_check__Request__mach_exc_subsystem__ +#if !defined(__MIG_check__Request__mach_exception_raise_t__defined) +#define __MIG_check__Request__mach_exception_raise_t__defined + +mig_internal kern_return_t __MIG_check__Request__mach_exception_raise_t(__attribute__((__unused__)) __Request__mach_exception_raise_t *In0P) +{ + + typedef __Request__mach_exception_raise_t __Request; +#if __MigTypeCheck + unsigned int msgh_size; +#endif /* __MigTypeCheck */ + +#if __MigTypeCheck + msgh_size = In0P->Head.msgh_size; + if (!(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) || + (In0P->msgh_body.msgh_descriptor_count != 2) || + (msgh_size < (mach_msg_size_t)(sizeof(__Request) - 16)) || (msgh_size > (mach_msg_size_t)sizeof(__Request))) + return MIG_BAD_ARGUMENTS; +#endif /* __MigTypeCheck */ + +#if __MigTypeCheck + if (In0P->thread.type != MACH_MSG_PORT_DESCRIPTOR || + In0P->thread.disposition != 17) + return MIG_TYPE_ERROR; +#endif /* __MigTypeCheck */ + +#if __MigTypeCheck + if (In0P->task.type != MACH_MSG_PORT_DESCRIPTOR || + In0P->task.disposition != 17) + return MIG_TYPE_ERROR; +#endif /* __MigTypeCheck */ + +#if defined(__NDR_convert__int_rep__Request__mach_exception_raise_t__codeCnt__defined) + if (In0P->NDR.int_rep != NDR_record.int_rep) + __NDR_convert__int_rep__Request__mach_exception_raise_t__codeCnt(&In0P->codeCnt, In0P->NDR.int_rep); +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_t__codeCnt__defined */ +#if __MigTypeCheck + if ( In0P->codeCnt > 2 ) + return MIG_BAD_ARGUMENTS; + if (((msgh_size - (mach_msg_size_t)(sizeof(__Request) - 16)) / 8 < In0P->codeCnt) || + (msgh_size != (mach_msg_size_t)(sizeof(__Request) - 16) + (8 * In0P->codeCnt))) + return MIG_BAD_ARGUMENTS; +#endif /* __MigTypeCheck */ + + return MACH_MSG_SUCCESS; +} +#endif /* !defined(__MIG_check__Request__mach_exception_raise_t__defined) */ +#endif /* __MIG_check__Request__mach_exc_subsystem__ */ +#endif /* ( __MigTypeCheck ) */ + + +/* Routine mach_exception_raise */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +MIG_SERVER_ROUTINE +kern_return_t catch_mach_exception_raise +( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t codeCnt, + injector_t *injector +); + +/* Routine mach_exception_raise */ +mig_internal novalue _Xmach_exception_raise + (mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP) +{ + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + mach_msg_trailer_t trailer; + } Request __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif + typedef __Request__mach_exception_raise_t __Request; + typedef __Reply__mach_exception_raise_t Reply __attribute__((unused)); + + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + Request *In0P = (Request *) InHeadP; + Reply *OutP = (Reply *) OutHeadP; +#ifdef __MIG_check__Request__mach_exception_raise_t__defined + kern_return_t check_result; +#endif /* __MIG_check__Request__mach_exception_raise_t__defined */ + + __DeclareRcvRpc(2405, "mach_exception_raise") + __BeforeRcvRpc(2405, "mach_exception_raise") + +#if defined(__MIG_check__Request__mach_exception_raise_t__defined) + check_result = __MIG_check__Request__mach_exception_raise_t((__Request *)In0P); + if (check_result != MACH_MSG_SUCCESS) + { MIG_RETURN_ERROR(OutP, check_result); } +#endif /* defined(__MIG_check__Request__mach_exception_raise_t__defined) */ + mach_msg_header_with_injector *mmhwi = (mach_msg_header_with_injector*)In0P; + OutP->RetCode = catch_mach_exception_raise(In0P->Head.msgh_request_port, In0P->thread.name, In0P->task.name, In0P->exception, In0P->code, In0P->codeCnt, mmhwi->injector); + + OutP->NDR = NDR_record; + + + __AfterRcvRpc(2405, "mach_exception_raise") +} + +#if ( __MigTypeCheck ) +#if __MIG_check__Request__mach_exc_subsystem__ +#if !defined(__MIG_check__Request__mach_exception_raise_state_t__defined) +#define __MIG_check__Request__mach_exception_raise_state_t__defined + +mig_internal kern_return_t __MIG_check__Request__mach_exception_raise_state_t(__attribute__((__unused__)) __Request__mach_exception_raise_state_t *In0P, __attribute__((__unused__)) __Request__mach_exception_raise_state_t **In1PP) +{ + + typedef __Request__mach_exception_raise_state_t __Request; + __Request *In1P; +#if __MigTypeCheck + unsigned int msgh_size; +#endif /* __MigTypeCheck */ + unsigned int msgh_size_delta; + +#if __MigTypeCheck + msgh_size = In0P->Head.msgh_size; + if ((In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) || + (msgh_size < (mach_msg_size_t)(sizeof(__Request) - 2472)) || (msgh_size > (mach_msg_size_t)sizeof(__Request))) + return MIG_BAD_ARGUMENTS; +#endif /* __MigTypeCheck */ + +#if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_t__codeCnt__defined) + if (In0P->NDR.int_rep != NDR_record.int_rep) + __NDR_convert__int_rep__Request__mach_exception_raise_state_t__codeCnt(&In0P->codeCnt, In0P->NDR.int_rep); +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_t__codeCnt__defined */ + msgh_size_delta = (8 * In0P->codeCnt); +#if __MigTypeCheck + if ( In0P->codeCnt > 2 ) + return MIG_BAD_ARGUMENTS; + if (((msgh_size - (mach_msg_size_t)(sizeof(__Request) - 2472)) / 8 < In0P->codeCnt) || + (msgh_size < (mach_msg_size_t)(sizeof(__Request) - 2472) + (8 * In0P->codeCnt))) + return MIG_BAD_ARGUMENTS; + msgh_size -= msgh_size_delta; +#endif /* __MigTypeCheck */ + + *In1PP = In1P = (__Request *) ((pointer_t) In0P + msgh_size_delta - 16); + +#if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_stateCnt__defined) + if (In0P->NDR.int_rep != NDR_record.int_rep) + __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_stateCnt(&In1P->old_stateCnt, In1P->NDR.int_rep); +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_stateCnt__defined */ +#if __MigTypeCheck + if ( In1P->old_stateCnt > 614 ) + return MIG_BAD_ARGUMENTS; + if (((msgh_size - (mach_msg_size_t)(sizeof(__Request) - 2472)) / 4 < In1P->old_stateCnt) || + (msgh_size != (mach_msg_size_t)(sizeof(__Request) - 2472) + (4 * In1P->old_stateCnt))) + return MIG_BAD_ARGUMENTS; +#endif /* __MigTypeCheck */ + + return MACH_MSG_SUCCESS; +} +#endif /* !defined(__MIG_check__Request__mach_exception_raise_state_t__defined) */ +#endif /* __MIG_check__Request__mach_exc_subsystem__ */ +#endif /* ( __MigTypeCheck ) */ + + +/* Routine mach_exception_raise_state */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +MIG_SERVER_ROUTINE +kern_return_t catch_mach_exception_raise_state +( + mach_port_t exception_port, + exception_type_t exception, + const mach_exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + const thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt +); + +/* Routine mach_exception_raise_state */ +mig_internal novalue _Xmach_exception_raise_state + (mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP) +{ + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[614]; + mach_msg_trailer_t trailer; + } Request __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif + typedef __Request__mach_exception_raise_state_t __Request; + typedef __Reply__mach_exception_raise_state_t Reply __attribute__((unused)); + + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + Request *In0P = (Request *) InHeadP; + Request *In1P; + Reply *OutP = (Reply *) OutHeadP; +#ifdef __MIG_check__Request__mach_exception_raise_state_t__defined + kern_return_t check_result; +#endif /* __MIG_check__Request__mach_exception_raise_state_t__defined */ + + __DeclareRcvRpc(2406, "mach_exception_raise_state") + __BeforeRcvRpc(2406, "mach_exception_raise_state") + +#if defined(__MIG_check__Request__mach_exception_raise_state_t__defined) + check_result = __MIG_check__Request__mach_exception_raise_state_t((__Request *)In0P, (__Request **)&In1P); + if (check_result != MACH_MSG_SUCCESS) + { MIG_RETURN_ERROR(OutP, check_result); } +#endif /* defined(__MIG_check__Request__mach_exception_raise_state_t__defined) */ + + OutP->new_stateCnt = 614; + + OutP->RetCode = catch_mach_exception_raise_state(In0P->Head.msgh_request_port, In0P->exception, In0P->code, In0P->codeCnt, &In1P->flavor, In1P->old_state, In1P->old_stateCnt, OutP->new_state, &OutP->new_stateCnt); + if (OutP->RetCode != KERN_SUCCESS) { + MIG_RETURN_ERROR(OutP, OutP->RetCode); + } + + OutP->NDR = NDR_record; + + + OutP->flavor = In1P->flavor; + OutP->Head.msgh_size = (mach_msg_size_t)(sizeof(Reply) - 2456) + (((4 * OutP->new_stateCnt))); + + __AfterRcvRpc(2406, "mach_exception_raise_state") +} + +#if ( __MigTypeCheck ) +#if __MIG_check__Request__mach_exc_subsystem__ +#if !defined(__MIG_check__Request__mach_exception_raise_state_identity_t__defined) +#define __MIG_check__Request__mach_exception_raise_state_identity_t__defined + +mig_internal kern_return_t __MIG_check__Request__mach_exception_raise_state_identity_t(__attribute__((__unused__)) __Request__mach_exception_raise_state_identity_t *In0P, __attribute__((__unused__)) __Request__mach_exception_raise_state_identity_t **In1PP) +{ + + typedef __Request__mach_exception_raise_state_identity_t __Request; + __Request *In1P; +#if __MigTypeCheck + unsigned int msgh_size; +#endif /* __MigTypeCheck */ + unsigned int msgh_size_delta; + +#if __MigTypeCheck + msgh_size = In0P->Head.msgh_size; + if (!(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) || + (In0P->msgh_body.msgh_descriptor_count != 2) || + (msgh_size < (mach_msg_size_t)(sizeof(__Request) - 2472)) || (msgh_size > (mach_msg_size_t)sizeof(__Request))) + return MIG_BAD_ARGUMENTS; +#endif /* __MigTypeCheck */ + +#if __MigTypeCheck + if (In0P->thread.type != MACH_MSG_PORT_DESCRIPTOR || + In0P->thread.disposition != 17) + return MIG_TYPE_ERROR; +#endif /* __MigTypeCheck */ + +#if __MigTypeCheck + if (In0P->task.type != MACH_MSG_PORT_DESCRIPTOR || + In0P->task.disposition != 17) + return MIG_TYPE_ERROR; +#endif /* __MigTypeCheck */ + +#if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__codeCnt__defined) + if (In0P->NDR.int_rep != NDR_record.int_rep) + __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__codeCnt(&In0P->codeCnt, In0P->NDR.int_rep); +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__codeCnt__defined */ + msgh_size_delta = (8 * In0P->codeCnt); +#if __MigTypeCheck + if ( In0P->codeCnt > 2 ) + return MIG_BAD_ARGUMENTS; + if (((msgh_size - (mach_msg_size_t)(sizeof(__Request) - 2472)) / 8 < In0P->codeCnt) || + (msgh_size < (mach_msg_size_t)(sizeof(__Request) - 2472) + (8 * In0P->codeCnt))) + return MIG_BAD_ARGUMENTS; + msgh_size -= msgh_size_delta; +#endif /* __MigTypeCheck */ + + *In1PP = In1P = (__Request *) ((pointer_t) In0P + msgh_size_delta - 16); + +#if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_stateCnt__defined) + if (In0P->NDR.int_rep != NDR_record.int_rep) + __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_stateCnt(&In1P->old_stateCnt, In1P->NDR.int_rep); +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_stateCnt__defined */ +#if __MigTypeCheck + if ( In1P->old_stateCnt > 614 ) + return MIG_BAD_ARGUMENTS; + if (((msgh_size - (mach_msg_size_t)(sizeof(__Request) - 2472)) / 4 < In1P->old_stateCnt) || + (msgh_size != (mach_msg_size_t)(sizeof(__Request) - 2472) + (4 * In1P->old_stateCnt))) + return MIG_BAD_ARGUMENTS; +#endif /* __MigTypeCheck */ + + return MACH_MSG_SUCCESS; +} +#endif /* !defined(__MIG_check__Request__mach_exception_raise_state_identity_t__defined) */ +#endif /* __MIG_check__Request__mach_exc_subsystem__ */ +#endif /* ( __MigTypeCheck ) */ + + +/* Routine mach_exception_raise_state_identity */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +MIG_SERVER_ROUTINE +kern_return_t catch_mach_exception_raise_state_identity +( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt +); + +/* Routine mach_exception_raise_state_identity */ +mig_internal novalue _Xmach_exception_raise_state_identity + (mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP) +{ + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[614]; + mach_msg_trailer_t trailer; + } Request __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif + typedef __Request__mach_exception_raise_state_identity_t __Request; + typedef __Reply__mach_exception_raise_state_identity_t Reply __attribute__((unused)); + + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + Request *In0P = (Request *) InHeadP; + Request *In1P; + Reply *OutP = (Reply *) OutHeadP; +#ifdef __MIG_check__Request__mach_exception_raise_state_identity_t__defined + kern_return_t check_result; +#endif /* __MIG_check__Request__mach_exception_raise_state_identity_t__defined */ + + __DeclareRcvRpc(2407, "mach_exception_raise_state_identity") + __BeforeRcvRpc(2407, "mach_exception_raise_state_identity") + +#if defined(__MIG_check__Request__mach_exception_raise_state_identity_t__defined) + check_result = __MIG_check__Request__mach_exception_raise_state_identity_t((__Request *)In0P, (__Request **)&In1P); + if (check_result != MACH_MSG_SUCCESS) + { MIG_RETURN_ERROR(OutP, check_result); } +#endif /* defined(__MIG_check__Request__mach_exception_raise_state_identity_t__defined) */ + + OutP->new_stateCnt = 614; + + OutP->RetCode = catch_mach_exception_raise_state_identity(In0P->Head.msgh_request_port, In0P->thread.name, In0P->task.name, In0P->exception, In0P->code, In0P->codeCnt, &In1P->flavor, In1P->old_state, In1P->old_stateCnt, OutP->new_state, &OutP->new_stateCnt); + if (OutP->RetCode != KERN_SUCCESS) { + MIG_RETURN_ERROR(OutP, OutP->RetCode); + } + + OutP->NDR = NDR_record; + + + OutP->flavor = In1P->flavor; + OutP->Head.msgh_size = (mach_msg_size_t)(sizeof(Reply) - 2456) + (((4 * OutP->new_stateCnt))); + + __AfterRcvRpc(2407, "mach_exception_raise_state_identity") +} + + +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +boolean_t mach_exc_server( + mach_msg_header_t *InHeadP, + mach_msg_header_t *OutHeadP); + +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +mig_routine_t mach_exc_server_routine( + mach_msg_header_t *InHeadP); + + +/* Description of this subsystem, for use in direct RPC */ +const struct catch_mach_exc_subsystem { + mig_server_routine_t server; /* Server routine */ + mach_msg_id_t start; /* Min routine number */ + mach_msg_id_t end; /* Max routine number + 1 */ + unsigned int maxsize; /* Max msg size */ + vm_address_t reserved; /* Reserved */ + struct routine_descriptor /*Array of routine descriptors */ + routine[3]; +} catch_mach_exc_subsystem = { + mach_exc_server_routine, + 2405, + 2408, + (mach_msg_size_t)sizeof(union __ReplyUnion__catch_mach_exc_subsystem), + (vm_address_t)0, + { + { (mig_impl_routine_t) 0, + (mig_stub_routine_t) _Xmach_exception_raise, 6, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__mach_exception_raise_t)}, + { (mig_impl_routine_t) 0, + (mig_stub_routine_t) _Xmach_exception_raise_state, 9, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__mach_exception_raise_state_t)}, + { (mig_impl_routine_t) 0, + (mig_stub_routine_t) _Xmach_exception_raise_state_identity, 11, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__mach_exception_raise_state_identity_t)}, + } +}; + +mig_external boolean_t mach_exc_server + (mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP) +{ + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + mig_routine_t routine; + + OutHeadP->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InHeadP->msgh_bits), 0); + OutHeadP->msgh_remote_port = InHeadP->msgh_reply_port; + /* Minimal size: routine() will update it if different */ + OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t); + OutHeadP->msgh_local_port = MACH_PORT_NULL; + OutHeadP->msgh_id = InHeadP->msgh_id + 100; + OutHeadP->msgh_reserved = 0; + + if ((InHeadP->msgh_id > 2407) || (InHeadP->msgh_id < 2405) || + ((routine = catch_mach_exc_subsystem.routine[InHeadP->msgh_id - 2405].stub_routine) == 0)) { + ((mig_reply_error_t *)OutHeadP)->NDR = NDR_record; + ((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID; + return FALSE; + } + (*routine) (InHeadP, OutHeadP); + return TRUE; +} + +mig_external mig_routine_t mach_exc_server_routine + (mach_msg_header_t *InHeadP) +{ + int msgh_id; + + msgh_id = InHeadP->msgh_id - 2405; + + if ((msgh_id > 2) || (msgh_id < 0)) + return 0; + + return catch_mach_exc_subsystem.routine[msgh_id].stub_routine; +} diff --git a/RemoteInput/Thirdparty/kubo_injector/src/macos/ptrace.c b/RemoteInput/Thirdparty/kubo_injector/src/macos/ptrace.c new file mode 100644 index 0000000..52e4888 --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/src/macos/ptrace.c @@ -0,0 +1,81 @@ +/* -*- indent-tabs-mode: nil -*- + * + * injector - Library for injecting a shared library into a Linux process + * + * URL: https://github.com/kubo/injector + * + * ------------------------------------------------------ + * + * Copyright (C) 2022 TheOiseth + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "injector_internal.h" +#include +#include +#include +#include +#define PTRACE_OR_RETURN(request, injector, addr, data) do { \ + int rv = injector__ptrace(request, injector->pid, addr, data, #request); \ + if (rv != 0) { \ + return rv; \ + } \ +} while (0) +static int set_ptrace_error(const char *request_name) +{ + int err = errno; + injector__set_errmsg("%s error : %s", request_name, strerror(errno)); + switch (err) { + case EFAULT: + return INJERR_INVALID_MEMORY_AREA; + case EPERM: + return INJERR_PERMISSION; + case ESRCH: + return INJERR_NO_PROCESS; + } + return INJERR_OTHER; +} + +int injector__ptrace(int request, pid_t pid, long addr, long data, const char *request_name) +{ + if (ptrace(request, pid, (caddr_t)addr, data) != 0) { + return set_ptrace_error(request_name); + } + return 0; +} + +int injector__ptrace_attach(const injector_t *injector) +{ + PTRACE_OR_RETURN(PT_ATTACHEXC, injector, 0, 0); + return 0; +} + +int injector__ptrace_detach(const injector_t *injector) +{ + PTRACE_OR_RETURN(PT_DETACH, injector, 0, 0); + return 0; +} + +int injector__ptrace_continue(const injector_t *injector) +{ + PTRACE_OR_RETURN(PT_CONTINUE, injector, 1, 0); + return 0; +} + +int injector__ptrace_update(const injector_t *injector, long thread_port) +{ + PTRACE_OR_RETURN(PT_THUPDATE, injector, thread_port, 0); + return 0; +} \ No newline at end of file diff --git a/RemoteInput/Thirdparty/kubo_injector/src/macos/remote_call.c b/RemoteInput/Thirdparty/kubo_injector/src/macos/remote_call.c new file mode 100644 index 0000000..f37072e --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/src/macos/remote_call.c @@ -0,0 +1,228 @@ +/* -*- indent-tabs-mode: nil -*- + * + * injector - Library for injecting a shared library into a Linux process + * + * URL: https://github.com/kubo/injector + * + * ------------------------------------------------------ + * + * Copyright (C) 2022 TheOiseth + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "injector_internal.h" +#include "mach_exc.h" +#include +#include +#include +#include +#include +#include + +//Before change shellcode, see: +//injector.c -> injector_detach +//exc_handler.c -> catch_mach_exception_raise +#if defined(__arm64__) || defined(__aarch64__) +char* shellcode = + "\x00\x01\x3f\xd6" //blr x8 + "\x00\x00\x00\x14" //b //infinity loop, we will terminate this thread later + + //second thread + "\x00\x00\x20\xd4" //brk 0 + "\x00\x01\x3f\xd6" //blr x8 + "\x00\x00\x20\xd4" //brk 0 + "\xc0\x03\x5f\xd6" //ret +; +int shellcode1_len = 8; +int shellcode_length = 24; +#else + +char* shellcode = + //"\x55" //push rbp + //"\x48\x89\xE5" //mov rbp, rsp + //"\x48\x83\xEC\x10" //sub rsp, 0x10 + //"\x48\x8D\x7D\xF8" //lea rdi, [rbp - 8] + "\x90" //nop + "\x90" //nop + "\x90" //nop + "\xFF\xD0" //call rax + //"\x48\x83\xC4\x10" //add rsp, 0x10 + //"\x5D" //pop rbp + "\xeb\xfe" //jmp 0 //infinity loop, we will terminate this thread later + + //second thread + "\xcc" //int3 + //"\x55" //push rbp + //"\x48\x89\xe5" //mov rbp, rsp + "\xff\xd0" //call rax + //"\x5D" //pop rbp + "\xcc" //int3 + "\xc3" //ret +; +int shellcode1_len = 7; +int shellcode_length = 12; +#endif +int injector__call_function(injector_t *injector, long *retval, long function_addr, ...) +{ + va_list ap; + va_start(ap, function_addr); + long arg1, arg2, arg3, arg4, arg5, arg6; + arg1 = va_arg(ap, long); + arg2 = va_arg(ap, long); + arg3 = va_arg(ap, long); + arg4 = va_arg(ap, long); + arg5 = va_arg(ap, long); + arg6 = va_arg(ap, long); + va_end(ap); + int rv; + + if(injector->shellcode_writed == 0){ + pcfmt_t pcfmt = (pcfmt_t)dlsym(RTLD_DEFAULT, "pthread_create_from_mach_thread"); + + + rv = injector__write(injector, injector->code_addr, shellcode, shellcode_length); + if(rv != 0){ + return rv; + } + if(pcfmt == 0){ + //char* legacy_append = + //"\xFF\xD0" //call rax + //"\xcc" //int3 + //; + //rv = injector__write(injector, injector->code_addr, legacy_append, 3); + + //It turns out that we can call pthread_create in mach thread without _pthread_set_self on MacOS < 10.12 + pcfmt = (pcfmt_t)dlsym(RTLD_DEFAULT, "pthread_create"); + } + rv = injector__protect(injector, injector->code_addr, injector->code_size, FALSE, VM_PROT_READ | VM_PROT_EXECUTE); + if (rv != 0) { + return rv; + } + injector->shellcode_writed = 1; + injector->code2_addr = injector->code_addr + shellcode1_len; + + thread_act_t mach_thread; +#if defined(__arm64__) || defined(__aarch64__) + arm_thread_state64_t state; + memset(&state, '\0', sizeof(state)); + state.__pc = injector->code_addr; + state.__sp = injector->stack; + state.__x[8] = (uint64_t)pcfmt; + state.__x[0] = injector->stack - 32; + + state.__x[1] = 0; + state.__x[2] = injector->code2_addr; + state.__x[3] = 0; + rv = thread_create_running(injector->remote_task, ARM_THREAD_STATE64, (thread_state_t)&state, ARM_THREAD_STATE64_COUNT , &mach_thread); +#else + x86_thread_state64_t state; + memset(&state, '\0', sizeof(state)); + state.__rip = injector->code_addr; + state.__rsp = injector->stack - 0x10; + state.__rbp = injector->stack; + if(pcfmt == NULL){ + state.__rax = (uint64_t)dlsym(RTLD_DEFAULT, "_pthread_set_self"); + state.__rdi = 0; + injector->func_addr = (uint64_t)dlsym(RTLD_DEFAULT, "pthread_create"); + injector->arg1 = injector->stack - 0x8; + injector->arg2 = 0; + injector->arg3 = injector->code2_addr; + injector->arg4 = 0; + } else { + state.__rax = (uint64_t)pcfmt; + state.__rdi = injector->stack - 0x8;//&thread + } + + state.__rsi = 0; + state.__rdx = injector->code2_addr; + state.__rcx = 0; + + rv = thread_create_running(injector->remote_task, x86_THREAD_STATE64, (thread_state_t)&state, x86_THREAD_STATE64_COUNT, &mach_thread); +#endif + if(rv != 0){ + injector__set_errmsg("%s error : %s", "CREATE_THREAD", mach_error_string(rv)); + return INJERR_ERROR_IN_TARGET; + } + injector->mach_thread = mach_thread; + if(pcfmt == NULL){ + injector->handle_action = TRAP_SETREGS; + injector__handle_exc(injector); + } + injector->func_addr = function_addr; + injector->arg1 = arg1; + injector->arg2 = arg2; + injector->arg3 = arg3; + injector->arg4 = arg4; + injector->arg5 = arg5; + injector->arg6 = arg6; + + injector->handle_action = TRAP_SETREGS; + injector__handle_exc(injector); + } else { +#if defined(__arm64__) || defined(__aarch64__) + + mach_msg_type_number_t state_count = ARM_THREAD_STATE64_COUNT; + arm_thread_state64_t state; + rv = thread_get_state(injector->remote_thread, ARM_THREAD_STATE64, (thread_state_t)&state, &state_count); + if(rv != 0){ + injector__set_errmsg("%s error : %s", "THREAD_GET_STATE", mach_error_string(rv)); + return INJERR_ERROR_IN_TARGET; + } + state.__pc = injector->code2_addr + 4; + state.__x[0] = arg1; + state.__x[1] = arg2; + state.__x[2] = arg3; + state.__x[3] = arg4; + state.__x[4] = arg5; + state.__x[5] = arg6; + state.__x[8] = function_addr; + rv = thread_set_state(injector->remote_thread, ARM_THREAD_STATE64, (thread_state_t)&state, ARM_THREAD_STATE64_COUNT); +#else + mach_msg_type_number_t state_count = x86_THREAD_STATE64_COUNT; + x86_thread_state64_t state; + rv = thread_get_state(injector->remote_thread, x86_THREAD_STATE64, (thread_state_t)&state, &state_count); + if(rv != 0){ + injector__set_errmsg("%s error : %s", "THREAD_GET_STATE", mach_error_string(rv)); + return INJERR_ERROR_IN_TARGET; + } + state.__rip = injector->code2_addr + 1; + state.__rax = function_addr; + state.__rdi = arg1; + state.__rsi = arg2; + state.__rdx = arg3; + state.__rcx = arg4; + state.__r8 = arg5; + state.__r9 = arg6; + rv = thread_set_state(injector->remote_thread, x86_THREAD_STATE64, (thread_state_t)&state, x86_THREAD_STATE64_COUNT); +#endif + if(rv != 0){ + injector__set_errmsg("%s error : %s", "THREAD_SET_STATE", mach_error_string(rv)); + return INJERR_ERROR_IN_TARGET; + } + rv = thread_resume(injector->remote_thread); + if(rv != 0){ + injector__set_errmsg("%s error : %s", "THREAD_RESUME", mach_error_string(rv)); + return INJERR_ERROR_IN_TARGET; + } + } + + injector->handle_action = TRAP_GETREGS; + injector__handle_exc(injector); + if(injector->handle_err != 0){ + return injector->handle_err; + } + *retval = injector->retval; + return 0; +} diff --git a/RemoteInput/Thirdparty/kubo_injector/src/macos/util.c b/RemoteInput/Thirdparty/kubo_injector/src/macos/util.c new file mode 100644 index 0000000..afa3cea --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/src/macos/util.c @@ -0,0 +1,155 @@ +/* -*- indent-tabs-mode: nil -*- + * + * injector - Library for injecting a shared library into a Linux process + * + * URL: https://github.com/kubo/injector + * + * ------------------------------------------------------ + * + * Copyright (C) 2022 TheOiseth + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "injector_internal.h" +#include +#include +#include +#include +#include +#include + + +char injector__errmsg[512]; +char injector__errmsg_is_set; + +void injector__set_errmsg(const char *format, ...) +{ + va_list ap; + int rv; + + /* prevent the error message from being overwritten. */ + if (injector__errmsg_is_set) { + return; + } + injector__errmsg_is_set = 1; + + va_start(ap, format); + rv = vsnprintf(injector__errmsg, sizeof(injector__errmsg), format, ap); + va_end(ap); + if (rv == -1 || rv >= sizeof(injector__errmsg)) { + injector__errmsg[sizeof(injector__errmsg) - 1] = '\0'; + } +} +#ifndef P_TRANSLATED +#define P_TRANSLATED 0x00020000 +#endif +int injector__get_process_arch(pid_t pid, arch_t *arch){ + int mib[CTL_MAXNAME] = {0}; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = pid; + size_t length = 4; + struct kinfo_proc proc_info = {0}; + size_t size = sizeof(proc_info); + + if(sysctl(mib, (u_int)length, &proc_info, &size, NULL, 0) != 0) { + *arch = ARCH_UNKNOWN; + return INJERR_SUCCESS; + } + if (size == 0) { + injector__set_errmsg("Process %d not found", pid); + return INJERR_NO_PROCESS; + } + + if(P_TRANSLATED == (P_TRANSLATED & proc_info.kp_proc.p_flag)){ + if(P_LP64 == (P_LP64 & proc_info.kp_proc.p_flag)){ + *arch = ARCH_X86_64; + return INJERR_SUCCESS; + } else { + *arch = ARCH_I386; + return INJERR_SUCCESS; + } + } else { + arch_t sys_arch = injector__get_system_arch(); + if(sys_arch == ARCH_ARM64){ + *arch = ARCH_ARM64; + return INJERR_SUCCESS; + } +#if defined(__arm64__) || defined(__aarch64__) + if(sys_arch == ARCH_UNKNOWN){ + *arch = ARCH_ARM64; + return INJERR_SUCCESS; + } +#endif + } + + if(P_LP64 == (P_LP64 & proc_info.kp_proc.p_flag)){ + *arch = ARCH_X86_64; + return INJERR_SUCCESS; + } + *arch = ARCH_I386; + return INJERR_SUCCESS; +} + +#ifndef CPU_TYPE_ARM64 +#define CPU_TYPE_ARM ((cpu_type_t) 12) +#define CPU_ARCH_ABI64 0x01000000 +#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) +#endif +arch_t injector__get_system_arch(){ + size_t size; + cpu_type_t type = -1; + int mib[CTL_MAXNAME] = {0}; + size_t length = CTL_MAXNAME; + + if (sysctlnametomib("sysctl.proc_cputype", mib, &length) != 0){ + return ARCH_UNKNOWN; + } + + mib[length] = getpid(); + length++; + size = sizeof(cpu_type_t); + + if (sysctl(mib, (u_int)length, &type, &size, 0, 0) != 0){ + return ARCH_UNKNOWN; + } + if (CPU_TYPE_X86_64 == type) { + return ARCH_X86_64; + } + + if (CPU_TYPE_ARM64 == type) { + return ARCH_ARM64; + } + return ARCH_UNKNOWN; +} +const char *injector__arch2name(arch_t arch) +{ + switch (arch) { + case ARCH_X86_64: + return "x86_64"; + case ARCH_I386: + return "i386"; + case ARCH_ARM64: + return "ARM64"; + case ARCH_POWERPC_64: + return "PowerPC 64-bit"; + case ARCH_POWERPC: + return "PowerPC"; + case ARCH_UNKNOWN: + return "Unknown"; + } + return "?"; +} \ No newline at end of file diff --git a/RemoteInput/Thirdparty/kubo_injector/src/windows/injector.c b/RemoteInput/Thirdparty/kubo_injector/src/windows/injector.c new file mode 100644 index 0000000..6854107 --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/src/windows/injector.c @@ -0,0 +1,859 @@ +/* -*- indent-tabs-mode: nil -*- + * + * injector - Library for injecting a shared library into a Linux process + * + * URL: https://github.com/kubo/injector + * + * ------------------------------------------------------ + * + * Copyright (C) 2018-2023 Kubo Takehiro + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0602 +#endif +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include "injector.h" + +#if !defined(WDK_NTDDI_VERSION) || WDK_NTDDI_VERSION < 0x0A00000B +// Windows SDK version < 10.0.22000.0 +#define ProcessMachineTypeInfo 9 +typedef enum _MACHINE_ATTRIBUTES { + UserEnabled = 0x00000001, + KernelEnabled = 0x00000002, + Wow64Container = 0x00000004 +} MACHINE_ATTRIBUTES; +typedef struct _PROCESS_MACHINE_INFORMATION { + USHORT ProcessMachine; + USHORT Res0; + MACHINE_ATTRIBUTES MachineAttributes; +} PROCESS_MACHINE_INFORMATION; +#endif + +#pragma comment(lib, "advapi32.lib") +#pragma comment(lib, "dbghelp.lib") +#if !defined(PSAPI_VERSION) || PSAPI_VERSION == 1 +#pragma comment(lib, "psapi.lib") +#endif + +typedef BOOL (WINAPI *IsWow64Process2_t)(HANDLE hProcess, USHORT *pProcessMachine, USHORT *pNativeMachine); +typedef BOOL (WINAPI *GetProcessInformation_t)(HANDLE hProcess, PROCESS_INFORMATION_CLASS ProcessInformationClass, LPVOID ProcessInformation, DWORD ProcessInformationSize); + +static DWORD page_size = 0; +static size_t func_LoadLibraryW; +static size_t func_FreeLibrary; +static size_t func_GetLastError; +static size_t func_GetProcAddress; +static char errmsg[512]; + +typedef struct { + uint64_t func; + uint64_t arg1; + uint64_t arg2; + uint64_t arg3; + uint64_t arg4; + uint64_t arg5; + uint64_t arg6; +} remote_call_args_t; + +// size_t remote_call(remote_call_args_t *args) +// { +// size_t rv = args->func(args->arg1, args->arg2, args->arg3, args->arg4, args->arg5, args->arg6); +// *(DWORD*)args = GetLastError(); +// return rv; +// } +static const char x64_code_template[] = + + /* 0000: */ "\x40\x53" // push rbx + /* 0002: */ "\x48\x8B\xD9" // mov rbx,rcx ; preserve the first argument + /* 0005: */ "\x48\x83\xEC\x30" // sub rsp,30h ; align the stack pointer + /* 0009: */ "\x48\x8B\x41\x30" // mov rax,qword ptr [rcx+30h] ; set the 6th argument + /* 000D: */ "\x48\x89\x44\x24\x28" // mov qword ptr [rsp+28h],rax ; ditto + /* 0012: */ "\x48\x8B\x41\x28" // mov rax,qword ptr [rcx+28h] ; set the 5th argument + /* 0016: */ "\x48\x89\x44\x24\x20" // mov qword ptr [rsp+20h],rax ; ditto + /* 001B: */ "\x4C\x8B\x49\x20" // mov r9,qword ptr [rcx+20h] ; set the 4th argument + /* 001F: */ "\x4C\x8B\x41\x18" // mov r8,qword ptr [rcx+18h] ; set the 3rd argument + /* 0023: */ "\x48\x8B\x51\x10" // mov rdx,qword ptr [rcx+10h] ; set the 2nd argument + /* 0027: */ "\x48\x8B\x49\x08" // mov rcx,qword ptr [rcx+8] ; set the 1st argument + /* 002B: */ "\xFF\x13" // call qword ptr [rbx] ; call func + /* 002D: */ "\x48\x89\x03" // mov qword ptr [rbx],rax ; store the return value + /* 0030: */ "\xFF\x15\x0A\x00\x00\x00" // call GetLastError + /* 0036: */ "\x48\x83\xC4\x30" // add rsp,30h + /* 003A: */ "\x5B" // pop rbx + /* 003B: */ "\xC3" // ret + /* 003C: */ "\x90\x90\x90\x90" // nop; nop; nop; nop +#define X64_ADDR_GetLastError 0x0040 + /* 0040: */ "\x90\x90\x90\x90\x90\x90\x90\x90" + ; +#define X64_CODE_SIZE 0x0048 + +static const uint32_t arm64_code_template[] = { + /* 0000: */ 0xa9be7bfd, // stp x29, x30, [sp, #-32]! ; prolog + /* 0004: */ 0x910003fd, // mov x29, sp ; ditto + /* 0008: */ 0xf9000bf3, // str x19, [sp, #16] ; reserve x19 + /* 000c: */ 0xaa0003f3, // mov x19, x0 ; set args to x19 + /* 0010: */ 0xa9429664, // ldp x4, x5, [x19, #40] ; set 5th and 6th arguments + /* 0014: */ 0xa9418e62, // ldp x2, x3, [x19, #24] ; set 3rd and 4th arguments + /* 0018: */ 0xa9408660, // ldp x0, x1, [x19, #8] ; set 1st and 2nd arguments + /* 001c: */ 0xf9400269, // ldr x9, [x19] ; get args->func + /* 0020: */ 0xd63f0120, // blr x9 ; call args->func + /* 0024: */ 0xf9000260, // str x0, [x19] ; set the return value + /* 0028: */ 0xf9400bf3, // ldr x19, [sp, #16] ; restore x19 + /* 002c: */ 0xa8c27bfd, // ldp x29, x30, [sp], #32 ; epilog + /* 0030: */ 0x58000049, // ldr x9, ARM64_ADDR_GetLastError + /* 0034: */ 0xd61f0120, // br x9 +#define ARM64_ADDR_GetLastError 0x0038 + /* 0038: */ 0, + /* 003c: */ 0, +}; +#define ARM64_CODE_SIZE 0x0040 + +static const uint16_t armt_code_template[] = { + /* 0000: */ 0xb530, // push {r4, r5, lr} ; prolog + /* 0002: */ 0xb083, // sub sp, #12 ; reserve stack for arguments + /* 0004: */ 0x0004, // movs r4, r0 + /* 0006: */ 0x6b25, // ldr r5, [r4, #48] ; set the 6th argument + /* 0008: */ 0x9501, // str r5, [sp, #4] ; ditto + /* 000a: */ 0x6aa5, // ldr r5, [r4, #40] ; set the 5th argument + /* 000c: */ 0x9500, // str r5, [sp, #0] ; ditto + /* 000e: */ 0x6a23, // ldr r3, [r4, #32] ; set the 4th argument + /* 0010: */ 0x69a2, // ldr r2, [r4, #24] ; set the 3rd argument + /* 0012: */ 0x6921, // ldr r1, [r4, #16] ; set the 2nd argument + /* 0014: */ 0x68a0, // ldr r0, [r4, #8] ; set the 1st argument + /* 0016: */ 0x6825, // ldr r5, [r4, #0] ; get args->func + /* 0018: */ 0x47a8, // blx r5 ; call args->func + /* 001a: */ 0x6020, // str r0, [r4, #0] ; set the return value + /* 001c: */ 0x4d01, // ldr r5, [pc, #4] ; get the address of GetLastError (0x0024) + /* 001e: */ 0x47a8, // blx r5 ; call GetLastError + /* 0020: */ 0xb003, // add sp, #12 ; restore stack + /* 0022: */ 0xbd30, // pop {r4, r5, pc} ; epilog +#define ARMT_ADDR_GetLastError 0x0024 + /* 0024: */ 0, // .word + /* 0026: */ 0, // .word +}; +#define ARMT_CODE_SIZE 0x0028 + +static const char x86_code_template[] = + /* 0000: */ "\x55" // push ebp + /* 0001: */ "\x8B\xEC" // mov ebp,esp + /* 0003: */ "\x53" // push ebx + /* 0004: */ "\x8B\x5D\x08" // mov ebx,dword ptr [ebp+8] ; get args + /* 0007: */ "\xFF\x73\x30" // push dword ptr [ebx+30h] ; set the 6th argument + /* 000A: */ "\xFF\x73\x28" // push dword ptr [ebx+28h] ; set the 5th argument + /* 000D: */ "\xFF\x73\x20" // push dword ptr [ebx+20h] ; set the 4th argument + /* 0010: */ "\xFF\x73\x18" // push dword ptr [ebx+18h] ; set the 3rd argument + /* 0013: */ "\xFF\x73\x10" // push dword ptr [ebx+10h] ; set the 2nd argument + /* 0016: */ "\xFF\x73\x08" // push dword ptr [ebx+8] ; set the 1st argument + /* 0019: */ "\xFF\x13" // call dword ptr [ebx] ; call args->func + /* 001B: */ "\x89\x03" // mov dword ptr [ebx],eax ; store the return value +#define X86_CALL_GetLastError 0x001D + /* 001D: */ "\xE8\x00\x00\x00\x00" // call GetLastError + /* 0022: */ "\x8B\x5D\xF8" // mov ebx,dword ptr [ebp-8] + /* 0025: */ "\xC9" // leave + /* 0026: */ "\xC2\x04\x00" // ret 4 + ; + +#define X86_CODE_SIZE 0x0029 + +#ifdef _M_AMD64 +#define CURRENT_ARCH "x64" +#define CURRENT_IMAGE_FILE_MACHINE IMAGE_FILE_MACHINE_AMD64 +#endif +#ifdef _M_ARM64 +#define CURRENT_ARCH "arm64" +#define CURRENT_IMAGE_FILE_MACHINE IMAGE_FILE_MACHINE_ARM64 +#endif +#ifdef _M_ARMT +#define CURRENT_ARCH "arm" +#define CURRENT_IMAGE_FILE_MACHINE IMAGE_FILE_MACHINE_ARMNT +#endif +#ifdef _M_IX86 +#define CURRENT_ARCH "x86" +#define CURRENT_IMAGE_FILE_MACHINE IMAGE_FILE_MACHINE_I386 +#endif + +#define CODE_SIZE __max(__max(X64_CODE_SIZE, ARM64_CODE_SIZE), __max(X86_CODE_SIZE, ARMT_CODE_SIZE)) + +static BOOL CallIsWow64Process2(HANDLE hProcess, USHORT *pProcessMachine, USHORT *pNativeMachine) +{ + static IsWow64Process2_t IsWow64Process2_func = (IsWow64Process2_t)-1; + if (IsWow64Process2_func == (IsWow64Process2_t)-1) { + IsWow64Process2_func = (IsWow64Process2_t)GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process2"); + } + if (IsWow64Process2_func == NULL) { + return FALSE; + } + return IsWow64Process2_func(hProcess, pProcessMachine, pNativeMachine); +} +#define IsWow64Process2 CallIsWow64Process2 + +static BOOL CallGetProcessInformation(HANDLE hProcess, PROCESS_INFORMATION_CLASS ProcessInformationClass, LPVOID ProcessInformation, DWORD ProcessInformationSize) +{ + static GetProcessInformation_t GetProcessInformation_func = (GetProcessInformation_t)-1; + if (GetProcessInformation_func == (GetProcessInformation_t)-1) { + GetProcessInformation_func = (GetProcessInformation_t)GetProcAddress(GetModuleHandleA("kernel32"), "GetProcessInformation"); + } + if (GetProcessInformation_func == NULL) { + return FALSE; + } + return GetProcessInformation_func(hProcess, ProcessInformationClass, ProcessInformation, ProcessInformationSize); +} +#define GetProcessInformation CallGetProcessInformation + +static void set_errmsg(const char *format, ...); +static const char *w32strerr(DWORD err); +static USHORT process_arch(HANDLE hProcess); +static const char *arch_name(USHORT arch); + +struct injector { + HANDLE hProcess; + USHORT arch; + char *code; + char *data; + size_t load_library; + size_t free_library; + size_t get_last_error; + size_t get_proc_address; +}; + +static BOOL init(void) +{ + SYSTEM_INFO si; + HANDLE hToken; + LUID luid; + TOKEN_PRIVILEGES tp; + HMODULE kernel32 = GetModuleHandleA("kernel32"); + + GetSystemInfo(&si); + page_size = si.dwPageSize; + func_LoadLibraryW = (size_t)GetProcAddress(kernel32, "LoadLibraryW"); + func_FreeLibrary = (size_t)GetProcAddress(kernel32, "FreeLibrary"); + func_GetProcAddress = (size_t)GetProcAddress(kernel32, "GetProcAddress"); + func_GetLastError = (size_t)GetProcAddress(kernel32, "GetLastError"); + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { + return FALSE; + } + if (!LookupPrivilegeValue(0, SE_DEBUG_NAME, &luid)) { + CloseHandle(hToken); + return FALSE; + } + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL)) { + CloseHandle(hToken); + return FALSE; + } + CloseHandle(hToken); + return TRUE; +} + +static DWORD name_index(IMAGE_NT_HEADERS *nt_hdrs, void *base, const DWORD *names, DWORD num_names, const char *name) +{ + DWORD idx; + for (idx = 0; idx < num_names; idx++) { + if (strcmp((const char*)ImageRvaToVa(nt_hdrs, base, names[idx], NULL), name) == 0) { + return idx; + } + } + set_errmsg("Could not find the address of %s", name); + return (DWORD)-1; +} + +static int funcaddr(DWORD pid, injector_t *injector) +{ + HANDLE hSnapshot; + MODULEENTRY32W me; + BOOL ok; + HANDLE hFile = INVALID_HANDLE_VALUE; + HANDLE hFileMapping = NULL; + void *base = NULL; + IMAGE_NT_HEADERS *nt_hdrs; + ULONG exp_size; + const IMAGE_EXPORT_DIRECTORY *exp; + const DWORD *names, *funcs; + const WORD *ordinals; + DWORD idx; + int rv = INJERR_OTHER; + + /* Get the full path of kernel32.dll. */ +retry: + hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid); + if (hSnapshot == INVALID_HANDLE_VALUE) { + DWORD err = GetLastError(); + switch (err) { + case ERROR_BAD_LENGTH: + goto retry; + case ERROR_ACCESS_DENIED: + rv = INJERR_PERMISSION; + break; + case ERROR_INVALID_PARAMETER: + rv = INJERR_NO_PROCESS; + break; + default: + rv = INJERR_OTHER; + } + set_errmsg("CreateToolhelp32Snapshot error: %s", w32strerr(err)); + return rv; + } + me.dwSize = sizeof(me); + for (ok = Module32FirstW(hSnapshot, &me); ok; ok = Module32NextW(hSnapshot, &me)) { + if (wcsicmp(me.szModule, L"kernel32.dll") == 0) { + break; + } + } + CloseHandle(hSnapshot); + if (!ok) { + set_errmsg("kernel32.dll could not be found."); + return INJERR_OTHER; + } + + /* Get the export directory in the kernel32.dll. */ + hFile = CreateFileW(me.szExePath, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + set_errmsg("failed to open file %s: %s", me.szExePath, w32strerr(GetLastError())); + goto exit; + } + hFileMapping = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL); + if (hFileMapping == NULL) { + set_errmsg("failed to create file mapping of %s: %s", me.szExePath, w32strerr(GetLastError())); + goto exit; + } + base = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0); + if (base == NULL) { + set_errmsg("failed to map file %s to memory: %s", me.szExePath, w32strerr(GetLastError())); + goto exit; + } + nt_hdrs = ImageNtHeader(base); + if (nt_hdrs == NULL) { + set_errmsg("ImageNtHeader error: %s", w32strerr(GetLastError())); + goto exit; + } + exp = (const IMAGE_EXPORT_DIRECTORY *)ImageDirectoryEntryToDataEx(base, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size, NULL); + if (exp == NULL) { + set_errmsg("ImageDirectoryEntryToDataEx error: %s", w32strerr(GetLastError())); + goto exit; + } + if (exp->NumberOfNames == 0) { + set_errmsg("No export entires are not found."); + goto exit; + } + names = (const DWORD*)ImageRvaToVa(nt_hdrs, base, exp->AddressOfNames, NULL); + if (names == NULL) { + set_errmsg("ImageRvaToVa error: %s", w32strerr(GetLastError())); + goto exit; + } + ordinals = (const WORD*)ImageRvaToVa(nt_hdrs, base, exp->AddressOfNameOrdinals, NULL); + if (ordinals == NULL) { + set_errmsg("ImageRvaToVa error: %s", w32strerr(GetLastError())); + goto exit; + } + funcs = (const DWORD*)ImageRvaToVa(nt_hdrs, base, exp->AddressOfFunctions, NULL); + if (funcs == NULL) { + set_errmsg("ImageRvaToVa error: %s", w32strerr(GetLastError())); + goto exit; + } + + /* Find the address of LoadLibraryW */ + idx = name_index(nt_hdrs, base, names, exp->NumberOfNames, "LoadLibraryW"); + if (idx == (DWORD)-1) { + goto exit; + } + injector->load_library = (size_t)me.modBaseAddr + funcs[ordinals[idx]]; + + /* Find the address of FreeLibrary */ + idx = name_index(nt_hdrs, base, names, exp->NumberOfNames, "FreeLibrary"); + if (idx == (DWORD)-1) { + goto exit; + } + injector->free_library = (size_t)me.modBaseAddr + funcs[ordinals[idx]]; + + /* Find the address of GetProcAddress */ + idx = name_index(nt_hdrs, base, names, exp->NumberOfNames, "GetProcAddress"); + if (idx == (DWORD)-1) { + goto exit; + } + injector->get_proc_address = (size_t)me.modBaseAddr + funcs[ordinals[idx]]; + + /* Find the address of GetLastError */ + idx = name_index(nt_hdrs, base, names, exp->NumberOfNames, "GetLastError"); + if (idx == (DWORD)-1) { + goto exit; + } + injector->get_last_error = (size_t)me.modBaseAddr + funcs[ordinals[idx]]; + rv = 0; +exit: + if (base != NULL) { + UnmapViewOfFile(base); + } + if (hFileMapping != NULL) { + CloseHandle(hFileMapping); + } + if (hFile != INVALID_HANDLE_VALUE) { + CloseHandle(hFile); + } + return rv; +} + +static int remote_call(injector_t *injector, remote_call_args_t *args, size_t size, intptr_t *retval, DWORD *last_error) +{ + char *code = injector->code; + HANDLE hThread; + SIZE_T sz; + + if (injector->arch == IMAGE_FILE_MACHINE_ARMNT) { + ++code; + } + if (!WriteProcessMemory(injector->hProcess, injector->data, args, size, &sz)) { + set_errmsg("WriteProcessMemory error: %s", w32strerr(GetLastError())); + return INJERR_OTHER; + } + hThread = CreateRemoteThread(injector->hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)code, injector->data, 0, NULL); + if (hThread == NULL) { + set_errmsg("CreateRemoteThread error: %s", w32strerr(GetLastError())); + return INJERR_OTHER; + } + WaitForSingleObject(hThread, INFINITE); + if (last_error) { + GetExitCodeThread(hThread, last_error); + } + CloseHandle(hThread); + if (retval) { + union { + size_t s; + uint32_t u32; + } val; + size_t valsize = sizeof(size_t); + switch (injector->arch) { + case IMAGE_FILE_MACHINE_ARMNT: + case IMAGE_FILE_MACHINE_I386: + valsize = 4; + break; + } + if (!ReadProcessMemory(injector->hProcess, injector->data, &val, valsize, &sz)) { + set_errmsg("ReadProcessMemory error: %s", w32strerr(GetLastError())); + return INJERR_OTHER; + } + if (valsize == 4) { + *retval = val.u32; + } else { + *retval = val.s; + } + } + return 0; +} + +int injector_attach(injector_t **injector_out, DWORD pid) +{ + injector_t *injector; + DWORD dwDesiredAccess = + PROCESS_QUERY_LIMITED_INFORMATION | /* for IsWow64Process() */ + PROCESS_CREATE_THREAD | /* for CreateRemoteThread() */ + PROCESS_VM_OPERATION | /* for VirtualAllocEx() */ + PROCESS_VM_READ | /* for ReadProcessMemory() */ + PROCESS_VM_WRITE; /* for WriteProcessMemory() */ + DWORD old_protect; + SIZE_T written; + int rv; + char code[CODE_SIZE]; + size_t code_size; + + if (page_size == 0) { + init(); + } + + injector = calloc(1, sizeof(injector_t)); + if (injector == NULL) { + set_errmsg("malloc error: %s", strerror(errno)); + return INJERR_NO_MEMORY; + } + injector->hProcess = OpenProcess(dwDesiredAccess, FALSE, pid); + if (injector->hProcess == NULL) { + DWORD err = GetLastError(); + set_errmsg("OpenProcess error: %s", w32strerr(err)); + switch (err) { + case ERROR_ACCESS_DENIED: + rv = INJERR_PERMISSION; + break; + case ERROR_INVALID_PARAMETER: + rv = INJERR_NO_PROCESS; + break; + default: + rv = INJERR_OTHER; + } + goto error_exit; + } + injector->load_library = func_LoadLibraryW; + injector->free_library = func_FreeLibrary; + injector->get_last_error = func_GetLastError; + injector->get_proc_address = func_GetProcAddress; + + injector->arch = process_arch(injector->hProcess); + switch (injector->arch) { +#if defined(_M_ARM64) // arm64 + case IMAGE_FILE_MACHINE_ARM64: + case IMAGE_FILE_MACHINE_ARMNT: + break; +#endif +#if defined(_M_AMD64) // x64 + static USHORT native_machine = IMAGE_FILE_MACHINE_UNKNOWN; + case IMAGE_FILE_MACHINE_AMD64: + break; + case IMAGE_FILE_MACHINE_I386: + if (native_machine == IMAGE_FILE_MACHINE_UNKNOWN) { + USHORT dummy; + if (!IsWow64Process2(GetCurrentProcess(), &dummy, &native_machine)) { + native_machine = IMAGE_FILE_MACHINE_AMD64; + } + } + if (native_machine == IMAGE_FILE_MACHINE_AMD64) { + // x86 process on Windows x64 + break; + } + // x86 process on Windows arm64 + // FALL THROUGH +#endif +#if defined(_M_IX86) // x86 + case IMAGE_FILE_MACHINE_I386: + break; +#endif +#if defined(_M_ARMT) // arm32 + case IMAGE_FILE_MACHINE_ARMNT: + break; +#endif + default: + set_errmsg("%s target process isn't supported by %s process.", + arch_name(injector->arch), CURRENT_ARCH); + rv = INJERR_UNSUPPORTED_TARGET; + goto error_exit; + } + + if (injector->arch != CURRENT_IMAGE_FILE_MACHINE) { + rv = funcaddr(pid, injector); + if (rv != 0) { + goto error_exit; + } + } + + injector->code = VirtualAllocEx(injector->hProcess, NULL, 2 * page_size, + MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READ); + if (injector->code == NULL) { + set_errmsg("VirtualAllocEx error: %s", w32strerr(GetLastError())); + rv = INJERR_OTHER; + goto error_exit; + } + injector->data = injector->code + page_size; + switch (injector->arch) { + case IMAGE_FILE_MACHINE_AMD64: /* x64 */ + memcpy(code, x64_code_template, X64_CODE_SIZE); + code_size = X64_CODE_SIZE; + *(size_t*)(code + X64_ADDR_GetLastError) = injector->get_last_error; + break; + case IMAGE_FILE_MACHINE_ARM64: /* arm64 */ + memcpy(code, arm64_code_template, ARM64_CODE_SIZE); + code_size = ARM64_CODE_SIZE; + *(size_t*)(code + ARM64_ADDR_GetLastError) = injector->get_last_error; + break; + case IMAGE_FILE_MACHINE_ARMNT: /* arm (thumb mode) */ + memcpy(code, armt_code_template, ARMT_CODE_SIZE); + code_size = ARMT_CODE_SIZE; + *(uint32_t*)(code + ARMT_ADDR_GetLastError) = (uint32_t)injector->get_last_error; + break; + case IMAGE_FILE_MACHINE_I386: /* x86 */ + memcpy(code, x86_code_template, X86_CODE_SIZE); + code_size = X86_CODE_SIZE; +#define FIX_CALL_RELATIVE(addr, offset) *(uint32_t*)(code + offset + 1) = addr - ((uint32_t)(size_t)injector->code + offset + 5) + FIX_CALL_RELATIVE(injector->get_last_error, X86_CALL_GetLastError); + break; + default: + set_errmsg("Never reach here: arch=0x%x", injector->arch); + rv = INJERR_OTHER; + goto error_exit; + } + + if (!WriteProcessMemory(injector->hProcess, injector->code, code, code_size, &written)) { + set_errmsg("WriteProcessMemory error: %s", w32strerr(GetLastError())); + rv = INJERR_OTHER; + goto error_exit; + } + + if (!VirtualProtectEx(injector->hProcess, injector->data, page_size, PAGE_READWRITE, &old_protect)) { + set_errmsg("VirtualProtectEx error: %s", w32strerr(GetLastError())); + rv = INJERR_OTHER; + goto error_exit; + } + + *injector_out = injector; + return 0; +error_exit: + injector_detach(injector); + return rv; +} + +int injector_inject(injector_t *injector, const char *path, void **handle) +{ + DWORD pathlen = (DWORD)strlen(path); + wchar_t *wpath; + DWORD wpathlen; + + if (pathlen == 0) { + set_errmsg("The specified path is empty."); + return INJERR_FILE_NOT_FOUND; + } + if (pathlen > MAX_PATH) { + set_errmsg("too long file path: %s", path); + return INJERR_FILE_NOT_FOUND; + } + + wpath = _alloca((pathlen + 1) * sizeof(wchar_t)); + wpathlen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, path, pathlen, wpath, pathlen + 1); + wpath[wpathlen] = L'\0'; + return injector_inject_w(injector, wpath, handle); +} + +int injector_inject_w(injector_t *injector, const wchar_t *path, void **handle) +{ + struct { + remote_call_args_t args; + wchar_t fullpath[MAX_PATH]; + } data = {0, }; + DWORD pathlen; + intptr_t retval; + DWORD last_error; + int rv; + + pathlen = GetFullPathNameW(path, MAX_PATH, data.fullpath, NULL); + if (pathlen > MAX_PATH) { + set_errmsg("too long file path: %S", path); + return INJERR_FILE_NOT_FOUND; + } + if (pathlen == 0) { + set_errmsg("failed to get the full path: %S", path); + return INJERR_FILE_NOT_FOUND; + } + data.args.func = injector->load_library; + data.args.arg1 = (size_t)injector->data + sizeof(remote_call_args_t); + + rv = remote_call(injector, &data.args, sizeof(data), &retval, &last_error); + if (rv != 0) { + return rv; + } + if (retval == 0) { + set_errmsg("LoadLibrary in the target process failed: %s", w32strerr(last_error)); + return INJERR_ERROR_IN_TARGET; + } + if (handle != NULL) { + *handle = (void*)retval; + } + return 0; +} + +int injector_uninject(injector_t *injector, void *handle) +{ + remote_call_args_t args; + DWORD pathlen; + size_t retval; + DWORD last_error; + int rv; + + args.func = injector->free_library; + args.arg1 = (size_t)handle; + + rv = remote_call(injector, &args, sizeof(args), &retval, &last_error); + if (rv != 0) { + return rv; + } + if ((BOOL)retval) { + return 0; + } else { + set_errmsg("FreeLibrary in the target process failed: %s", w32strerr(last_error)); + return INJERR_ERROR_IN_TARGET; + } +} + +int injector_detach(injector_t *injector) +{ + if (injector->code != NULL) { + VirtualFreeEx(injector->hProcess, injector->code, 0, MEM_RELEASE); + } + if (injector->hProcess != NULL) { + CloseHandle(injector->hProcess); + } + free(injector); + return 0; +} + +const char *injector_error(void) +{ + return errmsg; +} + +int injector_remote_func_addr(injector_t *injector, void *handle, const char* name, size_t *func_addr_out) +{ + struct { + remote_call_args_t args; + char name[512]; + } data = {0, }; + intptr_t retval; + DWORD last_error; + int rv; + + if (strlen(name) >= sizeof(data.name)) { + set_errmsg("too long function name: %s", name); + return INJERR_FUNCTION_MISSING; + } + + data.args.func = injector->get_proc_address; + data.args.arg1 = (size_t)handle; + data.args.arg2 = (size_t)injector->data + sizeof(remote_call_args_t); + strncpy(data.name, name, sizeof(data.name)); + rv = remote_call(injector, &data.args, sizeof(data), &retval, &last_error); + if (rv != 0) { + return rv; + } + if (retval == 0) { + set_errmsg("GetProcAddress in the target process failed: %s", w32strerr(last_error)); + return INJERR_ERROR_IN_TARGET; + } + *func_addr_out = (size_t)retval; + return 0; +} + +int injector_remote_call(injector_t *injector, intptr_t *retval, size_t func_addr, ...) +{ + va_list ap; + int rv; + + va_start(ap, func_addr); + rv = injector_remote_vcall(injector, retval, func_addr, ap); + va_end(ap); + return rv; +} + +int injector_remote_vcall(injector_t *injector, intptr_t *retval, size_t func_addr, va_list ap) +{ + remote_call_args_t args = {0,}; + + args.func = func_addr; + args.arg1 = va_arg(ap, size_t); + args.arg2 = va_arg(ap, size_t); + args.arg3 = va_arg(ap, size_t); + args.arg4 = va_arg(ap, size_t); + args.arg5 = va_arg(ap, size_t); + args.arg6 = va_arg(ap, size_t); + return remote_call(injector, &args, sizeof(args), retval, NULL); +} + +static void set_errmsg(const char *format, ...) +{ + va_list ap; + int rv; + + va_start(ap, format); + rv = vsnprintf(errmsg, sizeof(errmsg), format, ap); + va_end(ap); + if (rv == -1 || rv >= sizeof(errmsg)) { + errmsg[sizeof(errmsg) - 1] = '\0'; + } +} + +static const char *w32strerr(DWORD err) +{ + static char errmsg[512]; + DWORD len; + + len = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + errmsg, sizeof(errmsg), NULL); + if (len > 0) { + while (len > 0) { + char c = errmsg[len - 1]; + if (c == ' ' || c == '\n' || c == '\r') { + len--; + } else { + break; + } + } + errmsg[len] = '\0'; + } else if ((int)err >= 0) { + sprintf(errmsg, "win32 error code %d", err); + } else { + sprintf(errmsg, "win32 error code 0x%x", err); + } + return errmsg; +} + +static USHORT process_arch(HANDLE hProcess) +{ + PROCESS_MACHINE_INFORMATION pmi; + if (GetProcessInformation(hProcess, ProcessMachineTypeInfo, &pmi, sizeof(pmi))) { + // Windows 11 + return pmi.ProcessMachine; + } + USHORT process_machine; + USHORT native_machine; + if (IsWow64Process2(hProcess, &process_machine, &native_machine)) { + // Windows 10 + if (process_machine != IMAGE_FILE_MACHINE_UNKNOWN) { + return process_machine; + } else { + return native_machine; + } + } + /* Windows 8.1 or earlier */ + /* arch will be either x86 or x64. */ +#if defined(_M_AMD64) || defined(_M_IX86) + BOOL is_wow64_proc; +#if defined(_M_IX86) + if (IsWow64Process(GetCurrentProcess(), &is_wow64_proc) && !is_wow64_proc) { + // Run on 32-bit Windows + return IMAGE_FILE_MACHINE_I386; + } +#endif + if (IsWow64Process(hProcess, &is_wow64_proc)) { + return is_wow64_proc ? IMAGE_FILE_MACHINE_I386 : IMAGE_FILE_MACHINE_AMD64; + } +#endif + return IMAGE_FILE_MACHINE_UNKNOWN; +} + +static const char *arch_name(USHORT arch) +{ + switch (arch) { + case IMAGE_FILE_MACHINE_AMD64: + return "x64"; + case IMAGE_FILE_MACHINE_ARM64: + return "arm64"; + case IMAGE_FILE_MACHINE_ARMNT: + return "arm"; + case IMAGE_FILE_MACHINE_I386: + return "x86"; + default: + return "unknown"; + } +} diff --git a/RemoteInput/Thirdparty/kubo_injector/src/windows/injector.def b/RemoteInput/Thirdparty/kubo_injector/src/windows/injector.def new file mode 100644 index 0000000..53b997d --- /dev/null +++ b/RemoteInput/Thirdparty/kubo_injector/src/windows/injector.def @@ -0,0 +1,9 @@ +EXPORTS + injector_attach + injector_inject + injector_detach + injector_error + injector_inject_w + injector_remote_func_addr + injector_remote_call + injector_remote_vcall