How to Enumerate the Modules Loaded in a Process

Let’s see how to use a convenient Windows API C-interface library from C++ code to enumerate the modules loaded in a given process.

Suppose that you want to enumerate all the modules in a given process in Windows, for example because you want to discover the DLLs loaded into a given process.

You can use the so called Tool Help Library for that (the associated Windows SDK header file is <tlhelp32.h>)

In particular, you can start taking the snapshot of the process’s module list, invoking the CreateToolhelp32Snapshot Windows API function. On success, this function will return a HANDLE that will be used with the following module enumeration functions.

// Create module snapshot for the enumeration.
//
// The first parameter passed to CreateToolhelp32Snapshot
// tells the API what kind of elements are included in the snapshot:
// In this case we are interested in the list of *modules*
// loaded in the process of given ID.
HANDLE hEnum = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
                                          processID);
if (hEnum == INVALID_HANDLE_VALUE)
{
    // Signal error...
}

// On success, store the raw handle in some safe RAII wrapper,
// so it will be *automatically* closed via CloseHandle, 
// even in case of exceptions.
//
// E.g.: ScopedHandle enumHandle{ hEnum };

Then you can initialize the enumeration loop calling the Module32First API function, which will return information about the first module in the list. The module information is stored as fields of the MODULEENTRTY32 structure. You can retrieve the particular pieces of information that you want (e.g. the module name, or its size, etc.) from this structure’s fields.

Next, you can repeatedly invoke the Module32Next API to get information for the subsequent modules in the list.

In C++ code, the enumeration logic can look like this:

// Initialize this structure with its size field (dwSize).
// Other fields of the structure containing module info 
// will be written by the Module32First and Module32Next APIs.
MODULEENTRY32 moduleEntry = { sizeof(moduleEntry) };

// Start the enumeration loop invoking Module32First
BOOL continueEnumeration = ::Module32First(enumHandle.Get(),
                                           &moduleEntry);
while (continueEnumeration)
{
    // Extract the pieces of information we need 
    // from the MODULEENTRY32 structure
    moduleList.push_back(
        // Here we retrieve the module name (szModule) 
        // and the module size (modBaseSize),
        // pack them in a C++ struct, and push it into
        // a vector<ModuleInfo> that will contain the list
        // of all modules in the given process
        ModuleInfo{ moduleEntry.szModule, 
                    moduleEntry.modBaseSize }
    );

    // Move to the next module (if any)
    continueEnumeration = ::Module32Next(enumHandle.Get(),
                                         &moduleEntry);
}

When there are no more modules to enumerate in the snapshot, Module32Next will return FALSE, and a subsequent call to GetLastError will return ERROR_NO_MORE_FILES.

You can see that in action in some compilable C++ code in this repo of mine on GitHub.

For example, suppose that you want to see a list of DLLs loaded in the Notepad process. You can use your favorite tool to get the process ID (PID) associated to your running instance of Notepad, then pass this PID as the only parameter to the command line tool cited above, and it will print out a list of the loaded modules (DLLs) inside the Notepad process, as shown below.

List of modules in the Notepad process.

One thought on “How to Enumerate the Modules Loaded in a Process”

Leave a comment