В этой статье я расскажу как ловить события, происходящие в операционной системе Windows, используя временную подписку WMI. Как известно, у временной подписки есть ряд недостатков, поэтому в процессе изложения мы рассмотрим несколько, на мой взгляд, экзотических способов для их преодоления. Are you ready ?
Определимся с задачей: поймать события запуска стандартного блокнота Notepad, завершения его работы, и сделать запуск скрипта автоматическим, а процесс отлова как можно более "живучим".
Определимся с задачей: поймать события запуска стандартного блокнота Notepad, завершения его работы, и сделать запуск скрипта автоматическим, а процесс отлова как можно более "живучим".
Картина первая. Начнем с запуска. Ловим создание экземпляра и оповещаем об этом диалоговым окном.
Const ffProcName = "notepad.exe" 'ловим событие создания процесса Set colEvents = GetObject("winmgmts:\\.\Root\CIMV2").ExecNotificationQuery( _ "SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_Process' " & _ "AND TargetInstance.Name = '" & ffProcName& "'") Do Set objEvent = colEvents.NextEvent MsgBox "Вы запустили процесс " & objEvent.TargetInstance.Name Loop
Сохраним файл с именем CatchNPStart.vbs. Запускаем скрипт, блокнот... Все по плану. Запускаем диспетчер задач, убиваем процесс wscript.exe.
Картина вторая. Усложняем задачу. Добавим к запуску событие завершения работы блокнота. Ловим события, выбираем создание либо удаление экземпляра, оповещаем в зависимости от события.
Const ffProcName = "notepad.exe" 'ловим события Set colEvents = GetObject("winmgmts:\\.\Root\CIMV2").ExecNotificationQuery( _ "SELECT * FROM __InstanceOperationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_Process' " & _ "AND TargetInstance.Name = '" & ffProcName & "'") Do With colEvents.NextEvent 'если создание If .Path_.Class = "__InstanceCreationEvent" Then MsgBox "Вы запустили процесс " & ffProcName 'если удаление ElseIf .Path_.Class = "__InstanceDeletionEvent" Then MsgBox "Вы завершили процесс " & ffProcName End If End With Loop
Назовем файл CatchNPStartNFin.vbs. Запускаем скрипт, блокнот... Дело сделано.
Недостатки налицо: скрипт необходимо запустить и процесс его выполнения можно прервать.
Для решения проблемы запуска процесса у меня есть четыре варианта, три из которых в этой статье мы подробно рассматривать не будем по причине их тривиальности:
- автозапуск - разделы реестра Run, RunOnce
- логон-скрипт - он же сценарий входа
- Winlogon - чуть более "навороченный", но уже успевший стать довольно популярным способ, который используют всевозможные локеры
- четвертый вариант рассмотрим чуть позже
- автозапуск - разделы реестра Run, RunOnce
- логон-скрипт - он же сценарий входа
- Winlogon - чуть более "навороченный", но уже успевший стать довольно популярным способ, который используют всевозможные локеры
- четвертый вариант рассмотрим чуть позже
Итак, будем считать, что наш скрипт запущен при входе пользователя в систему, и теперь юзеру ничего не мешает запустить диспетчер задач Windows, Process Explorer от Марка Руссиновича (его имя мы еще вспомним далее в статье), или любой иной программный продукт, способный работать с процессами, и благополучно убить наше "творение" (что идет вразрез с поставленной выше задачей). Ограничения типа запрета использования диспетчера задач и пр. в расчет не берем. Пчелы начали что-то подозревать и они добьются своего :). Оградить свое времяпрепровождение от посторонних глаз в лице нашего скрипта для пчел - святое дело :).
Картина третья. Попробуем увеличить "плавучесть" процесса путем создания "катамарана" - напишем второй скрипт, задача которого состоит в том, чтобы следить за убийством процесса первого и возрождать его в случае необходимости.
Const wsProcName = "wscript.exe" Const scrFileName = "CatchNPStartNFin2.vbs" Set objWMI = GetObject("winmgmts:\\.\Root\CIMV2") 'ловим событие завершения скрипта Set colEvents = objWMI.ExecNotificationQuery( _ "SELECT * FROM __InstanceDeletionEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_Process' " & _ "AND TargetInstance.Name = '" & wsProcName & "' AND TargetInstance.CommandLine LIKE '%" & scrFileName & "%'") Do Set objEvent = colEvents.NextEvent With CreateObject("Scripting.FileSystemObject") 'перезапускаем скрипт objWMI.Get("Win32_Process").Create(wsProcName & " " & _ Chr(34) & .BuildPath(.GetParentFolderName(.GetFile(WScript.ScriptFullName)),scrFileName)) & Chr(34) End With Loop
Сохраним файл с именем CatchScriptKill.vbs
Картина четвертая. Изменим код скрипта CatchNPStartNFin.vbs с тем, чтобы он в свою очередь следил за убийством скрипта CatchScriptKill.vbs - в противном случае наш "катамаран" далеко не уплывет.
Const ffProcName = "notepad.exe" Const wsProcName = "wscript.exe" Const scrFileName = "CatchScriptKill.vbs" Set objWMI = GetObject("winmgmts:\\.\Root\CIMV2") 'ловим событие, добавим скрипт Set colEvents = objWMI.ExecNotificationQuery( _ "SELECT * FROM __InstanceOperationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_Process' " & _ "AND (TargetInstance.Name = '" & ffProcName & "' OR (TargetInstance.Name = '" & wsProcName & _ "' AND TargetInstance.CommandLine LIKE '%" & scrFileName & "%'))") Do With colEvents.NextEvent 'если создание If .Path_.Class = "__InstanceCreationEvent" Then If .TargetInstance.Name = ffProcName Then MsgBox "Вы запустили процесс " & ffProcName End If 'если удаление ElseIf .Path_.Class = "__InstanceDeletionEvent" Then 'если огнелис If .TargetInstance.Name = ffProcName Then MsgBox "Вы завершили процесс " & ffProcName 'если скрипт ElseIf .TargetInstance.Name = wsProcName Then With CreateObject("Scripting.FileSystemObject") 'перезапускаем скрипт objWMI.Get("Win32_Process").Create(wsProcName & " " & _ Chr(34) & .BuildPath(.GetParentFolderName(.GetFile(WScript.ScriptFullName)),scrFileName)) & Chr(34) End With End If End If End With LoopНазовем файл CatchNPStartNFin2.vbs. Не забудем убить запущенный ранее процесс wscript.exe. Запускам оба только что написанных скрипта (в любой последовательности), блокнот... Работает. Теперь попробуем убить процесс с помощью какого-нибудь диспетчера задач (я пробовал на обозначенных выше стандартном и Process Explorer), а он как феникс... Ну в общем понятно.
Картина пятая. С целью избавления системы от нашего "катамарана" пишем своего "киллера".
For Each objProcess In _ GetObject("winmgmts:\\.\Root\CIMV2").ExecQuery("SELECT * FROM Win32_Process WHERE Name='wscript.exe'") objProcess.Terminate() NextНазовем его WScriptKiller.vbs.
Можно обойтись и батником в одну строку.
taskkill /im wscript.exe /fКартина шестая. Рассмотрим пропущенный выше четвертый вариант и вспомним Марка Руссиновича. Среди его разработок есть интересное приложение по имени srvany.exe, использование которого позволит нам запускать скрипт в качестве службы. Не совсем "наш", но зато наиболее эффективный метод: автозапуск + отсутствие процесса в каком-либо диспетчере задач.
Const scrFileName = "CatchNPStartNFin.vbs" Const ServiceName = "MyService" Const HKLM = &H80000002 With CreateObject("Scripting.FileSystemObject") sPathName = .BuildPath(.GetParentFolderName(.GetFile(WScript.ScriptFullName)),"srvany.exe") sParamName = "wscript.exe " &.BuildPath(.GetParentFolderName(.GetFile(WScript.ScriptFullName)),scrFileName) End With Set objWMI = GetObject("winmgmts:\\.\Root\CIMV2") Set objInstance = objWMI.Get("Win32_Service") Set objMethod = objInstance.Methods_("Create") Set objInParam = objMethod.inParameters.SpawnInstance_() 'задаем параметры objInParam.Name = ServiceName objInParam.DisplayName = "My Interactive Service" objInParam.StartMode = "Automatic" objInParam.DesktopInteract = True objInParam.PathName = sPathName 'создаем службу Set objOutParam = objInstance.ExecMethod_("Create", objInParam) If objOutParam.ReturnValue <> 0 Then MsgBox "Не удалось создать службу " & ServiceName WScript.Quit End If 'создаем ключи реестра, чтобы запускать srvany.exe с параметром - нашим скриптом sKeyPath = "SYSTEM\CurrentControlSet\Services\" & ServiceName & "\Parameters" With GetObject("winmgmts:\\.\root\default:StdRegProv") .CreateKey HKLM,sKeyPath .SetStringValue HKLM,sKeyPath,"Application",sParamName End With If Err.Number <> 0 Then MsgBox "Не удалось создать ключи реестра " & ServiceName WScript.Quit End If 'запускаем службу Set colServices = objWMI.ExecQuery("SELECT * FROM Win32_Service WHERE Name='" & ServiceName & "'") If colServices.Count Then For Each objService In colServices ret = objService.StartService If ret <> 0 Then MsgBox "Не удалось запустить службу " & ServiceName WScript.Quit End If Next Else MsgBox "Не удалось создать службу " & ServiceName WScript.Quit End If MsgBox "Служба " & ServiceName & " установлена и запущена"
Сохраняем файл с именем ServiceCreate.vbs. Запускаем... Проверяем на нашем блокноте...
Картина седьмая. Не мешало бы научиться удалять наши службы.
Const ServiceName = "MyService" Const HKLM = &H80000002 Set objWMI = GetObject("winmgmts:\\.\Root\CIMV2") Set colServices = objWMI.ExecQuery("SELECT * FROM Win32_Service WHERE Name='" & ServiceName & "'") If colServices.Count Then For Each objService In colServices ret = objService.StopService If ret <> 0 Then MsgBox "Не удалось остановить службу " & ServiceName WScript.Quit End If ret = objService.Delete If ret <> 0 Then MsgBox "Не удалось удалить службу " & ServiceName WScript.Quit End If Next Else MsgBox "Служба " & ServiceName & " не найдена" WScript.Quit End If MsgBox "Служба " & ServiceName & " остановлена и удалена"
Назовем файл ServiceDelete.vbs. Удаляем нашу первую, очень функциональную, и для кого-то далеко не последнюю службу :).
Картина восьмая. Заключительная.
Содержание статьи - мой взгляд на временную подписку WMI и повышение "живучести" процесса. Для тех, кого заинтересовали технологии, использованные автором, хочу заметить, что в процессе изучения предметной области Вы сможете открыть для себя более "неубиваемые" способы мониторинга событий.
Удачи :).
p.s. Представьте насколько глубоко можно засадить в систему код, используя пару служб типа "катамарана" ;)?
Содержание статьи - мой взгляд на временную подписку WMI и повышение "живучести" процесса. Для тех, кого заинтересовали технологии, использованные автором, хочу заметить, что в процессе изучения предметной области Вы сможете открыть для себя более "неубиваемые" способы мониторинга событий.
Удачи :).
p.s. Представьте насколько глубоко можно засадить в систему код, используя пару служб типа "катамарана" ;)?
Комментариев нет:
Отправить комментарий
Комментарий будет опубликован после модерации