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

Asked

Viewed 198 times

3

I want to suspend a specific thread from a C++ process by Startaddress. My code already suspends some threads of the process, but others do not... It seems that this only happens to 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 works only on some start address, example: "Calc.exe+0x1b9b8", now if it’s, "Calc.exe! globalDllIndex+0xac3b08" doesn’t work.

Please can anyone 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();
}

Anyone have any suggestions? Thanks

  • How do you know you’re not getting the thread suspended? My code does exactly that and it works.

  • Could you send a printscreen? It only works on some start address, example: "Calc.exe+0x1b9b8", now if it is, "Calc.exe! globalDllIndex+0xac3b08" does not work. You can help me?

  • In my case I use only the ID of the thread I want to suspend, without entering the merit of addresses. So it always works. Try looking at the application source code Process Hacker. Good luck.

1 answer

0

From what I understand you are only doing a double check in case the pid does not match the name of the correct process? Because theoretically only with the PID can you 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 whole string, because theoretically the PID is already a validation process. (There can’t be 2 processes with same pid in the system at the same time )

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

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

Browser other questions tagged

You are not signed in. Login or sign up in order to post.