Windows Process Internals: A few Concepts to know before jumping on Memory Forensics [Part 2] – ldrmodules
Ldrmodules is one of the trusted plugins of Volatility suit to detect a dll-hiding or injection kind of activities in a process memory. I am sure most of the folks who have used volatility for memory analysis to detect any sort of malware are aware of “ldrmodules” plugin of the Volatility.
Today, we will talk about the Process Structures in a memory form where plugins like ldrmodules and dlllist fetch the data. If you refer the Table-1 (Mapping between Volatility Plugins and OS data structures) in the Part 1 of this article, you can see that plugins like ldrmodules and dllist depend on a Process Environment Block (PEB) structure of the _EPROCESS to get a list of the loaded dlls. _PEB, in turn, points to a different data structure called _PEB_LDR_DATA via ldr filed in a _PEB structure. _PEB_LDR_DATA structure has pointers to three doubly linked lists that stores the information about the loaded dlls for the process. In short, _PEB leads to three different linked lists that stores the information about the loaded dlls in the process memory. Please refer the following diagram to get an idea about how these structures are connected.
Ldrmodules fetches the information about loaded dlls from these 3 lists. The name of these 3 lists are as following
These 3 lists track the loaded dlls for a specific process based on their loading methods and locations in the memory.
Figure 1. Logical Connectivity view between various memory structures
Let’s us go through these data structures via live kernel debugging and see how they exactly look.
First of all, let us enumerate the loaded processes and select a process that we would like to take for further examination.
Once you have identified the offset of the process, we need to identify the _PEB offset by enumerating _EPROCESS structure as _PROCESS has a pointer to the _PEB. So, let us enumerate _EPROCESS structure and grep the pointer to the _PEB structure.
dt nt!_eprocess ffffe0814bb4d080 -y peb
Figure 2. Get the Pointer to the _PEB
We have our _PEB structure at offset 0x000000ea`83178000. Now, Let us enumerate _PEB structure to get the pointer to the _PEB_LDR_DATA structure that contains three doubly linked lists that track the loaded dlls in the process memory. _PEB stores this information under ldr field ( as mentioned above) of its structure. Ldr field points to the data structure (_PEB_LDR_DATA) that contains the 3 doubly linked lists.
Figure 3. Get the Pointer to the ldr (_PEB_LDR_DATA)
Now, let us enumerate, _PEB_LDR_DATA.
Figure 4. Get the Pointers to the module Lists
You can see the pointers to the three doubly linked lists that we discussed above. Each of these doubly linked lists stores information about the loaded dlls in the process memory via pointing to the dll structures (_LDR_DATA_TABLE_ENTRY) in the memory. Let us take FLINK of the InLoadOrderModuleList and see which dll it points to.
Figure 5. Enumerate the first entry of the InLoadOrder module list
You can see that it is pointing to the dwm.exe. Note that we are looking at the InLoadOrder list, this list tracks the dll based on the order they are loaded in to the process memory. The process executable is the first one to load when process is loaded, it is the first entry more often than not.
We can traverse through the entire list by keep following the pointers of the linkedlist. Let us do that.
Figure 6. Enumerate the entire InLoadOrder module list
Same way, we can traverse through the other 2 lists as well, however, we just need to be sure of the offsets that they are point in to the _LDR_DATA_TABLE_ENTRY. We need to factor-in that offset and subtract that offset to get on the top of the structure as shown in the diagram above. Let us take InInitializationOrder which is pointed by the offset 0x000002c7`410d26c0 and subtract the offset from this memory address and then traverse through the list.
Figure 7. Enumerate the InInitializationOrder module list
You might have noticed that InInitializationOrder list does not include the entry for the process executable (.exe) that is usually available in rest both of the lists. The reason behind that is InInitializationOrder tracks the dll based on the order dllmain function called by the process. As process executable does not have dllmain function and it loads differently than normal dll InInit list will not have entry for process executable which is by design. Hence, it is normal to observe “false” for .exe under “InInit” column in the output of ldrmodules.
That’s it for now, folks!! Happy hunting fellas!!!