Search code examples
c++windowswinapipsapi

Why does Windows deny access to some processes' names?


i wanted to try to build a little program which can read the memory of other programs and dump it into a text file(if it has access obviously). But the access seems to be a problem right beforehand to me. I first tried a bit around and wanted to print a list of all processes currently running but apparently i haven't even access to open some of the processes. However if i open the list in a program like Cheat Engine, it shows all process names (the system process for example mainly PID 4 if i have seen correctly). Now have i just messed up the desired access level while opening the process, or does Cheat Engine just use some tricks or reads the names from somewhere else? I tried both QueryFullProcessImageName and GetBaseModuleName where the latter requires PROCESS_VM_READ access thats why i used QueryFullProcessImageName because i tried to minimize my access level.

main.cpp

#include <cstring>
#include <iostream>
#include <iomanip>
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0600 /* Define so QueryFullProcessImageName can be used */
#include <windows.h>
#include <psapi.h>


using namespace std;


WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdLine, int cmdShow) {
    DWORD processIds[256];  /* Buffer for the process IDs */
    DWORD cbNeeded; /* Space needed from EnumProcesses() to store all IDs */
    /* 
     * I will not check if the space was sufficient or not because this is just a local experiment 
     * and i can insure it is enough space
     */
    if (EnumProcesses(processIds, sizeof(processIds), &cbNeeded) == 0) {
        cout << "Error while enumerating processes(" << GetLastError() << ")" << endl;
        return 0;
    }
    for (unsigned int i = 0; i < cbNeeded / sizeof(DWORD); i++) {
        DWORD nameBufferSize = 128;
        LPSTR processBaseName = new CHAR[128];
        /* Open the process; here is where i get access denied */
        HANDLE openProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processIds[i]);
        if (openProcess == NULL) {
            if(GetLastError() == 5) strcpy(processBaseName, "<denied>");
            else strcpy(processBaseName, "<unknown>");
        } else if (QueryFullProcessImageName(openProcess, NULL, processBaseName, nameBufferSize) == 0) {
            if(GetLastError() == 5) strcpy(processBaseName, "<denied>");
            else strcpy(processBaseName, "<unknown>");
        }
        cout << "PID: " << setw(6) << left << processIds[i] << "\t" << processBaseName << endl;
        delete processBaseName;
        CloseHandle(openProcess);
    }
    return 0;
}

Solution

  • There where many helpful information commented here so i can answer the question myself. The problem was, as stated, that i will never have sufficient permission to open protected system processes. The solution is to gather the information on another way. As commented this can be done much easier with CreateToolhelp32Snapshot to get a snapshot of all current running processes. Then i can iterate over them via Process32First and then all following with Process32Next and then just read the PROCESSENTRY32::szExeFile of the structure to get the name of the process.

    The code i now use:

    HANDLE processSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (processSnapshot == INVALID_HANDLE_VALUE) {
          std::cout << "Error while taking process snapshot(" << GetLastError() << ")" << std::endl;
          return 0
    }
    PROCESSENTRY32 process;
    process.dwSize = sizeof(PROCESSENTRY32); /* This is neccessary as the Process32First/Next function expects the size of the class in this member before the first call */
    if ( ! Process32First(processSnapshot, &process) ) {
          std::cout << "Error while accessing first entry of snapshot(" << GetLastError() << ")" << std::endl;
          return 0;
    }
    do {
          std::cout << "PID: " << process.th32ProcessID << "\t" << process.szExeFile << std::endl;
    } while( Process32Next(processSnapshot, &process) );
    if (GetLastError() != ERROR_NO_MORE_FILES) { /*  The Process32Next function throws the ERROR_NO_MORE_FILES error code when there is no more entry to read. If this is not the last error message something went wrong. */
            std::cout << "Error while enumerating processes(" << GetLastError() << ")" << std::endl;
    }
    

    Note that the snapshot is a snapshot of the current state and if any processes are opened or closed, the snapshot needs to be taken again to get the information of the new state and new processes.