71

I'm trying to get the process handle of, say example.exe, so I can call TerminateProcess on it. How can I do this? Notice, it doesn't have a window so FindWindow won't work.

Ayman Hourieh
  • 132,184
  • 23
  • 144
  • 116
Malfist
  • 31,179
  • 61
  • 182
  • 269

7 Answers7

97
#include <cstdio>
#include <windows.h>
#include <tlhelp32.h>

int main( int, char *[] )
{
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);

    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    if (Process32First(snapshot, &entry) == TRUE)
    {
        while (Process32Next(snapshot, &entry) == TRUE)
        {
            if (stricmp(entry.szExeFile, "target.exe") == 0)
            {  
                HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);

                // Do stuff..

                CloseHandle(hProcess);
            }
        }
    }

    CloseHandle(snapshot);

    return 0;
}

Also, if you'd like to use PROCESS_ALL_ACCESS in OpenProcess, you could try this:

#include <cstdio>
#include <windows.h>
#include <tlhelp32.h>

void EnableDebugPriv()
{
    HANDLE hToken;
    LUID luid;
    TOKEN_PRIVILEGES tkp;

    OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);

    LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid);

    tkp.PrivilegeCount = 1;
    tkp.Privileges[0].Luid = luid;
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    AdjustTokenPrivileges(hToken, false, &tkp, sizeof(tkp), NULL, NULL);

    CloseHandle(hToken); 
}

int main( int, char *[] )
{
    EnableDebugPriv();

    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);

    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

    if (Process32First(snapshot, &entry) == TRUE)
    {
        while (Process32Next(snapshot, &entry) == TRUE)
        {
            if (stricmp(entry.szExeFile, "target.exe") == 0)
            {  
                HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);

                // Do stuff..

                CloseHandle(hProcess);
            }
        }
    }

    CloseHandle(snapshot);

    return 0;
}
Aconcagua
  • 24,880
  • 4
  • 34
  • 59
xian
  • 4,657
  • 5
  • 34
  • 38
  • 10
    You code will skip the first process in the system (however, first process is most likely "SYSTEM" so no user-visible bug.) – Michael May 14 '09 at 19:29
  • The first process is SYSTEM, so it's fine (I literally took that code straight from one of my projects) ;) – xian May 14 '09 at 19:31
  • When I attempt to act on the hProcess I get error code 6 which is ERROR_INVALID_HANDLE – Malfist May 14 '09 at 19:39
  • 3
    change it to: HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION + PROCESS_VM_READ + PROCESS_TERMINATE, FALSE, entry.th32ProcessID ); and I'll give you the answer – Malfist May 14 '09 at 19:44
  • Updated it with a way to (maybe) let you open the process with PROCESS_ALL_ACCESS. – xian May 14 '09 at 19:59
  • Shouldn't you use stricmp instead of strcmp. I could imagine that you're executable may end up as "TARGET.EXE" or even worse after been copied around in some unusual way. – mmmmmmmm May 14 '09 at 19:59
  • 2
    I've been able to make much progress from this answer - thanks so much to everyone who contributed. I am running into a permission issue though. Even with EnableDebugPriv, "I get OpenProcess failed with error 5 (Access is denied)" when I try to open processes that are not my own. In my case I am looking for iexplore across all users. – tofutim Jul 18 '12 at 23:35
  • 6
    Excellent answer! You should change the line `if (stricmp(entry.szExeFile, "target.exe") == 0)` with `if (_tcsicmp(entry.szExeFile, _T("target.exe")) == 0)` to keep type integrity when changing between Unicode and ANSI compile flags. – rafeek Nov 18 '14 at 15:47
  • 2
    Note for people like me who like to alphabetize their headers -- `windows.h` has to be included before `tlhelp32.h` or you end up with confusing errors about the functions being undefined (because the definitions depend on `windows.h`) – Michael Mrozek Mar 10 '16 at 05:41
  • 1
    **This answer is quite dangerous** since there is no guarantee that the process you open by ID is the same process that was running when the snapshot is taken. Although the time delay is small, I wouldn't be surprised if an attacker could exploit the race condition. This is serious enough that I am voting the answer down. [The GetModuleBaseName approach](http://msdn.microsoft.com/en-us/library/ms682623.aspx) from Rob Kennedy's answer avoids this problem. – benrg Jul 02 '16 at 20:42
18

The following code shows how you can use toolhelp and OpenProcess to get a handle to the process. Error handling removed for brevity.

HANDLE GetProcessByName(PCSTR name)
{
    DWORD pid = 0;

    // Create toolhelp snapshot.
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 process;
    ZeroMemory(&process, sizeof(process));
    process.dwSize = sizeof(process);

    // Walkthrough all processes.
    if (Process32First(snapshot, &process))
    {
        do
        {
            // Compare process.szExeFile based on format of name, i.e., trim file path
            // trim .exe if necessary, etc.
            if (string(process.szExeFile) == string(name))
            {
               pid = process.th32ProcessID;
               break;
            }
        } while (Process32Next(snapshot, &process));
    }

    CloseHandle(snapshot);

    if (pid != 0)
    {
         return OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    }

    // Not found


       return NULL;
}
bytecode77
  • 14,163
  • 30
  • 110
  • 141
Michael
  • 54,279
  • 5
  • 125
  • 144
17

There are two basic techniques. The first uses PSAPI; MSDN has an example that uses EnumProcesses, OpenProcess, EnumProcessModules, and GetModuleBaseName.

The other uses Toolhelp, which I prefer. Use CreateToolhelp32Snapshot to get a snapshot of the process list, walk over it with Process32First and Process32Next, which provides module name and process ID, until you find the one you want, and then call OpenProcess to get a handle.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
5

The following code can be used:

DWORD FindProcessId(const std::wstring& processName)
{
    PROCESSENTRY32 processInfo;
    processInfo.dwSize = sizeof(processInfo);

    HANDLE processesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
    if (processesSnapshot == INVALID_HANDLE_VALUE) {
        return 0;
    }

    Process32First(processesSnapshot, &processInfo);
    if (!processName.compare(processInfo.szExeFile))
    {
        CloseHandle(processesSnapshot);
        return processInfo.th32ProcessID;
    }

    while (Process32Next(processesSnapshot, &processInfo))
    {
        if (!processName.compare(processInfo.szExeFile))
        {
            CloseHandle(processesSnapshot);
            return processInfo.th32ProcessID;
        }
    }

    CloseHandle(processesSnapshot);
    return 0;
}

Usage:

auto processId = FindProcessId(L"blabla.exe");

Getting a handle should be obvious, just call OpenProcess() or similar on it.

BullyWiiPlaza
  • 17,329
  • 10
  • 113
  • 185
2

Check out: MSDN Article

You can use GetModuleName (I think?) to get the name and check against that.

GEOCHET
  • 21,119
  • 15
  • 74
  • 98
Lloyd
  • 29,197
  • 4
  • 84
  • 98
  • Most of the GetModuleName, QueryFullProcessImage name, etc., require a handle and thus won't be of much use. Toolhelp does return process name. – Michael May 14 '09 at 19:33
1

If you don't mind using system(), doing system("taskkill /f /im process.exe") would be significantly easier than these other methods.

1

OpenProcess Function

From MSDN:

To open a handle to another local process and obtain full access rights, you must enable the SeDebugPrivilege privilege.

aJ.
  • 34,624
  • 22
  • 86
  • 128
  • I don't have the pID, only the name. – Malfist May 14 '09 at 19:21
  • 1
    SeDebugPrivilege is most definitely not needed for processes that are running as you. If you have access to the process via it's ACL (which you generally do for processes you create at the same integrity level as your code), you do not need SeDebugPrivilege. From same MSDN page: If the caller has enabled the SeDebugPrivilege privilege, the requested access is granted regardless of the contents of the security descriptor. – Michael May 14 '09 at 19:21
  • Yeah, you need to get the Process ID first by iterating processes. – aJ. May 14 '09 at 19:35