Этот сайт создан как клуб русификаторщиков. Для нас существуют три основных правила.
1. Мы никому и ничего не должны!
2.Один пришедший на сайт толковый русификаторщик дороже всех пользователей.
3. Мы делаем русификаторы для своего сайта, но в оригинале ими могут пользоваться все в интернете.
Как изменить размер ячеек в строке состояния (на примере отладчика OllyDbg v2.01)
Тема создана по вопросу от пользователя Metabolic и здесь будет рассказано, как изменить ширину ячеек в строке состояния отладчика OllyDbg v 2.01.
Ранее, на примере программы FairStars Audio Converter, я уже показывал, как это можно сделать, но здесь оказался несколько иной случай.
Итак, что имеем. В программе OllyDbg есть строка состояния для вывода различного рода информации, которая разделена на три ячейки. Первая самая большая, её размер динамически изменяется в зависимости от ширина окна. А размер второй и третьей ячеек - постоянный. Обе эти ячейки привязаны к правой границе окна, причем последняя ячейка может переключаться на панель инструментов (см. рис. 1).
Рисунок 1
Перевод строк, которые отображаются в ячейках 2 и 3, показывает, что они не помещаются в отведенных границах (см. рис 2).
Рисунок 2
Можно не переводить эти строки, а можно попытаться подкорректировать размеры ячеек, т.е. увеличить их ширину. Для этого необходимо выполнить анализ кода, найти нужный участок, где формируются размеры ячеек элементов строки состояния, и внести в них необходимые изменения. Основная сложность заключается в поиске нужного участка кода. Обычно элемент, который требует правки, можно найти по идентификатору (ID), воспользовавшись утилитой WinSpy++ (как это показано на примере программы FairStars Audio Converter). Но в данном случае она нам не поможет. Как еще можно найти? Сделайте скриншот проблемной области окна программы, загрузите его в графический редактор и определите размеры нужных элементов. Потом произведите поиск полученных значений ширины и высоты (плюс/минус пару пикселей) в отладчике. Обычно при формировании элементов используются инструкции PUSH или MOV, только не забывайте, что все значения в отладчике указываются в формате НЕХ. Если, например, вы получили значение ширины 30 пикселей, то в шестнадцатеричном формате (НЕХ) это будет 1Еh. Таких мест с найденными значениями может несколько. Вам остается только выполнить их анализ. К сожалению, в данном примере и этот способ не дает положительного результата. Как быть?
Обратите внимание на строки, которые отображаются в ячейках. Например, после запуска отладчика в третьей ячейке отображается строка "Ready". Во второй ячейке, при активации определенной опции, отображается строка "Top". По идее, перед загрузкой этих строк должна быть выполнена инициализация ячеек. Ну что ж, создайте копию исполняемого файла отладчика с именем, например, ollydbg1.exe. Затем запустите сам отладчик и загрузите в него эту копию самого себя.
Откроется список найденных строк. Поищем здесь строку "Ready". Список большой, поэтому имеет смысл воспользоваться поиском по списку. Щелкните правой кнопкой мышки в окне строк и в контекстном меню выберите команду "Search for text":
Рисунок 4
В открывшемся окошке в поле поиска введите строку "Ready" и нажмите "ОК". Если такая строка есть, то на ней будет установлен курсор. Да, есть такая строка (см. рис. 5).
Рисунок 5
Как вы можете видеть, рядом также находятся остальные строки, которые отображаются в ячейках 2 и 3. На всякий случай продолжите поиск строки в списке, мало ли, а вдруг еще где-то встречается. Нет, в данном случае строка используется только раз. Хорошо.
Двойной щелчок по найденной строке в списке перенесет нас в окно отладки, по месту обращения к этой строке, адрес 0040BE2F. Теперь начинаем процесс анализа кода. Ставим на адрес 0040BE2F точку останова (бряк) с этой строкой:
Рисунок 6
Далее эта строка должна быть отправлена в ячейку, посмотрим. Запускаем программу (F9) и когда ее выполнение дойдет до адреса 0040BE2F, отладчик сделает остановку. Далее в пошаговом режиме (F8 - без захода в функции) начинаем трассировку. Смотрим на колонку комментариев (Comments), где отладчик показывает дополнительную информацию. На что обращать внимание? На возможные данные с размерами ячейки или координаты ячейки относительно границы окна.
Небольшое отступление. Любой элемент в графическом интерфейсе характеризуется координатами размещения X, Y его левого верхнего угла и размерами W, H. Но размеры могут быть заданы также координатами X1, Y1 — правого нижнего угла элемента.
Рисунок 7
Тогда ширина элемента вычисляется как W = X1 - X, а высота H = Y1 - Y. Все эти вычисления могут выполняться в коде и нужно быть к этому готовым. . . .
Идем дальше. В пошаговом режиме мы дойдем до адреса 0040BE3C (см. рис. 6) с инструкцией безусловного перехода, которая перебросит нас ниже по коду на адрес 0040C112. Продолжаем пошаговое выполнение инструкций пока не дойдем до адреса 0040C136. Обратите внимание на подсказки отладчика-->Search for" -> "All referenced strings":
Рисунок 3
Откроется список найденных строк. Поищем здесь строку "Ready". Список большой, поэтому имеет смысл воспользоваться поиском по списку. Щелкните правой кнопкой мышки в окне строк и в контекстном меню выберите команду "Search for text":
Рисунок 4
В открывшемся окошке в поле поиска введите строку "Ready" и нажмите "ОК". Если такая строка есть, то на ней будет установлен курсор. Да, есть такая строка (см. рис. 5).
Рисунок 5
Как вы можете видеть, рядом также находятся остальные строки, которые отображаются в ячейках 2 и 3. На всякий случай продолжите поиск строки в списке, мало ли, а вдруг еще где-то встречается. Нет, в данном случае строка используется только раз. Хорошо.
Двойной щелчок по найденной строке в списке перенесет нас в окно отладки, по месту обращения к этой строке, адрес 0040BE2F. Теперь начинаем процесс анализа кода. Ставим на адрес 0040BE2F точку останова (бряк) с этой строкой:
Рисунок 6
Далее эта строка должна быть отправлена в ячейку, посмотрим. Запускаем программу (F9) и когда ее выполнение дойдет до адреса 0040BE2F, отладчик сделает остановку. Далее в пошаговом режиме (F8 - без захода в функции) начинаем трассировку. Смотрим на колонку комментариев (Comments), где отладчик показывает дополнительную информацию. На что обращать внимание? На возможные данные с размерами ячейки или координаты ячейки относительно границы окна.
Небольшое отступление. Любой элемент в графическом интерфейсе характеризуется координатами размещения X, Y его левого верхнего угла и размерами W, H. Но размеры могут быть заданы также координатами X1, Y1 — правого нижнего угла элемента.
Рисунок 7
Тогда ширина элемента вычисляется как W = X1 - X, а высота H = Y1 - Y. Все эти вычисления могут выполняться в коде и нужно быть к этому готовым. . . .
Идем дальше. В пошаговом режиме мы дойдем до адреса 0040BE3C (см. рис. 6) с инструкцией безусловного перехода, которая перебросит нас ниже по коду на адрес 0040C112. Продолжаем пошаговое выполнение инструкций пока не дойдем до адреса 0040C136. Обратите внимание на подсказки отладчика::002::
Когда завершится анализ загруженного файла, задайте поиск всех строк. Для этого щелкните правой кнопкой мышки в окне отладчика и в контекстном меню меню выберите команду "Search for" -> "All referenced strings":
Рисунок 3
Откроется список найденных строк. Поищем здесь строку "Ready". Список большой, поэтому имеет смысл воспользоваться поиском по списку. Щелкните правой кнопкой мышки в окне строк и в контекстном меню выберите команду "Search for text":
Рисунок 4
В открывшемся окошке в поле поиска введите строку "Ready" и нажмите "ОК". Если такая строка есть, то на ней будет установлен курсор. Да, есть такая строка (см. рис. 5).
Рисунок 5
Как вы можете видеть, рядом также находятся остальные строки, которые отображаются в ячейках 2 и 3. На всякий случай продолжите поиск строки в списке, мало ли, а вдруг еще где-то встречается. Нет, в данном случае строка используется только раз. Хорошо.
Двойной щелчок по найденной строке в списке перенесет нас в окно отладки, по месту обращения к этой строке, адрес 0040BE2F. Теперь начинаем процесс анализа кода. Ставим на адрес 0040BE2F точку останова (бряк) с этой строкой:
Рисунок 6
Далее эта строка должна быть отправлена в ячейку, посмотрим. Запускаем программу (F9) и когда ее выполнение дойдет до адреса 0040BE2F, отладчик сделает остановку. Далее в пошаговом режиме (F8 - без захода в функции) начинаем трассировку. Смотрим на колонку комментариев (Comments), где отладчик показывает дополнительную информацию. На что обращать внимание? На возможные данные с размерами ячейки или координаты ячейки относительно границы окна.
Небольшое отступление. Любой элемент в графическом интерфейсе характеризуется координатами размещения X, Y его левого верхнего угла и размерами W, H. Но размеры могут быть заданы также координатами X1, Y1 — правого нижнего угла элемента.
Рисунок 7
Тогда ширина элемента вычисляется как W = X1 - X, а высота H = Y1 - Y. Все эти вычисления могут выполняться в коде и нужно быть к этому готовым. . . .
Идем дальше. В пошаговом режиме мы дойдем до адреса 0040BE3C (см. рис. 6) с инструкцией безусловного перехода, которая перебросит нас ниже по коду на адрес 0040C112. Продолжаем пошаговое выполнение инструкций пока не дойдем до адреса 0040C136. Обратите внимание на подсказки отладчика: в регистре EAX находится адрес 0012DC04, по которому в данный момент находятся координаты некой прямоугольной области. У вас в регистре EAX может быть другой адрес, в любом случае запишите его где-нибудь, он нам понадобится позже. Значения координат у вас также будут другие, т.к. они зависят от разрешения экрана, размеров окна приложения и заданных настроек. Так вот, если в эту область отправляется строка "Ready", значит она (область) является ячейкой строки состояния.
Рисунок 8
Определим размеры ячейки: ширина - Right(619) — Left(558) = 61 пикс.; высота - Bottom(150) — Top(134) = 16 пикс. Давайте глянем на координаты в памяти по адресу 0012DC04. Перейдите на панель регистров (Registers (FPU)). Щелкните правой кнопкой мышки по адресу в регистре EAX и выберите команду "Follow in Dump":
Рисунок 9
Теперь перейдите в панель дампа. Здесь хорошо видно координаты ячейки в шестнадцатеричном формате:
Рисунок 10
Под каждое значение координаты отводится 4 байта (WORD). Заметьте, порядок размещения байт обратный. Что это значит? Возьмем первые четыре байта 2Е 02 00 00. Чтобы получить реальное значение, байты необходимо разместить в прямом порядке, т.е. вот так 00 00 02 2Е. Получили шестнадцатеричное число 22Еh (первые нули отбрасываем как незначащие). В десятичном формате — 558. Потренируйтесь на значениях, которые вы видите у себя. Думаю вам понятно. Теперь посмотрите на данные, которые размещены в строках по адресам 0012DC14 и 0012DC24. Если вы преобразуете эти значения в десятичный формат, то увидите, что это координаты всех трех ячеек строки состояния.
Рисунок 11
Еще раз напоминаю, что ваши данные будут отличаться от показанных в этом примере. Все эти координаты были созданы в памяти где-то ранее и теперь, при создании элемента, просто идет к ним обращение. Поэтому нужно найти участок кода, где идёт формирование координат и запись их в отведенную область памяти.
Очевидно, что раз значения уже созданы, то нет смысла продолжать выполнение программы. Перезагружаем её в отладчике и идём на адрес 0040BE2F, где у нас установлен бряк (по месту обращения к строке "Ready"). Поднимаемся выше по коду. По адресу 0040BD61 в стек заносится строка "Top", которая при определенных условиях отображается в ячейке 2 строки состояния. По аналогии с ячейкой 3 координаты ячейки 2 инициализируются по адресу 0040BD7F.
Рисунок 12
Подобный участок кода должен выполняться и для первой ячейки строки состояния. Поищем его. Поднимаемся еще выше по коду. А вот, смотрите, по адресу 0040BCF3 в стек заносится строка для отображения в первой ячейке. Чуть ниже, по адресу 0040BD0A, инициализируются координаты ячейки 1.
Рисунок 13
Как можно в этом удостовериться? Установите бряк на адреса 0040BCF3 и 0040BD0A. После запустите программу - F9. Когда отладчик прервет её работу, посмотрите на подсказки отладчика в колонке комментариев (Comments). По адресу 0040BCF3 в текущий момент находится строка "OllyDbg v2.01". Именно эта строка отображается в первой ячейке после запуска отладчика, когда в него еще не загружен объект исследования (см. рис. 1). Продолжите выполнение программы - F9. Следующая остановка адрес 0040BD0A. Здесь видны данные с координатами первой ячейки:
Рисунок 14
Так как и здесь программа считывает уже готовые значения, то нужно продолжить анализ кода. Подымаясь выше, устанавливая точки остановки и запуская программу на выполнение, необходимо определить момент, когда по адресам 0012DC04, 0012DC14 и 0012DC24 еще не будут находиться значения с координатами ячеек для строки состояния. Эта задача намного упрощается, если знать функции Windows API. К примеру структура RECT, на которую ссылается отладчик (ClipRect с координатами прямоугольной области), является составной частью структуры PAINTSTRUCT. Последняя в свою очередь используется в функциях окрашивания и рисования в окне приложения. В данном случае, если мы пролистаем код программы вверх от места установки последней точки остановки (по адресу 0040BCF3, см. рис. 14), то на глаза нам попадется функция BeginPaint по адресу 0040B95B. Установите здесь точку останова, перегрузите программу в отладчике и запустите её снова. Отладчик прервет её работу на адресе 0040B95B.
Рисунок 15
Переключитесь на окно дампа и перейдите на адрес 0012DC04. Здесь должны находится массивы с координатами ячеек (мы установили это ранее).
Как видите здесь их ещё нет (сравните с данными на рисунке 11). Продолжаем в пошаговом режиме выполнение инструкций кода по клавише F8, одновременно контролируя область памяти в дампе по адресам 0012DC04, 0012DC14 и 0012DC24. После того как будет выполнена подпрограмма по адресу 0040B985, по указанным в дампе памяти адресам появятся значения с координатами ячеек. Значит координаты элементов строки состояния инициализируются именно в ней.
Рисунок 17
Пускай вас не смущает некоторое различие в данных, мы пока в самом начале и массив сформирован еще не полностью. Если вы посмотрите в дамп памяти по адресу 0012DBF4, то последовательность байт полностью идентична той, которую можно видеть на рисунке 11.
Исходя из выше изложенного, необходимо перезагрузить программу в отладчике и заняться исследованием подпрограммы по адресу 004087E8. Убираем точку останова с функции BeginPaint по адресу 0040B95B и устанавливаем её по адресу 0040B985. Для начала можно просто зайти в эту подпрограмму и исследовать её на предмет констант близких по значениям к ширине ячеек. Просто установите курсор на адрес 0040B985 и нажмите клавишу "Enter". Вы окажетесь в начале кода подпрограммы, где первая инструкция будет PUSH EBP. Заканчивается подпрограмма по адресу 004089E6 инструкцией RET. Исследование этого кода показывает, что констант, близких по значения к ширине ячеек, здесь нет. Поэтому запускаем программу (F9) и когда отладчик остановит её выполнение на адресе 0040B985, заходим в подпрограмму по клавише F7. В окне дампа перейдите на адрес 0012DC04. Вернитесь в окно отладки и начинаем проход каждой инструкции по клавише F8, анализируя данные в регистрах и в дампе памяти. Наша задача состоит в том, чтобы определить конкретные инструкции, где расчитываются размеры ячеек, на основании которых уже вычисляются координаты.
По адресу 00408802 (функция GetClientRect) определяется размер окна приложения. По адресу 0040880B в регистр EAX записывается значение 5h. Хм, интересно...
Рисунок 18
Идем дальше. Нажимаем F8 снова и снова, в стеке появляются значения похожие на координаты в области элемента строки состояния. Так мы дойдем до адреса 00408882. Вы обратили внимание, что до этого момента, начиная с адреса 0040880B, регистр EAX нигде в инструкциях не фигурировал? Посмотрите в панель регистров, там в регистре EAX до сих пор висит значение 5h. Поначалу я этот факт упустил из виду. А вот что получается дальше. По адресу 00408882 записана инструкция MOV EDX,EAX, которая копирует содержимое регистра EAX в EDX. Нажмите F8 и посмотрите на панель регистров, вы увидите, что теперь в регистре EDX находится значение 5h. Сейчас мы находимся на следующей инструкции по адресу 00408884 — ADD EDX,EDX. Она удваивает содержимое в регистре EDX. После её выполнения там будет значение 5h + 5h = Ah. Выполните эту инструкцию, нажав F8. Что вы видите в регистре EDX? Инструкция по адресу 00408886 нас не интересует, поэтому F8. Мы на адресе 00408889, где записана инструкция LEA EDX,[EDX*2+EDX]. Здесь командой LEA выполняется арифметическое действие EDX*2+EDX, а его результат записыватся обратно в регистр EDX:
Рисунок 19
Давайте посчитаем, какое значение получится. Сейчас в этом регистре значение Ah — в десятичном формате число 10. Здесь и калькулятор не нужен:10*2+10=30 (в шестнадцатеричном формате 1Eh). Это значение хорошо соотносится с шириной второй ячейки.
Рисунок 20
Давайте проверим. В инструкции LEA EDX,[EDX*2+EDX] изменим множитель 2 на 8. Получится инструкция вида LEA EDX,[EDX*8+EDX]. Посчитаем, сколько получится:10*8+10=90 (5Ah). В окне отладки мы сейчас стоим на адресе 00408889, нажмите клавишу пробел. Откроется окно ввода ассемблерной инструкции. Измените её как описано выше:
Рисунок 21
Теперь отключите все точки останова (на панели инструментов нажмите кнопку с литерой "В", в открывшемся окошке переключите состояние точек останова на "Disabled") и запустите программу на выполнение клавишей F9. Мы увидим следующую картину:
Рисунок 22
Наше предположение о том, что в инструкции по адресу 00408889 вычисляется ширина ячейки 2 верное. "Но позвольте! — скажете вы. — Ведь в строке состояния отображается какая-то ерунда, поле с надписью "Тор" не изменилось!" Да, верно. Причина в том, что строка состояния в программе выводится на экран средствами Windows API, при помощи функций рисования (ссылки на них были даны выше). Рисуются ячейки, границы ячеек и текст! Чтобы нарисовать элемент создается прямоугольная область - подложка, на неё сверху накладывается прямоугольная область чуть меньшего размера, которая изображает границу элемента. Затем сверху рисуется прямоугольная область, показывающая внутреннее поле элемента и, наконец, на этом поле рисуется текст. Вот как это выглядит:
Рисунок 23
Видите, как все просто. Учтите, что для каждого прямоугольника расчитываются координаты левого вернего угла элемента и правого нижнего угла. Сейчас же, своими действиями по адресу 00408889, мы изменили только ширину подложки ячейки. Чтобы изменить остальные части ячейки, нужно дальше анализировать алгоритм вычислений. Например смотрите на рисунок 24, по адресам 004088FA - 004088FE выполняются те же самые инструкции, которые мы рассмотрели ранее (см. рис. 19).
Рисунок 24
Перезагрузите программу в отладчике и измените в инструкции по адресу 004088FE множитель на с 2 на 8 также, как мы сделали это ранее в инструкции по адресу 00408889. Запустите программу на выполнение. Что видим?
Рисунок 25
Это мы изменили только одну ячейку. Кстати, обратили внимание, что в инструкции MOV EDX,EAX по адресу 004088FA (см. рис. 24) в регистре EAX все еще находится значение 5h? По-видимому это какая-то константа, используемая для вычисления ширины ячеек. Можно продолжить анализ кода и найти место, где расчитывается ширина ячейки 3. А можно попробовать изменить эту константу и посмотреть, что получится. Давайте попробуем...
Если помните, то в регистр EAX записывается значение 5h по адресу 0040880B (см. рис. 18 ). Берется оно из памяти по адресу 005828ЕС. Как это значение попадает по этому адресу, нет смысла разбирать (если хотите, можете исследовать это самостоятельно). Проще всего задать прямо в инструкции новое значение вместо адреса. Перегружаем программу в отладчике и идем на адрес 0040880B. Нажмите клавишу "Пробел" и введите вместо адреса значение 0Аh (10):
Рисунок 26
Подтвердите ввод, нажав кнопку "Assemble". Теперь запустите программу на выполнение - F9 (предварительно отключите точки останова, если таковые имеются). Какой результат вы получили? Должно выйти вот так:
Рисунок 27
Как видите, размеры ячеек стали больше по сравнению с исходным вариантом. Предположение о том, что значение 5h, которое в начале подпрограммы записывается в регистр EAX, оказалось верным. Теперь вы можете подобрать для себя оптимальное значение, которое будет удовлетворять вашим условиям, будь-то для локализации или ещё для чего-то. Обратите внимание, что исходная константа влияет на размер обеих ячеек. Если вы хотите изменить ширину ячеек в индивидуальном порядке, то займемся разбором алгоритма далее.
Ранее мы выяснили, что по адресу 00408889 вычисляется ширина прямоугольной области, которая является подложкой ячейки 2 (см. рис. 19). Если в пошаговом режиме дойти до адреса 004088A7, то окажетесь на инструкции LEA EDX,[EDX*4+EAX]. В регистре EDX сейчас находится значение Fh, а в регистре EAX все также лежит значение 5h. Посчитаем выражение EDX*4+EAX:0F*4+5=41h. В десятичном формате — 65. Посмотрите на рисунок 20. Полученное значение 65 соответствует размеру ячейки 3. Значит это ширина прямоугольной области, которая является подложкой ячейки 3.
Рисунок 28
Мы хотим увеличить ширину, поэтому в этой инструкции можно изменить множитель с 4, к примеру, на 8. В этом случае ширина третьей ячейки должна получиться 0F*8+5=7Dh. В десятичном формате — 125. Как и при разборе ячейки 2, здесь мы изменили только ширину подложки, поэтому в пошаговом режиме опускаемся по коду ниже и ищем, где вычисляются размеры других элементов. Также здесь уже можно действовать по принципу аналогий. По адресу 004088FE мы изменяли размер прямоугольной области для ячейки 2. Посмотрите немного выше. По адресу 004088EE находится аналогичная инструкция, как и по адресу для второй 004088A7:LEA EDX,[EDX*4+EAX] (см. рис. 29).
Рисунок 29
Вполне возможно, что она относится к расчету какого-то элемента, но уже для ячейки 3. Также поменяем в этой инструкции множитель 4 на 8. Идем дальше. Так как третья ячейка переключается со строки состояния на панель инструментов, то далее расчитывается ешё одна ширина для одного из элементов ячейки. Это происходит по адресу 00408952, здесь записана инструкция LEA ECX,[ECX*4+EAX] (см. рис. 30).
Рисунок 30
Множитель в ней также изменяем с 4 на 8. На этом этапе все. Отключите установленные точки останова и запустите программу на выполнение.
Рисунок 31
Для этого варианта, в инструкциях вычисления ширины элементов ячеек, мы использовали множитель 8. Кстати имейте в виду, что в качестве множителя в показанных инструкциях можно использовать только значения 2, 4 или 8. Поэтому вариантов изменить ширину здесь не много. Но все хоть что-то, чем совсем ничего. А комбинируя значения множителя и константы в любом случае можно добиться необходимой ширины ячейки.
Сохраните сделанные в файле изменения, запустите модифицированный вариант отладчика и переключите в настройках отображение ячейки 3 в панель инструментов. Перезапустите отладчик. Что вы видите? Здесь ширина ячейки осталась прежней, т.е. 65 пикс. Поэтому возвращаемся в нашу подпрограмму. Для панели инструментов ширина элементов ячейки расчитывается при помощи подобных инструкций. Смотрите, по адресу 00408938 находится инсрукция LEA ECX,[ECX*4+EAX] и далее по адресу 0040898F инструкция LEA EAX,[EAX*4+ECX]:
Рисунок 32
Когда ячейка находится в строке состояния, то эти инструкции обходятся стороной, согласно условию. Измените в обеих инструкциях множитель 4 на 8 и сохраните измения в файле. Теперь точно все.
Рисунок 33
На этом наше исследование подошло к концу. Какой вариант изменения ширины ячеек вам выбрать (или использовать сразу оба), решите сами. Надеюсь, что это небольшое руководство поможет вам справляться с подобными задачами самостоятельно.