Presenting PeNet: a native .NET library for analyzing PE Headers with PowerShell

screen1The last years have seen a strong rise in PowerShell and .NET malware, so in this article we go native and show how PowerShell and the PeNet library can be leveraged to analyze Portable Executable (PE) headers of Windows executables, motivated by, but not limited to .NET binaries. PeNet is published under Apache License Version 2.0 and maintained by the author. Find an API description for C#, VB, C++ and F# in the PeNet API Reference.

Why PowerShell

PowerShell is an object-oriented programming language with full access to all .NET and Windows libraries. This is one of the reasons why PowerShell became more and more popular in malware and exploitation. The syntax makes it easy to use for everyone familiar with C/C++ or an equivalent modern programming language. Since most malware analysis is done automated to process huge amounts of malicious executables, a scripting language comes handy in this context. As every Windows PC has PowerShell and an IDE for it installed, it is easy to start coding and you can be sure that your code runs basically on every computer running Windows.

About PeNet Library

The PeNet library is a .NET library written in C# which parses PE headers of Windows executables. It can show and interpret values, flags, resources and so on, and is also capable of changing the values. The library is under the Apache 2 license and can be used by everyone in their projects.

Analyzing a PE Header

In the following section we walk through and example to demonstrate how to analyze the PE header of a Windows executable using PeNet. 

First, we need to import the PeNet library in PowerShell:

# Import the PeNet DLL

[System.Reflection.Assembly]::LoadFrom(“C:\PeNet.dll”| Out-Null

Now, we define a path to an executable and a new object which represents the PE header.

# Windows Executable to analyze

$executable ‘C:\Windows\System32\calc.exe’

# Create a new PE header object with PeNet

$peHeader New-Object PeNet.PeFile -ArgumentList $executable

The $peHeader object contains all information we can get from the PeNet library. 

Basic File Information

Now, let us check, if the file we are analyzing is a PE file or not and display some information about the PE file.

Write-Host “Is PE File`t” $peHeader.IsValidPeFile

Write-Host “Is 32 Bit`t”  $peHeader.Is32Bit

Write-Host “Is 64 Bit`t”  $peHeader.Is64Bit

Write-Host “Is DLL`t`t”   $peHeader.IsDLL

Write-Host “File Size`t”  $peHeader.FileSize “Bytes”

 

These lines are accessing flags and properties of the $peHeader object. The output for these lines is:

Is PE File    True

Is 32 Bit     False

Is 64 Bit     True

Is DLL        False

File Size     32768 Bytes

The output shows that the executable we are analyzing is a 64 Bit PE file and an executable but no DLL. The file size is 32768 bytes. To identify files, hashes are common in malware analysis, so let us display the most common hashes.

Write-Host “SHA-1`t”   $peHeader.SHA1

Write-Host “SHA-256`t” $peHeader.SHA256

Write-Host “MD5`t`t”   $peHeader.MD5

Output:

SHA-1         7270d8b19e3b13973ee905f89d02cc2f33a63aa5

SHA-256       700ee0e9c1e9dc18114ae2798847824577e587813c72b413127fb70b9cb042dd

MD5           c4cb4fdf6369dd1342d2666171866ce5

One more interesting hash is the Import-Hash (ImpHash), which is a hash over the imported functions of the PE file. The ImpHash can be used to identify similar malware, since the same ImpHash is a strong indicator for similar behavior, or at least the same packer.

Write-Host “ImpHash`t” $peHeader.ImpHash

Output:

ImpHash 251a86d312a56bf3a543b34a1b34d4cc

The ImpHash is used by VirusTotal, too, and besides the .NET implementation in PeNet, a Python library exists which can be used to compute the hash.

To check if the PE file is signed with a valid signature we can use the following PS code:

Write-Host “Signature Information” -ForegroundColor Yellow

Write-Host “Is Signed`t`t`t”        $peHeader.IsSigned

Write-Host “Is Chain Valid`t`t”     $peHeader.IsValidCertChain($True)

Write-Host “Is Signature Valid`t”  ([PeNet.Utility]::IsSignatureValid($executable))

The parameter $True indicates that PeNet should check the certificate chain online. If we set the parameter to $False, the check would be done offline, which could lead to outdated results.

The output for our example is:

Is Signed                   False

Is Chain Valid              False

Is Signature Valid          False

The executable isn’t signed at all, so obviously the chain and the signature are invalid.

DOS/NT Header

We have two options to get the values of each structure in the PE header. The first is
by value, where you can access every single structure member. The second methods
returns the whole structure with all value containing it as a string for easier representation in console output.

To access single values, let’s have a look how we can obtain the e_magic value from the
IMAGE_DOS_HEADER and how to access the Signature from the IMAGE_NT_HEADERS.

“e_magic`t {0:X0}” -f $peHeader.ImageDosHeader.e_magic

“NT signature {0:X0}” -f $peHeader.ImageNtHeaders.Signature

We start at the PE header and select the structure and value we want. The values are
printed to the console in hexadecimal.

Output:

e_magic        5A4D         

NT signature   4550

The PeNet library overrides a ToString() method for each PE structure. This means
that we can print the whole IMAGE_DOS_HEADER (and any other header) directly to
the console without caring for formatting or without the knowledge of the members of the structure.

Write-Host $peHeader.ImageDosHeader

Output:

IMAGE_DOS_HEADER

e_magic   :   5A4D

e_cblp    :   90

e_cp      :   3

e_crlc    :   0

e_cparhdr :   4

e_minalloc:   0

e_maxalloc:   FFFF

e_ss      :   0

e_sp      :   B8

e_csum    :   0

e_ip      :   0

e_cs      :   0

e_lfarlc  :   40

e_ovno    :   0

e_oemid   :   0

e_oeminfo :   0

e_lfanew  :   F8

File Header

The IMAGE_FILE_HEADER is a structure in the IMAGE_NT_HEADERS and can be accessed again as single values or as a whole.

For example, let’s access the machine type of the file header.

“Machine {0:X0}” -f $peHeader.ImageNtHeaders.FileHeader.Machine

Write-Host “Resolved Machine`t ([PeNet.Utility]::ResolveTargetMachine($peHeader.ImageNtHeaders.FileHeader.Machine))

In the first line, we print the machine field as a hex value. Since this value doesn’t
say much we can use the PeNet library to resolve the value to a meaningful
string as shown in the second line.

Output:

Machine              8664

Resolved Machine     AMD AMD64

Interesting in the file header are the file characteristics which can be accessed and
resolved like this:

“`nCharacteristics {0:X0}” -f $peHeader.ImageNtHeaders.FileHeader.Characteristics

Write-Host ([PeNet.Utility]::ResolveFileCharacteristics($peHeader.ImageNtHeaders.FileHeader.Characteristics))

The first line prints the file characteristics as a hex value and the second line resolves them to different flags. All flags can be access on their own, but we just print them all at once.

Output:

Characteristics 22

 

File Characteristics

RelocStripped                 :     False

ExecutableImage               :      True

LineNumbersStripped           :     False

LocalSymbolsStripped          :     False

AggressiveWsTrim              :     False

LargeAddressAware             :      True

BytesReversedLo               :     False

Machine32Bit                  :     False

DebugStripped                 :     False

RemovableRunFromSwap          :     False

NetRunFroMSwap                :     False

System                        :     False

DLL                           :     False

UpSystemOnly                  :     False

BytesReversedHi               :     False

And again to print the whole header just type:

Write-Host $peHeader.ImageNtHeaders.FileHeader

Output:

IMAGE_FILE_HEADER

Machine:                     8664

NumberOfSections:            6

TimeDateStamp:               5632D8CE

PointerToSymbolTable:        0

NumberOfSymbols:             0

SizeOfOptionalHeader:        F0

Characteristics:             22

Section Header

To access the sections of the executable we parse the section header and resolve the section characteristics to get an overview of the rights of each section.

$num = 1;

foreach($sec in $peHeader.ImageSectionHeaders)

{
    Write-Host “`nNumber:” $num

    Write-Host “Name:” ([PeNet.Utility]::ResolveSectionName($sec.Name))

    Write-Host $sec

    $flags ([PeNet.Utility]::ResolveSectionFlags($sec.Characteristics))

    Write-Host “Flags:” $flags 

    $num++;

}

The output for the first two sections with resolved name and resolved flags:

 

Number: 1

Name:  .text

IMAGE_SECTION_HEADER

PhysicalAddress:             16B0

VirtualSize:                 16B0

VirtualAddress:              1000

SizeOfRawData:               1800

PointerToRawData:            400

PointerToRelocations:        0

PointerToLinenumbers:        0

NumberOfRelocations:         0

NumberOfLinenumbers:         0

Characteristics:             60000020

 

Flags: IMAGE_SCN_CNT_CODE
IMAGE_SCN_MEM_EXECUTE IMAGE_SCN_MEM_READ

 

Number: 2

Name:  .rdata

IMAGE_SECTION_HEADER

PhysicalAddress:            151A

VirtualSize:                151A

VirtualAddress:             3000

SizeOfRawData:              1600

PointerToRawData:           1C00

PointerToRelocations:       0

PointerToLinenumbers:       0

NumberOfRelocations:        0

NumberOfLinenumbers:        0

Characteristics:            40000040

 

Flags:
IMAGE_SCN_CNT_INITIALIZED_DATA IMAGE_SCN_MEM_READ

Optional Header / Data Directory

The Optional Header is, like the File Header, a structure in the NT header and can be accessed by each member or as a whole. In the following we just print the whole header. Since the Optional Header includes the Data Directory structure it is printed (cut off), too.

IMAGE_OPTIONAL_HEADER

Magic:                      20B

MajorLinkerVersion:         C

MinorLinkerVersion:         A

SizeOfCode:                 1800

SizeOfInitializedData:      6A00

SizeOfUninitializedData:    0

AddressOfEntryPoint:        22E0

BaseOfCode:                 1000

BaseOfData:                 0

ImageBase:                  140000000

SectionAlignment:           1000

FileAlignment:              200

MajorOperatingSystemVersion: A

MinorOperatingSystemVersion: 0

MajorImageVersion:          A

MinorImageVersion:          0

MajorSubsystemVersion:      A

MinorSubsystemVersion:      0

Win32VersionValue:          0

SizeOfImage:                D000

SizeOfHeaders:              400

CheckSum:                   FB66

Subsystem:                  2

DllCharacteristics:         C160

SizeOfStackReserve:         80000

SizeOfStackCommit:          2000

SizeOfHeapReserve:          100000

SizeOfHeapCommit:           1000

LoaderFlags:                0

NumberOfRvaAndSizes:        10

 

IMAGE_DATA_DIRECTORY

VirtualAddress:             0

Size:                       0

IMAGE_DATA_DIRECTORY

VirtualAddress:             3D68

Size:                       DC

IMAGE_DATA_DIRECTORY

VirtualAddress:             7000

Size:                       4718

IMAGE_DATA_DIRECTORY

VirtualAddress:             6000

Size:                       180

IMAGE_DATA_DIRECTORY

VirtualAddress:             0

Size:                       0

IMAGE_DATA_DIRECTORY

VirtualAddress:             C000

Size:                       48

IMAGE_DATA_DIRECTORY

VirtualAddress:             3590

Size:                       38

IMAGE_DATA_DIRECTORY

VirtualAddress:             0

Size:                       0

IMAGE_DATA_DIRECTORY…

 

Imports, Exports and Resources

We have seen how the Optional Header and the Data Directory can be accessed. The most interesting parts of the Data Directory are the Imports, Exports and Resources. PeNet parses all these directories for us and shows us the content.

Let’s start with the imports. Since listing all imported functions would be too much for this article we will have a look at all function imported from Kernel32.dll

foreach($import in $peHeader.ImportedFunctions)

{
    if($import.DLL -eq “KERNEL32.DLL”)

    {

        $import

    }

}

This code iterates over all imported functions and checks if the DLL from which the function should be imported is the Kernel32.dll. If so, the imported function is printed.

Output:

Name                        DLL          Hint

—-                        —          —-

GetLastError                KERNEL32.dll  599

CreateEventExW              KERNEL32.dll  179

WaitForSingleObject         KERNEL32.dll 1483

SetEvent                    KERNEL32.dll 1291

FindPackagesByPackageFamily KERNEL32.dll  395

QueryPerformanceCounter     KERNEL32.dll 1081

GetCurrentProcessId         KERNEL32.dll  529

GetCurrentThreadId          KERNEL32.dll  533

CloseHandle                 KERNEL32.dll  124

GetTickCount                KERNEL32.dll  765

RtlCaptureContext           KERNEL32.dll 1210

RtlLookupFunctionEntry      KERNEL32.dll 1217

RtlVirtualUnwind            KERNEL32.dll 1224

UnhandledExceptionFilter    KERNEL32.dll 1441

SetUnhandledExceptionFilter KERNEL32.dll 1377

GetCurrentProcess           KERNEL32.dll  528

TerminateProcess            KERNEL32.dll 1407

RaiseException              KERNEL32.dll 1103

GetSystemTimeAsFileTime     KERNEL32.dll  736

Since we are analyzing an executable and not a DLL there are most likely no exports, but to be sure let us check.

if($peHeader.ExportedFunctions -eq $null)

{
    “Image has no exports.”

}

else

{
    “Image has exports.”

}

Output:

Image has no exports.

Nothing to see here, let’s move on and check for resources. We print the root elements of this executable and no subdirectories to keep the output readable.

 

foreach($de in $peHeader.ImageResourceDirectory.DirectoryEntries)

{
    if($de.IsIdEntry -eq $True)

{

      Write-Host “ID Entry” $de.ID ” Resolved Name: “ ([PeNet.Utility]::ResolveResourceId($de.ID))

      }

    elseif($de.IsNamedEntry -eq $True)
{ 

        Write-Host “Named Entry: “ $de.ResolvedName
    }

}

Output:

ID Entry 3  Resolved Name:   Icon

ID Entry 14  Resolved Name:  GroupIcon

ID Entry 16  Resolved Name:  Version

ID Entry 24  Resolved Name:  Manifest

Again, we used a resolve function to map the IDs of directory entries to meaningful names.

Pattern-Matching

Often, we don’t search for a structure member to have a specific value, but instead want
to match some byte or string signature over samples. That’s why PeNet comes with a build-in Aho-Corasick pattern matching algorithm for byte arrays and strings.

The idea is to construct a trie containing all signatures once and to use this trie to match multiple executables against the signatures. We will see an example below.

$trie New-Object PeNet.PatternMatching.Trie

 

$trie.Add(“MicrosoftCalculator”, ([System.Text.Encoding]::ASCII), “pattern1”)

$trie.Add(“not in the binary”, ([System.Text.Encoding]::ASCII), “pattern2”)

$trie.Add(“<assemblyIdentity”, ([System.Text.Encoding]::ASCII), “pattern3”)

 

$matches = $trie.Find($peHeader.Buff)

 

foreach($match in $matches)

{
    Write-Host “Pattern” $match.Item1 “matched at offset” $match.Item2

}

 

A new trie object is created and then filled with some strings to search for. The encoding is of the string is given, because string in binaries are often in Unicode. The pattern2 is not in the binary and should not be found, the other two patterns should.

The output is:

Pattern pattern1 matched at offset 9410

Pattern pattern3 matched at offset 14498

Pattern pattern3 matched at offset 14725

We see that pattern1 matched once and pattern3 matched two times at different offsets.

Conclusion

We’ve seen how PE headers can be analyzed with PowerShell and PeNet. PeNet is a .NET library, i.e., any other .NET language can be used, too. The library is still under development and a lot of PE features are still missing, but they will follow soon. None the less, it’s a mighty tool for malware analysis, if building large-scale, automated analysis systems with the .NET framework is what you aim for. Feel free to contribute to the PeNet library or fork it at GitHub.

 

 

G DATA ADAN at WKÖ eDay:16 in Vienna

Yesterday, G DATA Advanced Analytics was present at the WKO eDAY:16 in Vienna; a magnificent event, gathering Austrian economists and security professionals. Talks and panels were centered around the question, how to level up on Austrian corporate security in times where the internet is a hostile place.

Live on stage that day was our own Marion Marschalek, who was invited to hold the afternoon keynote. The keynote topic, translated to English, would be “The good, the bad, and the clueless”, a title potentially covering so much that’s happening on today’s internet. There are a lot of WTFs in the cyber, right? On that specific occasion, the focus of ‘cyber’ was all on the wild, wild west of the internet. Just like Clint Eastwood and Lee Van Cleef in the prairie back in the days, we now all have fictional roles and lots of pretentions while hunting for the lost treasure. In reality, roles and intentions aren’t super clear anymore on the cybersinterwebs.

24870836263_80e1072b32_z
Marion Marschalek during her keynote (CC-BY Paul Landl/wkoe)

To sum it up: Today, you could be chatting with a fridge on IRC. Also, your network could be nuked by a DDoS attack, carried out by an army of… home routers. Yes, indeed there are DDoS botnets operating on CPUs of routers. Furthermore, there are botnets being operated by criminals. And then, there are botnets being operated by spooks. One of those was used by the GCHQ to nuke Anonymous [1]. Now go back home to check up on your router, will you? Scary.

Just like “Hello Barbie”, Mattel’s latest Barbie doll, pretty as ever, and, since recently, extravagantly smart. Because “Hello Barbie” can now listen, understand, and answer things your kid tells her [2]. Or you. Or anyone else who is around, for that matter.

The keynote then moved on to critical infrastructures: lights in Ukraine went out early this year and the BlackEnergy malware was found to be the root cause of trouble [3, 4]. The world was shocked for this attack on critical infrastructure being the first of its kind on such large scale. Security pros on the other hand may be impressed the effort that went into the attack and its minute coordination [5], but aren’t really surprised by the attack itself, silently whistling told ya, told ya, told ya so.

Meanwhile, on the cybercomputerycrime venue — the mere continuation of longstanding objectives with the more or less novel means of information technology [6] — incident responders have taken a step back from the general “It’s China”-attribution to accept that other nationals might also be occasionally involved. Nation states have done their share of espionage on corporations too [7-9], but we don’t quite know yet what that is all about.

What we do know is that nation states have done their share on espionage in general; not only in the Snowden era but naturally since the invention of secret services. The issue now with that particular wild, wild west at hand, is now that espionage has gotten a whole lot easier for nations with offensive capabilities in the information, computer, and network domain (commonly sold as cyber*) [10].

So it happened that some of this planet’s nations turned on to their own citizens with digital weapons. Countries like Bahrain and the UAE put political figures and activists to prison under the pretext of national security, based on information gathered on the cybers. The arms traders in that game are plenty, the two most nefarious are likely HackingTeam, and Gamma Group with their FinFisher product [11]. Those companies operate on the lawful interception market and sell digital surveillance gear to those countries who opted to not develop their own [12].

If, in the end, you do want our advice on how to weapon up for the prairie: keep your eyes open and watch your data carefully, but don’t go crazy. It isn’t your fault wild west has turned upon us, but we all need to deal with it. A vast part of crime on the one side and privacy loss by surveillance on the other side are political concerns rather than technological ones. Meanwhile, ‘cyber’ has entered the agendas of parliaments and roundtables, on some occasions even us normal cowboys and -girls are asked for an opinion. Don’t be shy if that comes to you, Clint Eastwood wouldn’t be either.

Event website: https://www.wko.at/Content.Node/kampagnen/E-Day/index.html

References:
[1] UK Government Used ‘Rolling Thunder’ DDoS Attacks Against Anonymous, LulzSec and Syrian Electronic Army, IBTimes
http://www.ibtimes.co.uk/uk-government-used-rolling-thunder-ddos-attacks-against-anonymous-lulzsec-syrian-electronic-1435186
[2] About Hello Barbie, Mattel
http://hellobarbiefaq.mattel.com/about-hello-barbie/
[3] BlackEnergy APT Attacks in Ukraine employ spearphishing with Word documents, SecureList
https://securelist.com/blog/research/73440/blackenergy-apt-attacks-in-ukraine-employ-spearphishing-with-word-documents/
[4] First on CNN: U.S. investigators find proof of cyberattack on Ukraine power grid, CNN
http://edition.cnn.com/2016/02/03/politics/cyberattack-ukraine-power-grid/
[5] Inside the Cunning, Unprecedented Hack of Ukraine’s Power Grid
http://www.wired.com/2016/03/inside-cunning-unprecedented-hack-ukraines-power-grid/
[6] Russian hackers used Windows bug to target Nato, BBC
http://www.bbc.com/news/technology-29613247
[7] Brazil-Canada espionage: Which countries are we spying on?, CBC News
http://www.cbc.ca/news/canada/brazil-canada-espionage-which-countries-are-we-spying-on-1.1930522
[8] Snowden Documents Show U.S. Spied on Petrobras, Globo TV Reports, Bloomberg
http://www.bloomberg.com/news/articles/2013-09-08/u-s-government-spied-on-brazil-s-petrobras-globo-tv-reports
[9] French Said to Spy on U.S. Computer Companies, New York Times
http://www.nytimes.com/1990/11/18/world/french-said-to-spy-on-us-computer-companies.html
[10] Long-Term Strategy Needed When Analyzing APTs: Researcher, Security Week
http://www.securityweek.com/long-term-strategy-needed-when-analyzing-apts-researcher
[11] Schrodinger‘s cat video and the death of clear text, CitizenLab
https://citizenlab.org/2014/08/cat-video-and-the-death-of-clear-text/
[12] Here are all the sketchy goverment agencies buying HackinTeam‘s spy tech, Motherboard
http://motherboard.vice.com/read/here-are-all-the-sketchy-government-agencies-buying-hacking-teams-spy-tech

Cyber? WTF!

“The only real difficulties in programming are cache invalidation and naming things.” — Phil Karlton

Everything needs a name to go by, right? So did this blog. When we scrolled through the seemingly endless list of new TLDs, we stumbled upon .wtf and while it is all a bit of a blur looking back, our fingers must have developed a dynamic of their own and out came ‘whois cyber.wtf’, which was unregistered for whatever reason¹. During the several days of juggling alternative names – actually spending quite a few thoughts on ‘we probably shouldn’t do this’, anticipating what corporate communications and marketing might think of it – we kept returning to cyber.wtf. When you hear or read people prefixing ordinary, proper, and once actually useful nouns with ‘cyber’, what are your thoughts? We think that ‘WTF?’ might actually be the only appropriate letters to follow on ‘cyber‘. Anyway, this will be our home for the time being. Don’t expect a fixed post frequency, we don’t intend to post for the general sake of creating more bytes on the internet. Expect a post whenever there is both content and time for posting. Expect content that is mostly malware- and/or security-centric, the occasional nifty thing we find mixed in, and where we happen to give a talk. We’ll probably start out with the latter. Judge us by our content, naming is hard.

¹ which at that time actually resulted in

No whois server is known for this kind of object

because whois is pleasantly old-fashioned in its default. -h whois.donuts.co or the line

\.wtf$ whois.donuts.co

in your whois.conf catapults it into a part of the modern age of completely unnecessary but partially wonderful TLDs.