Copy to Clipboard
#https://hinchley.net/articles/creating-a-key-logger-via-a-global-system-hoo
k-using-powershell/
Add-Type -TypeDefinition @"
using System;
using System.IO;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace KeyLogger {
public static class Program {
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static HookProc hookProc = HookCallback;
private static IntPtr hookId = IntPtr.Zero;
public static string strKey = "";
public static bool blnDown = false;
//public delegate void EventHandler(string strKey);
//public event EventHandler KeyWasPressed;
public static event EventHandler KeyWasPressed = delegate {};
public static void Main() {
hookId = SetHook(hookProc);
Application.Run();
UnhookWindowsHookEx(hookId);
}
private static IntPtr SetHook(HookProc hookProc) {
IntPtr moduleHandle =
GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
return SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, moduleHandle, 0);
}
private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr
lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr
lParam) {
if (nCode >= 0) {
int vkCode = Marshal.ReadInt32(lParam);
strKey = Convert.ToString((Keys)vkCode);
if ( wParam == (IntPtr)WM_KEYDOWN ) {
blnDown = true;
}else{
blnDown = false;
}
Application.Exit();
//Console.WriteLine( strKey );
//RaiseKeyPressed( strKey );
//if ( strKey == "Escape"){
// Application.Exit();
//}
}
return CallNextHookEx(hookId, nCode, wParam, lParam);
}
public static void RaiseKeyPressed (string message)
{
if (KeyWasPressed != null){
KeyWasPressed( message, null );
}
}
[DllImport("user32.dll")]
private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn,
IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll")]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll")]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
}
"@ -ReferencedAssemblies System.Windows.Forms
$Debug = $false
#if ( $psISE ) { $Debug = $true }
$Keys = @{}
$Keys.Shift = $false
$Keys.Alt = $false
$Keys.Ctrl = $false
$Keys.HotKeys = @()
$Keys.KeepLooping = $true
$Keys.KeyIsDown = $false
$Keys.LastKey = ""
$Keys.Letter = ""
$Keys.Pressed = @{}
$Keys.Program = [KeyLogger.Program]
$Keys.Queued = [System.Collections.Queue]::Synchronized( (New-Object
System.Collections.Queue) )
#Register-ObjectEvent -InputObject $Keylogger -EventName "KeyWasPressed"
-Action { Write-Host ("KeyWasPressed: @ $(Get-Date) " + $EventArgs.Message +
"`r`n" + ( $EventArgs | fl * | Out-String )) }
[void]
[System.Reflection.Assembly]::LoadWithPartialName("'System.Windows.Forms")
$signature = '[DllImport("user32.dll")]public static extern short
GetKeyState(int nVirtKey);'
$type = Add-Type -MemberDefinition $signature -Name User32 -Namespace
GetKeyState -PassThru
function Add-Hotkey($CTRL = $false, $ALT = $false, $Shift = $false, $Key =
"", $Name = "", $Action = "type", $Variable=""){
$NewHK = @{}
$NewHK.CTRL = $CTRL
$NewHK.ALT = $ALT
$NewHK.Shift = $Shift
$NewHK.Key = $Key
$NewHK.Name = $Name
$NewHK.Action = $Action
$NewHK.Variable = $Variable
$Keys.HotKeys += $NewHK
}
function CheckForHotkeys{
# Interesting thing to note: Alt key can only be detected if it was NOT
the first key pressed!
# CTRL-ALT-T will detect all 3, but ALT-CTRL-T will only detect CTRL-T.
foreach ( $HK in $Keys.HotKeys ){
if ( $Keys.Alt -eq $HK.Alt -and $Keys.CTRL -eq $HK.CTRL -and
$Keys.Shift -eq $HK.Shift -and $Keys.Pressed.Item($HK.Key) ){
Write-Host "Found hot key: '$($HK.Name)' Action:
'$($HK.Action)' Variable: '$($HK.Variable)'"
switch ($HK.Action)
{
'type' {
Add-ToSendKeysQueue -Text $HK.Variable
}
'ps' {
Invoke-Expression $HK.Variable
}
'exit' {
$Keys.KeepLooping = $false
}
Default {
Write-Host "Unknown action: '$($HK.Action)' Variable:
'$HK.Variable'"
}
}
}
}
}
function Get-KeyState([uint16]$keyCode, $KeyName = ""){ #Used to query any
key state
#List of keycodes is here:
https://docs.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-codes
if ($KeyName.length -gt 0 ){
if ( $KeyName.length -gt 1 ){
if ( $KeyName -eq "F1" ) { $keyCode = 0x70 }
if ( $KeyName -eq "F2" ) { $keyCode = 0x71 }
if ( $KeyName -eq "F3" ) { $keyCode = 0x72 }
if ( $KeyName -eq "F4" ) { $keyCode = 0x73 }
if ( $KeyName -eq "F5" ) { $keyCode = 0x74 }
if ( $KeyName -eq "F6" ) { $keyCode = 0x75 }
if ( $KeyName -eq "F7" ) { $keyCode = 0x76 }
if ( $KeyName -eq "F8" ) { $keyCode = 0x77 }
if ( $KeyName -eq "F9" ) { $keyCode = 0x78 }
if ( $KeyName -eq "F10" ) { $keyCode = 0x79 }
if ( $KeyName -eq "F11" ) { $keyCode = 0x7A }
if ( $KeyName -eq "F12" ) { $keyCode = 0x7B }
}elseif ( $KeyName.length -eq 1 ){
$keyCode = [byte][char]($KeyName).ToUpper()
}
if ( $keyCode -eq 0 ){ return $null }
}
return [bool]($type::GetKeyState($keyCode) -band 0x80)
}
function Add-ToSendKeysQueue($Text){
Write-Host "$(Get-Date) - Adding text to send queue once keys are
released: $($Text)"
$Keys.Queued.Clear()
$Keys.Queued.Enqueue($Text)
}
function Send-Keys($Text){
if ( $true ){
#Save current clipboard text so we can revert back to it
$OldClipboard = Get-Clipboard
#Save text to the clipboard
Set-Clipboard $Text
#Send CTRL-V command to paste text
[System.Windows.Forms.SendKeys]::SendWait("^v") | Out-Null
Write-Host "$(Get-Date) - Just typed in text: $($Text)"
#Set clipboard text back to what it was
Set-Clipboard $OldClipboard
}else{
[System.Windows.Forms.SendKeys]::SendWait($Text) | Out-Null
Write-Host "$(Get-Date) - Just typed in text: $($Text)"
}
}
Add-Hotkey -CTRL $true -Shift $true -Key "F12" -Action "Exit" -Name "Exit"
Write-Host "Added exit hotkey of CTRL-SHIFT-F12"
Add-Hotkey -CTRL $true -Shift $true -Key "Q" -Action "type" -Name "Test1"
-Variable "Typing this is a test"
Write-Host "Added test hotkey of CTRL-SHIFT-Q"
Add-Hotkey -CTRL $true -Shift $true -Key "D" -Action "ps" -Name "Test2"
-Variable "Add-ToSendKeysQueue -Text (Get-Date)"
Write-Host "Added test hotkey of CTRL-SHIFT-D"
do{
#Show how long the last process loop took
if ( $Debug ) { if ( $StartTime ) { Write-Host "Time taken:
$((New-Timespan $StartTime).TotalMilliseconds)" } }
$SkipKeyCheck = $false
#Check if key was released while PS was processing, and if so then don't
wait for another key press!
if ( $NewKey.length -gt 0 -and $Keys.KeyIsDown ){
$StillPressed = Get-KeyState -KeyName $NewKey
if ( $StillPressed -eq $false ){
$SkipKeyCheck = $true
$Keys.Pressed.Remove( $NewKey )
}
}
#Check all keys that are marked as being pressed, if any aren't then
skip waiting for keypress
$AllKeys = ( $Keys.Pressed.Keys | Sort )
foreach ( $Key in $AllKeys ){
$StillPressed = Get-KeyState -KeyName $Key
if ( $StillPressed -eq $false ){
$SkipKeyCheck = $true
$Keys.Pressed.Remove( $Key )
}
}
#Start Program
if ( $SkipKeyCheck -eq $false ){
$Keys.Program::Main()
if ( $Debug ) { $StartTime = Get-Date }
$Keys.KeyIsDown = $Keys.Program::blnDown
$NewKey = $Keys.Program::strKey
}else{
#Key was released very quickly, run loop again
$Keys.KeyIsDown = $false
}
#Get Keys
#Check for duplicate
if ( $NewKey -eq $Keys.LastKey -and $Keys.KeyIsDown -and
$Keys.Pressed.Item( $Keys.LastKey ) ){
#Nothing changed, key must be held down, don't do anything
}else{
$Keys.LastKey = $NewKey
if ( $Keys.LastKey.length -gt 0 ){
#Save current state of this key
if ( $Keys.KeyIsDown ){
$Keys.Pressed.Item( $Keys.LastKey ) = $true
}else{
# Key is not pressed, change value to null
$Keys.Pressed.Remove( $Keys.LastKey )
}
#Shift Key
$Keys.Shift = [bool]($type::GetKeyState(0x10) -band 0x80)
if ( ! $Keys.Shift ){
$Keys.Pressed.Remove( "LShiftKey" )
$Keys.Pressed.Remove( "RShiftKey" )
}
#ALT Key
$Keys.ALT = [bool]($type::GetKeyState(0x12) -band 0x80)
if ( ! $Keys.ALT ){
$Keys.Pressed.Remove( "LMenu" )
$Keys.Pressed.Remove( "RMenu" )
}
#CTRL Key
$Keys.CTRL = [bool]($type::GetKeyState(0x11) -band 0x80)
if ( ! $Keys.CTRL ){
$Keys.Pressed.Remove( "LControlKey" )
$Keys.Pressed.Remove( "RControlKey" )
}
# Only check for hotkeys if one of these keys is pressed
if ( $Keys.ALT -or $Keys.CTRL -or $Debug ){
CheckForHotkeys
if ( $Keys.KeyIsDown ){
Write-Host "Pressed: $($Keys.LastKey) Shift:
$($Keys.Shift) ALT: $($Keys.ALT) CTRL: $($Keys.CTRL) Pressed: $(
$Keys.Pressed.Keys -join ',')"
}else{
Write-Host "Released: $($Keys.LastKey) Shift:
$($Keys.Shift) ALT: $($Keys.ALT) CTRL: $($Keys.CTRL) Pressed: $(
$Keys.Pressed.Keys -join ',')"
}
}
if ( $Debug -and $NewKey.Length -eq 1 ){
$StillPressed = Get-KeyState (
[byte][char]($NewKey).ToUpper() )
if ( $StillPressed -eq $false ){
Write-Host "Key $($NewKey) has been released"
#$Keys.Pressed.Remove( $NewKey )
}elseif ( $Debug ){
Write-Host "Key $($NewKey) is still pressed"
}
}
# If something is queued then run it if no keys are still
pressed
if ( $Keys.Queued.count -gt 0 -and ( $Keys.Pressed.Keys.count
-eq 0 -or $false ) ){
do {
#Item is queued and no keys are pressed
$Text = $Keys.Queued.Dequeue()
Send-Keys -Text $Text
}while ( $Keys.Queued.count -gt 0 )
}
#if ( $Keys.LastKey -eq "Escape" ){ $Keys.KeepLooping = $false }
} # End of $Keys.LastKey.length -gt 0
} # End of duplicate check
}
while ( $Keys.KeepLooping )
Get-EventSubscriber | Unregister-Event
|