利用psapi.dll提供的API枚举进程--Ring3枚举进程

按照惯例,先来看一下EnumProcesses的底层实现到底是个什么东东??其实其内部还是调用了Nt系列的函数,通过宏传递参数,查询各种信息。最终返出各个进程的ID值

BOOL
WINAPI
EnumProcesses(DWORD *lpidProcess,
              DWORD cb,
              LPDWORD lpcbNeeded)
{
     
    NTSTATUS Status;
    DWORD Size = MAXSHORT, Count;
    PSYSTEM_PROCESS_INFORMATION ProcInfo;//先定义两个结构体用来承接NtQuerySystemInformation系列的返回值
    PSYSTEM_PROCESS_INFORMATION ProcInfoArray;

    /*首先查询所有进程的信息*/
    do
    {
     
    //申请内存
        ProcInfoArray = LocalAlloc(LMEM_FIXED, Size);
        if (ProcInfoArray == NULL)
        {
     
            return FALSE;
        }
	//查询进程信息
        Status = NtQuerySystemInformation(SystemProcessInformation, ProcInfoArray, Size, NULL);
        if (Status == STATUS_INFO_LENGTH_MISMATCH)
        {
     
        //如果内存长度不够,释放,继续申请
            LocalFree(ProcInfoArray);
            Size += MAXSHORT;
            continue;
        }
		//查询结束
        break;
    }
    while (TRUE);

    if (!NT_SUCCESS(Status))
    {
     
    //若Status返回值失败,则设置错误码,结束函数
        LocalFree(ProcInfoArray);
        SetLastError(RtlNtStatusToDosError(Status));
        return FALSE;
    }

    /*查询成功,开始遍历操作*/
    Count = 0;
    ProcInfo = ProcInfoArray;

    _SEH2_TRY
    {
     
        do
        {
     
            /*更新返出值*/
            if (Count < cb / sizeof(DWORD))
            {
     
            //保存id值
                lpidProcess[Count] = (DWORD)ProcInfo->UniqueProcessId;
                Count++;
            }

            if (ProcInfo->NextEntryOffset == 0)
            {
     
            //如果进程链表结束,则退出
                break;
            }
			//遍历所有进程
            ProcInfo = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)ProcInfo + ProcInfo->NextEntryOffset);
        }
        while (TRUE);

        *lpcbNeeded = Count * sizeof(DWORD);
    }
    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
     
        SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
        LocalFree(ProcInfoArray);
        _SEH2_YIELD(return FALSE);
    }
    _SEH2_END;
	//释放内存,返回成功
    LocalFree(ProcInfoArray);
    return TRUE;
}

EnumProcess使用举例:
通过进程ImageName得到进程ID

ULONG GetActiveProcessIdW(wchar_t* ImageName)
{
     

	int i;
	wchar_t* TranslatedProcessName;
	DWORD    ProcessId[1024] = {
     };
	wchar_t  ProcessFullPath[1024] = {
     };
	DWORD    IsNeeded = NULL;
	HANDLE	 ProcessHandle;
	wchar_t* NameOnly = 0;//只有进程名,没有完整路径

	if (EnumProcesses(ProcessId, sizeof(ProcessId), &IsNeeded))
	{
     
		for (i = 0; i < (int)(IsNeeded / sizeof(DWORD)); i++)
		{
     
			if (ProcessId[i] != NULL)
			{
     
				//提升权限,打开进程
				ProcessHandle = KtOpenProcess(PROCESS_QUERY_INFORMATION,
					false,
					ProcessId[i]);
				if (ProcessHandle != NULL)
				{
     
					if (GetProcessImageFileNameW(ProcessHandle,
						ProcessFullPath,
						_countof(ProcessFullPath)) > NULL)
					{
     
						TranslatedProcessName = (wchar_t*)TranslateNativeNameW(ProcessFullPath);
						lstrcpyW(ProcessFullPath, TranslatedProcessName);
						VirtualFree((void*)TranslatedProcessName, NULL, MEM_RELEASE);
						KtCloseHandle(ProcessHandle);

						if (_wcsicmp(ProcessFullPath, ImageName) == 0)
						{
     
							//如果不匹配,说明传的参数不是完整路径
							return ProcessId[i];
						}
						else
						{
     
							//寻找最后一个'\'的位置
							NameOnly = wcsrchr(ProcessFullPath, L'\\');
							if (NameOnly)
							{
     
								//越过'\'
								NameOnly++;
								if (_wcsicmp(NameOnly, ImageName) == 0)
								{
     
									return ProcessId[i];
								}
							}
						}
					}
					else
					{
     
						KtCloseHandle(ProcessHandle);
					}
				}
			}
		}
	}
	return NULL;
}

越过山丘,会看见美景依旧!
参考资料:
Reactos

你可能感兴趣的:(Windows应用层开发)