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

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

AnGel

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

AnGel

Администратор
Команда форума
27 Авг 2015
3,411
2,025
Пожалуйста, Вход или Регистрация для просмотра содержимого URL-адресов!


Думаю, что в предыдущих главах мы рассмотрели все основные вещи относительно Visual Basic’а, а те, кто хочет изучить эту тему поглубже, могут прочитать посвящённые VB туториалы с cracklatinos (на испанском – прим. пер.), которые укрепят и дополнят ваши знания.

Среди них встречаются очень хорошие туториалы о Visual Basic’е, написанные COCO, которые достаточно сложны и могут стать хорошей практикой, туториалы ARAMPUMK о волшебных точках Visual Basic’а, а также другие прекрасные туториалы, которые открывают дорогу для дальнейшего углубления в данную область. А мы меж тем перейдём к следующей теме, а именно к P-CODE.

Программы на Visual Basic’е могут быть двух типов: NATIVE, который мы рассматривали ранее, и P-CODE (псевдокод). Это то, что мы будем рассматривать в данной главе.

Основная разница заключается в том, что программы в NATIVE-коде выполняют строки кода в секции кода программы, в то время как если мы откроем программу, где используется P-CODE, в OllyDbg, модифицированном на предмет OEP’ов и VB, и установим BPM ON ACCESS в секции CODE, то увидим, что при выполнении не происходит остановок в секции кода, кроме тех случаев, когда встречается вызов какой-либо API-функции. Это очевидным образом указывает на то, что никакого исполняемого кода в данной секции нет.

Дизассемблирование программы, использующей P-CODE, ничем не поможет, так как там нет исполняемого кода. В ней всегда запускается DLL Visual Basic'а, которая читает значения из секции кода, указывающие ей, что нужно сделать. Например:



1e делает Безусловный переход
1e означает условный переход (похоже, Рикардо не смог определиться, какой же переход он имел в виду – условный или безусловный? – прим. пер.). Он выполняется в DLL Visual Basic’а, то есть, то есть она считывает эти значения из секции кода, и они указывают DLL, что нужно сделать. Таким образом, никакого выполнения кода в соответствующей секции не происходит, только считываются из неё значения.

А сейчас, раз мы такие нахальные, то возьмём нож в руки и решительно атакуем то, за что ещё никто не брался: оттрасируем и интерпретируем действия, выполняемые крэкми с помощью псевдокода, и всё это в OllyDbg, опкод за опкодом, хе-хе.

Рассмотрим первый крэкми под названием clave1, в котором необходимо найти серийный номер. Этот крэкми мы позаимствовали у нашего друга JB DUC’а, написавшего очень хорошие статьи по данной тематике.

Очевидно, что большая часть исследования P-CODE проводится с помощью прекрасного отладчика WKT. Если хотите почитать туториалы с его применением, то поищите те, что были написаны JB DUC’ом, а также в «Новом курсе» от CracksLatinos также есть превосходные статьи о P-CODE. Здесь мы будем использовать OllyDbg и EXDEC, который нам поможет видеть имена опкодов, так как Билл Гейтс не предоставил нам их список, хе.

f28380157c8c8a319dcd4a472aacfc47.png -

Здесь открываем крэкми в обычном непропатченном OllyDbg с установленными плагинами для его сокрытия, которые мы рассматривали в прошлых главах.

Поверхностный осмотр показывает, что как и в NATIVE-крэкми метод 4c может быть применён и здесь, и мы можем найти место, где находятся формы таким же образом, что и в NATIVE-приложениях (4c для снятия наг-окон отлчино работает и в P-CODE, так что можно использовать именно этот метод, когда его возможно применить).

Что мы ещё видим?

Если пойдём вниз от точки входа, то не видим строк с кодом.

729b0fc0cb53d6e5735f36086d09434a.png -

Только мусор в подобном роде, поэтому не надо пытаться бессмысленно анализировать его, вспомним, что в NATIVE-приложениях на Visual Basic’е мы видели примерно то же самое, если спускали вниз от точки входа.

ccecf670e70f63a999ea111c5763e760.png -

Появляется мусор, но если продолжим дальше, то:

6313b7811e9859d1977deb27ac964140.png -

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

Возвращаемся к крэкми с псевдокодом.

5bea57d40593b081d9b1992945ce0e0f.png -

Другая особенность – это API-функция под названием MethCallEngine, которую мы встречаем в крэкми, использующих псевдокод, так что теперь, когда нам нужно сделать первый шаг – определить, использует ли программа псевдокод или нет, то уже знаем, что нужно делать: надо посмотреть, есть ли исполняемый код в секции CODE или встречается ли там упомянутая нами функция.

Первое, что нам стоит сделать – это посмотреть, найдём ли мы какие-нибудь строки.

d75f5e9ab736fd2cff526565c865e42d.png -

927f3efc4955f623a3011eabef9a84ba.png -

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

Хорошо, установим BP прямо на JMP, который является прямым переходом к функции MethCallEngine,

052476998ff27e7a6bbaf9f07afce28e.png -

Ищем сверху от точки входа и быстро встречаем JMP на функцию MethCallEngine и, находясь прямо на этой строке, делаем правый клик мышью и выбираем FOLLOW, что приведёт нас прямо к данной функции, где и устанавливаем BP.

ac2a8239de1f705a4dba37b522c8f91d.png -

8755c85b1c1947a0235f17d33074cb4f.png -

Теперь делаем RUN.

36f633bc1b6906b05b7ad5822475cc5e.png -

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

Теперь вводим ложный серийный номер.

c0bbadcb4a8079236f03ee32bcc1ce5a.png -

И нажимаем «REGISTRAR».

e6ec4a60df7d36653d78027295e1d126.png -

Останавливаемся на JMP, который начинает истинную часть P-CODE.

cf4fcac90ea9f5535935518717670759.png -

Здесь входим в API-функцию, посмотрим, что она будет делать.

08e21e2831c58c48976c24b974a89b90.png -

Здесь начинается.

Теперь, если откроем то же крэкми с помощью exdec, являющегося дизассемблером P-CODE, чтобы немного помочь себе, то увидим следующее:

c63e2720829d6164ca3ea914d80af93b.png -

То есть первый байт, который будет прочтён – это 04, находящийся по адресу 401BD0. Он находится не очень далеко отсюда, так что установим на него BPM ON ACCESS.

a4ddacdac2d31d7e28fb98425468f686.png -

f085ca6205a27d60b5da8c692ce39e6b.png -

971a4866f77e1cf882dcbbe7ebaddffa.png -

Этот первый байт, который будет прочтён. Когда остановимся, то окажемся в начале, и таким образом, мы можем оказаться там без помощи EXDEC. Как только остановимся на BP, установленном на API-функции MethCallEngine, мы можем поместить BPM ON ACCESS на секцию кода.

6f43e549be62d39b134ab0b28fdff78a.png -

И делаем RUN. Видим, что останов происходит несколько раз.

0f4a28bd12576e1f0232f0cb42c9f8a7.png -

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

0991b76c014bd905d634e080e8fc0f42.png -

В первый раз, когда происходит останов и байт из [ESI] считывается и перемещается в AL – это то место, где начинается чтение первого опкода P-CODE. Данным образом можно найти первый байт, не используя EXDEC.

Как видим, последующие опкоды, которые отображаются EXDEC’ом идут вслед за предыдущим.

238213f414ec3847748505d846673cca.png -

242fbb4322818330c175b227e0c81a86.png -

Как видим, порядок опкодов на обоих картинках соответствует друг другу. Между ними располагаются параметры, которые необходимы опкоду для выполнения.

96bc4db14bf7f40bf5d43a25099e5c36.png -

Как видим, здесь читается первый байт.

46f8eef598cdae75c317e75b6dafc4ce.png -

На который, как видим, указывает ESI. На следующей строке никаких действий по выполнению опкода не предпринимается. Значение ESI увеличивается на 1, чтобы затем прочитать параметры опкода.

fec7dcd54979a75fc0dc8e2b1be57eac.png -

Затем наконец доходим до косвенного JMP, который отправляет нас к строкам, выполняющим опкода, в данном случае это 04, как видим в EXDEC’е.



401BD0: 04 FLdRfVar local_008C
Видим, что такого загадочного делает этого опкод.

dbc8b2f9b15b989de26ee3dc1a9c82b3.png -

Здесь видим выполнение опкода 04 FLdRfVar, это несколько маленьких строк кода, ничего такого, чтобы испугаться, хе-хе, и в конце видим, что заканчивается XOR EAX, EAX – это подготовка к чтению следующего опкода.

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

853ba190e09dc073ea7868ae32a50f2f.png -

Хорошо, они помещаются в EAX с помощью инструкции MOVSX, и значение FF74 является отрицательным (мы рассматривали это в главах, посвящённым ассемблеру). Продолжаем трассировать.

4ed02c04f582cc978f88ccb8df5f9318.png -

Это значение в EAX равно -8c, и если кликнем по нему два раза:

cc0c041a0f92be76d1d12137c6fe6239.png -

В окне показывается, что это значение равно -140 в десятеричной системе счисления или -8c в шестнадцатеричной. В EXDEX нам показывается 8c.



401BD0: 04 FLdRfVar local_008C
На следующей строке значение, считанное из параметров опкода, суммируется с EBP.

af0c0480c05bad3552e40a8c5728cde5.png -

И к этому значению применяется PUSH.

a5e810d64f6e1139ff88179e0a96feab.png -

То есть это эквивалент PUSH EBP-8c – выделение в стеке места для локальной переменной. На моей машине EBP равен 12f4e0, если отнимем 8c, то получится 12f454, то есть значение, которое останется в EAX и будет передано инструкции PUSH.

9e4e9e5f9795845a6397b5cf2361fad5.png -

c43ad083df9a15ead11a75b3afc849e6.png -

Ничего хорошего. Продолжаем.

b2c7345e34d9193431cd3ebde30d58c2.png -

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

4d0fdf80748d8dec2972921ea5f55ffe.png -

Второй опкод – это 21.

Видим его тут.

2ee228fd397caa7bd75b2f35b7148ee1.png -

415638159cda84f857e0003bbb29c563.png -

Как обычно, он помещается в AL.

54cc64c03fae55b8e0bae52e973f5836.png -

А теперь к значению в ESI прибавляется 3, чтобы регистр указывал на параметры опкода. Затем управление переходит к косвенному JMP, который ведёт на опкод 21.

Посмотрим, что нам скажет гугл.



'21, FLdPrThis
(Загрузить ссылочный указатель в указатель на элемент данных.)
Хорошо, у нас здесь несколько указателей, про которые мы не знаем, для чего они служат, но примерно дело состоит в том, что берётся ссылочный указатель и загружается в указатель на элемент данных. В ассемблере это было бы чтение указателя из стека и загрузка его в другое место стека же.

Если продолжим трассировать:

b90c8fda845188fb18cc15ba507b8f90.png -

Видим, что читается содержимое EBP+8 (ссылочный указатель) и сохраняется в в EBP-4c (указатель на элемент данных).

Хорошо, прочитанное значение на моей машине равно 15b000. Если посмотрим в DUMP’е:

86f440a41f37dda21b99760400a5707a.png -

9a8fc3034b0fe040d3ba04d66797b0d6.png -

Видим, что здесь находится указатель на 4022e8, а если посмотрим в DUMP, то увидим:

ea863423330e7192556101682aef3bfb.png -

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

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

Хорошо, продолжаем.

1382ca6b5d1c543b5350b44bc144c763.png -

Далее обнуляется EAX, а на следующей строке читается третий опкод.

17d3c9042e49adae9788ebbc30d2e607.png -

Смотрим в EXDEC, что такое 0F.

35cdc728e40ac7ae2c6cf856d7708e74.png -

VcallAd

d9de260cd2153ad837fe2786012be1dc.png -

Ок, здесь видим, в чём заключается смысл опкода 0F, видим, что у него один параметр из двух байтов.

768a8a4c333e354864495b637653f877.png -

Параметр в моём случае – это 0300, и он указывает смещение в таблице дескрипторов элементов данных. Хм, видим, что доходим до косвенного JMP, посмотрим, совпадёт ли это с тем, что говорится.

fe730c774123c3494b19083052162679.png -

Здесь читается содержимое EBP-4c и помещается в EBX.

11fcf8dcff709a5242cf5a69f6999b12.png -

Здесь располагается указанное значение 15b000. Оно помещается в стек.

212e46c5913882e0875dc66478024df1.png -

f6615c7c9c3f484e35c7936a1edfed15.png -

Затем читаем параметры. В моём случае, это 300.

49512c16595d2674feebd577fbba1e16.png -

f0facea2cba83f4bc36e42b229ff9911.png -

Суть дела состоит в том, что содержимое EBX, равное 15b000, это начало таблички, которую мы ищем, то есть таблица дескрипторов элементов данных. Адрес – 4022e8.

a4178aef14b55471e30c5dcf10cd7e3e.png -

И к этом прибавляем 300, то есть смещение до адреса, где начинается искомое значение.

fde10d65cc72e7c41d33ff1adbe6b2de.png -

Таким образом, прибавив к началу таблицы 300, получим в EAX значение 4025e8.

42837d34628b4b63e3850fd2ea1a809a.png -

Это значение указывает сюда:

f57d58be6672aa52306fe09e5334f380.png -

То есть опкод 0f, используя предоставленный параметр, получает сохранённое в таблице значение.

30c0aec69b8c346ddde69d581c0cd3b8.png -

Дальше у нас вызов по адресу, где читается данная таблица, и как видим, содержимое EAX равно:

d90bf8f94069f4c106a1ac5a23f6bd74.png -

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

Продолжаем трассировать, проходим CALL с F8.

54e624b04ea54b7d141ebbfbad9f3082.png -

a19700f24a2e45490e3a76e1855eeaca.png -

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

b5e5b79097c14aacd60611bb5b59325d.png -

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

d9b75cf5b824f48889455e5416dd8a7c.png -

Здесь выходим из его выполнения.

f68c7b837e46099822d469548a5d2fd6.png -

Что у нас тут?

e5659e241bf3976f241c4604ad8028da.png -

С помощью MOVSX считываются параметры, отрицательные значения дополняются FF.

b7fbcb6909b4e7338801a9801f84caaf.png -

Как уже предсказывалось ранее, это значение -88 в шестнадцатеричной системе счисления, о чём нам говорит EXDEC.

1e9255c1d3c0a38f838ad7d9071da7f9.png -

-136 в десятеричной равной -88 в шестнадцатеричной.

ab8067d5240ae1047b3360e30f128bd5.png -

Здесь увеличиваем указатель ESI на два и складываем EBP с -88, и результат этой операции помещается в EAX.

fdd3c11af52e6206c5e191647aec31bd.png -

79b826b0bb50cb3853e6185cda240213.png -

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

3b93aa4e20c441b8df093529f5ba429a.png -

Первым является значение, которое было сохранено предыдущим опкодом, а два других значения в моём случае равны 12f458 (локальная переменная ebp-88) и -1 – третий параметр. Нажимаем F8, чтобы не заходить внутрь вызова.

После его выполнения видим, что в ebp-88 сохранилось значение, найденное предыдущим опкодом.

dbee1f33ff1ad1f9cea12d315c02032d.png -

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

То есть то, что было помещено в EBP-88 – это значение, полученное предыдущим опкодом.

bcf596fb197d0ddaaacb5de079d54d8a.png -

Доходим до другого опкода, равного 08, которая также пытается работать с той же локальной переменной 88, то есть ebp-88.

3c77db9328718c4c4c92329e7c6c13dd.png -

Входим в опкод.

bdfdb29ed00b80faa47ca3cadc197b92.png -

В куске кода, видим “XOR EAX, EAX”, завершающий выполнение опкода, а чуть выше – условный переход. Посмотрим, что он делает.

Сначала EAX’у передаются параметры опкода.

6bb78867b0b02e768529cabdcea9bb9a.png -

Как и в прошлый раз, значение FF78, перемещённое с помощью MOVSX, имеет FFы в своём составе, то есть это отрицательное число, равное -88 в шестнадцатеричной системе.

4aaf71b7e86e031f45f35c727289cd77.png -

f5605891a384537e61cff1f77a7d9255.png -

На это строке напрямую задаётся сумма EAX+EBP, то есть EBP-88, и перемещается значение, содержащееся по данному адресу. Очевидно, что мы берём его из таблицы элементов данных.

3ef26075d76a8ff8a3f06de20a112c0d.png -

ac17f4ac5e9615e7fa756578c4a97c37.png -

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

8944b82fd5bb8021cc0a891d5bf341da.png -

Сохраняем это значение в EBP-4C.

Здесь нам нужно вспомнить то, о чём говорилось в самом начале.

То, что мы видим – это чтение содержимого EBP + 8 (ссылочный указатель) и сохранение оного в EBP.

Так как ebp-4с – это указатель на элемент данных, и мы уже убедились, что он содержит корректное значение и в нём нет нуля, то поэтому эта переменная ebp-4c называется «указатель на элемент данных», так как это значение связано с таблицей элементов данных.

570bb5e678b9ea9549e551df32db3d36.png -

Доходим до следующего опкода.

a962ec79b71135a5e2f3c9bd5acf8ff3.png -

6b6cd437db68ab27d6ed3fd1891a2746.png -

В пресвятом Гугле смотрим, для чего служит этот опкод.

0d VCallHresult #получает текст из поля ввода текста (textbox)

То есть будет прочитан неправильный серийный номер, который мы ввели в текстовое поле. Трассируем и смотрим, так ли это.

92d6f35ba2e10d93af33d2e5272a4ab4.png -

Видим опкод, завершающийся “XOR EAX, EAX” как обычно.

Первое, что здесь происходит – это считывается содержимое из EBP-4c (а это, как мы говорили, указатель на элемент данных) и помещается в EAX. Это архизнакомое нам значение, считывающееся из таблицы элементов данных.

1750a95fff6196cd942054d8e8edadd2.png -

Дальше это значение помещается в стек.

f12b095f88c80f8d0de2004710e7c1ac.png -

Потом считывается параметр опкода.

e191c0242a24b37963c9347280cd46aa.png -

994abfcff929c2f1571e69a4925f1eb6.png -

7002519808cc5e217c13b4e9d8428c3f.png -

И помещается в EDI.

Затем читается содержимое EAX, являющееся началом другой таблицы.

cfb7ea30dd3f9a5b5c5c85866e37d2eb.png -

3037fa0ac3ac724d9d169d9925c91c84.png -

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

4be6f7c4ac0534d5fe67015a6422cb9a.png -

9d8e05fe18d5b0fbf98ff8d644c768d5.png -

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

3aa11d29a366188f1676d7703ab3a6de.png -

Выполняем CALL с помощью F8.

Затем помещаем в EDX значение из EBP-44.

7bfc2a5dd389dac29c23ca6a4560bba4.png -

fdbc264c6a92b7a7d033cfa6c18782ab.png -

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

09f89c6a5b3a559e76df55d46343e984.png -

Видим, что продолжается работа с локальной переменной 8c, которую мы также знаем как EBP-8C.

Если поищем значение EBP-8c:

4c68a40daa8da183a484a70ab65fe29e.png -

Оно равно 12f454.

d3e2a582babfd8b8cb402e735d6f9e0c.png -

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

7d789a277d70d08ad48c473e24bcf0f9.png -

Уф, пришлось попотеть, но мы, наконец, добрались до того места, где считывается неправильный серийник.

Следующий опкод – это 6c IldRf

681cd64c132d4c72fd6f577276bfea76.png -

4eacc0e3fbe639e1b956cfbf96f829a2.png -

9e24797319a08d33bbcd5580ee08a76f.png -

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

532de623ccf65c073e92dbed6846cf30.png -

Что у нас здесь?

980b6b95ea76c181eefc7c591a1e5456.png -

Сначала осуществляется перемещение параметра с помощью MOVSX, который является отрицательным (FF).

dcff835f405177d7ff974936815963f7.png -

Смотрим, что у нас оказывается в EAX.

4598278da28fa6cba7ef9ddffec59f66.png -

Это -8c в шестнадцатеричной системе.

b37a815bb4e0e64de0113636465f81d8.png -

Следующая инструкция суммирует его с EBP, что в результате даёт EBP-8c. Содержимое по этому адресу кладётся в стек.

79d38669323d4879e3c6a650aa469499.png -

Он содержимое ebp-8c – это указатель на неправильный серийник, то есть сейчас этот указатель находится у нас в стеке.

da701a85521329cc8e90b08766fdd0ff.png -

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

Следующий опкод – это:

1b LitStr , что расшифровывается как “Literal String” (символьная строка)

Смотрим, что он делает.

122f3bdd6e2c894f0f3eb5ea0376e11f.png -

Входим в опкод.

96718f1fd576967a7a0599936c091731.png -

Сначала читается параметр, который здесь равен 0001 (положительный, т.к. нет FF). Он помещается в EAX.

e63cf702f0472a12a3c8e305ab8f2123.png -

404cd7b7543639b518254984e1884038.png -

Видим, что на следующей строке в EDX помещается значение 4017E4. Для чего оно, мы не знаем.

fa2e5dc91fe48d2f706a95f8b6d9a33d.png -

И для чего может служить помещение в стек 4016f8?

010b56704c347599ff75856ebd1ce1fa.png -

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

337abaf0a2008b711e4a30c25cfd0974.png -

Конечно же, смотрим через DUMP, что указывает на пустую строку, заключённую в кавычки, то есть то, с чем будет работать следующий опкод, проверяющий, напечатали мы что-нибудь или оставили поле ввода пустым и нажали “Register”.

cd5b39d2c9062f35769f5f42522586ae.png -

Что есть:

e0671a94b5747db9168bc608ea380377.png -

Ок, “LEAD 0” – это операция, а “30 EqStr” – это вторая часть опкода. Посмотрим, что это такое в пресвятом Гугле.

Lead0/30 EqStr – сравнение двух строк.

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

9f88d5f4526b15791c00fd0a866e8c8d.png -

И здесь первый опкод завершается “XOR EAX, EAX”, где ничего не делается, и читается второй опкод.

279ed9455bbc1909a937afb2d684e4bf.png -

96af70d2fec656f0d36acb6d83e85e0e.png -

Здесь читается второй опкод 30, но разница в случае с двойным опкодом заключается в считывании параметров, так как в таком опкоде первый завершается с помощью «XOR EAX, EAX» и считывается второй, но параметры первого опкода остаются доступными для чтения.

fee4ad7147a3f8605dca92a4f83f6f8d.png -

Здесь находится второй опкод, который делает PUSH 0.

1ac2ffed35c8808f1152238ad0b873a6.png -

Когда доходим до CALL’а, у нас есть три аргумента. Минуем CALL с помощью F8 и смотрим, что изменилось.

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

Следующая строка «CMP AL, 0» сообщает, что здесь в AL сохраняется результат. В моём случае это:

3522dea19d18d254b34bab5825d04c3e.png -

AL=01

Потому что строки не равны.

5220dbbafaa6b27e5b6f1195002a8c78.png -

После сравнения в EAX помещается значение ноль, а в конечном итоге это значение помещается в стек, так как это результат опкода. Ноль, если не равны, а если бы были равно, то вместо ноля было бы FFFFFF. Можете проверить, хе-хе.

41410e41765f2dc62803be6ff8ce2760.png -

Доходим до следующего опкода.

afff3d6ba186852dfb53247d6b9337be.png -

Пресвятой Гугл сообщает нам, что это примерно то же, что и SysFreeString, которая освобждает память, занятую неиспользуемой строкой. Видим, что в данном случае освободится ebp-8c.

817a1283c7fd7b702caf96d117ce136c.png -

Видим, что в EDI перемещается значение 1, затем в EBX – FF74 (в шестнадцатеричной системе это -8c). Как обычно, используется MOVSX, чтобы перемещать вместе с FF’ами, если значение отрицательно.

4bc1df4665248b711864a7f4b8236bae.png -

8818965280141c12b0d5c40471c516af.png -

EBX+EBP равно EBP-8c, так что в стек помещается указатель на неправильный серийный номер.

24d55d2501f346d5d01dfa32e9cfe1e8.png -

392476fc180a3dd552b2add2d03d6b01.png -

Видим, что идёт вызов API-функции SysFreeString, а по возвращению из неё:

19cb360ee9889c02e596860413824334.png -

Указатель на наш неправильный серийный номер был заменён на нули.

6436aa90ed23c97c117bde92c7a49266.png -

Сам неправильный серийник не был стёр, он как был, так и остаётся по адресу 15d3bc. Был стёрт указатель на него, находившийся в EBP-8c.

e67c6de29470a51f3fb1c7b096d1eeef.png -

Доходим до следующего опкода.

ed5e5a91736c8510ebff36b6af344eff.png -

Это сотрёт содёржимое локальной переменной ebp-88.

А что там находится?

ec4c0f54b51cbdbb62c613757def2261.png -

978da9c28e49f58bd5809db328a0d90b.png -

Ах, это значение, которое мы искали в таблице элементов данных.

bab532da61b44fa26994b5359f718919.png -

Здесь смотрим параметры опкода:

7a08e480b82e8c69825ed33f3f3380bc.png -

FF78, который является шестнадцатеричным значением -88.

fac7e1d98fdb9b2cdeb7451e45c30d95.png -

Далее в EAX помещается содержимое EBP-88, проверяется, равно ли оно нулю, так как оно не равно, то продолжаем дальше.

8c40d950b26eddce5ed9face79a32f7a.png -

И доходим до вызова, который, как и раньше, освобождает это значение, и стирает содержимое ebp-88.

fa852c30eefdd8c79945355c5032c9d4.png -

Здесь помещаем в EAX ноль.

f485fbccd6e803a92f7aace866750068.png -

Следующий опкод – это:

59160200f28a3ce0c1ad695a207a3390.png -

Это условный переход, так как все BRANCH’и – это переходы.

bb1127f2a7fa81e272791415fd4e7d41.png -

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

Видим, что это так, если будет переход, то следующим опкодом станет:

fa75aa2694f588bd3805f2fa88eaba55.png - Так как это условный переход, избегаем JMP в 401bf3.

e6d96637573351441edcba05449463a0.png -

Здесь опкод завершается и читается следующий.

429394f949f6ebff1572c6581cf8ddb6.png -

Как можно предположить из FE в 401bfg6, условный переход срабатывает и минут JMP, хе-хе.

Lead3/c1 LitVarI4

Это двойной опкод. Посмотрим, что он делает.

4d70acffab44ec5e036886b1a5834da8.png -

Здесь завершается первый опкод и читается второй.

65178fe49f1d441de215838d6fa5e2a6.png -

Который начинается здесь. Терпеливо трассируем его.

f2c47cf17aef63b9e3c74a5401a60efe.png -

Считываются параметры опкода.

d7abcc34668831a69f7a291fa88504be.png -

Уже знаем, что они дополяются FF, если содержат отрицательное значение, как в данном случае.

5423e8971fe2d6eea7eb0512106b8180.png -

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

88ee69807956654af526e996c8d939f1.png -

4cc9735b982211601d777c59b85e5893.png -

И это значение сохраняется в локальную переменную.

2120add2734e42bd32170fc3708089c8.png -

EBP+ FFFFFF54 + 8, то есть сумма первого параметра и 8 даёт 12f43c, а здесь это значение сохранено.

81f516081a4b5694198ae2621177ba34.png -

0bce8ace2db1943c2b49b65557dc1ca4.png -

JMP помещает нас в:

d987f8640de2ff727c1eb3ee2778b265.png -

Где 12f434 помещается в стек.

ec91089705fb30dc2a17f348e112e138.png -

Это указатель на структуру, начинающуюся с 3, которое уже было сохранено, а чуть пониже – сохранённое значение.

d70cd109ea9f11bbbe09b0bd43b5b39e.png -

Продолжаем.

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

41da144f2aa4c89c7b6d47469629a783.png -

Посмотрим в OllyDbg, чему равно это число в десятеричной системе.

235ac2bcec67f73823128594fbae4b84.png -

Оно равно 246810. Введём его в крэкми.

abf60248314c18829c809c989623df71.png -

ca9ffbff65a4df0b56f99a272232ca9c.png -

Хе-хе, я подозревал это, но так легко нам не отделаться. Доходим до сравнения.

97febecc41de007a15a9c6e9144ec5c2.png -

Следующий опкод также двойной.

Это FC и немедленно он завершается и начинается второй.

346e90475a8542031e1eef41269b30c3.png -

65bf5e42d70756dc1cf1df9bac9a19b3.png -

Это F6, бесстрашно заходим в него, EXDEC нам говорит, что будем работать с локальной переменной 9c (то есть ebp-9c).

012aab1e221af1e6ca8db92cf88d53c6.png -

Здесь читаются параметры, которые дополнены FF.

84b9a0238ec646cf078b50176ed3614f.png -

Конечно, это значение -9c.

86b4982b5f43568243db6e25d9086d0d.png -

Прибавляем к EBP, чтобы получилось EBP-9c или 12f444, которое пока что остаётся пустым.

07c08836283cc2da499ddf4693513fcb.png -

b7c1951951e56c4db495f8f001fc8bbd.png -

9c2c6f9b47746c1305e537effc9a8cc8.png -

Затем проводится проверка, равно ли это значение 8, если да, то делаем переход.

e251d78cbd2090cc50d380bd3fc7e118.png -

Далее снова переход, но не будет вдаваться в детаил. Доходим до последних строк опкода.

362c76cbd1f6bcf4324d926d2a6ed9f7.png -

34cc71096a8a6822c86d391f0c4d1693.png -

Помещаем значение 3, находящееся в EAX в переменную EBP-9c

И стираем 3 из структуры, встреченной нами ранее.

87cb6ea2b869b870b9bb151cef286ad9.png -

При выполнении:

a19ee145dd1ffd78f956c9534250a4c1.png -

Затем последующие строки копируют всё, что у нас здесь есть в новое местоположение, то есть в EBP-9c.

2030129b52c390c7b6a5ac8d8a3f1a9e.png -

Здесь видим число, которое является правильным серийным номером и находящееся в структуре, начинающейся в EBP-9c.

1cbec873768e32349c75d4cb0dabdf55.png -

Доходим до следующего опкода.



401C02: 04 FLdRfVar local_008C
Видим, что повторяется всё, что мы уже видели в начале.



401C02: 04 FLdRfVar local_008C
401C05: 21 FLdPrThis
401C06: 0f VCallAd text
401C09: 19 FStAdFunc local_0088
401C0C: 08 FLdPr local_0088
401C0F: 0d VCallHresult get__ipropTEXTEDIT
401C14: 6c ILdRf local_008C
Всё похоже на то, как было в начале. Следующий опкод:

5f9297d87a0c596e6a6580db17962fc2.png -

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

2db22dc5d30e3cd17b2fef477bf225a4.png -

Останавливаемся здесь и читаем опкод 0A. Смотрим, что это такое в EXDEC’е.

Это ImpAdCallFPR4 – вызов API-функции. EXDEC показывает какой именно.

Например:

78f95ad8ea26f670fcd9773848fef3d8.png -

В данном примере произойдёт вызов API-функции rtcMsgBox. В нашем же случае это вызов функции:

401C17: 0a ImpAdCallFPR4: _rtcR8ValFromBstr

2ce6cb4e7676316810a08b3d85f9e887.png -

Читаются параметры опкода.

a960da27855f65c74691d429b2291399.png -

5b5ac5117f4761f03b92942953d68427.png -

Они помещаются в ECX.

6c3aec873fc7312036a3d7ec06743a28.png -

Затем в EAX помещается значение 401000 и тестируется, не равно ли оно нулю.

7f5eb070da36247c48568046e9259f82.png -

Далее читается второй параметр.

2189e2cd99066cd60ae40ac6740d8bd4.png -

f465dc7176ac68c47a9f8019c9c3f9ac.png -

f457e6bb7da544ecc53757cf1e2a5204.png -

И доходим до “CALL EAX”, где EAX равен 401000. Смотрим, куда это ведёт – а ведёт это к упомянутой выше API-функции.

007bba058dd248ed56342bd22d073adb.png -

Параметр, передающийся через стек API-фукнкции:

24db6f9365f7be01644908fd65865a8c.png -

Мой неправильный серийный номер:

6f16fdd821a84d53ff480df095c7943d.png -

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

ed6645407c8db5386dd8ae91657ed577.png -

Здесь загружается мой неправильный серийный номер.

4c72c6eb5b4e09288b4a9fa184194ffc.png -

Доходим до следующего опкода.

401C1C: Lead2/6b CVarR8

Итак, находимся здесь, заходим в опкод.

206abbb81f02368accc323d592f87ae5.png -

Так как опкод двойной, то завершается первый и грузится второй.

458042c72ed4e454fc310078b563f77d.png -

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

Но видим, что вначале загружаются параметры.

7b61d36c605bc1071197eee67a395e33.png - В данном случае:

8815ec20b7590ffcb407c6a0088c2c64.png -

de24812b0e039f7963a27ad325e80e7a.png -

Суммируются с EBP, и в EAX остаётся:

04caf894adae5c9d56269965dc6292cf.png -

374dfecdb930c9ed76b740f6ca2cfd72.png -

FSTP сохраняет первое первое значение из стека плавающей запятой, то есть из ST(0), в указанную ячейку памяти (в данном случае [EAX+8], то есть 12f43c) и делает следующий элемент стека верхним. Ок, мы рассмотрим это позже.

ed49cbb06d838f600ab3209b5d95fc19.png -

После выполнения:

5056d5a2a05695123bae775416e10997.png -

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

98cbc26189686c76910a89ef1ed2ad23.png -

faae8f3cfc3991a007d05dfde252e857.png -

Видим, что действительно это неправильный серийный номер, но только в другом представлении – 8 байтов, то есть 64-битном. Логично, раз 4 байта – это 32 бита, то двойное слово состоит из 64-х бит и выглядит по другому.

b8cae55413787e57908fa5d3441a4d73.png -

Включаем обратно обычный режим представления.

8a9c2c09fc9e68b6fe992d58a53653b4.png -

Эта инструкция сохраняет значение регистра SR (регистр состояния FPU) в AX. Выполняем:

b804bd39a709145693e6c5fb095cf988.png -

984a165c6f99833f07f84cdfe43a09d4.png -

Здесь опкод завершается.



401C20: 5d HardType
Ок, у меня нет ни малейшей идеи, что это такое, но попытаемся это выяснить.

6f492189eaf0389c8569fb9eadc35a58.png -

Ок, всего лишь две строки, которые грузят содержимое ESP в EAX.

977b48cec372cb32f18d6a3d65f2a211.png -

b116f019cfadefbe382dd05a7c56d881.png -

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

ab4e145efe5a53789d59a1ea0ea3a25c.png -

Следующий опкод.



401C21: 04 FLdRfVar local_009C
То есть PUSH ebp-9c, в данном случае:

c4732ba216ab6489c8640406dc7e8eea.png -

bb46f8380217d1607184740260ca4c7b.png -

Далее идёт двойной опкод.



401C24: Lead0/40 NeVarBool
377dec3b2ad425d61f659a1952d3db05.png -

Здесь читается второй опкод.

88a476d5b10d2fd8d21e56d8e91affde.png -

Доходим до вызова, а параметры в стеке следующие:

13b303a1ec0e82cee96259cda312ae52.png -

Один – это указатель на правильный серийный номер, другой – на трансформированный неправильный. Будет их сравнение?

37b9443d55b3d7c58917a2b621a076d3.png -

c06f627d6f20c20e71399682c91d1f2b.png -

7099b3f78093bffbdf9dde75cd795417.png -

Устанавливаем BP сюда.

7bbd8dcaba01192a9c0361599e079f9b.png -

Видим, что после выхода из call’а EAX содержит 1.

4b82a27ec5f243f72e4366b82b1b6a52.png -

И поскольку делается PUSH значения FFFFFFFF в стек, то можно практически безошибочно предположить, что именно здесь проводится сравнение, так что рестартуем крэкми, установив BP, и вводим правильный серийный номер, который был получен из этого сравнения.

0e527fef2727d3e12b4f875de7ba31a0.png -

03c41a в десятеричной системе – это 246810. Вводим его и снова идём к сравнению.

9bef6a6ead333435f0b8b9cb2d1b070a.png -

Остановившись, видим, что происходит сравнение:

432e168d4ce72c92c434a7214c26b92d.png -

246810 со прежним шестнадцатеричным значением. Дело в том, что они в разных форматах, но сверху каждого из них есть число, указывающее, в каком именно хранится значение, поэтому возможно, что внутри каждого call’а они будут трансформированы и сравнены. Смотрим, что у нас получится в результате.

90f42801e5bb892d088d77ba51fefc7d.png -

Видим, что теперь у нас EAX = 0 (раньше было 1).

1f09154e145beae3a1d966af2df34ebf.png -

И в стек также уходит ноль.

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

13f24c47d1aaade32a4dc1936ed9f3f3.png -

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

В следующей части мы рассмотрим крэкми “clave 2”, используя тот же метод. Мне бы хотелось, чтобы вы попробовали самостоятельно его сделать, но если не получится, то в следующей части вы сможете прочитать решение этого крэкми.
 

О нас

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

    Dark-Time 2015 - 2022

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

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

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