C++ HWBP rotation hook (experimental code)

Пользователь
Пользователь
Статус
Оффлайн
Регистрация
3 Янв 2020
Сообщения
153
Реакции
164
Hey everyone been experimenting with different hooking techniques. One approach I explored was using hardware breakpoints (HWBP). They work well but are limited to four slots so been working out ways have more then 4

This code was one of my early attempts. I’ve since moved on to a better solution, but the experiment taught me a stuff so I’m sharing it for anyone who wants to learn. There are alternative strategies for example rotating HWBP acroos your hook targets but they can miss a call if the game runs one of the tagets but they in the rotation list

so i got a different idea: instead of always keeping breakpoints active, detect when the game is about to call the target and then redirect at that moment. The code below is an older attempt at that approach. I’ve implemented a completely new system that works much better now, but this earlier version provided useful insights and debugging lessons, so I thought I’d post it for others interested, there is some slight changes and removed code, for private reasons

ps you need a decoder but you can use my public ones

exampe image, of my current one i have running 9 hooks atm all work fine and correct none misses the calls all hwbp, tho framestage disabled atm due to bug with getting address
here a video to show a completed hwbp hook working while in game no chams flicker etc or lag, fixed my decoder :)
Пожалуйста, авторизуйтесь для просмотра ссылки.


d7DOjxj.jpeg


C++:
Expand Collapse Copy
namespace utils::hwbp
{
    constexpr int MAX_HWBP = 4;

    class hwbp_manager;

    template <typename T>
    class hwbp_hook final : public hook_interface {
    public:
        uintptr_t get_target() const override {
            return reinterpret_cast<uintptr_t>(m_resolved_target_address);
        }

        uintptr_t get_endpoint() const override {
            return reinterpret_cast<uintptr_t>(m_detour_address);
        }

        uintptr_t get_resolved_target_address() const override {
            return reinterpret_cast<uintptr_t>(m_resolved_target_address);
        }

        bool use_pure_hwbp_mode() const { return m_pure_hwbp_mode; }
        void set_pure_hwbp_mode(bool enable) { m_pure_hwbp_mode = enable; }

        explicit hwbp_hook(void* target, void* detour, const DataStorage::library& module_lib, bool pure_mode = false)
            : m_original_target_address(target), m_detour_address(detour),
            m_module_library(module_lib), m_pure_hwbp_mode(pure_mode)
        {
            m_resolved_target_address = decoder::resolve_jump_thunk(static_cast<uint8_t*>(m_original_target_address));
            log_debug(tfm::format("[HWBP] Hook created: Original=0x%p, Resolved=0x%p, Pure=%d",
                m_original_target_address, m_resolved_target_address, pure_mode));
        }

        ~hwbp_hook() {
            if (m_trampoline_address) {
                VirtualFree(m_trampoline_address, 0, MEM_RELEASE);
                m_trampoline_address = nullptr;
            }
        }

        void attach() override {}
        void detach() override {}

        T* get_original() const { return reinterpret_cast<T*>(m_trampoline_address); }

        template<typename... A>
        auto call(A... args) const -> decltype(get_original()(args...))
        {
            auto original_fn = get_original();
            if (!original_fn)
                throw std::runtime_error("Original function pointer is null for HWBP hook");
            return original_fn(args...);
        }

        bool create_trampoline()
        {
            constexpr size_t MIN_COPY_SIZE = 14;
            size_t copied_bytes = 0;
            std::vector<decoder::Instruction> instructions;

            uint8_t* current_addr = static_cast<uint8_t*>(m_resolved_target_address);

            // SAFETY: Verify target is readable
            MEMORY_BASIC_INFORMATION mbi;
            if (!VirtualQuery(current_addr, &mbi, sizeof(mbi)) ||
                !(mbi.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY))) {
                log_debug(tfm::format("[HWBP] Target 0x%p is not executable", current_addr));
                return false;
            }

            while (copied_bytes < MIN_COPY_SIZE) {
                decoder::Instruction inst;
                if (!decoder::decode_instruction(current_addr, 15, inst) || inst.length == 0) {
                    log_debug(tfm::format("[HWBP] Failed to decode at 0x%p", current_addr));
                    return false;
                }

                // SAFETY: Don't copy instructions that can't be relocated
                if (inst.length > 15) {
                    log_debug("[HWBP] Instruction too long to relocate");
                    return false;
                }

                instructions.push_back(inst);
                copied_bytes += inst.length;
                current_addr += inst.length;
            }

            constexpr size_t JMP_SIZE = 14;
            size_t trampoline_size = copied_bytes + JMP_SIZE + 16; // +16 padding for alignment

            m_trampoline_address = VirtualAlloc(nullptr, trampoline_size,
                MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
            if (!m_trampoline_address) {
                log_debug("[HWBP] Failed to allocate trampoline");
                return false;
            }

            // SAFETY: Zero out trampoline
            memset(m_trampoline_address, 0xCC, trampoline_size);

            uint8_t* tramp_ptr = static_cast<uint8_t*>(m_trampoline_address);
            uint8_t* orig_ptr = static_cast<uint8_t*>(m_resolved_target_address);

            for (const auto& inst : instructions) {
                uint64_t orig_addr = reinterpret_cast<uint64_t>(orig_ptr);
                uint64_t tramp_addr = reinterpret_cast<uint64_t>(tramp_ptr);

                if (!decoder::relocate_instruction(inst, tramp_ptr, orig_addr, tramp_addr)) {
                    VirtualFree(m_trampoline_address, 0, MEM_RELEASE);
                    m_trampoline_address = nullptr;
                    log_debug(tfm::format("[HWBP] Failed to relocate instruction at 0x%p", orig_ptr));
                    return false;
                }

                tramp_ptr += inst.length;
                orig_ptr += inst.length;
            }

            uint8_t* return_addr = static_cast<uint8_t*>(m_resolved_target_address) + copied_bytes;
            decoder::write_absolute_jump(tramp_ptr, return_addr);

            // SAFETY: Flush instruction cache
            FlushInstructionCache(GetCurrentProcess(), m_trampoline_address, trampoline_size);

            log_debug(tfm::format("[HWBP] Trampoline: 0x%p -> 0x%p, %d bytes, returns to 0x%p",
                m_resolved_target_address, m_trampoline_address, copied_bytes, return_addr));
            return true;
        }

        void* m_original_target_address;
        void* m_resolved_target_address;
        void* m_detour_address;
        void* m_trampoline_address = nullptr;
        DataStorage::library m_module_library;
        bool m_pure_hwbp_mode = false;
    };

    class hwbp_manager
    {
    public:
        static hwbp_manager& get() {
            static hwbp_manager instance;
            return instance;
        }

        void init() {
            if (!m_veh_handle) {
                m_veh_handle = AddVectoredExceptionHandler(0, VectoredExceptionHandler);
            }
            if (!m_rearm_thread.joinable()) {
                m_shutdown_flag = false;
                m_rearm_thread = std::thread(&hwbp_manager::rearm_thread_func, this);
                SetThreadPriority(m_rearm_thread.native_handle(), THREAD_PRIORITY_ABOVE_NORMAL);
            }
            m_initialized = true;
        }

        template <typename T>
        bool create_hook(std::shared_ptr<hwbp_hook<T>>& entry, void* target, T* detour, const DataStorage::library& module_lib, bool pure_hwbp_mode = false)
        {
            auto ptr = std::make_shared<hwbp_hook<T>>(target, reinterpret_cast<void*>(detour), module_lib, pure_hwbp_mode);
            if (!ptr || !ptr->create_trampoline())
                return false;

            if (set_hook_internal(std::static_pointer_cast<hook_interface>(ptr))) {
                entry = ptr;
                return true;
            }
            return false;
        }

        void activate_all_pending_hooks() {
            std::lock_guard<std::mutex> lock(m_hooks_mutex);
            for (auto& hook : m_pending_hooks) {
                set_hook_internal(hook);
            }
            m_pending_hooks.clear();
        }

        void shutdown() {
            m_initialized = false;
            m_shutdown_flag = true;
            m_rearm_cv.notify_one();

            if (m_rearm_thread.joinable()) {
                m_rearm_thread.join();
            }

            if (m_veh_handle) {
                RemoveVectoredExceptionHandler(m_veh_handle);
                m_veh_handle = nullptr;
            }

            std::lock_guard<std::mutex> lock(m_hooks_mutex);
            clear_all_hooks_internal();
        }

    private:
        hwbp_manager() = default;
        ~hwbp_manager() { shutdown(); }

        std::vector<std::shared_ptr<hook_interface>> m_pending_hooks;
        std::atomic<bool> m_initialized{ false };

        std::unordered_map<void*, std::shared_ptr<hook_interface>> m_hooks;
        std::unordered_map<uintptr_t, std::vector<hook_interface*>> m_page_hooks;
        std::unordered_map<uintptr_t, DWORD> m_original_protections;
        std::unordered_map<uintptr_t, std::atomic_flag> m_page_rearm_locks;

        std::unordered_set<uintptr_t> m_blacklisted_addresses;
        std::unordered_set<uintptr_t> m_blacklisted_pages;
        std::atomic<size_t> m_total_page_guards{ 0 };
        std::atomic<size_t> m_ignored_page_guards{ 0 };

        std::unordered_map<void*, hook_interface*> m_pure_hwbp_hooks;
        static inline thread_local std::array<hook_interface*, MAX_HWBP> tls_pure_hwbp_slots{};

        struct PageHookCache {
            hook_interface* hooks[16];
            uint8_t count;
        };
        std::unordered_map<uintptr_t, PageHookCache> m_page_hook_cache;

        struct OneShotState {
            uintptr_t hook_target;
            hook_interface* hook_ptr;
            uint8_t dr_index;
        };
        static inline thread_local std::array<OneShotState, MAX_HWBP> tls_one_shots{};
        static inline thread_local hook_interface* tls_last_detour_hook = nullptr;
        static inline thread_local uint8_t tls_dr_mask = 0;

        static inline thread_local uintptr_t tls_last_page_guard = 0;

        std::mutex m_hooks_mutex;
        PVOID m_veh_handle = nullptr;

        std::set<uintptr_t> m_pages_to_rearm;
        std::mutex m_rearm_mutex;
        std::condition_variable m_rearm_cv;
        std::thread m_rearm_thread;
        std::atomic<bool> m_shutdown_flag{ false };

        static uintptr_t get_page_base(void* address) {
            return reinterpret_cast<uintptr_t>(address) & ~0xFFF;
        }

        static LONG NTAPI VectoredExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
            return get().ExceptionHandler(ExceptionInfo);
        }

        LONG NTAPI ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
            const DWORD exception_code = ExceptionInfo->ExceptionRecord->ExceptionCode;

            if (exception_code != STATUS_SINGLE_STEP && exception_code != STATUS_GUARD_PAGE_VIOLATION) {
                return EXCEPTION_CONTINUE_SEARCH;
            }

            const PCONTEXT ctx = ExceptionInfo->ContextRecord;
            void* exception_addr = ExceptionInfo->ExceptionRecord->ExceptionAddress;

            if (exception_code == STATUS_SINGLE_STEP) {
                const DWORD64 dr6 = ctx->Dr6;
                const uint8_t triggered_mask = static_cast<uint8_t>(dr6 & 0xF);

                if (!triggered_mask) {
                    ctx->EFlags &= ~0x100;
                    return EXCEPTION_CONTINUE_EXECUTION;
                }

                // Find which DR triggered
                int triggered_dr = 0;
                if (triggered_mask & 1) triggered_dr = 0;
                else if (triggered_mask & 2) triggered_dr = 1;
                else if (triggered_mask & 4) triggered_dr = 2;
                else if (triggered_mask & 8) triggered_dr = 3;

                // Check pure HWBP mode
                hook_interface* pure_hook = tls_pure_hwbp_slots[triggered_dr];
                if (pure_hook) {
                    ctx->Dr6 = 0;
                    ctx->EFlags &= ~0x100;
                    ctx->Rip = pure_hook->get_endpoint();
                    log_debug(tfm::format("[HWBP] Pure mode redirect 0x%p -> 0x%p",
                        pure_hook->get_target(), pure_hook->get_endpoint()));
                    return EXCEPTION_CONTINUE_EXECUTION;
                }

                OneShotState& one_shot = tls_one_shots[triggered_dr];

                if (one_shot.hook_target && one_shot.hook_ptr) {
                    hook_interface* hook = one_shot.hook_ptr;

                    // Validate detour
                    const uintptr_t detour_addr = hook->get_endpoint();
                    MEMORY_BASIC_INFORMATION mbi;
                    if (!VirtualQuery(reinterpret_cast<void*>(detour_addr), &mbi, sizeof(mbi)) ||
                        !(mbi.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY))) {
                        log_debug(tfm::format("[HWBP] Invalid detour address 0x%p", detour_addr));
                        one_shot.hook_target = 0;
                        one_shot.hook_ptr = nullptr;
                        ctx->EFlags &= ~0x100;
                        return EXCEPTION_CONTINUE_EXECUTION;
                    }

                    const uintptr_t saved_target = one_shot.hook_target;
                    one_shot.hook_target = 0;
                    one_shot.hook_ptr = nullptr;

                    // Clear DR state
                    ctx->Dr6 = 0;
                    (&ctx->Dr0)[triggered_dr] = 0;
                    const uint64_t dr7_clear = ~((3ULL << (triggered_dr * 2)) | (0xFULL << (16 + triggered_dr * 4)));
                    ctx->Dr7 &= dr7_clear;
                    tls_dr_mask &= ~(1u << triggered_dr);

                    // Redirect
                    ctx->EFlags &= ~0x100;
                    ctx->Rip = detour_addr;
                    tls_last_detour_hook = hook;

                    log_debug(tfm::format("[HWBP] Redirecting 0x%p -> 0x%p", saved_target, detour_addr));

                    // CRITICAL: Restore PAGE_GUARD immediately
                    const uintptr_t page_base = get_page_base(reinterpret_cast<void*>(saved_target));

                    // Safe to access m_original_protections here without lock
                    // because pages are only added/removed during hook creation/destruction
                    auto it = m_original_protections.find(page_base);
                    if (it != m_original_protections.end()) {
                        DWORD old_protect;
                        DWORD original_protect = it->second;

                        if (VirtualProtect(reinterpret_cast<void*>(page_base), 0x1000,
                            original_protect | PAGE_GUARD, &old_protect)) {
                            log_debug(tfm::format("[HWBP] PAGE_GUARD restored after redirect (0x%p: 0x%X)",
                                page_base, original_protect | PAGE_GUARD));
                        }
                        else {
                            log_debug(tfm::format("[HWBP] FAILED to restore PAGE_GUARD: error %d", GetLastError()));
                        }
                    }
                    else {
                        log_debug(tfm::format("[HWBP] Page 0x%p not in protections map", page_base));
                    }

                    return EXCEPTION_CONTINUE_EXECUTION;
                }

                ctx->EFlags &= ~0x100;
                return EXCEPTION_CONTINUE_EXECUTION;
            }

            // STATUS_GUARD_PAGE_VIOLATION
            {
                const uintptr_t page_base = get_page_base(exception_addr);
                const uintptr_t exception_addr_int = reinterpret_cast<uintptr_t>(exception_addr);

                // OPTIMIZATION: Thread-local blacklist cache
                static thread_local std::unordered_set<uintptr_t> tls_blacklisted_cache;

                if (tls_blacklisted_cache.count(exception_addr_int)) {
                    // Fast path: Already know this is blacklisted, just restore PAGE_GUARD
                    auto prot_it = m_original_protections.find(page_base);
                    if (prot_it != m_original_protections.end()) {
                        DWORD old_protect;
                        VirtualProtect(reinterpret_cast<void*>(page_base), 0x1000,
                            prot_it->second | PAGE_GUARD, &old_protect);
                    }
                    return EXCEPTION_CONTINUE_EXECUTION;
                }

                log_debug(tfm::format("[HWBP] PAGE_GUARD at 0x%p (page 0x%p)", exception_addr_int, page_base));

                std::lock_guard<std::mutex> lock(m_hooks_mutex);

                // Check global blacklist (might have been added by another thread)
                if (m_blacklisted_addresses.count(exception_addr_int)) {
                    tls_blacklisted_cache.insert(exception_addr_int); // Cache locally
                    auto prot_it = m_original_protections.find(page_base);
                    if (prot_it != m_original_protections.end()) {
                        DWORD old_protect;
                        VirtualProtect(reinterpret_cast<void*>(page_base), 0x1000,
                            prot_it->second | PAGE_GUARD, &old_protect);
                    }
                    return EXCEPTION_CONTINUE_EXECUTION;
                }

                // Check if this is a hook target
                auto hook_it = m_hooks.find(exception_addr);

                if (hook_it == m_hooks.end()) {
                    // Not a hook - track noise level PER ADDRESS
                    static std::unordered_map<uintptr_t, uint32_t> address_noise_counter;
                    uint32_t& noise_count = address_noise_counter[exception_addr_int];
                    noise_count++;

                    // BLACKLIST this specific address if too noisy (>10 hits)
                    if (noise_count > 10) {
                        m_blacklisted_addresses.insert(exception_addr_int);
                        tls_blacklisted_cache.insert(exception_addr_int); // Cache immediately

                        log_debug(tfm::format("[HWBP] BLACKLISTED noisy address 0x%p (hit %d times, page 0x%p still active)",
                            exception_addr_int, noise_count, page_base));
                    }
                    else {
                        log_debug(tfm::format("[HWBP] Ignoring non-hook 0x%p (count: %d)",
                            exception_addr_int, noise_count));
                    }

                    // Always restore PAGE_GUARD so other hooks on this page work
                    auto prot_it = m_original_protections.find(page_base);
                    if (prot_it != m_original_protections.end()) {
                        DWORD old_protect;
                        VirtualProtect(reinterpret_cast<void*>(page_base), 0x1000,
                            prot_it->second | PAGE_GUARD, &old_protect);
                    }

                    return EXCEPTION_CONTINUE_EXECUTION;
                }

                hook_interface* matching_hook = hook_it->second.get();

                // Check if we're on return path
                if (tls_last_detour_hook != nullptr) {
                    log_debug("[HWBP] Return path - restoring PAGE_GUARD");
                    tls_last_detour_hook = nullptr;
                    tls_last_page_guard = 0;

                    auto prot_it = m_original_protections.find(page_base);
                    if (prot_it != m_original_protections.end()) {
                        DWORD old_protect;
                        VirtualProtect(reinterpret_cast<void*>(page_base), 0x1000,
                            prot_it->second | PAGE_GUARD, &old_protect);
                        log_debug(tfm::format("[HWBP] PAGE_GUARD restored on return path (page 0x%p)", page_base));
                    }

                    return EXCEPTION_CONTINUE_EXECUTION;
                }

                // Find available DR
                int dr_index = -1;
                if (!(tls_dr_mask & 1)) { dr_index = 0; tls_dr_mask |= 1; }
                else if (!(tls_dr_mask & 2)) { dr_index = 1; tls_dr_mask |= 2; }
                else if (!(tls_dr_mask & 4)) { dr_index = 2; tls_dr_mask |= 4; }
                else if (!(tls_dr_mask & 8)) { dr_index = 3; tls_dr_mask |= 8; }

                if (dr_index == -1) {
                    log_debug("[HWBP] All DRs in use");

                    auto prot_it = m_original_protections.find(page_base);
                    if (prot_it != m_original_protections.end()) {
                        DWORD old_protect;
                        VirtualProtect(reinterpret_cast<void*>(page_base), 0x1000,
                            prot_it->second | PAGE_GUARD, &old_protect);
                    }

                    return EXCEPTION_CONTINUE_EXECUTION;
                }

                // Set HWBP
                (&ctx->Dr0)[dr_index] = exception_addr_int;
                ctx->Dr7 |= (1ULL << (dr_index * 2));
                ctx->Dr7 &= ~(0xFULL << (16 + dr_index * 4));

                tls_one_shots[dr_index] = { exception_addr_int, matching_hook, static_cast<uint8_t>(dr_index) };
                ctx->Dr6 = 0;
                tls_last_page_guard = page_base;

                log_debug(tfm::format("[HWBP] Set Dr%d = 0x%p", dr_index, exception_addr_int));

                // DON'T restore PAGE_GUARD yet - let HWBP trigger first
                return EXCEPTION_CONTINUE_EXECUTION;
            }

            return EXCEPTION_CONTINUE_SEARCH;
        }

        // Helper function to restore PAGE_GUARD
        void restore_page_guard(uintptr_t page_base) {
            // Must be called with m_hooks_mutex locked OR from single-step handler

            auto it = m_original_protections.find(page_base);
            if (it == m_original_protections.end()) {
                log_debug(tfm::format("[HWBP] Cannot restore PAGE_GUARD: page 0x%p not tracked", page_base));
                return;
            }

            DWORD old_protect;
            DWORD original_protect = it->second;

            if (VirtualProtect(reinterpret_cast<void*>(page_base), 0x1000,
                original_protect | PAGE_GUARD, &old_protect)) {
                log_debug(tfm::format("[HWBP] PAGE_GUARD restored for page 0x%p (protect: 0x%X -> 0x%X)",
                    page_base, old_protect, original_protect | PAGE_GUARD));
            }
            else {
                DWORD error = GetLastError();
                log_debug(tfm::format("[HWBP] FAILED to restore PAGE_GUARD for 0x%p: error %d", page_base, error));

                // Try to diagnose
                MEMORY_BASIC_INFORMATION mbi;
                if (VirtualQuery(reinterpret_cast<void*>(page_base), &mbi, sizeof(mbi))) {
                    log_debug(tfm::format("[HWBP] Page state: Base=0x%p, Size=0x%X, Protect=0x%X, State=0x%X",
                        mbi.BaseAddress, mbi.RegionSize, mbi.Protect, mbi.State));
                }
            }
        }

        void clear_all_hooks_internal();
        bool set_hook_internal(std::shared_ptr<hook_interface> hook_ptr);
        void rearm_thread_func();
    };

    inline void hwbp_manager::rearm_thread_func() {
        std::vector<uintptr_t> pages_to_process;
        pages_to_process.reserve(64);

        while (!m_shutdown_flag) {
            {
                std::unique_lock<std::mutex> lock(m_rearm_mutex);

                // IMMEDIATE re-arm (no timeout) for time-sensitive hooks
                m_rearm_cv.wait(lock, [this] { return !m_pages_to_rearm.empty() || m_shutdown_flag; });

                if (m_shutdown_flag && m_pages_to_rearm.empty()) {
                    break;
                }

                pages_to_process.assign(m_pages_to_rearm.begin(), m_pages_to_rearm.end());
                m_pages_to_rearm.clear();
            }

            for (uintptr_t page_base : pages_to_process) {
                if (!m_page_rearm_locks[page_base].test_and_set(std::memory_order_acquire)) {
                    DWORD old_protect;
                    DWORD original_protect = m_original_protections[page_base];

                    // Single VirtualProtect call// change to syscall
                    if (VirtualProtect(reinterpret_cast<void*>(page_base), 0x1000,
                        original_protect | PAGE_GUARD, &old_protect)) {
                    }

                    m_page_rearm_locks[page_base].clear(std::memory_order_release);
                }
            }
            pages_to_process.clear();
        }
    }

    inline bool hwbp_manager::set_hook_internal(std::shared_ptr<hook_interface> hook_ptr)
    {
        std::lock_guard<std::mutex> lock(m_hooks_mutex);
        if (!hook_ptr)
            return false;

        auto* hook_base = hook_ptr.get();
        uintptr_t target = hook_base->get_resolved_target_address();

        if (m_hooks.count(reinterpret_cast<void*>(target))) return false;

        m_hooks[reinterpret_cast<void*>(target)] = hook_ptr;

        uintptr_t page_base = get_page_base(reinterpret_cast<void*>(target));
        m_page_hooks[page_base].push_back(hook_base);

        auto& cache = m_page_hook_cache[page_base];
        if (cache.count < 16) {
            cache.hooks[cache.count++] = hook_base;
        }

        if (!m_original_protections.count(page_base)) {
            MEMORY_BASIC_INFORMATION mbi;
            if (VirtualQuery(reinterpret_cast<void*>(page_base), &mbi, sizeof(mbi))) {
                m_original_protections[page_base] = mbi.Protect;
                m_page_rearm_locks[page_base].clear();
                DWORD old_protect;

                if (!VirtualProtect(reinterpret_cast<void*>(page_base), 0x1000, mbi.Protect | PAGE_GUARD, &old_protect)) {
                    m_hooks.erase(reinterpret_cast<void*>(target));
                    m_page_hooks[page_base].pop_back();
                    if (m_page_hooks[page_base].empty()) {
                        m_page_hooks.erase(page_base);
                    }
                    m_original_protections.erase(page_base);
                    m_page_rearm_locks.erase(page_base);
                    // OPTIMIZATION 19: Clean cache
                    --cache.count;
                    m_page_hook_cache.erase(page_base);
                    log_debug(tfm::format("[HWBP] ERROR: Failed to set PAGE_GUARD. Error: %d", GetLastError()));
                    return false;
                }
                log_debug(tfm::format("[HWBP] Initial PAGE_GUARD set for page 0x%p", page_base));
            }
            else {
                m_hooks.erase(reinterpret_cast<void*>(target));
                m_page_hooks[page_base].pop_back();
                --cache.count;
                return false;
            }
        }

        return true;
    }

    inline void hwbp_manager::clear_all_hooks_internal()
    {
        if (m_hooks.empty()) return;

        for (const auto& [page_base, original_protect] : m_original_protections) {
            DWORD old_protect;
            VirtualProtect(reinterpret_cast<void*>(page_base), 0x1000, original_protect, &old_protect);
        }

        m_hooks.clear();
        m_page_hooks.clear();
        m_page_hook_cache.clear();
        m_original_protections.clear();
        m_page_rearm_locks.clear();

        {
            std::lock_guard<std::mutex> lock(m_rearm_mutex);
            m_pages_to_rearm.clear();
        }
    }
}
 
Последнее редактирование:
Назад
Сверху Снизу