How to Suspend Specific Thread of a Process (.exe) in C++?

Question:

I want to suspend a specific thread of a process in C++ by StartAddress. My code already suspends some process threads, but not others… It seems that this only happens with address that have something after the extension other than the address.

An example of the thread I want to suspend: https://prnt.sc/m9vcef

MY PROBLEM

It only works on some start address, example: " calc.exe+0x1b9b8 ", now if it is, " calc.exe!globalDllIndex+0xac3b08 " doesn't work.

Can someone please see my code and see what's missing? I have no idea what it is.

My code:

#pragma comment( lib, "psapi" )

enum THREADINFOCLASS
{
ThreadQuerySetWin32StartAddress = 9,
};

typedef NTSTATUS(__stdcall * f_NtQueryInformationThread)(HANDLE, THREADINFOCLASS, void*, ULONG_PTR, ULONG_PTR*);

ULONG_PTR GetThreadStartAddress(HANDLE hThread)
{
    auto NtQueryInformationThread = reinterpret_cast<f_NtQueryInformationThread>(GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationThread"));
    if (!NtQueryInformationThread)
        return 0;

    ULONG_PTR ulStartAddress = 0;
    NTSTATUS Ret = NtQueryInformationThread(hThread, ThreadQuerySetWin32StartAddress, &ulStartAddress, sizeof(ULONG_PTR), nullptr);

    if (Ret)
        return 0;

    return ulStartAddress;
}


bool SuspendThreadByStartaddress(ULONG_PTR StartAddress, DWORD dwProcId)
{
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
    if (!hSnap)
        return false;

    THREADENTRY32 TE32 = { 0 };
    TE32.dwSize = sizeof(THREADENTRY32);

    BOOL Ret = Thread32First(hSnap, &TE32);
    while (Ret)
    {
        if (TE32.th32OwnerProcessID == dwProcId)
        {
            HANDLE hTempThread = OpenThread(THREAD_ALL_ACCESS, FALSE, TE32.th32ThreadID);
            if (!hTempThread)
                continue;

            if (StartAddress == GetThreadStartAddress(hTempThread))
            {
                SuspendThread(hTempThread);
                CloseHandle(hTempThread);
                CloseHandle(hSnap);
                return true;
            }
        }
        Ret = Thread32Next(hSnap, &TE32);
    }

    CloseHandle(hSnap);

    return false;
}


uintptr_t dwGetModuleBaseAddress(DWORD procId, const char* modName)
{
    uintptr_t modBaseAddr = 0;
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);
    if (hSnap != INVALID_HANDLE_VALUE)
    {
        MODULEENTRY32 modEntry;
        modEntry.dwSize = sizeof(modEntry);
        if (Module32First(hSnap, &modEntry))
        {
            do
            {
                if (strcmp(modEntry.szModule, modName) == 0)
                {
                    modBaseAddr = (uintptr_t)modEntry.modBaseAddr;
                    break;
                }
            } while (Module32Next(hSnap, &modEntry));

        }
    }
    CloseHandle(hSnap);
    return modBaseAddr;
}


int main()
{
    HWND tibiaWindow;
    HANDLE hProcess;
    DWORD PID;

    tibiaWindow = FindWindow(NULL, "TitleName Process");
    if (!tibiaWindow) {
        cout << "Cannot found process...\n";
    }
    else {;
        GetWindowThreadProcessId(tibiaWindow, &PID);
        hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
        uintptr_t base = dwGetModuleBaseAddress(PID, "MyModuleDll.dll");
        SuspendThreadByStartaddress(base + 0xac3b08, PID);
    }
    getchar();
}

Does anyone have any suggestions? thanks

Answer:

As I understand you are only doing a double check in case the pid doesn't match the correct process name? Because theoretically only with the PID you can suspend the process.

What I saw is that the name is static. That is, it will be the Process Name + ADDRESS.

SuspendThreadByStartaddress(base + 0xac3b08, PID);

Now you can:

  1. check only the process name or the address at the end, not comparing the entire string, as theoretically the PID is already a validation process. (There is no way there are 2 processes with the same pid on the system at the same time)

  2. can create another argument in the function for you to pass the base and address. And you check if both are contained in the return address name GetThreadStartAddress(hTempThread)

Remembering that only by PID you can suspend the process. The address would be more for a double check.

Scroll to Top