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

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

AnGel

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

AnGel

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


Обнаружение OllyDbg - IsDebuggerPresent

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

Эта часть посвящена способу обнаружения отладчика с помощью API-функции IsDebuggerPresent, которая наиболее часто используется.

Для этого используем Crackme1.exe, который идёт вместе с данной лекцией. Загрузим его в OllyDbg.

13fa1fe61f9512fa63f25e50908017a5.png

Помните, что у моей OllyDbg пока что установлен только COMMAND BAR, а значит и нет никакого плагина, который мог бы избежать обнаружения с помощью IsDebuggerPresent, но как вообще работает эта функция?

25a541b5aadb5e6def018812cc4f1174.png

Если запустим крэкми с помощью F9, то увидим, что не только не открылось окошко крэкми, но и программа не запустилась.

724f1b29570c7ad63dc35224f8e41889.png

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

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

be7c9898222bfebaf703ff92973b8d5f.png

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

7de9746516ee76ba91897954b2fdc614.png

И смотрите, что мы нашли, хе-хе.

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

154e39454360712a179b27992e48b426.png

Нажимаем RUN и останавливаемся на вызове этой функции.

a4ebe2726ccfc2909f322564bf2b37fb.png

0d7521b48959807c2c342477418af2b6.png

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

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

cd7b02536e9399e340b7522566b02a3d.png

Это разъяснение функции. Переведём его.

API-функция IsDebuggerPresent показывает, находится ли процесс, который её вызывает, в контексте отладчика, то есть отлаживается ли он.

Далее говорится, что функция экспортируется из KERNEL32.dll, у которой, как видим, нет параметров, и если программа находится под отладкой, то возвращаемое значение равно единице, а если нет, то нулю.

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

a5d527bbc3bf3f04c4c0559fc3ba14ad.png

Доходим до RET, где смотрим регистры.

2aad9ef29aff86afb5c9e7fddb17c9c0.png

b1b5632b929d2e314677ac39ac94b824.png

Выделенное розовым цветом – это место, где изменяется EAX. Как практически все API-функции, IsDebbuggerPresent помещает возвращаемое значение в EAX, тогда если в нём 1, то это говорит о том, что программа находится под отладкой.

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

aec7b53ba072253f43555f5169c3cca1.png

2329e4dc8d986fe4a00815a3207fc55c.png

Делаем RUN.

648c627dafe67287973ce3558b5ab714.png

Снова останавливаемся на API-функции, поэтому снова доходим до RET и меняем EAX на ноль.

9a797afe65d1e8f6b67c0cb59090c086.png

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

921a28d7de43a0b1fadf111652134773.png

Снова доходим до RET, теперь можем перейти к пошаговой отладке с помощью F8.

388e1b78587892594e8bab0496d36c05.png

Когда доходим до RET, EAX равен 1, вернёмся в программу, нажав на F8.

643715c698bcfe09a795f9af932a6ba9.png

Здесь мы, прежде всего, видим, что если нет DLL uxtheme, то вызова не произойдёт. Делаем RUN и теперь происходит остановка на API-функции.

ffabd7105f249f5c7efda1362cd55de5.png

Там останавливаемся во второй раз, доходим до RET и возвращаемся в программу с помощью F8.

10bc90c1ade7a81b278546fd88960ab3.png

Оказываемся у JE, где происходит тестирование, равен ли EAX нулю или нет. Идём дальше.

881255319b1bc78f7d821749be15dba0.png

Видим, что если EAX отличается от нуля, то перехода не происходит, также замечаем, что если переход происходит, то выполнение программы продолжается функцией GetDlgItem, которая считывает информацию из окна крэкми.

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

6a1743cf99b566fcd4baefcd26c32fc7.png

Продолжим трассировку, чтобы узнать, куда попадём.

8101544439d2f7d25e680c35f30948e2.png

Новая API-функция – PostQuitMessage, посмотрим её описание.

5e4f41867a4bf2ab7b92ce09f4b90a0c.png

В переводе это означает, что данная API-функция посылает сообщение для закрытия окна WM_QUIT, то есть указание на то, что выполнение скоро будет завершено.

По возвращению оттуда:

42ea77253bb9f764e692028bac0f66dd.png

И если у нас будет терпение оттрассировать достаточно до того момента, когда всё закрывается, то обнаружим, что вызывается API-функция ExitProcess, которая и завершает процесс (если терпения нет, то установите на неё ExitProcess и остановитесь прямо на ней).

2732fc987b53bcae6e374e5c14647b73.png

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

f16d902500da99c13a4bcfe17f2c33ff.png

Останавливаемся там и изменим JE на JMP 4011b2 (для этого нажмите пробел).

f7db5e3a6b9290061cfe0b74548d885e.png

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

Сохраним программу с внесёнными нами изменениями под каким-нибудь другим именем. Нажимаем правую кнопку мыши.

286ad93a60cbdec701dfbde42c9db2dd.png

И в открывшемся окне снова нажимаем правую кнопку.

095aff19e3242bb08a050e10bab0de23.png

b6883a231c4070c17513d62a793b841b.png

Сохраняем под именем crackme1p, так что теперь у нас исходная программа и пропатченная.

Теперь откроем пропатченную программу в OllyDbg, чтобы проверить, выполнится ли она в отладчике. Никаких BP устанавливать не будем.

9d3f36249c1379eccf4fdeffb0e78320.png

20e7e101694cba33565b25e7dc615783.png

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

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

А сейчас загрузим исходный файл и рассмотрим API-функцию поподробнее.

70e9ca8ee2c60a05319275d4ac4449e4.png

31475ff769e2007da64901ac70ced061.png

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



MOV EAX,DWORD PTR FS:[18]
MOV EAX,DWORD PTR DS:[EAX+30]
MOVZX EAX,BYTE PTR DS:[EAX+2]
Можем их просто скопировать их по очереди.

d8fea8c936c0fc25c84ff1ec50d6db74.png

cd91eda0bbdc7b7c513c55e0acaeb320.png

Итак, добавили три строки.

2af8807d6a99ba2fc3da31c382a48766.png

Видим, что после выполнения последней из них, в EAX содержится значение 1, также, как после выполнения API-функции, из которой мы и взяли эти строки.

ca513b81041d7df8c884c5d21f5c5f2f.png

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

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

Когда программа запускается, система сохраняет в определённом месте в памяти, находится ли она (программа) под отладкой, и если там находится ноль, то значит, что нет. Этот байт и считывают эти три строки и соответствующая API-функция.

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

Первая строка:

b5f437f2f432e94e1ec52da3700db27c.png

В OllyDbg идём сюда:

2b3538723af8fa01f208292060edd6a1.png

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

cb8de18a344d05a46b32ed6ca3f3cf84.png

Эта структура называется TEB или TIB и хранить полезную информацию, которая нам может быть нам очень полезной. Например, в TIB хранится, откуда начинается и где заканчивается стек программы.

bf6643e13436d5999c4b192e97940c49.png

Посмотрим в окне M секцию стека.

6449762ae440de054d84b43cadd57815.png

Видим, что начинается в 12d000 и заканчивается там, где начинается следующая секция (130000).

Есть много других интересных значений, которые мы рассмотрим, когда будем изучать исключения, но пока, если взглянем на стек, то увидим по вышеуказанному адресу значение 12ffE0 (у меня).

62f2a28a59537ee90bcdc27d114654e5.png

Поищем его в стеке.

7a8fd5bd5a91070a5e4a8cf7267a67a5.png

Видим, что оно помечено как END OF SEH CHAIN (конец SEH-цепочки). Пока что это нам мало что говорит, но это связано с исключениями.

Интересно то, что следуя определённому алгоритму можно достать из него любое значение, например, которое находится после Fs:[0].

7fbf88fa4b95dc6a8561f343894e899b.png

Это Fs:[0], если поищем в command bar’е значение fs:[1], то получим:

ac30152f17d2481144289a29d292ad65.png

Поэтому:



Fs: [0] на моей машине здесь содержится 7ffdf000
Fs: [1] на моей машине здесь содержится 7ffdf001
…………………………………………………………………….
…………………………………………………………………….
Fs: [18] на моей машине здесь содержится 7ffdf018
То есть, это значение, которое, как мы помним, было на первой строке API-функции.

9b52939b9d67227594c92646c5a1e5d4.png

То есть видим содержимое 77ffdf018 (оно же FS:[18]).

c024b2b39b51dc883f3657e0c02c2448.png

Вот это значение, которое сохранено в TIB в FS:[18] – значение, которое отображается в регистрах, указывающее на начало TIB.

Таким образом, первая строка загружает в EAX указатель на начало TIB, конкретное значение может отличаться на разных машинах. Нажав F8, мы переместим это значение в EAX.

059e9af89c1ab94de891631e40b7f2df.png

Хорошо, теперь в EAX находится указатель на TIB.

2e724504da2f006ab50ea18b382cab1b.png

Теперь следующая строка.

5af9209cf695162cf4d7fc9ffa8f9c1c.png

К EAX прибавляется 30, на моей машине в результате получается 7ffdf000 + 30 =7ffdf030.

Это fs:[30].

a5d221a8f37c1805aff6951c6933f732.png

То есть в EAX помещается содержимое 7ffdf030 или fs:[30], на моей машине это содержимое равно 7ffdc000, не спутайте это с началом TIB, эти значения различаются.

3f8a3952b8ba45821c1edd10868c5dbe.png

Это указатель на что-то другое, посмотрим на что именно через DUMP:

cbeeb8d25d322e5393932d7c01277e9f.png

Последняя строка:

be0ca925733d4426cb1e23744d3a687a.png

Сумма 2 и EAX равна:



7FFDC000 + 2= 7FFDC002
И в EAX перемещается байт, адрес которого получился в результате, а он и есть искомый байт. На моей машине он находится по адресу 7FFDC002.

175fadebef25ceaf32bd7c2b19173296.png

Система сохраняет 1 в этом байт, который считывается API-функцией IsDebuggerPresent. У вас адрес этого байта может отличаться, но вы сможете легко его найти, используя вышеуказанный метод. Загрузим заново крэкми в OllyDbg.

e6e4b1017237b83c1a7acde2154d7789.png

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

Ищем начало TIB в окне регистров.

d19d7a5944f510825e05851c42e0e876.png

Смотрим TIB через DUMP (он уже не будет располагаться по тому адресу, что в прошлый раз).

9a7934cb0df90b586e13efb0d196987b.png

Ищем fs:[30], то есть к адресу, указывающему на TIB, прибавляем 30 и смотрим содержимое, находящееся по получившемуся адресу.

fb30e146e16e800beb6fa6ee34670cad.png

Его содержимое (7ffde000) также является адресом, смотрим через DUMP.

cf48c8e69e6e8cc9bab2c44f8e866ddf.png

И прибавляем 2 – вот и искомый байт. (Многие обращают внимание, что когда программа запускается, в EBX уже находится указатель на эту область, так вот, EBX=fs:[30]).

ef126a2c64299a2350869aedc3293a03.png

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

c5218c0d7d0da376d84bae09eaf8cedc.png

1de9b3844344af13c2a09ba35648d838.png

Теперь установим BP на функцию IsDebuggerPresent, чтобы посмотреть, работает ли данный подход.

15eb2476d92a379fa9efb6fa36e3fcc7.png

Трассируем до RET.

4cbed1fde03f4344db2bac330d51b58a.png

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

f7b5eba820ac14cee0401bad2eaf1500.png

И поэтому выполняется без проблем.

Разумеется, есть множество плагинов, которые делают то же самое, один из них – это HideDebugger 1.24.

Сначала скачиваем его, затем копируем dll в директорию с плагинами.

daff90d5e9dd2fc9df76e9dcfd6d400c.png

Копируем, хехе.

754703b219d86ab3e216d5bf1e9a199a.png

Теперь перезапускаем OllyDbg.

85c7430f48aac9abc9b06ca60d5c1de8.png

Смотрим настройки плагина.

2b02392d68d19f86a9cbc7a748075e26.png

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

Нажимаем SAVE.

072a85f0a418d89c572b4ecac1e764db.png

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

0606b658ab46e829f28f4fe94ab52628.png

Теперь EBX-FOLLOW IN DUMP.

7658daf3915d0233caf3c09f64b28d45.png

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

О нас

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

    Dark-Time 2015 - 2024

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

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

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