Calling Win32 APIs from PowerShell
PowerShell cannot natively interact with the Win32 APIs,
but with the power of the .NET framework we can use C# in our PowerShell session.
In C#, we can declare and import Win32 APIs using the DllImportAttribute class.
This allows us to invoke functions in unmanaged dynamic link libraries.
Just like with VBA, we must translate the C data types to C# data types.
We can do this easily with Microsoft’s Platform Invocation Services,
commonly known as P/Invoke.
The P/Invoke APIs are contained in the System
and System.Runtime.InteropServices namespaces
and must be imported through the using directive keyword.
The simplest way to begin with P/Invoke is through the pinvoke.net website,
which documents translations of the most common Win32 APIs.
For example, consider the syntax of MessageBox from User32.dll.
Let’s “translate” this into a C# method signature.
A method signature is a unique identification of a method
for the C# compiler.
The signature consists of a method name and the type and kind, such as value,
reference, or output, of each of its formal parameters and the return type.
To “translate” this, we can either search the pinvoke.net website
or simply Google for pinvoke User32 messagebox.
The first hit,
leads us to the C# signature for the call.
In order to use this, we’ll need to add a bit of code to import the System
and System.Runtime.InteropServices namespaces containing the P/Invoke APIs.
Remember that our Microsoft Office 2016 version of Word
is a 32-bit process,
which means that PowerShell will also launch as a 32-bit process.
In order to properly simulate and test this scenario,
we should use the 32-bit version of PowerShell ISE.
We’ll create a C# class called User32,
which imports the MessageBox signature with DllImport.
This class will allow us to interact with the Windows API.
Now that we have a C# import and a P/Invoke translation,
we need to invoke it from PowerShell with the Add-Type keyword.
Specifying Add-Type in PowerShell will force the .NET framework to compile
and create an object containing the structures, values,
functions, or code inside the Add-Type statement.
Put simply, Add-Type uses the .NET framework to compile the C# code
containing Win32 API declarations and then executes the compiled code.
Note that PowerShell uses either a newline
or a semicolon to signify the end of a statement.
The “@” keyword declares Here-Strings
which are a simple way for us to declare blocks of text.
In summary, the code first creates a $User32 variable,
and sets it to a block of text.
Inside that block of text, we set the program to use System
and System.Runtime.InteropServices.
Then we import the MessageBox API from the user32 dll,
and finally we use Add-Type
to compile the C# code contained in the $User32 variable.
Our code is nearly complete.
We now simply need to execute the API itself.
This can be done through the instantiated User32 .NET object.
Here we are telling the program to call MessageBox
and present a dialog prompt that says “This is an alert”:
This code should invoke MessageBox from PowerShell.
When the code is executed,
we obtain a message box
This works quite well
and demonstrates that while PowerShell can not natively use Win32 APIs,
Add-Type can invoke them through P/Invoke.
In the next section, we’ll use a similar technique
to implement our VBA shellcode runner in PowerShell.