Reputation: 771
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();
}
Upvotes: 1
Views: 6503
Reputation: 771
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;
}
Upvotes: 1
Reputation: 10613
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 isERROR_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.
Upvotes: 5
Reputation: 5607
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.
Upvotes: 2