Download: 'PETools' PowerShell module
Introducing, yet another PE parsing utility! Where Get-PEHeader differentiates itself though is that it will parse 32 and 64-bit executables both on disk and loaded in memory. Where it really shines is in its scriptability. For example, you can pipe the output of ls (Get-ChildItem) or ps (Get-Process) right to Get-PEHeader and it will return to you a fully parsed PE header.1) Set it up and get help
In this post, I'm going to show you how to:
In this post, I'm going to show you how to:
2) Use Get-PEHeader to analyze every loaded module in a process
3) Interactively inspect the in-memory PE header of kernel32.dll
4) Do some quick and dirty memory forensics using a reflectively loaded meterpreter sample
5) Analyze PE headers on disk
Setting things up
I've decided to package all of my PE tools from the PowerSploit project into a module for increased portability. For those who aren't terribly familiar with PowerShell, importing a module isn't initially straightforward. Just follow the following steps and refer to the screenshot below to get things up and running:
1) Download the PETools folder from the PowerSploit project
2) Drop the folder into one of your module paths. You can view your default module paths in Powershell by typing:
- After you drop the folder in the module path, restart PowerShell
- The default per-user module path is: "$Env:HomeDrive$Env:HOMEPATH\Documents\WindowsPowerShell\Modules"
- The default computer-level module path is: "$Env:windir\System32\WindowsPowerShell\v1.0\Modules"
3) Import all the scripts in the module
4) You can view all the cmdlets that were imported by typing:
Get-Command -Module PETools
5) For individualized help on each command, Get-Help is your friend.
|Setting up the PETools module for use|
Using Get-PEHeader to analyze every loaded module in a process
This is easy. We're going to use cmd.exe as an example. Simply run the following command:
$CmdModules = Get-Process cmd | Get-PEHeader
Note that this will only work if there is only one instance of cmd.exe open. If there is more than one, just give Get-Process a specific process ID.
Once the command completes (it may take ~30-40 seconds) you can start poking around. If you try this yourself, you'll see that it parsed all of the following modules:
$CmdModules | Select-Object Module
|Parsing PE headers of cmd.exe loaded modules|
Interactively poking around the in memory PE header for kernel32.dll
Now you can start digging deeper. Let's check out kernel32.dll. In particular, I'm interested in looking at all of its exported functions.
$Kernel32PE = $CmdModules
You'll see that listing the module's exports lists the virtual address, exported ordinal, name, and forwarded name (if available)
|Inspecting the exported functions of kernel32.dll in memory|
Doing some quick and dirty memory forensics using a reflectively loaded meterpreter sample
Now let's move beyond the novelties and start doing some in-memory malware analysis. I injected meterpreter into one of my running processes. For the armchair malware analyst, you probably wouldn't stumble upon anything terribly suspicious when attempting to view the loaded dlls of the infected process. That's because meterpreter gets reflectively loaded - i.e. it has a self-loading stub that loads itself in memory rather than having Windows do it. Since the main meterpreter dll - metsrv.dll is not visible to Windows in user-mode, you have to dig in a little deeper to find the address where it was loaded in memory. To quickly find the address, I attached to the process in WinDbg and used the .imgscan command to quickly determine the base address of metsrv.dll - 0x02560000. Armed with the knowledge of the infected process ID and the base address of the malicious module, you can use Get-PEHeader to dissect the PE header of meterpreter in memory.
$EvilHiddenDll = Get-PEHeader -ProcessId 4448 -ModuleBaseAddress 0x02560000
$EvilHiddenDll.Exports | Sort-Object -Descending VirtualAddress
Tip to malware authors: if you're loading your own module in memory, the executable doesn't need to start with 'MZ.' Just sayin'
As can be seen in the screenshot below, there are some things that just don't look right. First, if you've looked at enough DOS headers, you'd notice that some of those values don't look right. So if you broke out a hex editor and a disassembler, you'd see that the DOS header was comprised of an x86 assembly self-loader stub. Fortunately, you don't even have to get that sophisticated. If you look at the exports, you'll see '_ReflectiveLoader@0' and 'Init' - a sure sign you're dealing with meterpreter. By the way, the name decoration around ReflectiveLoader tells you that it's a stdcall function that takes zero arguments.
|Pulling apart meterpreter in memory|
|metsrv.dll optional and file headers. Note correctly displayed TimeDateStamp (in GMT)|
Analyzing PE headers of files on disk
Finally, you can use Get-PEHeader to analyze the PE headers of files on disk:
$CalcHeader = Get-PEHeader C:\Windows\System32\calc.exe
|Parsing the calc.exe PE header on disk|
Get-PEHeader in its current form is not nearly as sophisticated as dumpbin or CFF Explorer. Those tools are only able to parse PEs on disk, however. Currently, Get-PEHeader will parse and return the following:
- DOS Header
- File Header
- Optional Header
- Data Directories
- Section Headers
Should I find the time and motivation in the future, I hope to add the following features:
- Resource parsing
- CLR header parsing
- Resolution of addresses of forwarded functions
- Authenticode signature parsing
Let me know what you think and please let me know if you have any questions (please no generic PowerShell questions) or bug reports. Enjoy!