> For the complete documentation index, see [llms.txt](https://backoftut.gitbook.io/intro-cracking-with-ollydbg/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://backoftut.gitbook.io/intro-cracking-with-ollydbg/ch-09.md).

# Глава 9

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

Экспериментировать мы будем, естественно, с уже знакомым нам крэкми Cruehead'а [\[ссылка\]](https://github.com/yutewiyof/intro-cracking-with-ollydbg/blob/master/.gitbook/assets/files/1/ollydbg01-Crackme.7z), но не ограничимся рассмотрением различных способов взлома этого несложного крэкми - по ходу мы постараемся изучить стандартные приёмы, применимые в дальнейшем к более "продвинутым" жертвам.

Итак, давайте загрузим крэкми в отладчик.

На примере данного крекми можно рассмотреть несколько общих понятий.

Точка Входа - адрес инструкции, с которой стартует программа. Не путать с понятием OEP (Original Entry Point), которое мы рассмотрим чуть позже. При загрузке приложения в OllyDbg, отладчик останавливается на точке входа, анализирует код и ждёт дальнейших инструкций от пользователя.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-a0c9561bafa82c3110bfb9546a1140d1a1e421d2%2F0.png?alt=media)

В данном случае точка входа соответствует адресу 401000. Обычно в строке состояния выводится причина, по которой остановлен отладчик. Сейчас там находится сообщение о том, что мы находимся на точке входа:

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-5d71ba6500fa1044c876d88830827c5e47f771e3%2F1.png?alt=media)

Почти все программы на старте останавливаются на точке входа. Есть такие, которые не останавливаются, т.к. используют способы обхода отладчика. Об этих способах мы поговорим позже. Пока что примите к сведению существование подобных приёмов антиотладки.

Давайте, заодно, рассмотрим понятие DLL (динамические библиотеки) и экспортируемые ими функции.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-f96e2cdc9f0c629d74cbaae4094bf6ebf9cd742c%2F2.png?alt=media)

Обратите внимание на выделенную инструкцию. Вместо адреса, вроде CALL 401020, в данном случае указано имя внешней функции:

```
CALL LoadIconA
```

В крайнем правом столбике выводится какая-то дополнительная информация, но что представляет собой LoadIconA?

Операционная система Windows поддерживает так называемые динамические библиотеки (файлы с расширением DLL), которые имеют тот же формат, что и обычные исполнимые файлы EXE. В динамических библиотеках содержатся функции, которые могут быть использованы другими исполняемыми файлами (EXE и DLL). Вместо статического копирования одной и той же функции в несколько экзешников, её можно поместить в DLL, а в экзешниках указать ссылки на эту DLL. Если объём подобных функций велик, получается неплохая экономия на размере экзешников и, что более существенно, расходуемой памяти. Базовые функции для работы с файлами, динамической памятью, процессами и потоками, графикой, звуком, сетью и т.д. и т.п. реализованы в стандартных динамических библиотеках. LoadIconA как раз и является одной из стандартных функций, реализованной в одной из стандартных библиотек - в USER32.DLL. Стандартные функции ещё называют API.

Давайте рассмотрим пример другой API'шной функции - MessageBoxA.

В окне Command Bar вводим: ? MessageBoxA

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-01b9386fcefa2f3b169e896da54b19c9361bd04e%2F3.png?alt=media)

Получаем короткий отчёт, в котором первым делом указан настоящий адрес данной функции. Давайте пройдём по этому адресу, т.е. воспользуемся командой Go to - Expression и введём тот адрес, что выдал нам Command Bar.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-bfda081d54a606058e1f938174613b390323e263%2F4.png?alt=media)

Вводим тот адрес, что выдал Command Bar (у Вас этот адрес может быть другим!)

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-e2072080b96eda6dde806839e94cfb0a34029e86%2F5.png?alt=media)

Если у Вас установлена Windows 9x, этот фокус не сработает, о чём мы подробнее поговорим ниже.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-82380397ba4d6c275d10730c6f74cf2804fd05ca%2F6.png?alt=media)

Сразу видим, что функция принадлежит USER32.DLL, но мы это уже знали, ведь имя DLL обычно указывается вместе с именем функции в дизассемблере (вроде CALL USER32.MessageBoxA). Ещё можно заметить, что MessageBoxA - это обычная функция, которая начинается по текущему адресу и завершается инструкцией RET. Код данной функции находится в библиотеке, а не в экзешнике, что позволяет сэкономить на размере и упрощает работу крэкера :)

Чтоб вернуться к текущей инструкции, достаточно нажать МИНУС. В окне Go to - Expression можно было прямо ввести MessageBoxA.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-f9d12e483d85273574ff88df899bc8547aaadc39%2F7.png?alt=media)

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-ba94cf3c8e99e13f5ab54d3e93273ead158746e8%2F8.png?alt=media)

Вот, мы снова оказались внутри функции MessageBoxA из библиотеки USER32.DLL.

В имени функции важно правильно указывать строчные и прописные буквы (MessageBoxA и messageboxa - разные имена). Как же узнать правильный регистр той или иной буквы?

Нажимаем "МИНУС" - возвращаемся к точке входа.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-dcbe143b3808291b9070d96fd6223dc1e1b4fe40%2F9.png?alt=media)

Правая кнопка мыши в листинге: Search for - Name (label) in current module. Получаем полный список имён API'шных функций, задействованных в данном экзешнике.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-799f37ce2aaa23a4c1c53689b60547d5b1462c6a%2F10.png?alt=media)

Не нужно перечитывать весь список - чтобы найти нужную функцию, достаточно начать набирать её имя. Нажимаем "M":

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-af294a74046b7a5d3e45b3b5c2203b0fc6d8aef5%2F11.png?alt=media)

Курсор позиционируется на первой функции, имя которой начинается на M.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-81b62ad4d68b4a69de9bda8586481f95d40acf7f%2F12.png?alt=media)

В заголовке окна выводятся буквы, по которым осуществляется поиск.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-00e7bb898570039288fb250d16eedf419aa07b03%2F13.png?alt=media)

Правая кнопка мыши по имени функции вызывает меню со следующими опциями:

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-66466983bef039398aaf3c72bd11b4c0f2ad7785%2F14.png?alt=media)

Опция "Follow import in Disassembler" подгружает эту функцию в дизассемблер - это ещё один способ попасть внутрь API'шной функции.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-d606a66952a5045409f8d4a35d9c7f2bc46a078a%2F15.png?alt=media)

Часто новички ошибочно задают поиск символов (Search for - Name (lable) in current module), находясь при этом внутри какой-либо внешней функции. К примеру, если мы воспользуемся данной опцией внутри функции MessageBoxA, мы получим список имён функций, которые импортирует библиотека USER32.DLL, а вовсе не подопытный экзешник. В меню чётко сказано, что поиск осуществляется в текущем модуле (current module), а текущем в данном случае окажется USER32, ведь функция MessageBoxA находится именно в нём.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-b3c5da01c4c0319f19e8318e4dc59f6f9c12ea78%2F16.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-d6491b6c975c2f781616600354a98255342f334b%2F17.png?alt=media)

Даже если мы просто заглянули во внешнюю функцию в дизассемблере, а не передали управление в отладчике, т.е. функция даже не выполняется ещё, текущим модулем всё равно окажется библиотека, в которой находится внешняя функция. В таком случае нужно понажимать на МИНУС пока Вы не окажитесь в "основном" модуле, чтобы воспользоваться такими опциями как Search for - Names и т.п.

## Windows NT: 2000, XP и 2003

Дальнейшее обсуждение касается операционных систем NT: 2000, XP и 2003. Если у Вас мастдай (пардон, тут автор использовал термин Windows 95/98 - прим. пер.), смею порекомендовать перейти на любую из вышеперечисленных осей, т.к. на NT OllyDbg обладает большими возможностями (и глючит меньше - опять прим. пер.) Если такой возможности нет, можете пропустить дальнейшее обсуждение и перейти сразу к "Приложение. Windows 9x"

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-34ec4b355664142542c8cb65a84c9ba4e99ba627%2F18.png?alt=media)

В перечне API'шных функций, которые использует крэкми, есть ещё одна полезная опция в контекстном меню: Toggle breakpoint on import. Данная опция позволяет установить точку останова на вызове функции API.

Точку останова на вызовах конкретной API'шной функции можно установить и через Command Bar:

```
bp MessageBoxA
```

В отличие от bpx, bp ставит точку останова на первой инструкции внутри заданной функции, а не на самих инструкциях вызова (call или jmp) в текущем модуле. Давайте снова зайдём в функцию MessageBoxA (любым из вышеописанных способов) и удостоверимся, что на первой инструкции данной функции появилась точка останова. Так и есть:

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-78a815e2b0bbeae3d36d43a6fc8f057df3f9502e%2F19.png?alt=media)

Таким образом, при вызове функции MessageBoxA, должна сработать точка останова. Давайте нажмём F9, чтобы запустить крэкми.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-cc9870f4297fd8470859a0d37c372eec93e9605a%2F20.png?alt=media)

Появилось главное окно крэкми. В меню выбираем Help - Register:

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-b9a52ca2086174575d36bd2dc62541d26ec360af%2F21.png?alt=media)

Вводим произвольные данные в поля Name и Serial; нажимаем OK. В этот момент должен произойти вызов функции MessageBoxA, который должна зафиксировать наша точка останова... Ага, отладчик прервал выполнение! В правом нижнем углу светится надпись Paused (будто нам и так непонятно, что процесс остановлен - прим. пер.).

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-126f77ef46af15f6b264da3acabe7e9a089f1d42%2F22.png?alt=media)

Левее указана причина, по которой произошла остановка.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-116f3c04ab42d1159f2a453594bccf5a2c86a60a%2F23.png?alt=media)

Там написано: "Breakpoint at USER32.MessageBoxA", что значит "Точка останова на USER32.MessageBoxA". Наша точка останова сработала.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-463b6bd1915e662679a807ed58b42249384434b2%2F24.png?alt=media)

В момент вызова функции можно посмотреть на значения аргументов данной функции. Аргументы API'шных функций обычно передаются через стек справа налево, согласно соглашению stdcall. Давайте рассмотрим их внимательно.

В самом верху стека хранится адрес возврата. В данном случае - 4013C1.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-2615db114f430abff21118696eb90c832bf5c136%2F25.png?alt=media)

Когда мы проходили инструкции CALL и RET в подготовительной части этого цикла (Глава 7), мы имели возможность убедиться, что при вызове любой подпрограммы (т.е. функции) верхушка стека содержит адрес возврата - адрес, на который перейдёт управление, после завершения функции. В данном случае, после завершения MessageBoxA, управление перейдёт на адрес 4013C1.

Далее (т.е. ниже) идут аргументы функции. MessageBoxA принимает 4 аргумента (можете посмотреть описание функции API MessageBox в MSDN, чтобы убедиться): дескриптор родительского окна, текст сообщения, текст заголовка и стиль.

Текст сообщения - "No luck there, mate!" - констатирует, что Вы не угадали правильные параметры регистрации :)

Вот-вот вылезет роковое сообщение...

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-f44e34810b3501d43f01b7cb1a800d0dd30fc0e0%2F26.png?alt=media)

Чтобы убедиться, что текущий вызов MessageBoxA - это тот самый MessageBox, что уведомляет нас о неправильно набранном серийнике, если у Вас есть сомнения... Давайте изолируем текущий вызов, поставив точку останова на инструкции RETN 10h, которую можно найти чуть ниже. Адрес инструкции возврата у Вас, возможно, будет отличаться, но, в любом случае, это должен быть первый RET внутри функции.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-a4ab89ed3d67384a7c860495e6918d64019a58f3%2F27.png?alt=media)

Нажимаем F9.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-42206a0fd988ad4a1378740a76bf1077c47c6ec8%2F28.png?alt=media)

Окно MessageBox появилось на экране. Текст заголовка и сообщения соответствует параметрам функции, которые мы только что перехватили: "Lo luck!" и "No luck there, mate!". Серийник не подошёл :)

Нажимаем "Да" - срабатывает точка останова на RETN 10h.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-47906e5aac3ad438f00f40a0d568a76b32ed318a%2F29.png?alt=media)

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

Чем отличается RETN 10h от обычного RET? Обычный RET просто вернул бы управление на адрес возврата - 4013C1.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-d1a6acf3c70df876a3364561f804b1540e949743%2F30.png?alt=media)

Из стека извлекается адрес возврата. Указатель на верхушку стека перемещается на 4 байта вниз (точнее, в сторону старших адресов). Таким образом, ESP увеличивается на 4 в результате выполнения инструкции RET. В случае с RET 10h, в добавок к тому, что делает обычный RET, ESP увеличивается ещё на 10h. В общей сложности, к значению ESP прибавляется 10h + 4 = 14h = 20. Давайте проверим: нажимаем F7.

Дальнейшее обсуждение касается обоих семейств Windows: 9x и NT.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-595289b73f88d7c71069882b16b79534f4312324%2F31.png?alt=media)

Вот мы и вернулись из API-функции обратно в код крэкми. Обратите внимание, что указатель верхушки стека сдвинулся на 20 байт вниз, как и следовало ожидать, т.е. RETN не просто извлекает из стека адрес возврата, но и очищает аргументы, переданные в функцию, как того требует соглашение stdcall.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-e95e7cec9fb8c13371b503637308de82c1e473ab%2F32.png?alt=media)

В данный момент крэкми уже точно знает, что серийник не верен и даже успел нам об этом сообщить. На данном этапе уже поздно что-либо предпринимать. Нажимаем F9.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-8ce551104cfeebf4ace3517fb576ec270fd5b78a%2F33.png?alt=media)

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-7a8f5250364504ee654eea00736ccbcb77c16818%2F34.png?alt=media)

Снова срабатывает точка останова. Оказывается, крэкми решил снова вывести сообщение о неправильном серийнике, будто мы успели забыть, что серийник не подошёл :)

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-5584a523c24be5b042ad85aa6279b4e3212e3ed0%2F35.png?alt=media)

Адрес возврата на этот раз указывает на 40137D. Давайте посмотрим, что за код находится по этому адресу. Для этого можно воспользоваться опцией Go to - Expression: 40137D. Или прямо по правому щелчку в верхней ячейке стека - Follow in Disassembler.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-4df3f8a43d915dbec93307bda0e7e8a1b150cdf7%2F36.png?alt=media)

Сразу над строчкой по адресу возврата (40137D) находится инструкция CALL, которая вызвала функцию MessageBox (401378).

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-d4c81d7a5a001a1d117ba52aabed9d46bcfbc194%2F37.png?alt=media)

Чуть выше виден другой MessageBox, но с совершенно другим текстом: Great work, mate! Похоже, что это сообщение выскакивает, если серийник оказывается правильным :) Для начала было бы неплохо попасть на тот другой MessageBox, вместо того, что вот-вот покажется на экране.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-3793075c827dce23cc79d85a6e7b537a43dfd81a%2F38.png?alt=media)

Предварительный анализ проделанный отладчиком показывает, что данный код входит в состав функции, о чём свидетельствует жирная скобка в колонке с машинным кодом. Таких функций несколько: одна начинается по адресу 401362 и содержит сообщение "No luck...", другая - "Great work..." и начинается по адресу 40134D.

Если выделить первую строчку функции "No luck..." (по адресу 401362), в окне подсказки покажется следующая информация:

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-f7dee8cdfcc57f03b23309d8a36414d70e5d7fbf%2F39.png?alt=media)

Отладчик в курсе откуда вызывается данная функция, но так бывает только с прямыми вызовами! Щелчёк правой кнопкой мыши - Go to - CALL from 401245.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-f1fb83d320b0ae672bc387cc4a345756193b8b07%2F40.png?alt=media)

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-cbdfb6732032bf7b28cfea93d5df5896b2d13c5a%2F41.png?alt=media)

Занятненько... Перед нами типичный код сравнения некоторого значения, в результате которого вызывается одна из тех двух функций с сообщениями: "No luck..." и "Great work...". Такое нельзя пропускать! Ставим точку останова на условный переход.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-fd417f35b87c02e7850c0ce13c314d062d09dafb%2F42.png?alt=media)

Заодно убираем точки останова на MessageBox. Это можно сделать через окно \[B], т.е. Breakpoints:

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-cd3eeb2cf368035252736d4b89c0ef4caebba611%2F43.png?alt=media)

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-435a06a6c9025aa03e0df5d31e3d9d05ad666a32%2F44.png?alt=media)

Правая кнопка мыши - Remove. Таким образом убираем обе точки останова на MessageBox и оставляем только свежепоставленную точку на том подозрительном условном переходе.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-74cdd083d9ee58126145cdf0c43b8c7faaa8d3b0%2F45.png?alt=media)

Командуем Run (F9), принимаем сообщение "No luck...", которое мы только что трассировали. Снова вводим имя и серийник (используйте те же, что и на снимке).

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-5dc1005853c9b7913d3d11728d2a86c148b87c56%2F46.png?alt=media)

Нажимаем OK.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-d845526e1be5cdcacb3e1d65e0317cd781bea45a%2F47.png?alt=media)

Переход не осуществляется, т.к. предварительное сравнение EAX и EBX обернулось неравенством. Таким образом, выполняется вызов CALL 401362 - там нехорошее сообщение, если кто-то уже забыл. Можете нажать правую кнопку мыши - Follow и освежить память.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-a164f96346f9f1d6ba9f52296383660906f3b206%2F48.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-384355e854419905d608304ae39ae97891b86277%2F49.png?alt=media)

Установленный флаг Z означает, что EAX = EBX, т.е. разность EAX - EBX равна нулю. Переход осуществляется.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-be6abc570aa40a3efbdf1fae7bc0c065f9fca57e%2F50.png?alt=media)

Теперь вызовется другая функция. Смотрим через Follow:

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-4ebde773558d3293bc9f3c2eb67cb7b0cf22aeac%2F51.png?alt=media)

Нажимаем Run (F9) :)))

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-5b4f491df930dfc66e3b96d0a35d24e648f8062c%2F52.png?alt=media)

Значит, то сравнение является ключевым моментом в проверке правильности серийника. Если значения EAX и EBX равны, выскакивает "хорошее" сообщение, иначе выводится "Lo luck...". Раньше мы заметили, что "нехорошие" сообщения в коде имеются в двух экземплярах, но в последний раз выскочило только одно из них. Когда крэкми замечает, что в имени есть цифры (в ricnar456 как раз они есть), сначала выводится одно сообщение, а потом, после ключевого сравнения, выводится ещё одно. Давайте проверим ещё раз.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-087a4055f2c59252cb3586e3cced5055f56c6e1e%2F53.png?alt=media)

Вводим имя, содержащее цифры. Нажимаем OK.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-63ab33758466b7bea36703baf953c9102d216d18%2F54.png?alt=media)

Появляется сообщение о неправильном серийнике и уже ПОСЛЕ этого срабатывает точка останова на условном переходе!

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-688561b4e9fb2aea9c47e022c423c69249dcbc24%2F55.png?alt=media)

Потом появляется окончательное сообщение. Когда мы первый раз остановились на входе в MessageBox (на начальной стадии данного пособия), это был тот первый MessageBox, т.е. не окончательный.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-d1a6acf3c70df876a3364561f804b1540e949743%2F56.png?alt=media)

Адрес возврата соответствовал 4013C1.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-2873943e0d7716273f65429b5cecb03ca939a49e%2F57.png?alt=media)

В окне дизассемблера выделена функция (см. жирную скобку), начинающаяся по адресу 40137E и заканчивающаяся по адресу 4013C1: там находится завершающий RET сразу после вызова MessageBox.

Обратите внимание, что по адресу 4013AC есть стрелочка (>), а это значит, что данный адрес используется в каком-то прямом переходе. Давайте выделим эту строчку, чтобы узнать где находится этот переход.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-1531297fdb9a23e66dabeb239a88fc84ebb364bf%2F58.png?alt=media)

Перед нами ещё одно сравнение и условный переход, который приводит к отображению нехорошего сообщения. Давайте поставим точку останова в этом месте.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-bc9166412fa5d59ff90dfa12bbea955c5e0263ed%2F59.png?alt=media)

Снова пускаем приложение (RUN); принимаем сообщение; опять вводим наши дежурные данные регистрации (имя содержащее цифры!) и опять нажимаем OK.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-f7e934b419c0bf6ab8e0ef788b64c019940ff322%2F60.png?alt=media)

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

На седьмом прохождении цикла (первая цифра в имени ricnar456 - это ‘4’ и занимает 7ую позицию) переход будет осуществлён, но мы этому воспрепятствуем :)

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-cfa70906f897addcaa7945650dab102f0e078461%2F61.png?alt=media)

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-0fe2a5280d451d7c9c28f4ed022e0a5d5e6bb18d%2F62.png?alt=media)

Условный переход JB осуществляется в зависимости от состояния флага C. Делаем двойной щелчёк по этому флагу, чтобы изменить его состояние.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-903b33bc7d46b38baefabc43a5a50a2f39a12db8%2F63.png?alt=media)

Таким образом, переход не будет выполнен. Повторяем фокус с флагом для 2х оставшихся цифер, чтобы не сработал этот переход.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-1a6c50ae1e814f4294344e634361cae1d39316b5%2F64.png?alt=media)

Далее мы попадаем на сравнение EAX и EBX, где нужно повлиять на флаг Z, как в прошлый раз, чтобы переход осуществился.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-e28625501694e2488325a5782536783da9dccf6e%2F65.png?alt=media)

Нажимаем F9.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-54877c4937b06992e52ab79ff1b4d963449bc451%2F66.png?alt=media)

Не будем же мы всё время ручками менять флаги C и Z?! Настало время рассмотреть каким образом это дело можно зафиксировать, чтобы крэкми безропотно принимал любой серийник, причём вне отладчика.

Выделяем первый условный переход (где мы поставили точку останова).

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-465b02c709046f19de5182fbc65c26ce4d28c6ec%2F67.png?alt=media)

Чтоб этот переход не выполнялся никогда, независимо от состояния флага C, его можно просто и грубо забить инструкциями NOP. Нажимаем на данном переходе пробел и вводим NOP.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-943b0e8ab9cb0f42dd1f2fdcca79e4dd6c497f93%2F68.png?alt=media)

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-e86b127121a5fefba073173b268e7ad79d1ba438%2F69.png?alt=media)

Точку останова уже можно убрать. Для этого достаточно нажать F2.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-ae97802d7622eee09e16d3c7c457afadf9b49578%2F70.png?alt=media)

Идём ко второму ключевому условному переходу.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-cfb935ab0126cd59bcf743bcc6dbaad4bd0ced13%2F71.png?alt=media)

В данном случае нам нужно, чтобы переход всегда выполнялся. Для этого его можно сделать безусловным, т.е. поменять JE на JMP.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-30737946cccbc1a00ba9420061b63bba0926942f%2F72.png?alt=media)

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-1971e09276ae71e5aa8d72fa9b38dc1b9c767001%2F73.png?alt=media)

Давайте снимем и эту точку останова (F2). Пока ещё не выходим из OllyDbg! Чтобы опробовать в свободном полёте наши достижения, нажимаем F9.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-d01f72240468abd550a944255ac83db6663a2bbf%2F74.png?alt=media)

Нажимаем OK.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-35a6bcb7b9c9c9ab891a0252d401fe2db8b73de6%2F75.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-0f735aac69efcb6572b2194499b56bb7d35387ed%2F76.png?alt=media)

Правый щелчёк в любом месте листинга - Copy to executable - All modifications. Далее выводится следующий запрос:

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-ad0891e45b9bd2df46e1931651600954703b961b%2F77.png?alt=media)

Выбираем опцию Copy all чтобы перенести все изменения (в данном случае ими являются двойной NOP и один JMP).

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-d97efe0348c8636ee1c4b220ce890b6e6c05a5dc%2F78.png?alt=media)

Открывается новое окно, в котором нужно опять сделать правый щелчёк - Save file.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-2fe5dc61a80d61d415cf0bb2257c8c3c83367a6c%2F79.png?alt=media)

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-8bb86bcb0346b4e01dad8ac3bb630181444f55c4%2F80.png?alt=media)

Сохраняем файл под НОВЫМ именем (старый экзешник нам ещё пригодится, да и перезаписать его всё равно не получится, т.к. он всё ещё загружен операционной системой). Назовём новый экзешник CRACKME2.EXE.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-663455d51670f98c78caf429249c43619c30e04b%2F81.png?alt=media)

Вот, теперь можно, наконец, закрыть OllyDbg.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-6e123792a68d5c915becd785209f8c36e601daed%2F82.png?alt=media)

Запускаем новую версию крэкми (уже вне отладчика) и проверяем, что регистрация проходит успешно при указании любого серийника.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-6232a30f3a871bb4da250383d79eb7825179dd24%2F83.png?alt=media) Выбераем Help - Register:

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-e3774864797e79e0156ce325df548505b5c42de7%2F84.png?alt=media) Нажимаем OK.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-8bf487de27d3aad529af8a05b11169a848d331f8%2F85.png?alt=media)

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

Приложение. Windows 9x

В мастдае возможности отладчика ограничены. К примеру, нельзя ставить точки останова прямо на вызовы API-функций, как было показано на примере MessageBox в NT/XP. При выполнении поиска API-функций по импорту:

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-3d38d5efc731dc912d2d373f9433c2c3a40cdc7b%2F86.png?alt=media)

Получаем аналогичный список импортируемых символов, но опция Toggle breakpoint on import не будет доступна, т.к. 9x не позволяет ставить точки останова прямо на внешние функции.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-96848c864f3143d3366a4090cd23f282431e08c5%2F87.png?alt=media)

В остальном, контекстное меню будет сходным с полнофункциональным вариантом в NT.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-fe358325450da89be9e3a2a51ce0e0a3f60a5859%2F88.png?alt=media)

Таким образом, вызовы API-функций могут идти в обход точек останова. Достаточно вызвать функцию косвенным образом, чтобы анализатор не смог его автоматически засечь, и точка останова уже не сработает. Досадное ограничение, в общем.

Вместо одной точки останова на начало функции MessageBox в данном случае Вам придётся поставить 3 точки останова (F2): по одной на каждый вызов MessageBox, которые выводятся в списке внешних символов.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-7f1250c765e9e08cafe1cc2aa83249a8d72d6e7f%2F89.png?alt=media)

Нажимаем Run (F9); выбираем опцию Help - Register; вводим следующие регистрационные данные:

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-e5f6a005a36a463a2d1574f21eabfb6189e564d0%2F90.png?alt=media)

Нажимаем OK - срабатывает одна из точек останова.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-d74c06db101b62070daba97416a343f53a27ad5c%2F91.png?alt=media)

В NT/XP в этом месте мы ставили ещё одну точку останова на инструкции RET, внутри функции MessageBox. В 9х мы это не можем сделать, т.к. внутрь функции нас не пускают. Поэтому ограничимся точкой останова на следующей после CALL инструкции, т.е. уже после возвращения из функции.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-7a896a53401ef90589a1e7ab9652a45d017628ec%2F92.png?alt=media)

Аналогично поступаем в любой подобной ситуации по ходу развития учебного цикла. В 9х вместо точек останова на обращениях к внешим функциям, их приходится ставить на ссылки в конкретных вызовах. Теперь можете вернуться к основному материалу статьи , где написано:

Дальнейшее обсуждение касается обоих семейств Windows: 9x и NT.

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