Windows uses a circular double linked list of _EPROCESS structures to keep track of all the active processes. The _EPROCESS structure contains a field called ActiveProcessLinks which is of type LIST_ENTRY. The _LIST_ENTRY is another structure that contains two members, as shown in the following command output. The Flink (forward link) points to the _LIST_ENTRY of the next _EPROCESS structure, and the Blink (backward link) points to the _LIST_ENTRY of the previous _EPROCESS structure:
kd> dt nt!_LIST_ENTRY
+0x000 Flink : Ptr64 _LIST_ENTRY
+0x008 Blink : Ptr64 _LIST_ENTRY
Flink and Blink together create a chain of process objects; this can be visualized as follows:
A point to note is that Flink and Blink do not point to the start of the _EPROCESS structure. Flink points to the start (first byte) of the _LIST_ENTRY structure of the next _EPROCESS structure, and Blink points to the first byte of the _LIST_ENTRY structure of the previous _EPROCESS structure. The reason why this is important is that, once you find the _EPROCESS structure of a process, you can walk the doubly linked list forward (using Flink) or backward (Blink) and then subtracting an offset value to get to the start of the _EPROCESS structure of the next or the previous process. To help you understand what this means, let's look at the values of the fields Flink and Blink in the _EPROCESS structure of smss.exe:
kd> dt -b -v nt!_EPROCESS fffffa8061d35700
struct _EPROCESS, 135 elements, 0x4d0 bytes
.....
+0x180 UniqueProcessId : 0x00000000`000000fc
+0x188 ActiveProcessLinks : struct _LIST_ENTRY, 2 elements, 0x10 bytes
[ 0xfffffa80`62583cb8 - 0xfffffa80`6106ccb8 ]
+0x000 Flink : 0xfffffa80`62583cb8
+0x008 Blink : 0xfffffa80`6106ccb8
Flink has a value of 0xfffffa8062583cb8; this is the start address of the ActiveProcessLinks (Flink) of the next _EPROCESS structure. Since ActiveProcessLinks, in our example, is at offset 0x188 from the start of the _EPROCESS, you can get to the beginning of the _EPROCESS structure of the next process by subtracting 0x188 from the Flink value. In the following output, note how by subtracting 0x188 we landed on the _EPROCESS structure of the next process, which is csrss.exe:
kd> dt nt!_EPROCESS (0xfffffa8062583cb8-0x188)
+0x000 Pcb : _KPROCESS
+0x160 ProcessLock : _EX_PUSH_LOCK
[REMOVED]
+0x180 UniqueProcessId : 0x00000000`0000014c Void
+0x188 ActiveProcessLinks : _LIST_ENTRY [ 0xfffffa80`625acb68 - 0xfffffa80`61d35888 ]
+0x198 ProcessQuotaUsage : [2] 0x2c18
[REMOVED]
+0x288 Win32WindowStation : (null)
+0x290 InheritedFromUniqueProcessId : 0x00000000`00000144 Void
[REMOVED]
+0x2d8 Session : 0xfffff880`042ae000 Void
+0x2e0 ImageFileName : [15] "csrss.exe"
+0x2ef PriorityClass : 0x2 ''
As you can see, by walking the doubly linked list, it is possible to list the information about all the active processes running on the system. On a live system, tools such as task manager or Process Explorer make use of API functions, which ultimately rely on finding and walking the same doubly linked list of _EPROCESS structures that exist in kernel memory. The pslist plugin also incorporates the logic of finding and walking the same doubly linked list of _EPROCESS structures from the memory image. To do that, the pslist plugin finds a symbol named _PsActiveProcessHead, which is defined in ntoskrnl.exe (or ntkrnlpa.exe). This symbol points to the beginning of the doubly linked list of _EPROCESS structures; the pslist then walks the doubly linked list of the _EPROCESS structures to enumerate all the running processes.
The Art of Memory Forensics: Detecting Malware and Threats in Windows, Linux, and Mac Memoryby Michael Hale Ligh, Andrew Case, Jamie Levy, and Aaron Walters.
As mentioned earlier, a plugin such as pslist supports multiple options and arguments; this can be displayed by typing -h (--help) next to the plugin's name. One of the pslist options is --output-file. You can use this option to redirect the pslist output to the file, as shown here:
$ python vol.py -f perseus.vmem --profile=Win7SP1x86 pslist --output-file=pslist.txt
Another option is -p (--pid). Using this option, you can determine the information of a specific process if you know its process ID (PID):
$ python vol.py -f perseus.vmem --profile=Win7SP1x86 pslist -p 3832
Volatility Foundation Volatility Framework 2.6
Offset(V) Name PID PPID Thds Hnds Wow64 Start
---------- ------------ ---- ---- ---- ---- ----- -------------------
0x8503f0e8 svchost..exe 3832 3712 11 303 0 2016-09-23 09:24:55