Введение в крэкинг с нуля, используя OllyDbg - Глава 16

  • На форуме работает ручное одобрение пользователей. Это значит, что, если Ваша причина регистрации не соответствует тематике форума, а также Вы используете временную почту, Ваша учётная запись будет отклонена без возможности повторной регистрации. В дальнейшем - пожизненная блокировка обоих аккаунтов за создание мультиаккаунта.
  • Мы обновили Tor зеркало до v3!
    Для входа используйте следующий url: darkv3nw2...bzad.onion/
  • Мы вновь вернули telegram чат форуму, вступайте, общайтесь, задавайте любые вопросы как администрации, так и пользователям!
    Ссылка: https://t.me/chat_dark_time

AnGel

Администратор
Команда форума

AnGel

Администратор
Команда форума
27 Авг 2015
3,411
2,025
В этой части мы начнём разбор крэкми, которые отличаются от предыдущих тем, что серийный номер является переменным и высчитывается на основе имени, которое мы вводим.

Способ его решения очень похож, но рассмотрим несколько примеров, чтобы всё стало понятным.

Начнём с поиска правильного серийного номера в крэкми CrueHead’а.

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

d9441349f93426db106306787778b40e.png

Мы находимся на точке входа.

Смотрим, какие API-функции используются для получения введённого серийного номера.

0fa4b145bec1e01a86e3e0ee97ad7006.png

Попробуем установить BP на указанной функции, чтобы остановиться на том месте, где будет считываться имя и серийный номер.

1bdcfb54664e0bf4f32f6c3f8d0078ce.png

Делаем RUN.

d15826ebb5b29c19fb64b1cf84e655aa.png

После нажатия на OK оказываемся на api-функции и в стеке видим параметры.

a13641c3788069987765fe165421d671.png

49e3e517a39bcc028742ad764c161af5.png

10f19db1f4dd9c9e01111e8783da8437.png

Буфер, в котором сохраняется введённый текст, начинается с 40218E, посмотрим через DUMP, что там находится – правый клик мыши и FOLLOW IN DUMP на строке, где приводится информация о буфере.

946c24afac5c020ad5013cd033d54679.png

Здесь ничего нет, потому что API-функция ещё не выполнилась, так что выполняем DEBUG-EXECUTE TILL RETURN, и когда оказываемся на RET, нажимаем F7, чтобы вернуться в программу.

50fc20a061be82512d855e855a4c7983.png

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

1174a0a3a57482b502686c7cb5fc6fb7.png

Встречаем ту же API-функцию во второй раз. Здесь используется новый буфер, куда помещается введённый серийник. Посмотрим его через дамп.

d72f268d2f4a278ea31a7782903a0192.png

То же самое, что и в прошлый раз; выполняем API-функцию с помощью EXECUTE TILL RETURN, а чтобы вернуться в программу, нажмём F7.

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

0e774bf34368bdcbf932dcbf4640ca14.png

Отметим нужные байты, правый клик – BREAKPOINT – MEMORY ON ACCESS, и RUN.

1e442a80aeb098bdd80af8745f6a0114.png

Видим, что остановка произошла там, где программа считывает первый байт неправильного серийного номера и перемещает его в BL. Нажимаем F7.

66a0bd7d0df869405517fe73389e4ed3.png В BL находится 39 – значение первого байта. Нам нужно отловить, что программа делает с ним и, по возможности, записать, какие математические действия программа над ним совершает.

4b82e3f69f0512c8051f4af0ec60ae0f.png

Здесь делается проверка на то, равен ли он нулю, если да – это конец строки и произойдёт выход из цикла.

55cfee5bb7ae4b2a1955a93d6497ec93.png

Так как нулю первый байт не равен, то перехода не происходит и попадаем на SUB BL, 30.

d70f92af2ef13d7c5d01d2b4a272bb89.png

После того, как было вычтено 30, в BL осталось 9.

На следующей строке EDI умножается на EAX.

fe41685314eb0ab8a2246b4e3b84c016.png s

Эти регистры были инициализированы следующими значениями: в начале процедуры в EAX было помещено 0A, а EDI до входа в цикл приравнен к нулю с помощью инструкции XOR EDI, EDI.

7d58790e856b34100b45584d2ab69045.png

9db7ccb702996175c0b960020ebe346e.png



По нажатию F7, как мы помним, исходя из определения инструкции IMUL с двумя операндами, в данном случае, они будут умножены с учётом знака, а результат сохранён в первый операнд, т.е. в EDI.

a7281e8d47530c49b521e2b28ffeee32.png

Таким образом, в EDI остаётся ноль, ставший результатом выполнения предыдущей операции.

4f5aac4dff379696410ded9146189f49.png

Дальше идёт сложение EDI со значением в EBX.

24a2f490ed0fa02f4fdce299858a00ad.png



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

22a11e83a8f949df55590d66ad54e00a.png

После это в AL снова помещается значение 0A, прочитывается следующий байт неправильного серийного номера (это будет 38), проверяется, равно ли оно нулю, из него вычитается 30 и прибываем в IMUL.

dbc0e8c3b26ed833c155bbbe99ed8a22.png

Видим, что умножается EDI, в котором осталось значение ещё с прошлого пробега цикла, на 0A, а результат помещается в EDI же.

381f483fdf2dd13629653e5749d80bcc.png

Теперь EDI содержит 5A, а на следующей строке он складывается с EBX.

f679db3361fccb7384d2e3e6a90f290b.png

То есть результат всех производящихся операций накапливается в EDI; тем, кто усерден и прилежен на ниве крэкинга, уже ясно, что происходит. Объясним.

8424d1a3837b31ebce9580587c6f2c8b.png

Достаточно установить точку останова на выход из цикла: нажимаем F9 и, когда происходит остановка, видим, чему равен EDI.

28dcd73d26d07649d7383a63b48cd214.png

Если кликнем два раза на EDI.

3efec6826cc9ee4f064ec6842290745f.png Значение EDI – значение шестнадцатеричное, во втором поле видим его же в десятеричной системе счисления, и это значение соответствует серийному номеру, введённому мной, т.е. после выхода из цикла в EDI содержится серийник в шестнадцатеричном виде.

Т.е. резюмируя кратко: если напечатаем слово 98989898, оно будет трансформировано в десятеричное число 98989898 или шестнадцатеричное 5E6774A.

18370b1ccff7ec66ad3c286521c2ae6e.png

На следующей строке EDI xor’ится с 1234.

714646c6186a5941b8a9c70c843f006d.png

В результате получается 5E6657E, которое перемещается в EBX, а затем мы прибываем в RET.

0601bff6f0fc18ec0d8217a4ea0d9398.png

Видим, что выйдя через RET, мы оказались у сравнения EAX с EBX, то есть туда, где находится переход, решающий, правилен или нет серийный номер.

c02c1a37347b3aebf6a5dc281340b540.png

688f3dae3bc90f1d4d883821d4f650ac.png



И видим, что сравнивается вычисленное значение, находящееся в EBX с EAX, который содержит 547B.

Так как EAX определяется программой, а EBX – высчитывается, то очевидно, что поскольку мой серийный номер неверен, то и значения этих регистров не будет равно.

Если EBX был бы равен EAX, то программа сделала бы нужный переход, поэтому нам нужно проанализировать, отчего произошло неравенство регистров.

Смотрим сделанные нами заметки.

EBX= (Шестнадцатиричное значение неверного серийного номера) XOR 1234

Мне нужно, чтобы EBX был равен EAX, тогда проверка на равенство выдаст нужный результат.

Если EAX=EBX

Reemplazo EBX por EAX ya que son iguales

Заменим EBX на EAX, то есть чтобы они были равны.

EAX=(Шестнадцатиричное значение правильного серийного номера) XOR 1234

При выполнении этого условия введенный серийный номер будет верным.

Переформулируем.

EAX XOR 1234= (Шестнадцатиричное значение правильного серийного номера)

И поскольку в EAX есть значение (547B), то можем заменить на него EAX.

547B XOR 1234 = (Шестнадцатеричное значение правильного серийника)

Если посчитаем результат операции XOR:

464F = (Шестнадцатеричное значение правильного серийника)

Если 464F – это шестнадцатеричное значение, то соответствующее десятеричное, которое нужно ввести, будет:

b66598a30a5b7e65693d89940529e3d8.png

Переводим в десятеричную систему.

9611c6d6456955711d17ece918029544.png

Это и есть правильный серийный номер для имени “narvaja”. Убираем все BPM и BP.

2a7dae4a412f07622886df99e2067faa.png

Нажимаем OK.

ad3e2dfdf160eb3a28e89735d17bc01f.png

Так мы получили серийник для моего имени.

Это один способ решения. Можно прибегнуть и к другому ходу мысли, чтобы придти к тому же результату.

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

F (неправильный серийный номер) =EBX

То есть над неправильным серийником производятся операции, называемые функцией F, результат чего сохраняется в EBX, с которым и происходит сравнение.

Другим членом сравнения является EAX, что приводит нас к следующему равенству:

F (правильный серийный номер)=EAX

Применение вышеуказанных операций над правильным серийным номером в данном случае даст то же значение, что и в EAX, поэтому если у нас есть EAX, то мы также имеем на руках данные для сравнения и производимые операции.

Чтобы получить правильный серийный номер, нужно применить над EAX операции, обратные используемым при проверке введённого серийника.

Правильный серийный номер = (операции, обратные F)EAX

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

В данном случае операцией, обратной XOR, является тот же самый XOR, так как эта операция инвертируемая.

Поэтому XOR EAX будет функцией обратной F и даст мне шестнадцатеричное значение правильного серийного номера, из которого, если переведём его в десятеричную систему, получится собственно серийник.

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

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

Загрузим SPLISH в OllyDbg и окажемся на точке входа.

6c1f482f644b66cb58b7398286f2fa20.png

Смотрим используемые API-функции.

d1adde813a1a97ce45119516d0841fae.png

Ставим BPX на уже знакомую нам GetWindowTextA.

8dad4cfa0c261818abd76dd8d286c9f9.png

И запускаем программу с помощью F9.

421a63e8188a5efdc03eeaea8b42b913.png

Вводим имя и неверный серийник, после чего нажимаем кнопку NAME/SERIAL CHECK.

34dc1d103a3532d658704a5e91eda3cb.png

Остановившись на вызове API-функции, смотрим буфер.

e31cfe84a849c7017a8bb74b39a8bfd9.png

Ищем буфер в DUMP’е.

da226b2f84fbf0f24374a1e20f21e2db.png

1fc6d92bcf3508ccaac5f541df697bc1.png



Так как здесь ничего нет, выполним EXECUTE TILL RETURN, чтобы остановиться на RET, а заме нажмём F7 для возврата в программу.

941cdc12d7ba1229a9ca0f642fa327f2.png

Видим, что сначала получили неправильный серийный номер, поэтому отмечаем его и устанавливаем BPM ON ACCESS.

38355469ac78b17c3e56acb14c9c5f64.png

Делаем RUN.

ba4e2823749bbd56671bcdb01b3389c7.png

Снова останавливаемся на вызове той же функции, которая в этот раз получает из формы имя, но поскольку нам это сейчас не интересно, снова нажимаем RUN.

0b03e3b7e027c1bf3f47abebefa159e9.png

Останавливаемся на этой процедуре.

Первая строка перемещает первый байт неправильного серийник. Если выполним её:

71afbfc91a420cdf52fcaf159425e7db.png

Дальше следует инструкция CDQ. Посмотрим, что о ней говорит наш друг Google.

CDQ
IDIV ESI

Инструкция IDIV ESI делит содержимое EDX:EAX на ESI, сохраняя результат деления в EAX, а остаток в EDX. Чтобы быть это деление было эффективным, содержимое EDX должно быть равно нулю, что можно сделать с помощью CDQ или XOR EDX, EDX. В этом случае не нужно помещать ноль в регистр EDX, потому что результат предыдущей инструкции уже делает это.

В этом случае EDX подготавливается перед делением для получения остатка, а поскольку у нас здесь цикл, то каждый раз для этой цели перед выполнением команды IDIV используется CDQ.

EDX:EAX делится на ECX, результат помещается в EAX, а остаток в EDX. Ок, это посмотрим, как это работает. Первый байт равен 39, он делится на ECX, который содержит 0A.

0426ae32d91be88448311891c82c4888.png Видим, что получилось.

0a871ced366e6928bb229e259e755156.png

Здесь результат деления (5) оказывается в EAX, а остаток (7) – в EDX.

de9c128e9a867be68cf5f9893879e4ea.png

Видим, что следующая строка сохраняет результат деления в 40324D. Посмотрим через DUMP, что там.

6121611deab972dcc7b949f62a0bfe66.png

45ea166b604731c5f3c1f0854108d342.png

Продолжаем выполнение с помощью F7.

16392fce7117c44c2d602cf16368884c.png

Здесь сохраняется 7.

9a973926b00aa9e8af2f21b83a008113.png

ec47cea87047f138d8c0eb45add395f0.png



Видим, что EBX, равный нулю, увеличивается на 1 и сравнивается с 6, и так как эти значения не равны, то цикл повторяется.

82c99f900c57f2391d6c56bc09ea062c.png

d84452a02ffa81de529f64b159c05fba.png

Теперь посмотрим, что происходит со вторым байтом.

7a01e03c36fc5dd9e0423d1493ccdea1.png

Снова происходит деление на 0A и сохранение остатка.

e60edaf18ad87fc85615ee45363acce4.png

5e911813061962a710d8588c025c7bf6.png



Сохраняем…

85b3f9114eae5e5ed60240e17cd19b9a.png

Ок, одна и та же операция производится над всеми байтами.

a8f15ff4c56564b2364e41a1a692eb20.png

И выходим из цикла, так как не происходит перехода с помощью JNZ, возвращавшего нас раньше.

a52d64afde2e0b53110d4c7e1a1e9393.png

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

a32d424462119f3274aff55f2e82170a.png

Здесь два LEA, которые помещают адреса в ESI и EDI.

951a9efd5caa1a542d4bb963a5acc481.png

ESI указывает туда, где сохраняются остатки, а EDI, возможно, на что-то интересное?

2968d389d15c8243495d038bb0c34983.png

Продолжаем.

62dd2fa8b81a7d7ff7dfff19c30fb692.png Видим, что EBX содержит ноль, который сравнивается с 7, и если бы они были равны…

a41751eadbcaec40ecd75901f33e8413.png

Перешли бы на окошко с сообщением о правильном вводе. В середине находится другой JNZ, который перемещает на другое окошко с сообщением о вводе неправильном.

6f6be0d2fc842739b06a96aa0dc867c0.png

Ок, видим, что сравнивается.

698a938a2958bd73b9f0fead684be522.png

В EAX переместится первый байт, на который указывает EDI, то есть 02, а в ECX будет перемещён первый байт наших остатков, то есть 7.

22b478a3b851c8eb23567fce18247831.png

0ebcaf591d231dc0fe063fb8d7328a0d.png

И если остаток первого байта был бы равен 02, то был бы совершён переход.

В моём случае найти остаток можно было бы следующим образом.

39= 5 .0A + 7

То есть результатом деления 39 на 0A является 5 с остатком 7. Переформулируя, можно сказать, что умножив 0A на 5, получим 32 и прибавление 7 даст 39.

39= 5 x 0A + 7

Правильный остаток должен быть равен двум в случае правильного серийного номера.

BYTE CORRECTO= 5 x 0A + 2

BYTE CORRECTO= 32 +2 = 34

34 это цифра ‘4’ в ASCII.

Мы можем также увидеть, что

BYTE CORRECTO= 5 x 0A + 2

Даёт нам одно из цифровых значений (от 30 до 39). В случае, если результат выходит за эту границу, то нужно сделать понижение и считать так:

BYTE CORRECTO= 4 x 0A + RESTO

Ок, посчитали, что первый байт равен 34 или ‘4’ в ASCII.

Высчитаем другие правильные байты с помощью наших остатков.

b9d0f016215333894833b02b9b0f92e2.png

C 02 уже посчитали.

Продолжаем с 08.

ПРАВИЛЬНЫЙ БАЙТ = 5 x 0A + 8

ПРАВИЛЬНЫЙ БАЙТ = 32 + 8

Получилось 40, что перевышаем максимальное установленное нами значение 39 (‘9’ в ASCII), поэтому понижаем и пересчитываем заново:

ПРАВИЛЬНЫЙ БАЙТ = 4 x 0A + 8

ПРАВИЛЬНЫЙ БАЙТ = 28 + 8 = 30 que es 0 en ASCII

Если хотите доказательство, то смотрим, что 30, делённое на 0A, даёт 4 с остатком 8.

f59513c775cfe7d593a4df4766e450c1.png

Поэтому у нас есть второй правильный байт, равный 30, то есть ‘0’ в ASCII.

Посчитаем всё остальное байт за байтом.

Следующий опять 08, то есть результатом будет 30 или ‘0’ в ASCII.

Потом 03.

ПРАВИЛЬНЫЙ БАЙТ = 5 x 0A + 3

ПРАВИЛЬНЫЙ БАЙТ = 32+ 3= 35, то есть ‘5’ в ASCII.

Затем 05.

ПРАВИЛЬНЫЙ БАЙТ = 5 x 0A + 5

ПРАВИЛЬНЫЙ БАЙТ = 32+ 5= 37, то есть ‘7‘ в ASCII

Потом снова идёт 5, то есть повторяется 37 или ‘7’ в ASCII.

Последним идёт 3, который, как мы уже знаем, даёт 35 или ‘5’ в ASCII.

Таким образом, правильным серийным номером для имени ‘narvaja’ будет 4005775. Убираем все BPM и BPX и запускаем RUN.

571a390326054c8cef01e8de150d1f2c.png

Нажимаем кнопку NAME/SERIAL CHECK.

495e4ecf2ff46d8860eb0a0801ace3b5.png

Ещё одна победа.

К этой главе прилагаетcz крэкми для практики под названием
Пожалуйста, Вход или Регистрация для просмотра содержимого URL-адресов!
.
 

О нас

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

    Dark-Time 2015 - 2022

    При поддержке: XenForo.Info

Быстрая навигация

Меню пользователя