diff --git a/cxx-shared/cxx-shared.vcxitems b/cxx-shared/cxx-shared.vcxitems
index 081badd..176a9e5 100644
--- a/cxx-shared/cxx-shared.vcxitems
+++ b/cxx-shared/cxx-shared.vcxitems
@@ -18,6 +18,7 @@
+
\ No newline at end of file
diff --git a/cxx-shared/shared/native.hpp b/cxx-shared/shared/native.hpp
new file mode 100644
index 0000000..e7235b9
--- /dev/null
+++ b/cxx-shared/shared/native.hpp
@@ -0,0 +1,51 @@
+#pragma once
+#include
+#include
+#include
+
+#pragma pack(push, 1)
+namespace native {
+ class PEB {
+ public:
+ std::uint8_t inherited_address_space;
+ std::uint8_t read_image_file_exec_options;
+ /// - we don't need other fields
+ };
+
+ static_assert(offsetof(PEB, read_image_file_exec_options) == 1);
+
+ 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");
+ }
+
+ 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 6cf26fe..4834c97 100644
--- a/defendnot-loader/core/inject.cpp
+++ b/defendnot-loader/core/inject.cpp
@@ -1,6 +1,8 @@
#include "core/core.hpp"
#include "shared/defer.hpp"
+#include "shared/native.hpp"
+
#include
#include
@@ -19,11 +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