#include "bootstrap/bootstrap.hpp"
#include "core/log.hpp"
#include "shared/ipc.hpp"

#include <stdexcept>
#include <thread>

#include <Windows.h>

namespace {

} // namespace

BOOL __stdcall DllMain(HINSTANCE base, std::uint32_t call_reason, LPVOID reserved) {
    if (call_reason != DLL_PROCESS_ATTACH) {
        return TRUE;
    }

    const auto th = CreateThread(nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(entry_thread), base, 0, nullptr);
    if (th != nullptr) {
        CloseHandle(th);
    }

    return TRUE;
}

void entry_thread(HMODULE base) {
        bool success = false;
        std::unique_ptr<shared::InterProcessCommunication> ipc;
        try {
            ipc = std::make_unique<shared::InterProcessCommunication>(shared::InterProcessCommunicationMode::WRITE);
            defendnot::startup();
            success = true;
        } catch (std::exception& err) {
            MessageBoxA(nullptr, err.what(), "defendnot", MB_TOPMOST | MB_ICONERROR);
        }
        if (ipc) {
            (*ipc)->success = success;
            (*ipc)->finished = true;
        }
        FreeLibraryAndExitThread(base, 0);
    }

#include "core/core.hpp"

#include "shared/defer.hpp"
#include "shared/native.hpp"

#include <print>
#include <stdexcept>

#include <Windows.h>

namespace loader {
    [[nodiscard]] HANDLE inject(std::string_view dll_path, std::string_view proc_name) {
        STARTUPINFOA si = {
            .cb = sizeof(si),
        };
        PROCESS_INFORMATION pi = {
            0,
        };
        SECURITY_ATTRIBUTES sa = {
            .nLength = sizeof(sa),
            .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);
        const auto process_flags = CREATE_SUSPENDED | DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
        if (!CreateProcessA(nullptr, const_cast<char*>(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
        };

        LPVOID mem = VirtualAllocEx(pi.hProcess, nullptr, dll_path.size() + 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
        if (mem == nullptr) {
            throw std::runtime_error(std::format("unable to allocate memory: {}", GetLastError()));
        }

        defer->void {
            VirtualFreeEx(pi.hProcess, mem, 0, MEM_RELEASE);
        };

        if (!WriteProcessMemory(pi.hProcess, mem, dll_path.data(), dll_path.size() + 1, nullptr)) {
            throw std::runtime_error(std::format("unable to write memory: {}", GetLastError()));
        }

        HANDLE thread = CreateRemoteThread(pi.hProcess, nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(LoadLibraryA), mem, 0, nullptr);
        if (thread == NULL) {
            throw std::runtime_error(std::format("unable to create thread: {}", GetLastError()));
        }

        defer->void {
            CloseHandle(thread);
        };

        /// Wait for DllMain to complete
        WaitForSingleObject(thread, INFINITE);
        return pi.hProcess;
    }
} // namespace loader

#include "core/core.hpp"
#include "shared/ctx.hpp"
#include "shared/defer.hpp"
#include "shared/ipc.hpp"
#include "shared/strings.hpp"
#include <argparse/argparse.hpp>

#include <format>
#include <print>
#include <thread>

namespace {
    void setup_window(const loader::Config& config) {
        if ((!config.from_autorun || config.verbose) && config.alloc_console) {
            shared::alloc_console();
        }
    }

    void setup_context(const loader::Config& config) {
        std::println("** setting up context");

        if (config.name.length() > shared::kMaxNameLength) {
            throw std::runtime_error(std::format("Max name length is {} characters", shared::kMaxNameLength));
        }

        shared::ctx.state = config.disable ? shared::State::OFF : shared::State::ON;
        shared::ctx.verbose = config.verbose;
        std::ranges::copy(config.name, shared::ctx.name.data());

        /// No need to overwrite ctx if we are called from autorun
        if (!config.from_autorun) {
            std::println("** overwriting ctx.bin");
            shared::ctx.serialize();
        }
    }

    [[nodiscard]] HANDLE load_defendnot() {
        std::println("** loading defendnot");

        auto dll_path = shared::get_this_module_path().parent_path();
        dll_path /= strings::kDllName;
        if (!std::filesystem::exists(dll_path)) {
            throw std::runtime_error(std::format("{} does not exist!", strings::kDllName));
        }

        return loader::inject(dll_path.string(), strings::kVictimProcess);
    }

    void wait_for_finish(shared::InterProcessCommunication& ipc) {
        std::println("** waiting for process to finish, this can take a while");
        std::cout << std::flush;
        while (!ipc->finished) {
            std::this_thread::sleep_for(std::chrono::milliseconds(500));
        }
        std::println("** success: {}", ipc->success);
    }

    void process_autorun(const loader::Config& config) {
        if (shared::ctx.state == shared::State::ON && config.enable_autorun) {
            std::println("** added to autorun: {}", loader::add_to_autorun(config.autorun_type));
        } else {
            std::println("** removed from autorun: {}", loader::remove_from_autorun());
        }
    }

    void banner(const loader::Config& config) {
        std::println();
        std::println("thanks for using {}", strings::kProjectName);
        std::println("please don't forget to leave a star at {}", strings::kRepoUrl);

        if (!config.from_autorun && config.alloc_console) {
            system("pause");
        }
    }
} // namespace

int main(int argc, char* argv[]) try {
    argparse::ArgumentParser program(std::format("{}-loader", strings::kProjectName), strings::kVersion.data(), argparse::default_arguments::none);

    const auto fatal_print = [](const std::string_view str) -> void {
        shared::alloc_console();
        std::cerr << str << std::endl;
        system("pause");
        std::exit(EXIT_FAILURE);
    };

    /// We are registering these ourselves because we have to alloc console first
    program.add_argument("-h", "--help")
        .help("prints help message and exits")
        .default_value(false)
        .implicit_value(true)
        .action([&fatal_print, &program](const auto& /*unused*/) -> void { fatal_print(program.help().str()); });
    program.add_argument("--version")
        .help("shows version and exits")
        .default_value(false)
        .implicit_value(true)
        .action([&fatal_print](const auto& /*unused*/) -> void { fatal_print(std::format("{}-loader v{}", strings::kProjectName, strings::kVersion)); });

    /// defendnot-loader parameters:
    program.add_argument("-n", "--name").help("av display name").default_value(std::string(strings::kDefaultAVName)).nargs(1);
    program.add_argument("-d", "--disable").help(std::format("disable {}", strings::kProjectName)).default_value(false).implicit_value(true);
    program.add_argument("-v", "--verbose").help("verbose logging").default_value(false).implicit_value(true);
    program.add_argument("--silent").help("do not allocate console").default_value(false).implicit_value(true);
    program.add_argument("--autorun-as-user").help("create autorun task as currently logged in user").default_value(false).implicit_value(true);
    program.add_argument("--disable-autorun").help("disable autorun task creation").default_value(false).implicit_value(true);
    program.add_argument("--from-autorun").hidden().default_value(false).implicit_value(true);

    try {
        program.parse_args(argc, argv);
    } catch (std::exception& e) {
        std::stringstream ss;
        ss << e.what() << '\n';
        ss << program.help().str();
        fatal_print(ss.str());
        return EXIT_FAILURE;
    }

    auto config = loader::Config{
        .name = program.get<std::string>("-n"),
        .disable = program.get<bool>("-d"),
        .alloc_console = !program.get<bool>("--silent"),
        .verbose = program.get<bool>("-v"),
        .from_autorun = program.get<bool>("--from-autorun"),
        .autorun_type = program.get<bool>("--autorun-as-user") ? /// As system on boot is the default value
                            loader::AutorunType::AS_CURRENT_USER_ON_LOGIN :
                            loader::AutorunType::AS_SYSTEM_ON_BOOT,
        .enable_autorun = !program.get<bool>("--disable-autorun"),
    };

    /// When running from autorun, we'll be missing all the cli arguments, so lets load some relevant ones
    if (config.from_autorun) {
        shared::ctx.deserialize();
        config.verbose = shared::ctx.verbose;
    }

    if (!config.alloc_console && config.verbose) {
        fatal_print("--silent flag can not be used in combination with --verbose");
    }

    setup_window(config);
    loader::ensure_environment();

    setup_context(config);

    /// \todo @es3n1n: move this to a separate function and add move ctor for ipc
    std::println("** setting up ipc");
    auto ipc = shared::InterProcessCommunication(shared::InterProcessCommunicationMode::READ_WRITE, true);
    ipc->finished = false;

    const auto process = load_defendnot();
    defer->void {
        TerminateProcess(process, 0);
    };

    wait_for_finish(ipc);

    /// Only create autorun task when not running from autorun, no need to recreate it because we're missing some config vars
    if (!config.from_autorun) {
        process_autorun(config);
    }

    banner(config);

    return EXIT_SUCCESS;
} catch (std::exception& err) {
    shared::alloc_console();
    std::println(stderr, "** fatal error: {}", err.what());
    system("pause");
    return EXIT_FAILURE;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow) {
    return main(__argc, __argv);
}

#include <Windows.h>
#include <winternl.h>

#include <filesystem>
#include <fstream>
#include <optional>
#include <print>
#include <ranges>
#include <set>

#include "shared/defer.hpp"

#pragma comment(lib, "Crypt32.lib")

namespace {
    constexpr std::string_view kTargetDirectory = "c:\\Windows\\System32";
    /* constexpr */ auto kTargetFileExts = std::set<std::string_view>{".exe"};

    constexpr std::uint16_t kDosMagic = 0x5A4D;
    constexpr std::uint32_t kNtSignature = 0x00004550;
    constexpr std::uint16_t kARM64Machine = 0xAA64;
    constexpr std::uint16_t kAMD64Machine = 0x8664;
    constexpr std::uint16_t kI386Machine = 0x014C;
    constexpr std::uint16_t kDllCharacteristicsForceIntegrityMask = 0x80;

    [[nodiscard]] std::optional<std::vector<std::uint8_t>> read_file(const std::filesystem::path path) {
        std::ifstream file(path, std::ios::binary);
        if (!file.good()) {
            return std::nullopt;
        }

        const auto size = std::filesystem::file_size(path);
        std::vector<std::uint8_t> buffer(size);

        file.read(reinterpret_cast<char*>(buffer.data()), static_cast<std::streamsize>(buffer.size()));
        return buffer;
    }

    [[nodiscard]] bool check_characteristics(const std::span<std::uint8_t> data) {
        if (data.size() < sizeof(IMAGE_DOS_HEADER)) {
            throw std::runtime_error("got invalid pe image");
        }

        const auto p_dos = reinterpret_cast<PIMAGE_DOS_HEADER>(data.data());
        if (p_dos->e_magic != kDosMagic) {
            throw std::runtime_error("got invalid pe image (2)");
        }

        const auto p_nt = reinterpret_cast<PIMAGE_NT_HEADERS>(data.data() + p_dos->e_lfanew);
        if (p_nt->Signature != kNtSignature) {
            throw std::runtime_error("got invalid pe image (3)");
        }

        const auto machine = p_nt->FileHeader.Machine;
        std::uint16_t characteristics;

        if (machine == kARM64Machine || machine == kAMD64Machine) {
            characteristics = reinterpret_cast<PIMAGE_NT_HEADERS64>(p_nt)->OptionalHeader.DllCharacteristics;
        } else if (machine == kI386Machine) {
            characteristics = reinterpret_cast<PIMAGE_NT_HEADERS32>(p_nt)->OptionalHeader.DllCharacteristics;
        } else {
            throw std::runtime_error(std::format("unsupported machine: {:#x}", machine));
        }

        return (characteristics & kDllCharacteristicsForceIntegrityMask) != 0;
    }

    [[nodiscard]] bool check_signature(const std::filesystem::path path) {
        HCERTSTORE store = {0};
        HCRYPTMSG msg = {0};
        if (!CryptQueryObject(1, path.wstring().c_str(), 0x400, 0xE, 0, nullptr, nullptr, nullptr, &store, &msg, nullptr) //
            || !store || !msg) {
            /// Most likely the binary is just not signed
            return false;
        }

        defer->void {
            CryptMsgClose(msg);
            CertCloseStore(store, 1);
        };

        PCCERT_CONTEXT signer = nullptr;
        if (!CryptMsgGetAndVerifySigner(msg, 0, nullptr, 2, &signer, nullptr) || signer == nullptr) {
            throw std::runtime_error(std::format("CryptMsgGetAndVerifySigner() on {}", path.string()));
        }

        defer->void {
            CertFreeCertificateContext(signer);
        };

        /// I don't think we have to do something with signer?
        return true;
    }
} // namespace

int main() try {
    for (auto& entry : std::filesystem::recursive_directory_iterator(kTargetDirectory, std::filesystem::directory_options::skip_permission_denied)) {
        auto path = entry.path();
        auto ext = path.extension().string() //
                   | std::views::transform([](const char c) -> char { return ::tolower(c); }) //
                   | std::ranges::to<std::string>();

        if (!kTargetFileExts.contains(ext)) {
            continue;
        }

        auto file = read_file(path);
        if (!file.has_value()) {
            std::println(stderr, "unable to read {}", path.string());
            continue;
        }

        const std::span file_ptr = *file;
        if (!check_characteristics(file_ptr)) {
            continue;
        }

        if (!check_signature(path)) {
            continue;
        }

        std::println("matches: {}", path.string());
    }

    return EXIT_SUCCESS;
} catch (const std::exception& e) {
    std::println(stderr, "fatal error: {}", e.what());
    return EXIT_FAILURE;
}

#include "core/core.hpp"

#include "shared/com.hpp"
#include "shared/ctx.hpp"
#include "shared/strings.hpp"

#include <memory>
#include <print>
#include <stdexcept>
#include <type_traits>

#include <comdef.h>
#include <taskschd.h>

#pragma comment(lib, "taskschd.lib")
#pragma comment(lib, "comsupp.lib")
#pragma comment(lib, "ole32.lib")

namespace loader {
    namespace {
        constexpr std::string_view kTaskName = strings::kProjectName;

        void co_initialize() {
            static std::once_flag fl;
            std::call_once(fl, []() -> void {
                const auto result = CoInitializeEx(nullptr, COINIT_MULTITHREADED);

                if (FAILED(result)) {
                    throw std::runtime_error("failed to CoInitializeEx");
                }
            });
        }

        template <typename Callable>
        [[nodiscard]] bool with_service(Callable&& callback) {
            co_initialize();

            com::Ptr<ITaskService> service;
            auto hr =
                CoCreateInstance(CLSID_TaskScheduler, nullptr, CLSCTX_INPROC_SERVER, IID_ITaskService, reinterpret_cast<void**>(service.ref_to_ptr()));
            if (FAILED(hr)) {
                return false;
            }

            hr = service->Connect(VARIANT{}, VARIANT{}, VARIANT{}, VARIANT{});
            if (FAILED(hr)) {
                return false;
            }

            com::Ptr<ITaskFolder> root_folder;
            hr = service->GetFolder(BSTR(L"\\"), root_folder.ref_to_ptr());
            if (FAILED(hr)) {
                return false;
            }

            /// Cleanup our task, we will recreate it in the callback if needed
            root_folder->DeleteTask(BSTR(kTaskName.data()), 0);
            return callback(service.get(), root_folder.get());
        }
    } // namespace

    [[nodiscard]] bool add_to_autorun(AutorunType type) {
        const auto bin_path = shared::get_this_module_path();

        return with_service([bin_path, type](ITaskService* service, ITaskFolder* folder) -> bool {
            /// Deduce the autorun config based on type
            const auto task_trigger = type == AutorunType::AS_SYSTEM_ON_BOOT ? TASK_TRIGGER_BOOT : TASK_TRIGGER_LOGON;
            const auto logon_type = type == AutorunType::AS_SYSTEM_ON_BOOT ? TASK_LOGON_SERVICE_ACCOUNT : TASK_LOGON_INTERACTIVE_TOKEN;

            BSTR user_id = nullptr;
            auto bstr_sys = bstr_t(L"SYSTEM");
            if (type == AutorunType::AS_SYSTEM_ON_BOOT) {
                user_id = bstr_sys;
            }

            com::Ptr<ITaskDefinition> task;
            auto hr = service->NewTask(0, task.ref_to_ptr());
            if (FAILED(hr)) {
                return false;
            }

            com::Ptr<IRegistrationInfo> reg_info;
            hr = task->get_RegistrationInfo(reg_info.ref_to_ptr());
            if (FAILED(hr)) {
                return false;
            }

            com::Ptr<IPrincipal> principal;
            hr = task->get_Principal(principal.ref_to_ptr());
            if (FAILED(hr)) {
                return false;
            }

            com::Ptr<ITriggerCollection> trigger_collection;
            hr = task->get_Triggers(trigger_collection.ref_to_ptr());
            if (FAILED(hr)) {
                return false;
            }

            com::Ptr<ITrigger> trigger;
            hr = trigger_collection->Create(task_trigger, trigger.ref_to_ptr());
            if (FAILED(hr)) {
                return false;
            }

            com::Ptr<IActionCollection> action_collection;
            hr = task->get_Actions(action_collection.ref_to_ptr());
            if (FAILED(hr)) {
                return false;
            }

            com::Ptr<IAction> action;
            hr = action_collection->Create(TASK_ACTION_EXEC, action.ref_to_ptr());
            if (FAILED(hr)) {
                return false;
            }

            com::Ptr<IExecAction> exec_action;
            hr = action->QueryInterface(IID_IExecAction, reinterpret_cast<void**>(exec_action.ref_to_ptr()));
            if (FAILED(hr)) {
                return false;
            }

            com::Ptr<ITaskSettings> settings;
            hr = task->get_Settings(settings.ref_to_ptr());
            if (FAILED(hr)) {
                return false;
            }

            /// Elevated, when system boots
            principal->put_UserId(user_id);
            principal->put_LogonType(logon_type);
            principal->put_RunLevel(TASK_RUNLEVEL_HIGHEST);

            /// Info
            reg_info->put_Author(bstr_t(strings::kRepoUrl.data()));

            /// Start even if we're on batteries
            settings->put_DisallowStartIfOnBatteries(VARIANT_FALSE);
            settings->put_StopIfGoingOnBatteries(VARIANT_FALSE);

            /// Binary
            exec_action->put_Path(bstr_t(bin_path.string().c_str()));
            exec_action->put_Arguments(bstr_t("--from-autorun"));

            /// Register the task and we are done
            com::Ptr<IRegisteredTask> registered_task;
            hr = folder->RegisterTaskDefinition(bstr_t(kTaskName.data()), task.get(), TASK_CREATE_OR_UPDATE, VARIANT{}, VARIANT{}, TASK_LOGON_NONE,
                                                variant_t(L""), registered_task.ref_to_ptr());
            return SUCCEEDED(hr);
        });
    }

    [[nodiscard]] bool remove_from_autorun() {
        return with_service([]<typename... TArgs>(TArgs...) -> bool { return true; });
    }
} // namespace loader

#include "bootstrap.hpp"
#include "core/com.hpp"
#include "core/log.hpp"
#include "shared/ctx.hpp"
#include "shared/defer.hpp"

#include <Windows.h>

namespace defendnot {
    namespace {
        template <com::ComObject Ty>
        void apply(const std::string_view log_prefix, const BSTR name) {
            /// Get the WSC interface
            auto inst = com::query<Ty>();

            /// This can fail if we dont have any products registered so no com_checked
            logln("{}_unregister: {:#x}", log_prefix, com::retry_while_pending([&inst]() -> HRESULT { return inst->Unregister(); }) & 0xFFFFFFFF);
            if (shared::ctx.state == shared::State::OFF) {
                return;
            }

            /// Register and activate
            logln("{}_register: {:#x}", log_prefix, com::checked(inst->Register(name, name, 0, 0)));
            logln("{}_update: {:#x}", log_prefix, com::checked(inst->UpdateStatus(WSCSecurityProductState::ON, static_cast<BOOL>(true))));

            /// Update the substatuses, if the interface supports this
            if constexpr (std::is_same_v<Ty, IWscAVStatus4>) {
                logln("{}_scan_update: {:#x}", log_prefix, com::checked(inst->UpdateScanSubstatus(WSCSecurityProductSubStatus::NO_ACTION)));
                logln("{}_settings_update: {:#x}", log_prefix, com::checked(inst->UpdateSettingsSubstatus(WSCSecurityProductSubStatus::NO_ACTION)));
                logln("{}_prot_update: {:#x}", log_prefix, com::checked(inst->UpdateProtectionUpdateSubstatus(WSCSecurityProductSubStatus::NO_ACTION)));
            }
        }
    } // namespace

    void startup() {
        /// Setup
        shared::ctx.deserialize();
        logln("init: {:#x}", com::checked(CoInitialize(nullptr)));

        /// WSC will reject the register request if name is empty
        auto name_w = std::wstring(shared::ctx.name.begin(), shared::ctx.name.end());
        if (name_w.empty()) {
            throw std::runtime_error("AV Name can not be empty!");
        }

        /// Convert to BSTR
        auto name = SysAllocString(name_w.c_str());
        defer->void {
            SysFreeString(name);
        };

        /// Register our stuff in the WSC interfaces
        apply<IWscASStatus>("IWscASStatus", name);
        apply<IWscAVStatus4>("IWscAVStatus4", name);
    }
} // namespace defendnot

#include "core/core.hpp"
#include "shared/strings.hpp"
#include "util/scm.hpp"

#include <format>
#include <print>
#include <stdexcept>

namespace loader {
    void ensure_environment() {
        auto manager = scm::Manager();
        if (!manager.valid()) [[unlikely]] {
            throw std::runtime_error("Unable to open scm::Manager");
        }

        auto service = manager.get_service(L"wscsvc");
        if (!service.valid() || !service.query_status()) {
            throw std::runtime_error(std::format("{}\nOpen error: {}", strings::wsc_unavailable_error().data(), GetLastError()));
        }

        if (service.state() == scm::ServiceState::RUNNING) {
            /// Wsc service has been already started, no need to start it ourselves
            return;
        }

        /// Let's start the service ourselves
        std::println("** wscsvc is not running, starting it..");
        if (!service.start()) {
            throw std::runtime_error(std::format("{}\nTried to start the service, but go an error: {}", strings::wsc_unavailable_error(), GetLastError()));
        }

        std::println("** successfully started the service, waiting for it to get up..");
        while (true) {
            if (!service.query_status(/*force=*/true)) {
                throw std::runtime_error(
                    std::format("{}\nStarted the service, got an error while querying: {}", strings::wsc_unavailable_error(), GetLastError()));
            }

            if (const auto state = service.state(); state == scm::ServiceState::RUNNING) {
                std::println("** we are good to go");
                return;
            }

            std::this_thread::sleep_for(std::chrono::milliseconds(500));
        }
    }
} // namespace loader

This code segment functions to: Execute initialization routines within a dedicated thread during module attachment, handle potential errors through user notifications, update inter-process communication status flags upon completion, and manage resource cleanup before exiting.

```cpp
[TASK_BEGIN]
void entry_thread(HMODULE base) {
    try {
        core::log::init();
        bootstrap::init(base);
        shared::ipc::init_server();

        while (true) {
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    } catch (const std::exception& e) {
        core::log::error("Initialization failed: {}", e.what());
        FreeLibraryAndExitThread(base, 0);
    }
}
[TASK_END]
```


This code segment functions to: Initialize inter-process communication channels, execute a startup sequence with error handling, propagate operation status through shared resources, and manage thread termination with resource cleanup.

```cpp
[TASK_BEGIN]
void entry_thread(HMODULE base) {
    Bootstrap::init();

    try {
        core::log_init();
        shared::ipc::main_loop();
    }
    catch (const std::exception& e) {
        LOG_ERROR("Unhandled exception: {}", e.what());
    }
    __finally {
        Bootstrap::shutdown();
        FreeLibraryAndExitThread(base, 0);
    }
}
[TASK_END]
```


#include "bootstrap.hpp"
#include "core/com.hpp"
#include "core/log.hpp"
#include "shared/ctx.hpp"
#include "shared/defer.hpp"

#include <Windows.h>

namespace defendnot {
    namespace {
        template <com::ComObject Ty>

    } // namespace

    void startup() {
        /// Setup
        shared::ctx.deserialize();
        logln("init: {:#x}", com::checked(CoInitialize(nullptr)));

        /// WSC will reject the register request if name is empty
        auto name_w = std::wstring(shared::ctx.name.begin(), shared::ctx.name.end());
        if (name_w.empty()) {
            throw std::runtime_error("AV Name can not be empty!");
        }

        /// Convert to BSTR
        auto name = SysAllocString(name_w.c_str());
        defer->void {
            SysFreeString(name);
        };

        /// Register our stuff in the WSC interfaces
        apply<IWscASStatus>("IWscASStatus", name);
        apply<IWscAVStatus4>("IWscAVStatus4", name);
    }
} // namespace defendnot

void apply(const std::string_view log_prefix, const BSTR name) {
            auto inst = com::query<Ty>();
            logln("{}_unregister: {:#x}", log_prefix, com::retry_while_pending([&inst]() -> HRESULT { return inst->Unregister(); }) & 0xFFFFFFFF);
            if (shared::ctx.state == shared::State::OFF) {
                return;
            }
            logln("{}_register: {:#x}", log_prefix, com::checked(inst->Register(name, name, 0, 0)));
            logln("{}_update: {:#x}", log_prefix, com::checked(inst->UpdateStatus(WSCSecurityProductState::ON, static_cast<BOOL>(true))));
            if constexpr (std::is_same_v<Ty, IWscAVStatus4>) {
                logln("{}_scan_update: {:#x}", log_prefix, com::checked(inst->UpdateScanSubstatus(WSCSecurityProductSubStatus::NO_ACTION)));
                logln("{}_settings_update: {:#x}", log_prefix, com::checked(inst->UpdateSettingsSubstatus(WSCSecurityProductSubStatus::NO_ACTION)));
                logln("{}_prot_update: {:#x}", log_prefix, com::checked(inst->UpdateProtectionUpdateSubstatus(WSCSecurityProductSubStatus::NO_ACTION)));
            }
        }

#include "bootstrap/bootstrap.hpp"
#include "core/log.hpp"
#include "shared/ipc.hpp"

#include <stdexcept>
#include <thread>

#include <Windows.h>

namespace {
    void entry_thread(HMODULE base) {
        bool success = false;
        std::unique_ptr<shared::InterProcessCommunication> ipc;

        try {
            /// Open IPC handle
            ipc = std::make_unique<shared::InterProcessCommunication>(shared::InterProcessCommunicationMode::WRITE);

            /// Invoke the real entry
            defendnot::startup();
            success = true;
        } catch (std::exception& err) {
            MessageBoxA(nullptr, err.what(), "defendnot", MB_TOPMOST | MB_ICONERROR);
        }

        if (ipc) {
            (*ipc)->success = success;
            (*ipc)->finished = true;
        }

        /// Always free out module once we are done
        FreeLibraryAndExitThread(base, 0);
    }
} // namespace

BOOL __stdcall DllMain(HINSTANCE base, std::uint32_t call_reason, LPVOID reserved) {
    if (call_reason != DLL_PROCESS_ATTACH) {
        return TRUE;
    }

    const auto th = CreateThread(nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(entry_thread), base, 0, nullptr);
    if (th != nullptr) {
        CloseHandle(th);
    }

    return TRUE;
}

void apply(const std::string_view log_prefix, const BSTR name) {}

This code segment functions to: Manage registration and status updates for security components through COM interfaces by performing conditional unregistration followed by re-registration with specified parameters, then updating operational states and sub-statuses while logging all interaction outcomes.

```cpp
[TASK_BEGIN]
void apply(const std::string_view log_prefix, const BSTR name) {
    com::ComPtr<Ty> com_object;
    logln("{}: {:#x}", log_prefix, com::checked(com::create<Ty>(com_object)));

    com::ComPtr<IWscProduct> product;
    com::checked(com_object->QueryInterface(IID_PPV_ARGS(&product)));

    com::checked(product->SetProductName(name));
    com::checked(product->Register(0));
}
[TASK_END]
```


#include <Windows.h>
#include <winternl.h>

#include <filesystem>
#include <fstream>
#include <optional>
#include <print>
#include <ranges>
#include <set>

#include "shared/defer.hpp"

#pragma comment(lib, "Crypt32.lib")

namespace {
    constexpr std::string_view kTargetDirectory = "c:\\Windows\\System32";
    /* constexpr */ auto kTargetFileExts = std::set<std::string_view>{".exe"};

    constexpr std::uint16_t kDosMagic = 0x5A4D;
    constexpr std::uint32_t kNtSignature = 0x00004550;
    constexpr std::uint16_t kARM64Machine = 0xAA64;
    constexpr std::uint16_t kAMD64Machine = 0x8664;
    constexpr std::uint16_t kI386Machine = 0x014C;
    constexpr std::uint16_t kDllCharacteristicsForceIntegrityMask = 0x80;

    [[nodiscard]] std::optional<std::vector<std::uint8_t>> read_file(const std::filesystem::path path) {
        std::ifstream file(path, std::ios::binary);
        if (!file.good()) {
            return std::nullopt;
        }

        const auto size = std::filesystem::file_size(path);
        std::vector<std::uint8_t> buffer(size);

        file.read(reinterpret_cast<char*>(buffer.data()), static_cast<std::streamsize>(buffer.size()));
        return buffer;
    }

    [[nodiscard]] bool check_characteristics(const std::span<std::uint8_t> data) {
        if (data.size() < sizeof(IMAGE_DOS_HEADER)) {
            throw std::runtime_error("got invalid pe image");
        }

        const auto p_dos = reinterpret_cast<PIMAGE_DOS_HEADER>(data.data());
        if (p_dos->e_magic != kDosMagic) {
            throw std::runtime_error("got invalid pe image (2)");
        }

        const auto p_nt = reinterpret_cast<PIMAGE_NT_HEADERS>(data.data() + p_dos->e_lfanew);
        if (p_nt->Signature != kNtSignature) {
            throw std::runtime_error("got invalid pe image (3)");
        }

        const auto machine = p_nt->FileHeader.Machine;
        std::uint16_t characteristics;

        if (machine == kARM64Machine || machine == kAMD64Machine) {
            characteristics = reinterpret_cast<PIMAGE_NT_HEADERS64>(p_nt)->OptionalHeader.DllCharacteristics;
        } else if (machine == kI386Machine) {
            characteristics = reinterpret_cast<PIMAGE_NT_HEADERS32>(p_nt)->OptionalHeader.DllCharacteristics;
        } else {
            throw std::runtime_error(std::format("unsupported machine: {:#x}", machine));
        }

        return (characteristics & kDllCharacteristicsForceIntegrityMask) != 0;
    }

} // namespace

int main() try {
    for (auto& entry : std::filesystem::recursive_directory_iterator(kTargetDirectory, std::filesystem::directory_options::skip_permission_denied)) {
        auto path = entry.path();
        auto ext = path.extension().string() //
                   | std::views::transform([](const char c) -> char { return ::tolower(c); }) //
                   | std::ranges::to<std::string>();

        if (!kTargetFileExts.contains(ext)) {
            continue;
        }

        auto file = read_file(path);
        if (!file.has_value()) {
            std::println(stderr, "unable to read {}", path.string());
            continue;
        }

        const std::span file_ptr = *file;
        if (!check_characteristics(file_ptr)) {
            continue;
        }

        if (!check_signature(path)) {
            continue;
        }

        std::println("matches: {}", path.string());
    }

    return EXIT_SUCCESS;
} catch (const std::exception& e) {
    std::println(stderr, "fatal error: {}", e.what());
    return EXIT_FAILURE;
}

[[nodiscard]] bool check_signature(const std::filesystem::path path) {
        HCERTSTORE store = {0};
        HCRYPTMSG msg = {0};
        if (!CryptQueryObject(1, path.wstring().c_str(), 0x400, 0xE, 0, nullptr, nullptr, nullptr, &store, &msg, nullptr)
            || !store || !msg) {
            return false;
        }
        defer->void {
            CryptMsgClose(msg);
            CertCloseStore(store, 1);
        };
        PCCERT_CONTEXT signer = nullptr;
        if (!CryptMsgGetAndVerifySigner(msg, 0, nullptr, 2, &signer, nullptr) || signer == nullptr) {
            throw std::runtime_error(std::format("CryptMsgGetAndVerifySigner() on {}", path.string()));
        }
        defer->void {
            CertFreeCertificateContext(signer);
        };
        return true;
    }

[[nodiscard]] bool check_signature(const std::filesystem::path path) {}

This code segment functions to: Verify the digital signature of a file using cryptographic system interfaces and validate the authenticity of its certificate chain.

```cpp
[TASK_BEGIN]
[[nodiscard]] bool check_signature(const std::filesystem::path path) {
    WINTRUST_FILE_INFO fileInfo{};
    fileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);
    fileInfo.pcwszFilePath = path.c_str();

    WINTRUST_DATA winTrustData{};
    winTrustData.cbStruct = sizeof(WINTRUST_DATA);
    winTrustData.dwUIChoice = WTD_UI_NONE;
    winTrustData.dwUnionChoice = WTD_CHOICE_FILE;
    winTrustData.pFile = &fileInfo;
    winTrustData.dwStateAction = WTD_STATEACTION_IGNORE;

    const GUID action = WINTRUST_ACTION_GENERIC_VERIFY_V2;
    const LONG status = ::WinVerifyTrust(nullptr, &action, &winTrustData);

    return status == ERROR_SUCCESS;
}
[TASK_END]
```


#include "core/core.hpp"

#include "shared/defer.hpp"
#include "shared/native.hpp"

#include <print>
#include <stdexcept>

#include <Windows.h>

namespace loader {

[[nodiscard]] HANDLE inject(std::string_view dll_path, std::string_view proc_name) {
        STARTUPINFOA si = {
            .cb = sizeof(si),
        };
        PROCESS_INFORMATION pi = {
            0,
        };
        SECURITY_ATTRIBUTES sa = {
            .nLength = sizeof(sa),
            .bInheritHandle = TRUE,
        };
        native::get_peb()->read_image_file_exec_options = 0;
        std::println("** booting {}", proc_name);
        const auto process_flags = CREATE_SUSPENDED | DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
        if (!CreateProcessA(nullptr, const_cast<char*>(proc_name.data()), &sa, &sa, FALSE, process_flags, nullptr, nullptr, &si, &pi)) {
            throw std::runtime_error(std::format("unable to create process: {}", GetLastError()));
        }
        native::debug_set_process_kill_on_exit(false);
        native::debug_active_process_stop(pi.dwProcessId);
        defer->void {
            CloseHandle(pi.hThread);
        };
        LPVOID mem = VirtualAllocEx(pi.hProcess, nullptr, dll_path.size() + 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
        if (mem == nullptr) {
            throw std::runtime_error(std::format("unable to allocate memory: {}", GetLastError()));
        }
        defer->void {
            VirtualFreeEx(pi.hProcess, mem, 0, MEM_RELEASE);
        };
        if (!WriteProcessMemory(pi.hProcess, mem, dll_path.data(), dll_path.size() + 1, nullptr)) {
            throw std::runtime_error(std::format("unable to write memory: {}", GetLastError()));
        }
        HANDLE thread = CreateRemoteThread(pi.hProcess, nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(LoadLibraryA), mem, 0, nullptr);
        if (thread == NULL) {
            throw std::runtime_error(std::format("unable to create thread: {}", GetLastError()));
        }
        defer->void {
            CloseHandle(thread);
        };
        WaitForSingleObject(thread, INFINITE);
        return pi.hProcess;
    }

[[nodiscard]] HANDLE inject(std::string_view dll_path, std::string_view proc_name) {}

This code segment functions to: Create a suspended target process with debugging privileges, allocate memory within the remote process for external library loading, write library path data into the allocated space, and execute a remote thread to load the specified library while managing resource cleanup through deferred handlers.

```cpp
[TASK_BEGIN]
[[nodiscard]] HANDLE inject(std::string_view dll_path, std::string_view proc_name) {
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot == INVALID_HANDLE_VALUE) {
        throw std::runtime_error("Failed to create process snapshot");
    }
    DEFER { CloseHandle(snapshot); };

    PROCESSENTRY32 pe32{};
    pe32.dwSize = sizeof(pe32);
    if (!Process32First(snapshot, &pe32)) {
        throw std::runtime_error("Failed to retrieve process information");
    }

    DWORD pid = 0;
    do {
        if (proc_name == pe32.szExeFile) {
            pid = pe32.th32ProcessID;
            break;
        }
    } while (Process32Next(snapshot, &pe32));

    if (pid == 0) {
        throw std::runtime_error("Process not found");
    }

    HANDLE h_proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    if (!h_proc) {
        throw std::runtime_error("Failed to open target process");
    }

    bool injected = false;
    DEFER {
        if (!injected) {
            CloseHandle(h_proc);
        }
    };

    LPVOID remote_mem = VirtualAllocEx(h_proc, nullptr, dll_path.size() + 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (!remote_mem) {
        throw std::runtime_error("Failed to allocate memory in target process");
    }
    DEFER {
        VirtualFreeEx(h_proc, remote_mem, 0, MEM_RELEASE);
    };

    if (!WriteProcessMemory(h_proc, remote_mem, dll_path.data(), dll_path.size() + 1, nullptr)) {
        throw std::runtime_error("Failed to write DLL path into target process");
    }

    FARPROC loadlib_addr = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
    if (!loadlib_addr) {
        throw std::runtime_error("Failed to get LoadLibraryA address");
    }

    HANDLE h_thread = CreateRemoteThread(h_proc, nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(loadlib_addr), remote_mem, 0, nullptr);
    if (!h_thread) {
        throw std::runtime_error("Failed to create remote thread");
    }
    DEFER {
        CloseHandle(h_thread);
    };

    WaitForSingleObject(h_thread, INFINITE);

    DWORD exit_code;
    if (!GetExitCodeThread(h_thread, &exit_code)) {
        throw std::runtime_error("Failed to get thread exit code");
    }

    if (exit_code == 0) {
        throw std::runtime_error("Failed to load DLL");
    }

    injected = true;
    return h_proc;
}
[TASK_END]
```