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

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


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


Asprotect 2.1x SKE Inline patching




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

Asprotect 2.1x SKE Inline patching

Программа

RAR Recovery Toolbox v1.0

Download

http://www.oemailrecovery.com/rarrecovery


html

Описание

Восстановление файлов из поврежденных архивов .rar

Инструменты

OllyDbg 1.10, PhantOm v0.58, PEiD v0.94, PE Tools v1.8.800.2006 RC7, Hex Workshop v4.23

Сложность

Для опытных crackers

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

ASProtect 2.1xSKE

Защита

ASProtect 2.1xSKE

Цель

Inline patching

Cracker

vnekrilov Дата: 20/06/07

Туториал №



0. ВВЕДЕНИЕ

Однажды, упорядочивая скачанные программы на жестком диске, и записывая их на CD, я ненароком удалил и некоторые незаписанные программы. Для восстановления этих удаленных программ мне пришлось использовать прекрасну ю программу EasyRecovery Professional, которая восстановила удаленные мной файлы .RAR. Однако эти архивы оказались поврежденными, которые не смог восстановить архиватор WinRAR. Оказалось, что в некоторые файлы .rar, которые относятся к одним программам, включена часть файлов из других программ, поэтому я решил спасти хоть что-то. Полазив в сети, я нашел довольно интересную программу RAR Recovery Toolbox v1.0, которая прекрасно проанализировала битый архив .rar, и указала, какие файлы она может восстановить. Однако, у нее имеется один недостаток - она требует регистрационный ключ. Поскольку этого ключа у меня нет, я решил взломать эту программу, которая оказалась упакована ASProtect 2.1xSKE. Она очень легко распаковалась с помощью прекрасного скрипта Aspr2.XX_unpacker_v1.0E.osc, написанного VolX, далее я нашел места в коде программы, где заменил условные прыжки INE безусловными прыжками JMP. Программа прекрасно запустилась, и нормально восстанавливала файлы небольшого размера. Однако, она давала сбой при анали зе файлов большого размера. Это было обусловлено тем, что, видимо, при распаковке программы не были замечены некоторые ошибки в коде. Поэтому, я решил сделать inline patching этой программы.

На русском языке я нашел весьма неплохую статью lord_Phoenix / REVENGE под названием "iNLiNE PATCHiNG ASPROTECT 2", однако она, с моей точки зрения, недостаточно подробно описывает метод inline patching программ, упакованных ASProtect. Кроме того, имеется ряд статей зарубежных cracker's (ThunderPwr, Synopsis, Nacho, и др.), которые написаны на английском или испанском языках, и не доступны для большого числа русскоязычных cracker's. Учитывая это, я решил написать эту статью на основе реверсинга конкретной программы RAR Recovery Toolbox v1.0 .

1. АНАЛИЗ ПАКЕРА ПРОГРАММЫ

С помощью сканера файлов PEiD v0.94 проверяем, чем упакована эта программа:


Этот пакер также подтверждается прямым осмотром структуры Entry Point, которая одинакова для всех программ, упакованных ASProtect:


Для выполнения inline patching этой программы, нам надо сначала найти OEP (или область около OEP) программы. Для поиска OEP используем скрипт Aspr2.XX_unpacker_v1.0E.osc, который, после завершения своей работы, останавливает программу на OEP:


Теперь перезапускаем программу, и переходим в окно дампа отладчика OllyDbg (нижнее окно), нажимаем клавиши CTRL+G, и вписываем адрес 004A29BC найденной нами OEP. Это позволит нам определить, из какой области памяти ASProtect записывается код в область OEP.


Пока все адреса около OEP заполнены нолями, поскольку код программы должен быть распакован из секции пакера. Поэтому устанавливаем breakpoint ^ memory on write на байт, расположенный в OEP:


Нажимаем клавиши ALT+O, чтобы показать диалог опций отладчика OllyDbg, устанавливаем флажки на все исключения:

Asprotect 2.1xSKE Inline patching



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

Asprotect 2.1xSKE Inline patching



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

Asprotect 2.1xSKE Inline patching



Переходим в окно кода OllyDbg, нажимаем клавиши CTRL+G, вписываем адрес OEP (004A29BC), и видим следующий код:

Asprotect 2.1xSKE Inline patching



Очевидно, что код полностью распакован, поскольку он соответствует тому коду, который мы нашли с помощью скрипта Aspr2.XX_unpacker_v1.0E.osc.

Теперь мы знаем, что запись кода в OEP выполняется из области памяти, которую можно увидеть, нажав клавиши ALT+M (отображение карты памяти программы):

Asprotect 2.1xSKE Inline patching


Эта область памяти не принадлежит к имеющимся секциям файла на диске, как это видно из PE-заголовка, она динамически создается пакером, и затем заполняется кодом.



Поскольку эта область памяти создается в процессе запуска программы, то мы не можем ее найти, когда программа загружена в отладчик, и остановлена на Entry Point. Поэтому нам надо найти момент создания пакером этой области памяти, чтобы ее протрассировать, и обеспечить минимальную доработку программы с помощью inline code.

Сначала нам нужно найти точку в секции ASProtect, из которой выполняется распределение памяти пакером ASProtect.

Перезагружаем программу в отладчике с помощью клавиш CTRL+F2.

Нажимаем клавиши CTRL+G, и вписываем слово VirtualAlloc; эта API используется для выделения требуемой памяти в системе. Она широко используется во многих пакерах, в т.ч. и в ASProtect, для выделения области памяти, которая затем будет заполнена кодо м из пакера.

Asprotect 2.1xSKE Inline patching



Нажимаем клавишу F9, и OllyDbg прерывается на точке входа в API VirtualAlloc. Затем нажимаем на клавиши ALT+F9, чтобы вернуться в код вызывающей программы, и посмотреть на адрес, который записан в регистре EAX:

Asprotect 2.1xSKE Inline patching



ПРИМЕЧАНИЕ

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

После первого вызова API VirtualAlloc, создается область памяти по адресу 00980000:

Asprotect 2.1xSKE Inline patching



Однако, как мы видели немного раньше, код в область OEP записывается из области памяти 009B0000, которая создается при выполнении второго вызова API VirtualAlloc, который находится по адресу 004D44FC. Поэтому проходим на адрес 004D44FC, выполняем инструкцию CALL DWORD PTR SS:[EBP+3F0], и в регистре EAX мы видим адрес 009B0000.

В области памяти по адресу 009B0000 пока нет никакого кода, который выполняет распаковку кода OEP. Это означает, что данная область памяти создана для кода, который пока еще не распакован, и нам надо найти точку, где выполняется распаковка этого кода в данную область памяти.

Давайте посмотрим, доступен ли код подпрограммы, которая вызывает API VirtualAlloc, когда программа находится на Entry Point, или нам снова нужно заняться его поиском его раскриптовки.

Нажимаем клавиши CTRL+F2, и переходим на адрес 004D44FC, чтобы посмотреть, что там находится:

Asprotect 2.1xSKE Inline patching



Эта часть кода абсолютно не похожа на код, который мы видели немного выше, а это означает, что ASProtect выполняет некоторую предварительную раскриптовку кода, перед вызовом API VirtualAlloc. Поэтому, нам надо найти, откуда записывается этот код. Чтобы выполнить этот поиск, мы должны перезагрузить програм му в OllyDbg, и установить breakpoint ^ memory on writing на адрес 004D44FC, чтобы найти точку записи кода по этому адресу.

Asprotect 2.1xSKE Inline patching



Нажимаем клавишу F9, и OllyDbg прерывается на адресе 004EB13F; следующая инструкция CALL 004D424E, которая находится на адресе 004D4239, выполняет раскриптовку этого кода.

Asprotect 2.1xSKE Inline patching



Теперь перезагружаем программу в OllyDbg с помощью клавиш CTRL+F2, и из Entry Point проходим на адрес 004D4239, чтобы посмотреть, что там находится. Мы видим, что код, который здесь имеется, не соответствует вышеприведенному коду:

Asprotect 2.1xSKE Inline patching



Нам опять надо найти, откуда записывается этот код, для чего устанавливаем breakpoint ^ memory on writing на адрес 004D4239, и нажимаем клавишу F9:

Asprotect 2.1xSKE Inline patching



Здесь производится раскриптовка кода, и появляется инструкция CALL 004D424E. Опять перезагружаем программу в OllyDbg с помощью клавиш CTRL+F2, и из Entry Point проходим на

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

Трассируем программу с помощью клавиши F7, и видим, что мы находимся в цикле распаковки; чтобы сделать этот вид более наглядным и понятным, можно провести некоторые небольшие манипуляции с кодом , с помощью инструкции NOP.

Asprotect 2.1xSKE Inline patching



Точка выхода из цикла расположена по адресу 004D419E, поэтому устанавливаем здесь breakpoint, и нажимаем клавишу F9, чтобы выполнить весь цикл. После остановки программы на инструкции JMP, смотрим, как изменяется код при выполнении цикла распаковки.

Asprotect 2.1xSKE Inline patching



Теперь нам надо снова перезагрузить программу в OllyDbg с помощью клавиш CTRL+F2, и пройти на адрес 004D419E, чтобы посмотреть там код:

Asprotect 2.1xSKE Inline patching



Здесь мы видим нормальный код, который означает, что этот прыжок не изменяется, при ег о просмотре из Entry Point программы, и до полного выполнения первого цикла раскриптовки. Это - очень хорошая для нас информация, поскольку эта точка является первой точкой переадресации на область нашего патча; записываем комментарий для этого адреса .

КОНЕЦ ЦИКЛА #1 (Часть #1): 004D419E

ОРИГИНАЛЬНАЯ ИНСТРУКЦИЯ: JMP 004D41CA (E9 27 00 00 00)

После выполнения цикла, нам надо проверить, правильно ли записан код по адресу второго вызова API VirtualAlloc.

Нажимаем клавиши CTRL+G, и вписываем адрес 004D44FC, и видим, что код здесь все еще не раскриптован. Продолжаем трассирование кода с помощью клавиши F7, и после выполнения нескольких инструкций, мы опять попадаем на цикл раскриптовки .

Asprotect 2.1xSKE Inline patching



По адресу 004D4278 у нас находится точка выхода из цикла, поэтому мы можем просто установить breakpoint на этот адрес (F2), и нажать клавишу F9, для быстрого выполнения всего цикла.

Записываем в комментарии адрес выхода из цикла; это - вторая точка переадресации на область патча.

КОНЕЦ ЦИКЛА #2 (Часть #2): 004D4278 ОРИГИНАЛЬНАЯ ИНСТРУКЦИЯ: MOV EBX,EDI (8B DF)

Как это делали и раньше, смотрим, правильно ли записан код по адресу вызова API VirtualAlloc. Видим, что искомый код все еще отсутствует, поэтому опять трассируем программу.


Asprotect 2.1xSKE Inline patching



Как и ранее, выполняем этот цикл, устанавливая breakpoint на адресе выхода из цикла 004D42FD, и нажимаем клавишу F9, чтобы пройти на эту точку.

Записываем комментарии для этого адреса выхода из цикла; это - третья точка переадресации на область патча.

КОНЕЦ ЦИКЛА #3 (Часть #3): 004D42FD

Здесь у нас находится третий цикл распаковки:

ОРИГИНАЛЬНАЯ ИНСТРУКЦИЯ: JMP 004D4320 (E9 1E 00 00 00)

Нужного кода по адресу 004D44FC опять нет, поэтому мы продолжаем трассирование программы.

Опять у нас имеется еще один цикл раскриптовки.


Устанавливаем breakpoint (F2) на адресе выхода из цикла 004D4416, и выполняем программу с помощью клавиши F9, это - четвертая точка переадресации на область патча.

КОНЕЦ ЦИКЛА #4 (Часть #4): 004D4416 ОРИГИНАЛЬНАЯ ИНСТРУКЦИЯ: MOV AH,DL (8A E2)

Наконец-то, теперь записан наш код:

Asprotect 2.1xSKE Inline patching


Итак, давайте запишем сделанные нами шаги :




  1. Находимся на точке входа пакера.

  2. Выполняем цикл раскриптовки #1, точка

  3. Выполняем цикл раскриптовки #2, точка

  4. Выполняем цикл раскриптовки #3, точка

  5. Выполняем цикл раскриптовки #4, точка

выхода находится по адресу 004D419E выход а находится по адресу 004D4278 выхода находится по адресу 004D42FD выхода находится по адресу 004D4416

6. Проходим на API VirtualAlloc, которая вызывается из адреса 004D44FC

При установке breakpoint на адреса выхода из циклов раскриптовки, следует иметь ввиду, что каждая breakpoint активизируется поочередно в последовательности, которая начинается с Entry Point, и после выполнения каждого цикла.

Asprotect 2.1xSKE Inline patching

Выполняем трассирование программы до инструкции RETN:

Asprotect 2.1xSKE Inline patching

Теперь мы можем установить breakpoint на адрес 004D44FC, и программа останавливается на инструкции вызова API VirtualAlloc.

Инструкция PUSH 9DE000, сопровождаемая инструкцией RETN, выполняет прыжок в новую распределенную область памяти, откуда производится распаковка кода программы . Но, для нас представляет интерес инструкция PUSH 8000, которая позволяет восстановить в регистре EDI базовый адрес новой распределенной области памяти (009B0000).

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


АБСОЛЮТНЫЙ АДРЕС (Часть #5): 004D45D5 ОРИГИНАЛЬНАЯ ИНСТРУКЦИЯ : PUSH 8000 -> 68 00 80 00 00

Прыжок выполняется в распределенную ASProtect область, на offset 0002E000 (009DE000 - 009B0000 = 0002E000).

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

Теперь мы попали в область памяти, которая выполняет распаковку кода для OEP.


Если мы пройдем на offset 00002663 от базового адреса, чтобы посмотреть на код, то видим, что он не соответствует тому коду, который мы имели в начале нашего анализа. Значит, где-то еще происходит раскриптовка данного кода.

Asprotect 2.1xSKE Inline patching



Продолжаем трассирование программы от адреса 009DE000, и видим вызов API VirtualAlloc по адресу 009DE0C4; здесь у нас имеется еще один цикл раскриптовки кода.

Asprotect 2.1xSKE Inline patching



И, в итоге, получаем прыжок на offset 0002E30D.

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

OFFSET (Часть #6): 0002E0F3

ОРИГИНАЛЬНАЯ ИНСТРУКЦИЯ : PUSH 8000 - > 68 00 80 00 00

Опять смотрим на раскриптовку кода по адресу 009B2663 в окне кода OllyDbg. Код еще не раскриптован, поэтому продолжаем трассирование программы.

Выполняем инструкцию RETN с помощью клавиши F8, и попадаем на offset 0002E30D, проходим на offset 0002E343, на котором записана инструкция вызова API VirtualAlloc.

Asprotect 2.1xSKE Inline patching



Выполняем трассирование с F8 до offset 0002E3C7, где находится очередной цикл записи раскриптованного кода, который используется для распаковки кода программы :

Asprotect 2.1xSKE Inline patching



Снова записываем комментарий для offset инструкции PUSH 8000, это - наша следующая точка переадресации на область патча.

OFFSET (Часть #7): 0002E3D7

ОРИГИНАЛЬНАЯ ИНСТРУКЦИЯ: PUSH 8000 - > 68 00 80 00 00

При нажатии клавиши F8, будет записан следующий код:

Asprotect 2.1xSKE Inline patching



Поэтому мы можем утверждать, что полностью раскриптовали все инструкции, которые записаны в область памяти 009B0000.

Продолжаем трассирование программы. И, приходим на весьма интересный блок инструкций, который раскриптовывает IAT:

Asprotect 2.1xSKE Inline patching


Здесь записываются реальные адреса API:

Asprotect 2.1xSKE Inline patching



Декодированные API записываются на offset 0002E5867, а внизу, в окне дампа, мы видим таблицу IAT, заполненную реальными адресами API:

Asprotect 2.1xSKE Inline patching



Точка выхода из цикла раскриптовки API находится в offset 0002E5AB. С помощью инструкции MOV DWORD PTR SS:[EBP+442F11],EAX, выполняется установка адреса, на который мы должны прыгнуть, после выполнения инструкции RETN:

Asprotect 2.1xSKE Inline patching



Нашу следующую переадресацию на область патча запишем в offset 0002E5C1: OFFSET (Часть #8): 0002E5C1

ОРИГИНАЛЬНЫЕ ИНСТРУКЦИИ: POPAD/JNZ (61 75 08)

Выполняем инструкцию RETN, которая находится в offset 0002E5D1, и попадаем сюда:

Asprotect 2.1xSKE Inline patching



Здесь полезно, для ускорения дальнейшего анализа, установить hardware breakpoint on execution на этой новой области памяти (offset 000250C4); это позволит сэкономить время при перезагрузке программы.

Теперь подошло время заняться проверкой CRC (проверка целостности кода на жестком диске). Нажимаем клавиши CTRL+B, и вписываем бинарную строку 6A006A006A006A04, для ее поиска:

Asprotect 2.1xSKE Inline patching



Нажимаем кнопку OK, и переходим на указанную последовательность байт, которая начинается в offset 00017C73:

Asprotect 2.1xSKE Inline patching



Этот код показывает образ файла с помощью API MapViewOfFileEx, которая вызывается через инструкцию CALL EAX:

Asprotect 2.1xSKE Inline patching



ASProtect, используя API MapViewOfFile, создает образ файла, который находится на нашем жестком диске, эта проверка должна обнаружить чередование некоторого кода, который был записан hardraded-способом, эта проверка выполняется только для оригинального файла, поскольку код в OEP еще не записывается.

ПРИМЕЧАНИЕ для API MapViewOfFile

Из справочника MSDN: MapViewOfFile

The MapViewOfFile function maps a view of a file mapping into the address space of a calling process,

To specify a suggested base address for the view, use the MapViewOfFileEH function. However this practice is not recommended.

LPVOID MapVieTjOfEile (

HANDLE hFileMappinyObj&ct,

DflDKD tih'FileOffsetHicrh, SUOKD dHrFileOffsetLow, SIZE_T dufhmberOfBytesTcitap

) ;

Инструкция PUSH 4 устанавливает флажок для методов доступа к области, которая содержит образ файла (mapping) для значения FILE_MAP_READ, и у нас должен быть способ изменения байта в отображаемом образе, для обмана ASProtect, чтобы показать, что файл не был изменен. Для этого нам надо изменить атрибут доступа к FILE_MAP_COPY, который должен иметь значение 01; поэтому мы должны будем заменить оригинальную инструкцию PUSH 4, новой инструкцией PUSH 1, и позднее, восстановить оригинальный код, чтобы избежать последующего детектирования изменений из ASProtect.

FILE_MAP_COPY = 01 FILE_MAP_WRITE = 02 FILE_MAP_READ = 04

Value


Meaning

FILE.

.MAP.

.WRITE

Read/write access. The mapping object must be created with PAGE_READWRITE protection. A read/write view of the file is mapped.

FILE.

.MAP.

.READ

Read-only access. The mapping object must be created with PAGE_RE AD WRITE or PAGE_READONLY protection. A read-only view of the file is mapped.

FILE.

.MAP.

.COPY

Copy-on-write access. The mapping object must be created with PAGE_WRITECOPY protection.

The system commits physical storage from the paging file at the time that MapViewOfFile is called, The actual physical storage is not used until a thread in the process writes to an address in the view. At that time, the system copies the original page to a new page that is backed by the paging file, maps the page into the process address space, and changes the page protection to PAGE_READWRITE. The threads in the process can access only the local copy of the data, not the original data, If the page is ever trimmed from the working set of the process, it can be written to the paging file storage that is committed when MapViewOfFile is called,

This process only allocates physical memory when a virtual address is actually written to. Changes are never written back to the original file, and are freed when the thread in your process unrnaps the view,

Paging file space for the entire view is committed when copy-on-write access is specified, because the thread in the process can write to every single page. Therefore, enough physical storage space must be obtained at the time MapViewOfFile is called,

FILE.

.MAP.

.EXECUTE

Execute access, Code can be run from the mapped memory, The mapping object must be created with PAGE_EXECUTE_RE AD WRITE or PAGE_EXECUTE_READ access,

Windows Server 2003 and Windows XP: This feature is not available until Windows XP SP2 and Windows Server 2003 SP1,


Offset инструкции PUSH 4 равен 00017C79, и мы должны выполнить другую переадресацию на область нашего патча только после выполнения API MapViewOfFile, что должно быть сделано в offset 00017C8B.

OFFSET (Часть #9): 00017C8B

Опять трассируем с F8, и приходим сюда:

ОРИГИНАЛЬНАЯ ИНСТРУКЦИЯ : MOV EBX,EAX (8B D8)

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

После выполнения API MapViewOfFile, образ файла записан по адресу 00AE0000:

Asprotect 2.1xSKE Inline patching



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

Asprotect 2.1xSKE Inline patching




Asprotect 2.1xSKE Inline patching



Здесь производится сравнение подсчитанного значения CRC с контрольным значением. Если они не равны, то пакер показывает следующую заставку:

Asprotect 2.1xSKE Inline patching



Если же они равны, то мы приходим сюда:

Asprotect 2.1xSKE Inline patching




Здесь, при выполнении CALL 009B5994, выполняется распаковка кода программы:

Asprotect 2.1xSKE Inline patching



Выходим из цикла распаковки кода программы, установив breakpoint на адрес 009C7F58, и продолжаем трассирование программы, пока не приходим сюда:

Asprotect 2.1xSKE Inline patching



При выполнении инструкции CALL 009C185C, которая находится по адресу 009C84D9, подсчитывается CRC распакованного кода программы, значение которого записывается в регистре EAX:

Asprotect 2.1xSKE Inline patching



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

Asprotect 2.1xSKE Inline patching



Правильное значение CRC хранится в стеке по адресу [ESP+10], и в этом адресе записано значение - 7A4B03AD:

Asprotect 2.1xSKE Inline patching



Теперь можно выполнить патчирование кода нашей программы, но только после этой проверки CRC; после чего программа должна нормально за пускаться и работать. Адреса для патчирования (я не описываю здесь поиск этих адресов, поскольку темой этой статьи является написание inline code):

Asprotect 2.1xSKE Inline patching



Asprotect 2.1xSKE Inline patching



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

OFFSET (Часть #10): 000184F8

ОРИГИНАЛЬНАЯ ИНСТРУКЦИЯ : MOV EAX,DWORD[ESP+C] (8B 44 24 0C)

2. INLINE PATCHING

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

Последняя секция .adata является подходящей областью; параметр Raw Size этой секции равен 0, а Virtual Size равен 1000, поэтому мы можем смело увеличить эту секцию, чтобы можно было записать здесь код патча. Запускаем PE Tools v1.5.800.2006 RC7, и загружаем в него наш упакованный файл. Изменяем параметр Raw Size секции .adata, вместо 0 мы записываем 1000 (это - достаточный размер для нашего патча), и сохраняем изменения :

Asprotect 2.1xSKE Inline patching



Теперь запускаем Hex Workshop v4.23, и загружаем в него упакованный файл; прокручиваем файл в самый его конец (до адреса 0006C600), и вставляем 1000 байт, заполняя их значениями 90. Сохраняем все изменения :

Asprotect 2.1xSKE Inline patching


Теперь, если мы попытаемся запустить файл, появляется следующая ошибка


Asprotect 2.1xSKE Inline patching



Эта ошибка возникает из-за проверки целостности образа файла через API MapViewOfFile.

Примечание:

Здесь нужно учитывать следующий важный аспект; некоторые версии ASProtect, после выполнения API MapViewOfFile, заполняют нолями часть области .adata. Это означает, что мы должны проверить, какая часть области .adata заполняется нолями, и выполнить переадресацию на адрес, который следует за последним затираемым байтом ASProtect (вот по этой причине мы и заполнили секцию .adata числами 90, поскольку не затертая область этой секции будет содержать числа 90 вместо нолей) .

Давайте загрузим наш файл в отладчик, и выполним API MapViewOfFile. Мы видим, что в нашем случае, ASProtect не заполняем нолями эту область памяти, поэтому мы можем начать запись кода патча с адреса 004F5000.

Записываем следующий код патча:

004D419E JMP 004F5000 ; Прыжок на часть 1 из прыжка hardcoded



Часть #1

004F5000 MOV DWORD PTR DS:[4D4278],0C4EB 004F500A MOV DWORD PTR DS:[4D4244],4F502268

004F5014 MOV WORD PTR DS:[4D4248],0C300 004F501 D JMP 004D41CA

Часть #2

004F5022 MOV DWORD PTR DS:[4D4244],E970B322 004F502C MOV WORD PTR DS:[4D4248],0F6E 004F5035 MOV DWORD PTR DS:[4D4278],D181DF8B 004F503F MOV DWORD PTR DS:[4D42FD],20D4CE9 004F5049 JMP 004D4278

Часть #3

004F504E MOV DWORD PTR DS:[4D42FD],1 EE9 004F5058 MOV DWORD PTR DS:[4D4416],0AAEB 004F5062 MOV DWORD PTR DS:[4D43C2],4F507A68

004F506C MOV WORD PTR DS:[4D43C6],0C300

004F5075 JMP 004D4320

Часть #4

004F507A MOV DWORD PTR DS:[4D43C2],E970B322

004F5084 MOV WORD PTR DS:[4D43C6],0F6E

004F508D MOV DWORD PTR DS:[4D4416],0E8E28A

004F5097 MOV DWORD PTR DS:[4D45D5],20ACCE9

004F50A1 JMP 004D4416

Часть #5

004F50A6 MOV DWORD PTR DS:[4D45D5],800068

004F50B0 MOV DWORD PTR DS:[4F5FFC],EDI

004F50B6 MOV DWORD PTR DS:[EDI+2E0F3],4F50CE68

004F50C0 MOV WORD PTR DS:[EDI+2E0F7],0C300

004F50C9 JMP 004D45D5

Часть #6

004F50CE PUSHAD

004F50CF PUSHFD

004F50D0 MOV EAX,DWORD PTR DS:[4F5FFC]

004F50D5 MOV DWORD PTR DS:[EAX+2E0F3],800068

004F50DF MOV BYTE PTR DS:[EAX+2E0F7],0

Записываем прыжок на часть 2 патча, которая будет записана по адресу 004F5022 через промежуточный на адрес 004D4244, поскольку по адресу 004D4278 не хватает места для записи прыжка на патч Прыжок выполняется через инструкции PUSH и RETN Восстанавливаем прыжок, который был из адреса 004D419E (в оригинальной программе)

Восстанавливаем оригинальные байты в 00 4D4244 Восстанавливаем оригинальные байты в 004D4248 Восстанавливаем оригинальные байты в 00 4D4278 Записываем прыжок на часть 3 патча (адрес 004F504E) Прыгаем на начало инструкции MOV EBX,EDI

Восстанавливаем оригинальные байты в 004 D42FD Записываем прыжок на часть 4 патча, которая будет записана по адресу 004D4416 через промежуточный на адрес 004D43C2, поскольку по адресу 004D4416 не хватает места для записи прыжка на патч Прыжок выполняется через инструкции PUSH и RETN Восстанавливаем прыжок, который был из адреса 004D42FD (в оригинальной программе)

Восстанавливаем оригинальные байты в 00 4D43C2 Восстанавливаем оригинальные байты в 004D43C6 Восстанавливаем оригинальные байты в 4D4416 Записываем прыжок на часть 5 патча (адрес 004F50A6) Прыгаем на начало инструкции MOV Ah,DL

Восстанавливаем код PUSH 8000 Сохраняем базовый адрес (в конце секции файла) Прыжок на часть 6 с offset 0002E0F3 (PUSH 004F50CE) RETN на offset 0002E0F7

Возвращаемся к выполнению инструкции PUSH 8000

; Сохраняем регистры ; Сохраняем флаги

; Загружаем базовый адрес в регистр EAX ; Восстанавливаем PUSH 8000 на offset 0002E0F3 ; Восстанавливаем PUSH 0 (опкод 006A)

004F50E6 MOV BYTE PTR DS:[EAX+2E0F8],6A

004F50ED MOV DWORD PTR DS:[EAX+2E3D7],4F511 268

004F50F7 MOV WORD PTR DS:[EAX+2E3DB],0C300

004F5100 ADD EAX,2E0F3

004F5105 MOV DWORD PTR DS:[4F510D],EAX

004F510A POPFD

004F510B POPAD

004F510C PUSH 00000000

004F5111 RET

Часть #7

004F5112 PUSHAD

004F5113 PUSHFD

004F5114 MOV EAX,DWORD PTR DS:[4F5FFC]

004F5119 MOV DWORD PTR DS:[EAX+2E3D7],800068

004F5123 MOV BYTE PTR DS:[EAX+2E3DB],0

004F512A MOV BYTE PTR DS:[EAX+2E3DC],6A

004F5131 MOV DWORD PTR DS:[EAX+2E5C1],4F515668

004F513B MOV WORD PTR DS:[EAX+2E5C5],0C300

004F5144 ADD EAX,2E3D7

004F5149 MOV DWORD PTR DS:[4F5151],EAX

004F514E POPFD

004F514F POPAD

004F5150 PUSH 00000000

004F5155 RET

Часть #8

004F5156 PUSHAD

004F5157 PUSHFD

004F5158 MOV EAX,DWORD PTR DS:[4F5FFC]

004F515D MOV DWORD PTR DS:[EAX+2E5C1],B8087561

004F5167 MOV WORD PTR DS:[EAX+2E5C5],1

004F5170 MOV BYTE PTR DS:[EAX+17C7A],1

004F5177 MOV DWORD PTR DS:[EAX+17C8B],4F519C68

004F5181 MOV WORD PTR DS:[EAX+17C8F],0C300

004F518A ADD EAX,2E5C1

004F518F MOV DWORD PTR DS:[4F5197],EAX

004F5194 POPFD

004F5195 POPAD

004F5196 PUSH 00000000

004F519B RET

Прыжок на часть 7 с offset 0002E3D7 (PUSH 004F5112)

RETN на offset 0002E3DB

Вычисляем адрес возврата

Записываем адрес возврата

Восстанавливаем флаги

Восстанавливаем регистры

Опкод 6800000000

Прыгаем на offset 0002E0F3

Сохраняем регистры Сохраняем флаги

Загружаем базовый адрес в регистр EAX Восстанавливаем PUSH 8000 на offset 0002E3D7 Восстанавливаем PUSH 0 (опкод 006A)

Прыжок на часть 8 с offset 0002E5C1 (PUSH 004F5156)

RETN на offset 0002E5C5

Вычисляем адрес возврата

Записываем адрес возврата

Восстанавливаем флаги

Восстанавливаем регистры

Опкод 6800000000

Прыгаем на offset 0002E3D7

Сохраняем регистры Сохраняем флаги

Загружаем базовый адрес в регистр EAX Восстанавливаем POPAD/JNZ для offset 0002E5C1 Восстанавливаем 1

Меняем PUSH 4 на PUSH 1 (offset 0001 7C7A)

Прыжок на часть 9 (с инструкции MOV EBX,EAX)

RETN на offset 00017C8F

Вычисляем адрес возврата

Записываем адрес возврата

Восстанавливаем флаги

Восстанавливаем регистры

Опкод 6800000000

Прыгаем на offset 0002E5C1



На части 9 нашего патча мы должны обойти проверку CRC, для чего нам необходимо рассмотреть изменения, которые имеют два образа файла: оригинальный, и с нашем патчем. Запускаем два отладчика OllyDbg, в которые загружаем оба файла, проходим до инструкции CALL EAX, которая находится по адресу 009C7C8B, и выполняем API MapViewOfFile. В регистре EAX записывается адрес области памяти, где загружен Образ файла:

Asprotect 2.1xSKE Inline patching



Запускаем Tools v1.8.800.2006 RC7, и делаем дампы Образа памяти оригинального и пропатченного файлов:


Asprotect 2.1xSKE Inline patching


d

л

1

Полученные дампы загружаем в утилиту сравнения файлов Hex Workshop v4.23, и получаем следующий результат:

Asprotect 2.1xSKE Inline patching



Для нас интерес представляют различия, которые содержатся в offset 00000399 и 0004BF9F. В offset 00000399 содержится значение параметра Raw Size секции .adata, а в offset 0004BF9F содержится код первого прыжка hardcoded, который мы заменили прыжком на область нашего патча. В верхней части мы можем посмотреть на оригинальные байты, которые нам надо восстановить в пропатченном файле:




Теперь мы можем написать код для части #9 нашего патча:



Часть #9

004F519C MOV BYTE PTR DS:[EAX+399],0

004F51A3 MOV DWORD PTR DS:[EAX+4BF9F],27

004F51AD PUSHAD

004F51AE PUSHFD

004F51AF MOV EAX,DWORD PTR DS:[4F5FFC]

004F51 B4 MOV BYTE PTR DS:[EAX+17C7A],4

004F51 BB MOV DWORD PTR DS:[EAX+17C8B],1 D89D88B

004F51C5 MOV WORD PTR DS:[EAX+17C8F],8418

004F51CE MOV DWORD PTR DS:[EAX+184F8],4F51F368

004F51D8 MOV WORD PTR DS:[EAX+184FC],0C300

004F51E1 ADD EAX,17C8B

004F51 E6 MOV DWORD PTR DS:[4F51 EE],EAX

004F51EB POPFD

004F51 EC POPAD

004F51 ED PUSH 00000000

004F51F2 RET

Восстанавливаем размер raw size Восстанавливаем первый прыжок Сохраняем регистры Сохраняем флаги Загружаем базовый адрес Восстанавливаем PUSH 1 на PUSH 4 Восстанавливаем MOV EBX,EAX Восстанавливаем байты 8418

Прыжок на часть 10 с offset 000184F8 (PUSH 4F51 F3)

RETN на offset 000184FC

Вычисляем адрес возврата

Записываем адрес возврата

Восстанавливаем флаги

Восстанавливаем регистры

Опкод 6800000000

Прыгаем на offset 00017C8B



Из предыдущего анализа мы знаем, что нам нужно пропустить проверку значения 45, и тогда мы можем написать нашу последнюю часть кода.



Часть #10

004F51F3 PUSHAD

004F51F4 PUSHFD

004F51 F5 MOV EAX,DWORD PTR DS:[4F5FFC]

004F51 FA MOV DWORD PTR DS:[EAX+184F8],0C24448B

004F5204 MOV WORD PTR DS:[EAX+184FC],40A3

004F520D MOV WORD PTR DS:[49E882],7CEB

004F5216 MOV WORD PTR DS:[49E937],6CEB

004F521F MOV WORD PTR DS:[49EA4B],9090

004F5228 MOV DWORD PTR DS:[49F89A],6563694C

004F5232 MOV DWORD PTR DS:[49F89E],6465736E

004F523C MOV DWORD PTR DS:[49F8A2],29

004F5246 MOV BYTE PTR DS:[49F8A6],0

004F524D MOV DWORD PTR DS:[4C3DE6],656E7628

Сохраняем регистры

Сохраняем флаги

Загружаем базовый адрес

Восстанавливаем оригинальную инструкцию

Восстанавливаем оригинальную инструкцию

Patch 1

Patch 2

Patch 3

Patch 4 (Слово "Licensed") Patch 5 (Слово "vnekrilov")

004F5257 MOV DWORD PTR DS:[4C3DEA],6C69726B

004F5261 MOV DWORD PTR DS:[4C3DEE],29766F

004F526B MOV DWORD PTR DS:[4C3DF2],0

004F5275 MOV DWORD PTR DS:[4C3DF6],0

004F527F MOV DWORD PTR DS:[4C3DFA],0

004F5289 MOV WORD PTR DS:[4C3DFE] ,0

004F5292 ADD EAX,184F8

004F5297 MOV DWORD PTR DS:[4F529F],EAX

004F529C POPFD

004F529D POPAD

004F529E PUSH 0

004F52A3 RET

Вот и все.

Благодарности:

lord_Phoenix / REVENGE за его статью "iNLiNE PATCHiNG ASPROTECT 2".

ThunderPwr за его статьи "Inline Asprotect 2.x" и "ASProtect 2.3 SKE inline patching tutorial".

Nacho за его статьи "Inline Patching Asprotect (parte 1) и (parte 2)"



Скачать статью "Asprotect 2.1x SKE Inline patching" в авторском оформление + файлы.
пароль архива на картинке



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


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