| My Training Period: yy hours. Before you begin, read someinstruction here.
The expected abilities include:
Note: For Multithreaded program examples, you have to set your project toMultithread project type.
Enumerating All Modules For a Process
To determine which processes have loaded a particular DLL, you must enumerate the modules for each process. The following sample code uses theEnumProcessModules() function to enumerate the modules of current processes in the system.
// ForWinXp #define _WIN32_WINNT 0x0501 #include <windows.h> #include <stdio.h> #include <psapi.h>
void PrintModules(DWORD processID) { HMODULE hMods[1024]; HANDLE hProcess; DWORD cbNeeded; unsignedint i; // Print the process identifier. printf("\nProcess ID: %u\n", processID); // Get a list of all the modules in this process. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); if (hProcess == NULL) return; |
if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
{
for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
{
char szModPathName[MAX_PATH];
// Get the full path to the module's file.
if (GetModuleFileNameEx(hProcess, hMods[i], szModPathName, sizeof(szModPathName)))
{
// Print the module name and handle value.
printf("\t%s (0x%08X)\n", szModPathName, hMods[i]);
}
else
printf("GetModuleFileNameEx() failed!.\n");
}
}
CloseHandle(hProcess);
}
int main()
{
// Get the list of process identifiers.
DWORD aProcesses[2048], cbNeeded, cProcesses;
unsignedint i;
printf("Listing all the process's module...\n");
// If fail...
if (!EnumProcesses(aProcesses,sizeof(aProcesses), &cbNeeded))
printf("EnumProcesses() failed!.\n");
else
printf("EnumProcesses() is OK!.\n");
// Calculate how many process identifiers were returned.
cProcesses = cbNeeded / sizeof(DWORD);
// Print the name of the modules for each process.
for (i = 0; i < cProcesses; i++)
PrintModules(aProcesses[i]);
return 0;
}
A sample output:
F:\myproject\myprocess\Debug>myprocess | more
Listing all the process's module...
EnumProcesses() is OK!.
Process ID: 0
Process ID: 4
Process ID: 468
\SystemRoot\System32\smss.exe (0x48580000)
C:\WINDOWS\system32\ntdll.dll (0x7C900000)
Process ID: 528
Process ID: 552
\??\C:\WINDOWS\system32\winlogon.exe (0x01000000)
C:\WINDOWS\system32\ntdll.dll (0x7C900000)
C:\WINDOWS\system32\kernel32.dll (0x7C800000)
[trimmed]
C:\WINDOWS\system32\comdlg32.dll (0x763B0000)
C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.2180_x-ww_a84f1ff9\comctl32.dll (0x773D0000)
C:\WINDOWS\system32\odbcint.dll (0x20000000)
[trimmed]
C:\WINDOWS\system32\NTDSAPI.dll (0x767A0000)
C:\WINDOWS\system32\DNSAPI.dll (0x76F20000)
Process ID: 596
C:\WINDOWS\system32\services.exe (0x01000000)
C:\WINDOWS\system32\ntdll.dll (0x7C900000)
[trimmed]
C:\WINDOWS\system32\umdmxfrm.dll (0x5B0A0000)
C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.2180_x-ww_a84f1ff9\comctl32.dll (0x773D0000)
C:\WINDOWS\system32\comctl32.dll (0x5D090000)
C:\WINDOWS\system32\secur32.dll (0x77FE0000)
[trimmed]
C:\WINDOWS\system32\PSAPI.DLL (0x76BF0000)
C:\WINDOWS\system32\wtsapi32.dll (0x76F50000)
Process ID: 608
C:\WINDOWS\system32\lsass.exe (0x01000000)
C:\WINDOWS\system32\ntdll.dll (0x7C900000)
[trimmed]
C:\WINDOWS\system32\umdmxfrm.dll (0x5B0A0000)
C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.2180_x-ww_a84f1ff9\comctl32.dll (0x773D0000)
C:\WINDOWS\system32\comctl32.dll (0x5D090000)
C:\WINDOWS\system32\msprivs.dll (0x20000000)
[trimmed]
C:\WINDOWS\system32\pstorsvc.dll (0x743A0000)
C:\WINDOWS\system32\psbase.dll (0x743C0000)
Process ID: 756
C:\WINDOWS\system32\svchost.exe (0x01000000)
C:\WINDOWS\system32\ntdll.dll (0x7C900000)
[trimmed]
C:\WINDOWS\system32\USER32.dll (0x77D40000)
C:\WINDOWS\system32\GDI32.dll (0x77F10000)
-- More --
The output for this example has been trimmed because it is very long. You may redirect it to a text file. The main function obtains a list of processes by using the EnumProcesses() function. For each process, the main function calls thePrintModules() function, passing it the process identifier. PrintModules() in turn calls the OpenProcess() function to obtain the process handle. If OpenProcess() fails, the output shows only the process identifier. For example,OpenProcess() fails for the Idle and CSRSS processes because their access restrictions prevent user-level code from opening them. Next, PrintModules() calls the EnumProcessModules() function to obtain the module handles function. Finally,PrintModules() calls the GetModuleFileNameEx() function, once for each module, to obtain the module names.
The following example obtains a list of modules for the specified process. The ListProcessModules() function takes a snapshot of the modules associated with a given process using theCreateToolhelp32Snapshot() function, and then walks through the list using Module32First() and Module32Next(). The dwPID parameter of ListProcessModules identifies the process for which modules are to be enumerated, and is usually obtained by calling CreateToolhelp32Snapshot() to enumerate the processes running on the system. An example using it is presented in the next program.A simple error-reporting function, printError(), displays the reason for any failures, which usually result from security restrictions. This example also can be used to list process and thread as demonstrated in the next program example.
// ForWinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
// Function prototypes...
BOOL ListProcessModules(DWORD dwPID);
void printError(TCHAR* msg);
int main(int argc,char argv[ ])
{
// 0 means current process, this program...
ListProcessModules(0);
return 0;
}
BOOL ListProcessModules(DWORD dwPID)
{
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;
// Take a snapshot of all modules in the specified process.
hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
if(hModuleSnap == INVALID_HANDLE_VALUE)
{
printError("CreateToolhelp32Snapshot()");
return (FALSE);
}
// Set the size of the structure before using it.
me32.dwSize = sizeof(MODULEENTRY32);
// Retrieve information about the first module, and exit if unsuccessful
printf("\n******************************************\n");
printf("* List of module for current process *\n");
printf("******************************************");
if(!Module32First(hModuleSnap, &me32))
{
printError("Module32First()"); // Show cause of failure
CloseHandle(hModuleSnap); // Must clean up the snapshot object
return (FALSE);
}
// Now walk the module list of the process, and display information about each module
do
{
printf("\n\n MODULE NAME: %s", me32.szModule);
printf("\n executable = %s", me32.szExePath);
printf("\n process ID = 0x%08X", me32.th32ProcessID);
printf("\n ref count (g) = 0x%04X", me32.GlblcntUsage);
printf("\n ref count (p) = 0x%04X", me32.ProccntUsage);
printf("\n base address = 0x%08X", (DWORD) me32.modBaseAddr);
printf("\n base size = %d\n", me32.modBaseSize);
}while (Module32Next(hModuleSnap, &me32));
// Do not forget to clean up the snapshot object.
CloseHandle(hModuleSnap);
return (TRUE);
}
void printError(TCHAR* msg)
{
DWORD eNum;
TCHAR sysMsg[256];
TCHAR* p;
eNum = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, eNum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
sysMsg, 256, NULL);
// Trim the end of the line and terminate it with a null
p = sysMsg;
while ((*p > 31) || (*p == 9))
++p;
do { *p-- = 0; }
while ((p >= sysMsg) && ((*p == '.') || (*p < 33)));
// Display the message...
printf("\n WARNING: %s failed with error %d (%s)\n", msg, eNum, sysMsg);
return 0;
}
A sample output:
--------------------------------------------------------------------------
Taking a Snapshot and Viewing Processes
The following simple console application obtains a list of running processes. First, the GetProcessList() function takes a snapshot of currently executing processes in the system usingCreateToolhelp32Snapshot(), and then it walks through the list recorded in the snapshot usingProcess32First() and Process32Next(). For each process in turn, GetProcessList() calls theListProcessModules() function and the ListProcessThreads() function. A simple error-reporting function, printError(), displays the reason for any failures, which usually result from security restrictions.
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
// Function prototypes...
BOOL GetProcessList();
BOOL ListProcessModules(DWORD dwPID);
BOOL ListProcessThreads(DWORD dwOwnerPID);
void printError(TCHAR* msg);
int main(int argc,char argv[])
{
GetProcessList();
return 0;
}
// =================Get the processes=====================
BOOL GetProcessList()
{
HANDLE hProcessSnap;
HANDLE hProcess;
PROCESSENTRY32 pe32;
DWORD dwPriorityClass;
// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(hProcessSnap == INVALID_HANDLE_VALUE)
{
printError("CreateToolhelp32Snapshot (of processes)");
return(FALSE);
}
// Set the size of the structure before using it.
pe32.dwSize = sizeof(PROCESSENTRY32);
// Retrieve information about the first process,
// and exit if unsuccessful
printf("\n\n*********************************");
printf("\nList of process & their info...\n");
printf("*********************************");
if (!Process32First(hProcessSnap, &pe32))
{
printError("Process32First()"); // Show cause of failure
CloseHandle(hProcessSnap); // Must clean up the snapshot object
return (FALSE);
}
// Now walk the snapshot of processes, and
// display information about each process in turn
do
{
printf("\n\n===========================================================");
printf("\nPROCESS NAME: %s", pe32.szExeFile);
printf("\n-----------------------------------------------------------");
// Retrieve the priority class.
dwPriorityClass = 0;
// OpenProcess() with all possible access rights for a process object,
// handle cannot be inherited and Identifier of the process to open...
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID);
if (hProcess == NULL)
printError("OpenProcess()");
else
{
dwPriorityClass = GetPriorityClass(hProcess);
if (!dwPriorityClass)
printError("GetPriorityClass()");
CloseHandle(hProcess);
}
printf("\n Name of the exe = %s", pe32.szExeFile);
printf("\n Parent process ID = 0x%08X", pe32.th32ParentProcessID);
printf("\n Process ID = 0x%08X", pe32.th32ProcessID);
printf("\n Thread count = %d", pe32.cntThreads);
printf("\n Priority Base = %d", pe32.pcPriClassBase);
if(dwPriorityClass)
printf("\n Priority Class = %d", dwPriorityClass);
// List the modules and threads associated with this process
ListProcessModules(pe32.th32ProcessID);
ListProcessThreads(pe32.th32ProcessID);
}while (Process32Next(hProcessSnap, &pe32));
// Don't forget to clean up the snapshot object!
CloseHandle(hProcessSnap);
return (TRUE);
}
// =================List the process modules=====================
BOOL ListProcessModules(DWORD dwPID)
{
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;
// Take a snapshot of all modules in the specified process.
hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
if(hModuleSnap == INVALID_HANDLE_VALUE)
{
printError("CreateToolhelp32Snapshot(of modules)");
return (FALSE);
}
// Set the size of the structure before using it...
me32.dwSize = sizeof(MODULEENTRY32);
// Retrieve information about the first module,
// and exit if unsuccessful
printf("\n\n*****************************************");
printf("\nList of process module & their info...\n");
printf("*****************************************");
if (!Module32First(hModuleSnap, &me32))
{
printError("Module32First()"); // Show cause of failure
CloseHandle(hModuleSnap); // Must clean up the snapshot object
return (FALSE);
}
// Now walk the module list of the process,
// and display information about each module...
do
{
printf("\n\n MODULE NAME: %s", me32.szModule);
printf("\n executable = %s", me32.szExePath);
printf("\n process ID = 0x%08X", me32.th32ProcessID);
printf("\n ref count (g) = 0x%04X", me32.GlblcntUsage);
printf("\n ref count (p) = 0x%04X", me32.ProccntUsage);
printf("\n base address = %p", me32.modBaseAddr);
printf("\n base size = %d", me32.modBaseSize);
}while(Module32Next(hModuleSnap, &me32));
// Don't forget to clean up the snapshot object.
CloseHandle(hModuleSnap);
return (TRUE);
}
// =================List the process threads=====================
BOOL ListProcessThreads(DWORD dwOwnerPID)
{
HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
THREADENTRY32 te32;
// Take a snapshot of all running threads
hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hThreadSnap == INVALID_HANDLE_VALUE)
return (FALSE);
// Fill in the size of the structure before using it.
te32.dwSize = sizeof(THREADENTRY32);
// Retrieve information about the first thread,
// and exit if unsuccessful
printf("\n\n*****************************************");
printf("\nList of process thread & their info...\n");
printf("*****************************************");
if(!Thread32First(hThreadSnap, &te32))
{
printError("Thread32First()"); // Show cause of failure
CloseHandle(hThreadSnap); // Must clean up the snapshot object
return (FALSE);
}
// Now walk the thread list of the system,
// and display information about each thread
// associated with the specified process
do
{
if (te32.th32OwnerProcessID == dwOwnerPID)
{
printf("\n\n THREAD ID = 0x%08X", te32.th32ThreadID);
printf("\n base priority = %d", te32.tpBasePri);
printf("\n delta priority = %d", te32.tpDeltaPri);
}
}while (Thread32Next(hThreadSnap, &te32));
// Don't forget to clean up the snapshot object.
CloseHandle(hThreadSnap);
return (TRUE);
}
void printError(TCHAR* msg)
{
DWORD eNum;
TCHAR sysMsg[256];
TCHAR* p;
eNum = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, eNum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
sysMsg, 256, NULL);
// Trim the end of the line and terminate it with a null
p = sysMsg;
while ((*p > 31) || (*p == 9))
++p;
do { *p-- = 0; }
while ((p >= sysMsg) && ((*p == '.') || (*p < 33)));
// Display the message
printf("\n WARNING: %s failed with error %d (%s)", msg, eNum, sysMsg);
}
A sample output:
F:\myproject\myprocess\Debug>myprocess | more
*********************************
List of process & their info...
*********************************
===========================================================
PROCESS NAME: [System Process]
-----------------------------------------------------------
WARNING: OpenProcess() failed with error 87 (The parameter is incorrect)
Name of the exe = [System Process]
Parent process ID = 0x00000000
Process ID = 0x00000000
Thread count = 1
Priority Base = 0
*****************************************
List of process module & their info...
*****************************************
MODULE NAME: myprocess.exe
executable = F:\myproject\myprocess\Debug\myprocess.exe
process ID = 0x00000244
ref count (g) = 0xFFFF
ref count (p) = 0xFFFF
base address = 00400000
base size = 184320
MODULE NAME: ntdll.dll
executable = C:\WINDOWS\system32\ntdll.dll
process ID = 0x00000244
ref count (g) = 0xFFFF
ref count (p) = 0xFFFF
base address = 7C900000
base size = 720896
MODULE NAME: kernel32.dll
executable = C:\WINDOWS\system32\kernel32.dll
process ID = 0x00000244
ref count (g) = 0xFFFF
ref count (p) = 0xFFFF
base address = 7C800000
base size = 999424
*****************************************
List of process thread & their info...
*****************************************
THREAD ID = 0x00000000
base priority = 0
delta priority = 0
===========================================================
PROCESS NAME: System
-----------------------------------------------------------
WARNING: OpenProcess() failed with error 5 (Access is denied)
Name of the exe = System
Parent process ID = 0x00000000
...
...
...
Beware, the output is very long! You may pipe the output to a text file:
your_program_name > the_text_file_name.txt
For this example, with myprocess is the program name and test.txt is the text file used to redirect the output:
myprocess > test.txt
Further reading and digging:
Microsoft C references, online MSDN.
Microsoft Visual C++, online MSDN.
ReactOS - Windows binary compatible OS - C/C++ source code repository, Doxygen.
Linux Access Control Lists (ACL) info can be found atAccess Control Lists.
For Multi bytes, Unicode characters and Localization please refer to Locale, wide characters & Unicode (Story) and Windows users & groups programming tutorials (Implementation).
Structure, enum, union and typedef story can be found C/C++ struct, enum, union & typedef.
Check the best selling C / C++ and Windows books at Amazon.com.