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

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

AnGel

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

AnGel

Администратор
Команда форума
27 Авг 2015
3,411
2,025
Хорошо, победитель обоих частей конкурса из прошлой части - это Ularteck, который прислал оба скрипта и объяснение первой части в виде туториала, который мы используем здесь. Вот скрпит-победитель первой часчти, который предназначается для починки украденных байтов. Объяснение идёт ниже.



/*
###############################################################################################################

CracksLatinoS - 2006

Скрипт создан: Ulaterck.

Описание: Скрипт создан для курса «Введение в крэкинг с нуля, используя OllyDbg» Рикардо Нарвахи, главы 52-ой. Он предназначается для первой части: ищет OEP и чинит украденные байты.

Цель: UnPackMe_TPPpack.exe
Требования: ODBGScript 1.48 , HideDebugger 1.24 , HideOD, остановленные на точке входа, снять все случаи исключений меньше KERNEL32, так как используемый метод – это метод исключений Рикардо.

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

В любом случае смотрите объяснение, которое находится ниже.
###############################################################################################################
*/

var dir_excep
var Newoep
var dir_JMP

var dir_CALL
var oep
var StartScan
var Opcodes
var temp
var temp2
var temp3

Datos:
mov Newoep, eip // Сохраняем адрес точки входа
// Отмечаем последний адрес скрипта
ask "Введите последнее исключение" // Выводить окно для ввода данных.
cmp $RESULT,0 // Сравниваем, был ли введён какой-либо адрес.
je aviso // Если нет, то прыгаем на метку aviso
mov dir_excep, $RESULT // Если ввели адрес сохраняем его в dir_excep.
jmp Inicio // Прыгаем на метку Inicio, чтобы продолжить.

aviso:
msg "Выполняем скрипт заново – введите правильный адрес"
jmp final

Inicio:
run // Запускаем программу
eoe verifica // Если происходит исключение, переходим на метку verifica.

verifica:
cmp eip,dir_excep // как только мы здесь из-за исключения, смотрим, последнее ли оно.
je ultima // Если да, то переходим на метку ultima.
esto // Если нет, то запускаем SHIFT + F9, чтобы пройти исключение.
jmp Inicio: // И переходи на метку Inicio для поиска других исключений

ultima:
findop eip,#FFE0# // Попав на последнее исключение, ищем переход JMP EAX на украденный код.
mov dir_JMP,$RESULT // Как нашли – сохраняем адрес в dir_JMP
bp dir_JMP // Устанавливаем точку останов (F2) на переход JMP EAX.
esto // Проходим исключениес помощью SHIFT + F9, чтобы оказаться в точке останова
bc dir_JMP // Снимаем точку останова с перехода JMP EAX.
sti // Запускаем F7, чтобы оказаться в украденном коде.

mov oep,eip // Сохраняем адрес украденного OEP.
mov StartScan,eip // Сохраняем адрес OEP также в StartScan, который используется для поиска Call'ов.

BuscarCall: // Также начинаем искать прямые вызовы, чтобы починить их, когда будет создаваться двоичная копия, и прикрепить их к новому OEP.
// Посмотрите MIniTuto.PARTE1.doc

findop StartScan,#E8# // Ищем прямые вызовы, которые начинаются с опкода E8
cmp $RESULT, 0 // Когда их больше нет, $RESULT равен 0 и переходим на
// метку final.
je final
mov dir_CALL, $RESULT // Сохраняем адрес первого встреченного call (вызова).
mov StartScan, $RESULT // Задаём, откуда ходим искать вызовы, в данном случае – оттуда, где был встречен первый вызов.
add dir_CALL,1 // К адресу встреченного вызова прибавляем 1, чтобы миновать опкод E8.
mov Opcodes, [dir_CALL] // Перемещаем опкоды из этого адреса в Opcodes.
add Opcodes,StartScan // К этим опкодам прибавляем адрес вызова.
add Opcodes,5 // К результату прибавляем 5 и получаем адрес, который указывает на вызов.
// Для пояснений смотрите MiniTuto.PARTE1.doc.


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

mov temp, StartScan // Помещаем адрес, содержащий StartScan, во временную переменную. ( StartScan = адрес встреченного вызова.)
sub temp, oep // От адреса вызова на починку отнимаем адрес OEP украденного кода.
mov temp2, Newoep // Перемещаем адрес нового OEP (EntryPoint) в вторую временную переменную.
add temp,temp2 // К ней прибавляем значение первой.
sub Opcodes, temp // Теперь отнимаем результат от адреса, на который указывает CALL.
sub Opcodes, 5 // И от того, что остаётся, отнимаем (в оригинале – прибавляем, но это не соответствует команде) 5, получая необходимые для починки этого вызова опкоды.

Editar: // Начинаем редактировать вызов с помощью новых опкодов.
mov temp3, StartScan // Помещаем в третью временную переменную адрес вызова для починки, содержащийся в StartScan.
add temp3,1 // К адресу вызова прибавляем 1, чтобы не учитывать опкод E8.
mov [temp3], Opcodes // Чиним вызов новыми опкодами.
jmp BuscarCall

final:
ret
Теперь продолжаем объяснение, как всё это работает, написанное Ularteck'ом.

Часть 1: Ищем OEP и чиним украденные байты (написано Ularteck'ом)

Введение:

Хотя всё уже было объяснено в туториале №4 курса C97, написанного marciano, поясню некоторые вещи, чтобы пояснить как выполняется скрипт.

Marciano говорил об ошибке из-за антиотладочного OpenProcess'а, хотя у меня она не возникала.

Вот конфигурация используемых плагинов.

1d4a68355a04f618186a2e7ac93700c0.png

18b89eb69226b188032ac0e4445191dd.png

ee533d2b7e7a100c9ae693ec1db4f692.png

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

b0d9f28b39b75dbb98d7fd16b9fdd2a2.png

Метод, использованный для нахождения OEP для этой программы, мне понравился, так как часть встречается в новых версиях Asprotect, таких как 2.1 SKE , 2.2 SKE и 2.3 SKE, в которых есть украденный код

Конфигурируем исключения.

bac671a2d1a48a88041c665b51831490.png

Запускаем программу, и как только она начинается выполняться, идём в Log, чтобы посмотреть, каким было последнее исключение.

996dbe0d9d355b95c60dbeecd3e63517.png

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

Перезапускаем.

Нажимаем ALT+O.

309aa0d4da7ad9b55c965b18f08b3401.png

И конфигурируем согласно картинке выше.

Запускаем программу с помощью F9 и проходим исключения с помощью SHIFT + F9, пока не окажемся в исключении по адресу 0046D36B, то есть в последнем

794d41d73eb63c6380d80a9d7fa8145a.png

Теперь, находясь на последнем исключении, нажимаем ALT + M.

И устанавливаем точку останова на доступ к памяти в секции кода.

0872aa83f9887925856f046e2af3df64.png

И нажимаем SHIFT + F9, чтобы пройти исключение и оказаться здесь.

d419775cf90dcd191835c9ad3c073422.png

Но это это не OEP. Если посмотрим на стек.

b2c0b031cfa4e31086577f4c8b84f61e.png

Видим, что это исполняемый код. Выполненный код находится по адресу 8B0EA4 в секции 8B0000.

47d88b58eca39edac3f2a11bdd4bd622.png

Так что перезапускаем. Делаем ту же процедуру, но точку останова устанавляем теперь на доступ к этой секции. Начинаем делать скрипт для автоматизации задач.

cf4ee99943e4a9e6e82e7b48dcf6604a.png

cd64b0542b1499f74a2543bcb800e3e1.png

После этого перезапускаем Olly и запускаем скрипт.

b3799cba81289486aa9e8185e9be799c.png

8d761b8d5439e933eda105240d182a7a.png

Нам показывается диалоговое окно, в котором нужно указать последнее исключение. В моём случае это 46d36b.

Нажимаем OK.

dcb6061b4832d826143a42e0f41abec2.png

Y al momento termina cuando está en la ultima excepción. Presionamos ALT + M

И когда оказываемся в этом исключении – выполнение останавливается.

Нажимаем ALT + M.

d73c42e9100540f8e545523bae1a4af4.png

И вместо установки BP на доступ к секции кода, делаем это на секцию где бы выполненный код. Нажимаем SHIFT + F9 и оказываемся в украденном коде.

3bb315ade32f87c7364890c0f9bc2dfa.png

Si presionamos la tecla (-) vemos que nos sitúa en la ultima excepción

Если нажмём клавишу «-», то увидим, что находимся в последнем исключении.

И ниже находится переход, о котором нам говорил marciano, что он который ожидаемо переносит нас на OEP, и как только мы его нашли сразу модифицируем скрипт, чтобы когда в последнем исключении найдётся этот переход, на него среди опкодов FFEO был установлен точка останова, и когда находимся на переходе, мы нажимаем F7, чтобы перейти на украденный код.

В секции переменных скрипта добавляем ещё одну:

ccbd7d0cc0beb0323561ec7693b691d2.png

dir_JMP, в которой будет храниться адрес перехода JMP EAX.

И в метке ultima добавляем следующее:

9e092cd5cc4117ab489f89f5a51a2857.png

Пробуем.

a4330c4189f75470d7cc48c6b4e0212c.png

И готово — мы в OEP. Здесь дело усложняется, как сказал marciano, если скопируем этот код в точку входа:

b38405c40dbd56e3757c5110ffe70ccf.png

Просто скопируем кусок украденного кода, как миним прямой вызов, который находится в 008B0E9F.

И вставляем в точку входа:

c0229ae19ae370ac703a5819288aa5cb.png

d284ca5bb6b02acc6aed7f22166816ee.png

c5056665bcf9f35d523401ecda197ec8.png

Здесь у нас немного вставленного когда, видимо, что это косвенный вызов, который находится по адресу 0046b067. Он испорчен, посмотрим, куда он должен указывать. Идём туда, где находится OEP.

295ff8dcb83ce52ea4903f76d0919082.png

В оригинальном украденном коде находится CALL 004293A0.

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

Идём по этому вызову в DUMP.

d37b697ecdeb482fb5158531ab5c3e76.png

28ce742d732d03633043a0c496e78b16.png

Не берём в расчёт E8 и используем четыре следующих байта.

FF B7 84 FC  назовём их «OPCODES».

17d61a7cd21fbe437bcf9e9b83313037.png

Берём адрес из Call 008B0E9F  назовём DIR_CALL.

Теперь этот вызов становится CALL 004293A0, а адрес получили следующим образом:

УКАЗАТЕЛЬ = OPCODES + DIR_CALL + 5

УКАЗАТЕЛЬ = FFB784FC + 008B0E9F + 5 = 004293A0

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

PUNTERO - DIRECCIÓN_NUEVA – 5 = NUEVOS OPCODES

УКАЗАТЕЛЬ – НОВЫЙ_УКАЗАТЕЛЬ – 5 = НОВЫЕ ОПКОДЫ ----------------------------------------------------------------------------------------------------

DIRECCIÓN _NUEVA: рассчитываем таким образом.

Например:

701ddac83eff7085e6c58b4ec3f7cf14.png

Если скопируем первые строки украденного кода и скопируем их в точку входа.

e335e67c2e4d1e649d94e177df47d983.png

Видим, что первый прямой вызов будет находится по этому адресу в точке входа 0046B057. Поэтому этот адрес рассчитываем так:

ИСХОДНЫЙ АДРЕС – АДРЕС OEP (УКРАДЕННЫЙ КОД) + АДРЕС ТОЧКИ ВХОДА Где ИСХОДНЫЙ АДРЕС = 008B09EF

d92a47bc09072adcc260bfcb11971c36.png

АДРЕС OEP (УКРАДЕННЫЙ КОД) = 008B0E48

e5f3ba41963d00b0f68730f9a220c0e3.png

И АДРЕС ТОЧКИ ВХОДА : 0046b010

3e3d0aa77ab3b3b1dc538a060e7665fe.png

8B0E9F - 8B0E48 + 46B010= 0046B067 , по этому адресу будет находится наш починенный адрес.

Получается, что НОВЫЙ АДРЕС = 0046B067

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

004293A0 - 0046B067 – 5 = FFFBE334

У нас есть новые опкоды. Теперь осталось их отредактировать вручную. Идём в первый прямой вызов в украденном коде.

1a2bb59fdfbf20eb50596d2f5af1045e.png

В дампе нам показывают вот что:

2347b9d39e877ff314c642c6b7e23df6.png

Не берём E8 и модифицируем следующие за ним четыре байта:

093097460d925d4955a42a62769c5715.png

c41c29bed2e4e7d1b1ddcb8a8e778791.png

И заменяем их новыми опкодами.

2770bbfc3a3131cfcef44fd3fb833d2b.png

10eec98979d551dcf4f063a2f323465f.png

Видим, что наш вызов стал ужасен, но если скопируем этот кусок кода и вставим в точку входа.

d0c0cb71af9bc059a9d286b18b05c097.png

87001888244e8d649598f29f2380b919.png

Остаётся починенный код, как раз такой, какой должен быть.

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

c0ac928b266f24c25177ac05333e3346.png

А потом ещё вот это:

161c7d3657cacece98de626c25bd7acb.png

d9b62ab064ea70e71474c6990674d020.png

Запускаем скрипт.

527fec152cab44fb6043ee878be6270c.png

7e8b6a5e8acda5f521afcdcf61313693.png

66460b8b78680c404255eb492452bdb4.png

93f5519ee084fa7c5076e8f49060faf5.png

Видим, что починились все нужные вызовы.

Выбираем весь украденный код: делаем Binary Copy.

И вставляем в точку входа.

0c8152966f66b806612476dc2ca14460.png

Находясь в точке входа, меняем EIP.

93e2cbfccd1407783eec136555825def.png

df4d42ad20d54eb1ec4047d217ad3fff.png

Говорим, что «Да» и делаем дамп.

98abbdbcc35b338f79fbdd515618ee0a.png

Marciano говорил, что нужно поменять это

a4bdbcf4a99be0034392cd5d9d3a73db.png

На

6c26b466a8a15b50d5d79284ce9b0624.png

Ставим флажок «Rebuild Import» и нажимаем «Dump».

13a586fb62bd62615af8dfce50be4997.png

Вот наш сдампленный файл, в котором проблема с IAT.

Если попробуем открыть его с помощью Олли:

7cc2013c174d131a0ef3e835466091c0.png

Попробуем починить его с помощью PE Editor'а.

980f1b9193da0015402a67041961dafa.png

e11ad6edffcabd3d28b79b8ac12d54e7.png

И готово.

e746e847d2d157a7bdec58a955a31fe2.png

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

Ок, на этом можно завершить объяснение скрипта из первой части и перейти к скрипту из второй.

*/



var base
var dir_VirtualAlloc
var dir_VirtualProtect
VAR dir_mov
Inicio:

gpa "VirtualAlloc", "kernel32.dll" // Buscamos la dirección de la Funcion VirtualAlloc
mov dir_VirtualAlloc, $RESULT
log dir_VirtualAlloc

gpa "VirtualProtect", "kernel32.dll"
mov dir_VirtualProtect, $RESULT

bp dir_VirtualAlloc
run
eob info

info:

mov base, eax
log base
bc dir_VirtualAlloc
bp dir_VirtualProtect

Zona:
eob seccion
run

seccion:
cmp esi, 00460000
je retornar
jmp Zona

retornar:
bc dir_VirtualProtect
mov Reg_esp, [esp]
bp Reg_esp

eob zona_1
run

zona_1:
bc Reg_esp
find base, #897C24188B4424#
mov dir_mov, $RESULT
log dir_mov
jmp nopear

nopear:
bp dir_mov
eob nopear2
run
nopear2:
bc dir_mov
fill dir_mov, 4, 90

final:

msg "Mov nopeado, al terminar el script presiona run (F9)."

ret
Метод для починки IAT – классический, который был хорошо объяснён в туториале marciano. Устанавливаем BPM ON WRITE на одном из плохих элементов IAT, который нашли ранее, находясь в OEP, а затем пытаемся попасть в место, где сохраняется плохое значение. К сожалению во время выполнения функции VirtualProtect стирает BPM ON WRITE, так что нужно установить BP на этой функции, чтобы произвести восстановление вышеуказанного BPM, когда она отработает.

680b268435f3749e4acf51a2585ec63f.png

Здесь видим изображение, взятое из туториала marciano, когда происходит останов на VirtualProtect, чтобы изменить права доступа к области IAT, так что в этот момент должны дойти до RET и снова установить BPM ON WRITE, чтобы продолжить с помощью «RUN», пока не остановимся на месте, где плохое значение сохраняется в элементе.

ba2032362f20eeb213a37efe9e4c0f64.png

Останавливаемся здесь, где происходит сохранение. Плохое значение находится в EAX, а EBP указывает на элемент IAT, за которым мы наблюдали.

Затем устанавливаем BP несколькими строками выше, и когда останавливаемся, то трассируя видим следующее:

cda57c94a95c961848f0743c18cb0223.png

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

Так что скрипт толже установить местонахождение этой инструкции и заNOPить её.

Таким образом, первое что делает скрипт — это ищет адрес API-функции VirtualAlloc, так как первый раз, когда останавливается на ней, получает адрес области, где находится инструкцию, которую нужно заNOPить. Этот адрес может быть разным на разных машинах, поэтому его необходимо искать.



var base
var dir_VirtualAlloc
var dir_VirtualProtect
VAR dir_mov
Inicio:

gpa "VirtualAlloc", "kernel32.dll" // Buscamos la dirección de la Funcion VirtualAlloc
mov dir_VirtualAlloc, $RESULT
log dir_VirtualAlloc
Здесь сохраняем адрес вышеуказанной функции в переменную var dir_VirtualAlloc, потом делаем то же самое с функцией VirtualProtect.


gpa "VirtualProtect", "kernel32.dll"
mov dir_VirtualProtect, $RESULT
В переменной var dir_VirtualProtect сохраняем адрес соответствующей API-функции.



bp dir_VirtualAlloc
run
eob info

info:

mov base, eax
log base
bc dir_VirtualAlloc
bp dir_VirtualProtect
Затем нужно установить BP на VirtuallAlloc, делаем RUN и с помощью eob останавливаемся на указанном bp, сохраняем в переменной base адрес, где программа собирается создать область, в которой будет находится адрес для NOPинга.

Также устанавливаем BP на API-функции VirtualProtect.



Zona:
eob seccion
run

seccion:
cmp esi, 00460000
je retornar
jmp Zona
Когда останавливаемся на BP, сравниваем равен ли ESI 460000, что является началом IAT, так как VirtualProtect использует его как аргумент функции для защиты указанной зоны и стирает BPMы, которые там находится, и если равна, то идём в метку retornar.


retornar:
bc dir_VirtualProtect
mov Reg_esp, [esp]
bp Reg_esp
Где стирается BP на функции VirtualProtect, ищется значение, что будет находится в [esp] и устанавливается BP, чтобы остановиться, как только выйдем из API-функции.



zona_1:
bc Reg_esp
find base, #897C24188B4424#
mov dir_mov, $RESULT
log dir_mov
jmp nopear
Когда возвращаемся из API-функции, то уже можно искать инструкцию, которую будем NOPить. Искать надо по достаточно большой последовательности байтов, чтобы не встретить левые инструкции: 897C24188B4424.

fd3a433a0deb8c6094a9d4faefd3cc95.png

После того, как нашли, делаем переход на процедуру заNOPления.



nopear:
bp dir_mov
eob nopear2
run
nopear2:
bc dir_mov
fill dir_mov, 4, 90

final:

msg "Mov nopeado, al terminar el script presiona run (F9)."

ret
Вот и всё объяснение и спасибо Ularteck'у за хорошую работу и marciano за его прекрасный туториал, из которого мы взяли изображения для объяснения 2-ой части скрипта.

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

В 54-ой части мы начнём новую тему.
 

О нас

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

    Dark-Time 2015 - 2022

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

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

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