Время вспять…

    Вот и отгремело первое апреля. Кто-то в этот день нюхал свои девайсы в новом сервисе Google Nose, кто-то играл в «Поле чудес», а кто-то, позабыв о роковой дате, просто угрюмо отряхивал спину от мела…

    Я же, воодушевлённый статьёй про скрытые возможности кастомизации процесса explorer.exe, тоже решил сделать что-нибудь забавное.
    Пусть сегодня моя секундная стрелка часов в Windows идёт в обратную сторону! Не самый, конечно, полезный в хозяйстве мод, но в академических и рекреационных целях вполне сгодится :)
    Часовую и минутную стрелки я оставил в правильном направлении. Иногда всё же приходится полгядывать на часы в трее — пусть они показывают время с точностью хотя бы до минуты...

    Подготовка


    Последовательность действий представляется примерно следующей:
    1. Поисследовать explorer.exe и понять каким образом он считает время
    2. Как-то что-то поменять в логике, чтобы часы шли обратно

    Немного поменять логику какого-нибудь 32-битного usermode-процесса не представляет сложностей: давно есть полюбившийся многим отладчик OllyDbg, туториалов по которому предостаточно даже на русском языке. Поэтому, для придания изюминки было решено реализовывать задачу на моей 64-битной Windows 7 — давно хотел узнать каково́ там живётся процессам с удвоенной разрядностью…

    В 64-битном мире на уровне дизассемблера пока, к сожалению, живется не очень сладко: ни тебе комфортного Olly для отладки, ни тебе удобнейшего Detours, за который просят выложить ни много ни мало $9,999.95 (ну, спасибо, что не $10k — маркетологи знают как сделать цену привлекательнее). Даже старые 32-битные инжекторы нельзя использовать для внедрения 64-битных dll. Видимо, моему поисковику по умолчанию придётся неслабо поработать…

    Да простят меня любители статического анализа, с IDA Pro у меня отношения не сложились, так что выбора у меня почти не осталось — старичок WinDbg дождался своего часа.
    В вопросах работы с WinDbg ценнейшим источником информации является ресурс windbg.info

    Исследуем explorer.exe


    Подключаемся к процессу и ищем что-нибудь связанное со словом "clock":



    Присмотревшись получше к выданному списку функций, можно заметить неприметную функцию explorer!CClockCtl::_RecalcCurTime. Неужели первый выстрел сразу в цель? Посмотрим что у неё внутри:



    Всё верно, сразу за прологом функции видим вызов GetLocalTime, которая, как известно, возвращает местное время и дату. Если мы сможем влиять на возвращаемый результат этой функции, то сможем также и изменять направление секундной стрелки — осталось только поставить хук на эту функцию.

    Чтобы реализовать задуманное, нам нужно как-то попасть в адресное пространство процесса explorer.exe. И в этом как нельзя лучше нам поможет утилита командной строки CLI DLL-Injector. Она мало того что поддерживает 32 и 64 бита, так еще и умеет внедрять dll двумя способами: через инжект LoadLibrary, и с помощью прямой записи кода через WriteProcessMemory с последующим переносом reloc'ов.

    Непосредственно для установки хуков внутри процесса explorer.exe воспользуемся простой и надёжной библиотекой MinHook.
    Стоит обратить внимание, что за кажущейся простотой библиотеки, внутри скрывается очень продуманная логика, которая работает даже в достаточно сложных случаях. Так, библиотека Powerful x86/x64 Mini Hook-Engine, которую я пытался использовать поначалу, приводила к Access Violation всвязи с тем, что первая же инструкция функции GetLocalTime — это относительный переход JMP. В этом случае задача усложняется необходимостью перерасчёта смещения.

    Реализация


    С инструментами определились. Теперь осталось написать dll, которая при DLL_PROCESS_ATTACH будет ставить хук на функцию GetLocalTime:

    #include <windows.h>
    #include "MinHook.h"
    
    // Статически линкуемся с libMinHook.dll
    #pragma comment(lib, "libMinHook.x64.lib")
    
    // Указатель на оригинальный GetLocalTime
    static void (WINAPI *GetLocalTime_)(LPSYSTEMTIME lpSystemTime);
    
    void WINAPI MyGetLocalTime(LPSYSTEMTIME lpSystemTime)
    {
      // Вызываем оригинальный GetLocalTime
      GetLocalTime_(lpSystemTime);
    
      // Инвертируем количество секунд: 59 -> 0, 0 -> 59
      lpSystemTime->wSecond = 59 - lpSystemTime->wSecond;
    }
    
    BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
    {
      switch (dwReason) {
      case DLL_PROCESS_ATTACH:
        // Не повторяйте этого в продакшене!
        // Во избежание неприятных дедлоков, внутри DllMain() нужно оставлять только самый необходимый функционал
    
        // Инициализируем библиотеку libMinHook
        if (MH_Initialize() != MH_OK) {
          return FALSE;
        }
    
        // Создаём хук (пока что он будет в выключенном состоянии)
        if (MH_CreateHook(&GetLocalTime, &MyGetLocalTime, reinterpret_cast<void**>(&GetLocalTime_)) != MH_OK) {
          return FALSE;
        }
    
        // Активизируем хук
        if (MH_EnableHook(&GetLocalTime) != MH_OK) {
          return FALSE;
        }
      }
    
      return TRUE;
    }
    

    Используем полученную dll


    Теперь можно внедрять dll. Запускаем в консоли инжектор следующей командой:



    В ключе --lib важно передавать полный путь к dll, подробнее почему так сделано см. комментарий

    Всё, можно наслаждаться результатами! (осторожно, гипнотизирует)

    Исходники (проекты под VS2010) и бинарники для самостоятельного ковыряния можно посмотреть здесь.
    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 29

      +31
      Торт!
        +2
        Над своими коллегами, что ли, прикольнуться?
        Спасибо, загипнотизировало :)
          +38
          Самый годный первоапрельский пост за сегодня!
          • UFO just landed and posted this here
              +82
              Пока не лег, еще не завтра.
                +2
                У меня 1 апреля только началось :)
                • UFO just landed and posted this here
              0
              Прикольно)) реальная шутка будет в офисе, если какой-нибудь менеджер откроет часы (возможно все), а стрелка в обратку ))
                +8
                Думаю, он даже не заметит.
                +2
                Интереснее было бы найти процедуру вычисления координат для отрисовки стрелок и через неё поменять направление.
                  +18
                  Давным давно, еще когда учился в универе, делал подобную штуку. Правда, там все было намного топорнее — программка просто 1 раз в секунду переводила системное время на 2 секунды назад. Часы реально шли в обратную сторону :)
                    0
                    Странно (Win7 x64). Идеи?
                    Открыл в студии, всё собралось нормально а вот внедряться не хочет.

                    D:\down\4\reverse-clock>newloaderv4.1x64.exe --lib reverse-clock-dll\x64\Release\reverse-clock.dll --procname explorer.exe
                    Loader v4.1 by Wadim E.
                    Project Home: injector.googlecode.com
                    Copyright (C) 2011 Wadim E.
                    Email: wdmegrv@gmail.com
                    
                    Error: [@InjectLibraryW] Unknown Error (LoadLibraryW).
                    Error: [@InjectEjectToProcessNameA] Injection failed. (PID: 870) [LastError: 6]
                    
                      0
                      В ключе --lib важно писать полный путь к dll — скорее всего ошибка в этом.
                      Связано это со способом внедрения библиотеки: сначала в процесс explorer.exe пишется маленький кусочек кода, который делает LoadLibrary() для указанной --lib. Так как процесс explorer.exe ничего не знает о путях относительно процесса newloaderv4.1x64.exe, то и выходит ошибка.
                      Обновил топик.
                        0
                        да, с полным путём заработало.
                        Спасибо
                          0
                          А ключ --launch работает хорошо? Я пытаюсь тут одну очень нехорошую штуку провернуть, но для этого нужно подделать номер билда операционки, а GetVersionExW запускается со старта — в таком случае лесть взапущенный процесс смысла нет.
                            0
                            Про --launch ничего не скажу — не проверял…
                            Если вам нужно при старте поставить хуки, то можно к примеру захучить CreateProcessA у запускающего процесса, тем самым получив контроль над запуском процесса.
                        0
                        Одна знакомая левша-ардуинщица такое постоянно носит на правой руке:))
                          +7
                            0
                            да, неплохой сценарий, правда яшяа JFIF для меня бы всю контору спалил
                              0
                              Реально, если додумать, IT-фильм отличный вышел бы!..
                              0
                              Как думаете, файл можно расшифровать?

                              Скрытый текст

                              Только не вручную :)
                              +8
                              Почему бы не писать «Google Nose» или «Гугл Нос»? А то «Google Hoc» я сначала читал как «Гугл Хок».
                                0
                                Официальное название (:
                                Всё равно с сегодняшнего дня бета-тестирование прикрыли)
                                  0
                                  Эх, вечно они самые хорошие сервисы закрывают :-(
                                +3
                                Баг)
                                image
                                  +4
                                  Нашим инженерам известно о наличии указанной проблемы.
                                  В качестве временного решения предлагается использовать следующую команду всякий раз при открытии окна настроек даты и времени:
                                  –10
                                  Такую энергию на полезные вещи бы направлять.
                                    0
                                    Лет 10 назад в школе такую штуку делали, на VisualBasic, тупо по таймеру меняло системное время раз в секунду, без хуков. Правда, минус в том, что оно таки менялось, а в сабже только иллюзия смены, что идеалогически вернее.
                                      +1
                                      В молодости пользовался SoftIce`ом для подобных задач. Но он приказал долго жить. Сейчас существует Syser Kernel Debugger, который поддерживает набор команд SoftIce`а. Поигрался с ним в свое время — вроде бы довольно неплохая альтернатива (хотя и багов много было). На сколько он популярен сейчас?

                                      Only users with full accounts can post comments. Log in, please.