Last active
August 5, 2023 14:53
-
-
Save mmlac/67eb02b60bd0b8682c08dc61fab065f2 to your computer and use it in GitHub Desktop.
[C++ & C# Examples] Getting the existing processes running on the system and their modules - Written & Tested in VS2015
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Getting the existing processes running on the system and their modules (in this case filtered by whether they load a | |
DirectX or OpenGL library). | |
-- ALL this code is heavily heavily copied together from answers on StackOverflow and other parts of the internet. | |
Because I probably went through a thousand tabs while looking up tons of minor things | |
(I have never coded C# before and never touched the Win API) I don't have all the sources. :( | |
I still want to aggregate my results here for others to benefit from. | |
NOTE!!! WMI & PrintProcesses will only see 32bit when running as 32bit and 64bit when running 64bit. | |
Might be able to fix as well with flags. See revision on how I got the flags to work in C++ and PInvoke solution. | |
Written & Tested in VS2015 on Win10 64bit - YMMV on other OSes, architectures and compilers. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "stdafx.h" | |
#include <windows.h> | |
#include <tchar.h> | |
#include <stdio.h> | |
#include <psapi.h> | |
#include <list> | |
#include <algorithm> | |
#include <string> | |
#include <cctype> | |
#include <sstream> | |
#include <iostream> | |
/// Try to find in the Haystack the Needle - ignore case | |
bool findStringIC(const std::wstring & strHaystack, const std::wstring & strNeedle) | |
{ | |
auto it = std::search( | |
strHaystack.begin(), strHaystack.end(), | |
strNeedle.begin(), strNeedle.end(), | |
[](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); } | |
); | |
return (it != strHaystack.end()); | |
} | |
// To ensure correct resolution of symbols, add Psapi.lib to TARGETLIBS | |
// and compile with -DPSAPI_VERSION=1 | |
int PrintModules(DWORD processID) | |
{ | |
HMODULE hMods[1024]; | |
HANDLE hProcess; | |
DWORD cbNeeded; | |
unsigned int i; | |
// Print the process identifier. | |
//printf("\n\"Process ID: %u\":[\n", processID); | |
// Get a handle to the process. | |
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | | |
PROCESS_VM_READ, | |
FALSE, processID); | |
if (NULL == hProcess) { | |
return 1; | |
} | |
WCHAR procWChar[MAX_PATH]; | |
DWORD namelen = GetProcessImageFileName(hProcess, procWChar, sizeof(procWChar) / sizeof(*procWChar)); | |
if (0 == namelen) | |
{ | |
printf("Name was empty, skipping...."); | |
return 1; | |
} | |
std::wstring procName = std::wstring(procWChar); | |
size_t lastPath = procName.find_last_of(L"\\"); | |
procName = procName.substr(lastPath + 1, procName.length() - lastPath - 1); | |
// Get a list of all the modules in this process. | |
if (EnumProcessModulesEx(hProcess, hMods, sizeof(hMods), &cbNeeded, LIST_MODULES_ALL)) | |
{ | |
std::wstringstream modsString; | |
for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) | |
{ | |
TCHAR szModName[MAX_PATH]; | |
// Get the full path to the module's file. | |
if (GetModuleFileNameEx(hProcess, hMods[i], szModName, | |
sizeof(szModName) / sizeof(TCHAR))) | |
{ | |
std::wstring modName = std::wstring((WCHAR *)szModName); | |
if (findStringIC(modName, L"d3d") || findStringIC(modName, L"opengl")) | |
{ | |
if (0 != i) | |
modsString << L" ,"; | |
modsString << modName; | |
} | |
// Print the module name and handle value. | |
//if(0 != i) printf(","); | |
//_tprintf(TEXT("\"\t%s (0x%08X)\"\n"), szModName, hMods[i]); | |
} | |
} | |
if (modsString.rdbuf()->in_avail() != 0) | |
std::wcout << L"Process: " << procName << L": " << modsString.str() << std::endl; | |
} | |
// Release the handle to the process. | |
CloseHandle(hProcess); | |
return 0; | |
} | |
int main(void) | |
{ | |
DWORD aProcesses[1024]; | |
DWORD cbNeeded; | |
DWORD cProcesses; | |
unsigned int i; | |
// Get the list of process identifiers. | |
if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) | |
return 1; | |
// Calculate how many process identifiers were returned. | |
cProcesses = cbNeeded / sizeof(DWORD); | |
// Print the names of the modules for each process. | |
for (i = 0; i < cProcesses; i++) | |
{ | |
PrintModules(aProcesses[i]); | |
} | |
return 0; | |
} | |
// MOSTLY THE ORIGINAL BELOW: | |
// | |
//#include "stdafx.h" | |
//#include <windows.h> | |
//#include <tchar.h> | |
//#include <stdio.h> | |
//#include <psapi.h> | |
// | |
//// To ensure correct resolution of symbols, add Psapi.lib to TARGETLIBS | |
//// and compile with -DPSAPI_VERSION=1 | |
// | |
//int PrintModules(DWORD processID) | |
//{ | |
// HMODULE hMods[1024]; | |
// HANDLE hProcess; | |
// DWORD cbNeeded; | |
// unsigned int i; | |
// | |
// // Print the process identifier. | |
// | |
// printf("\n\"Process ID: %u\":[\n", processID); | |
// | |
// // Get a handle to the process. | |
// | |
// hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | | |
// PROCESS_VM_READ, | |
// FALSE, processID); | |
// if (NULL == hProcess) { | |
// printf("]"); | |
// return 1; | |
// } | |
// | |
// // Get a list of all the modules in this process. | |
// | |
// if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) | |
// { | |
// | |
// for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) | |
// { | |
// TCHAR szModName[MAX_PATH]; | |
// | |
// // Get the full path to the module's file. | |
// | |
// if (GetModuleFileNameEx(hProcess, hMods[i], szModName, | |
// sizeof(szModName) / sizeof(TCHAR))) | |
// { | |
// // Print the module name and handle value. | |
// if (0 != i) printf(","); | |
// _tprintf(TEXT("\"\t%s (0x%08X)\"\n"), szModName, hMods[i]); | |
// } | |
// } | |
// | |
// } | |
// | |
// | |
// | |
// // Release the handle to the process. | |
// | |
// CloseHandle(hProcess); | |
// | |
// return 0; | |
//} | |
// | |
//int main(void) | |
//{ | |
// | |
// DWORD aProcesses[1024]; | |
// DWORD cbNeeded; | |
// DWORD cProcesses; | |
// unsigned int i; | |
// | |
// // Get the list of process identifiers. | |
// | |
// if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) | |
// return 1; | |
// | |
// // Calculate how many process identifiers were returned. | |
// | |
// cProcesses = cbNeeded / sizeof(DWORD); | |
// | |
// // Print the names of the modules for each process. | |
// printf("{"); | |
// for (i = 0; i < cProcesses; i++) | |
// { | |
// if (0 != i) printf(","); | |
// PrintModules(aProcesses[i]); | |
// } | |
// printf("}"); | |
// | |
// return 0; | |
//} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Text; | |
using System.Runtime.InteropServices; | |
using System.Globalization; | |
namespace Test | |
{ | |
class Program | |
{ | |
[DllImport("psapi")] | |
private static extern bool EnumProcesses( | |
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U4)] [In][Out] UInt32[] processIds, | |
UInt32 arraySizeBytes, | |
[MarshalAs(UnmanagedType.U4)] out UInt32 bytesCopied); | |
[DllImport("psapi.dll", SetLastError = true)] | |
public static extern bool EnumProcessModules( | |
IntPtr hProcess, | |
[Out] IntPtr lphModule, | |
UInt32 cb, | |
[MarshalAs(UnmanagedType.U4)] out UInt32 lpcbNeeded); | |
public enum DwFilterFlag : uint | |
{ | |
LIST_MODULES_DEFAULT = 0x0, // This is the default one app would get without any flag. | |
LIST_MODULES_32BIT = 0x01, // list 32bit modules in the target process. | |
LIST_MODULES_64BIT = 0x02, // list all 64bit modules. 32bit exe will be stripped off. | |
LIST_MODULES_ALL = (LIST_MODULES_32BIT | LIST_MODULES_64BIT) // list all the modules | |
} | |
[DllImport("psapi.dll", SetLastError = true)] | |
public static extern bool EnumProcessModulesEx( | |
IntPtr hProcess, | |
[Out] IntPtr lphModule, | |
UInt32 cb, | |
[MarshalAs(UnmanagedType.U4)] out UInt32 lpcbNeeded, | |
DwFilterFlag dwff); | |
[DllImport("psapi.dll")] | |
static extern uint GetModuleFileNameEx( | |
IntPtr hProcess, | |
IntPtr hModule, | |
[Out] StringBuilder lpBaseName, | |
[In] [MarshalAs(UnmanagedType.U4)] int nSize); | |
[DllImport("psapi.dll")] | |
static extern uint GetProcessImageFileName( | |
IntPtr hProcess, | |
[Out] StringBuilder lpImageFileName, | |
[In] [MarshalAs(UnmanagedType.U4)] int nSize); | |
public enum ProcessAccessFlags : uint | |
{ | |
All = 0x001F0FFF, | |
Terminate = 0x00000001, | |
CreateThread = 0x00000002, | |
VirtualMemoryOperation = 0x00000008, | |
VirtualMemoryRead = 0x00000010, | |
VirtualMemoryWrite = 0x00000020, | |
DuplicateHandle = 0x00000040, | |
CreateProcess = 0x000000080, | |
SetQuota = 0x00000100, | |
SetInformation = 0x00000200, | |
QueryInformation = 0x00000400, | |
QueryLimitedInformation = 0x00001000, | |
Synchronize = 0x00100000 | |
} | |
[DllImport("kernel32.dll", SetLastError = true)] | |
public static extern IntPtr OpenProcess( | |
ProcessAccessFlags processAccess, | |
bool bInheritHandle, | |
UInt32 processId | |
); | |
public static void Foo() | |
{ | |
List<UInt32> procIds = Procs(); | |
Console.WriteLine("Found {0} processes.", procIds.Count); | |
ProcModule(procIds); | |
} | |
private static List<UInt32> Procs() | |
{ | |
List<UInt32> proclist = new List<UInt32>(); | |
UInt32 arraySize = 120; | |
UInt32 arrayBytesSize = arraySize * sizeof(UInt32); | |
UInt32[] processIds = new UInt32[arraySize]; | |
UInt32 bytesCopied; | |
bool success = EnumProcesses(processIds, arrayBytesSize, out bytesCopied); | |
Console.WriteLine("success={0}", success); | |
Console.WriteLine("bytesCopied={0}", bytesCopied); | |
if (!success) | |
{ | |
Console.WriteLine("Boo!"); | |
return proclist; | |
} | |
if (0 == bytesCopied) | |
{ | |
Console.WriteLine("Nobody home!"); | |
return proclist; | |
} | |
UInt32 numIdsCopied = bytesCopied >> 2; ; | |
if (0 != (bytesCopied & 3)) | |
{ | |
UInt32 partialDwordBytes = bytesCopied & 3; | |
Console.WriteLine("EnumProcesses copied {0} and {1}/4th DWORDS... Please ask it for the other {2}/4th DWORD", | |
numIdsCopied, partialDwordBytes, 4 - partialDwordBytes); | |
return proclist; | |
} | |
for (UInt32 index = 0; index < numIdsCopied; index++) | |
{ | |
//Console.WriteLine("ProcessIds[{0}] = {1}", index, processIds[index]); | |
proclist.Add(processIds[index]); | |
} | |
return proclist; | |
} | |
private static void ProcModule(List<UInt32> procIds) | |
{ | |
int _3dProcs = 0; | |
foreach (UInt32 pid in procIds) | |
{ | |
List<String> modNames = new List<String>(); | |
IntPtr procPtr = OpenProcess(ProcessAccessFlags.All, false, pid); | |
if( IntPtr.Zero == procPtr ) | |
continue; | |
uint[] modsInt = new uint[1024]; | |
// Setting up the variable for the second argument for EnumProcessModules | |
IntPtr[] hMods = new IntPtr[1024]; | |
GCHandle gch = GCHandle.Alloc(hMods, GCHandleType.Pinned); // Don't forget to free this later | |
IntPtr pModules = gch.AddrOfPinnedObject(); | |
// Setting up the rest of the parameters for EnumProcessModules | |
uint uiSize = (uint)(Marshal.SizeOf(typeof(IntPtr)) * (hMods.Length)); | |
uint cbNeeded = 0; | |
if (EnumProcessModulesEx(procPtr, pModules, uiSize, out cbNeeded, DwFilterFlag.LIST_MODULES_ALL) == true) | |
{ | |
Int32 uiTotalNumberofModules = (Int32)(cbNeeded / (Marshal.SizeOf(typeof(IntPtr)))); | |
for (int i = 0; i < (int)uiTotalNumberofModules; i++) | |
{ | |
StringBuilder strbld = new StringBuilder(1024); | |
GetModuleFileNameEx(procPtr, hMods[i], strbld, (int)(strbld.Capacity)); | |
String module = strbld.ToString(); | |
if( ContainsCaseInsensitive(module, "d3d") || ContainsCaseInsensitive(module, "opengl" ) ) | |
modNames.Add(CutPath(module)); | |
} | |
StringBuilder procName = new StringBuilder(2000); | |
GetProcessImageFileName(procPtr, procName, 2000); | |
if (modNames.Count > 0) | |
{ | |
++_3dProcs; | |
Console.WriteLine("File: {0} Modules: {1}", CutPath(procName.ToString()), String.Join(",", modNames)); | |
} | |
} | |
// Must free the GCHandle object | |
gch.Free(); | |
} | |
Console.WriteLine("Processes with 3D modules loaded: {0}", _3dProcs); | |
} | |
private static bool ContainsCaseInsensitive(String paragraph, String word) | |
{ | |
return CultureInfo.CurrentCulture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0; | |
} | |
private static String CutPath(String path) | |
{ | |
int last = path.LastIndexOf("\\"); | |
return path.Substring(last + 1, path.Length- last - 1); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private void PrintProcesses() | |
{ | |
List<String> printList = new List<String>(); | |
Process[] localAll = Process.GetProcesses(); | |
//Process[] localAll = { Process.GetProcessById(23268) }; | |
/*TODO: This is filled on startup witheverything that has | |
the graphic libraries loaded and than track only what | |
is loaded afterwards. Maybe even do a 15sec wait | |
after startup to make sure everything has loaded. | |
Also allow to block these standard apps below. Run a | |
unique on the list after the initial parse. | |
*/ | |
String[] ignoreProcessList = { | |
"GalaxyClient", "GalaxyClient Helper", "RzSynapse", "devenv", | |
"XDesProc", "GameOverlayUI", "Steam", "steamwebhelper", | |
"GameplayTimeTracker", "chrome", "firefox", "Dropbox", | |
"explorer", "CompanionApp", "procexp64", "notepad++", | |
"SkypeApp", "VeraCrypt", "SearchUI", "ShellExperienceHost", | |
"ScriptedSandbox64", "SetPoint", "SystemSettings", | |
"SkypeHost", "Microsoft.Photos", "UpdateChecker", | |
"ApplicationFrameHost" | |
}; | |
foreach (Process p in localAll) | |
{ | |
//printList.Add(String.Format("ID: {0} Name: {1}", p.Id, p.ProcessName)); | |
if (false && ignoreProcessList.Contains(p.ProcessName)) | |
continue; | |
try | |
{ | |
List<String> moduleList = new List<String>(); | |
ProcessModuleCollection pmc = p.Modules; | |
foreach (ProcessModule pm in pmc) | |
{ | |
String name = pm.ModuleName; | |
//printList.Add(String.Format("{0} runs {1}", p.ProcessName, name)); | |
if (ContainsCaseInsensitive(name, "d3d") || ContainsCaseInsensitive(name, "opengl")) | |
{ | |
moduleList.Add(name); | |
} | |
} | |
if (moduleList.Count > 0) | |
printList.Add(String.Format("{0} is running {1}", p.ProcessName, String.Join(",", moduleList))); | |
} | |
catch (System.ComponentModel.Win32Exception e) | |
{ | |
Console.WriteLine("W32 exception: {0} -> {1}", e.ErrorCode, e.Message); | |
} | |
catch (Exception e) { } | |
} | |
for (int i = 0; i < 10; ++i) | |
{ | |
Console.WriteLine(); | |
} | |
Console.WriteLine(printList.Count); | |
foreach (String line in printList) | |
{ | |
Console.WriteLine(line); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private void UseWMIToGetProcesses() | |
{ | |
HashSet<int> handle_list = new HashSet<int>(); | |
string win32_proc_query_string = "select * from CIM_Process"; | |
string cim_query_string = "select * from CIM_ProcessExecutable"; | |
ManagementScope ms = new ManagementScope(@"\\localhost\root\cimv2", null); | |
ms.Connect(); | |
if (ms.IsConnected) | |
{ | |
ObjectQuery cim_query = new ObjectQuery(cim_query_string); | |
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(ms, cim_query)) | |
{ | |
using (ManagementObjectCollection searchResult = searcher.Get()) | |
{ | |
foreach (ManagementObject mo in searchResult) | |
{ | |
if (ContainsCaseInsensitive(mo["Antecedent"] + "", "d3d") || ContainsCaseInsensitive((String)mo["Antecedent"], "opengl")) | |
{ | |
//foreach (PropertyData pd in mo.Properties) | |
//{ | |
// Console.WriteLine("{0}: {1} #### ", pd.Name, mo[pd.Name]); | |
//} | |
String dependent = (String)mo["Dependent"]; | |
if (dependent.Contains("\"")) | |
{ | |
// Dependent of the form: \\<hostname>\root\cimv2:Win32_Process.Handle="23312" | |
int first_quot = dependent.IndexOf("\""); | |
int start = first_quot + 1; //skip the -"- itself | |
int end = dependent.Count() - 1; | |
int range = end - start; | |
String handle = dependent.Substring(start, range); | |
int handle_i; | |
if (Int32.TryParse(handle, out handle_i)) | |
{ | |
handle_list.Add(handle_i); | |
} | |
} | |
} | |
} | |
} | |
} | |
Console.WriteLine("Handles: {0}", String.Join(", ", handle_list)); | |
//Console.WriteLine("Process count:{0}", process_count); | |
if (handle_list.Count > 0) | |
{ | |
int cntr = 0; | |
StringBuilder sb = new StringBuilder(win32_proc_query_string); | |
sb.Append(" WHERE "); | |
bool first = true; | |
foreach (int h in handle_list) | |
{ | |
if (first) | |
{ | |
first = false; | |
} | |
else | |
{ | |
sb.Append(" OR "); | |
} | |
sb.Append(String.Format("Handle = {0}", h)); | |
} | |
Console.WriteLine("QUERY: {0}", sb.ToString()); | |
ObjectQuery win32_proc_query = new ObjectQuery(sb.ToString()); | |
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(ms, win32_proc_query)) | |
{ | |
using (ManagementObjectCollection searchResult = searcher.Get()) | |
{ | |
foreach (ManagementObject mo in searchResult) | |
{ | |
++cntr; | |
//foreach (PropertyData pd in mo.Properties) | |
//{ | |
// Console.WriteLine("{0}: {1} #### ", pd.Name, mo[pd.Name]); | |
//} | |
Console.WriteLine("Cap: " + mo["Caption"] + " Desc: " + mo["Description"] + " ExecPath: " + mo["ExecutablePath"] + " CreatDate: " + mo["CreationDate"]); | |
} | |
} | |
} | |
Console.WriteLine("Counters: handle_list: {0} - cntr: {1}", handle_list.Count(), cntr); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment