«Прокачиваем» notepad.exe

    image

    Какая ассоциация связана у Вас с клавишей F5? Обновление страницы в браузере? Копирование файла из одной директории в другую? Запуск приложения из Visual Studio? А вот авторы notepad.exe подошли к этому вопросу довольно оригинально — по нажатию клавиши F5 происходит добавление текущей даты и времени в место, куда в этот момент указывает курсор. Всё было бы круто, если бы в notepad.exe была такая популярная и вполне естественная для большинства текстовых редакторов фича, как перечитывание содержимого текущего файла, которая, казалось бы, и должна быть назначена на F5 / Ctrl-R или ещё какой-нибудь общепринятый хоткей.

    Мы можем ждать, пока её реализуют Microsoft, выбрать другой текстовый редактор (ведь это не единственное ограничение по функционалу стандартного notepad.exe) или… Взять в руки дизассемблер, отладчик и редактор PE-файлов.

    Как протекал процесс, и что из этого вышло, читайте под катом (осторожно, много скриншотов). Перед прочтением данной статьи также настоятельно рекомендую ознакомиться с предыдущими.

    Чтобы не иметь дело с теми же неудобствами, с которыми мы столкнулись в предыдущей статье, давайте для начала отключим использование ASLR. Согласно вики, ASLR (Address space layout randomization) — это технология, при использовании которой случайным образом изменяется расположение в адресном пространстве процесса важных структур, а именно: образа исполняемого файла, подгружаемых библиотек, кучи и стека. Именно из-за неё в прошлый раз перезапуск приложения и приводил к изменению уже найденных нами ранее адресов. Если Вы используете Windows XP или более старую ОС, то можете с лёгкостью пропустить то, о чём будет рассказано в нескольких следующих абзацах, ведь ASLR на тот момент ещё не было.

    Отключить использование ASLR можно как глобально (для этого необходимо добавить / отредактировать значение опции «MoveImages», хранящейся в реестре по адресу «HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management», чтобы сделать её равной нулю), так и локально, т.е. для конкретного исполняемого файла. Последний вариант выглядит более привлекательным, особенно если речь идёт не о виртуальной машине, а о реальной системе, так что давайте остановимся на нём.

    Копируем notepad.exe в любую отличную от "%WINDIR%\System32" директорию, скачиваем, разархивируем и запускаем PE Tools, нажимаем Alt-1 и выбираем скопированный ранее notepad.exe:

    image

    Нажимаем на кнопку «Optional Header» и смотрим на поле DLL Flags, которое в нашем случае равно 0x8140:

    image

    Значение в этом поле является результатом выполнения операции битового «OR» для констант, перечисленных в официальной документации на MSDN. Несложно заметить, что наш бинарник обладает следующими характеристиками:

    IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
    0x8000
    The image is terminal server aware

    IMAGE_DLLCHARACTERISTICS_NX_COMPAT
    0x0100
    The image is compatible with data execution prevention (DEP)

    IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
    0x0040
    The DLL can be relocated at load time

    Обратили внимание на последнее значение? Что ж, это именно то, что нас интересует. Меняем 0x8140 на 0x8100, нажимаем «Ok» в обоих окнах и приступаем к отладке.

    На какие этапы можно условно разделить наш патчинг notepad.exe?

    • Поиск адреса, по которому хранится путь до текущего файла
    • Поиск процедуры считывания содержимого файла
    • Поиск кода, отвечающего за обработку нажатия клавиши F5
    • Собственно, написание самого патча

    Открываем notepad.exe в OllyDbg и приступаем к первому этапу.

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

    Надеясь, что файл при сохранении каждый раз открывается заново, ставим бряки на вызовы WinAPI-функции CreateFileW:

    image

    Нажимаем Ctrl-S, выбираем имя файла (в моём случае это «C:\helper.txt») и останавливаемся на следующем месте:

    image

    Посмотрим, откуда и с какими аргументами нас позвали:

    image

    Если посмотреть, на что указывает адрес, переданный в качестве второго аргумента (right-click по строке с данным аргументом -> Follow address in stack), то мы увидим как раз наш путь:

    image

    Давайте посмотрим на код, находящийся перед вызовом исследуемой нами процедуры, чтобы понять, откуда и как именно к нам попал этот адрес:

    image

    Как Вы видите, адрес, по которому хранится путь до файла, содержится в EBP-8. Давайте снова нажмём Ctrl-S и посмотрим, куда мы попадём на этот раз (ведь теперь программа уже знает путь до файла, что может поменять ход работы приложения):

    image

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

    image

    На этот раз адрес, по которому содержится путь до файла, хранится в регистре EBX. С момента начала текущего case-блока (обратите внимание на комментарий несколькими инструкциями раньше выделенного места) значение данного регистра не изменяется, что означает, что искать оригинальный адрес надо где-то раньше. Смотрим, какие инструкции ссылаются на начало данного case-блока (left-click по адресу 0x01004D5D -> Ctrl-R):

    image

    Раз такое обращение всего одно, прыгаем на него по нажатию клавиши Enter и сразу же видим, откуда в EBX появляется данный адрес:

    image

    Итак, мы поняли, что по адресу 0x0100CAE0 хранится путь до текущего файла. Что дальше? А дальше мы должны найти процедуру, ответственную за считывание содержимого файла.

    Очевидно, что она также будет вызывать CreateFileW (вместо этого мы могли бы перехватить вызов функции GetOpenFileName, но её нет в списке межмодульных вызовов — видимо, вместо неё используется Common Item Dialog API, которое рекомендуется на MSDN). Нажимаем Ctrl-O, выбираем любой файл (я выбрал тот же самый) и, не успев сделать двойной клик мышью, оказываемся на бряке по адресу 0x01006E8C:

    image

    Проделываем то же самое несколько раз, прежде чем убрать данный бряк и надеяться на остальные. И правда, после того, как был убран бряк по указанному ранее адресу, мы всё же смогли сделать двойной клик по интересующему нас файлу, в результате чего сработала точка останова уже совершенно в другом месте:

    image

    Итак, наша задача — выяснить, каким образом и какую именно процедуру необходимо вызвать, чтобы успешно перечитать интересующий нас файл. Ставим бряк на адрес, с которого нас позвали

    image

    , нажимаем F9, и… Он тут же срабатывает! Ничего, снова нажимаем F9, пытаемся передать фокус окну notepad.exe и видим, что бряк снова срабатывает. Да что ж такое! Давайте посмотрим на начало процедуры, которую вызывает данный CALL:

    image

    Обратите внимание на единственный комментарий — судя по кол-ву обрабатываемых значений и тому, что мы наблюдаем на практике, данная процедура служит для реакции на любое выполняемое пользователем действие, будь то передача окну notepad.exe фокуса или открытие файла. Видимо, после нажатия Ctrl-O программа не выполняет никакого CALL'а, а лишь переходит на соответствующий case-блок при помощи операции условного перехода. Давайте уберём данный бряк, ещё раз попытаемся открыть файл и найдём ближайшую к бряку, стоящему на месте вызова CreateFileW, инструкцию, к которой есть обращения в коде. Ею оказалась инструкция по адресу 0x01004DF5:

    image

    Ставим бряки на оба обращения, проделываем те же самые действия и оказываемся тут:

    image

    Ставим бряк на начало данного case'а, снова открываем тот же самый файл и пытаемся понять, что тут происходит:

    ; Зануляем значение в регистре EDI
    01003ECC   > \33FF          XOR EDI,EDI                              ;  Case 2 of switch 01001824
    ; Вызываем процедуру проверки изменений в текущем файле
    ; Если они были, отобразится диалоговое окно с предложением сохранить изменения в файл
    01003ECE   .  57            PUSH EDI
    01003ECF   .  E8 90D7FFFF   CALL notepad.01001664
    ; Проверяем возвращаемое значение
    ; EAX == 1, если изменений не было / пользователь нажал клавишу Save / Don't Save, EAX == 0, если была нажата кнопка Cancel
    01003ED4   .  85C0          TEST EAX,EAX
    ; Если нажали Cancel, то дальнейшее нас уже не интересует, переходим в другой case
    01003ED6   .^ 0F84 8ED9FFFF JE notepad.0100186A
    ; Перемещаем нечто с адреса 0x100C00C в EAX и затем в EBP-10
    01003EDC   .  A1 0CC00001   MOV EAX,DWORD PTR DS:[100C00C]
    01003EE1   .  8945 F0       MOV DWORD PTR SS:[EBP-10],EAX
    ; Вызываем процедуру отображения диалогового окна с просьбой выбрать файл
    01003EE4   .  8D45 F8       LEA EAX,DWORD PTR SS:[EBP-8]
    01003EE7   .  50            PUSH EAX                                 ; /Arg2
    01003EE8   .  FF75 F4       PUSH DWORD PTR SS:[EBP-C]                ; |Arg1
    01003EEB   .  E8 31000000   CALL notepad.01003F21                    ; \notepad.01003F21
    ; В результате вызова данной процедуры в EBP-8 будет храниться путь до открываемого файла
    ; EAX == 0 в случае успеха и 0x800704C7 в случае нажаия кнопки Cancel
    01003EF0   .  8BF0          MOV ESI,EAX
    01003EF2   .  3BF7          CMP ESI,EDI
    ; Один из прыжков на интересующую нас процедуру
    01003EF4   .  0F8D FB0E0000 JGE notepad.01004DF5
    01003EFA   .  81FE C7040780 CMP ESI,800704C7
    01003F00   .  0F85 DC0E0000 JNZ notepad.01004DE2
    01003F06   >  3BF7          CMP ESI,EDI
    01003F08   .  0F8D E70E0000 JGE notepad.01004DF5
    01003F0E   >  8B45 F0       MOV EAX,DWORD PTR SS:[EBP-10]
    01003F11   .  A3 0CC00001   MOV DWORD PTR DS:[100C00C],EAX
    01003F16   .  56            PUSH ESI
    01003F17   .^ E9 A2FCFFFF   JMP notepad.01003BBE
    

    Теперь давайте посмотрим, какие регистры и адреса использует код по адресу 0x01004DF5, чтобы понять, какое «окружение» необходимо для его корректной работы:

    image

    Разумеется, данный код обращается к EBP-8, по которому, как Вы помните, хранится путь до открываемого файла. Помимо этого, ему также важно значение регистра EDI, который используется в качестве аргументов для параметров hTemplateFile и pSecurity. Первое мы можем достать из адреса 0x0100CAE0, а в обозначенные параметры можно просто передать ноль.

    Теперь давайте найдём код, отвечающий за обработку нажатия клавиши F5. Для этого предлагаю поставить бряк на вызовы функций, отвечающих за получение текущего времени. Наиболее популярные из них — GetSystemTime и GetLocalTime. Первой нет в списке межмодульных вызовов, а вот вторая вызывается сразу из двух мест:

    image

    Ставим бряки, нажимаем F5 и оказываемся тут:

    image

    Прыгаем на место вызова текущей процедуры и попадаем практически в самое начало ещё одного case-блока, который, очевидно, и отвечает за обработку нажатия F5:

    image

    Отлично. Ищем место для нашего code cave'а и пишем (разумеется, адреса могут отличаться):

    0100BEB3      33FF          XOR EDI,EDI
    0100BEB5      C745 F8 E0CA0>MOV DWORD PTR SS:[EBP-8],notepad.0100CAE0    ;  UNICODE "C:\helper.txt"
    0100BEBC      A1 0CC00001   MOV EAX,DWORD PTR DS:[100C00C]
    0100BEC1      8945 F0       MOV DWORD PTR SS:[EBP-10],EAX
    0100BEC4    ^ E9 2C8FFFFF   JMP notepad.01004DF5
    

    Вставляем по адресу 0x0100447B прыжок на наш code cave:

    image

    Нажимаем F9, снова жмём F5 и наблюдаем следующую картину:

    image

    Как видите, мы упали где-то в недрах функции CoTaskMemFree. Обратите внимание на аргумент, переданный этой функции — да-да, это адрес нашей строки с путём до файла. Значит, память под неё необходимо выделять при помощи CoTaskMemAlloc. В этом нам может помочь функция SHStrDup, которая создаёт дупликат переданной ей строки, выделив память под неё при помощи CoTaskMemAlloc.

    Перезапускаем notepad.exe и ищем адрес функции SHStrDupW в IAT. Для этого смотрим на вызов любой другой WinAPI-функции в модуле:

    image

    Следовательно, адрес функции GetDlgItemTextW в IAT — 0x010012A4. Прыгаем на него и ищем нашу SHStrDupW:

    image

    Получается, её вызов можно оформить в виде инструкции CALL DWORD PTR DS:[010013B4]. Тогда пишем следующий код (проверка на наличие ошибок опущена):

    0100BFA5   .  33FF             XOR EDI,EDI
    0100BFA7   .  8D45 F8          LEA EAX,DWORD PTR SS:[EBP-8]
    0100BFAA   .  50               PUSH EAX                                          ; /pTarget
    0100BFAB   .  68 E0CA0001      PUSH notepad.0100CAE0                             ; |Source = "C:\helper.txt"
    0100BFB0   .  FF15 B4130001    CALL DWORD PTR DS:[<&SHLWAPI.SHStrDupW>]          ; \SHStrDupW
    0100BFB6   .  A1 0CC00001      MOV EAX,DWORD PTR DS:[100C00C]
    0100BFBB   .  8945 F0          MOV DWORD PTR SS:[EBP-10],EAX
    0100BFBE   .^ E9 328EFFFF      JMP notepad.01004DF5
    

    Открываем наш файл «C:\helper.txt», убеждаемся, что он пустой, редактируем и сохраняем его в другой копии notepad.exe, нажимаем F5 в отлаживаемой нами версии, и… Файл обновляется!

    Давайте сохраним наши изменения в исполняемый файл. Делаем right-click по окну CPU -> Copy to executable -> All modifications -> Copy all и видим:

    image

    Получается, что мы вылезли за физические границы исполняемого файла. Давайте взглянем на границы секций в PE Tools (кнопка «Sections»)

    image

    и поместим наш code cave в какое-нибудь другое место. Для получения верхней «границы» области для «безболезненного» патча мы должны сложить Virtual Offset секции .text, куда мы собираемся положить наш патч, её Raw Size и Image Base, т.е. Virtual Offset (0x00001000) + Raw Size (0x0000A800) + Image Base (0x01000000) = 0x0100B800. Поместим его, например, по адресу 0x0100B6CF и попытаемся сохранить изменения ещё раз (right-click по окну CPU -> Copy to executable -> All modifications -> Copy all -> right-click на появившемся окне -> Save file).

    Проверяем получившийся исполняемый файл на работоспособность и убеждаемся, что всё ведёт себя так, как и ожидается.

    Послесловие


    Цель данной статьи — в очередной раз продемонстрировать возможность добавления собственного функционала в существующие программы, не имея при этом на руках исходных кодов. А теперь возвращайтесь к своим vim'ам / emacs'ам / Notepad++ / etc, но помните — если Вы встретите баг или обратите внимание на отсутствие какого-либо функционала в редакторе с закрытым кодом, теперь Вы знаете, что надо делать.

    Спасибо за внимание, и снова надеюсь, что статья оказалась кому-нибудь полезной.
    Share post

    Comments 39

      0
      Могу порекомендовать всем, кто не знает: есть такая штука как Notepad2, которым можно заменить стандартный и получить ряд плюшек включая и рассмотренную перезагрузку файла. А за статью спасибо!
        +6
        Мне показалось, автор другую цель преследовал. А за наводку на программу спасибо.
          +1
          есть еще AkelPad
          0
          Есть ещё Notepad 2e с ещё большим количеством плюшек типа подсветки слов.
          –23
          >Какая ассоциация связана у Вас с клавишей F5?

          Да хрен его знает… По Alt+F5 запускается xsel, передающий выделение в онлайн-переводчик, по Shift+F5 — компиляция проекта, если в IDE. А вот так чтобы голая F5 — не припомню :)
            +14
            Спасибо за эту ценную информацию.
            +3
            Как мне нравятся все эти статьи с olly — «щелкаем и видим», «очевидно», «оно выполняется»
            где внятно прочитать про коды ассемблера и отладчик — для самых маленьких?
              +1
              Начните отсюда: habrahabr.ru/post/131971 там с десяток книг упомянуто, какая-нибудь да подойдёт.
                +1
                А Вы остальные статьи, которые я тут публиковал, читали? Возможно, было бы больше понимания того, что происходит конкретно в этой
                  +1
                  Однозначно рекомендую goo.gl/8obaoR
                  Отличный курс статей!
                +3
                Что-то вспомнилось:

                1. Открыть notepad.exe
                2. Написать .LOG и нажать enter
                3. Сохранить и закрыть.
                4. Открыть сохранённый файл.
                  0
                  извините, но любопытство замучало, а на винды с блокнотом нет. Поверхностный поиск тоже не помог… А что будет то? :-)
                    +1
                    Можно почитать, например, тут
                      0
                      Во время открытия такого файла, добавится строка с датой открытия =)
                      Ну у меня так.
                        0
                        И ещё курсор встает в конец файла.
                    0
                    Ехх… если бы ещё избавить notepad.exe ещё от таких багов, чтобы им бы можно было нормально пользоваться:
                    — При сохранении файла иногда курсор оказывается не в том месте где был
                    — Постоянно сбивается/сохраняется перенос строк ломая весь текст
                    — Не может открывать большие файлы
                    Хотя это скорее пожелания в сторону Microsoft
                      +3
                      Легче альтернативный редактор поставить. Хотя конечно исправить базовые глюки не помешало бы.
                      В связи с новым трендом, думаю следующий notepad будет написан на HTML5.
                        0
                        На самом деле, во многих случаях открывать большие текстовые файлы не следует ни в одном текстовом редакторе — лучше «вытаскивать» интересующие места при помощи того же grep'а (можно с контекстом)
                          +1
                          При этом на ZX Spectrum в далёкие времена в iS-DOS был текстовый редактор, который мог редактировать файлы в сотни раз больше оперативной памяти, просто загружая нужный кусок в память.
                          А сейчас, имея i7 и 16gb памяти на борту, нечем даже открыть обычный sql dump на 3gb, всё что угодно жёстко повисает. Скатились…
                            +4
                            Far
                              0
                              FAR, при открытии на редактирование (F4), кэширует весь файл в памяти, к сожалению.
                                0
                                Это да, только просмотр, а less (минимальный пак команд принёс с собой в win) аналогично кэширует?
                                  0
                                  WinHex, но для бинарников. 3 гига текста я представить не в состоянии :)
                                    0
                                    Просмотр я и по f3 могу в Total Commander сделать хоть терабайта.
                                  0
                                  UltraEdit
                                0
                                Перенос строк сбивается не просто так. Каждый раз как вы нажимаете «сохранить», длины строк фиксируются по ширине открытого окна — в каждой строке будет 2 перевода строки. Если после этого скопипастить текст куда-нибудь, он будет нарезан на строки одинаковой длины. Чтобы восстановить автопереносы, надо включить/выключить перенос строк.
                                  0
                                  Не уверен что это у всех. При нажатии ctrl+backspace появляется квадратик вместо удаления последнего слова.
                                    0
                                    Ну еще тогда можно пожелать, чтоб там была подсветка синтаксиса, поддержка проектов, плагины, смена кодировки и line-endings, и т.п. Но кто тогда будет покупать VS?:)
                                      +1
                                      Статья об исправлении этого бага: habrahabr.ru/post/264081
                                      0
                                      Хардкор!

                                      Чтобы не писать код по одной инструкции, могу посоветовать плагин multiasm. Автор кстати с Хабра, вроде.
                                      0
                                      www.wasm.ru/wault/article/show/addfunc
                                      Статья по добавлению калькулятора функций в стандартный блокнот
                                        0
                                        Читая такие статьи понимаешь, какой же чудесный, этот наш мир открытого программного обеспечения.
                                          0
                                          Цель данной статьи — в очередной раз продемонстрировать возможность добавления собственного функционала модификации существующих программ, не имея при этом на руках исходных кодов.
                                          Эти статьи подтолкнули меня несколько лет назад наконец сделать несколько небольших патчей для Windows, и опубликовать пару статей с описанием процесса их создания.

                                          Но так и не написал их (статьи), и вряд ли уже смогу. Поэтому я взял все, что у меня есть и поместил в архив. В надежде, что один из читающих эти строки reverse engineer напишет по ним статьи.

                                          Всего два патча (две статьи):



                                          • Первый патч: раньше, в Windows XP я настраивал Explorer на отображение файлов в виде {иконок 32x32, подпись снизу, автовыравнивание с возможностью менять файлы местами}. Начиная с Vista поведение Explorer по умолчанию изменилось:

                                            1. Нельзя одновременно использовать размер иконок 32x32 и подпись снизу. Если выбрать размер 32x32, то подпись будет справа. Если выбрать размер 33x33, то подпись окажется снизу, но иконки будут размыты (особенно видно на старых иконках: «reg» — 32x32 масштабируется до 33x33).
                                            2. При включенном автовыравнивании — нельзя менять файлы местами.

                                            Вторую проблему я решил практически сразу (для ее решения нужно внести небольшие изменения в реестр).

                                            А первую проблему я долгое время не решал — так и жил с размытыми иконками 33x33. И однажды нашел в сети тему на форуме, в котором люди пытались решить эту же проблему. Но решали при помощи ужасного (лагающего и повышающего нагрузку на CPU) «костыля» (скрипта для AutoHotkey).

                                            Именно в этот момент я и решил наконец сделать патч.

                                            И по написании статьи я хотел оповестить всех, кто был бы рад этому патчу (например sumanai и сюда).
                                          • Второй патч: мне очень нравится четкий однопиксельный шрифт текста. Нравится из-за того, что можно быстро навести фокус (глаз) на текст + слова более разборчивы + меньше утомляешься при чтении текста (глаза не «устают», не краснеют), по сравнению со сглаженным (субпиксельно-размытым) текстом.

                                            Я видел как люди, которые сами используют/восхищены ClearType, при встрече человека, который отключает ClearType — советуют...
                                            • «Просто попробуй настроить ClearType (гамма/смещение...)» — пробовал, размытый текст так и остается размытым (что логично).
                                            • «У тебя плохой монитор, выкинь и купи хороший» — если профессиональный NEC MultiSync/SpectraView LCD2090UXi (шаг пикселей 0.255 мм), за котором я проработал продолжительное время (до этого был 15″ NEC, но с большим пикселем 0.31 мм, и TN матрицей), считается «плохим монитором», то я даже не знаю какой монитор тогда будет хорошим. Возможно от Eizo?..

                                              Note: вообще в то время я считал лучшими дисплеями NEC 2490/2690WUXi из-за «A-TW» поляризатора.


                                            Причина, из-за которой мы хорошо замечаем цветные «каймы» при включении ClearType
                                            Note: все нижеописанное смогут увидеть только те, кто отключает ClearType, и продолжительное время использует хинтованный/однопиксельный (или растровый) шрифт в качестве основного.

                                            Эксперимент:

                                            Note: у меня был планшетный ПК с относительно крупным шагом пикселей (размером пикселя) 0.20-0.24 (примерно) — именно на нем я впервые заметил это.

                                            1. откройте какой-нибудь текст;
                                              Текст (ClearType отключен):
                                            2. не меняя расстояние между глазами и экраном — поверните экран на 180°;
                                            3. посмотрите опять на текст (с прежнего расстояния), появилась ли цветная «кайма»?

                                            Note: можно попробовать с поворотом на 90°.

                                            А теперь включите ClearType и повторите шаги. Исчезла ли цветная «кайма» на 4-м шаге?

                                            Почему так происходит?
                                            Ответ в расположении субпикселей (на экране), пост-обработке (в зрительной коре головного мозга), и смещении границ линии между субпикселями (при включении ClearType).

                                            Фото субпикселей:


                                            Попросту говоря нейросеть натренировалась преобразовывать (усреднять) последовательность субпикселей (ClearType отключен, 0°):

                                            RGBrgbRGBRGB|rgb|RGB → белый | черный | белый

                                            Note: R — включен (светит); r — выключен (не светит).

                                            P.S. но даже при повороте на 180° — ClearType мне не нравится — «кайма» исчезла, но текст по-прежнему выглядит размытым.

                                            И еще несколько тестов:

                                            1


                                            Какого цвета граница слева (при переходе от белого к черному)?
                                            Какого цвета правая граница (при переходе от черного к белому)?

                                            А теперь откройте эту картинку в графическом редакторе, и убедитесь, что она черно-белая в градациях серого (в ней нет цвета).

                                            2


                                            Какой из этих градиентов имеет более теплые цвета, а какой — более холодные?

                                            А теперь откройте эту картинку в графическом редакторе, и убедитесь, что нижний градиент является зеркально отраженной копией верхнего градиента.

                                            Так вот этот патч для Windows 10 (интерфейс + IE + Edge; 32bit — на скриншоте — почти сделан; 64bit — на начальной стадии), которая большинство надписей выводит через DirectWrite (Direct2D, WPF, ...). После патча все (кроме крупного и полужирного текста — сделал специально) становится четко (скриншот).

                                            Но все же предыдущий рендер шрифта (GDI):

                                            — был лучше (четче), чем DirectWrite.


                                          Оба патча здесь (un[7z]me):

                                          un[7z]me

                                          Note: для первого патча сохранил инструкцию (TODO) с моими шагами.
                                            0
                                            И если понравилась иконка ярлыка (на скриншоте), то вот она (и несколько других; un[7z]me):

                                            imageres

                                            Для установки нужно скопировать их в "%windir%\System32\".

                                            А затем внести изменения в реестр
                                            [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Icons]
                                            "29"=hex(2):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,53,00,79,00,\
                                              73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,69,00,6d,00,61,00,67,00,65,00,72,\
                                              00,65,00,73,00,31,00,36,00,33,00,2e,00,69,00,63,00,6f,00,2c,00,30,00,00,00
                                            "153"=hex(2):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,53,00,79,00,\
                                              73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,69,00,6d,00,61,00,67,00,65,00,72,\
                                              00,65,00,73,00,36,00,37,00,2e,00,69,00,63,00,6f,00,2c,00,30,00,00,00
                                            "0"=hex(2):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,53,00,79,00,\
                                              73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,69,00,6d,00,61,00,67,00,65,00,72,\
                                              00,65,00,73,00,32,00,2e,00,69,00,63,00,6f,00,2c,00,30,00,00,00

                                              +1
                                              Занятно. Жаль не понятно с развитием, хотелось бы патчи под последние версии windows 10 x64, но и то хлеб.

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