> 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-24.md).

# Глава 24

Мне попросили, чтобы прежде, чем начинать рассказ об исключениях, я рассказал о том, как запустить в OllyDbg крэкми "antisocial" [\[ссылка\]](https://github.com/yutewiyof/intro-cracking-with-ollydbg/tree/3679d233f4d394747f712e9b6b09bc9c2a3cad80/.gitbook/assets/files/23/antisocial1.7z), которое было приложено к предыдущей статье.

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

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

Итак, запускаем antisocial в переименованном и пропатченном OllyDbg со всеми доступными плагинами.

![](/files/-LmvTvhegx9nvCD2eEI8)

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

![](/files/-LmvTvhtEXqWo0scvaQf)

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

Запускаем, чтобы посмотреть, до куда дойдёт.

![](/files/-LmvTviCBHWwmE59lb4s)

Досюда.

![](/files/-LmvTviUherra0O4SXnZ)

То есть, когда крэкми пытается сделать PUSH, выдётся ошибка, что нет прав писать в стек, но права писать в стек должны быть всегда. Взглянем на стек.

![](/files/-LmvTviehBq4A6PxPOAl)

То есть, значение наверху стека равно 130000, и если рестартуем программу:

![](/files/-LmvTviqlSDblZ0f_OrJ)

Посмотрим секции и увидим, что стек на моей машине идёт с 12c000 до 12ffff, ошибка возникает, потому что стек вышел за пределы своей секции на другую, которая начинается с 130000, а туда-то писать как раз прав и нет.

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

![](/files/-LmvTvj1Gtso4CJDfCP8)

Видим, что программа выполняет ещё один popad и совершает JNZ-переход на PUSH, который также вызывает ошибку. Установим BPX на этот popad до того, как произойдёт ошибка.

![](/files/-LmvTvjBt3X7uNjKpHOH)

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

![](/files/-LmvTvjOOqiW_fWFVPx6)

Смотрим стек.

![](/files/-LmvTvjgxlRO_5VJN0lR)

Находимся в правильной секции. Запускается POPAD.

![](/files/-LmvTvjuD640q2MKtDBs)

Здесь заканчивается секция, так что проблему можно решить, забив POPAD NOP’ами, но вообще, POPAD должен предшествовать PUSHAD, которая сохраняет начальные значения регистров в стек, а этот POPAD тогда будет получать их обратно, поэтому давайте посмотрим, что будет, если заменить POPAD на PUSHAD. Рестартуем программу.

Нажимаем пробел.

![](/files/-LmvTvk9PIuatevWv04A)

Пишем PUSHAD.

![](/files/-LmvTvkK61ByNe1JNbVw)

![](/files/-LmvTvkYIlcJagPLEp7I)

Теперь нажимаем RUN и останавливаемся на второй POPAD.

![](/files/-LmvTvkk63LFStwUx_Jz)

Но в этот раз стек в порядке.

![](/files/-LmvTvkusVb0X-zvoIls)

Поэтому POPAD не выходит за границу секции стека, и мы можем миновать это место с помощью F8.

![](/files/-LmvTvl-gtguuWaUD7tZ)

Видим, что всё прошло без проблем.

![](/files/-LmvTvl7o0Nng5kPeCUi)

Доходим до PUSH и RET, трассируем и, нажимая на F8, доходим до RET.

![](/files/-LmvTvlHfQzaz6kMYKmq)

Хорошо, здесь есть проблема с анализированием.

![](/files/-LmvTvlc6B9bubNM2Z-H)

![](/files/-LmvTvm6xXxrelxJ2PRj)

Здесь это особенно видно.

Посмотрим, что случится, если сделаем RUN.

![](/files/-LmvTvmOyDm5sFOx4Vsl)

![](/files/-LmvTvm_hiiNHQn8vUdJ)

Так как программа завершилась, посмотрим в LOG’е OllyDbg, есть ли там что-нибудь интересное.

![](/files/-LmvTvmlJg29Iy94VY_5)

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

![](/files/-LmvTvmxUM-wTpmvceW3)

Уберём галочки со всех опций, которые относятся к исключениям.

![](/files/-LmvTvnA_i3LALWkcips)

Делаем RUN.

![](/files/-LmvTvnNaw5qENJezAvn)

Останавливаемся на исключении, что отображается в LOG’е.

![](/files/-LmvTvnWpdY5Vctt2oH9)

INT68 – одно из немногих исключений, которое OllyDbg не может избежать, но можем забить его NOP’ами.

![](/files/-LmvTvneWqLnv1dOFg9h)

![](/files/-LmvTvnpqqp790meV1NE)

С другой стороны, знаем, что могут быть ещё INT68, которые будут мешать, поэтому поищем их и также забьём NOP’ами.

![](/files/-LmvTvo-C2Viu7h5jTzO)

![](/files/-LmvTvoAmiZO-ZEY1cpK)

![](/files/-LmvTvoJlH_XEfM7FXmX)

Видим, что нашлось ещё одно исключение, забиваем его NOP’ами.

![](/files/-LmvTvoW5rmBo1vwY9Uu)

Ищем заново, находим, забиваем NOP’ами.

![](/files/-LmvTvoiGOrxjkzF99RQ)

Если нажмём CTRL + L, то продолжим искать то, что искали в последний раз.

Когда ничего больше не находим, делаем RUN.

![](/files/-LmvTvowz3LgcYVK1ZGO)

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

![](/files/-LmvTvp7O5SlBY47d-bx)

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

![](/files/-LmvTvpKHKJRNhWsnePS)

![](/files/-LmvTvpTnK2awYb1Bn1H)

Как видим, здесь только один плагин. Запускаем OllyDbg.

![](/files/-LmvTvpdhABnJcIw8GNb)

Повторяем операции по замене popad.

![](/files/-LmvTvppAdoLY3Fekggv)

![](/files/-LmvTvq2zePEqIrKolj0)

Устанавливаем BPX на POPAd, нажимаем RUN и смотрим куда попадём.

![](/files/-LmvTvqBJWTQ1AqCHHJg)

Прибываем туда, где распаковывается код программы.

![](/files/-LmvTvqJveRJyGOM7Dtu)

Можем забить INT68 или снять галочки с исключений, и каждый раз, останавливаясь на INT68, забивать его NOP’ами, а не идти дальше с помощью SHIFT+F9, как это мы обычно делаем с другими исключениями.

![](/files/-LmvTvqUQSGPEoHgbFSb)

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

![](/files/-LmvTvqda1WNtTbvMksp)

Необходимо отметить её, чтобы отображалась информация о секции, в которой мы сейчас находимся.

![](/files/-LmvTvqmiw-8JXs0PMLj)

![](/files/-LmvTvquaILCgziuikUd)

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

![](/files/-LmvTvr4SxUwW0dyXmbU)

Жмём RUN.

![](/files/-LmvTvrClaXBFBlJtzgI)

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

![](/files/-LmvTvrKasgpgAgYPaOQ)

Здесь нам повстречалась первая странность: API-функция, которая делает снимок состояния всех выполняющихся процессов. Доходим до RET и ставим BP EAX, так как EAX будет содержать адрес функции.

![](/files/-LmvTvrYNjtLAu_sqJBG)

![](/files/-LmvTvrkgrxYaVmqBuxG)

![](/files/-LmvTvrvr1ddEMPDVi1p)

![](/files/-LmvTvs6okiJfF2ct_Ns)

Там, где находится BP, оставим комментарий, чтобы не забыть, к какой API-функции это относится.

![](/files/-LmvTvsJE6zGJrh8g60Y)

Список продолжается.

![](/files/-LmvTvsV3Q4BzYb_06n1)

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

![](/files/-LmvTvsf7ThqcTKAd8WH)

Жмём RUN.

![](/files/-LmvTvsrokloBU5u3tLl)

Ставим BP на неё.

![](/files/-LmvTvt1ML-3uGe9ux2C)

![](/files/-LmvTvtCRqZqX9dk9lNp)

То же самое.

![](/files/-LmvTvtNMNvia9L0RGMs)

![](/files/-LmvTvtYQejxdFiTIUsD)

![](/files/-LmvTvtifBIVUI_EBaAK)

![](/files/-LmvTvttcXic3ZsVI1BA)

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

![](/files/-LmvTvu4G0r2V90q-QrZ)

Видим пустые пробелы (NOP’ы), так что можем сделать EAX равным нулю, до того как его значение будет возвращено.

![](/files/-LmvTvuG9eWMgAT_5N0i)

Так мы возвращаем ноль, и у программы нет логического номера, с помощью которого она могла бы обработать снимок или что-то узнать о процессах. Это один способ, а другой состоит в изменении кода самой программы. Выполним неизменённый RET функции.

![](/files/-LmvTvuSVPj8bW1bo4Zv)

Чуть пониже есть JNZ-переходы, а ещё чуть ниже их – вызов TerminateProcess, который закрывает OllyDbg, и перед которым есть OpenProcess, получающий логический номер программы.

![](/files/-LmvTvueKnpLy6BAt9jI)

Если заменить все JNZ на JMP, можно избежать перехода на TerminateProcess и закрытия OllyDbg.

Первая часть защиты преодолена, теперь переходим ко второй части. Жмём RUN.

![](/files/-LmvTvupYAiXOUl0LQbn)

Забиваем NOP’ами, запускаем выполнение программы, но она всё равно закрывается. Если поставить плагин HideDebugger [\[ссылка\]](https://github.com/yutewiyof/intro-cracking-with-ollydbg/tree/3679d233f4d394747f712e9b6b09bc9c2a3cad80/.gitbook/assets/files/19/HideDebugger124.7z), который защищает от FindeWindows/EnumWindows, то выполнится нормально, если повторить сделанные до этого шаги.

Место, где происходит закрытие, следующее:

![](/files/-LmvTvv-9jekniyxY1Bq)

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

![](/files/-LmvTvvAdy-zUTUygKUM)

![](/files/-LmvTvvN-c1kctaK9b4_)

Видим, что здесь сравнивается.

![](/files/-LmvTvvY0auQNa1pplcw)

![](/files/-LmvTvviAdfYTfIrmOpz)

Вопрос в том, как избежать сравнения этих нехороших вещей, хе-хе, можно сделать это заменив JNZ, который стоит после первого CALL, на JMP.

![](/files/-LmvTvvtmGOhZp5gADlY)

Этот загадочный переход заменяется на JMP.

![](/files/-LmvTvw3y7FYJN40LWKT)

Избегаем второго CALL, внутри которого находится следующее.

![](/files/-LmvTvwGBFNWV_rqcIjv)

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

Конечно, если спросите меня, как найти этот JNZ, то это легко.

Как только прошли первую часть защиты, устанавливаем BPX на PostQuitMessage.

![](/files/-LmvTvwQx383My8Zt0xt)

![](/files/-LmvTvwZTAFg9EivYl7A)

Останавливаемся на API, смотрим на стек, чтобы узнать откуда вызывается.

![](/files/-LmvTvwkhPi_f5705cco)

Идём в 4532d7, так что стек расскажет, откуда происходит вызов.

![](/files/-LmvTvwvxEJ70C08THKK)

Конечно, я попробовал изменить JE, стоящий перед PostQuitMessage, на обратный и не смог избежать закрытия окна, так что идём ко втором RETURN TO, который есть в стеке.

![](/files/-LmvTvx51ETyy2KSf8Vc)

Он ведёт в 4532СС.

![](/files/-LmvTvxJy3u8bdCuGPxN)

Как видим, этот call можно избежать, обратив JNZ, и тогда не будет вызван и PostQuitMessage, и изменив JNZ на JMP видим, что крэкми выполняется без помощи каких-либо плагинов.

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

До встречи в 25-ой главе, где мы будем изучать исключения.

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