|< Windows Process & Threads Programming 6 | Main | Windows Process & Threads Programming 8 >| Site Index | Download |


 

 

 

MODULE U1

PROCESSES AND THREADS: Win32/WINDOWS APIs

Part 7: More Program Examples

 

 

 

What we will learn in this Module?

 

  1. Enumerating All Modules For a Process.

  2. Traversing the Module List.

  3. Taking a Snapshot and Viewing Processes.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

My Training Period: yy hours. Before you begin, read some instruction here.

 

The expected abilities include:

  • Able to understand and use various processes and threads functions (Windows APIs/Win32).

  • Able to build and run your own simple processes and threads programs.

  • Able to understand, build and run your own simple multithreading programs.

  • Able to extract, understand and use functions information from MSDN documentation.

Note: For Multithreaded program examples, you have to set your project to Multithread 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 the EnumProcessModules() function to enumerate the modules of current processes in the system.

 

// For WinXp

#define _WIN32_WINNT 0x0501

#include <windows.h>

#include <stdio.h>

#include <psapi.h>

 

void PrintModules(DWORD processID)

{

    HMODULE hMods[1024];

    HANDLE hProcess;

    DWORD cbNeeded;

    unsigned int 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;

    unsigned int 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 the PrintModules() 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.

 

Traversing the Module List

 

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 the CreateToolhelp32Snapshot() 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.

 

// For WinXp

#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:

 

 

 

 

 

 

 

 

 

 

 

 

--------------------------------------------------------------------------

 

 

 

 

Windows process: Traversing the module list example

 

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 using CreateToolhelp32Snapshot(), and then it walks through the list recorded in the snapshot using Process32First() and Process32Next(). For each process in turn, GetProcessList() calls the ListProcessModules() 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:

 

  1. Microsoft Visual C++, online MSDN.

  2. For Multibytes, Unicode characters and Localization please refer to Locale, wide characters & Unicode (Story) and Windows users & groups programming tutorials (Implementation).

  3. Structure, enum, union and typedef story can be found C/C++ struct, enum, union & typedef.

  4. Check the best selling C / C++ and Windows books at Amazon.com.

 

 

 

 

 

 

 

 |< Windows Process & Threads Programming 6 | Main | Windows Process & Threads Programming 8 >| Site Index | Download |