To begin walking the Windows process list, we have to start by first enabling kernel mode debugging on our host. To enable kernel mode debugging on Windows 10, I did the following within an "Administrator" command prompt (cmd.exe).
C:\WINDOWS\system32>bcdedit /debug ON The operation completed successfully.
Once the computer rebooted and I started WinDbg, the next thing was to take a look at what the doubly linked list structure looks like.
lkd> dt _LIST_ENTRY nt!_LIST_ENTRY +0x000 Flink : Ptr64 _LIST_ENTRY +0x008 Blink : Ptr64 _LIST_ENTRY
Note: to get help on the commands I've used, in the input bar of the WinDbg "command" window, execute ".hh" and this will bring up the help screen. Once in there search for your command to learn what they do.
Above, we see that the list has two entries. One is the "Flink" and the second is the "Blink". To understand how these are used, we can look at the following blog post on "Kernel-Mode Basics: Windows Linked Lists" from the folks at OSR Online.
To begin walking the list, we need to find the head of this list. We can do this by looking at "nt!PsActiveProcessHead".
lkd> x nt!PsActiveProcessHead fffff800`625ad3b0 nt!PsActiveProcessHead = <no type information>
From above, we see that our Active Process Head can be found at address "fffff800`625ad3b0".
Now that we have the pointer to the list, let's see what its Flink and Blink points to:
lkd> dt _LIST_ENTRY fffff800`625ad3b0 nt!_LIST_ENTRY [ 0xffff998b`c62cb328 - 0xffff998b`e9ae9368 ] +0x000 Flink : 0xffff998b`c62cb328 _LIST_ENTRY [ 0xffff998b`c636b328 - 0xfffff800`625ad3b0 ] +0x008 Blink : 0xffff998b`e9ae9368 _LIST_ENTRY [ 0xfffff800`625ad3b0 - 0xffff998b`e636d368 ]
Ok! From above we see some values returned for the Flink and Blink. Let's now learn where within the EPROCESS structure is the _LIST_ENTRY for "ActiveProcessLinks" found. Rather than list the entire EPROCESS structure, I've taken a bit of a short cut by specifying the "-y" option to get the specific field.
lkd> dt nt!_EPROCESS -y ActiveProcessLinks +0x2e8 ActiveProcessLinks : _LIST_ENTRY
To help get further clarity, let's pick on a process which is currently running. To see the list of processes currently known by the Kernel, let's use the "!process" extension.
lkd> !process 0 0 **** NT ACTIVE PROCESS DUMP **** PROCESS ffff998bc62cb040 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 001aa002 ObjectTable: ffffd605aca14040 HandleCount: 6914. Image: System .... PROCESS ffff998bd5c3b080 SessionId: 1 Cid: 1858 Peb: baa6893000 ParentCid: 13d8 DirBase: 31d200002 ObjectTable: 00000000 HandleCount: 0. Image: notepad.exe PROCESS ffff998bd6303080 SessionId: 1 Cid: 234c Peb: e97bb99000 ParentCid: 198c DirBase: 3dc400002 ObjectTable: 00000000 HandleCount: 0. Image: firefox.exe ....
Above, we see a snapshot of some of the process returned from my use of "!process 0 0". Let's pick on "notepad.exe" at address "ffff998bd5c3b080"
lkd> !process 0xffff998bd5c3b080 0 PROCESS ffff998bd5c3b080 SessionId: 1 Cid: 1858 Peb: baa6893000 ParentCid: 13d8 DirBase: 31d200002 ObjectTable: 00000000 HandleCount: 0. Image: notepad.exe
Now that we have the process at the address and confirm it is "notepad.exe", let's now look at the EPROCESS structure of it.
lkd> dt nt!_EPROCESS ffff998bd5c3b080 -y ActiveProcessLinks +0x2e8 ActiveProcessLinks : _LIST_ENTRY [ 0xffff998b`d6303368 - 0xffff998b`d3d2c868 ]
From above, just as we saw before the "ActiveProcessLinks" can be found at +0x2e8. Therefore, to confirm if we subtract 0x2e8 from ffff998bd5c3b080, we will get to the head of the EPROCESS structure, let's test that theory.
lkd> dt nt!_EPROCESS ffff998bd5c3b080-0x2e8 +0x000 Pcb : _KPROCESS +0x2d8 ProcessLock : _EX_PUSH_LOCK +0x2e0 UniqueProcessId : 0xffffd605`b6216ea6 Void +0x2e8 ActiveProcessLinks : _LIST_ENTRY [ 0x00000001`00b60003 - 0xffff998b`d5c3b088 ] +0x2f8 RundownProtect : _EX_RUNDOWN_REF +0x300 Flags2 : 0xd5c3b098 +0x300 JobNotReallyActive : 0y0 +0x300 AccountingFolded : 0y0 +0x300 NewProcessReported : 0y0 .....
From above we see we are at the top of the EPROCESS structure. Let's move on to see how we can map the rest of the processes. To do so, let's do like Ami and go back to something we did before. That is to once again, figure out the head of the list by looking at the address of "PSActiveProcessHead".
lkd> x nt!PsActiveProcessHead fffff800`625ad3b0 nt!PsActiveProcessHead = <no type information>
Once again, we get the value we had before in "fffff800`625ad3b0". Now that we have this, let's look at the _LIST_ENTRY once again.
lkd> dt nt!_LIST_ENTRY fffff800`625ad3b0 [ 0xffff998b`c62cb328 - 0xffff998b`ea802568 ] +0x000 Flink : 0xffff998b`c62cb328 _LIST_ENTRY [ 0xffff998b`c636b328 - 0xfffff800`625ad3b0 ] +0x008 Blink : 0xffff998b`ea802568 _LIST_ENTRY [ 0xfffff800`625ad3b0 - 0xffff998b`e7b2b868 ]
Once again, the values look similar to what we saw before. Let's use the Flink value "0xffff998b`c62cb328" to begin walking the list. Do remember, we need to subtract "0x2e8" to get to the beginning of the next EPROCESS structure. Let's do that and grab the "ImageFileName" and the "ActiveProcessLinks" of the next process.
lkd> dt nt!_EPROCESS 0xffff998b`c62cb328-0x2e8 -y ActiveProcessLinks.Flink -y ActiveProcessLinks.Blink -y ImageFileName +0x2e8 ActiveProcessLinks : [ 0xffff998b`c636b328 - 0xfffff800`625ad3b0 ] +0x000 Flink : 0xffff998b`c636b328 _LIST_ENTRY [ 0xffff998b`d0e97868 - 0xffff998b`c62cb328 ] +0x008 Blink : 0xfffff800`625ad3b0 _LIST_ENTRY [ 0xffff998b`c62cb328 - 0xffff998b`ea78e468 ] +0x450 ImageFileName : [15] "System"
From above we see the first process is "System". We also see for it's "ActiveProcessLinks.Flink" that is the next process, it is at "0xffff998b`c636b328" while the "ActiveProcessLinks.Blink" is at "0xfffff800`625ad3b0". Let's use the same logic we did previously to learn what is the next process seen by the Kernel after the "System" process. Do remember to once again subtract "0x2e8" from the "ActiveProcessLinks.Flink" value you received above.
Above, we see the next process is the "Registry". Let's do two more examples to see if this pattern continues.
... and finally for the Flink ...
lkd> dt nt!_EPROCESS 0xffff998b`c636b328-0x2e8 -y ActiveProcessLinks.Flink -y ActiveProcessLinks.Blink -y ImageFileName +0x2e8 ActiveProcessLinks : [ 0xffff998b`d0e97868 - 0xffff998b`c62cb328 ] +0x000 Flink : 0xffff998b`d0e97868 _LIST_ENTRY [ 0xffff998b`da09e868 - 0xffff998b`c636b328 ] +0x008 Blink : 0xffff998b`c62cb328 _LIST_ENTRY [ 0xffff998b`c636b328 - 0xfffff800`625ad3b0 ] +0x450 ImageFileName : [15] "Registry"
Above, we see the next process is the "Registry". Let's do two more examples to see if this pattern continues.
lkd> dt nt!_EPROCESS 0xffff998b`d0e97868-0x2e8 -y ActiveProcessLinks.Flink -y ActiveProcessLinks.Blink -y ImageFileName +0x2e8 ActiveProcessLinks : [ 0xffff998b`da09e868 - 0xffff998b`c636b328 ] +0x000 Flink : 0xffff998b`da09e868 _LIST_ENTRY [ 0xffff998b`d085b868 - 0xffff998b`d0e97868 ] +0x008 Blink : 0xffff998b`c636b328 _LIST_ENTRY [ 0xffff998b`d0e97868 - 0xffff998b`c62cb328 ] +0x450 ImageFileName : [15] "smss.exe"
lkd> dt nt!_EPROCESS 0xffff998b`da09e868-0x2e8 -y ActiveProcessLinks.Flink -y ActiveProcessLinks.Blink -y ImageFileName +0x2e8 ActiveProcessLinks : [ 0xffff998b`d085b868 - 0xffff998b`d0e97868 ] +0x000 Flink : 0xffff998b`d085b868 _LIST_ENTRY [ 0xffff998b`d0859868 - 0xffff998b`da09e868 ] +0x008 Blink : 0xffff998b`d0e97868 _LIST_ENTRY [ 0xffff998b`da09e868 - 0xffff998b`c636b328 ] +0x450 ImageFileName : [15] "csrss.exe"
Looks good so far. Let's verify this by looking by at the "!process" extension.
kd> !process 0 0 **** NT ACTIVE PROCESS DUMP **** PROCESS ffff998bc62cb040 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 001aa002 ObjectTable: ffffd605aca14040 HandleCount: 7052. Image: System PROCESS ffff998bc636b040 SessionId: none Cid: 0060 Peb: 00000000 ParentCid: 0004 DirBase: 1e0c00002 ObjectTable: ffffd605aca28c00 HandleCount: 0. Image: Registry PROCESS ffff998bd0e97580 SessionId: none Cid: 01d4 Peb: 65129c2000 ParentCid: 0004 DirBase: 296d10002 ObjectTable: ffffd605af644540 HandleCount: 52. Image: smss.exe PROCESS ffff998bda09e580 SessionId: 0 Cid: 02a8 Peb: 705bc80000 ParentCid: 028c DirBase: 199900002 ObjectTable: ffffd605ae720c00 HandleCount: 756. Image: csrss.exe PROCESS ffff998bd085b580 SessionId: 0 Cid: 0304 Peb: 3aa038000 ParentCid: 028c DirBase: 45bc00002 ObjectTable: ffffd605af212380 HandleCount: 155. Image: wininit.exe PROCESS ffff998bd0859580 SessionId: 1 Cid: 030c Peb: 5e45a62000 ParentCid: 02f8 DirBase: 334200002 ObjectTable: ffffd605aea12680 HandleCount: 1213. Image: csrss.exe PROCESS ffff998bda3ea480 SessionId: 0 Cid: 0354 Peb: a3794a6000 ParentCid: 0304 DirBase: 19a00002 ObjectTable: ffffd605afc25e80 HandleCount: 847. Image: services.exe PROCESS ffff998bd85e8580 SessionId: 0 Cid: 0368 Peb: 6c5042e000 ParentCid: 0304 DirBase: 107a00002 ObjectTable: ffffd605afd3b8c0 HandleCount: 1749. Image: lsass.exe PROCESS ffff998bd8e25080 SessionId: 1 Cid: 03a4 Peb: 35e2b86000 ParentCid: 02f8 DirBase: 46a800002 ObjectTable: ffffd605b091f600 HandleCount: 256. Image: winlogon.exe .... PROCESS ffff998bea2e4580 SessionId: 1 Cid: 26cc Peb: 1002d1000 ParentCid: 0f34 DirBase: 4a700002 ObjectTable: ffffd605b9b0a040 HandleCount: 142. Image: SystemIdleCheck.exe PROCESS ffff998bf5ea0380 SessionId: 0 Cid: 27ac Peb: ce9260a000 ParentCid: 0354 DirBase: 61900002 ObjectTable: ffffd605c637b680 HandleCount: 192. Image: WmiApSrv.exe
Believe it or not, it is just the same as we did above. Only difference is instead of using the address in the Flink, we instead use the addresses in the Blink.
Let's look at the "Registry" process to see what it points to via its Blink.
lkd> !process ffff998bc636b040 0 PROCESS ffff998bc636b040 SessionId: none Cid: 0060 Peb: 00000000 ParentCid: 0004 DirBase: 1e0c00002 ObjectTable: ffffd605aca28c00 HandleCount: 0. Image: Registry
Let's look at its "ActiveProcessLinks.Flink" and "ActiveProcessLinks.Blink".
lkd> dt nt!_EPROCESS ffff998bc636b040 -y ActiveProcessLinks.Flink -y ActiveProcessLinks.Blink -y ImageFileName +0x2e8 ActiveProcessLinks : [ 0xffff998b`d0e97868 - 0xffff998b`c62cb328 ] +0x000 Flink : 0xffff998b`d0e97868 _LIST_ENTRY [ 0xffff998b`da09e868 - 0xffff998b`c636b328 ] +0x008 Blink : 0xffff998b`c62cb328 _LIST_ENTRY [ 0xffff998b`c636b328 - 0xfffff800`625ad3b0 ] +0x450 ImageFileName : [15] "Registry"
If we now look at the Blink value to see where it points, we see we get:
lkd> dt nt!_EPROCESS 0xffff998b`c62cb328-0x2e8 -y ActiveProcessLinks.Flink -y ActiveProcessLinks.Blink -y ImageFileName +0x2e8 ActiveProcessLinks : [ 0xffff998b`c636b328 - 0xfffff800`625ad3b0 ] +0x000 Flink : 0xffff998b`c636b328 _LIST_ENTRY [ 0xffff998b`d0e97868 - 0xffff998b`c62cb328 ] +0x008 Blink : 0xfffff800`625ad3b0 _LIST_ENTRY [ 0xffff998b`c62cb328 - 0xffff998b`ea5a35a8 ] +0x450 ImageFileName : [15] "System"
Nice!!! As expected, "Registry" Blink points to the previous process in the list which is "System". Let's look at one more. Once again, considering what we looked at previously, let's look at the "smss.exe" process to see where that points. If all goes according to plan, its Blink should be pointing to "Registry". Let's see if this holds true.
lkd> !process ffff998bd0e97580 0 PROCESS ffff998bd0e97580 SessionId: none Cid: 01d4 Peb: 65129c2000 ParentCid: 0004 DirBase: 296d10002 ObjectTable: ffffd605af644540 HandleCount: 52. Image: smss.exe
Let's look at its "ActiveProcessLinks.Flink" and "ActiveProcessLinks.Blink".
lkd> dt nt!_EPROCESS ffff998bd0e97580 -y ActiveProcessLinks.Flink -y ActiveProcessLinks.Blink -y ImageFileName +0x2e8 ActiveProcessLinks : [ 0xffff998b`da09e868 - 0xffff998b`c636b328 ] +0x000 Flink : 0xffff998b`da09e868 _LIST_ENTRY [ 0xffff998b`d085b868 - 0xffff998b`d0e97868 ] +0x008 Blink : 0xffff998b`c636b328 _LIST_ENTRY [ 0xffff998b`d0e97868 - 0xffff998b`c62cb328 ] +0x450 ImageFileName : [15] "smss.exe"
lkd> dt nt!_EPROCESS 0xffff998b`c636b328-0x2e8 -y ActiveProcessLinks.Flink -y ActiveProcessLinks.Blink -y ImageFileName +0x2e8 ActiveProcessLinks : [ 0xffff998b`d0e97868 - 0xffff998b`c62cb328 ] +0x000 Flink : 0xffff998b`d0e97868 _LIST_ENTRY [ 0xffff998b`da09e868 - 0xffff998b`c636b328 ] +0x008 Blink : 0xffff998b`c62cb328 _LIST_ENTRY [ 0xffff998b`c636b328 - 0xfffff800`625ad3b0 ] +0x450 ImageFileName : [15] "Registry"
Now for the image below. The image below represents a snapshot of what we saw above. However, I did not map all processes but the concept remains the same.
Well hope you enjoyed this post.
As always, do leave a comment if you think I missed something.
Reference:
http://jumpdollar.blogspot.com/2014/09/windbg-walking-windows-linked-lists.html
http://www.osronline.com/article.cfm?article=499
https://www.blackhat.com/presentations/win-usa-04/bh-win-04-butler.pdf
No comments:
Post a Comment