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

ВИДЕОКУРС ВЗЛОМ
выпущен 8 мая!


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


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




Массу крэкерских инструментов, видеоуроков и статей вы сможете найти на видеокурсе от нашего сайта. Подробнее здесь.

Восстановление ASProtect IAT:


Теперь переходим к восстановлению таблицы IAT. При поиске VOEP мы использовали метод, связанный с раскриптовкой пакером таблицы IAT, которая расположена в программе в секции 00481000, и имеет размер 3000 байтов. Сначала нам надо найти начало и конец IAT. Следует отметить, что вся секция 00481000, помимо элементов IAT, содержит массу мусорного кода, который затрудняет определить границы таблицы IAT, особенно для неопытных cracker’s. Поэтому, чтобы очистить IAT от мусорного кода, мы сделаем следующее.


Загружаем программу в отладчик, и выполняем все те действия, когда мы искали VOEP программы. Переходим в Memory Map, нажав клавиши Alt + M, и устанавливаем BPM on write на область памяти 00481000. После нескольких остановок программы на BP, которые мы устанавливали на выходе из цикла раскриптовки, и BPM on write, мы окажемся здесь:


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


Удаляем BPM on write, и проходим до инструкции RET с F8. Переходим в окне dump на адрес начала секции IAT - 00481000, выделяем всю эту секцию, и выполняем команду Binary → Fill witch 00’s:


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


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



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


Этот фактор для нас очень важен; ASProtect очень сильно засоряет таблицу IAT мусорным кодом, поэтому мы можем убрать весь мусорный код из таблицы IAT, что намного облегчит нам ее восстановление.


Примечание: Я делал два варианта восстановления таблицы IAT; без очистки от мусорного кода, и с очисткой от мусорного кода. В первом случае скрипт не смог найти 16 API, и дописал их в конец таблицы IAT. Во втором случае, скрипт нашел все API, и ничего не дописал в секцию кода. Кроме того, поскольку секция IAT - практически пустая, я решил восстановить таблицу IAT с помощью ImpREC на ее родное место, т.е. по адресу начала таблицы IAT - 00481154. Когда таблица IAT была заполнена мусорным кодом, то, при загрузке программы, отладчик показал ошибку (0хс00000005), которая означает повреждение таблицы IAT. Когда же таблица IAT была очищена от мусорного кода, программа нормально загрузилась в отладчик.


Теперь найдем начало и конец IAT:


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

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


Итак, у нас имеются все необходимые данные для использования ImpREC:


VOEP: 00950294

НАЧАЛО IAT: 00481154; для ImpREC 00481154 - 00400000 = 00081154

КОНЕЦ IAT: 00481838

РАЗМЕР: 00481838 - 00481154 = 6E4


Посмотрим, вся ли таблица IAT заполнена реальными адресами API; запускаем ImpREC, и вводим значения начала IAT и ее размер (значение OEP оставляем таким, каким его определил ImpREC):




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


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


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


Мы видим, что ImpREC не распознал два элемента, т.е. два элемента ссылаются на область памяти, которую создал Asprotect во время загрузки программы. И мы видим, что таблица IAT содержит 1AA распознанных элементов, и 2 нераспознанных элемента.


Теперь выполним еще одну проверку. Запускаем ImpREC на программе с секцией IAT, которая не заполнена нолями. Зачем нам нужно это делать? Дело в том, что когда программа остановлена на Entry Point, таблица IAT заполнена мусором. Затем пакер начинает записывать в нее значения переадресованных API, и, в последнюю очередь, пакер записывает реальные адреса API. Когда мы заполнили таблицу IAT нолями, перед записью реальных адресов API, мы тем самым удалили все переадресованные API, после чего пакер записал только реальные адреса API. ImpREC, в таком случае, не видит переадресованные API, и показывает нам неверные параметры таблицы IAT - ее начальный адрес и размер. Давайте посмотрим результат:


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


Мы видим, что значения не изменились, а это означает, что таблица IAT не содержит переадресованные API (кроме двух), что существенно упрощает нашу работу.


Но у нас осталось два нераспознанных элемента таблицы IAT, которые находятся по адресам 004811A0 и 00481308. В этих адресах записано одно значение - 00987574, которое мы должны перевести в реальный адрес API, чтобы получить полностью восстановленную таблицу IAT.


Перезагружаем программу в отладчике, проходим на VOEP с помощью скрипта, и устанавливаем BP на адрес 00987574, и нажимаем клавишу F9. Программа останавливается на BP:


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


Трассируем с помощью клавиши F8 до инструкции RET 8, и смотрим, что у нас происходит. Сначала в регистр EDX записывается имя API - GetDiskFreeSpaceExA:


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


Затем в регистр EAX записывается базовый адрес библиотеки kernel32.dll - 7C800000:


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


После этого производится сравнение значения регистра EAX с содержимым адреса 00996458:


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


Затем в стек вводятся значения регистров EDX и EAX (инструкции PUSH EDX и PUSH EAX), программа останавливается на инструкции CALL 0097584C:


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


Выполнив API GetProcAddress, программа получает реальный адрес API GetDiskFreeSpaceExA. Таким образом, пакер эмулирует инструкцию API GetProcAddress. Поэтому мы можем записать по адресам 004811A0 и 00481308 реальный адрес API GetProcAddress - 7C80AC28:


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


Теперь нам нужно восстановленную секцию таблицы IAT скопировать в файл. Для этого выделяем всю секцию Таблицы IAT, и выбираем команду binary copy:


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


Запускаем HexWorkshop, и повторяем все те действия, которые мы делали при создании файла таблицы INIT. Сохраняем полученный файл с именем Recovery_IAT.


5. Восстановление прыжков на IAT



Перезагружаем программу в Olly, проходим на VOEP с помощью скрипта, переходим в секцию .code на адрес 00401000, и выполняем команду Search for → all intermodular calls. В окне ссылок выбираем команду Сортировать по → Назначению, и здесь мы видим много calls типа CALL 00AA0000:


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




Теперь наша задача заключается в восстановлении всех этих CALL 00AA0000 в их оригинальный формат. Сначала мы сделаем это вручную, чтобы понять идею восстановления этих прыжков. Выполняем поиск всех CALL 00AA0000, выбрав команду Serch for → All commands:


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


В окне ссылок видим:


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


Записываем первое появление этого CALL по адресу 00401250. Теперь посмотрим, где находится последний CALL 00AA0000, для чего прокручиваем листинг вниз, и находим следующий адрес:


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


Итак, последняя инструкция CALL 00AA0000 находится по адресу 00434638.


Переходим на любой из этих CALL, например, по адресу 00401250:


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


Этот CALL мы восстановим вручную; поэтому выделяем CALL 00AA0000, и нажимаем клавиши CRTL + * (команда “New origin here”).


Для получения адреса API, Asprotect последних версий использовал API VirtualAlloc вместо API GetProcAddress, однако в данной версии ASProtect v1.35 build 06.26 не применяет ни первую, ни вторую API. Попытка установить BP на API VirtualAlloc или API GetProcAddress, не вызывает остановку программы. Возникает вопрос, как же нам узнать, какую API вызывает этот CALL? Ведь должен же ASProtect использовать какую-либо API для определения реального адреса API, которая вызывается этим CALL. Поскольку API VirtualAlloc и API GetProcAddress входят в библиотеку kernel32.dll, то давайте установим BPM on access на секцию кода библиотеки kernel32.dll:


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


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


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


Это - API GetCurrentProcessId, которая нам ничего не дает, поэтому еще раз нажимаем клавишу F9. Программа останавливается здесь:


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


А в окне регистров мы видим следующее:




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


Становится интересно! Программа остановилась на Entry Point API LoadLibraryA. В регистре EAX записана текстовая строка ASCII "kernel32.dll", а в регистре EDI - текстовая строка ASCII "GetFileType".


В справке по этой API мы видим:


Функция LoadLibrary


Описание:

function LoadLibrary(LibFileName: PChar): THandle;


Загpужает поименованный модуль библиотеки.


Паpаметpы:

LibFileName: Имя файла библиотеки (заканчивающееся пустым символом).


Возвpащаемое значение:

В случае успешного завеpшения - идентификатоp экземпляpа модуля библиотеки (значение, больше 32); если нет, то его значение меньше 32 и является одним из следующих: (0) нет памяти; (5) попытка связать задачу; (11) невеpный файл EXE; (12) пpикладная задача из OS/2; (13) пpикладная задача из DOS 4.0; (14) невеpный тип EXE; (15) незащищенный pежим.


Давайте пройдем до инструкции RET 4 данной API, для чего удаляем BPM on access, и нажимаем клавиши Ctrl + F9. В окне регистров мы видим:


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


В регистре EAX записан базовый адрес библиотеки kernel32.dll, а в регистре EDI - указатель на имя API GetFileType. Эти два параметра использует API GetProcAddress, которая возвращает реальный адрес API GetFileType. Однако пакер не использует API GetProcAddress в чистом виде, а эмулирует ее. Возникает очевидный вопрос, ведь сначала где-то должен появится реальный адрес API GetFileType, и, потом, каким-то образом должна быть вызвана эта API? Давайте установим BP на API GetFileType, и выполним трассирование программы, нажав клавиши Ctrl + F12. После остановки программы на API GetFileType, переходим в окно трассирования, нажав кнопку “…”, и там видим следующее:




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


При выполнении программой CALL 00991294, выполняется прыжок на API GetFileType. Перезагружаем программу в отладчике, проходим на VOEP, переходим на адрес 00401250, где находится инструкция CALL 00AA0000, и выполняем команду “New origin here”. Устанавливаем BP на адрес 009915C8, где находится инструкция CALL 00991294, и нажимаем клавишу F9. Программа останавливается на BP, и мы входим в CALL 00991294 с F7:


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


Немного потрассируем программу с F8, и приходим сюда:



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


Здесь видим, что, при выполнении инструкции PUSH DWORD PTR SS:[EBP+14], в стек будет помещен реальный адрес API GetFileType:


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


Т.е., если мы установим Hardware BP on execution на адрес 009912CD, то на вершине стека мы получим реальный адрес API. Давайте проверим эту гипотезу. Перезагружаем программу, проходим на VOEP, и нажимаем несколько раз клавишу F9. При остановке программы на Hardware BP on execution, на вершине стека мы видим реальный адрес вызываемой API.


Очевидно, что эти CALL 00AA0000 должны быть прыжком на IAT - типа JMP [address IAT]:


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


Причем, это будет именно JMP [IAT] потому, что перед этим прыжком расположен опкод 8BC0, который является опкодом инструкции MOV EAX,EAX. Поскольку мы знаем, что этот CALL выполняет прыжок на API GetFileType, то нам надо найти эту API в таблице IAT. Но, перед поиском этой API, нам нужно восстановить корректную таблицу IAT из файла, который мы сделали чуть ранее, и назвали Recovery_IAT.


Запускаем HexWorkshop, открываем в нем файл Recovery_IAT, выделяем и копируем весь код:


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


Теперь переходим в окно dump отладчика, выделяем всю секцию таблицы IAT, и выбираем команду binary paste:



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



Ищем в Таблице IAT API GetFileType:


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


Мы видим, что эта API находится в IAT по адресу 004811EC; поэтому мы уже сможем восстановить наш прыжок:


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


Удаляем флажок на опции “Fill with NOP’s”, нажимаем клавишу Assemble, и получаем восстановленный прыжок:




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


Здесь мы видим, что до и после прыжка находится инструкция MOV EAX,EAX, которая представлена опкодом 8BC0; именно по этой причине мы знаем, что здесь должен быть прыжок, а не CALL.


Итак, приступаем к написанию скрипта, который восстановит все эти CALL:



  //Разработчик скрипта: Ulaterck, доработка - vnekrilov.
  //Описание: Скрипт разработан для восстановления прыжков в таблицу IAT
  //программы Reactive MYCOP Cleaner v1.2, защищенной ASProtect v1.35 build 06.26.
  //Цель: RMC.EXE
  //Условия применения: ODBGScript 1.48, Olly Advanced v1.26 Beta 12, PhantOm v1.04.
 

var Address_Call // Переменная для хранения найденного адреса CALL var Start_IAT // Переменная для хранения адреса начала таблицы IAT var End_IAT // Переменная для хранения адреса конца таблицы IAT var New_IAT // Переменная для записи адресов API, которых нет в IAT var Field_Asprotect // Переменная для хранения области памяти CALL var Start_scan // Переменная для хранения адреса начала сканирования var End_scan // Переменная для хранения адреса конца сканирования var Address_API // Переменная для хранения найденного адреса API var Stack // Переменная для хранения адреса стека var Temp_EIP // Переменная для хранения текущего адреса EIP var OP_Code // Переменная для хранения значения опкода var New_EIP // Переменная для хранения нового адреса EIP var Address_IAT // Переменная для хранения адреса IAT с найденной API var My_API // Переменная для хранения адреса IAT с восстановленной // API var Flag // Переменная для хранения значения флажка

preparation: mov Start_IAT,00481154 // Сохраняем начало таблицы IAT. mov End_IAT,00481834 // Сохраняем конец таблицы IAT. mov New_IAT,0048183C // Указываем адрес, куда будем записывать недостающие API mov Field_Asprotect,00AA0000 // Сохраняем адрес, который мы будем искать. mov Start_scan,00401000 // Указываем адрес начала поиска CALL 00AA0000. mov End_scan,00434638 // После этого адреса CALL, прекращаем поиск mov eip,Start_scan // Устанавливаем EIP на начало секции .code. bp Start_scan // Устанавливаем breakpoint на начало секции .code. run // Запускаем программу. bc Start_scan // Удаляем breakpoint с адреса 401000.
SearchCallAsprotect: // Поиск calls типа CALL 00AA0000 (область asprotect) findop Start_scan,#E8# // Ищем инструкцию CALL, которая имеет опкод #E8# mov Address_Call,$RESULT // Сохраняем найденный адрес в переменной Address_Call mov Start_scan,$RESULT // Сохраняем найденный адрес в переменной Start_scan mov New_EIP,$RESULT // Сохраняем найденный адрес в переменной New_EIP. mov Field_Asprotect,00AA0000 // В этой области памяти asprotect мы будем работать (CALL // 00AA0000) sub Field_Asprotect,Address_Call // Проверяем, является ли найденный CALL требуемым sub Field_Asprotect,5 // CALL 00AA0000 add $RESULT,1 cmp [$RESULT],Field_Asprotect // Сравниваем полученные результаты, и если найден jne SearchCallAsprotect // не CALL 00AA0000, то прыгаем на начало поиска cmp Start_scan,End_scan // Проверяем, не является ли последним этот Call. je activeflag // Если пришли на последний CALL, прыгаем на activeflag jmp SearchApi // Если это не последний CALL, то прыгаем на поиск API
activeflag: mov Flag,1 // активизируем переменную Flag
SearchApi: // Процедура поиска API, которая соответствует этому прыжку mov eip,New_EIP // Устанавливаем EIP на найденный адрес CALL 00AA0000. bphws 009912CD, "x" // Устанавливаем Hardware BP на адрес 009912CD run // Запускаем программу. mov Stack,esp // Записываем в переменную Stack адрес вершины стека mov Address_API,[Stack] // Останавливаемся на 009912CD, и записываем содержимое // адреса вершины стека (реальный адрес API)
AnalysCall: // Процедура анализа, что использовать - JMP или CALL bphwc 009912CD // Удаляем Hardware BP с адреса 009912CD mov eip,New_EIP // Устанавливаем EIP на адресе нашего CALL 00AA0000 mov Temp_EIP,New_EIP // Сохраняем в переменной Temp_EIP адрес CALL 00AA0000 sub Temp_EIP,2 // Вычитаем из адреса 2 байта mov OP_Code,[Temp_EIP] // Сохраняем результат в переменной OP_Code and OP_Code,0000FFFF // Выполняем логический AND результата переменной OP_Code log OP_Code // Регистрируем полученный результат cmp OP_Code,C08B // Проверяем, являются ли байты перед Call байтами 8BC0 je EditAsJMP // Если байты имеются, то пишем call как JMP [addr IAT] add Temp_EIP,8 // Если нет байтов 8BC0 перед call, проверяем, есть ли они // после CALL. mov OP_Code,[Temp_EIP] // Сохраняем в переменной OP_Code полученный результат and OP_Code,0000FFFF // Выполняем логический AND результата переменной OP_Code log OP_Code // Регистрируем полученный результат cmp OP_Code,C08B // Проверяем, являются ли байты после Call байтами 8BC0 je EditAsJMP // Если равно, то редактируем call как JMP [addr IAT]
EditAsCall: // Если мы редактируем CALL как CALL [addr IAT] mov Address_IAT,Start_IAT // Копируем в переменную Address_IAT адрес начала IAT
continue1: cmp Address_API,[Address_IAT] // Сравниваем полученное значение API со значением в IAT jne next1 // Если не равны, прыгаем на метку next: mov My_API,Address_IAT // Если равны, записываем значение адреса IAT в My_API, jmp build1 // и прыгаем на метку build1:
next1: add Address_IAT,4 // Переходим на следующий адрес IAT cmp Address_IAT,End_IAT // Проверяем этот адрес с концом IAT je newwrite1 // Если прыгаем, значит в таблице IAT нет данной API. jmp continue1 // Если не конец IAT, повторяем цикл
build: // Процедура для формирования прыжка как Call eval "Call dword[{My_API}]" // Оцениваем адрес IAT, где записана найденная API asm New_EIP, $RESULT // Ассемблируем CALL [My_API] в двоичный код cmp Flag,1 // Проверяем, работаем ли мы с последним CALL 00AA0000 je Final // Если Да, прыгаем на завершение работы скрипта jmp SearchCallAsprotect // Если Нет, ищем следующий CALL 00AA0000
EditAsJMP: // Процедура для формирования прыжка как JMP
mov Address_IAT,Start_IAT // Копируем в переменную Address_IAT адрес начала IAT
continue2: cmp Address_API,[Address_IAT] // Сравниваем полученное значение API со значением в IAT jne next2 // Если не равны, прыгаем на метку next: mov My_API,Address_IAT // Если равны, записываем значение адреса IAT в My_API, jmp build2 // и прыгаем на метку build2:
next2: add Address_IAT,4 // Переходим на следующий адрес IAT cmp Address_IAT,End_IAT // Проверяем этот адрес с концом IAT je newwrite2 // Если прыгаем, значит в таблице IAT нет данной API. jmp continue2 // Если не конец IAT, повторяем цикл
build2: // Процедура для формирования прыжка как JMP eval "Jmp dword[{My_API}]" // Оцениваем адрес IAT, где записана найденная API asm New_EIP, $RESULT // Ассемблируем JMP [My_API] в двоичный код cmp Flag,1 // Проверяем, работаем ли мы с последним CALL 00AA0000 je Final // Если Да, прыгаем на завершение работы скрипта jmp SearchCallAsprotect // Если Нет, ищем следующий CALL 00AA0000
newwrite1: add End_IAT,4 // Добавляем к концу IAT 4 байта mov [End_IAT],0 // Делаем разделительные нули между концом IAT и New_IAT mov [New_IAT],Address_API //Записываем недостающее значение API add New_IAT,4 // Увеличиваем размер IAT на 4 байта mov End_IAT,New_IAT // Записываем новое значение конца IAT jmp EditAsCall // Прыгаем новый поиск API в IAT, и восстанавливаем CALL // 00AA0000
newwrite2: add End_IAT,4 // Добавляем к концу IAT 4 байта mov [End_IAT],0 // Делаем разделительные нули между концом IAT и New_IAT mov [New_IAT],Address_API //Записываем недостающее значение API add New_IAT,4 // Увеличиваем размер IAT на 4 байта mov End_IAT,New_IAT // Записываем новое значение конца IAT jmp EditAsJMP // Прыгаем новый поиск API в IAT, и восстановление CALL // 00AA0000
Final: Ret // Завершаем работу скрипта


Примечание: Этот скрипт предоставлен Ulaterck в своем туториале “Asprotect 2.2 Parte II by Ulaterck”. Я его доработал в части записи в конце таблицы IAT тех API, которые отсутствуют в IAT, и записал установку Hardware BP on access на адрес 009912CD; при остановке на этой Hardware BP, на вершине стека записывается реальный адрес API. Также мной убран поиск API VirtualAlloc, которая не применяется для поиска реального значения API. Я полагаю, что комментарии достаточно полно объясняют работу скрипта. Значения, помеченные желтым цветом, вписываются для каждой конкретной программы.


Удаляем все установленные breakpoints, включая Hardware BP. Перезагружаем программу, и запускаем скрипт OEPFinder, для прохода на VOEP. Когда программа остановилась на VOEP, нам нужно вставить Таблицу IAT и Таблицу INIT на их соответствующие места.


Проходим на начало секции таблицы IAT, которое находится по адресу 00481154, и вставляем скопированные байты восстановленной секции таблицы IAT из HexWorkshop (как это мы делали чуть выше).


Затем вставляем Таблицу INIT, для чего из HexWorkshop копируем байты файла Recovery_INIT:



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


И вставляем на ее место в Olly - по адресу 0047D110:


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


Теперь можем запускать наш скрипт, который я назвал Recovery_CALL_as_JMP_or_CALL .osc. Ждем несколько минут, пока скрипт не закончит свою работу, и видим, что скрипт ничего не добавил в таблицу IAT (т.е. он нашел все нужные API в таблице IAT):


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


Давайте, выполним поиск и посмотрим, все ли мы восстановили CALL, для чего выбираем команду Search for → All commands, и ничего не находим. Значит, наш скрипт восстановил все CALL 00AA0000.



Мы закончили восстановление CALL, и теперь переходим на новую OEP, которая находится после конца Таблицы INIT. Когда мы запускали второй скрипт для восстановления таблицы INIT, то видели адрес, где находится наша OEP - 0047D310. Переходим на этот адрес, и выполняем команду - New origin here:


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


Кстати, обратите внимание, что по этому адресу выполняется прыжок на адрес VOEP - 00950294.


6. Получение дампа памяти программы


Теперь можно сдампировать память программы. Для этой цели я использую plugin OllyDbg PE Dumper v3.03 by FKMA:





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


Сохраняем полученный дамп памяти с любым именем, (я его сохранил с именем dumped).


Не закрывая Olly, открываем ImpREC, выбираем процесс, и вводим новые данные:


OEP : 0047D310 - 00400000 = 0007D310

RVA: 00481154 - 00400000 = 00081154

SIZE: 00481838 - 00481154 = 6E4


Нажимаем кнопку “Get Imports”, и в окне “Imported Functions Found” видим:




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


Все элементы таблицы IAT - распознаны!


Теперь нам нужно вставить таблицу IAT в наш дамп по ее родному адресу 00481154. Удаляем флажок из опции “Add new section”, и в окно вводим адрес начала таблицы IAT - 00081154:


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


Нажимаем кнопку Fix Dump, выбираем сделанный нами дамп памяти программы, и получаем дамп с восстановленной секцией импорта:


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


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


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


Такое сообщение об ошибке (0хс0000005) свидетельствует о проблемах или с таблицей IAT, или с параметром TLS Directory.


Давайте посмотрим на таблицу IAT в нашем файле dumped_.exe, для чего на заставке с сообщением об ошибке нажимаем кнопку ОК, после чего переходим в окно dump, в котором переходим на начало таблицы IAT по адресу 00481154:


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


Сначала идут нормальные адреса API, а затем ImpREC допустил сбой в своей работе (обведено красной рамкой).

Как заставить ImpREC восстановить таблицу IAT без ошибок? Я принял следующее решение. Надо полностью заполнить нулями секцию импорта в файле dumped.exe, и в чистую секцию импорта записать таблицы IAT. Чтобы загрузить файл dumped.exe в отладчик OllyDbg, необходимо обнулить значения адреса и размера в Import Directory:


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


Теперь файл dumped.exe нормально загружается в отладчик OllyDbg. Переходим в окне dump на секцию импорта, и выделяем всю эту секцию, и заполняем ее нолями:


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


Сохраняем эти изменения в файле, выбрав команду Copy to executable file.


Теперь опять, с помощью ImpREC, восстанавливаем таблицу IAT в доработанном файле dumped.exe. Опять пытаемся загрузить файл dumped_.exe в отладчик, и файл нормально загружается:


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


Теперь мы можем вырезать лишние секции в нашем файле dumped_.exe, которые были добавлены ASProtect. Но сначала давайте проверим, не украл ли пакер какие-либо ресурсы. Для этого запускаем утилиту ResFixer v1.0 beta 1:



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


Как видим, пакер действительно украл несколько ресурсов из секции ресурсов .rsrc, и перенес их в созданную им секцию .data. Нам нужно вернуть эти ресурсы в их родную секцию .rsrc, для чего мы будем использовать утилиту GUI for Resource Rebuilder v1.0 by Dr.Golova. Конечно, можно использовать и утилиту ResFixer v1.0 beta 1, однако она не всегда корректно восстанавливает ресурсы. Наиболее корректно работает утилита Resource Rebuilder v1.0 by Dr.Golova:


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



Загружаем файл в утилиту, оставляем настройки по умолчанию, нажимаем кнопку “Rebuild”, и утилита восстанавливает секцию ресурсов:


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


Теперь мы можем удалить из нашего файла dump_.exe две последние секции, созданные ASProtect, и секцию ресурсов .rsrc, которая сейчас - не полная. Для этого используем утилиту PE Tools v1.5 RC7:


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


Нам надо поправить данные Optional Header, для чего нажимаем на три кнопки с вопросительным знаком, которые я на рисунке указал стрелками:



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


И вставляем секцию .rsrc из файла rsrc.bin:


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


Корректируем имя этой секции на .rsrc:



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


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


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


В чем же дело. Открываем файл dump_.exe в PE Tools v1.5 RC7, и проходим на вкладку Directory Editor:


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


И нам сразу же бросаются в глаза адреса директорий Base Relocation Table, и TLS Directory, которые ранее находились в удаленной нами секции .data. Нам надо перенести эти адреса в другую секцию. Я решил перенести адрес TLS Directory - в секцию, которая находится по адресу 00085000, а Base Relocation Table - в секцию, которая находится по адресу 0024F000. Почему я принял такое решение? Если мы посмотрим на адрес 0049C9DC в упакованной программе, то увидим следующую цепочку байтов:


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


А если мы поищем эту цепочку байтов в HexWorkshop, то мы ее находим по адресу 00085000:


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


Секция файла, которая начинается с адреса 0084000, пустая (заполнена нолями), поэтому мы можем сюда перенести Base Relocation Table:


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


В упакованной программе по адресу 0049C9DC мы видим:


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


Значит, нам нужно вставить эти байты в наш файл dumped_.exe:


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


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


Сохраняем изменения, и корректируем адреса в этих директориях:


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


Одновременно корректируем имена секций (за аналог я взял неупакованную программу GridinSoft Notepad v3.2), чтобы придать файлу dumped_.exe законченный вид:


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


На этом мы закончили работу с доведением дампа dumped_.exe до нормального вида.



Конец части II



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



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


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