Краткое содержание: история в картинках, как я «улучшал» Task Manager в Windows Server 2012
Преамбула
Началось всё с того, что я в тестовых целях (выяснить, есть ли принципиальное различие), поставил Windows Server 2012. Для тех, кто не знает, это такая Windows 8, только дороже. Ну, а ещё, от него можно оторвать GUI и поставить всякие разные роли.
Ну так вот, одна из наиболее приятных вещей в Windows 8 для меня — новый Таск Менеджер, и красивый и удобный. Какое же было моё удивление, когда я открыл его в WinServer 2012 и не увидел некоторых данных.
Вот пара картинок для понятности.
Windows 8:
Windows Server 2012
Как видно, не хватает пары вкладок, кроме того, отсутствуют столбцы с диском и сетью. Диск ещё отсутствут на вкладке Performance, но это хотя бы можно включить командой:
diskperf -y
Вооружившись гуглом, я выяснил, что проблема в следующем:
This is because disk metrics are disabled by default on Windows Server 2012 because of significant performance impact, however, it is enabled in Windows 8.Use Resource Monitor to gauge Disk and Network IO usage. — Syed Yusuf from Microsoft R&D
Что в переводе на русский звучит как «слишком большая нагрузка на диск, поэтому мы это убрали».
Так и представляю картину: серверная, все бегают в мыле, сервер не отвечает, ужасающая нагрузка. И скромный админ в углу: «я случайно открыл таск менеджер на сервере вместо своего нетбука, я больше не буууду!».
То есть, по мнению Microsoft на могучих серверах это вызывает огромную нагрузку, но при этом на планшетах совершенно не вызывает проблем, поэтому там уберём, тут включим. При том, что на серверах таск менеджер запускается раз в полгода, как раз, чтобы посмотреть на проблемы с производительностью, а нам убирают данную возможность по какой-то странной причине.
В общем, меня это не устроило, и я начал исследовать проблему.
Версия 1. Реестр
Зная Microsoft и то, что всё настраивается в реестре, я начал копать taskmgr.exe с целью найти возможные ключи. Единственный подходящий ключ обнаружился в
HKLM SystemCurrentControlSetServicesPartmgr, EnableCounterForIoctl
Но как я уже выяснил раньше, этот ключ включается командой diskperf и интереса не представляет.
Версия 2. Неужели действительно проверка на тип системы?
Совершенно не веря, что такое может быть (Microsoft обычно просто выпиливает лишние файлы), я решил проверить, а что будет, если сказать Таск Менеджеру, что он на самом деле на клиентской системе.
Чтобы проверить версию системы из своего приложения, нужно вызвать функцию GetVersionEx. Вернётся структура OSVERSIONINFOEX, где в поле dwProductType будет указано, сервеная или клиентская версия системы.
При этом, GetVersionEx вызывает RtlGetNtProductType, которая в регистре ecx возвращает 1 для клиентской и 3 для серверной. С неё-то и начнём.
Отладчиками под Windows я пользовался мало, поэтому выбрал единственный, с которым умею обращаться в данном случае, WinDbg (прямая ссылка на не самую свежую версию). Для него есть замечательная команда, которой можно сделать автоматический брекпоинт с заменой:
bp ntdll!RtlGetNtProductType "as /x ReturnValue rcx; gu; ed ReturnValue 1; g"
(т.е. открываем наш taskmgr.exe, выполняем команду, запускаем выполнение).
И… идея сработала. Все вкладки появились, да ещё и полностью рабочие. Т.е. функционально всё присутствует, а отключено только по политическим мотивам (могли бы по тем же мотивам их просто спрятать по умолчанию).
Соответственно, нужно копать дальше в данном направлении. Ставим бряк на ntdll!RtlGetNtProductType и смотрим по Call Stack, когда нас вызовет реальный taskmgr, а не инициализационные куски. Выглядит это примерно так:
Идём по стектрейсу ставим брекпоинт на TaskMgr (или доходим вручную) и видим следующий код:
Это проверка кода возврата, тут нам делать нечего, идём чуть дальше:
Вот он, самый сок!
Сравнивается регистр на 1 и на 3, и в зависимости от ситуации идёт переход на нужную ветку.
Ставим al в 1 и наблюдаем что всё успешно работает. Половина пути пройдена. Нужно думать над решениями, как это всё оформить на постоянной основе.
- Можно сделать скрипт для WInDbg, который всё будет делать сам. Неспортивно
- Пропатчить память перед запуском TaskMgr. Вариант пришлось отбросить, потому что я не знаю как это сделать, а разбираться долго.
- Пропатчить сам taskmgr.exe. Самый простой вариант, только сломаем целостность файла и система может периодически его возвращать к старой версии. Но решил, что с этим можно прожить и стал думать над этим вариантом
Итак, нам нужно заменить данный код. Способов заменить его множество: сравнить al не с 1, а с 3, заменить jne, на je, изменить адрес джампа. В общем, я выбрал самый дубовый способ, заменить jne на пару nop'ов. Так что в результате, будет бессмысленное сравнение, затем прыжок куда надо. Делается это просто. Запоминаем нужную последовательность байт: 8a84244a0100003с01, находим её в вашем любимом Hex-редакторе и меняем на что надо. В данном случае 750c на 9090.
Сохраняем и…
Выясням, что мы сломали цифровую подпись файла (ну, кто бы сомневался). Значит её надо убить. Вариантов много, но мы на хабре, поэтому воспользуемся программой design от читателя DnV.
Запускаем… и ничего. Те же проблемы с повреждённой подписью. Откуда он её берёт? Не буду утомлять рассказом про то, как я пытался с этим разобраться, подписывал файл самостоятельно, готов был бросить всё это дело, а оказалось…
(это скриншот из программы Stud_PE).
Заценили шутку от Microsoft? Целостность файла проверяется флагом в самом файле. Тайный смысл этого мне не понять, если только защита от глупых вирусов.
Как я дошёл до этого флага, сам не понимаю, но в общем, снимаем его, сохраняем, и… всё работает!
После этого заменяем оригинальный (не забывая раздать себе права на это действие), и пользуемся продвинутым Таск Менеджером.
Ну и бонусом пишем статью на хабр :) Надеюсь, что вам она была интересна.
Если кто захочет повторить в образовательных целях, то для проверки корректности результата вот вам файл.
Автор: force