Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 2 июля!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь


Распаковка ASProtect 1.35 (на примере Reactive MYCOP Cleaner 1.2), часть 1




Очень удобно, когда все крэкерские инструменты, книги и статьи в одном месте. Используйте сборник от EXELAB - вот тут.

Распаковка ASProtect 1.35


Программа

Reactive MYCOP Cleaner v1.2

Download

Приложена к туториалу

Описание

Учебная программа для распаковки ASProtect v1.35 build 06.26

Инструменты

OllyDbg 1.10, PhantOm v0.60, PEiD v0.94, PE Tools v1.8.800.2006 RC7, Hex Workshop v4.23, Plugin OdbgScript v1.64.3, Import REConstructor v1.6 F

Сложность

Для опытных crackers

Пакер/Компилятор

ASProtect v1.35 build 06.26

Защита

ASProtect v1.35 build 06.26

Цель

Распаковка

Cracker

vnekrilov

Туториал №




0. Введение


На форуме CRACKLAB многими читателями задаются вопросы по распаковке программ, упакованных пакером ASProtect. Судя по задаваемым вопросам, возникают трудности по поиску расположения OEP, восстановлению таблицы IAT, поиску Stolen Codes, и т.д. В этом туториале, на примере программы Reactive MYCOP Cleaner v1.2, которую мне любезно предоставил Gideon Vi, я подробно опишу процесс распаковки пакера ASProtect v1.35 build 06.26. Сначала я думал объяснить только те вопросы, которые конкретно относятся к этому пакеру, и не описывать повторно то, что мной было написано в статье “ASProtect v2.2 - Распаковка программы CHM Editor v1.1 по vnekrilov”. Но, после некоторых колебаний, я решил все-таки подробно описать процесс распаковки этой программы, повторяя все то, что я писал в предыдущей статье. По своему личному опыту знаю, как сложно искать ссылки по многим источникам, и намного лучше все иметь в одном месте. Поэтому я прошу извинения у тех читателей, которые считают, что нет смысла повторять все то, что написано в предыдущих материалах. Новички, которые будут читать эту статью, в одной месте найдут всю необходимую для них информацию.


Перед началом работы, проанализируем программу в Peid:


Распаковка ASProtect 1.35 - часть 1




Программа упакована ASProtect 2.1xSKE. Попробуем уточнить версию пакера, для чего применим plugin VerA 0.15:


Распаковка ASProtect 1.35 - часть 1


Программа упакована ASProtect 1.35 build 04.25 or 06.26 Release [Extract].

Теперь посмотрим на эту программу в DiE v0.64:


Распаковка ASProtect 1.35 - часть 1


Здесь мы видим, что программа скомпилирована на Delphi.


1. Запуск файла в OllyDbg



Как всегда, попытаемся запустить программу в отладчике, чтобы проверить наличие анти-отладочных ловушек. Загружаем программу в отладчик, и получаем сообщение об ошибке:


Распаковка ASProtect 1.35 - часть 1


Посмотрим на карту памяти программы:


Распаковка ASProtect 1.35 - часть 1


Памяти по адресу 60000000 - НЕТ!

Программа еще не остановилась на Entry Point, а мы уже получили сообщение об ошибке.

Хорошо, в таких случаях рекомендуется останавливать в отладчике не Entry Point программы, а на системной BreakPoint. Делаем соответствующие изменения на вкладке отладчика “События”:





Распаковка ASProtect 1.35 - часть 1


Перезагружаем программу, и останавливаемся здесь:


Распаковка ASProtect 1.35 - часть 1


Мы остановились на системной BreakPoint.


Хорошо, давайте посмотрим на вкладку Directory Editor нашего файла, поскольку, как мы определили, программа написана на Delphi, а этот язык программирования часто использует такой параметр, как TLS Directory. Открываем программу в PE Tools v1.8.800.2006 RC7, переходим на вкладку Directory Editor, и там мы видим адрес TLS Directory - 0009C9E4. Если мы щелкнем по кнопке “…”, то увидим данные TLS Directory:



Распаковка ASProtect 1.35 - часть 1


Нас, естественно, интересует адрес 00485010. Поскольку программа остановлена на системной BreakPoint, то переходим в окно дампа, и там видим:


Распаковка ASProtect 1.35 - часть 1


Т.е., мы видим адрес 60000000, по которому у нас произошла ошибка при загрузке программы в OllyDbg.


Распаковывая многие программы, упакованные ASProtect, можно увидеть, что адрес, который показан в окне “Address of callbacks”, содержит 0. Например, если мы посмотрим на программу RAR Recovery Toolbox, которую я использовал при написании статьи по Inline patching ASProtect 2.1xSKE, то по адресу callback - 004AD010, видим:




Распаковка ASProtect 1.35 - часть 1


Значит, в нашем файле, вместо значения 60000000, которое записано по адресу 00485010, мы должны записать 0. Давайте проверим эту идею. Загружаем программу в отладчик, останавливаемся на системной BreakPoint, проходим на адрес 00485010, и заменяем значение 00485010 на 0:


Распаковка ASProtect 1.35 - часть 1


Нажимаем клавишу F9, и программа останавливается на Entry Point:


Распаковка ASProtect 1.35 - часть 1


Это - обычное начало программ, защищенных протектором ASProtect.


Пытаемся запустить программу, нажав клавишу F9, и программа нормально запускается:


Распаковка ASProtect 1.35 - часть 1


Возникает соблазн сохранить измененное значение по адресу 00485010. Однако нам это не разрешает сделать пакер Asprotect. При запуске программы с измененным значением по адресу 00485010, показывается следующая заставка:




Распаковка ASProtect 1.35 - часть 1


Эта ошибка говорит о том, что протектор где-то выполнил проверку CRC, а поскольку мы изменили файл, откорректировав значение по адресу 00485010, то, естественно, пакер обнаружил это изменение, и показывает нам сообщение о повреждении файла.


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


Распаковка ASProtect 1.35 - часть 1


Эта заставка нам сообщает, что отладчик пытался установить BreakPoint по адресу 60000000, но не нашел этот адрес, и удалил breakpoint. В этом случае, нужно нажать кнопку ОК, и программа остановится на системной BreakPoint.


2. Поиск оригинальной точки входа (OEP)


В этой версии Asprotect, автор протектора Алексей Солодовников, убрал генерацию исключений, которые можно было бы использовать при прохождении на OEP (этот метод очень неплохо описан в статье PE_Kill “Распаковка ASProtect 2.xx (Декомпиляция VM)”.


При запуске же нашей программы, если мы посмотрим в окно LOG, исключения не генерируются:


Распаковка ASProtect 1.35 - часть 1


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




Итак, появилась первая проблема, нам нужно что-то придумать, чтобы пройти на OEP. Давайте вспомним работу ASProtect. Сначала протектор раскриптовывает код в секции кода, а затем, в последнюю очередь, он восстанавливает Таблицу IAT. Поэтому, нам нужно посмотреть, где находится Таблица IAT. Поскольку программа у нас запущена, то мы переходим в секцию кода (адрес 00401000), и выполняем бинарный поиск опкода FF 25 (выше мы определили, что программа написана на Delphi):


Распаковка ASProtect 1.35 - часть 1


В окне дампа выбираем режим отображения Long → Address; и мы нашли первую API CloseHandle, которая находится по адресу 004811F4 таблицы IAT.


Распаковка ASProtect 1.35 - часть 1


Значит, таблица IAT находится здесь (в секции 00481000, которая имеет размер 3000 байтов):


Распаковка ASProtect 1.35 - часть 1


Перезагружаем программу в отладчике, исправляем значение 60000000 по адресу 00485010 на 0, и устанавливаем BPM on write на эту область памяти:



Распаковка ASProtect 1.35 - часть 1


Запускаем программу, нажав клавишу F9, и попадаем в цикл, который нам не нужен:


Распаковка ASProtect 1.35 - часть 1


Устанавливаем BP (F2) после прыжка JNZ, который выполняется на начало цикла, и удаляем BPM on write. Нажимаем клавишу F9, чтобы пройти этот цикл, удаляем установленную BP, и снова устанавливаем BPM on write на секцию IAT. Такие действия нам придется повторить несколько раз, поскольку идет раскриптовка и запись кода в секцию .code. И, наконец, мы приходим сюда:


Распаковка ASProtect 1.35 - часть 1


Здесь началась запись адресов API в таблицу IAT. Удаляем BPM on write с секции IAT, и устанавливаем BPM on access на секцию кода программы:




Распаковка ASProtect 1.35 - часть 1


Нажимаем клавишу F9, и останавливаемся здесь:


Распаковка ASProtect 1.35 - часть 1


Попадаем на цикл записи; поэтому, устанавливаем BP на выходе из этого цикла (после прыжка JA), удаляем BPM on access, и нажимаем клавишу F9. Удаляем BP и снова устанавливаем BPM on access на область кода. Такие действия нам придется сделать несколько раз, и мы попадаем сюда:


Распаковка ASProtect 1.35 - часть 1


Мы пришли на OEP, но - это ложная OEP. Это утверждение можно проверить еще и следующим образом. Щелкаем правой кнопкой мыши по инструкции CALL 00AA0000, и выбираем команду:



Распаковка ASProtect 1.35 - часть 1


В окне ссылок (кнопка R) видим много ссылок на эту инструкцию:


Распаковка ASProtect 1.35 - часть 1


Очевидно, что мы имеем дело с Виртуальной Машиной (VM), в которой должна выполняться реальная OEP.


Итак, мы находимся на ложной OEP, и теперь нам надо найти реальную OEP. Как правило, при остановке программы на ложной OEP, адрес реальной OEP должен быть записан в одном из регистров:


Распаковка ASProtect 1.35 - часть 1


Реальная OEP должна находиться по адресу 00950294. Давайте посмотрим, что там имеется:




Распаковка ASProtect 1.35 - часть 1


Здесь мы видим инструкцию PUSH EBP, и, чуть ниже, инструкции MOV EBP,ESP и ADD ESP,-10. Это - инструкции Entry Point программ, написанных на Delphi. Кроме того, мы видим много инструкций CALL 00B30000. Давайте щелкнем мышкой по CALL 00B30000, и нажмем клавишу Enter. Устанавливаем Hardware BP on access на начало подпрограммы CALL 00B30000:


Распаковка ASProtect 1.35 - часть 1


Перезагружаем программу, и нажимаем клавишу F9, и, когда программа остановилась на Hardware BP on access, смотрим в окно регистров:


Распаковка ASProtect 1.35 - часть 1


В регистре EBX мы видим адрес реальной OEP - 00950294; но поскольку эта OEP находится в виртуальной машине, то мы назовем ее - виртуальной OEP (VOEP).


Примечание: Адрес VOEP не обязательно может быть записан в регистре EDX. У меня, при каждой перезагрузке программы, этот адрес записывался также в регистры ESI и EDI.


Здесь я показал, как вручную можно найти VOEP. Умение ручного нахождения OEP очень важно для любого cracker’s программ. Найдя вручную OEP, можно написать скрипт для прохождения на OEP, поскольку, при распаковке программ, эту процедуру приходится выполнять много раз. REVENGE Crew написал скрипт, который успешно выполняет эту работу, и очень мне нравится в работе. Я его снабдил некоторыми комментариями:



  // ASProtect 1.32 and greater (except ASProtect 2.0 alpha) OEP finder by  
  // sanniassin::REVENGE Crew
  // Ignore all exceptions
  // Clear all breakpoints
  // Tested on WinXP only
 
var x // Объявляем переменные var y var is_DLL
mov x,esp // В переменную Х копируем значение регистра ESP sub x,48 // Из значения Х вычитаем число 48 bphws x,"r" // Устанавливаем Hardware breakpoint on read на полученном // адресе mov y,[eip] // В переменную Y записываем байты кода регистра EIP and y,000000FF // Выполняем логическую операцию AND cmp y,60 // Сравниваем полученное значение с числом 60 jne zzz // Если не равно, прыгаем на метку ZZZ: mov is_DLL,1
zzz: run // Запускаем программу mov y,[eip] // Записываем в переменную Y байты кода регистра EIP cmp y,01B80875 // Сравниваем полученное значение с числом 01B80875 jne zzz // Если не равно, прыгаем на метку ZZZ: bphwc x // Удаляем Hardware breakpoint on read find edi,#83C404010424C3# // Ищем цепочку байтов mov x,$RESULT // Результат поиска записываем в переменную Х add x,6 // Прибавляем число 6, чтобы получить адрес инструкции RETN bp x // Устанавливаем BP на инструкции RETN run // Запускаем программу bc x // Удаляем BP на инструкции RETN sto // Выполняем F8 mov x,eip // Записываем в переменную Х значение регистра EIP
findcall: dec x // Вычитаем из значения переменной Х - 1 mov y,[x] // Записываем в переменную Y содержимое полученного значения cmp y,5B5E5F5D // Сравниваем полученную цепочку байтов с цепочкой 5B5E5F5D jne findcall // Если не равно, продолжаем поиск sub x,8 // Из полученного значения переменной Х вычитаем число 8 go x // Выполняем программу до указанного адреса в переменной Х sti // Входим в CALL по F7 rtr // Выполняем код до инструкции RETN sto // Выходим из CALL по F8 mov x,eip // Записываем в переменную Х значение регистра EIP (OEP) and x,0000FFFF // Выполняем логическое действие AND cmp x,0 // Если не равно 0, прыгаем на метку VM_on_OEP:, если равно 0, // прыгаем на метку no_VM_on_OEP: je no_VM_on_OEP
VM_on_OEP: msg "OEP found! OEP stolen." // Показываем сообщение о VOEP jmp pause
no_VM_on_OEP: mov x,esp // Записываем в переменную Х адрес регистра ESP cmp is_DLL,1 // Проверяем на равенство 1 jne is_exe // Если не равно, прыгаем на метку is_exe: add x,10 jmp label_9
is_exe: add x,8 // Добавляем 8 к значению переменной Х
label_9: bphws x,"r" // Устанавливаем Hardware breakpoint on read на полученном // адресе run // Запускаем программу mov y,eip // В переменную Y записываем значение регистра EIP dec y mov y,[y] // Записываем в переменную Y байты полученного адреса and y,000000FF // Логическая операция AND cmp y,5C // Сравниваем со значение 5С jne label_9 bphwc x cmp is_DLL,1 jne is_exe2
find eip,#8944241C61FFE0# add $RESULT,5 bp $RESULT run bc $RESULT sto jmp msg is_exe2: mov x,eax go x msg: msg "OEP found! OEP not stolen."
pause: pause


3. Восстановление INIT: Таблица инициализации.


Init table имеется только в программах, скомпилированных на Delphi, и, поскольку наша программа скомпилирована тем же самым компилятором, то нашу работу, после прохождения на VOEP, надо начинать с восстановления Таблицы инициализации INIT.


Чтобы немного разобраться, как работает эта таблица, давайте посмотрим на какую-либо неупакованную программу, скомпилированную на Delphi. У меня установлена такая программа -Resource Hacker v3.3.4.75, которая хорошо известна всем cracker’s. Давайте на ней и рассмотрим формат Init Table:

Загружаем эту программу в отладчик, и она останавливается на Entry Point - 004AB1FC:


Распаковка ASProtect 1.35 - часть 1


Здесь мы видим OEP (или, точнее Entry Point), поэтому перейдем на эту OEP в Dump, и, чтобы сделать ее более наглядной, выбираем режим отображения Long → Address.


Распаковка ASProtect 1.35 - часть 1


Давайте немного прокрутим вверх, и находим начало таблицы INIT:


Распаковка ASProtect 1.35 - часть 1


Собираем необходимую информацию:


004AB02C: Число вызываемых адресов (39h адресов).

004AB030: Начало таблицы INIT.


Распаковка ASProtect 1.35 - часть 1


004AB1F8: Конец таблицы INIT.

004AB1FC: OEP.


И, обратите внимание на разделительные нули перед последним адресом таблицы INIT.


Вот такую таблицу мы и должны восстановить на нашей программе Reactive MYCOP Cleaner. Каким образом это можно сделать?


Загружаем программу в OllyDbg, и когда она остановилась на Entry Point, нажимаем клавиши ALT+M, и устанавливаем BPM on write на секцию кода:



Распаковка ASProtect 1.35 - часть 1


Нажимаем клавишу F9, и программа останавливается здесь:


Распаковка ASProtect 1.35 - часть 1


Эта область памяти нас не интересует, поэтому несколько раз нажимаем клавишу F9, пока не окажемся здесь:


Распаковка ASProtect 1.35 - часть 1


Примечание: Мы должны остановиться на области памяти, созданную пакером ASProtect, базовым адресом которой является адрес 00970000.


Устанавливаем BP (F2) после прыжка JNZ, удаляем BPM on write, нажимаем клавишу F9, и останавливаемся на BP. Удаляем эту BP, и снова устанавливаем BPM on write на секции .code, как это делали ранее. Нажимаем клавишу F9, и останавливаемся здесь:


Распаковка ASProtect 1.35 - часть 1



Примечание: Снова обратите внимание на эту область памяти, потому что она реализует действия с таблицей инициализации. Мы видим, что адрес 00987A24 находится внутри области памяти 00970000.


Опять устанавливаем BP (F2) после прыжка JA, и удаляем BPM on write. Нажимаем клавишу F9, и останавливаемся на BP. Удаляем эту BP, и снова устанавливаем BPM on write на секции .code, как это делали ранее. Нажимаем клавишу F9, и останавливаемся здесь:


Распаковка ASProtect 1.35 - часть 1


Устанавливаем BP после прыжка JA, и удаляем BPM on write. Нажимаем клавишу F9, и останавливаемся на BP. Удаляем эту BP, и снова устанавливаем BPM on write на секции .code, как это делали ранее. Нажимаем клавишу F9, и останавливаемся здесь:


Распаковка ASProtect 1.35 - часть 1


И снова устанавливаем BP после прыжка, удаляем BPM on write, запускаем программу с F9, и останавливаемся на BP; опять удаляем BP и устанавливаем BPM on write на секцию .code, запускаем программу, и останавливаемся здесь:


Распаковка ASProtect 1.35 - часть 1

Распаковка ASProtect 1.35 - часть 1


Как писал в своей статье Rain, в регистр EDX - записываются первый и второй вызовы процедур раскриптовки Таблицы инициализации INIT, а в регистр ECX - записываются адреса расположения процедур раскриптовки таблицы инициализации INIT. При выполнении первой инструкции MOV DWORD PTR DS:[EDX],ECX, по адресу, записанному в регистр EDX, записывается адрес первой процедуры раскриптовки таблицы инициализации. Когда нажимаем еще раз клавишу F9, то останавливаемся на второй инструкции MOV DWORD PTR DS:[EDX],ECX, где, по адресу, записанному в регистр EDX, будет записан адрес второй процедуры раскриптовки таблицы инициализации, который хранится в регистре ECX. Поэтому, мы сначала будем работать с первой процедурой раскриптовки таблицы инициализации, которая находится по адресу 00987194, а затем, со второй процедурой раскриптовки таблицы инициализации, которая находится по адресу 009871C0. Кстати, обращаем внимание на то, что адрес, записанный в регистре EDX (0047D120), находится недалеко от конца секции .code, где обычно, в большинстве программ, написанных на Delphi, хранится INIT TABLE.


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

Поэтому, записываем значение регистра EDX как адрес первого вызова Таблицы инициализации, потому что по этому адресу записывается адрес первой процедуры раскриптовки таблицы инициализации.

Таблица Nº1: INIT

Адрес

Значение

Комментарии

0047D120


- Адрес хранения первого вызова процедуры раскриптовки таблицы INIT



- Адрес хранения второго вызова процедуры раскриптовки таблицы INIT



- Число вызываемых адресов



- Адрес вызова первой процедуры раскриптовки таблицы инициализации



- Начало выполнения процедуры раскриптовки таблицы инициализации (Первое восстанавливаемое значение в script1)



- Завершение выполнения процедуры раскриптовки таблицы инициализации (Первое восстанавливаемое значение в script2)



- Это будет наша новая OEP


Перезагружаем программу, записываем 0 по адресу 00485010, удаляем все установленные BP и Hardware BP, и запускаем script для поиска VOEP. Нам нужно остановить программу VOEP, адрес которой мы уже нашли - 00950294:


Распаковка ASProtect 1.35 - часть 1


Находясь на VOEP, проходим в окне dump на первый адрес, который мы нашли в регистре EDX, т.е. на адрес 0047D120. По этому адресу записан адрес расположения первой процедуры раскриптовки таблицы INIT:


Распаковка ASProtect 1.35 - часть 1


Здесь мы видим два адреса, которые расположены рядом. Первый адрес содержит адрес вызова первой процедуры раскриптовки таблицы INIT - 00987194, а второй адрес содержит адрес вызова второй процедуры раскриптовки таблицы INIT - 009871C0. Давайте запишем эти адреса в нашу таблицу:


Таблица Nº1: INIT

Адрес

Значение

Комментарии

0047D120

00987194

- Адрес хранения первого вызова процедуры раскриптовки таблицы INIT

0047D124

009871C0

- Адрес хранения второго вызова процедуры раскриптовки таблицы INIT



- Число вызываемых адресов



- Адрес вызова первой процедуры раскриптовки таблицы инициализации



- Начало выполнения процедуры раскриптовки таблицы инициализации (Первое восстанавливаемое значение в script1)



- Завершение выполнения процедуры раскриптовки таблицы инициализации (Первое восстанавливаемое значение в script2)



- Это будет наша новая OEP


Находясь в dump, нажимаем клавиши CTRL + B, и вписываем адрес хранения первого вызова процедуры раскриптовки таблицы INIT в обратном порядке 0047D120 → 20 D1 47 00:




Распаковка ASProtect 1.35 - часть 1


Нажимаем кнопку OK:


Распаковка ASProtect 1.35 - часть 1


Мы видим, что адрес, который находится выше найденного адреса, должен содержать число вызываемых адресов, но вместо этого, asprotect установил там 1. Кроме того, в следующем адресе записан адрес, в котором находится первый вызов процедуры раскриптовки таблицы INIT. Поэтому, чтобы не усложнять процедуру, мы указываем адрес, откуда надо начать восстановление таблицы INIT, и, соответственно, имеем:


Таблица Nº1: INIT

Адрес

Значение

Комментарии

0047D120

00987194

- Адрес хранения первого вызова процедуры раскриптовки таблицы INIT

0047D124

009871C0

- Адрес хранения второго вызова процедуры раскриптовки таблицы INIT

0047D110

#1

- Число вызываемых адресов

0047D114

0047D120

- Адрес вызова первой процедуры раскриптовки таблицы инициализации

0047D118

5F2BF074

- Начало выполнения процедуры раскриптовки таблицы инициализации (Первое восстанавливаемое значение в script1)

Проходим в область вызова процедуры раскриптовки таблицы INIT, т.е., на адрес 00987194, и устанавливаем там BP (F2). Запускаем программу, и останавливаемся на BP:




Распаковка ASProtect 1.35 - часть 1


Вызов первой процедуры раскриптовки таблицы INIT: Теперь мы напишем другую таблицу, которую назовем “Таблица № 2 - Вызов первой процедуры раскриптовки таблицы INIT”.


Аналогично предыдущим действиям, мы должны заполнить эту таблицу, которая будет полезной для написания script1. Первым мы указываем адрес нахождения CALL DWORD PTR DS:[996430] (для сведения), и адрес нахождения инструкции RETN:


Таблица Nº2: Вызов первой процедуры раскриптовки таблицы INIT

Адрес Call (для справки)

009871B4

Адрес инструкции RETN

009871BD (для установки Hardware BP)

Адрес Call EXX

Находится внутри CALL [966430] (для установки Hardware BP)


Теперь нам осталось найти адрес Call EXX, для чего входим в CALL DWORD PTR DS:[996430] с помощью клавиши F7:


Распаковка ASProtect 1.35 - часть 1


Прокручиваем листинг вниз, чтобы найти CALL EXX, где EXX может быть любым регистром:


Распаковка ASProtect 1.35 - часть 1


Устанавливаем Hardware BP on execution на этот call, и нажимаем клавишу F9. Останавливаемся на CALL EAX, смотрим в окно регистров, и видим:


Распаковка ASProtect 1.35 - часть 1


Здесь мы видим значение, которое должно быть записано нашей таблице инициализации - EAX = 00406BFC.


Теперь у нас имеется вся таблица № 2:


Таблица Nº2: Вызов первой процедуры раскриптовки таблицы INIT

Адрес Call (для справки)

009871B4

Адрес инструкции RETN

009871BD (для установки Hardware BP)

Адрес Call EXX (CALL EDX)

00B200D4 (для установки Hardware BP)


Нам нужно откорректировать script для восстановления вызовов инициализации, который предложил Rain, и немного доработан мной. Находим помеченные цветом данные в таблице № 2, и записываем эти данные в скрипт.


Данные для script инициализации.



  // Скрипт запускать, когда программа остановлена на VOEP
  // Скрипт разработан Rain, и доработан vnekrilov
 
// Объявляем переменные
var init // Переменная для записи адресов таблицы INIT var value // Счетчик числа восстановленных адресов (с шагом 8)
mov value,0 // Устанавливаем начальное значение переменной value в 0
// Записываем значения из предыдущей таблицы.
bphws 00B200D4,"x" // Устанавливаем Hardware BP на CALL EAX bphws 009871BD,"x" // Устанавливаем Hardware BP на RETN, на выходе из подпрограммы // инициализации
search: mov init,0047D118 // Записываем адрес первого восстанавливаемого значения INIT TABLE // из таблицы 1 run // Запускаем программу eob recovery // Если останавливаемся на breakpoint, то прыгаем на метку recovery
recovery: cmp eip,00B200D4 // Проверяем, остановились ли мы на CALL EAX jne completion // Если EIP = 00B200D4, то выполняем восстановление адреса, если // EIP = 009871BD, то прыгаем на метку completion: add init,value // Сначала счетчик установлен на 0, и его значение мы поочередно // добавляем начальному значению адреса таблицы IAT, который нам // надо восстановить. Счетчик value мы увеличиваем с шагом 8, // поскольку эти элементы Init попарно чередуются друг с другом. mov [init],eax // Остановившись на call EAX, записываем значение регистра EAX в // таблицу инициализации add value,8 // Увеличиваем значение переменной value, для перехода на следующий // адрес таблицы инициализации. jmp search // Продолжаем работу с последующими адресами таблицы INIT
completion: cmp eip,009871BD // Проверяем, остановились ли мы на инструкции RETN (этот адрес // имеется в таблице № 2) je end // Если Да, то работа завершена успешно. jmp error // Если Нет, то работа была неудачной.


end: add init,value // Получаем последний адрес вызова начала процедуры инициализации mov [init],0 // Этот адрес должен быть заполнен 0 bphwc 00B200D4 // Удаляем Hardware BP на CALL EAX bphwc 009871BD // Удаляем Hardware BP на RETN, на выходе из подпрограммы // инициализации ret
error: MSG "Ошибка, работа не закончена" ret


Удаляем все Hardware BP, которые у нас были, и перезапускаем программу.


Проходим на VOEP с помощью script OEPFinder.osc.


Когда программа остановлена на VOEP, запускаем только что рассмотренный скрипт, который я назвал Recovery_INIT_1.osc. Немного ожидаем, пока скрипт не закончит свою работу. После завершения работы скрипта, смотрим, что у нас получилось:


Распаковка ASProtect 1.35 - часть 1


Ура! Script восстановил адреса таблицы INIT, для которых используется первая процедура раскриптовки. Теперь давайте посмотрим на второй вызов процедуры раскриптовки таблицы INIT:


Таблица Nº1: INIT

Адрес

Значение

Комментарии

0047D120

00987194

- Адрес хранения первого вызова процедуры раскриптовки таблицы INIT

0047D124

009871C0

- Адрес хранения второго вызова процедуры раскриптовки таблицы INIT

0047D110

#1

- Число вызываемых адресов

0047D114

0047D120

- Адрес вызова первой процедуры раскриптовки таблицы инициализации

0047D118

5F2BF074

- Начало выполнения процедуры раскриптовки таблицы инициализации (Первое восстанавливаемое значение в script1)

0047D30C

32EE3BA3

- Завершение выполнения процедуры раскриптовки таблицы инициализации (Первое восстанавливаемое значение в script2)

0047D310


- Это будет наша новая OEP


В этой таблице вторая строка показывает адрес вызова второй процедуры раскриптовки таблицы INIT - 009871C0. Этот адрес находится чуть ниже инструкции RETN, на которой наш скрипт завершил свою работу. Причем код этой части процедуры раскриптовки, практически ничем не отличается от кода предыдущей процедуры раскриптовки (просто на 4 байта сдвинуты все адреса, по сравнению с адресами второй процедуры раскриптовки таблицы INIT).


Поэтому мы можем легко заполнить таблицу Вызовов конца процедуры инициализации, для чего переходим на адрес подпрограммы раскриптовки по адресу 009871C0. Выделяем инструкцию PUSH, и устанавливаем новый адрес регистра EIP, нажав клавиши CTRL + *:


Таблица Nº3: Вызов второй процедуры раскриптовки таблицы INIT

Адрес Call (для справки)

009871E6

Адрес инструкции RETN

009871EF (для установки Hardware BP)

Адрес Call EXX (CALL EDX)

00B200D4 (для установки Hardware BP)


Устанавливаем новый адрес регистра EIP - 009871C0:


Распаковка ASProtect 1.35 - часть 1



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


Первое, что нам надо найти - это конец таблицы INIT. Для этого проходим в окно dump, и ищем последнее восстановленное значение INIT (вспомните, что в 1-м скрипте мы завершили восстановление первой части таблицы INIT записью 0):


Распаковка ASProtect 1.35 - часть 1


Красной стрелкой я пометил последнее восстановленное значение первым скриптом (помните, мы в нем записали нулевое значение), и после него идет значение, которое будет первым значением для второго скрипта восстановления таблицы INIT. Адрес этого значения - 0047D30C. А следующий адрес, который следует за этим значением, будет новым OEP - 0047D310. Необходимо иметь в виду, что второй скрипт будет запускаться с адреса предыдущей OEP, поэтому мы завершим работу скрипта адресом, который будет содержать фактическое число адресов Таблицы INIT (0047D110), и восстановим значение первого адреса таблицы INIT (0047D114):



  // Скрипт запускать, когда программа остановлена на VOEP
  // Скрипт разработан Rain, и доработан vnekrilov
 
// Объявляем переменные
var init // Переменная для записи адресов таблицы INIT var value // Счетчик числа восстановленных адресов (с шагом 8) var numbercall // Счетчик числа вызовов процедуры инициализации
mov value,0 // Устанавливаем начальное значение переменной value в 0 mov numbercall,0 // Устанавливаем начальное значение переменной numbercall в 0
// Записываем значения из предыдущей таблицы.
bphws 00B200D4,"x" // Устанавливаем Hardware BP на CALL EAX bphws 009871EF,"x" // Устанавливаем Hardware BP на RETN, на выходе из подпрограммы // восстановления вызовов инициализации
search: mov init,0047D30C // Записываем адрес первого восстанавливаемого значения INIT TABLE // из таблицы 1 (Вызов конца процедуры инициализации) run // Запускаем программу eob recovery // Если останавливаемся на breakpoint, то прыгаем на метку recovery
recovery: cmp eip,00B200D4 // Проверяем, остановились ли мы на CALL EAX jne completion // Если EIP = 00B200D4, то выполняем восстановление адреса, если // EIP = 009871EF, то прыгаем на метку completion: sub init,value // Сначала счетчик установлен на 0, и его значение мы поочередно // добавляем начальному значению адреса таблицы IAT, который нам // надо восстановить. Счетчик value мы увеличиваем с шагом 8, // поскольку эти элементы Init попарно чередуются друг с другом. mov [init],eax // Остановившись на call EAX, записываем значение регистра EAX в // таблицу инициализации add value,8 // Увеличиваем значение переменной value, для перехода на следующий // адрес таблицы инициализации. inc numbercall jmp search // Продолжаем работу с последующими адресами таблицы INIT
completion: cmp eip,009871EF // Проверяем, остановились ли мы на инструкции RETN (этот адрес // имеется в таблице № 3) je end // Если Да, то работа завершена успешно. jmp error // Если Нет, то работа была неудачной.


end: mov [0047D110],numbercall // Записываем число вызовов процедуры инициализации mov [0047D114],0047D118 // Устанавливаем первый элемент для INIT bphwc 00B200D4 // Удаляем Hardware BP на CALL ADX bphwc 009871EF // Удаляем Hardware BP на RETN, на выходе из подпрограммы // инициализации ret
error: MSG "Ошибка, работа не закончена" ret


Запускаем этот скрипт, который я назвал Recovery_INIT_2.osc.


Распаковка ASProtect 1.35 - часть 1

Распаковка ASProtect 1.35 - часть 1


Итак, мы восстановили таблицу INIT, и теперь знаем, где должна быть наша новая OEP.


Нам нужно скопировать эту восстановленную таблицу INIT:




Распаковка ASProtect 1.35 - часть 1


Запускаем HexWorkshop:


Распаковка ASProtect 1.35 - часть 1


Распаковка ASProtect 1.35 - часть 1

Распаковка ASProtect 1.35 - часть 1


Вставляем и сохраняем этот новый файл с именем Recovery_INIT.


Конец части I


Далее мы рассмотрим восстановление IAT и прыжков на IAT, виртуальную машину Asprotect, и регистрацию программ, которые используют Asprotect.



Скачать статью "Распаковка ASProtect 1.35 (на примере Reactive MYCOP Cleaner 1.2), часть 1" в авторском оформление + файлы.
пароль архива на картинке



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS