When evaluating processes, first think about what properties you might want to compare. A simple comparison might just be the name of the process, but malware can be much stealthier than just running under its name like "evil_process". One of the ways malware can disguise itself is by using common names but running from incorrect locations. In this case the path of the process executable would be a good property to check. What about an instance where the malware is actually infected a legitimate process. I'm not talking about process hollowing. I'll save that discussion for a later post. In a simpler context, the malware could just overwrite the legitimate executable. In this case we could analyze the hash of the executable.
So far we have decided to look at the name, path and hash of the running process objects. How could we get this data using a PowerShell script? Fortunately, PowerShell has a built-in cmdlet that will retrieve process objects for each running process on a host machine. You could find this cmdlet using a search. This search takes advantage of PowerShell's consistent naming convention and superior documentation. These attributes combine to make PowerShell a very discoverable language. Here is how we could search for a cmdlet to retrieve running processes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PS C:\> Get-Command -Verb Get -Noun *Process* | |
CommandType Name Version Source | |
----------- ---- ------- ------ | |
Function Get-AppvVirtualProcess 1.0.0.0 AppvClient | |
Cmdlet Get-Process 3.1.0.0 Microsoft.PowerShel... | |
Cmdlet Get-ProcessMitigation 1.0.11 ProcessMitigations | |
Cmdlet Get-PSHostProcessInfo 3.0.0.0 Microsoft.PowerShel... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Get-Help Get-Process | |
NAME | |
Get-Process | |
SYNOPSIS | |
Gets the processes that are running on the local computer or a remote computer. | |
..... |
Next, we need to test and see if the cmdlet provides all the properties we want to analyze. From the previous discussion, what we want is name, executable path and a hash of the executable. To discover all the properties of objects returned from our cmdlet, simply pipe the results to Get-Member. This command will perform what's called "introspection" and display the object types along with their associated properties and methods.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Get-Process | Get-Member | |
TypeName: System.Diagnostics.Process | |
Name MemberType Definition | |
---- ---------- ---------- | |
Handles AliasProperty Handles = Handlecount | |
Name AliasProperty Name = ProcessName | |
.... | |
Id Property int Id {get;} | |
.... | |
ProcessName Property string ProcessName {get;} | |
.... | |
Path ScriptProperty System.Object Path {get=$this.Mainmodule.FileName;} |
Looking at the list of properties returned, we can see 2 of the 3 properties we need are contained in these process objects. The only one not contained is the file hash of the executable. That's ok, we can add that one in using a different cmdlet. How could we find a cmdlet that will return a hash of file? You guessed it with Get-Command.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Get-Command -Verb Get -Noun *hash* | |
CommandType Name Version Source | |
----------- ---- ------- ------ | |
Function Get-BCHashCache 1.0.0.0 BranchCache | |
Function Get-FileHash 3.1.0.0 Microsoft.PowerShell.Utility |
Let's test this cmdlet out and find out what type of object it returns along with its properties. We'll just run it against a file on our computer and pipe the results to Get-Member.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PS C:\> Get-FileHash -Path .\TestFile.txt | Get-Member | |
TypeName: Microsoft.Powershell.Utility.FileHash | |
Name MemberType Definition | |
---- ---------- ---------- | |
Equals Method bool Equals(System.Object obj) | |
GetHashCode Method int GetHashCode() | |
GetType Method type GetType() | |
ToString Method string ToString() | |
Algorithm NoteProperty string Algorithm=SHA256 | |
Hash NoteProperty string Hash=B08022D315CF1EB12D2665BDED0E6AF40653C0A0BE975232FB49BCBD021CFC36 | |
Path NoteProperty string Path=C:\TestFile.txt |
Looking at the properties, it appears the "hash" property contains the data we need for our script.
Now lets start putting this together. We need to run Get-Process but only need 2 of the automatic object properties. We also need a third custom property that will use Get-FileHash to generate the property value. We can use the Select-Object cmdlet to select object properties along with creating our own custom properties. We can pipe objects to Select-Object to enumerate the properties. We'll start with the 2 automatic properties.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PS C:\> Get-Process | Select-Object ProcessName, Path | |
ProcessName Path | |
----------- ---- | |
AbtSvcHost_ C:\Windows\SysWOW64\AbtSvcHost_.exe | |
ac.activclient.gui.scagent C:\Program Files\HID Global\ActivClient\ac.activclient.gui.scagent.exe | |
acevents C:\Program Files\HID Global\ActivClient\acevents.exe | |
ApplicationFrameHost C:\Windows\system32\ApplicationFrameHost.exe | |
.... |
Now we need to add the custom property. To add a custom property, simply add a hashtable to the list of properties. Hashtables in PowerShell can be created with a special operator @{}. Inside the curly braces place the key/value pairs. This syntax is <key>=<value>. For custom properties we need two keys: name and expression. These can be abbreviated with n and e. Name will be a string that is the name of the new property and expression will be a script block that returns the value for the new custom property. So it looks like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PS C:\> Get-Process | Select-Object -Property name, path, @{n="Hash"; e={(Get-FileHash -Path $_.path).hash}} | |
Name Path Hash | |
---- ---- ---- | |
AbtSvcHost_ C:\Windows\SysWOW64\AbtSvcHost_.exe 5F4CB0541F9BBD1DCBDEDF8515983FDAEB77568D3A494E7797B202702CBFA10C | |
ac.activclient.gui.scagent C:\Program Files\HID Global\ActivClient\ac.activclient.gui.scagent.exe 7D9A576A61FFCEF0DFB6A5A3DFB221EE5946A962FB510D1AE89ED8685D1CE16D | |
acevents C:\Program Files\HID Global\ActivClient\acevents.exe DCABA20776941463B1BA5508003B9E658B46DEFC7257C5B2E278DE37981F7E34 | |
ApplicationFrameHost C:\Windows\system32\ApplicationFrameHost.exe 71A1CA978834C0DDBAB05E3987CB4BD6CC2783F9E05B3D00C8FCD333349528AC | |
atmgr c:\users\micha\appdata\local\webex\webex\meetings_01\atmgr.exe E18895EF5D12AD59B4DE6B6D42ED4E484C79034D9F0B81944FD0FB1372C3B10B |
Note the $_ is used to reference the current object in the pipeline. Now we have the command all built out we can view the data right on the screen, save the results to variable or export the results to a file for analysis later.
In the next post we will add to the functionality of this command by exporting the data and comparing it to a baseline.