Sunday, June 30, 2013

Logging Keys with PowerShell: Get-Keystroke

I was recently inspired by Matt Graeber's series of posts on Microsoft's "Hey, Scripting Guy! Blog" to go back and look at old scripts and implement reflection. One of the scripts that I use regularly and mentioned in a previous post is a keylogger. Generally, I use keyloggers in one of two ways. The first way is to keep a record of every key I press with a timestamp for logging purposes during pentests or incident response activities. The other is to collect password credentials in a post-exploitation scenario. Both of these scenarios require a script that has a minimal forensic footprint.

There are a lot of keyloggers out there that make use of GetAsyncKeyState, GetKeyboardState and VirtualKeyCode and if you have ever written or used one, you know it isn't an exact science. There are even examples of other PowerShell keyloggers. A preferred method would be to hook each window with SetWindowsHookEx but there are several security products that flag on that behavior, so I avoided it.

In the script that originally wrote early last year, I made use of Add-Type to interact with user32.dll (it was included in the Invoke-TwitterBot presentation ). If you have read Matt's posts, then you understand why that is not ideal. A few requirements that I had were tracking of special characters such as [Shift] and [Caps Lock] which are really important. VirtualKeyCode doesn't track all common characters so I had to map the other ones:

I also needed to capture the window title and a date time group which is really simple once you load GetForegroundWindow:

Ultimately, the exercise of properly using reflection proved too much of a challenge for me and I reached out to the professional. Matt made short work of it and together we have a script that meets the standards for inclusion in the PowerSploit project:

The full script is available on the PowerSploit Github page. We hope you find the script useful.



  1. FYI - you can simplify your code by using strings instead of enums - PowerShell will do the work for you. e.g.


    Jeffrey Snover[MSFT]
    Distinguished Engineer and Lead Architect for Windows Server and System Center Datacenter

    1. Thanks for the tip! Certainly honored to have you checking out the PowerSploit project and the blog.

  2. The Script Works fine while initiate directly by the logged-on user.
    But I tried it with several methods of self-persistance that will re-start automatically after the original process termination and it wint work...

    1. What methods did you try? As with most keyloggers, any method of persistence requires that the code be ran in the user's context. This could be accomplished with a registry key entry.