Easily Defining Enums, Structs, and Win32 Functions in Memory

In the past, I’ve spoken extensively on how to use reflection to define enums, structs, and Win32 functions in PowerShell and the merits of doing so. PowerSploit is also heavily reliant upon these techniques in order to perform low-level operations while remaining entirely memory-resident.

Those familiar with using reflection to create .NET types on the fly (i.e. Boe Prox, Joe Bialek, Will Schroeder, etc.) probably know how frustrating it is due to all the ceremony involved in having to control every nuance of the type being created. Fed up with the amount of work involved and considering I have a unique requirement to use reflection so often in my scripts, I needed a way to ease the process of defining in-memory enums, structs, and Win32 functions. I had the following design goals in mind:

Create intuitive wrapper functions around all the reflection code

Be able to declare enum, struct, and Win32 function definitions in as close to a “C-style” as PowerShell would allow – i.e. sometimes disregarding PowerShell best practices.

Structs should be aware of their size, eliminating the need to constantly call [Runtime.InteropServices.Marshal]::SizeOf in my scripts.

Structs should allow for explicit conversion from an IntPtr, eliminating the need to constantly call [Runtime.InteropServices.Marshal]::PtrToStructure in my scripts.

Maintain PowerShell 2.0 compatibility

PSReflect

Introducing PSReflect–a series of helper functions designed to make defining in-memory enums, structs, and Win32 functions extremely easy.

PSReflect consists of the following helper functions:

New-InMemoryModule – Creates a host in-memory assembly and module

Add-Win32Type – Creates a .NET type for an unmanaged Win32 function

func – A helper function for Add-Win32Type that can be sued to eliminate typing when defining a large quantity of Win32 function definitions

enum – Creates an in-memory enumeration for use in your PowerShell session

struct – Creates an in-memory structure for use in your PowerShell session

field – A helper function for struct used to reduce typing while defining struct fields

Starting Out

Before you can define anything, you must create an assembly and module that will host your enums, structs, and Win32 functions. It is really easy to create an in-memory assembly and module with the New-InMemoryModule function.

$Mod = New-InMemoryModule

Assemblies and modules require a name. If the ‘ModuleName’ parameter is not specified, it will create a GUID and use that as the name. With our in-memory module set up, we can now begin defining everything else.

Explicit layout – Indicates that an explicit offset for each field will be specified

Each struct field is a hash table that requires the following components:

The order in which the field should be defined. Unfortunately, this cannot be omitted because PowerShell doesn’t not guarantee the order of defined elements in a hash table. Starting in PowerShell 3.0, you can prepend [Ordered] to a hash table but that is not possible in PowerShell 2.0. The order in which fields are defined is essential, whereas with an enum, the order doesn’t matter.

The .NET type of the field

Optionally, struct fields may also contain the following components:

An explicit offset. If you indicate that your struct has an explicit layout, you must specify the offset of each field. An example of when you would want to use explicit offsets is when creating a union. PowerShell/.NET isn’t aware of the concept of a C union but you can define an equivalent – a struct with overlapping fields.

Since each field of the struct is another hash table, I wrote the ‘field’ helper function to reduce the typing required.

Once your struct is defined, it behaves exactly the way you would expect only it has two additional features:

It comes with a built-in GetSize method which returns the size of the struct in bytes.

It comes with a built-in explicit IntPtr conversion operator. This means that you can cast an IntPtr to your struct type. This is very useful for me since many of my scripts contain calls to [Runtime.InteropServices.Marshal]::PtrToStructure. Having a built-in converter save a lot of typing.

Win32 Functions

When using Add-Win32Type, it will be easiest to define your functions as an array of function declarations:

An array of parameters that the function expects. If the function doesn’t have any parameters, just provide an empty array.

Optionally, you may also specify the following properties:

The native calling convention – The default is stdcall but you may also specify cdecl or thiscall. Unfortunately, .NET does not support the X86 fastcall calling convention.

The character set – If you want to explicitly call an ‘A’ or ‘W’ version of a function, you can specify either an ANSI or Unicode character set.

Once your function declarations are defined, you bake everything in with the Add-Win32Type function at which point you provide your in-memory module defined earlier and optionally, a namespace for each type.

After the Win32 type are created, Add-Win32Type returns a hash table of each type corresponding to each DLL name.

Tying everything together

Now that we have all the requirements under our belt, we can start building some cool tools around this capability. Without further ado, I present to you a very basic PE DOS header parser – the “Hello, World” of working with structs in Windows. 😉

PowerShell 2.0 Quirks

In every example provided, particular attention was paid to writing examples that specifically worked in PowerShell 2.0 and later. Specifically, all types must be saved to variables. In PowerShell 2.0, a bug exists where if you create a type using reflection, you cannot explicitly refer to its type despite it being properly loaded in your PowerShell session. For example, in the previous example, you wouldn’t be able to call [Win32.kernel32]::GetModuleHandle. Rather, in PowerShell 2.0, you have to save each type to a variable when it’s created. In PowerShell 3.0 and later, you can refer to your types explicitly using bracket syntax or via a variable.

If you’re in the unique position of needing to define types in memory, hopefully PSReflect will help speed up your workflow.

Like this:

About Matt Graeber

Matt is a malware reverse engineer, security professional, and PowerShell MVP who is always finding new ways to incorporate PowerShell into his workflow. As one of just a handful of security-minded PowerShell hackers, he also promotes PowerShell as an attack platform in an effort to raise awareness of its security implications in the enterprise. Matt frequently writes about esoteric uses of PowerShell, reverse engineering, and security research on his blog - www.exploit-monday.com.