[Tut] Hooking threads without mem writes or breakpoints menu

User Tag List

Results 1 to 3 of 3
  1. #1
    Master674's Avatar Elite User
    Reputation
    487
    Join Date
    May 2008
    Posts
    578
    Thanks G/R
    2/23
    Trade Feedback
    1 (100%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    [Tut] Hooking threads without mem writes or breakpoints

    Hey everyone,

    recently I had to do some small tool for someone and needed a quick way to hook into the main thread.
    I was too lazy to search for a function that I could use as a "pulse" and import a hook lib, so I did some magic with VEH's and WoWs ClientSetTimer function.

    It does not use any memory patches or HW-breakpoints, it's just triggering a single step exception in the main thread and catching it with a simple VEH.
    I figured this method was not widely used so I decided to make a thread about it.

    Here's what I came up with (behold, it's very very simple):

    Code:
    uint32_t hooks::get_main_thread_id() const {
        DWORD main_thread_id = 0;
        DWORD process_id = GetCurrentProcessId();
        ULONGLONG min_create_time = MAXULONGLONG;
    
        HANDLE thread_snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
        if (thread_snap != INVALID_HANDLE_VALUE) {
            THREADENTRY32 th32;
            th32.dwSize = sizeof(THREADENTRY32);
    
            BOOL ok = TRUE;
            for (ok = Thread32First(thread_snap, &th32); ok;
                    ok = Thread32Next(thread_snap, &th32))
            {
                if (th32.th32OwnerProcessID != process_id)
                    continue;
    
                if (HANDLE thread_handle = OpenThread(
                        THREAD_QUERY_INFORMATION,
                        FALSE, th32.th32ThreadID))
                {
                    FILETIME times[4] = { 0 };
                    if (GetThreadTimes(thread_handle, &times[0],
                            &times[1], &times[2], &times[3]))
                    {
                        ULONGLONG time = MAKEULONGLONG(
                            times[0].dwLowDateTime,
                            times[0].dwHighDateTime);
    
                        if (time && time < min_create_time) {
                            min_create_time = time;
                            main_thread_id = th32.th32ThreadID;
                        }
                    }
    
                    CloseHandle(thread_handle);
                }
            }
    
            CloseHandle(thread_snap);
        }
    
        return (uint32_t) main_thread_id;
    }
    
    bool hooks::hook_thread(uint32_t thread_id) {
        HANDLE handle = OpenThread(THREAD_SUSPEND_RESUME
            | THREAD_SET_CONTEXT | THREAD_GET_CONTEXT
            | THREAD_QUERY_INFORMATION, FALSE, thread_id);
    
        if (handle == NULL)
            return false;
    
        CONTEXT ctx;
        ZeroMemory(&ctx, sizeof(ctx));
        ctx.ContextFlags = CONTEXT_CONTROL;
    
        SuspendThread(handle);
    
        BOOL ret = FALSE;
        if (GetThreadContext(handle, &ctx)) {
            ctx.EFlags |= 0x100;
    
            if (ret = SetThreadContext(handle, &ctx)) {
                this->ve_handler = AddVectoredExceptionHandler(
                    TRUE, vectored_handler);
            }
        }
    
        ResumeThread(handle);
        CloseHandle(handle);
        return ret != FALSE;
    }
    
    LONG CALLBACK hooks::vectored_handler(PEXCEPTION_POINTERS exp) {
        if (exp->ExceptionRecord->ExceptionCode != EXCEPTION_SINGLE_STEP ||
            GetCurrentThreadId() != hooks::instance()->main_thread_id)
            return EXCEPTION_CONTINUE_SEARCH;
    
        if (RemoveVectoredExceptionHandler(hooks::instance()->ve_handler))
            hooks::instance()->ve_handler = nullptr;
    
        auto delegates = hooks::instance()->hook_delegates;
        delegates->client_set_timer(0, timer_callback, nullptr);
        return EXCEPTION_CONTINUE_EXECUTION;
    }
    
    bool __cdecl hooks::timer_callback(const void*, void*) {
        engine::instance()->on_pulse();
    
        if (engine::instance()->is_shutting_down()) {
            engine::instance()->on_unload();
            return true;
        }
    
        auto delegates = hooks::instance()->hook_delegates;
        delegates->client_set_timer(100, timer_callback, nullptr);
        return true;
    }
    ClientSetTimer = 0x1F52 (19802 - rebased)

    Have fun

    [Tut] Hooking threads without mem writes or breakpoints
  2. #2
    R4zyel's Avatar Active Member
    Reputation
    26
    Join Date
    Apr 2009
    Posts
    63
    Thanks G/R
    12/7
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    -Thanks for it, you prepotent.
    -C sucks.
    -+ Rep
    -Bye.

  3. #3
    Jadd's Avatar 🐸 Premium Seller
    Reputation
    1515
    Join Date
    May 2008
    Posts
    2,433
    Thanks G/R
    81/336
    Trade Feedback
    1 (100%)
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by R4zyel View Post
    -C sucks.
    That's a good argument.

Similar Threads

  1. MouseOverGUID and mem write
    By kajko in forum WoW Memory Editing
    Replies: 4
    Last Post: 03-01-2012, 06:47 PM
  2. Replies: 5
    Last Post: 05-09-2010, 11:22 PM
  3. [HELP] Mailing without memory writes
    By weber7655 in forum WoW Memory Editing
    Replies: 5
    Last Post: 10-14-2009, 10:22 AM
All times are GMT -5. The time now is 09:34 AM. Powered by vBulletin® Version 4.2.3
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Google Authenticator verification provided by Two-Factor Authentication (Free) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search