Ассемблер. Процедуры (функции). Крэкинг ч.7

Обсудить статью на форуме


Свежая 2020 года подборка видеоуроков, инструментов крэкера, книг и статей - здесь.


CALL и RET

Я намеренно оставил эти 2 инструкции напоследок. На данном этапе у Вас уже достаточно базовых знаний, чтобы вплотную подойти к изучению CALL и RET.

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

Итак, давайте снова загрузим крэкми CrueHead'а в OllyDbg.

Правая кнопка мыши на любой строке листинга - "Go to" - Expression".

Взлом программ отладчиком OllyDbg

Во всплывшем диалоге вводим 401245

Взлом программ отладчиком OllyDbg

В окне дизассемблера разворачивается код по только что заданному адресу, где видим CALL, который нам и нужен для практики.

Взлом программ отладчиком OllyDbg

Чтобы выполнить этот CALL, подсвечиваю строчку - правая кнопка мыши - "New origin here". Теперь значение EIP указывает на 401245, а это значит, что следующей инструкцией выполнится наш CALL.

Взлом программ отладчиком OllyDbg

Тут можем проследить как изменяется значение EIP.

Взлом программ отладчиком OllyDbg

Вернёмся же к нашему CALL.

Взлом программ отладчиком OllyDbg

Инструкция CALL передаёт управление заданной процедуре (или просто подпрограмме), адрес которой указан в операнде. Например:

CALL 401362 означает, что управление будет передано на адрес 401362, т.е. процессор пойдёт и выполнит подпрограмму, которая находится по этому адресу, и как только подпрограмма завершится управление вернётся к следующей за CALL инструкции.

В данном случае, после завершения процедуры 401362, управление вернётся на адрес 40124A.

Когда мы имеем дело с инструкцией CALL, OllyDbg предоставляет несколько полезных механизмов трассирования. Если нам интересно продолжить трассировку по внутренностям данной процедуры, можно "нырнуть" в неё клавишей F7. Если же нам хочется просто глянуть на содержимое процедуры, чтобы далее принять решение трассировать её или нет, можно воспользоваться следующей опцией: правая кнопка мыши - "Follow". Наконец, если мы не хотим трассировать данную процедуру, т.к. её содержимое не сулит ничего интересного, можем выполнить её на одном дыхании клавишей F8 и продолжить трассировку по адресу следующей за CALL инструкции.

Итак, чтобы посмотреть содержимое процедуры, не переводя на неё управление, подсвечиваем CALL - правая кнопка мыши - "Follow":

Взлом программ отладчиком OllyDbg

Как видите, значение EIP по-прежнему 401245, т.к. FOLLOW просто подгружает в дизассемблер код по заданному адресу и ждёт дальнейших распоряжений, но ничего при этом не выполняет.

Взлом программ отладчиком OllyDbg

Итак, перед нами код процедуры, которая, естественно, начинается по адресу 401362, в соответствии со значением операнда CALL. Где же конец процедуры? - В данном случае конец приходится на следующую инструкцию RET, которая находится чуть ниже. OllyDbg использует мнемонику RETN вместо RET, что одно и тоже. Эта инструкция завершает процедуру, возвращая управление на адрес 40124A, где находится следующая за CALL инструкция.

Мы теперь знаем как подсмотреть код процедуры не переводя на неё управление. Вернёмся же назад - для этого достаточно нажать на клавишу (-), т.е. "минус". Эта клавиша всегда возвращает нас на один шаг назад в цепочке FOLLOW, ничего при этом не выполняя.

Вот мы снова видим изначальный CALL:

Взлом программ отладчиком OllyDbg

Далее мы погрузимся в процедуру, т.е. переведём на неё управление клавишей F7, но сначала обратите внимание на стек. Это очень важно, т.к. в стеке хранится адрес возврата, который использует инструкция RET, чтобы передать управление обратно.

Взлом программ отладчиком OllyDbg

Предыдущая картинка отображает содержимое стека на моей машине. Возможно, у Вас будут другие значения, но это несущественно.

Нажимаю на F7:

Взлом программ отладчиком OllyDbg

"Погружаемся" в процедуру и видим, что на этот раз, в отличие от предыдущих манипуляций с FOLLOW, значение EIP изменилось - теперь оно равно 401362 и это значит, что мы действительно начали выполнять код процедуры.

Давайте обратим внимание на стек

Взлом программ отладчиком OllyDbg

На предыдущей картинке я выделил жёлтым состояние стека до входа в процедуру. Как видите, в стеке появилась новая ячейка, т.е. при выполнении инструкции CALL в стек добавляется адрес возврата, чтобы RET знала, куда вернуть управление при завершении процедуры.

Значение этой новой ячейки - 40124A - соответствует адресу следующей после CALL инструкции. Если Вы вдруг успели забыть об этом, следующая картинка освежит вашу память:

Взлом программ отладчиком OllyDbg

Причём Olly заботливо добавляет к этой ячейке некоторую дополнительную информацию.

Взлом программ отладчиком OllyDbg

Сообщает нам, что это адрес возврата из 401262 в 40124A.

Т.е. Olly ещё не в курсе, где находится RET, но точно знает, что процедура начинается по адресу 401362 и заканчивается по какому-нибудь адресу, где вероятнее всего находится инструкция RET, которая вернёт управление на адрес 40124A.

Давайте ещё раз нажмём на F7, чтобы выполнить PUSH 0, и посмотрим, как этот ноль добавится в стек, сместив вниз наш адрес возврата.

Взлом программ отладчиком OllyDbg

Процедура может содержать тысячи стековых операций (PUSH, POP и др.), добавляя и удаляя из стека различные значения, но при завершении процедуры в верхушке стека должен снова оказаться адрес возврата. Давайте продолжим выполнять процедуру в пошаговом режиме, нажимая F8, чтобы не трассировать код внутри процедур, пока не доберёмся до инструкции RET.

Взлом программ отладчиком OllyDbg

Вот мы и добрались до завершающей инструкции RET, и в верхушке стека снова находится адрес возврата.

Взлом программ отладчиком OllyDbg

Таким образом, можно заключить, что RET обычно является прямой противоположностью CALL, т.е., если CALL вызывает процедуру, RET возвращает управление обратно. RET также удаляет за ненадобностью из стека адрес возврата.

Жмём F7.

Взлом программ отладчиком OllyDbg

и возвращаемся к адресу 40124A. При этом состояние стека становится таким, каким оно было до вызова процедуры.

Взлом программ отладчиком OllyDbg

Стоит добавить, что RET можно использовать не только для завершения текущего CALL, например:
PUSH 401256
RET


Сначала PUSH затолкнёт в стек значение 401256. Далее, следующий за ним RET воспримет это значение как адрес возврата из текущего CALL, хотя это вовсе не так, и передаст управление на адрес 401256. Таким образом, этот код отработает точно также как JMP 401256.

Далее мы рассмотрим ещё один пример использования CALL/RET. Перезагружаем крэкми CrueHead'а. "Go to" - "Expression" - вводим 401364.

Взлом программ отладчиком OllyDbg

По этому адресу нажимаем F2, устанавливая таким образом точку останова (об этом мы подробно поговорим позже). Olly прервёт исполнение как только начнёт выполняться инструкция по адресу, на который установлена точка останова.

Взлом программ отладчиком OllyDbg

Адрес выделяется красным цветом и это значит, что точка останова (BREAKPOINT) установлена. Нажимаем на F9 (RUN), чтобы приложение запустилось...

Взлом программ отладчиком OllyDbg

Появилось окно крэкми. Если Вы его не видите, поищите хорошенько через Alt+Tab :)

Приложение ещё не выполнило код, на который мы поставили точку останова. В окне крэкми вызовите меню и выберите опцию "Help" - "Register".

Взлом программ отладчиком OllyDbg

Появилось окно, через которое нужно ввести имя и серийник.

Взлом программ отладчиком OllyDbg

Пишем что угодно.

Взлом программ отладчиком OllyDbg

Нажимаем OK.

Взлом программ отладчиком OllyDbg

Выскакивает сообщение о том, что нам не повезло, т.е. крэкми не понравились наши имя и серийник (было бы просто удивительно, если бы мы сразу угадали правильные регистрационные данные :-) Если закрыть это сообщение, активизируется наконец наша точка останова.

Взлом программ отладчиком OllyDbg

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

Взлом программ отладчиком OllyDbg

Видим сразу несколько RETURN TO... Видимо, мы находимся внутри процедуры и самый верхний RETURN TO содержит адрес возврата, на который передаст управление ближайший RET. Этот адрес, вероятно, окажется на верхушке стека, перед выполнением RET и управление будет передано на адрес 40124A.

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

Жмём на F8, чтобы добраться до RET, как и раньше. Только в этот раз при выполнении последнего CALL сразу перед RET должно появиться сообщение, которое нужно закрыть, чтобы продолжить трассирование.

Взлом программ отладчиком OllyDbg

Закрываем его.

Взлом программ отладчиком OllyDbg

Вот мы и добрались до инструкции RET и верхушка стека теперь содержит адрес возврата, как мы и предполагали.

Взлом программ отладчиком OllyDbg

В прошлый раз мы выполнили процедуру самостоятельно, принудительно изменив значение EIP. В этот раз мы попали в код процедуры в следствии нормального выполнения программы. Достаточно снова нажать на F9, чтобы программа продолжила выполняться как ни в чём не бывало.

Взлом программ отладчиком OllyDbg

Взлом программ отладчиком OllyDbg

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

Рассмотрим ещё один закрепляющий пример. Для этого нужно перезагрузить крэкми в отладчике, сразу нажать на клавишу пробела и ввести следующую инструкцию: CALL 401245.

Взлом программ отладчиком OllyDbg

Взлом программ отладчиком OllyDbg

Готово. Далее воспользуемся опцией FOLLOW, чтобы попасть во внутрь функции.

Взлом программ отладчиком OllyDbg

Процедура начинается по адресу 401245 и заканчивается по адресу 401288 (где находится инструкция RETN 10, которая немного отличается от знакомого нам уже RET, но об этом позже). Обратите внимание на вложенный CALL (первая инструкция процедуры является вызовом другой процедуры).

Нажмите МИНУС, чтобы выйти из FOLLOW. Теперь нажмите F7, чтобы войти в процедуру, фактически передав на неё управление.

Взлом программ отладчиком OllyDbg

Вот мы и внутри, о чём свидетельствует значение EIP: оно указывает на адрес 401245.

Взлом программ отладчиком OllyDbg

В верхушке стека хранится адрес возврата к следующей за нашим свежевписанным CALL инструкции.

Взлом программ отладчиком OllyDbg

Адрес возврата имеется, но OllyDbg не выделил его как RETURN TO 401005. Чтобы понять почему он в этот раз не проявил сообразительность, нужно принять во внимание, что мы вписали CALL после того, как OllyDbg выполнил предварительный анализ кода. Представьте себе, что OllyDbg - это Чапаев, пересекающий реку верхом :-) Прямо посреди реки мы модифицируем его скакуна, чем, мягко говоря, дезориентируем Василия Ивановича. Точно также в растерянность впадает и OllyDbg. (В общем, OllyDbg в воде не тонет, но пословица тут не при чём - прим. переводчика ;-) )

Чтоб исправить ситуацию, достаточно нажать на правую кнопку мыши в любом месте окна дизассемблера - "Analysis" - "Analyse code". Таким образом, отладчик снова пробежится по коду анализатором и скорректирует подсказки в стековом кадре.

Взлом программ отладчиком OllyDbg

Теперь адрес возврата в верхушке стека корректно распознан анализатором:

Взлом программ отладчиком OllyDbg

Адрес возврата в данном случае обозначен относительно стартовой точки программы: MODULE ENTRY POINT + 5 = 401000 + 5 = 4010005.

В общем, не забывайте запускать анализатор после внесения изменений в код программы (это касается также изменений кода самой программой). Иногда анализ кода может оказаться ошибочным и его следует сбросить опцией "Analysis" - "Remove analysis from module".

Давайте вернёмся к нашему примеру.

Взлом программ отладчиком OllyDbg

Жмём F7 и "погружаемся" в следующий CALL.

Взлом программ отладчиком OllyDbg

Над предыдущим адресом возврата теперь появился ещё один. В общем случае, между адресами возврата вложенных процедур могут находиться произвольные значения, попавшие в стек в результате промежуточных инструкций PUSH и других операций.

Если Вы попадёте в подобную ситуацию, например, в результате срабатывания точки останова, не имея представления о ходе выполнения программы до останова, взглянув на стек можете сориентироваться:

Ниже в окне дизассемблера виден RET, что наталкивает на мысль о том, что мы находимся внутри процедуры.

Взлом программ отладчиком OllyDbg

Смотрим в стек, чтобы удостовериться:

Взлом программ отладчиком OllyDbg

Сверху вниз первый RETURN TO указывает на возможный адрес возврата из текущей процедуры. В данном конкретном случае - это адрес 40124A.

Взлом программ отладчиком OllyDbg

К тому же, ниже есть ещё один RETURN TO, а это может значить, что текущая процедура была вызвана из другой процедуры.

Взлом программ отладчиком OllyDbg

Второй RETURN TO говорит нам, что в конечном итоге программа должна вернуться к адресу 401005 и непосредственно над этим адресом находится CALL, который инициировал всю эту цепочку вызовов. Кстати, вот он:

Взлом программ отладчиком OllyDbg

Привыкайте реконструировать таким образом цепочки вызовов, т.к. в подобной ситуации вместо 2х вложенных процедур может оказаться, например, 30 и трассировать их индивидуально ни у кого не хватит терпения.

Если что-то непонятно - спрашивайте. До следующей главы!

  [C] Рикардо Нарваха, пер. Quantum

Обсуждение статьи: Ассемблер. Процедуры (функции). Крэкинг ч.7 >>>


При перепечатке ссылка на https://exelab.ru обязательна.



Видеокурс ВЗЛОМ