# Глава 44

Ок, продолжаем как обычно. Мы уже нашли украденные байты, и у нас теперь есть скрипты [\[ссылка\]](https://github.com/yutewiyof/intro-cracking-with-ollydbg/blob/master/.gitbook/assets/files/44/scripts%20\(44\).7z) для того, чтобы легко попасть в OEP и чтобы починить IAT, так что осталось сделать дамп.

![](/files/ojslQYO4Lgx7SxUOwz7x)

Открываем программу [\[ссылка\]](https://github.com/yutewiyof/intro-cracking-with-ollydbg/blob/master/.gitbook/assets/files/42/UnPackMe_ACProtect1.09g.f.7z) в OllyDbg и устанавливаем два BP, необходимых для работы скриптов, и стираем BPX, которые могли остаться от прошлого раза.

![](/files/aZCBFaLad7r1bjqaKu9G)

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

![](/files/QZTEoMoj5KG4fYy7ZhuX)

![](/files/5c6lHmTaE2sPqAN1BsqX)

Отвечаем, что нет и находимся в OEP.

![](/files/UwgMl05WhUMnV3JiTdYt)

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

![](/files/WfvodTWKLkUuQxiFiDiq)

![](/files/ij7Ec5kX4nUx6EVaLEWI)

Снимаем галку и сохраняем как dumped.exe или другое имя, которое мы хотим. Теперь перезапускаем OllyDbg и используем скрипт для того, чтобы работать с починенной таблицей.

![](/files/ipHkXc6uh3OFWqNmAOve)

Здесь уже всё работает, так что открываем IMPORT RECONSTRUCTOR [\[ссылка\]](https://github.com/yutewiyof/intro-cracking-with-ollydbg/blob/master/.gitbook/assets/files/34/ImportReconstructor16f.7z) и ищем нужный нам процесс в списке процессов в выпадающем меню.

Теперь ищем данные OEP, RVA и РАЗМЕР IAT, как мы это делали в прошлой части.

OEP=**271b5**

НАЧАЛО=**60818**

РАЗМЕР= 460f28-460818= **710**

Видим, что все API-функции правильны кроме одной. Я её пропустил?

Можем посмотреть, что случится, если бы эта ошибка не была показана. Рестартуем OllyDbg и устанавливаем на этот элемент MEMORY BREAKPOINT ON WRITE.

![](/files/KuiOA1OSBvNpRa6gD4Pr)

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

![](/files/xTtfdGYY16KqdqInb8TF)

Здесь видим, что будет сохраняться значение и в ESP-0C нет никакой API-функции.

![](/files/JDlsC0gpAeEu6nnhgN4V)

Видим, что скрипт изменил его на значение, которое в данном случае равно 46E5CB, так что видим значение, которое сохраняется в IAT без использования скрипта. Нажимаем F7.

![](/files/zfoMvWRHk0eCNKaRyOyB)

Значение, сохраняющееся без использования скрипта, будет плохим, так что смотрим, куда оно ведёт. Идём в 46BD5B.

![](/files/qPhC8UMGXQlpe2p4x8zL)

Хорошо, как видели раньше, выполняется PUSH константа, и над ней совершается XOR с другой константой, а результатом этой операции становится адрес API-функции. Считаем.

942c0892 xor 946aed59

Если нет желания использовать калькулятор, может использовать то, что OllyDbg выполнит сама эти строки и получит результат, хе-хе.

![](/files/P3gMNS4LsZT6rLICYCcb)

![](/files/KSvTpLANbXzP0hmxNeQd)

Видим, что результатом XOR является 46E5CB – это значение, которое скрипт поместит в элемент, поэтому скрипт не ошибается. Дело в том, что этот элемент особенный, так что рестартуем и прибываем в OEP, что посмотреть, найдём ли то, к чему динамически относится API-функция, то есть, откуда она запускается.

![](/files/yuVvnlPVYdEIN8cXjUaw)

Тут оказываемся в OEP с помощью соответствующего скрипта и устанавливаем BPM ON ACCESS на элементе IAT, относительно которого хотим узнать, к какой API-функции он ведёт, для чего останавливаемся, чтобы получить к нему доступ.

![](/files/cTP4TZIXjXSRYVENR1RV)

Останавливаемся, трассируем.

![](/files/AnX0n0ourpe7lo3jzWRZ)

Конечно, доходим до RET и отсюда прыгаем:

![](/files/KRhpjIfhRXtDq93R6str)

Посмотрим, ведёт ли это к какой-нибудь API-функции. Начинаем трассировать с помощью F7 и видим, что это ведёт в большой кусок кода, так что применяем метод pushad. Вот эта инструкция в начале, и останавливаемся на POPAD, до куда нужно оттрасировать некоторое количество строк.

![](/files/LZMemdmLENCGsArkoxUP)

И видим, что API-функция, с которой у нас проблемы – это MessageBoxA.

Другой, более быстрый метод – это сделать RUN TRACE с условием, что необходимо остановиться, когда EIP станет, например, больше 500000, то есть когда произойдёт выход из секции в API-функцию. Смотрим:

![](/files/H82xjn5vRyqTTOFueJob)

Здесь останавливаемся, когда EIP выходит за пределы 0-500000. Пробуем, сработает ли.

![](/files/sJvK7wZWEcAwavhvgLUb)

![](/files/XEepxm40PtcjFjMmVMMV)

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

![](/files/2tcVxWM1tnPziV1PAfHW)

Адрес возврата – это 40E51B. Если пойдём туда:

![](/files/PuXvkGgtkWNCeEemmJt5)

Возвращаемся прямо на следующую строку вызванного call’а, так что у нас уже есть все данные. Перезапускаем процесс с помощью скрипта для IAT и устанавливаем данные как в прошлый раз в IMP REC.

![](/files/oesCjiQhmEKYfCoaBaeN)

Делаем двойной щелчок по неправильному элементу и меняем его на MessageBoxA.

![](/files/HxrcOUUaMV6oeGIO0L1i)

Теперь, если всё правильно, починим дамп с помощью FIX DUMP. Ищем файл дампа.

![](/files/9C32PZcuUcUfejFxiGAZ)

И сохраняем его как dumped\_.exe. Нам осталось исправить OEP на предмет украденных байтов, так что открываем файл в OllyDbg.

![](/files/KrUT9IOttGEnk50T8wsJ)

Нам нужно скопировать украденные байты и поменять OEP.

```
00485AF3 Main     PUSH EBP
00485AF4 Main     MOV EBP,ESP                               ; EBP=0012FFC0
00485AF6 Main     PUSH -1
```

Вот украденные байты, которые мы можем ввести с помощью функции "Assemble".

![](/files/EHRUhkcNq0rtO0Bt7w6x)

![](/files/86HTkRv0lVHliAzht46v)

Видим введённые байты, которых ровно пять, так что теперь считаем: 4271b5 (фальшивая OEP) минус пять байт дают нам правильный OEP, то есть 4271b0.

![](/files/JboEvKkd4tUzSS7oCV1M)

Теперь, если сохраним изменения с помощью COPY TO EXECUTABLE – SAVE FILE, мне останется поменять OEP. Перезапускаем и идём в заголовок дампа с помощью GOTO EXPRESSION 400000.

![](/files/WyCbjULP2hRk8Lcup7Al)

Переходим в режим SPECIAL-PE HEADER, ищем значение ADDRESS OF ENTRY POINT, меняем его и сохраняем изменения.

![](/files/bm0EjNuF2HnJtleAignN)

![](/files/lgzCATms0BcLG6S6e6Tf)

Ок, если запустим файл после починки, то будет показана ошибка. Снимаем все галочки с исключений и смотрим, какой ещё трюк был применён против нас.

![](/files/ZY4GzpCkY1AgnQ5tmNV5)

Видим в LOG’е, что произошла ошибка, смотрим CALL STACK, то есть нажимаем кнопку с буквой "K", показывающую последние исполненные call’ы (можем также посмотреть в стеке RETURN TO…).

![](/files/hzJk11uRQxU3q7INe2r7)

Последний CALL был выполнен из 429806, идём туда.

![](/files/v74b7dWRrTzrOZ0gP6JR)

![](/files/fZx6zE0AV5AXFkxIZeIb)

Продолжаем с помощью FOLLOW, чтобы посмотреть куда идёт CALL.

![](/files/mHTwXPr1oHll6cSP0D3g)

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

Запускаем оригинальный файл в другом OllyDbg и доходим до OEP с помощью скрипта, стирая старые HBP и устанавливая два необходимых BP.

![](/files/VdiRVropbWTePcIMjpse)

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

![](/files/q9Rssdl4Ss2O0Go5oQVY)

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

![](/files/nPAzzKfF2Pw8pzISPL1f)

Ок, есть много способов решить эту проблему. Классический – это сделать инъекцию в то же место, где создаётся секция и скопировать все байты в вышеуказанную секцию, откуда всё сохраняется, а затем перейти на OEP, починив всё. Смотрим, сможем ли найти альтернативный метод, который были бы гораздо проще, так как описанный метод мы будем использовать часто в других упаковщиках.

Ищем первый переход в 46c0f5.

![](/files/KMRGd5sNTS7qwYU1orLu)

Он занимает 6 байт – инструкция JMP, ведущая в 178250, где также происходит выполнение 6 байт и возврат.

![](/files/3GYw1JRYmcA2k4jp6Q8u)

Идея заключается в том, чтобы заменить 6 байтов косвенного перехода на 6 байтов, которые действительно что-то делают.

![](/files/n7kysLlyUbA0XASXec0N)

Отмечаем три строки и делаем BINARY COPY.

Возвращаемся к переходу и делаем BINARY PASTE.

![](/files/8OYuv4KwYO4srZlZqcGF)

![](/files/moJv2qfAZd8Ge7H49tlM)

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

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

![](/files/zTmmxuhX7ilEOBEe0eJG)

Байты начинают выполняться с 178256 – это первый элемент таблицы, а последний заканчивается в 1799ba.

![](/files/nqCSp3W0myRHo4eZHYP7)

Так что копируем с помощью BINARY COPY всю область с нужными нам байтами и заменяем переходы с помощью BYNARY PASTE.

![](/files/z6KdZ3mnR8RmwBjueKuQ)

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

![](/files/LSSmZL3mE8dOtcuqlqHp)

Я предположил, что эти переходы не используются, так что, по идее, проблем возникнуть не должно. Ок, починили секцию. Теперь может сделать BINARY COPY всей секции и скопировать её в файл дампа с помощью BYNARY PASTE.

![](/files/lw6inIbn4SBVjlPEV4QF)

Теперь сохраняем изменения в дамп с помощью COPY TO EXECUTABLE и так далее.

![](/files/835hDRU2euHAQb7yEXOC)

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

![](/files/CpDf1sqGwtLKvcrc3om0)

Отмечаем отсюда и до начала секции вверх и сохраняем изменения. Перезапускаем и пробуем.

![](/files/j1hABfOQ3gqdKBMdF4qz)

Работает превосходно. Мы победили украденные байты, переадресовочную IAT, антидампы, и защиту против HBP.

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


---

# 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/ch-44.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.
