Click here to Skip to main content
Click here to Skip to main content

Snapshot Running Processes With SeguroList, Part 1

, 21 Aug 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
Creating a utility to take a snapshot of my system's running processes leads to more learning.

Introduction

For quite some time I have wanted a program which would take a snapshot of all the processes running on my machine.  Well, that's fairly easy and a lot of programs out there can iterate through the running processes.  But I wanted more.  I wanted a way to :

  1. Grab a current snapshot of processes as a baseline
  2. Save the snapshot off somewhere, somehow.
  3. At a later date (minute, hour, day, week, etc.), run my program again and have it show me the diff between what was running and what is running at the present.  I would like this diff to be some kind of nice UI which would be very intuitive.  

The diff information would have to include:

  • Which processes were running but aren't running now?
  • Which processes are running now that weren't then?
  • Even if PROCNAME was running before and still is, then is it the exact same one -- or is a newer or different version running?
  • Even if the process running is the same one, are the same Modules (DLLs) loaded for that process?

Security Related Information

Then after all that, I want to have a way to indicate if each process and module is a known / certified and valid process or module.  This may sound way over the top but I have a good way of doing this that is possible.

All of this may sound like quite a lot and way too much for me so that makes it a perfect project to share.  I hope you enjoy what I've learned and decide to work with the project  and follow my series of articles.

Background

This idea has been something I've been thinking on for years, because I always want to know what is going on with my system.  However, recently as I actually decided to create the program I bumped into some small issues related to 64bit processes and 32bit processes (more about this later).  After that I almost gave up, because as I was learning about that I stumbled upon the great SystemInternals utilties.

Why I Almost Gave Up

There is a fantastic utility which will list all of your running processes created by the SysInternals team.  It is called Process Explorer and it is truly amazing with a great UI.  

You can get that great program at: http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx

Not only does it have a great UI, but it does everything you can imagine and more.  But it doesn't create this idea of process snapshots and that is what I really want.  So after a couple of days of sitting around and not writing my program I decided to move forward anyway.  

What We Will Learn

I believe this can be really interesting project and here are the things we will delve into in the first one or two articles:

  • Serializing / Deserializing classes to/from JSON (some interesting things when dealing with collections of objects)
  • A little view and model separation of concerns that makes it all easier
  • Good ways (and less good ways) of running processes in the background
  • The challenges of iterating through the list of process modules (DLLs) when the main process is 64bit and one way to solve this problem.
  • WPF - very little now, but more as we go along

First Article: What Will It Cover?

In this article I will show you what I've learned about:

  • Getting all running processes
  • Iterating through those processes to get the DLLs which each process loads.
  • The challenges when you are running a 64bit Windows OS and a brute-force way to solve that problem
  • Builiding SeguroList as Run On Any CPU, but determining which CPU user's system has.
  • The main class SegListProc which we use to Model a process.
  • How to serialize and deserialize a collection of SegListProc to JSON using basic .NET framework library
  • A generic method to display a collection of SegListProc in a WPF TreeView.
  • A bit about my 256 bit hashkey algorithm and why I chose the 256 bit hash key -- hint: related to www.virustotal.com

Why Is It Named SeguroList?

Seguro means safe or secure in Spanish.  For quite some time I have thought the antivirus makers should just keep a list of all the good (safe) executables instead of listing every virus.  More about this as we go along. Anyway, just trying to name the thing a bit differently, so instead of SafeList, I've named it SeguroList.

Please Don't Judge Me By The Present UI

Here's a quick screenshot of the current state of the UI.  This is just a quick utility so I can do proof of concept and insure that I can serialize / deserialize the JSON for my class and then display it nicely in a TreeView control.  Of course much more will come in following articles.  

Separation of Concerns: Future Development

However, I hope you see the huge value in how I've separated out the SegListProc model so we can easily keep adding to it as we move forward.  This is the power of OOP.

Now, let's begin by talking about iterating through the running processes.

Iterating Running Processes and Modules

It is extremely easy to get a list of all the running processes using C#.  

Warning: While we take a look at this, please keep in mind that you must be an administrator on your system to be able to see all the processes which are running on your system.  I'm not going to go through all those issues right now.

If you get the source code from the download you can take a look at the BuildProcessList() method and you will see something similar to the following code snippet:

using System.Diagnostics;
//...
private void BuildProcessList()
        {
            Process[] allProcs = Process.GetProcesses(); // 1. call static method
            int counter = 0;

            foreach (Process p in allProcs) // 2. iterate through the array of processes
            {

                try
                {
                    foreach (ProcessModule pm in p.Modules) // 3. iterate through list of DLLs

                 .....

 

The .NET Process class (found in System.Diagnostics) helps us to get the list of processes that are currently running on the machine.  We simply call the static method Process.GetProcesses() and it returns an array of those processes.  It couldn't be any easier*.

After that we can just foreach through the list of Processes grabbing each loaded ProcessModule (DLL) from the collection called Modules contained within each Process object.  Well, I said it couldn't be easier, but I'm actually wrong, because there are some issues*.

64-Bit Challenges

If you run SeguroList on a 32-bit OS, you will never see a problem (as long as you have full administrative privileges).  That's because SeguroList will run as a 32-bit program and it will iterate through a list of 32-bit programs and it can iterate the ProcessModules of all the 32-bit programs.

Build As AnyCPU

In the Project...Project Options... I have set the SeguroList to build for AnyCPU, which means if you are running a 64-bit OS then SeguroList will become a 64-bit app and if you're running a 32-bit OS SeguroList becomes a 32-bit app.

64-Bit Apps Cannot Examine ProcessModules of 32-Bit Apps

You will notice no real problem if you are running a 32-bit OS. However, if you are running a 64-bit OS, as I am, 32-bit apps running on your system -- and there are far more than you may have believed -- will throw an exception when we attempt to iterate their ProcessModules.  A 64-bit application is not allowed to inspect those ProcessModules.  I searched all over for a solution to this problem and finally came up with a workaround.

No Easy Way To Determine If Another Process Is Running As 64 or 32 Bit

There are more difficulties in that there is no easy way to determine if a particular running process is 64 or 32 bit.  However, I've created a work-around solution for this.

Work-Around Solution: Keep It Simple, Smarty (KISS)

Take another look at a partial snippet of the BuildProcessList method and you will see some code which checks to see if a couple of DLLs are loaded in a process.  Those DLLs are the ones which indicate that the 32-bit app is running under the 64-bit OS.  They are the Windows On Windows DLLs.

foreach (ProcessModule pm in p.Modules)
  {
     if (pm.ModuleName.ToUpper() == "WOW64.DLL" || pm.ModuleName.ToUpper() == "WOW64WIN.DLL")
        {
             is32BitProc = true;
             break;
        }

So basically, if I find out that the current process has either one of those DLLS loaded, then I do not even attempt to iterate through it's ProcessModules, becuase it is a 32-bit app and it will fail anyway.  Instead I set a flag and break out immediately so I don't waste more time.

But, then how do we get a list of the 32-bit ProcessModules?  That's where another work-around comes in.  

Get 32-Bit Apps & Modules From 64-bit Process

To do this I have written a separate program called SeguroListCL (command-line) which the initial SeguroList program can spawn if needed.

The Beauty of Re-Use: Not Just A Promise

When it spawns that program -- when running on a 64-bit OS -- command-line program uses the exact same SegListProc class so that it can generate it's list of 32-bit processes and ultimately serialize them to a file, which the initial program can then render in it's TreeView of all processes.

Separation of Concerns Is Power

You see, that is the beauty of re-use.  Two different programs are using the exact same code.  Because I have Separation of Concerns, I can re-use my code in any number of programs and it makes me faster as a developer and I waste less time.

SegListProc: Model of Processes

However, since we want to keep this information in an organized way, we want to store it in a class (our Model). We will use this class to represent all of this information and allow us to organize our code.  That's where the SegListProc class comes in.   Let's take a look at that some of the interesting parts of that class, because it is the most important class in our program since it is the class that everything else will interact with.

Note: I've decided to only display the interesting parts below, if you want to see the entire class, take a look at the source download.

/// <summary>
    /// SegListProc is the class which wraps up all the information
    /// related to windows process / or ProcessModule
    /// </summary>
    public class SegListProc
    {
        private string name;
        private string fileName;
        private int processId;
        /// <summary>
        /// The 256 bit hash of the file
        /// </summary>
        private string hashKey;
        private List<string> childrenHashKeys;
        
        private JavaScriptSerializer serializer;
                   
        public List<string> ChildrenHashKeys
        {
            get { return childrenHashKeys; }
            set { childrenHashKeys = value; }
        }

        public void AddChild(string childHashKey)
        {
            if (childrenHashKeys == null)
            {
                childrenHashKeys = new List<string>();
            }
            if (this.HashKey == childHashKey)
            {
                //childHashKey = "0";
            }
            childrenHashKeys.Add(childHashKey);
        }

        public string GetJSON()
        {
            serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
            return serializer.Serialize(this);
        }

        public SegListProc LoadFromJSON(string json)
        {
            serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
           return (SegListProc) serializer.Deserialize(json, this.GetType());
        }
        
        private string CreateHashValue()
        {
            System.Diagnostics.FileVersionInfo fiv = System.Diagnostics.FileVersionInfo.GetVersionInfo(fileName);
        
            Byte [] allBytes = File.ReadAllBytes(fileName);
            return Hash(allBytes);
        }
    }

First of all notice that we have a couple of properties where I keep the Name (of the exe or dll) which is the short filename (no path) and the FileName (which includes the entire path).

Next, you see a place where we can store a ProcessId (which uniquely identifies every parent process which is running in the system).  I also generate a 256 bit SHA Hashkey to uniquely identify the process.  

How I Generate A 256 bit SHA HashKey

Take a look at the simple CreateHashValue() method above and you can see the basics of how I generate a hashkey from the actual bytes in the file that the process was originally loaded from.  Why do I do that?

Why Generate A HashKey?

Keep in mind that one of my goals to is create a list of the exact processes which are loaded in memory.  The best way to do that is to know which file the Process loaded from.  That is easy to get using the fileName that is associated with the Process object.  However, I need to take a snapshot of that exact file so I can know if the bytes loaded in memory are the same ones that were loaded at some other time.  The best way to do this is to create a one-way Hash (SHA 256 bit) which will always represent that exact file.

VirusTotal Team Uses 256 Bit SHA HashKey

This is the exact value that the VirusTotal team has chosen to use to track files also.  That means when you upload a file to VirusTotal.com you will see that one of the details is the 256 Bit SHA hashkey.  That uniquely identifies that file and it really cannot (theoretically at this time) be hacked.  You will know that is the same file.  Here's a snapshot of the first step when uploadoing the shell32.dll from my c:\windows\system32\ directory to VirusTotal.

virus total step 1

VirusTotal already knows the file has been analyzed in the past.  How can it know that?  It is simply because it creates a one-way hash from the bytes in the file. I do the same thing.  That way, later I can even use VirusTotal to verify files.  I think that is pretty cool.  

You can see the 256 Bit Hash value which is generated by Virus Total to identify the shell32.dll in the next image:

So if you take a close look at the code, you will see that every time I create a new SegListProc the CreateHashValue() method is called.  When that method is called I read every byte of the file in and create the Hash key with the following line: 

Byte [] allBytes = File.ReadAllBytes(fileName);

This is a really cool way to know that two files are exactly the same.  

ProcessModules : Children to Each Parent Process

I have to do the same thing for every DLL and in our case, every child DLL (ProcessModule) is also a SegListProc so I create the DLL and add it to the childrenHashKeys list.  This way I can identify which ProcessModules (DLLs) each parent owns (or has loaded).

Running The Program

  1. Get or build the two executables
  2. Drop the two executables in a directory where you have read/write access (if you're running 64-bit OS, it creates a JSON file in that directory)
  3. Run the SeguroList.exe (UI).  If the program needs to, it will call SeguroListCL.

CAVEAT !!

Make sure you run the application AS ADMINISTRATOR or the SeguroList will not be able to find processes it doesn't own.

Why Is It So Slow?

The first thing everyone is going to wonder, is why is it so slow?  Please consider that this thing is examining every running process in your system and iterating down through every loaded module.  When you see the large number of items listed you may be very amazed.  Also, please compare my program to the SystemInternals Process Explorer.  I'm really not slower than they are.  This just takes a while.

Obviously there are things I can do to speed it up and/or make the user experience better.  We will talk about those things in future articles.

When you start the app you'll see a WPF SplashScreen which basically loads a PNG graphic (see following image) just so you know the app is doing something.

SeguraList splash screen

Finally, you will see the main screen which will include a list of all processes (64 & 32 bit on the left) in a treeview, which can be clicked to see each associated ProcessID and ProcessModule.

main segurolist window

Clicking the Save JSON Button

Clicking that button will allow you to save the Process List in the left-hand treeview to a file of your choosing (JSON format).

Load JSON Button

Then, you can load that JSON from that file and it will render in the TreeView on the bottom right.  It's just a proof-of-concept thing.

Double-Clicking TreeView Nodes

If you double-click any treeview node it will copy the associated JSON for that node into the textbox on the right top of the screen.  Again, just a way to look at the JSON.

Looking To The Next Article

I think that is enough in this first article.  We will go over more things and hopefully answer any questions you may have in the second article.  I will also clean up much of the program and make it more user friendly.  We will also look more closely at the serialization / deserialization to/from JSON.

There are many other things to talk about like:

  • WPF SplashScreen - adds a reference to a PNG file in your .proj file. What? Very odd.  And no place I can find in VStudio 2012 to edit that.
  • LazyLoading some of the work the SegListProc class does so it will be more responsive.
  • Serialize and Deserialize and nested collection classes with SegListProc.  This was a challenge that didn't work as I expected it to.  Am going to investigate NewtonSoft.JSON project to see if it works.
  • How SeguroList and SeguroListCL are tied by the output (procs.json) of SeguroListCL  - kind of a magic thing.  Should be able to pass a filename you are expecting.
  • Need to talk about the DisplayProcessList() method which takes a treeView and a collection of SegProcList items and will render them to the tree.  Very cool, one-stop shopping for your display needs.  
  • Need to make it much more evident which processes in the list are 32 bit ones.

Build Notes

  • Make sure both projects' root folders are in the same directory.
  • Open the SLN file in the SegList project.
  • There is a POST BUILD EVENT in the SegListCL will copy the SegListCL to the bin\release or bin\debug directory.
  • Watch out, debug has some #if DEBUG statements that may make it run a little differently for testing.

Known Bugs

  • There seems to be a problem on 32 Bit systems when saving the JSON and then deserializing it to display in the treeview. Very odd.

History

Initial release: 08/21/2014

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

newton.saber
Architect
United States United States
My newest book is Learn Python, Think Python (amazon link opens in new window/tab)
 
My previous book is Object-Oriented JavaScript (See it at Amazon.com)
 
My book, Learn JavaScript - amazon.com link is available at Amazon.
 
My upcoming book, Learn AngularJS - Think AngularJS, will be releasing later in 2014.
 
You can learn more about me and my other books, at, NewtonSaber.com
Follow on   Twitter

Comments and Discussions

 
QuestionA very informative article! PinmemberjediYL23-Aug-14 21:02 
AnswerRe: A very informative article! Pinmembernewton.saber24-Aug-14 6:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141220.1 | Last Updated 21 Aug 2014
Article Copyright 2014 by newton.saber
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid