- PVSM.RU - https://www.pvsm.ru -

«Полезняшки» или «Реестр Windows как платформа»

Хочу рассказать вам историю, как решение конкретных прикладных задач привело меня к использованию реестра Windows в качестве платформы для хранения и исполнения кода.

Приоритеты

Давным-давно, когда я переходил с ХР на Семерку, одним из важных преимуществ новой системы я считал введение приоритетов на ввод-вывод и на пейджинг, а не только на процессор. Однако сейчас у нас Десятка на дворе, а удобных штатных средств управления этими приоритетами так и не появилось.
Как я с удивлением обнаруживаю, большинство пользователей вообще не в курсе о такой замечательной возможности. Их удовлетворяет опция в Task Manager по смене текущего приоритета CPU для уже запущенного процесса (и то только если им это будет позволено). А ситуацию, когда даже выставленный в LOW фоновый процесс своим дисковым обменом или свопингом мешает работать более приоритетным задачам, считают неизбежным злом.
Некоторые, устав от обращения к Task Manager при каждом запуске, вставляют в ярлыки запуска критичных программ перед самим объектом что-то вроде

cmd /c start /realtime

Это позволяет запустить что-то с приоритетом HIGH (а не realtime, как они думают), но никак не затрагивает проблему с приоритетом ввода-вывода. Кроме того, ряд приложений используют файл-запускальщик, который, в свою очередь, запускает основную программу. А она в таком варианте будет запущена с приоритетом по умолчанию, и лишь уже не нужный запускальщик будет красоваться в Task Manager с приоритетом HIGH.

Решением проблемы является создание веток в «Image File Execution Options» в реестре, но руками это делать достаточно утомительно.
Конечно, есть ряд сторонних приложений, которые позволят вам прописать правильные ветки в реестре для нужной программы, но я специально упомянул в первом абзаце слово «штатных»: зачастую это нужно делать на машине, на которой запрещена установка сторонних экзешников, отключены сменные носители, и затруднено получение (как из интернета, так и по почте) любых исполняемых файлов, пакетов, архивов, BAT, CMD и даже REG-файлов. В особо серьезных случаях контролируется реальное содержимое файла на предмет смены типа или внедрение в документ-контейнер вложения недозволенного типа.

Итак, намаявшись с реестром, я поставил себе задачу написать утилитку, которая позволяет менять базовый приоритет запуска программы как для CPU, так и для IO и Paging, и при этом:

  • использует только штатные средства, присутствующие в дефолтной инсталляции windows.
  • избавляет от необходимости вписывать имя файла (например, активируясь из его контекстного меню)
  • избавляет от необходимости во введении пароля администратора в командной строке или в предварительном открытии сессии под администратором (единственно, что допустимо – всплывающее окно UAC)
  • (необязательно) не оставляет никаких постоянных файлов на диске (дабы не нервировать сотрудников Первого отдела)
  • (необязательно) поддерживает деинсталляцию
  • (главное) может быть получена, как текст (по почте или с web-страницы), а не файл.

Последнее требование важно не только в плане доставки. Это универсальный способ показать пользователю, что утилита не содержит закладок или нежелательного функционала. Заодно и выполнение одного из требований GPL – предоставления исходного кода.

Изложенные требования определили выбор, что это должен быть скриптовый язык, последующие исследования показали, что даже к PowerShell прибегать не нужно, достаточно будет обычного синтаксиса CMD и VBS, затем попробовал уместить одно действие в одну строку, а не в bat-файл, а далее, так как в любом случае требовалась запись в реестр, родилась мысль уместить все в самом реестре, тем самым выполнив условие по отсутствию файлов.

В итоге получилась утилитка, которая выглядит, как выпадающее подменю в свойствах исполняемых файлов:
image

А вот она сама:

Windows Registry Editor Version 5.00 

;Copyright 2016 Trottle 
;This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3. 
;This program is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
;See <http://www.gnu.org/licenses/> for more details. 

[-HKEY_CLASSES_ROOTexefileshellBpc] 

[HKEY_CLASSES_ROOTexefileshellBpc] 
"ExtendedSubCommandsKey"="exefile\shell\Bpc" 
"HasLUAShield"="" 
"MUIVerb"="Set base priority" 

[HKEY_CLASSES_ROOTexefileshellBpcshell1low] 
"MUIVerb"="Idle CPU, lowest IO, low paging" 
"Icon"="comres.dll,9" 

[HKEY_CLASSES_ROOTexefileshellBpcshell1lowcommand] 
@="cmd /q /c echo Windows Registry Editor Version 5.00>%%TEMP%%\pr.reg & echo.>>%%TEMP%%\pr.reg & for /f "delims=<" %%i in ("%1") do echo [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\%%~nxi\PerfOptions]>>%%TEMP%%\pr.reg & echo.>>%%TEMP%%\pr.reg & echo "CpuPriorityClass"=dword:00000001>>%%TEMP%%\pr.reg & echo.>>%%TEMP%%\pr.reg & echo "IoPriority"=dword:00000000>>%%TEMP%%\pr.reg & echo.>>%%TEMP%%\pr.reg & echo "PagePriority"=dword:00000001>>%%TEMP%%\pr.reg & regedit /s %%TEMP%%\pr.reg & del %%TEMP%%\pr.reg & msg * %~ni priority is set to IDLE" 

[HKEY_CLASSES_ROOTexefileshellBpcshell2below] 
"MUIVerb"="Below normal CPU, low IO" 
"Icon"="comres.dll,12" 

[HKEY_CLASSES_ROOTexefileshellBpcshell2belowcommand] 
@="cmd /q /c echo Windows Registry Editor Version 5.00>%%TEMP%%\pr.reg & echo.>>%%TEMP%%\pr.reg & for /f "delims=<" %%i in ("%1") do echo [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\%%~nxi\PerfOptions]>>%%TEMP%%\pr.reg & echo.>>%%TEMP%%\pr.reg & echo "CpuPriorityClass"=dword:00000005>>%%TEMP%%\pr.reg & echo.>>%%TEMP%%\pr.reg & echo "IoPriority"=dword:00000001>>%%TEMP%%\pr.reg & echo.>>%%TEMP%%\pr.reg & echo "PagePriority"=->>%%TEMP%%\pr.reg & regedit /s %%TEMP%%\pr.reg & del %%TEMP%%\pr.reg & msg * %~ni priority is set to BELOW NORMAL" 

[HKEY_CLASSES_ROOTexefileshellBpcshell3above] 
"Icon"="comres.dll,8" 
"MUIVerb"="Above normal CPU" 

[HKEY_CLASSES_ROOTexefileshellBpcshell3abovecommand] 
@="cmd /q /c echo Windows Registry Editor Version 5.00>%%TEMP%%\pr.reg & echo.>>%%TEMP%%\pr.reg & for /f "delims=<" %%i in ("%1") do echo [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\%%~nxi\PerfOptions]>>%%TEMP%%\pr.reg & echo.>>%%TEMP%%\pr.reg & echo "CpuPriorityClass"=dword:00000006>>%%TEMP%%\pr.reg & echo.>>%%TEMP%%\pr.reg & echo "IoPriority"=->>%%TEMP%%\pr.reg & echo.>>%%TEMP%%\pr.reg & echo "PagePriority"=->>%%TEMP%%\pr.reg & regedit /s %%TEMP%%\pr.reg & del %%TEMP%%\pr.reg & msg * %~ni priority is set to ABOVE NORMAL" 

[HKEY_CLASSES_ROOTexefileshellBpcshell4high] 
"MUIVerb"="High CPU" 
"Icon"="comres.dll,16" 

[HKEY_CLASSES_ROOTexefileshellBpcshell4highcommand] 
@="cmd /q /c echo Windows Registry Editor Version 5.00>%%TEMP%%\pr.reg & echo.>>%%TEMP%%\pr.reg & for /f "delims=<" %%i in ("%1") do echo [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\%%~nxi\PerfOptions]>>%%TEMP%%\pr.reg & echo.>>%%TEMP%%\pr.reg & echo "CpuPriorityClass"=dword:00000003>>%%TEMP%%\pr.reg & echo.>>%%TEMP%%\pr.reg & echo "IoPriority"=->>%%TEMP%%\pr.reg & echo.>>%%TEMP%%\pr.reg & echo "PagePriority"=->>%%TEMP%%\pr.reg & regedit /s %%TEMP%%\pr.reg & del %%TEMP%%\pr.reg & msg * %~ni priority is set to HIGH" 

[HKEY_CLASSES_ROOTexefileshellBpcshell5delim] 

[HKEY_CLASSES_ROOTexefileshellBpcshell6ask] 
"MUIVerb"="Show current priorities" 
"Icon"="shell32.dll,23" 

[HKEY_CLASSES_ROOTexefileshellBpcshell6askcommand] 
@="cmd /q /c for /f "delims=<" %%i in ("%1") do reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\%%~nxi\PerfOptions" /s | msg *" 

[HKEY_CLASSES_ROOTexefileshellBpcshell7default] 
"MUIVerb"="Restore to default" 
"Icon"="comres.dll,4" 

[HKEY_CLASSES_ROOTexefileshellBpcshell7defaultcommand] 
@="cmd /q /c echo Windows Registry Editor Version 5.00>%%TEMP%%\pr.reg & echo.>>%%TEMP%%\pr.reg & for /f "delims=<" %%i in ("%1") do echo [-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\%%~nxi\PerfOptions]>>%%TEMP%%\pr.reg & regedit /s %%TEMP%%\pr.reg & del %%TEMP%%\pr.reg & msg * %~ni priority is restored to default" 

; If you do not want to have uninstaller you can skip next part: 

[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionUninstallBpcSubMenu] 
"DisplayName"="'Set base priority' submenu" 
"DisplayIcon"="imageres.dll,73" 
"UninstallString"="cmd /q /c echo Windows Registry Editor Version 5.00>%TEMP%\pr.reg & echo.>>%TEMP%\pr.reg & echo [-HKEY_CLASSES_ROOT\exefile\shell\Bpc]>>%TEMP%\pr.reg & echo.>>%TEMP%\pr.reg & echo [-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\BpcSubMenu]>>%TEMP%\pr.reg & regedit /s %TEMP%\pr.reg & del %TEMP%\pr.reg" 
"DisplayVersion"="1.0" 
"URLInfoAbout"="http://habrahabr.ru/post/317802/" 
"NoModify"=dword:00000001 
"NoRepair"=dword:00000001

Соответственно, процесс инсталляции выглядит так: получаем вышеизложенный исходник, сохраняем его, как reg-файл, и запускаем. После чего его можно смело удалять. А мы получаем новое подменю по правому клику мышки на исполняемом файле.
При этом, правда, стоит учитывать две вещи:
1. То, что делает утилитка, разрешено только админам, поэтому, если вы не член группы админов, одним только запросом UAC не обойдется.
2. Windоws почему-то показывает подменю не только на самих.ЕХЕ, но и на их ярлыках, но при этом не вызывает на последних пункты подменю.

Также вы, должно быть, заметили, что
— во-первых, нет приоритета Realtime,
— во вторых, все приоритеты, кроме CPU, идут только в сторону уменьшения
— в третьих, приоритет Paging ставится чуть выше, чем приоритет IO.
Это соответствует рекомендациям Microsoft по работе с приоритезацией:
— уменьшать у ненужного, а не увеличивать у нужного;
— свопинг важнее работы с файлами;
— не работать с Realtime («честный» риалтайм действительно может быть опасен для стабильности всей системы, поэтому через реестр ни его, ни высокий приоритет IO не выставить).

Брандмауэр

Между первой и второй промежуток небольшой – решил таким же образом упростить работу со штатным брандмауэром. Многим он хорош, но не удобством обращения с ним. В данном случае решил ускорить создание разрешений или запрещений на программу. (Считаю возможность привязывать правила к программам главным преимуществом внутреннего брандмауэра перед внешним.) Я использую брандмауэр в режиме блокировки исходящих соединений по умолчанию, поэтому добавлять новую программу, как правило, приходится часто.

Получилось такое:
image

и текст:

Windows Registry Editor Version 5.00 

;Copyright 2016 Trottle 
;This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3. 
;This program is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
;See <http://www.gnu.org/licenses/> for more details. 

[-HKEY_CLASSES_ROOTexefileshellFWc] 

[HKEY_CLASSES_ROOTexefileshellFWc] 
"ExtendedSubCommandsKey"="exefile\shell\FWc" 
"MUIVerb"="Set firewall rules" 
"Icon"="imageres.dll,102" 

[HKEY_CLASSES_ROOTexefileshellFWcshell1] 
"MUIVerb"="block inbound" 
"Icon"="imageres.dll,100" 

[HKEY_CLASSES_ROOTexefileshellFWcshell1command] 
@="cmd /q /c echo CreateObject("Shell.Application").ShellExecute "cmd", "/q /c chcp 1251 & netsh advfirewall firewall add rule name=""%1"" dir=in action=block program=""%1"" enable=yes | msg * ", "", "runas" > %%temp%%\ev.vbs & cscript %%temp%%\ev.vbs & del %%temp%%\ev.vbs" 

[HKEY_CLASSES_ROOTexefileshellFWcshell2] 
"MUIVerb"="allow inbound" 
"Icon"="imageres.dll,101" 

[HKEY_CLASSES_ROOTexefileshellFWcshell2command] 
@="cmd /q /c echo CreateObject("Shell.Application").ShellExecute "cmd", "/q /c chcp 1251 & netsh advfirewall firewall add rule name=""%1"" dir=in action=allow program=""%1"" enable=yes | msg * ", "", "runas" > %%temp%%\ev.vbs & cscript %%temp%%\ev.vbs & del %%temp%%\ev.vbs" 

[HKEY_CLASSES_ROOTexefileshellFWcshell3] 
"Icon"="imageres.dll,100" 
"MUIVerb"="block outbound" 

[HKEY_CLASSES_ROOTexefileshellFWcshell3command] 
@="cmd /q /c echo CreateObject("Shell.Application").ShellExecute "cmd", "/q /c chcp 1251 & netsh advfirewall firewall add rule name=""%1"" dir=out action=block program=""%1"" enable=yes | msg * ", "", "runas" > %%temp%%\ev.vbs & cscript %%temp%%\ev.vbs & del %%temp%%\ev.vbs" 

[HKEY_CLASSES_ROOTexefileshellFWcshell4] 
"MUIVerb"="allow outbound" 
"Icon"="imageres.dll,101" 

[HKEY_CLASSES_ROOTexefileshellFWcshell4command] 
@="cmd /q /c echo CreateObject("Shell.Application").ShellExecute "cmd", "/q /c chcp 1251 & netsh advfirewall firewall add rule name=""%1"" dir=out action=allow program=""%1"" enable=yes | msg * ", "", "runas" > %%temp%%\ev.vbs & cscript %%temp%%\ev.vbs & del %%temp%%\ev.vbs" 

[HKEY_CLASSES_ROOTexefileshellFWcshell5delim] 

[HKEY_CLASSES_ROOTexefileshellFWcshell6] 
"MUIVerb"="Show firewall panel" 
"Icon"="imageres.dll,109" 

[HKEY_CLASSES_ROOTexefileshellFWcshell6command] 
@="mmc.exe wf.msc" 

; If you do not want to have uninstaller you can skip next part: 

[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionUninstallFWcSubMenu] 
"DisplayName"="'Set firewall rules' submenu" 
"DisplayIcon"="imageres.dll,102" 
"UninstallString"="cmd /q /c echo Windows Registry Editor Version 5.00>%TEMP%\pr.reg & echo.>>%TEMP%\pr.reg & echo [-HKEY_CLASSES_ROOT\exefile\shell\FWc]>>%TEMP%\pr.reg & echo.>>%TEMP%\pr.reg & echo [-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\FWcSubMenu]>>%TEMP%\pr.reg & regedit /s %TEMP%\pr.reg & del %TEMP%\pr.reg" 
"DisplayVersion"="1.0" 
"URLInfoAbout"="http://habrahabr.ru/post/317802/" 
"NoModify"=dword:00000001 
"NoRepair"=dword:00000001 

Замечу, что, в отличие от первой утилитки, здесь клик на одном пункте не отменяет другие, т.е. создание запрещающего правила не стирает разрешающее, и наоборот. Сделано это на случай, когда создается несколько правил на одну программу и в дальнейшем каждое уточняется (по портам, адресам, режимам, и т.д.). Таким образом, если кликнуть и на «allow», и на «block», будет создано 2 правила, а сетевой доступ программе будет закрыт (запрещающие правила имеют приоритет перед разрешающими).

Деинсталляция для обеих утилит штатная – заходим в «Программы и компоненты» и удаляем:
image

Автор: Trottle

Источник [1]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/open-source/221686

Ссылки в тексте:

[1] Источник: https://habrahabr.ru/post/317802/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best