> For the complete documentation index, see [llms.txt](https://backoftut.gitbook.io/intro-cracking-with-ollydbg-2/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-2/ch-15.md).

# Глава 15

Прежде, чем перейти к последнему из крэкми с жёстко заданными серийными номерами, рассмотрим тот, который я оставил вам в прошлый раз для самостоятельной работы. Он назывался SPLISH [\[ссылка\]](https://github.com/yutewiyof/intro-cracking-with-ollydbg/tree/3679d233f4d394747f712e9b6b09bc9c2a3cad80/.gitbook/assets/files/14/Splish.7z).

Откроем его в OllyDbg.

![](/files/-LmvTvhS7k3FhqmtNJsZ)

Он открывается на точке входа (ENTRY POINT).

Смотрим используемые API-функции (правая кнопка мыши - SEARCH FOR-NAME (LABEL) IN CURRENT MODULE).

![](/files/-LmvTvhkbcb3vcw11Kat)

Видим список используемых API-функций.

![](/files/-LmvTvhtVlAq7SKoI_Mj)

Видим, что используется GetWindowTextA при вводе серийного номера и MessageBoxA для отображения сообщения, правилен ли он или нет. Можем установить BPX на обе функции, но сначала ещё глянем, что покажет список строк, используемых программой.

![](/files/-LmvTvi1eCormWlcWub3)

Кликаем правой кнопкой мыши на листинге и выбираем SEARCH FOR-ALL REFERENCED TEXT STRING.

![](/files/-LmvTviAgR5mBf0WoZMt)

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

Попадаем в область, где ведётся работа с серийным номером.

![](/files/-LmvTviJENoEuKnvfQtB)

Видим ввод текста с помощью функции GetWindowTextA и два MessageBoxA с разным текстом: правилен ли серийный номер или нет.

Ставим здесь на вызов API-функции GetWindowTextA BPX, чтобы начать с того места, где вводится серийный номер.

![](/files/-LmvTviULTx9hRJZDKX7)

Запускаем крэкми с помощью F9 или RUN.

![](/files/-LmvTvicysuNBpqr5KZx)

Так как пока что мы можем решить только ту часть, которая относится к жёстко заданным серийным номерам, пишем в поле HARDCODED, которое находится наверху, неверный серийник или нажимаем на кнопку CHECK HARDCODED.

![](/files/-LmvTvilP9RAEyHwm7xw)

Останавливаемся на BPX, установленный ранее.

![](/files/-LmvTviuhJSjk8R2J1Y6)

Пояснения показывают нам, что находится в стеке и это даёт нам сразу понять, что буфер, в котором будет сохранён введенный серийный номер, находится по адресу 403215.

![](/files/-LmvTvj4XgCqYqp6mNDr)

Посмотрим через DUMP, что находится в буфере.

![](/files/-LmvTvjCAh3hDWlO6nt_)

![](/files/-LmvTvjLdjMHnpt8BOFb)

Вот этот буфер, куда будет сохранён введённый серийный номер. Нажимаем F8, чтобы выполнить вызов API-функции.

![](/files/-LmvTvjVRWvtQW4jqb6S)

Так как использовали F8, выполняется вся функция, так что неправильный серийник уже находится в буфере.

![](/files/-LmvTvjdN_FcWdfdXlil)

Ок, следующая строка переместит 401353 в EAX (помните, что LEA не перемещает содержимое ячейки памяти по заданному адресу, а только результат того, что находится в квадратных скобках; в данном случае это будет 401353). Видим в DUMP’е, что по вышеуказанному адресу (кликаем на строке правой кнопкой мыши и выбираем FOLLOW IN DUMP-MEMORY ADDRESS, и это нам покажет, что находится по адресу 401353).

![](/files/-LmvTvjmGZL01E50ev0E)

По адресу 401353 находится строка "HARDCODED"; нажимаем F7, чтобы выполнилась LEA.

![](/files/-LmvTvjwUKNWqge6Ll7f)

После выполнения в EAX остаётся 401353, а с правой стороны появляется пояснение, что данный адресу указывает на строку "HARDCODED".

![](/files/-LmvTvk4Ijw4rIyH9PmX)

Следующая строка загружает в EBX другой адрес, в данному случае это 403215.

![](/files/-LmvTvkA6T66WKsbdmNM)

После нажатия F7 EBX содержит значение 403215.

![](/files/-LmvTvkMQxfRAcUOzT3q)

И справа Олли показывает нам, что этот адрес указывает на строку "98989898", являющуюся введёнными нами неправильным серийным номером, который мы посмотрим в DUMP’е так же, как сделали это для предыдущей инструкции.

![](/files/-LmvTvkW9eq56vuhW-XM)

Здесь 403215 указывает на наш неправильный серийный номер.

![](/files/-LmvTvkekUedp-jDPs7J)

![](/files/-LmvTvkqoUc9vXXp29Ab)

Следующая строка проверяет, равен ли нулю первый байт содержимого EAX, который равен 401353.

![](/files/-LmvTvl1hnZBTq_NG4RZ)

Так как мы уже смотрели содержимое по этому адресу через DUMP, то уже знаем, что там находятся байты строки "HARDCODED".

![](/files/-LmvTvlC4rddEUGy_xwS)

Первый байт в данном случае равен 48, пояснения OllyDbg нам также говорят, что это соответствует символу "H" в кодировке ASCII, а это первая буква слова "HARDCODED". Так как это не ноль, то продолжаем.

![](/files/-LmvTvlKyWkwwQ5HLhrp)

Так как сравнение не активирует флаг Z (операнды не равны друг другу), JE не совершает перехода (помните, что JE срабатывает только тогда, когда активируется флаг Z),

Нажимаем на F7 и продолжаем.

![](/files/-LmvTvlb-h2Ut5QzrTp3)

Здесь очень хорошо видно, что сначала будет перемещён первый байт \[EAX], равный 48, что соотвтествует слову "HARDCODED", а на следующей строке перемещается \[EBX], являющийся первым байтом неправильного серийного номера, после чего оба сравниваются и если они не равны, то происходит переход на 4013D2, где выводится сообщение "SORRY, PLEASE TRY AGAIN".

Проверим это следующим образом.

Нажмём F7 и переместим в CL значение 48.

![](/files/-LmvTvlkHeBfSkzOCyB7)

CL, как мы помним, это регистр, соответствующий двум последним цифрам ECX, здесь перемещаем 48, и вот, что получится в результате.

![](/files/-LmvTvlxrPdmBwBWxPpz)

Затем в DL перемещается первый байт неправильного серийного номера.

![](/files/-LmvTvm3NLjTzqXsjX5L)

Выполним строку с помощью F7, видим, что в DL находится значение 39.

![](/files/-LmvTvmCI0Cg9rNBnKrL)

Теперь CL сравнивается с DL.

![](/files/-LmvTvmLC4v6jHveiV28)

Пояснение OllyDbg не оставляет сомнение: сравнивается 39 (что есть 9, т.е. первый символ введённого мной серийного номера с H, являющейся первым символом строки "HARDCODED").

![](/files/-LmvTvmUpsRSLRzaXUF-)

![](/files/-LmvTvmc19JHrDUteGds)

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

![](/files/-LmvTvmmHW-y9NulpoVm)

Теперь Z равен 1, как если бы в сравнении двух байтов они были равны и их вычитание друг от друга дало бы ноль, активировав данный флаг.

![](/files/-LmvTvmvZjfwazRAbCnk)

Видим, что в этом случае происходит увеличение EAX и EBX и переход с помощью JMP на начало цикла.

![](/files/-LmvTvn7EEsk1SePCi9T)

Теперь EAX указывает на второй байт строки "HARDCODED" и видим, что цикл повторяет побайтовое сравнение, пока \[EAX] не будет указывать на ноль, то есть пока не завершится строка "HARDCODED" (в конце строки за последним символом находится ноль).

Тогда, после увеличения значения EAX и EBX на 1, будут считаны и сравнены друг с другом вторые байты, если равны, то цикл повторится, но уже будут рассматриваться третьи байты, а когда слово "HARDCODED" закончится, то если все сравнения на равенство CL с DL прошли успешно, перехода на окошко с ошибкой не произойдёт и попадём вот куда:

![](/files/-LmvTvnHLwmV6ZJ1C6wQ)

Здесь EAX указывает не на какой-либо из байтов слова "HARDCODED", а на ноль, так как строка уже закончилась.

![](/files/-LmvTvnRVPOVRY3QZ_FA)

Вот и тот самый ноль, а это значит, что сработает соответствующая проверка.

![](/files/-LmvTvn_1HEVa2TyhBG7)

Срабатывает JE и мы выходим из цикла.

![](/files/-LmvTvnhTbodUulDAXxb)

И попадаем в то место, где отображается сообщение о правильно введённом номере (так как поменяли значение флага Z при побайтовом сравнении, хе-хе).

![](/files/-LmvTvnoBXWiTRQ33KwI)

Очевидно, что менять значение флага Z пришлось при каждом сравнении CL с DL, чтобы программа поверила в одинаковость обоих серийников и не перешла на сообщение об ошибке и не вышла, но в любом случае мы теперь знаем, что правильный серийный номер – это слово "HardCoded" (с соблюдением прописных и строчных букв, так как у них разный ASCII-код).

![](/files/-LmvTvnwezR68OuvMkT9)

Уберём все точки останова, введём найденный серийный номер и нажмём кнопку "CHECK HARDCODED".

![](/files/-LmvTvo2MMR8EZUz6mVj)

Ещё одна победа, поздравляю.

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

Алгоритм следующего крэкми, который называется SAMBO [\[ссылка\]](https://github.com/yutewiyof/intro-cracking-with-ollydbg/tree/3679d233f4d394747f712e9b6b09bc9c2a3cad80/.gitbook/assets/files/15/SamBo.7z), отличается от предыдущих. Откроем его в OllyDbg.

![](/files/-LmvTvoBzl9ypYZ3Okyi)

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

Соглашаемся с предупреждением OllyDbg и прибываем в EP.

![](/files/-LmvTvoJVZA3yBkT5C00)

С помощью ещё одного окошка OllyDbg сообщает нам, что программа, возможно, запакована или зашифрована, поэтому анализ её будет настолько же неэффективным, как пепельница в мотоцикле, так как программа будет распаковывать себя во время выполнения, поэтому пока что выберем "Нет".

![](/files/-LmvTvoSkeEzQmtZf6YT)

Уже на первых строках листинга мы можем заметить, что этот крэкми выполняется не так, как его не запакованные сородичи, чья первая секция начинается с 401000.

Здесь точка входа равна 4d4001.

![](/files/-LmvTvo_lTO2bj_hEc3U)

Посмотрим, является ли секция исполняемой, для этого идём VIEW-MEMORY или нажмём клавишу M.

![](/files/-LmvTvoiZ70SUdW7AD8l)

![](/files/-LmvTvove3UYOMJFltzo)

Видим, что программа стартует в секции, начинающейся с 4D4000, размер которой равен 2000 (в шестнадцатеричной системе), и поэтому 4d4001 – это адрес, который относится к данной секции.

Это и есть то, о чём говорила OllyDbg – точка входа находится за пределами секции code.

![](/files/-LmvTvp9cVLo93a7LPea)

Секция CODE начинается с 401000, а выполнение начинается с адреса 4D4001, который относится к другой секции. OllyDbg нам сообщила, что это характеристика многих запакованных программ.

Секция, в которой находится точка входа, соответствует распаковщику, и как только он отработает и сделает то, что должен сделать, он сделает переход на секцию code, где и будет выполнена сама программа.

А раз так, нажимаем F9.

![](/files/-LmvTvpImwOdlVUoh6jt)

Мы уже знаем, что когда появится окошко крэкми для ввода серийника, программа уже распакована в памяти и выполняется в секции code, поэтому можем установить на эту секцию BPM ON ACCESS , чтобы остановить выполнение на её первой строке.

![](/files/-LmvTvpTidFB59cFNWp3)

При попытке вернуться в окошко крэкми OllyDbg остановится в секции code (т.е. первой секции после PE-заголовка).

![](/files/-LmvTvpjBhOYxinridAf)

Видим, что теперь программа распакована в памяти, можем её анализировать. Кликнем правую кнопку мыши в листинге.

![](/files/-LmvTvpw4TVPGgJopJNU)

![](/files/-LmvTvqDhwWudnrxvtsE)

Видим, что OllyDbg прекрасно показывает нам проанализированный код.

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

![](/files/-LmvTvqNRTWqM-dh6IMD)

![](/files/-LmvTvqWhSWDsU9kkniK)

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

![](/files/-LmvTvqeLFrURKyXPvuA)

Ещё один ужасный список.

![](/files/-LmvTvqmnsIRIc4__uZE)

"YOU DID IT" – одна из строк с поздравлением.

![](/files/-LmvTvqvCgrAsG4BONoU)

Хорошо, есть сравнение и переход, где мы видим строки с поздравлением и ошибкой, хотя здесь и нет MessageBoxA.

![](/files/-LmvTvr35zF3sfxJeD0W)

Устанавливаем BPX на условный переход, чтобы проверить, решающий ли это переход, и убираем BPM ON ACCESS щелчком правой кнопки мыши.

![](/files/-LmvTvrC1odAdL_1TaCb)

И делаем RUN.

![](/files/-LmvTvrN4ZW7UzbxrWUq)

В окне крэкми вводим "Narvajita" или любой другой неправильный серийный номер.

Нажимаем кнопку "Test-o-Doom".

![](/files/-LmvTvrWIbAQc6uJIx4Z)

Видим, что произошёл переход, нажимаем F9.

![](/files/-LmvTvrf43Z5SHWhtkH_)

Тогда соглашаемся с окошком с поздравлением, что у нас получилось.

![](/files/-LmvTvrpMkyDVLH170ew)

Оно говорит, что это была шутка, и ничего не вышло на самом деле, ха ха! Делаем RUN по-новой и снова прибываем к переходу, связанному с кнопкой "Test-o-Doom".

![](/files/-LmvTvry3DK2qEF_GS8i)

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

![](/files/-LmvTvsDh24j-t-YCKHC)

После двойного щелчка на флаге Z и изменения его значения, делаем RUN.

![](/files/-LmvTvsKxnlewaYajDOR)

И отображается окошко с поздравлением, значит, это и есть то место, где решается правильность или неправильность серийного номера. Посмотрим сравнение до перехода.

![](/files/-LmvTvsS5sZNFZcY5XxA)

Это TEST CL, CL, где проверяется, равен ли CL нулю или единице, что задаётся где-то до этого, возможно в CALL, вызываемый ранее, на который мы можем поставить BPX.

![](/files/-LmvTvsaIg3C1xAmJZKA)

Делаем RUN, возвращаемся в окно и снова нажимаем кнопку Test, чтобы остановиться на CALL.

Остановившись, осмотримся любопытным взором вокруг, хе-хе.

![](/files/-LmvTvsi9_35ml5qyc4x)

Если посмотрим в стек, то увидим введённый неправильный серийный номер, заглянем в DUMP (через FOLLOW IN DUMP).

![](/files/-LmvTvsr5G3F0a95KrVx)

![](/files/-LmvTvt-Fr9KbYkiNcEA)

Мой глаз крэкера видит здесь строку, которая, возможно, является верным серийником; могли бы посмотреть, так ли это, но пока делать этого не будем и продолжим поиск серьёзным образом.

Если внутри данного CALL производятся какие-либо сравнения или операции с неправильным серийником, то можно установить BPX ON ACCESS на него, чтобы программа остановилась, когда с ним будет что-нибудь делаться, то есть на какой-либо операции или сравнении.

![](/files/-LmvTvt7HPILPb3fhslm)

Выделим неправильный серийный номер, нажмём правую кнопку мыши и выберем BREAKPOINT-MEMORY ON ACCESS.

![](/files/-LmvTvtGrrTApZusB-zV)

После этого, когда продолжим выполнение, то если внутри call происходит какая-либо работа с этим серийником, OllyDbg остановится.

Нажимаем F9.

Видим, что остановки не произошло, возможно, сравнение происходит раньше, так что мы можем поставить точки останова на CALL'ы, находящиеся ещё выше, и повторить то, что делали прежде, но лучше пустим в ход другой способ остановиться на том месте, где вводится серийный номер: здесь не используется API-функция GetWindowTextA, но у нас есть сообщения Windows, которые послужат нам не хуже.

Убираем BPM ON ACCESS.

![](/files/-LmvTvtPKi7pCIvT11aA)

Ставим быстрым способом BP TranslateMessage.

![](/files/-LmvTvtZ0im4EOpxgwCX)

А теперь RUN.

![](/files/-LmvTvtga59U2c-b4qrr)

Остановившись на API-функции, нажимаем на правую кнопку мыши и выбираем:

![](/files/-LmvTvtoeB1tUBFo6dRh)

![](/files/-LmvTvtwpt3kyDsV3d_8)

И в окошке печатаем условие MSG==202, которое является значением WM\_LBUTTONUP.

И устанавливаем переключатели так, чтобы остановка происходила по ON CONDITION, и чтобы логгировалось всё.

![](/files/-LmvTvu24pG-HmdTb_Ad)

Здесь розовым цветом обозначен BPX CONDICIONAL. Делаем RUN.

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

![](/files/-LmvTvuAxaVOpbARrmWt)

И по нажатию на кнопку срабатывает BPX CONDICIONAL.

![](/files/-LmvTvuJ16FoJW8gjjcx)

Остановка произошла на WM\_LBUTTONUP.

Возвращаемся в программу с помощью EXECUTE TILL RETURN.

![](/files/-LmvTvuVgyxd0Pr3ils3)

![](/files/-LmvTvuetT4CP-3Edf8y)

Нажимаем F7 и возвращаемся в программу.

![](/files/-LmvTvunQggJwF9I80Z6)

Здесь у меня появляется две возможности. Установить BPM ON ACCESS в первой секции, чтобы сделать переход с помощью F9 и посмотреть, куда ведёт процедура сравнения серийного номера, что мне кажется сложноватым, так как я уже видел, что эта процедура весьма большая.

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

![](/files/-LmvTvuxeD6a3XfLKDQB)

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

![](/files/-LmvTvv6QFGttTOrngF9)

В появившемся окне в поле ASCII введём наш неправильный серийник.

![](/files/-LmvTvvDhcd3C_jj3gZz)

Нажимаем OK, чтобы начать поиск в памяти.

![](/files/-LmvTvvKW6__VCh13WeK)

С помощью CTRL+L можно искать остальные вхождения этого слова, но больше ничего не находим ни в секции, которую мы открыли, ни в остальной памяти.

![](/files/-LmvTvvThzPVaxIU5tzE)

Устанавливаем BPM ON ACCESS на этот неправильный серийник, чтобы найти момент, когда с ним производятся какие-либо операции, чтение или сравнение.

И нажимаем F9.

![](/files/-LmvTvvao8nUQRBuqiME)

Останавливаемся там, где он копируется в то место, которое мы видели в последнем CALL’е.

![](/files/-LmvTvvjuYaeLQRhE_Jc)

Мы знаем, что REP MOVS копирует содержимое из ESI в EDI, так что посмотрим EDI в DUMP (правая кнопка мыши на EDI-FOLLOW IN DUMP).

![](/files/-LmvTvvsaB7welS-Uh5H)

![](/files/-LmvTvw-EiOIBXX0t0bU)

Сюда REP MOVS скопирует серийник, нажмём F8, чтобы он это сделал.

![](/files/-LmvTvwDVoY-YfJi87OP)

Оказались после этого на RET, серийник полностью скопировался, и устанавливаем на него BPM ON ACCESS.

![](/files/-LmvTvwNyEfGRPldXpFF)

Выполнив RUN, останавливаемся здесь.

![](/files/-LmvTvwVOcuHtsJDtyD1)

Точнёхонько на сравнение, хех.

![](/files/-LmvTvwct7CXNKeKtjPh)

ESI указывает на мой неправильный серийник, а EDI на правильный, который равен "1556555".

Убираем все BPX.

![](/files/-LmvTvwnvY_sg3VC9u6f)

![](/files/-LmvTvwv8v2IKsXnhb5_)

![](/files/-LmvTvx2Uf5lT-4-kpS3)

![](/files/-LmvTvxHXbC4LUh92cHN)

Появляется окошко с поздравлением.

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

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