GuideProgramming + ScriptingPowershell Hotkeys Test Updated August 11 2024
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




©2024 - Some portions of this website are Copyrighted.
Your IP: 18.222.56.251     Referring URL:
Browser: Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)
Terms and Conditions, Privacy Policy, and Security Policy