diff --git a/cxx-shared/shared/native.hpp b/cxx-shared/shared/native.hpp index fe880a9..e7235b9 100644 --- a/cxx-shared/shared/native.hpp +++ b/cxx-shared/shared/native.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include #include @@ -13,13 +14,22 @@ namespace native { static_assert(offsetof(PEB, read_image_file_exec_options) == 1); - inline PEB* get_peb() { - static auto function = reinterpret_cast(GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlGetCurrentPeb")); - - if (function == nullptr) { - throw std::runtime_error("no RtlGetCurrentPeb"); + template + inline Ty get_system_routine(const std::string_view module_name, const std::string_view function_name) { + const auto mod = GetModuleHandleA(module_name.data()); + if (mod == nullptr) { + throw std::runtime_error(std::format("unable to find module {}", module_name)); } + auto function = reinterpret_cast(GetProcAddress(mod, function_name.data())); + if (function == nullptr) { + throw std::runtime_error(std::format("unable to obtain {} from {}", module_name, function_name)); + } + return function; + } + + inline PEB* get_peb() { + static auto function = get_system_routine("ntdll.dll", "RtlGetCurrentPeb"); static auto result = function(); if (result == nullptr) [[unlikely]] { throw std::runtime_error("no peb"); @@ -27,5 +37,15 @@ namespace native { return result; } + + inline bool debug_set_process_kill_on_exit(const bool value) { + static auto function = get_system_routine("kernel32.dll", "DebugSetProcessKillOnExit"); + return static_cast(function(static_cast(value))); + } + + inline bool debug_active_process_stop(const std::uint32_t process_id) { + static auto function = get_system_routine("kernel32.dll", "DebugActiveProcessStop"); + return static_cast(function(process_id)); + } } // namespace native #pragma pack(pop) diff --git a/defendnot-loader/core/inject.cpp b/defendnot-loader/core/inject.cpp index 0f2c2db..4834c97 100644 --- a/defendnot-loader/core/inject.cpp +++ b/defendnot-loader/core/inject.cpp @@ -21,14 +21,20 @@ namespace loader { .bInheritHandle = TRUE, }; + /// By setting ReadImageFileExecOptions to FALSE and attaching ourselves as a debugger we can skip the IFEO /// \xref: https://github.com/es3n1n/defendnot/issues/7#issuecomment-2874903650 native::get_peb()->read_image_file_exec_options = 0; std::println("** booting {}", proc_name); - if (!CreateProcessA(nullptr, const_cast(proc_name.data()), &sa, &sa, FALSE, CREATE_SUSPENDED, nullptr, nullptr, &si, &pi)) { + const auto process_flags = CREATE_SUSPENDED | DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS; + if (!CreateProcessA(nullptr, const_cast(proc_name.data()), &sa, &sa, FALSE, process_flags, nullptr, nullptr, &si, &pi)) { throw std::runtime_error(std::format("unable to create process: {}", GetLastError())); } + /// Detach + native::debug_set_process_kill_on_exit(false); + native::debug_active_process_stop(pi.dwProcessId); + defer->void { CloseHandle(pi.hThread); /// Not closing hProcess because we return it