Глава 11
Last updated
Last updated
Хорошо, нам осталось рассмотреть процессорные точки останова (hardware breakpoints), условные точки останова и message breakpoints, и после этого мы закончим с этой темой.
Процессорные точки останова (hardware breakpoints, HBP) - это возможность, предоставляемая процессором. Как это устроено на самом деле, я не знаю, но тем не менее мы можем устанавливать их, чтобы программа, когда их встречает, останавливалась и передавала управление.
Мы можем установить до 4 четырёх HBP, на пятый Ollydbg попросит нас указать, какой из четырёх уже установленных убрать.
Как обычно, для практики будем использовать крэкми CrueHead'а [ссылка].
Есть три возможности: HBP ON EXECUTION, ON WRITE и ON ACCESS.
Установка HBP ON EXECUTION выполняет ту же роль, что и BPX на адрес, но HBP не изменяет код и его сложнее обнаружить, хотя есть программы, которые используют кое-какие приёмы, чтобы сбросить HBP. Эти приёмы и способы противостоять им, мы рассмотрим в следующих главах.
Если хотим установить HBP ON EXECUTION на 401013, отмечаем строку, кликаем на правую кнопку мыши и выбираем BREAKPOINT-HARDWARE ON EXECUTION.
Также можем написать в командной строке:
После этого HBP установлен.
У Ollydbg есть специальное окно, с помощью которого мы можем просмотреть и управлять HBP'ами. Чтобы открыть его, идём в DEBUG-HARDWARE BREAKPOINTS.
Здесь мы видим окошко с HBP, и если нажмём FOLLOW, мы окажемся в листинге на той строке, где он был установлен. С помощью DELETE мы можем его удалить.
Теперь нажмём F9 для того, чтобы начать выполнение программы.
И остановимся на 401013.
Как видим, он ведёт себя как обычный BPX, если же сделаем то же, что делали и с BPX - напишем MOV EAX, DWORD PTR DS:[401013] и запустим, то увидим, что код не изменился.
Изменим EIP на 401000 с помощью NEW ORIGIN HERE и нажмём F7.
Видим, что в EAX содержатся E8 A6 04 00 (в обратной форме, поэтому мы видим 00004A6E8), то есть никаких изменений в коде не было.
Если мы перезапустим Ollydbg, то увидим, что HBP остался установленным.
Убираем его и устанавливаем HBP на MessageBoxA таким же образом, как и BPX.
Теперь смотрим список HBP.
Не будем повторять снова, но знаем, что если запустим программу и введём юзера и пароль, и мы согласимся, то выполнение остановится на API MessageBoxA, т.е. примерно так же, как если бы мы использовали обычный BPX.
HBP ON ACCESS и ON WRITE могут охватывать только 1, 2 или 4 байта, если же мы выберем в DUMP зону большего размера, то будут иметь значение только первые четыре байта.
Сбросим все HBP, установленные нами ранее, и попытаемся установить HBP ON ACCESS на адрес 4020CA.
Посмотрим в DUMP'е, что находится по этому адресу.
А теперь отметим первые 4 байта.
Нажимаем правую кнопку мыши.
Видим, что для отмеченной нами зоны был предложен HBP на байт или два байта (WORD), выбор четырёх байтов предлагается только для адресов, которые кратны 4. В данном случае это условие не соблюдается.
Проделаем ту же операцию для следующего байта и выберем HARDWARE ON ACCESS, и теперь есть только возможность выбора BYTE.
А на следующем появилась, наконец-то, опция DWORD, то есть HBP на четыре байта.
Идея в том, что если нам нужно контролировать сохранение или чтение по адресу 4020CA, то для этой цели достаточно поставить HBP на один байт.
Возвратимся к 4020CA и поставим HBP ON ACCESS – BYTE.
Видим, что поставленный нами HBP в списке имеет размер 1, т.е. байт (BYTE).
Делаем RUN.
Здесь OLLY говорит нам, что сработал HBP 1, т.е. тот, который идёт первым в списке HBP.
Видим, что выполнение программы прекращается на строке, следующей за той, где производилось сохранение или чтение. Это верно как для HBP ON ACCESS, так и для ON WRITE - инструкция, на которой срабатывает HBP, выполняется, а программа останавливается на следующей.
Как вы можете видеть, отличие от MEMORY BREAKPOINT заключается в том, что программа остановилась бы на 401007 - непосредственно на той инструкции, которая вызвала срабатывание точки останова.
Как вы можете догадаться, HBP ON WRITE срабатывает, когда происходить сохранение, а не чтение, и остановка программы происходит на инструкции, следующей за той, которая вызвала срабатывание HBP.
В действительности это вариант обычных BPX, отличающийся тем, что при активации такого BPX OllyDbg проверяет, верно ли некое условие, и если да, то останавливает выполнение программы, а если нет, то продолжает выполнение программы, как будто BP не существует.
Рассмотрим пример.
Сбросим всё, что мы делали ранее, и установим BREAKPOINT CONDICIONAL на 40100E, для чего выделим строку, нажмём правую кнопку мыши и выберем BREAKPOINT CONDICIONAL.
Открывается окошко, в котором нужно задать условие.
Например, если хотим задать, чтобы останов происходил, когда EAX равен 400000, то условие должно быть таким: "EAX==400000".
В хелпах, прилагаемых к OllyDbg, написано какие символы мы можем использовать и каким условиям они соответствуют.
Видим, что в случае с BPX CONDICIONAL используется розовый цвет. Нажимаем F9:
Видим, что произошёл останов и OllyDbg нам сообщает:
Раз EAX равен 400000, значит сработало заданное условие.
Начнём выполнение заново, сотрём BPX CONDICIONAL и поставим другой, где, например, EAX==500000.
И сделаем RUN.
Видим, что крэкми выполнился и останова не произошло, т.к. EAX всегда был равен 400000 и условие не выполнялось.
Если откроем HELP-CONTENTS.
Вот BREAKPOINTS и место где объясняются выражения:
Также в хелпе есть примеры выражений, которые можно использовать для условий.
Это условный BPX, такой же как и предыдущий, только в этом случае мы можем указать, чтобы все точные значения сохранялись при прохождении точки останова. Там есть много опций, и мы продемонстрируем применение этого BPX на примере одного API, который встречается в разных местах, и нам хочется, чтобы сохранялись данные, передающиеся ему.
Установим BPX CONDITIONAL LOG на адрес, где находится API, перезапустив предварительно OllyDbg.
Идем к нужному адресу, где находится api, и уже знаем, как это сделать: CLICK DERECHO-GOTO EXPRESSION.
Находясь здесь, нажимаем CLICK DERECHO- BREAKPOINT- CONDICIONAL LOG.
Видим окошко с множеством опций.
В данном случае нам нужно, чтобы сохранялись только требуемые нам данные.
Так как мы не хотим, чтобы происходил останов, то не задаём никакого условия, а в опции PAUSE PROGRAM выбираем, чтобы этого не происходило, то есть отмечаем NEVER. Потом в LOG VALUE OF EXPRESSION можем сделать так, чтобы сохранялось значение [esp], которое мы написали в поле EXPRESSION, в котором, как мы знаем, будет адрес возврата в основное тело программы после выполнения api, то есть самое верхнее значение стека, поэтому во второй строке LOG VALUE OF EXPRESSION выбираем ALWAYS, то есть логировать всегда. В третьей строке находится опция, задающая хотим ли мы логировать аргументы/параметры функции/api, и поскольку их немного, можем поставить ALWAYS.
Идём в окно LOG или L.
И очищаем его, чтобы ясно видеть, что сохраняет программа. Кликаем CLICK DERECHO-CLEAR WINDOW.
Видим, что есть опция, позволяющая сохранять лог в текстовый файл, если это необходимо.
Теперь запускаем выполнение программы с помощью F9.
Идём в окошко крэкми и пока в LOG’е ничего нет, так как заданное нами api не вызывалось.
Идём в REGISTER, где можем задать имя и пароль пользователя.
Когда нажимаем OK
Видим, что в окошке лога отобразилась информация о MessageBoxA, самое верхнее значение стека (которое равно 40137D и является адресом возврата из api), а затем параметры api, в данном случае это адрес из которого оно было вызвано, текст, заголовок и т.п.
В данном случае нам отобразилась информация только об одном вызове, но если api вызывается, скажем, 100 раз, то можем сохранять лог в текстовый файл. Если же нам нужно, чтобы отображались только некоторые из этих вызовов, то можем задать определённое условие.
Если у нас есть список с информацией о 100 различных вызовах данного api, выполненных программой, то можно задать какие-нибудь данные в поле условия, например, адрес возврата. В этом случае из всех 100 случаев вызова отобразятся только те, которые возвращаются на 40137D, а остальные нет.
Для этого перезагрузим крэкми, снова найдём api и установим на неё BPX CONDICIONAL LOG.
Изменим опции, так чтобы точка останова срабатывала только тогда, когда выполняется условие и зададим его, чтобы проверялось равен ли [esp] 40137D.
Запускаем программу, и когда появится окошко регистрации, введём имя пользователя ‘ricnar456’ и пароль ‘989898’.
Помните, что когда вводится имя пользователя, в котором есть цифры, messageboxa вызывается 2 раза? Нажимаем ОК.
Видим, что на первый MessageBoxA Олли никак не отреагировала. В логах показано, что адрес возврата был равен 4013C1, поэтому условие не выполнялось.
Когда нажимаем кнопку OK
Это второй раз, когда вызывается api. Здесь условие выполняется и срабатывает точка останова.
Видим, что верхнее элемент стека содержит значение 40137d, которое активирует BPX CONDICIONAL LOG.
В обоих случая OllyDbg сохранил информацию об обоих вызовах.
Во втором случае адресом возврата было 40137D, и мы видим, что в этот раз условная точка останова сработала.
Ок, думаю, что этого достаточно, чтобы вам было в чём попрактиковаться некоторое время. Ещё остались MESSAGE BREAKPOINTS, но я не хочу вас уморить, так что ждите 12 часть, а после того, как рассмотрим последний вид точек останова, обещаю, что продолжим крэкать по-немногу, так, чтобы не заскучать.
[C] Рикардо Нарваха, пер. Aquila