简体   繁体   中英

Cannot get handle of process

SOLVED: Look at the last post by me. This is probably Windows XP and previous versions problem with the rights needed for GetProcessId function.

There are no build errors. GetProcessId still returns 0. I can't solve this problem.

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <psapi.h> //For EnumProcessModules.
#include <tlhelp32.h>

#include <iostream>
using namespace std;

HANDLE GetHandleByName( string str )
{
    HANDLE hProcess = NULL;
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof( PROCESSENTRY32 );

    HANDLE snapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, NULL );

    if( Process32First( snapshot, &entry ) == TRUE )
    {
        while( Process32Next( snapshot, &entry ) == TRUE )
        {
            WCHAR* wchrstr = ( WCHAR * )malloc( 128 );
            mbstowcs ( wchrstr, str.c_str(), 128 );
            if( wcscmp( reinterpret_cast< const wchar_t * >( entry.szExeFile ), wchrstr ) == 0 )
            {
                hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID );
            }
            free( wchrstr );
         }
    }

    CloseHandle( snapshot );
    return hProcess;
}



void main()
{
    HANDLE hProcess = GetHandleByName( "System" );

    cout << GetProcessId( hProcess );
    cin.get();
}

First of all, are you trying to get the System process or the [System Process] virtual process? Either way, your code has a few issues that must be addressed.

If you're trying for just System then your code would work with only minor tweaks. If what you really want is [System Process] then you're out of luck.

First of all, you do no error checking. Perhaps CreateToohelp32Snapshot failed and you're using an invalid handle in your Process32First call. Secondly, you call Process32First and then immediately call Process32Next without looking at the process that Process32First returned. In other words, you're always skipping the first process returned. Coincidentally, guess which process is the first process returned? It's the virtual [System Process] .

So let's try a function that enumerates all processes and does it correctly:

void EnumAllProcesses(BOOL bTryToOpen = FALSE,
                      DWORD dwAccess = PROCESS_QUERY_INFORMATION)
{
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof( PROCESSENTRY32 );

    HANDLE snapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, NULL );

    if( snapshot == INVALID_HANDLE_VALUE )
    {
        _tprintf(_T("Unable to create a ToolHelp32 snapshot (%08X)\n"), GetLastError());
        return;
    }

    if( Process32First( snapshot, &entry ) == TRUE )
    {
        do
        {
            _tprintf(_T("Process: %s (%u)\n"), entry.szExeFile, entry.th32ProcessID);

            if(bTryToOpen)
            {
                HANDLE hProcess = OpenProcess( dwAccess,
                                               FALSE, 
                                               entry.th32ProcessID );

                _tprintf(_T("    hProcess = %p (%08X)\n"), hProcess, GetLastError());

                if(hProcess != NULL)
                    CloseHandle(hProcess);
            }
        } while( Process32Next( snapshot, &entry ) == TRUE );        
    }

    CloseHandle( snapshot );
}

But even with this new code you will have issues if you want to open [System Process] . The reason is that OpenProcess will fail with ERROR_INVALID_PARAMETER when you specify the process ID of this process (which happens to always be zero). This is documented behavior. Look at the MSDN page on CreateProcess and specifically at the dwProcessId argument explanation:

If the specified process is the System Process (0x00000000), the function fails and the last error code is ERROR_INVALID_PARAMETER . If the specified process is the Idle process or one of the CSRSS processes, this function fails and the last error code is ERROR_ACCESS_DENIED because their access restrictions prevent user-level code from opening them.

Here's a snapshot of the output of this code on my system, running as non-admin:

Process: [System Process] (0)
    hProcess = 00000000 (00000057) 
Process: System (4)
    hProcess = 00000000 (00000005)
Process: smss.exe (324)
    hProcess = 00000000 (00000005)
Process: csrss.exe (492)
    hProcess = 00000000 (00000005)
Process: wininit.exe (568)
    hProcess = 00000000 (00000005) 

Notice that the error when trying to open [System Process] (with PID 0) the error is, correctly, "invalid parameter". When trying to open System (with PID 4) the error is 5 - which translates to ERROR_ACCESS_DENIED . This is what I'd expect since I ask for full access and I'm not running as admin. So I try running this as admin. Yet the results won't change. Hmm... what could be the problem?

Well, it might be that you are asking for PROCESS_ALL_ACCESS to processes that do not allow you to ask for that much access even if you're an admin. Just because you are the owner of ancyBank doesn't mean you can walk into a branch and demand that the manager just open other people's safety deposit boxes... So how about you try asking for LESS access. How about PROCESS_QUERY_INFORMATION instead?

Now, the evidence (as you relay it) suggests that your call to CreatToolHelp32Snapshot fails, and the loop is never entered or that you are running as non-admin and asking for information on a process which you don't have access to. But I have no faith that you are accurately relaying what's happening and you are not helping us help you.

The OS will not allow you to open the system process. It would also be pretty useless as it's not a usual process with modules etc.

dwProcessId [in]
The identifier of the local process to be opened.

If the specified process is the System Process (0x00000000), the function fails and the last error code is ERROR_INVALID_PARAMETER. If the specified process is the Idle process or one of the CSRSS processes, this function fails and the last error code is ERROR_ACCESS_DENIED because their access restrictions prevent user-level code from opening them.

Also you need higher privileges to open another process. You can do this by executing the program as administrator, require an administrator from the UAC manifest or disabling UAC to test such applications.

To open a handle to another local process and obtain full access rights, you must enable the SeDebugPrivilege privilege. For more information, see Changing Privileges in a Token.

On my UAC disabled system the program works fine, when I only change the process name to something that can be opened.

And the real problem was ladies and gentelmen: GetProcessId( HANDLE process ) from windows.h which still returned 0 as the result. I have replaced the function with:

EDIT: There is also second way to fix the problem, using AdjustTokenPrivileges thanks that we can use PROCESS_ALL_ACCESS so the original GetProcessId will work without using the function below which simply creates remote thread.

DWORD WINAPI GetProcessIDbyProcessHandle(HANDLE hProcess)
{
    if (hProcess == NULL)    return 0xffffffff;
    PTHREAD_START_ROUTINE lpStartAddress = (PTHREAD_START_ROUTINE)
        GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "GetCurrentProcessId");
    if (lpStartAddress == NULL) return 0xffffffff;
    // We do not know, whether process handle already has required access rights;

    // thus we have to duplicate it
    HANDLE hProcessAccAdj;
    BOOL bRes = DuplicateHandle(GetCurrentProcess(), 
                                hProcess, GetCurrentProcess(), &hProcessAccAdj, 
                                PROCESS_QUERY_INFORMATION|PROCESS_CREATE_THREAD|
                                PROCESS_VM_OPERATION|PROCESS_VM_WRITE, 
                                FALSE, 0);
    if (!bRes || hProcessAccAdj == NULL)
    {
        UINT unError = GetLastError();
        return 0xffffffff;
    }
    // Create a remote thread; as its starting address 

    // we specify GetCurrentProcessId() address,
    // which is the same for all processes. Note that GetCurrentProcessId() has no input
    // parameters, and we don't care about our thread stack cleanup,
    // as it will be destroyed right after this call

    DWORD dwThreadID;
    HANDLE hRemoteThread = CreateRemoteThread(hProcessAccAdj, NULL, 
        0, lpStartAddress, 0, 0, &dwThreadID);
    CloseHandle(hProcessAccAdj);
    if (hRemoteThread == NULL) return 0xffffffff;
    // Wait until process ID is obtained

    // (replace INFINITE value below to a smaller value to avoid deadlocks);
    // then get the thread exit code, which is a value returned by GetCurrentProcessId()
    // in the context of the remote process
    WaitForSingleObject(hRemoteThread, INFINITE);
    DWORD dwExitCode;
    if (GetExitCodeThread(hRemoteThread, &dwExitCode) == 0)    dwExitCode = 0xffffffff;
    CloseHandle(hRemoteThread);
    return dwExitCode;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM