«Полезняшкі», або «Реєстр 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_ROOT\exefile\shell\Bpc] 

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

[HKEY_LOCAL_MACHINE\exefile\shell\Bpc\shell\01low] 
"MUIVerb"="Idle CPU, lowest IO, low paging" 
"Icon"="comres.dll,9" 

[HKEY_LOCAL_MACHINE\exefile\shell\Bpc\shell\01low\command] 
@="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_LOCAL_MACHINE\exefile\shell\Bpc\shell\02below] 
"MUIVerb"="Below normal CPU, low IO" 
"Icon"="comres.dll,12" 

[HKEY_LOCAL_MACHINE\exefile\shell\Bpc\shell\02below\command] 
@="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_LOCAL_MACHINE\exefile\shell\Bpc\shell\03above] 
"Icon"="comres.dll,8" 
"MUIVerb"="Above normal CPU" 

[HKEY_LOCAL_MACHINE\exefile\shell\Bpc\shell\03above\command] 
@="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_LOCAL_MACHINE\exefile\shell\Bpc\shell\04high] 
"MUIVerb"="High CPU" 
"Icon"="comres.dll,16" 

[HKEY_LOCAL_MACHINE\exefile\shell\Bpc\shell\04high\command] 
@="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_LOCAL_MACHINE\exefile\shell\Bpc\shell\05delim] 

[HKEY_LOCAL_MACHINE\exefile\shell\Bpc\shell\06ask] 
"MUIVerb"="Show current priorities" 
"Icon"="shell32.dll,23" 

[HKEY_LOCAL_MACHINE\exefile\shell\Bpc\shell\06ask\command] 
@="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_LOCAL_MACHINE\exefile\shell\Bpc\shell\07default] 
"MUIVerb"="to Restore default" 
"Icon"="comres.dll,4" 

[HKEY_LOCAL_MACHINE\exefile\shell\Bpc\shell\07default\command] 
@="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 down to default" 

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

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\BpcSubMenu] 
"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_ROOT\exefile\shell\FWc] 

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

[HKEY_LOCAL_MACHINE\exefile\shell\FWc\shell\01] 
"MUIVerb"="block inbound" 
"Icon"="imageres.dll,100" 

[HKEY_LOCAL_MACHINE\exefile\shell\FWc\shell\01\command] 
@="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_LOCAL_MACHINE\exefile\shell\FWc\shell\02] 
"MUIVerb"="allow inbound" 
"Icon"="imageres.dll,101" 

[HKEY_LOCAL_MACHINE\exefile\shell\FWc\shell\02\command] 
@="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_LOCAL_MACHINE\exefile\shell\FWc\shell\03] 
"Icon"="imageres.dll,100" 
"MUIVerb"="block outbound" 

[HKEY_LOCAL_MACHINE\exefile\shell\FWc\shell\03\command] 
@="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_LOCAL_MACHINE\exefile\shell\FWc\shell\04] 
"MUIVerb"="allow outbound" 
"Icon"="imageres.dll,101" 

[HKEY_LOCAL_MACHINE\exefile\shell\FWc\shell\04\command] 
@="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_LOCAL_MACHINE\exefile\shell\FWc\shell\05delim] 

[HKEY_LOCAL_MACHINE\exefile\shell\FWc\shell\06] 
"MUIVerb"="Show firewall panel" 
"Icon"="imageres.dll,109" 

[HKEY_LOCAL_MACHINE\exefile\shell\FWc\shell\06\command] 
@="mmc.exe wf.msc" 

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

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\FWcSubMenu] 
"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
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.