简体   繁体   English

无法处理程序

[英]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. 这可能是Windows XP和以前版本的问题,具有GetProcessId函数所需的权限。

There are no build errors. 没有构建错误。 GetProcessId still returns 0. I can't solve this problem. GetProcessId仍然返回0。我无法解决此问题。

#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? 首先,您是要获取System进程还是[System 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. 如果您仅尝试使用System则您的代码仅需进行少量调整即可使用。 If what you really want is [System Process] then you're out of luck. 如果您真正想要的是[System Process]那么您不走运。

First of all, you do no error checking. 首先,您不执行任何错误检查。 Perhaps CreateToohelp32Snapshot failed and you're using an invalid handle in your Process32First call. 可能CreateToohelp32Snapshot失败,并且您在Process32First调用中使用了无效的句柄。 Secondly, you call Process32First and then immediately call Process32Next without looking at the process that Process32First returned. 其次,您调用Process32First ,然后立即调用Process32Next而无需查看Process32First返回的进程。 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] . 这是虚拟的[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] . 但是即使使用此新代码,如果您想打开[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). 原因是当您指定此进程的进程ID(总是为零)时, OpenProcess将失败并显示ERROR_INVALID_PARAMETER This is documented behavior. 这是记录的行为。 Look at the MSDN page on CreateProcess and specifically at the dwProcessId argument explanation: 查看CreateProcess上的MSDN页面,尤其是dwProcessId参数说明:

If the specified process is the System Process (0x00000000), the function fails and the last error code is ERROR_INVALID_PARAMETER . 如果指定的进程是系统进程(0x00000000),则该函数将失败,并且最后一个错误代码是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. 如果指定的进程是Idle进程或CSRSS进程之一,则此函数将失败,并且最后一个错误代码为ERROR_ACCESS_DENIED因为它们的访问限制会阻止用户级代码打开它们。

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". 请注意,尝试打开[System Process] (PID为0)时,该错误正确地是“无效参数”。 When trying to open System (with PID 4) the error is 5 - which translates to ERROR_ACCESS_DENIED . 尝试打开System (使用PID 4)时,错误为5-转换为ERROR_ACCESS_DENIED This is what I'd expect since I ask for full access and I'm not running as admin. 这是我期望的,因为我要求完全访问并且我没有以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. 好吧,可能是您正在要求PROCESS_ALL_ACCESS处理那些即使您是管理员也不允许您要求这么多访问权限的进程。 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. 仅仅因为您是ancyBank的所有者,并不意味着您可以走进分支机构并要求经理只打开其他人的保险箱...那么,您如何尝试要求LESS访问权限。 How about PROCESS_QUERY_INFORMATION instead? 改为PROCESS_QUERY_INFORMATION呢?

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. 现在,证据(在您中继时)表明您对CreatToolHelp32Snapshot的调用失败,并且永不进入循环,或者您以非管理员身份运行并要求获得您无权访问的进程的信息。 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. 您可以通过以管理员身份执行程序, 从UAC清单中要求管理员或禁用UAC来测试此类应用程序来执行此操作。

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. 在我禁用了UAC的系统上,当我仅将进程名称更改为可以打开的名称时,程序运行良好。

And the real problem was ladies and gentelmen: GetProcessId( HANDLE process ) from windows.h which still returned 0 as the result. 真正的问题是女士们和先生们:windows.h中的GetProcessId(HANDLE process)仍然返回0作为结果。 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. 编辑:还有第二种方法来解决此问题,使用AdjustTokenPrivileges,感谢我们可以使用PROCESS_ALL_ACCESS,这样原始的GetProcessId将可以工作,而无需使用下面的函数,该函数仅创建远程线程。

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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