# Глава 56

[Прикрепленные файлы к статье](https://github.com/yutewiyof/intro-cracking-with-ollydbg/tree/37614a6cb157fe18b76d7ddc29fc259e5403c1eb/.gitbook/assets/files/56/\(123\)AttachedFiles.zip)

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

Запустив программу вне OLLYDBG мы увидим :

![](/files/-LmvTvmmMInYMvTRYf3P)

Мы знаем, что это b, он должен быть немного сложнее и мы видим, что задействован агрессивный режим, wow, я уже дрожу, хе-хе.

Давайте, прежде всего, посмотрим, выполняется ли программа в OLLYDBG с конфигурацией, использованной нами прежде, с plugin OLLY ADVANCED и остановкой в system breakpoint для удаления BP, размещаемых OLLYDBG для остановки на EP.

![](/files/-Lk33RvHEwljqJ1ELByp)

![](/files/-Lk33RvQuUlrI_WJvOlO)

Мы в system breakpoint, перейдем в окно b, чтобы удалить breakpoint, размещаемый OLLYDBG автоматически.

![](/files/-LmvTvniGfVBv_olY1RL)

Хорошо, я удаляю их и помещаю BREAK ON EXECUTE в первую секцию, как и раньше

![](/files/-Lk33Rvi0T8p01s5uwRz)

Не забываем, что для этого нами используется plugin OLLYBONE.

Хорошо, давайте сделаем RUN

![](/files/-Lk33RwRS8YfZFE-iz08)

Хорошо, до сих пор различий нет, давайте уберем флажок BREAK ON EXECUTE и остановимся.

Если немного присмотреться, можно заметить, что у нас появилось много threads в сравнении с предыдущим вариантом unpackme, в котором при попадании в OEP их было всего 2.

![](/files/-LmvTvp538ugQ-ZFTHYc)

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

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

![](/files/-Lk33RwnhnYtmsr7M_sj)

Я кликнул правой кнопкой мыши и выбрал SUSPEND для всех потоков, кроме главного, выделенного красным цветом, программа выполнится все равно? Давайте посмотрим.

Мы видим, что программа остается RUNNING и ничего не происходит.

![](/files/-LmvTvpcyrRLxznIfN3i)

Прервав выполнение и посмотрев в call stack, мы увидим, что находимся в WaitForSingleObject, что говорит нам о том, что поток чего-то ждет и пока другие прерваны, он не продолжит свое выполнение.

Хорошо, чтобы найти тот поток, который ждет программа, давайте выберем RESUME для первого потока и сделаем RUN.

![](/files/-Lk33RxHv6iezKSpdngq)

![](/files/-LmvTvq1cnXD_xMu0uGa)

Мы видим, что ничего не происходит и программа по-прежнему имеет статус "RUNNING", сейчас, не прерывая программы, давайте снова остановим первый поток и восстановим второй и так до тех пор, пока не найдем есть ли один, который приведет к выполнению программы.

![](/files/-LmvTvqBkG328n9t638F)

Когда я включаю этот thread, программа выполняется.

Мы видим, что thread - процедура, которая начинается в 270000 на моей машине.

![](/files/-LmvTvqPg_FmOcVJCnuM)

Мы видим, что это просто процедура, находящаяся там

![](/files/-Lk33Ry0JlOCCIwBIac2)

Давайте поместим BPM ON ACCESS в вышеупомянутую секцию

![](/files/-LmvTvrI3Vbi7jckPA4h)

Мы не будем углубляться в исследование работы threads, так как наша задача - ремонт IAT.

![](/files/-Lk33RyI4iUTwt_wq3f_)

Давайте проверим, будет ли выполняться программа с основным и начинающимся на моей машине в 270000 потоками, так как чем меньше будет вмешательства, тем лучше, если бы не было достаточно двух, нам бы пришлось искать 3-ий или другое минимальное число, другая возможность заключается в поимке вызова ExitProcess с помощью BP, так как программа завершает все потоки, перед выходом, и пытаться продолжить с этого места выполнение скрипта.

Давайте посмотрим, будет ли выполняться программа только с этими двумя потоками

![](/files/-LmvTvs7MZ1cQ2AhwBR4)

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

Давайте выполним RUN и посмотрим, что произойдет.

![](/files/-LmvTvsR-RDCiu-9kNQT)

Хорошо, эти два threads - необходимый минимум, требуемый unpackme для выполнения.

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

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

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

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

Хорошо, так как я заметил во время предыдущих запусков, что, как и в версии "а", первый адрес в IAT переписывается корректным, я попробую вначале тот же метод, что и в предыдущей части, для этого я помещу BPM ON WRITE в вышеупомянутый адрес и запущу трассировку, которая через длительный промежуток времени завершится при срабатывании BPM в этом участке кода. (файл с трассировкой прилагается к статье)

![](/files/-Lk33Ryicv73tZU2hRgr)

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

![](/files/-Lk33RyvAIPDiQE7fWx5)

Мы видим, что сейчас эта инструкция расположена в 483420, так что теперь нам необходимо помещать HE ON EXECUTION в адрес 483423, который указывает на следующую инструкцию.

Конечный скрипт предыдущей части был

```
var tabla
var contenido
mov tabla,460818
start:
cmp tabla,460f28
ja final
cmp [tabla],50000000
ja saltear
mov contenido,[tabla]
cmp contenido,0
je saltear
log contenido
log tabla
mov eip,contenido
bphws 47691f, "x"
mov [47691f],0
mov [476920],0
cob reparar
run
reparar:
cmp eip,7c91e88e
je saltear
log eax
mov [tabla],eax
run
saltear:
add tabla,4
jmp start
final:
ret
```

Мы помним, что в предыдущей части адрес, где происходило чтение api, был

> **0047691C Main MOV EAX,DWORD PTR SS:\[EBP-C] ; EAX=77DA6BF0**
>
> 0047691F Main MOV ESP,EBP ; ESP=0012FFB0

в то время как сейчас

> **00483420 > 8B45 F4 MOV EAX,DWORD PTR SS:\[EBP-C] ; kernel32.GetVersion**
>
> 00483423 . |8BE5 MOV ESP,EBP

так что в скрипте мы должны заменить 47691f, который был адресом, где скрипт помещал HE ON EXECUTION, для получения верного адреса в EAX, на 483423 и скрипт примет вид

```
var tabla
var contenido
mov tabla,460818
start:
cmp tabla,460f28
ja final
cmp [tabla],50000000
ja saltear
mov contenido,[tabla]
cmp contenido,0
je saltear
log contenido
log tabla
mov eip,contenido
//483423
bphws 483423, "x"
mov [483423],0
mov [483424],0
cob reparar
run
reparar:
cmp eip,7c91e88e
je saltear
log eax
mov [tabla],eax
run
saltear:
add tabla,4
jmp start
final:
ret
```

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

Хорошо, давайте перезапустим olly, снова переместимся в OEP, нужно не забыть снять BREAK ON EXECUTE и галочки в DEBUGGING OPTIONS - EXCEPTIONS - MEMORY ACCESS VIOLATION, как в прошлый раз.

Сейчас необходимо не забыть остановить все threads, кроме 2, которые являются необходимыми, прежде чем выполнять скрипт.

![](/files/-LmvTvtiX7S6STnHIyXr)

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

![](/files/-Lk33RzDA9j8TxMyVXiI)

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

![](/files/-LmvTvuAvc4OD5nST4xU)

![](/files/-LmvTvuYiKQcgnTZYrK3)

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

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

```
reparar:
cmp eip,483423
jne saltear
log eax
mov [tabla],eax
run
```

Что же тут происходит? Неужели вариант b содержит дополнительные хитрости? Давайте посмотрим, где может быть ошибка.

Раньше при обнаружении ошибки происходила попытка закрытия программы, но теперь по логу видно, что не происходит вызовов ZwTerminateProcess, я провоцировал исключение для того, чтобы можно попасть и вернуться из ZWTerminateProcess, но теперь этого не происходит, может всему виной галочка в memory access exception? Давайте посмотрим, что будет, если я ее поставлю и запущу скрипт снова.

![](/files/-Lk33RzhT5eicpSjKeJA)

AHHHHHHHHHHHH, сейчас это функционирует как раньше, на каждом адресе порождается исключение из-за ошибки, которую я спровоцировал, и мы попадаем в ZwTerminateProcess и сейчас таблица исправляется, ошибка состояла в том, что не было отмечено memory access.

![](/files/-Lk33RzlHFsBdLUS_weN)

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

![](/files/-Lk33RzsEjaiPhZ1E_cp)

Скрипт принял вид :

```
var tabla
var contenido
mov tabla,460818
start:
cmp tabla,460f28
ja final
cmp [tabla],50000000
ja saltear
mov contenido,[tabla]
cmp contenido,0
je saltear
log contenido
log tabla
mov eip,contenido
bphws 483423, "x"
mov [483423],0
mov [483424],0
cob reparar
run
reparar:
cmp eip,483423
jne saltear
log eax
mov [tabla],eax
run
saltear:
add tabla,4
jmp start
final:
ret
```

(прим. пер. у меня это не заработало, мой вариант в файле 56\_1.osc)

и нужно помнить, что необходимо вручную установить HE on EXECUTION по адресу ZwTerminateProcess перед запуском, поставить галочку в MEMORY ACCESS EXCEPTION и отменять избыточные threads.

Я прибываю в OEP, снимаю BREAK ON EXECUTE, снова обращаю Ваше внимание на то, что должны быть отмечены все галочки исключений, устанавливаю HE ZwTerminateProcess и запускаю скрипт.

![](/files/-Lk33RzyRXqn69z9FaTR)

Исправление успешно завершается.

Сейчас я делаю дамп с помощью OLLYDMP и открываю IMP REC.

![](/files/-LmvTvvctQDSBx1C7rqK)

Я вижу, что все адреса исправлены

![](/files/-Lk33S-8YdKUo0DVMhkY)

Сейчас я должен исправить TLS, мы открываем dumpeado в OLLY и в header ищем

![](/files/-LmvTvw6Yhg6rHWsZK9X)

и изменяем на

![](/files/-LmvTvwGGz-mBZkzo1my)

а затем сохраняем изменения

![](/files/-Lk33S-QnseuaEfOdq6-)

Теперь программа функционирует правильно, хе-хе, в следующей части мы встретимся с c, еще один этап пути пройден.

До встречи в статье 57

\[C] Рикардо Нарваха, 10.11.06


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://backoftut.gitbook.io/intro-cracking-with-ollydbg-2/ch-56.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
