Detouring Win32 Function Calls in PowerShell

Detouring Win32 API function calls is a more common practice than some may think. A long standing Microsoft research project has made this very easy in unmanaged code. The Detours project injects a hook in between a process and a Windows library (or any library for that matter). So when the process goes to call a function like StartProcess, the hook will instead be invoked and can execute its own version of the hooked function. This is very powerful and very dangerous. Serious system instability can be caused from using this the wrong way. That said, if you are only hooking the local process you only have to worry about crashing that. ๐Ÿ˜‰

An open source project exists called EasyHook. EasyHook is another implementation of a hooking mechanism like the one used in Detours. The difference with EasyHook is that is has a managed wrapper over the top of the unmanaged hooking code. This makes it consumable by PowerShell. Scary right! EasyHook makes hooking local process a snap. Here’s an example I cooked up in C# to hook GetSystemTimeByFileTime.

The hook redirects to my “Hooked” method and outputs a static time rather than actually looking up the system time. The result of this is the following output.

Whoa! Now the time changes all the way back to 1999. Since DateTime.Now just calls GetSystemTimeAsFileTime under the covers (thanks Reflector), the hooked method changes the behavior of that class as well. So any call to that Win32 API function will result in our 1999 time.

PowerShell Hooking

Hooking in PowerShell is a bit trickier. We need to still create a .NET class that we can define a delegate and method on and then call a script block that will execute within the hook. The first step is to collect the necessary information about the function we are hooking. We need the DLL it lives in, the function name and the signature to get this right. I created a New-Detour function that accepts these parameters. Then I load up EasyHook.


Notice that I didn’t include a parameter for the signature. To grab the signature I thought it would be cool if it was generated based on the parameters of the script block defined for the detour. Because we have access to the AST, this makes this much easier. Doing some careful iteration and using the new PSCustomObject class I put together some objects that represented the parameters in the param block of the ScriptBlock.

Next, I started to put together the C# code using the parameters. I have to initialize any out variables with the default value, fill out the delegate and function definition and actually execute the script block in the class. I’ll skip some of the parameter parsing (you can check out the full attached script). The C# class is pretty simple. It has a delegate, a hook and a script block execution.

The outVarSnippet is a bit interesting. Since [ref] variables aren’t reflected outside of the PowerShell engine, setting variables within like we did in the C# class in the first example won’t work. Instead I am returning variables based on position. So the first variable returned from the script block will be set to the first out variable and so forth (I don’t have support for returning anything from the detoured functions yet). ย This wasn’t ideal, is a bit of a hack and I don’t like it but it was the best thing I could think of to work around this.

Once we have generated the class we can compile it and use EasyHook to inject it into the current project.

Although all this looks kind of complicated, what we are left with is a pretty simple function to hook processes hosting Powershell. Here’s an example of hooking the same function as the C# project.

The result is even cooler.

Now we can go party like it’s 1999 again!

You can leave a response, or trackback from your own site.

14 Responses to “Detouring Win32 Function Calls in PowerShell”

  1. […] used to hook Windows API calls. As you might expect, this can also be done in other languages, and Adam Driscoll shows to to do so with Power Shell. Share this:TwitterFacebookLike this:LikeBe the first to like […]

  2. […] Companies focus most of the security spending and policies on keeping hackers out remotely. Detouring Win32 Function Calls in PowerShell – Detouring Win32 API function calls is a more common practice than some may […]

  3. […] my last post we looked at how to hook the local PowerShell process and adjust the date by hooking the […]

  4. bloob says:


    can you help with this:

    Cannot use [ref] with other types in a type constraint.

    At c:\temp\New-Detour\New-Detour.ps1:107 char:124
    + $Detour = New-Detour -Library “Kernel32.dll” -FunctionName GetSystemTimeAsFileTime -Detour { param([ref][System.Int64
    ]$time <<<< )
    + CategoryInfo : InvalidOperation: (time:Token) [], RuntimeException
    + FullyQualifiedErrorId : ReferenceNeedsToBeByItselfInTypeConstraint

  5. bloob says:


    modified only to change the dll location, but it’s powershell 1, so i’ll update and give it another go – thanks for the pointer

  6. […] function within the DLL. This is the function that is called during registration with regsvr32. It hooks the Win32 registry functions to decipher which progids, COM class, etc are exported from the DLL. […]

  7. nohandle says:

    This is sick ๐Ÿ™‚ I am gonna need to re-read it at least once more.

  8. Passenger says:

    Hi, the source file is unavailable.

  9. muted says:

    Hello Dead Adam, thanks for the great work, can you please provide your example sourcecode? the download file is not available. Thanks in advance.

  10. muted says:

    i cant edit my comment, sory, i mean dear and Not dead. :/

    • adamdriscoll says:

      No worries. ๐Ÿ™‚ I looks like the ZIP was somehow deleted off of my account. I’ll see if I can recover it from backup.

  11. deadlink says:

    Did you manage to recover the deleted file?

  12. b33f says:

    I’m trying to reimplement this,, step by step in powershell. It is pretty straight forward but I don’t quite understand how to create a delegate that returns a static long. Can I create a delegate in the same way using Get-DelegateType like here,

Leave a Reply

In an effort to prevent automatic filling, you should perform a task displayed below.