С чего начинать?
Итак Вы приняли решение изучать Reverse Engineering, но не знаете с чего начинать. Мы попытаемся Вам помочь и укажем, что Вы должны изучить в первую очередь. Не воспринимайте это как догму, просто попробуйте придерживаться наших советов.
Первый, и наиболее важный шаг: Вы должны скопировать и установить на свой компьютер программу-отладчик, с помощью которой будете исследовать все остальные программы. Отладчик предназначен для обнаружения ошибок в программе и их устранения непосредственно в процессе ее выполнения. Конечно, никаких ошибок искать мы не будем, просто для работы нам необходимы все те функции, которые предоставляет отладчик. Наиболее важным свойством отладчика является то, что исследуемая программа полностью находится под его контролем, и Вы легко можете влиять на ход ее выполнения. Для нас это действительно наиболее нужное свойство отладчика - без возможности контроля над ходом выполнения программы мы не добъемся никаких положительных результатов.
Следующий абзац описывает достаточно сложные для начинающих детали архитектуры процессора 80х86, поэтому Вы смело можете его пропустить. Но сказать о них все-же стоит. Из всех существующих для Windows-платформы отладчиков, наибольшей популярностью вполне заслуженно пользуется SoftICE фирмы Numega. Вы можете скопировать его с нашего FTP-сервера. Чем же SoftICE отличается от остальных подобных ему програм?. Наиболее важным отличием является то, что SoftICE работает в 0-м кольце защиты. Не пугайтесь, если Вы пока ничего не знаете о кольцах защиты, существующих в архитектуре 32-разрядных процессоров фирмы Intel и предназначенных для ограничения взаимодейстия выполняющихся программ между собой и с операционной системой. Обычно ОС имеет права полного доступа ко всем остальным выполняемым программам, т.к. она работает в 0-м кольце защиты (наиболее привелигерованном), системные задачи выполняются в 1-м и 2-м кольцах, а приложения - в 3-м (наименее привелигерованном). Частично осуществлять управление запущенными приложениями можно из 1-го и 2-го кольца защиты, именно так работает большинство отладчиков из крупных пакетов для разработки программ. Разработчики из Numega подошли к делу более профессионально и создали SoftICE - отладчик, который работает в 0-м кольце защиты (для этого он загружается до загрузки ядра ОС Windows) и позволяет полностью контролировать не только все выполняемые системой задачи, но и саму ОС Windows.
Скоро появится статья полностью описывающая процесс установки, конфигурирования и работы с SoftICE. Пока дадим лишь несколько основных советов:
При установке SoftICE, когда программа спросит о типе Вашего видеоадаптера, Вы можете указать Standard Display Adapter (VGA) и обязательно установите галочку напротив пункта Universal Video Driver (в нижней части экрана), это позволит вам работать с SoftICE в окне, не переходя на другое разрешение и видеть большую часть того, что выводится на экран Windows (очень удобно).
В следующем окне выберите порт, к которому у Вас подключена мышь. Потом программа установки спросит Вас, что она должна делать с файлом autoexec.bat. Укажите самый верхний пункт (Let Setup modify AUTOEXEC.BAT).
После того как завершится копирование файлов и программа установки попросит перегрузить компьютер, выберите пункт I restart my computer later. Сейчас мы произведем некоторые изменения в файле конфигурации SoftICE (winice.dat). Открываем его любым текстовым редактором. Находим строчку:
INIT="X;"
и заменяем ее на
INIT="wl; color f a 4f 1f e; code on; lines 60; wc 40; wd 2; wr; faults off; X;"
пока мы не будем пояснять значения всех элементов строки - обо всем Вы подробно узнаете немного позже. Пока просто используйте данную строку.
Найдите также строку
PHYSMB=32
в ней указывается количество оперативной памяти, установленной на компьютере. Замените указанное по умолчанию значение (32) на то, количество, которое соответствующее для Вашего компьютера. Например, если у Вас 64 Мб, то напишите
PHYSMB=64
И, наконец, самое важное. В самом конце файла найдем следующий фрагмент:
; ***** Examples of export symbols that can be included *****
; Change the path to the appropriate drive and directory
;EXP=c:\windows\system\vga.drv
;EXP=c:\windows\system\vga.3gr
;EXP=c:\windows\system\sound.drv
;EXP=c:\windows\system\mouse.drv
;EXP=c:\windows\system\netware.drv
;EXP=c:\windows\system\system.drv
;EXP=c:\windows\system\keyboard.drv
;EXP=c:\windows\system\toolhelp.dll
;EXP=c:\windows\system\shell.dll
;EXP=c:\windows\system\commdlg.dll
;EXP=c:\windows\system\olesvr.dll
;EXP=c:\windows\system\olecli.dll
;EXP=c:\windows\system\mmsystem.dll
;EXP=c:\windows\system\winoldap.mod
;EXP=c:\windows\progman.exe
;EXP=c:\windows\drwatson.exe
; ***** Examples of export symbols that can be included for Windows 95 *****
; Change the path to the appropriate drive and directory
;EXP=c:\windows\system\kernel32.dll
;EXP=c:\windows\system\user32.dll
;EXP=c:\windows\system\gdi32.dll
;EXP=c:\windows\system\comdlg32.dll
;EXP=c:\windows\system\shell32.dll
;EXP=c:\windows\system\advapi32.dll
;EXP=c:\windows\system\shell232.dll
;EXP=c:\windows\system\comctl32.dll
;EXP=c:\windows\system\crtdll.dll
;EXP=c:\windows\system\version.dll
;EXP=c:\windows\system\netlib32.dll
;EXP=c:\windows\system\msshrui.dll
;EXP=c:\windows\system\msnet32.dll
;EXP=c:\windows\system\mspwl32.dll
;EXP=c:\windows\system\mpr.dll
с помощью этих строк Вы можете подключить к SoftICE системные библиотеки экспортируемых функций. Для этого Вы должны убрать в начале строк символ ";", который означает, что строка является комментарием, и изменить путь к файлу на тот, который существует у Вас на компьютере. Например, если ОС Windows98 у Вас установлена в каталог win98 диска с, то вместо c:\windows\system\ Вы должны написать c:\win98\system.
Внимание! Обязятельно проверьте наличие всех, включаемых Вами файлов на диске (в разных ОС их состав меняется) и если какого-то не найдете - не включайте его (т.е. не убирайте в начале строки символ ";").
Теперь сохраняйте сделанные в файле изменения и перегружайте компьютер.
Если Вы все сделали правильно, то теперь при нажатии сочетания клавишь Ctrl+D должно появится черное окно SoftICE (при разрешении 1024х768 оно занимает половину экрана). Теперь нажав сочетание Ctrl+Alt+C вы переместите окно SoftICE в центр экрана.
Выход из SoftICE в Windows можно осуществить повторным нажанием Ctrl+D, но мы советуем для этих целей использовать клавишу F5 - это более корректно (клавиша F5 соответствует команде X).
Основы работы с SoftICE
Вернемся теперь к установленному нами в первой статье SoftICE и попытаемся разобраться с интерфейсом этой замечательной программы и также узнаем команды, которые нам пригодятся в самое ближайшее время.
Так как SoftICE работает в 0-м кольце защиты, получить изображение интерфейса программы практически невозможно. Поэтому все описание будет чисто текстовым. Если при установке программы Вы следовали нашим указаниям, то сейчас интерфейс отладчика состоит из следующих частей (назовем их окнами, потому, что с ними действительно можно работать как с окнами - включать, выключать, изменять размер):
Самое верхнее окно - окно регистров (wr - сокращенное обозначение, используемое в SoftICE). В этом окне отображается содержимое регистров процессора. Отдельно от остальных в правом углу отображается состояние регистра флагов (каждого флага в отдельности). Наибольшее значение для нас имеет флаг нуля (изображается символом z). Заглавная буква Z означает, что флаг установлен, строчная - флаг сброшен. Под содержимым регистра флагов отображается также очень полезная для нас информация, но подробно я расскажу о ней в следующих статьях. Окно регистров включается и выключается командой wr.
Следующее - окно данных. В нем мы можем наблюдать содержимое интересующего нас участка памяти. Существует несколько различных форм представления информации в этом окне:
db - информация отображается в виде байтов (byte)
dw - информация отображается в виде слов (word)
dd - информация отображается в виде двойных слов (double word - dword)
Информация в этом окне меняется при изменении содержимого участка памяти, т.е. Вы всегда видите именно то, что находится в данный момент в памяти. Окно включается и выключается командой wd.
Ниже расположено окно кода. В нем отображается дизассемблированный текст исследуемой программы. Курсор (красная строка для рекомендованных настроек) указывает на команду, которая будет выполнена на следующем шаге. В нижней части окна (на желтой полоске) показано, в каком модуле мы в данный момент находимся. Переключается окно с помощью команды wc.
Самое нижнее окно - окно команд SoftICE. Здесь Вы вводите команды и получаете некоторую полезную информацию о работе SoftICE. Т.к. выводимая информация целиком зависит от введенных команд, то описывать ее мы будем для каждой команды отдельно.
Работа всех Windows-приложений основана на вызове API-функций. Это очень удобно и выгодно. Например, для вывода окна сообщения с некоторым текстом, достаточно вызвать функцию MessageBoxA с адресом выводимой строки в качестве аргумента. Замечательной особенностью SoftICE является то, что Вы можете устанавливать точки прерывания на вызовы API-функций. Установив точку прерывания на некоторую строку программы, Вы сообщаете SoftICE, что при достижении этой строки программа должна прервать свое выполнение и возвратить управление отладчику. Например, Вы установили точку прерывания на выполнение команды по адресу 40А00020, а затем запускаете программу с адреса 40А00000. Дойдя до строки с адресом 40А00020, программа прервется, управление вновь вернется в SoftICE, и Вы сможете узнать содержимое регистров процессора, участков памяти, а также, при необходимости, что-то изменить.
Точка прерывания на вызов API-функции устанавливается точно так же, как и не выполнение команды по определенному адресу. При вызове функции программа прерывается в самом ее начале, и после этого Вы можете выполнить необходимые Вам действия. Обычно точку прерывания на вызов API-функции устанавливают, когда хотят узнать, из какого места программы она вызывается. Допустим, в программе имеется следующий фрагмент:
некоторый код
...
40200100 call MessageBoxA
40200105 cmp eax, 01
...
продолжение программы
Вы точно знаете, что вызывается функция MessageBoxA, но не знаете, что это происходит по адресу 40200100h. Для того, чтобы это выяснить мы должны проделать следующее:
Активизируем SoftICE (Ctrl+D)
Устанавливаем точку прерывания на вызов функции MessageBoxA (bpx MessageBoxA, советуем всегда писать общепринятые имена функций с заглавными и строчными буквами, SoftICE их не различает, а Вы так быстрее запомните). При этом происходит следующее: SoftICE устанавливает точку прерывания на выполнение первой команды указанной функции
Выходим в Windows (F5)
Выполняем те действия, в результате которых произойдет вызов функции MessageBoxA
При вызове этой функции (сообщение в окне команд) программа прерывается в модуле USER (указано в низу окна кода) и активизируется SoftICE, при этом курсор установлен не первой команде функции MessageBoxA. Чтобы узнать, из какого места произошел ее вызов, используем команду p ret (быстрая клавиша F12) - продолжение программы до выполнения команды ret (команда возврата из подпрограммы)
После этого, программа вновь прерывается по адресу 40200105 (на этой строке установлен курсор), а на предыдущей строке мы видим, что происходит вызов MessageBoxA. Вот мы и нашли то место, откуда вызывается функция MessageBoxA
Мы описали лишь незначительную часть команд SoftICE. Остальные подробно рассмотрим по мере их использования в наших следующих исследованиях конкретных программ. Что ж, мы уже немного освоились в SoftICE и вплотную подошли к необходимости использования дизассемблера. Без него никакого серьезного исследования программы Вам провести не удастся. Наш следующий рассказ о IDA Pro.
Команда а
Описание: ассемблирование кода
Синтаксис: а [адрес]
Использование: используется встроенный в SoftICE ассемблер для ассемблирования (преобразование команд ассемблера в машинный код) команд непосредственно в память. Ассемблер поддерживает стандартный набор инструкций процессоров Intel 80x86.
Если Вы не укажите адрес, ассемблирование будет производиться в то место, где окончилось предыдущее. Если Вы до этого не использовали команду а и не указали адрес, то ассемблирование начинается с адреса, указанного в cs:eip.
По команде а Вы попадаете в интерактивный ассемблер SoftICE. В качестве приглашения, в каждой строке отображается адрес будущей команды. После того, как вы ввели команду и нажали Enter, происходит преобразование и ее машинный код помещается по указанному адресу. Команды вводятся в стандартном формате Intel.
Для выхода из режима ассемблера нажмите Enter в ответ на очередное приглашение. Если диапазон, в котором Вы ассемблируете команды, отображаются в окне кода, то при вводе очередной команды содержимое этого окна изменяется соответствующим образом.
Ассемблер SoftICE поддерживает наборы команд следующих процессоров:
386, 486, Pentium, Pentium Pro и соответствующие им наборы команд сопроцессоров, а также MMX.
SoftICE также поддерживает следующие дополнительные мнемоники:
Используйте use16 или use32 в начале стоки, чтобы ассемблировать команды соответственно как 16-ти или 32-х битные. Если Вы не определите ни use16, ни use32, то по умолчанию используется разрядность регистра cs (т.к. этот регистр описывает разрядность текущего сектора).
Используйте retf для возврата из функции дальнего вызова (только для Win16)
Используйте word ptr, byte ptr, dword ptr и fword ptr для определения разрядности данных, если в аргументе указана ссылка непосредственно на ячейку памяти, например:
mov byte ptr es:[1234], 1
Используйте far и near для указания типа перехода и вызова функции [ближний или дальний] (только для Win16)
Кроме того
несколько операндов между собой разделяются пробелом или запятой
операторы, ссылающиеся непосредственно на ячейку памяти помещаются в квадратные скобки, например:
mov ax, [1234]
Пример использования:при использовании команды а cs:1234 ассемблер выводит приглашение в виде адреса и ожидает от Вас ввода команд. Введите все необходимые команды и нажмите Enter в ответ на очередное приглашение. Ассемблер преобразует инструкции в машинный код и поместит их начиная с адреса 1234 в текущем кодовом сегменте.
Разговор о регистрах
Регистры является составной частью процессора. Они используются для временного хранения информации. Интенсивное использование регистров в программе определяется тем, что скорость доступа к ним намного больше, чем к ячейкам памяти. 32-х битные процессоры имеют 16 регистров. Мы рассмотрим лишь основные и наиболее часто используемые из них: регистры общего назначения, указатель инструкций, регистры сегментов и регистр флагов.
Регистры общего назначения.
32-х битные регистры общего назначения eax, ebx, ecx, edx, esi, edi, ebp и esp могут хранить следующие типы данных:
Операнды для логических и арифметических операций
Операнды для рассчета адресов
Указатели на ячейки памяти
Хотя для хранения операндов, результатов операций и указателей Вы можете использовать любой из вышеперечисленных регистров, будте осторожны с регистром esp. В нем хранится указатель вершины стека и некорректное изменение этого значения приведет к неправильной работе программы и ее аварийному завершению.
Многие команды используют конкретные регистры для хранения своих операндов. Например, команды обработки текстовых строк используют содержимое регистров ecx, esi и edi в качестве операндов.
Основные случаи использования регистров общего назначения:
eax - используется для хранения операндов и результатов операций
ebx - как указатель на данные в сегменте ds
ecx - как счетчик для строковых операций и циклов
edx - указатель для ввода/вывода
esi - указатель на данные в сегменте ds, а также как указатель на источник в командах работы со строками
edi - указатель на данные в сегменте es, а также как указатель на приемник в командах работы со строками
esp - указатель вершины стека в сегменте ss
ebp - указатель на некоторые данные в стеке
В регистрах, оканчивающихся на x, можно обращаться к младщим 16-и битам (ax, bx, cx и dx соответственно), которые в свою очередь можно разделить на старший байт (ah, bh, ch и dh) и младший (al, bl, cl и dl) и работать с ними, как с регистрами длиной 8 бит. Регистры-указатели esp (указатель вершины стека) и ebp (базовый регистр), а также индексные регистры esi (индекс источника) и edi (индекс приемника) допускают только 32-битное обращение.
Регистры сегментов.
Регистры сегментов (cs, ds, ss, es, fs и gs) хранят 16-ти битные дескрипторы сегментов. Дескрипторы сегментов - это специальные указатели, определяющие расположение сегмента в памяти. В защищенном режиме работы процессора (Windows 95/98) все сегментные регисты указывают на один и тот же сегмент, поэтому обычно в программе они не используются.
Регистр флагов.
И, наконец, регистр флагов. О нем мы поговорим более подробно. Этот регистр представляет собой набор флагов, устанавливаемых или сбрасываемых по результатам выполняемых команд.
Надеюсь, дорогие друзья, вы знаете, что флаг - это переменная длиной 1 бит, используемая в командах условного перехода. Если значение этой переменной равно 1, то считается, что флаг установлен, если 0 - сброшен. В первую очередь нас интересуют: флаг нуля, флаг переноса и флаг знака.
Флаг нуля (zf) устанавливается в случае получения нулевого результата при выполнении очередной команды и сбрасывается при остальных ненулевых значениях.
Флаг переноса (сf) устанавливается при переносе или заеме старшего бита в арифметических операциях, в остальных случаях сбрасывается.
Флаг переполнения (оf) устанавливается, если результат арифметической операции не умещается в операнде-приемнике.
Флаг знака (sf) устанавливается при единичном значении старщего бита результата - признаке отрицательного числа.
Регистрация WinZip 7.0 (beta)
В этой статье мы попытаемся почувствовать себя настоящими исследователями программ. Конечно, это будут только первые робкие шаги, но именно они обычно являются определяющими для всей остальной работы в этом направлении. Нашей целью будет регистрация всемирно известной программы WinZip 7.0 (beta). В статье рассматривается build 1243, для более новой программы возможны некоторые отличия в адресах. Скопировать программу Вы можете с нашего FTP-сервера.
Устанавливаем и запускаем WinZip. Сразу после старта появляется окно, сообщающее о том, что программа не зарегистрирована. Если программу не зарегистрировать это окно будет появляться при каждом новом запуске. Это неудобно! В меню Help выбираем пункт About WinZip... В появившемся окне нажимаем кнопку Register. Открывается окно регистрации. Вводим в поле Имя имя, под которым хотим зарегистрировать программу (я использовал Fox Mulder). В поле РН вводим любую информацию (я обычно использую 200001, чтобы потом при необходимости его легко было опознать) и нажимаем кнопку ОК. Появляется окно, сообщающее, что введена неполная или неверная информация. Обращаю Ваше внимание на это окно. Это типичное окно MessageBox (окно сообщения). Его отличительными чертами являются:
неактивная кнопка закрытия окна
наличие внутри окна иконки (вид иконки зависит от типа сообщения)
наличие одной или нескольких кнопок (их названия и количество также зависит от типа сообщения)
В программе окно MessageBox может создаваться с помощью четырех функций: MessageBox(), MessageBoxA(), MessageBoxIndirect() и MessageBoxIndirectA(). Функции, не оканчивающиеся символом A (MessageBox(), MessageBoxIndirect()) используются преимущественно приложениями Win16 (Windows 3.x) и на них мы будем рассчитывать меньше всего. Остаются две функции: MessageBoxA() и MessageBoxIndirectA(). Какая из них используется программой, определяем опытным путем:
Закрываем окно сообщения
Активизируем SoftICE (Ctrl+D)
Устанавливаем точки прерывания на вызов MessageBoxA() и MessageBoxIndirectA() (bpx MessageBoxA, bpx MessageBoxIndirectA)
Возвращаемся в Windows (F5)
Нажимаем кнопку ОК в окне регистрации, программа прерывается при вызове функции и передает управление SoftICE. В окне команд сообщается, что программа прервалась при вызове функции MessageBoxIndirectA() из модуля USER32. И действительно в окне кода мы видим, что курсор стоит на первой строке этой функции и, что имя текущего модуля USER32 (написано внизу окна кода). Дальше мы тоже знаем, что делать:
Нажимаем F12 (команда p ret), для продолжения программы до выполнения команды ret. Перед нами вновь появляется знакомое окно сообщения, при нажатии в нем на кнопку ОК программа прерывается и управление передается SoftICE. Мы видим, что теперь программа остановилась в модуле WINZIP32:
0137:00426920 FF15C4AF4700 call [USER32!MessageBoxIndirectA]
0137:00426926 EB14 jmp 0042693C <- в этой строке находится курсор
Вот мы и нашли то место, где вызывается функция MessageBoxIndirectA() и создается окно сообщения. Теперь можно удалить установленные точки прерывания (команда bc *), т.к. они нам больше не понадобятся. В этой статье мы больше ничего, связанного с функцией MessageBoxIndirectA(), не узнаем. Использовали мы ее по двум причинам:
Чтобы Вы научились устанавливать точки прерывания на вызовы API-функций, и находит место их вызова в программе.
Чтобы прервать программу в модуле WINZIP32. Это необходимо для установки точек прерывания на конкретные адреса в памяти. Как я уже говорил в статье о распределении памяти, каждая программа работает в своем адресном пространстве. Причем, практически у всех запущенных приложений есть разные участки кода с одинаковыми адресами. Поэтому, для установки точки прерывания на некоторый адрес памяти кроме самого этого адреса, необходимо еще правильно указать нужное адресное пространство (или модуль, что в данном случае одно и тоже). Особенностью SoftICE является то, что он устанавливает точку прерывания на адрес в том модуле, в котором прервалось выполнение. Вот почему, для установки точки прерывания на адрес памяти (нам ее еще только предстоит установить) пришлось воспользоваться точкой прерывания на вызов функции MessageBoxIndirectA()
Здесь уместным был бы Ваш вопрос о том, почему этой точки прерывания не пришлось прибегать к каким-либо хитростям? Все очень просто! Точка прерывания на вызов MessageBoxIndirectA() устанавливается на первую команду кода этой функции в модуле USER32. Этот модуль находится в области памяти, которая является общей для всех запущенных приложений Windows (она расположена выше 2-го Гб), поэтому здесь никаких трудностей не возникает.
Итак, продолжим:
Мы все еще находимся в SoftICE. Устанавливаем точку прерывания на выполнение команды по адресу 00407CA5 (команда bpx 407CA5).
Выходим в Windows (F5) и вновь пытаемся зарегистрироваться. При этом программа прерывается при выполнении команды по адресу 00407CA5, в окне команд SoftICE сообщается, что программа остановилась на точке прерывания по адресу 0137:00407CA5.
Вводим команду db eax (показать в окне данных содержимое памяти в виде байт, начиная с адреса, содержащегося в регистре eax) и переписываем 8 символов нашего регистрационного номера (у меня это 409A11AA).
Убираем не нужную уже точку прерывания (команда bc *) и выходим в Windows (F5).
Наступает решающий момент. Вводим в поле РН полученный регистрационный номер и нажимаем кнопку ОК. Программа просит подтвердить регистрационную информацию, и после нажатия ОК Вы уже являетесь владельцем личного WinZip'а.
Я надеюсь, Вас посетило чувство гордости, как оно посещает меня всегда, когда я справляюсь с чем-либо сложным и поначалу непонятным. Иногда, очень приятно почувствовать, что ты тоже чего-то стоишь в этой жизни! На этом наша очередная статья закончена. Не смущайтесь, если Вы чего-то не поняли, я не ставил целью объяснить Вам все в мельчайших подробностях в самый первый Ваш раз. Нет, я хотел, чтобы Вы узнали, с чем мы будем иметь дело, и что после успешной работы чувствует настоящий Исследователь Программ.