Первое, на что я обратил внимание после установки — новая панель задач. А конкретнее — тот факт, что она группирует кнопки по программе, к которой они принадлежат.
Сразу же полез в настройки, чтобы отключить это безобразие, и с удивлением обнаружил, что группировка не отключается. Наиболее близкий к желаемому вариант, Never combine, кнопки все же группирует.
Я думал, что как и мне, многим это не понравится, и был уверен, что спустя неделю-две в интернете всплывет решение этой проблемы. Но я так ничего путного и не нашел, и понял, что придется действовать самому.
Под катом:
- Подробная демонстрация того, как можно самостоятельно подправить принцип работы такого системного процесса, как explorer, под себя, используя отладчик OllyDbg.
- Готовое решение описанной выше проблемы.
Приступаем
Для понимания описанного ниже процесса, желательно иметь базовое знание ассемблера.
Для того, чтобы отучить панель задач от группировки, нам понадобится OllyDbg — бесплатный проприетарный 32-битный отладчик уровня ассемблера для операционных систем Windows, предназначенный для анализа и модификации откомпилированных исполняемых файлов и библиотек, работающих в режиме пользователя (ring-3) © Wikipedia.
Повторить процесс можно на ОС Windows 7 или Windows 8. К сожалению, на данный момент имеется только 32-битная версия OllyDbg, так что если у вас 64-битная ОС, повторить следующие действия у вас не получится (в таком случае можно использовать виртуальную машину).
Инсталляция OllyDbg
OllyDbg — портативная программа, и в инсталляции не нуждается. Создайте папку с правами записи, и перепишите туда файлы с этого архива.
Настройка Microsoft Symbol Server
Microsoft Symbol Server — Майкрософтовский сервер отладочных символов, благодаря которым мы, кроме чистого ассемблера, будем видеть еще и названия функций и переменных. Это очень помогает при анализе кода.
Для этого нужно сделать следующее:
- Скачайте этот архив, и поместите его содержание в папку программы OllyDbg.
Что это за файлы?- symsrv.dll — DLL файл Майкрософта, предназначен для работы с их сервером отладочных символов. Подписан Майкрософтом.
- symsrv.yes — пустой файл. Обозначает, что вы согласны с условиями предоставленных услуг.
- symsrv.ini — исключает все файлы кроме тех, которые начинаются на exp — для нашего explorer.exe. Иначе, если будут качаться все символы, придется очень долго ждать, да и не нужно оно нам для данной демонстрации.
- Включите OllyDbg, откройте настройки (Alt+O), и пометьте опцию Demangle symbolic names. Эта опция декодирует символических имена, делая их более читаемые для нас, людей.
Скриншот - В настройках, откройте страницу Debugging data, и пометьте Allow access to Microsoft Symbol Server. Затем создайте папку для символов, и выберете ее в настройках, как на скриншоте.
Скриншот - Перезапустите OllyDbg.
Присоединение процесса explorer
Как известно, панель задач — часть процесса Windows Explorer. Запускаем OllyDbg, и выбираем File -> Attach…. Затем, выбираем explorer и жмем на Attach.
Attach, с английского — присоединять — то есть мы присоединяем наш отладчик к проводнику для его отладки.
Затем ждем, пока все модули загрузятся. Это может занять несколько минут, и в это время проводник не будет реагировать. После завершения загрузки в строке состояния справа будет написано Paused на желтом фоне — то есть процесс приостановлен. Жмем F9 чтобы возобновить работу процесса.
Внимание, исключения: если процесс приостанавливается, и в строке состояния появляется надпись Exception xxxxxxxx (как на скриншоте ниже), нажмите Shift+F9 чтобы передать исключение по назначению.
Обзор функций проводника
Теперь проводник работает под надзором нашего отладчика, OllyDbg. Если связь с сервером отладочных символов прошла как следует, мы можем взглянуть на функции проводника.
Сначала, откроем модуль процесса explorer в окошке CPU отладчика. Для этого откроем окошко модулей (буква E на голубом фоне), нажмем правой кнопкой на Explorer, и выберем View code in CPU.
Затем, нажмем правой кнопкой на код, и выберем Search for -> Names. Перед нами появится список функций, присутствующих в проводнике. Для более удобной работой со списком, отсортируем его по имени, скопируем и вставим в текст в любимый текстовой редактор.
Итак, нам нужно отключить группировку. Логично начать поиск со слова group. В глаза сразу бросаются два класса: CTaskBtnGroup и CTaskGroup. Вместе у этих двух классов 131 функций — не очень много для беглого просмотра названий.
Мне сложно сказать, можно ли найти нужную нам функцию, всего лишь изучая названия, так как я уже неплохо с многими из них знаком. В любом случае, нужная нам функция — CTaskGroup::DoesWindowMatch, название которой переводится как совпадает ли окошко, и делает она именно это — отвечает, подходит ли окошко к определенной группе.
Просмотр выбранной функции
Мы нашли функцию с интересным названием, теперь давайте посмотрим, чего она из себя представляет. Вернемся в OllyDbg, нажмем на Ctrl+G и перейдем на адрес функции (тот восьмизначный номер в начале строки, в нашем случае 00973629).
P.S. Советую включить подсветку Jumps and calls, благодаря которой четко видны вызовы функций и условные/безусловные прыжки.
Итак, вот наша функция:
Столбцы, слева на право: адрес, байты, команды (ассемблер), комментарии.
Голубым цветом помечены функции, желтым — переходы. На них мы и сосредоточимся.
Первым делом, вызывается какая-то функция, и в зависимости от результата происходит переход. Здесь я на них задерживаться не буду, замечу только, что к нашей задачи они дело не имеют.
Дальше мы видим три перехода. Первый перепрыгивает через второго и третьего. Второй и третий переходят куда-то подальше — давайте посмотрим, куда…
Первый
В глаза сразу бросается WinAPI функция ILIsEqual, которая сравнивает две структуры. После некоторого анализа становится ясно, что сравниваемые структуры связаны с группами. Наша цель — отменить любую группировку, так что пропатчим код так, чтобы проводник думал, что структуры не ровны.
Для этого, пропишем безусловный прыжок JMP, как на скриншоте сверху.
Второй
Как и в первом разе, сразу видим WinAPI функцию для сравнения, на этот раз текста — CompareStringOrdinal. Опять же, после экспериментирования становится ясно, что и это сравнение связано с группами. На этот раз сравниваются так называемые Application ID — идентификатор аппликации, по которым панель задач группирует кнопки.
Опять же, ставим безусловный прыжок, заставляя проводника думать, что все идентификаторы разные.
Пробуем
Большое преимущество отладчика от, например, простого дисассемблера в том, что изменения сразу вступают в силу, так как модифицируем мы память запущенного процесса напрямую. По этой же причине нужно быть очень осторожным, так как ошибка может привести к краху процесса.
Попробуем открыть несколько копий блокнота, и увидим, что они не группируются:
Получилось 🙂
Так как мы изменили код только в памяти запущенного процесса, наша модификация продержится только до завершения процесса.
Бонус — декомпилированная версия функции CTaskGroup::DoesWindowMatch
Несмотря на то, что оригинальный язык данного кода — C++, ниже превидена самописная декомпиляция на чистом C.
/* return: S_OK if there's a match, E_FAIL otherwise *pnMatch: 1: AppId matches, ITEMIDLIST is missing 2: AppId matches, ITEMIDLIST doesn't match 3: ITEMIDLIST matches 4: hWnd already exists (pTaskItem recieves the CTaskItem) */ HRESULT CTaskGroup_DoesWindowMatch(void /*CTaskGroup*/ *this, /*IN*/ HWND hCompareWnd, /*IN*/ ITEMIDLIST *pCompareItemIdList, /*IN*/ WCHAR *pCompareAppId, /*OUT*/ int *pnMatch, /*OUT*/ void /*CTaskItem*/ **pTaskItem) { void /*CTaskItem*/ *CompareWndTaskItem; int nMatch; HRESULT hr; nMatch = 0; hr = this->lpVtbl->GetItemFromWindow(this, hCompareWnd, &CompareWndTaskItem); if(SUCCEEDED(hr)) // if an item for this window already exists { if(pTaskItem) { *pTaskItem = NULL; IUnknown_Set(pTaskItem, CompareWndTaskItem); } nMatch = 4; CompareWndTaskItem->lpVtbl->Release(CompareWndTaskItem); } else { if(!(this->SomeFlags & 0x80000000)) { if(pCompareItemIdList && this->pItemIdList && ILIsEqual(pCompareItemIdList, this->pItemIdList) != 0) { nMatch = 3; hr = S_OK; } else if(pCompareAppId && CompareStringOrdinal(this->pAppId, -1, pCompareAppId, -1, TRUE) == CSTR_EQUAL) { hr = S_OK; if(pCompareItemIdList && this->pItemIdList) nMatch = 2; else nMatch = 1; } } } *pnMatch = nMatch; return hr; }
Готовое решение
Программа 7+ Taskbar Tweaker, автор которой являюсь я, умеет отключать группировку как глобально, так и выборочно по Application ID. Кроме этого, имеются в наличие еще несколько интересных настроек панели задач.
Заключение
Иногда я открываю статью на хабре, которая кажется мне интересной, но после того как начинаю читать, понимаю что она не такая уж и интересная (или не очень понятная). В таких случаях я часто сразу перелистываю вниз к заключению/выводам.
Если вы находитесь здесь по этой же причине, расскажу вкратце о чем шла речь:
Я взял отладчик, и присоединил его к проводнику. Затем я нашел нужную функцию, и изменил ее так, чтобы проводник думал, что любое созданное окошко не подходит ни к одной из существующих групп. В связи с этим изменением, проводник перестал группировать кнопки на панели задач.
ссылка на оригинал статьи http://habrahabr.ru/post/174593/
Добавить комментарий