175
© <2009> <Некрылов Валентин> Распаковка программ, защищенных Asprotect Note: To change the product logo for your own print manual or PDF, click "Tools > Manual Designer" and modify the print manual template.

распаковка Asprotect

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: распаковка Asprotect

© <2009> <Некрылов Валентин>

Распаковка программ,защищенных Asprotect

Note:

To change the product logo for your own print manual or

PDF, click "Tools > Manual Designer" and modify the print

manual template.

Page 2: распаковка Asprotect

Title page 1Use this page to introduce the product

by vnekrilov

This is "Title Page 1" - you may use this page to introduceyour product, show title, author, copyright, company logos,etc.

This page intentionally starts on an odd page, so that it is onthe right half of an open book from the readers point of view.This is the reason why the previous page was blank (theprevious page is the back side of the cover)

Page 3: распаковка Asprotect

All rights reserved. No parts of this work may be reproduced in any form or by any means - graphic, electronic, ormechanical, including photocopying, recording, taping, or information storage and retrieval systems - without thewritten permission of the publisher.

Products that are referred to in this document may be either trademarks and/or registered trademarks of therespective owners. The publisher and the author make no claim to these trademarks.

While every precaution has been taken in the preparation of this document, the publisher and the author assume noresponsibility for errors or omissions, or for damages resulting from the use of information contained in thisdocument or from the use of programs and source code that may accompany it. In no event shall the publisher andthe author be liable for any loss of profit or any other commercial damage caused or alleged to have been causeddirectly or indirectly by this document.

Printed: Декабрь 2009 in (whereever you are located)

Распаковка программ, защищенныхAsprotect© <2009> <Некрылов Валентин>

PublisherSpecial thanks to:

All the people who contributed to this document, to mum and dadand grandpa, to my sisters and brothers and mothers in law, to oursecretary Kathrin, to the graphic artist who created this great productlogo on the cover page (sorry, don't remember your name at themoment but you did a great work), to the pizza service down thestreet (your daily Capricciosas saved our lives), to the copy shopwhere this document will be duplicated, and and and...

Last not least, we want to thank EC Software who wrote this greathelp tool called HELP & MANUAL which printed this document.

Managing Editor

Technical Editors

Cover Designer

...enter name...

...enter name...

...enter name...

...enter name...

...enter name...

Production

...enter name...

Team Coordinator

...enter name...

Page 4: распаковка Asprotect

Распаковка программ, защищенных Asprotect4

© <2009> <Некрылов Валентин>

Table of Contents

Foreword 7

Part I Введение 9

Part II Распаковка программ, защищенныхAsprotect 12

................................................................................................................................... 121 Определение версии протектора и компилятора

................................................................................................................................... 142 Конфигурация отладчика и плагинов

................................................................................................................................... 163 Поиск OEP (SBOEP)

................................................................................................................................... 214 Восстановление таблицы INIT

................................................................................................................................... 285 Восстановление таблицы IAT

................................................................................................................................... 386 Восстановление вызовов эмулируемых APIs

................................................................................................................................... 437 Эмуляция APIs Asprotect

.......................................................................................................................................................... 43Эмуляция APIs Asprotect в ASProtect с коротким ключом (версии 2.xx SKE)

.......................................................................................................................................................... 47Эмуляция APIs Asprotect в ASProtect с длинным ключом (версии 1.xx)

.......................................................................................................................................................... 53Эмуляция APIs Asprotect, вызываемых из Asprotect.dll

.......................................................................................................................................................... 56Эмуляция APIs Asprotect, вызываемых из кода программы

................................................................................................................................... 568 Устранение проверок целостности кода (CRC) в

распакованной программе

................................................................................................................................... 589 Восстановление подпрограмм с эмулированными

инструкциями

.......................................................................................................................................................... 61Получение файла Asprotect.dll из распаковываемой программы

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

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

.......................................................................................................................................................... 74Получение таблицы расположения данных в массиве данных для эмулированных инструкций

.......................................................................................................................................................... 84Получение таблицы расположения данных в массиве для эмулированных инструкций, выполняемых во второй VM

.......................................................................................................................................................... 87Получение таблицы идентификаторов эмулированных инструкций, выполняемых во второй VM

.......................................................................................................................................................... 88Корректировка кода VM для восстановления эмулированных инструкций в коде программы

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

................................................................................................................................... 9110 Восстановление секции импорта в распаковываемой

программе

.......................................................................................................................................................... 91Восстановление секции импорта с помощью скрипта “Восстановление секции импорта (.idata) в распакованных программах.osc”

.......................................................................................................................................................... 98Восстановление секции импорта с помощью утилиты Import REConstructor

................................................................................................................................... 10111 Борьба с переносом кода в специальные области памяти

.......................................................................................................................................................... 102Поиск подпрограммы адресации прыжков в области памяти Asprotect и создание таблицы прыжков

.......................................................................................................................................................... 104Поиск адресов массивов данных с эмулированными инструкциями в областях памяти Asprotect с украденным кодом

.......................................................................................................................................................... 109Объединение всех областей со Stolen Code в одну секцию файла

................................................................................................................................... 11112 Сборка распакованного файла

.......................................................................................................................................................... 112Подготовка файла dumped.exe к прикручиванию секции с украденным кодом

.......................................................................................................................................................... 115Прикручивание секции с украденным кодом к файлу dumped.exe

.......................................................................................................................................................... 116Восстановление секции ресурсов .rsrc

.......................................................................................................................................................... 118Переадресация прыжков из кода программы на секцию с украденным кодом .aspr

.......................................................................................................................................................... 119Устранение проверок целостности кода второго типа

................................................................................................................................... 12113 Очистка областей со Stolen Code от мусорного кода

Page 5: распаковка Asprotect

5Contents

5

© <2009> <Некрылов Валентин>

Part III Практика распаковки программ 125

................................................................................................................................... 1251 Распаковка программы Sticky Password v4.0.0.148

.......................................................................................................................................................... 125Определение протектора и языка программирования

.......................................................................................................................................................... 126Определение опций защиты программы

.......................................................................................................................................................... 127Восстановление таблицы IAT и вызовов эмулированных APIs

.......................................................................................................................................................... 128Устранение проверок целостности кода CRC) программы

.......................................................................................................................................................... 128Эмуляция APIs Asprotect, вызываемых из кода программы

.......................................................................................................................................................... 128Восстановление секции импорта в распакованной программе

.......................................................................................................................................................... 131Поиск областей со Stolen Code и восстановление в них эмулированных инструкций

.......................................................................................................................................................... 131Подготовка файла dumped.exe к восстановлению секции ресурсов

.......................................................................................................................................................... 134Восстановление секции ресурсов .rsrc

.......................................................................................................................................................... 135Дампирование секции JCLDEBUG

.......................................................................................................................................................... 136Запуск полученного дампа программы

................................................................................................................................... 1372 Распаковка программы LanAgent v3.0.0.0

.......................................................................................................................................................... 137Определение протектора и языка программирования

.......................................................................................................................................................... 138Определение опций защиты программы

.......................................................................................................................................................... 139Восстановление таблицы INIT

.......................................................................................................................................................... 140Восстановление таблицы IAT и вызовов эмулированных APIs

.......................................................................................................................................................... 141Устранение проверок целостности кода CRC) программы

.......................................................................................................................................................... 141Эмуляция APIs Asprotect, вызываемых из кода программы

.......................................................................................................................................................... 141Восстановление секции импорта в распакованной программе

.......................................................................................................................................................... 142Поиск областей со Stolen Code и восстановление в них эмулированных инструкций

.......................................................................................................................................................... 143Перенос области SBOEP на место секции файла .rsrc

.......................................................................................................................................................... 143Подготовка файла dumped.exe к его сборке

.......................................................................................................................................................... 146Прикручивание секции с украденным кодом к файлу dumped.exe

.......................................................................................................................................................... 147Восстановление секции ресурсов .rsrc

.......................................................................................................................................................... 149Переадресация прыжков из кода программы на секцию с украденным кодом .aspr

.......................................................................................................................................................... 150Очистка мусорного кода в секции файла с украденным кодом .aspr

.......................................................................................................................................................... 150Выявление причины появления ошибки при запуске распакованной программы

................................................................................................................................... 1523 Распаковка программы Asprotect v2.5 SKE build 04.08 Demo

.......................................................................................................................................................... 153Определение протектора и языка программирования

.......................................................................................................................................................... 154Определение опций защиты программы

.......................................................................................................................................................... 155Восстановление таблицы INIT

.......................................................................................................................................................... 156Получение файла Asprotect.dll

.......................................................................................................................................................... 157Получение таблиц соответствия для корректировки VM

.......................................................................................................................................................... 160Корректировка кода VM для восстановления подпрограмм с эмулированными инструкциями

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

.......................................................................................................................................................... 162Эмуляция APIs Asprotect, вызываемых из кода программы

.......................................................................................................................................................... 162Устранение проверок целостности кода программы

.......................................................................................................................................................... 162Восстановление секции импорта программы

.......................................................................................................................................................... 163Поиск областей со Stolen Code и восстановление в них эмулированных инструкций

.......................................................................................................................................................... 164Перенос области SBOEP на место секции файла .rsrc

.......................................................................................................................................................... 165Подготовка файла dumped.exe к его сборке

.......................................................................................................................................................... 167Прикручивание секции с украденным кодом к файлу dumped.exe

.......................................................................................................................................................... 168Восстановление секции ресурсов .rsrc

.......................................................................................................................................................... 170Переадресация прыжков из кода программы на секцию с украденным кодом .aspr

Part IV Эпилог 173

Page 6: распаковка Asprotect

Распаковка программ, защищенных Asprotect6

© <2009> <Некрылов Валентин>

Index 0

Page 7: распаковка Asprotect

Foreword

This is just another title pageplaced between table of contents

and topics

7Foreword

© <2009> <Некрылов Валентин>

Page 8: распаковка Asprotect

Top Level IntroThis page is printed before a new

top-level chapter starts

Part

I

Page 9: распаковка Asprotect

Введение 9

© <2009> <Некрылов Валентин>

1 Введение

Прошло более полугода с того времени, когда я на форуме CRACKL@B выложилцикл статей по распаковке программ, упакованных протектором ASProtect. В этихстатьях был описан процесс распаковки программ, упакованной этим протектором, атакже к ним был приложен комплект скриптов, который, собственно говоря, ивыполнял процесс распаковки программы. За это время разработчики выложилиновые версии протектора ASProtect – 1.51 build 09.22 и 2.51 SKE build 09.22(сентябрь 2009 г.). Кроме того, за это время я получил много вопросов по разнымаспектам распаковки программ, упакованных Asprotect, замечания по работескриптов, да и сам распаковал немало программ, упакованных этим протектором.Поэтому я решил подготовить второй выпуск цикла статей. Можно было бы, конечно,сделать небольшие примечания к предыдущему циклу статей, чтобы сократить объемизлагаемого материала, но немного подумав, я пришел к выводу о том, чтоповторение – это мать учения, и лучше всего сделать полный цикл статей, хотя он, вомногом, будет повторяться с предыдущим изложенным материалом. Кроме того, ктовпервые столкнется с этим циклом статей, не будет лихорадочно искать, а где можнодостать первый цикл статей.

И еще одно. Разработанные скрипты для распаковки программ, защищенныхAsprotect, тестировались мной на нескольких десятках программ. Я уже считал, чтоони будут работать везде, без каких-либо сбоев. И, когда уже была готова к отправкеэта часть статьи, мне попалась программа, на которой не сработал скрипт длявосстановления эмулированных инструкций в областях памяти со Stolen Code. Яначал разбираться с причиной этого сбоя и нашел тот случай, о котором даже и неподозревал. Дело в том, чтобы скрипт случайно не затер нужный код кодомвосстановленных инструкций, я предусмотрел в скрипте смещение от началасвободного места на 20h байтов. А в этой программе оказалось, что имеетсясвободного места в конце области памяти со Stolen Code только 0Ah байтов.Естественно, что скрипт, при прибавлении 20h байтов к найденному адресусвободного места, вычислил адрес за пределами области памяти со Stolen Code(которой там нет). И, естественно, произошел сбой в работе прививки. Мне пришлосьвводить проверку наличия не менее 20h байтов свободного места в два скрипта: длявосстановления эмулированных инструкций в областях памяти со Stolen Code, и дляпереноса областей памяти со Stolen Code на место секций файла .rsrc или .adata.Поэтому, если произошел сбой в работе какого-либо скрипта, нужно найти причинуэтого сбоя, и сделать соответствующие корректировки, поскольку они, как правило,небольшие.

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

Page 10: распаковка Asprotect

Распаковка программ, защищенных Asprotect10

© <2009> <Некрылов Валентин>

выполнения определенных процедур для распаковки программы.

Как известно, протектор выполняет многоуровневую защиту программ:

- протектор может защищать Оригинальную точку входа программы (OEP) путемвыполнения части кода в специальной области памяти (Stolen Bytes OEP, илиSBOEP);- может быть защищена таблица импорта (IAT) путем применения специальныхподпрограмм, которые определяют, какие APIs эмулированы протектором, ивыполняют часть кода этих APIs в специальных областях памяти программы;- в программах, написанных на Delphi, протектор шифрует таблицу инициализациипрограммы (INIT), которую выполняет, по мере необходимости;- шифрует часть кода программы, и выполняет эти зашифрованные части кода вспециальных областях памяти протектора;- применяет эмуляцию кода целых подпрограмм, и эмулированные инструкциивыполняет в специальных подпрограммах. Как правило, разработчики программприменяют эту опцию для зашифровки подпрограмм, связанных с регистрациейпрограммы, что значительно затрудняет процесс определения корректногорегистрационного кода.

Короче говоря, протектор делает множество гадостей, которые значительноусложняют жизнь cracker's.

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

Автор данного туториала - vnekrilov (НекрыловВалентин)

e-mail: [email protected]

Page 11: распаковка Asprotect

Top Level IntroThis page is printed before a new

top-level chapter starts

Part

II

Page 12: распаковка Asprotect

Распаковка программ, защищенных Asprotect12

© <2009> <Некрылов Валентин>

2 Распаковка программ, защищенных Asprotect

Этот материал разделен на две части. В первой части показаны основные действия,которые нужно выполнить при распаковке программ, защищенных Asprotect. Во второйчасти рассмотрены примеры распаковки конкретных программ, защищенных Asprotect.

Программа для распаковки: ASProtect SKE v2.51 build 09.22Описание программы: Пакер/Протектор исполняемых файловИнструменты: OllyDbg 1.10, PhantOm v1.54, PEiD v0.95, PE Tools

v1.8.800.2006 RC7, Hex Workshop v5.00.2511, PluginOdbgScript v1.78.1, Import REConstructor v1.6 F, DiE v0.64 byHellsp@wn, Resource Binder v3.1

Сложность: Для опытных crackersЗащита: ASProtect SKE v2.51 build 09.22Цель: Распаковка программ, упакованных ASProtect

2.1 Определение версии протектора и компилятора

Перед распаковкой программы всегда нужно выяснять версию протектора икомпилятора программы, поскольку по этим параметрам можно определитьнаправление дальнейшей работы. Так, например, если программа скомпилированакомпилятором Delphi, то в ней, как правило, будет закриптована таблицаинициализации программы (INIT), которую нам нужно раскриптовать на ее родноеместо в программе. Программы, скомпилированные на C/C++, не имеют таблицы инициализации, поэтому работа по восстановлению таблицы INIT не выполняется.

Для выяснения, упакована ли программа, или нет, можно использовать анализаторыфайлов PEiD v0.95, DiE v0.64 или RDG Packer Detector v0.6.6. Вообще имеетсябольшое число всяки анализаторов файлов, но, на мой взгляд, достаточноиспользовать эти три анализатора файлов.

Сначала проанализируем программу в PEiD v0.95.

Page 13: распаковка Asprotect

Распаковка программ, защищенных Asprotect 13

© <2009> <Некрылов Валентин>

Как видим, программа упакована ASProtect 1.2x - 1.3x [Registered]. Попробуемуточнить версию пакера, для чего применим прекраснейшую утилиту ASPrINF v1.6Beta:

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

Поскольку нами определен пакер, которым защищена анализируемая программа, намосталось определить компилятор, которым скомпилирована программа. Для этихцелей будем использовать утилиту DiE v0.64:

Page 14: распаковка Asprotect

Распаковка программ, защищенных Asprotect14

© <2009> <Некрылов Валентин>

И, наконец, проанализируем программу в RDG Packer Detector v0.6.6:

Как видим, анализ файла в анализаторах DiE v0.64 или RDG Packer Detector v0.6.6позволил нам определить компилятор, которым скомпилирована исследуемаяпрограмма – это Borland Delphi. Поскольку программы, скомпилированные этимкомпилятором, имеют таблицу INIT, то, со значительной степенью вероятности,можно предположить, что пакер закриптовал эту таблицу, и нам придется еевосстанавливать.

2.2 Конфигурация отладчика и плагинов

Перед загрузкой программы в отладчик OllyDbg v1.10, нужно предварительновыполнить его конфигурацию на вкладке “Исключения”:

Page 15: распаковка Asprotect

Распаковка программ, защищенных Asprotect 15

© <2009> <Некрылов Валентин>

И, также сконфигурировать plugin PhantOm v1.54:

Page 16: распаковка Asprotect

Распаковка программ, защищенных Asprotect16

© <2009> <Некрылов Валентин>

2.3 Поиск OEP (SBOEP)

Итак, загружаем программу в отладчик:

Это – традиционная точка входа программ, упакованных Asprotect. ИнструкцияPUSH 5C5001 отсылает нас в предпоследнюю секцию файла .data, которая содержитв упакованном виде код программы, код Asprotect.dll, и все данные (которыехранятся в массивах), необходимые для распаковки программы в память компьютера.

Имеется много статей разных авторов (в том числе и мои статьи), в которыхподробно описывается процесс распаковки программы в память компьютера,поэтому я не буду здесь повторять все то, что было написано раньше. Здесь я хочутолько отметить, что самой первой распаковывается Asprotect.dll, которая управляетпроцессом дальнейшей распаковки программы в память компьютера, обеспечивая еекорректную работу. И еще одно! Несмотря на большое число версий данногопротектора, Asprotect.dll практически не меняется от версии к версии, что позволяетзначительно облегчить процесс распаковки программ, упакованных разнымиверсиями Asprotect. О незначительных отличиях разных версий Asprotect.dll будетуказано в соответствующих разделах данной статьи.

Остановка программы на коде Asprotect.dll

Итак, как указал выше, процессом распаковки программы управляет Asprotect.dll,поэтому нашей задачей является, при запуске программы в отладчике, остановитьвыполнение программы после распаковки Asprotect.dll в память компьютера.Конечно, можно идти по циклам распаковки, как это описано в статьях разныхавторов (в том числе и моих статьях), однако можно и значительно упростить этотпроцесс, используя следующий прием. Asprotect.dll – это библиотека, которая имеетвсе секции, присущие библиотекам .dll, т.е. секции кода, импорта, экспорта, и т.д.(кроме PE-заголовка, который обычно имеет виртуальный размер в 1000h байтов).Место заголовка этой библиотеки Asprotect.dll в памяти компьютера заполненонолями (хотя некоторые разработчики программ используют эти 1000h байтов кодадля записи начального кода программы, и размещают библиотеку Asprotect.dll впредпоследней секции файла). Как и любая программа, при своем запуске, Asprotect.dll вызывает API GetSystemTime из kernel32.dll, и вызов этой API можноиспользовать для остановки программы в области кода Asprotect.dll:

Page 17: распаковка Asprotect

Распаковка программ, защищенных Asprotect 17

© <2009> <Некрылов Валентин>

Как видно из приведенного рисунка, после выполнения API GetSystemTime, мыпопадаем в область кода Asprotect.dll. Точка входа Asprotect.dll имеет следующийвид:

На нее можно пройти, нажав несколько раз клавиши Ctrl+F9, после остановкипрограммы на выполнении API GetSystemTime.

Когда программа остановилась на коде Asprotect.dll после выполнения APIGetSystemTime, то еще не выполнена распаковка кода программы, таблиц IAT иINIT, и других частей кода программы. Поэтому, мы можем, проходя насоответствующие подпрограммы в Asprotect.dll, управлять процессом распаковкикода программы в память компьютера таким образом, чтобы получить кодпрограммы, достаточный для выполнения рабочего дампа памяти программы.Программа полностью распакована в память компьютера, когда она остановлена наOEP или SBOEP, поэтому нам надо сначала определиться, сворована ли пакеромчасть кода из области OEP, или нет. Для этого нам нужно пройти на OEPпрограммы, и определить, что мы здесь имеем – OEP или SBOEP.

Прохождение на OEP – SBOEP программы

Как я уже писал выше, Asprotect.dll не сильно отличается в разных версияхпротектора, поэтому имеются некоторые волшебные точки, одинаковые для всехверсий Asprotect.dll, и которые можно использовать для поиска OEP или SBOEPпрограммы. Одной из таких волшебных точек является следующий код:

Page 18: распаковка Asprotect

Распаковка программ, защищенных Asprotect18

© <2009> <Некрылов Валентин>

Адрес 00CB1CB8 – это очень интересный адрес. В нем записан адрес SBOEPпрограммы (если пакер своровал часть кода из OEP программы), и в этом адресезаписаны 00000000, если разработчик программы не защитил OEP своей программы.Этот участок кода Asprotect.dll можно легко найти, выполнив поиск инструкцииMOV BYTE PTR DS:[EAX],0E1:

Следует отметить, что в некоторых версиях Asprotect.dll (например, версии 1.32),применяется инструкция - MOV DWORD PTR DS:[EAX],0E1.

Различие этих двух инструкций заключается только в размерах операндов – BYTEили DWORD.

А затем, начиная от предыдущей найденной инструкции, нам надо найти следующиедве инструкции:

00C9FFA3 A1 B81CCB00 MOV EAX,DWORD PTR DS:[CB1CB8]

00C9FFA8 894424 04 MOV DWORD PTR DS:[ESP+4],EAX

Page 19: распаковка Asprotect

Распаковка программ, защищенных Asprotect 19

© <2009> <Некрылов Валентин>

Поскольку адреса констант и регистров в разных программах будут разными, топоиск этого места выполняем по маске “A1????????894?”.

Обратите внимание на то, что при поиске этих двух инструкций, необходимо снятьфлажок с опции “Весь блок”.

Наличие этой волшебной точки позволяет написать скрипт, который сам находитOEP (SBOEP) на любой программе, упакованной Asprotect.

Фактически скрипт должен сделать следующее:1. Пройти на адрес API GetSystemTime на нашей машине.2. Найти инструкцию MOV BYTE PTR DS:[EAX],0E1 (или MOV DWORD PTR

DS:[EAX],0E1).3. Найти инструкцию MOV EAX,DWORD PTR DS:[CB1CB8]. 4. Запустить программу до этой инструкции, и прочитать значение SBOEP.

Разработанный мной скрипт “Поиск OEP (SBOEP).osc” построен на этой логикеработы. Однако он снабжен рядом дополнительных функций, которые позволяюттакже определить основные опции защиты, которые использовал программист длязащиты разработанной им программы. Это позволяет, на самом первомпредварительном анализе защищенной программы, определить, с чем нам придетсяработать.

И здесь я не могу не сказать о том, что разработчики протектора весьма ревнивоотносятся к защите кода Asprotect.dll, встраивая в него несколько проверок егоцелостности (CRC). Так, например, если мы установим обычную BreakPoint наадрес инструкции MOV BYTE PTR DS:[EAX],0E1, и попытаемся запуститьпрограмму, то получим следующее сообщение:

Page 20: распаковка Asprotect

Распаковка программ, защищенных Asprotect20

© <2009> <Некрылов Валентин>

И таких проверок в коде Asprotect.dll, имеется достаточно много. Поэтому однипроверки приходится обходить, используя Hardware BreakPoint вместо обычныхBreakPoint, другие проверки приходится обходить путем принудительного переносарегистра EIP на необходимый адрес программы. А третьи проверки приходитсяобходить путем принудительной перезаписи имеющегося контрольного значения нанужное контрольное значение.

Все это можно посмотреть в комментариях к скрипту “Поиск OEP (SBOEP).osc”,который приложен к данной статье. По предложению r-e я вырезал частькомментариев, которые загромождают скрипт, и оставил только основныекомментарии, которых вполне достаточно для того, чтобы понять логику работыскрипта, и позволяют, в случае необходимости, быстро найти причины сбоев егоработы. Просматривать этот скрипт лучше всего в редакторе скриптов Olly DebuggerScript Editor v1.2 от Guru.exe, или используя редактор скриптов OllySubScript v1.4.1by Sub Xero (мне больше понравился этот редактор скриптов).

Запустив этот скрипт, мы довольно быстро оказываемся здесь:

Как видим, в этой программе мы остановились на SBOEP. А это означает, чтовполне возможно, программист защитил свою программу, используя криптованиетаблицы INIT, переадресацию импорта, и, вполне вероятно, весь набор гадостей,которые предоставляет этот протектор.

Page 21: распаковка Asprotect

Распаковка программ, защищенных Asprotect 21

© <2009> <Некрылов Валентин>

На этом рисунке приведен результат работы скрипта при прохождении на OEPпрограммы, у которой не защищена оригинальная точка входа. Если мы посмотримна “волшебную” область кода, то увидим следующее:

Как видим, по интересующему нас адресу записаны ноли, что указывает нанезащищенность протектором OEP программы.

Приложение: Скрипт для прохода на OEP (SBOEP) программы - “Поиск OEP(SBOEP).osc”

PS. Я хотел бы поблагодарить r-e за его ценные замечания по изменению текстаскриптов, которые помогли сделать их более наглядными, и удобными в работе.

2.4 Восстановление таблицы INIT

Если программа написана на Borland Delphi, то она имеет так называемую таблицуинициализации (таблица INIT), которая содержит адреса подпрограмм,выполняемых при запуске программы. Протектор Asprotect полностью шифруеттаблицу INIT, и выполняет ее в специально выделенной области памяти, а область вкоде программы, где раньше находилась эта таблица, протектор заполняет мусорнымкодом.

Давайте немного подробнее рассмотрим таблицу INIT. Если мы посмотрим на EntryPoint (EP) неупакованной программы, написанной на Borland Delphi, то увидимследующее:

Page 22: распаковка Asprotect

Распаковка программ, защищенных Asprotect22

© <2009> <Некрылов Валентин>

На рисунке стрелкой показан адрес расположения таблицы INIT в программе. Нанижнем рисунке приведен фрагмент таблицы INIT:

Красным цветом выделено число подпрограмм, содержащихся в этой таблице INIT (112h), Желтым цветом выделен указатель на адрес первой подпрограммы таблицыINIT, Ярко-зеленым цветом выделены адреса подпрограмм инициализации, иБирюзовым цветом выделены адреса подпрограмм деинициализации.

А теперь давайте посмотрим на таблицу INIT упакованной программы. Там мывидим следующее:

Здесь мы видим, что вместо числа подпрограмм, содержащихся в этой таблице INIT,записано значение 01h (выделено Красным цветом), Желтым цветом выделенуказатель на адрес подпрограмм CALL, в которых выполняются закриптованныеподпрограммы инициализации (выделена Ярко-зеленым цветом), идеинициализации (выделена Бирюзовым цветом). Остальная же часть таблицы INITзаполнена мусорным кодом.

Очевидно, что таблицу INIT лучше всего восстанавливать до восстановления

Page 23: распаковка Asprotect

Распаковка программ, защищенных Asprotect 23

© <2009> <Некрылов Валентин>

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

Уже с первой части данного цикла статей можно предположить, что и здесь можнонайти волшебный код, который позволит нам восстановить таблицу INIT,закриптованную протектором Asprotect. Во всех версиях Asprotect.dll имеется одноочень интересное место, которое находится чуть выше кода ошибки “60”:

На рисунке Красным цветом выделена та волшебная точка, которая определяет,закриптована ли таблица INIT, или нет. Если таблица INIT закриптованапротектором, то условный прыжок “JE XXXXXXXX” не выполняется (значениефлажка Z равно 0), и это означает, что нам надо будет восстанавливать таблицу INIT.А выполнив инструкцию CALL 00BDABD0, расположенную на адресе 00BDD8F4,можно получить все данные, которые необходимы для восстановления таблицыINIT.

Если же таблица INIT не закриптована, или она отсутствует (для программ,написанных на других языках программирования), значение флажка Z равно 1,выполняется условный прыжок JE SHORT 00BDD907, и пропускается выполнениеинструкции CALL 00BDABD0.

Естественно, что для поиска этой волшебной точки нужно использовать строкуASCII “60”, которая, как я отметил выше, имеется во всех версиях Asprotect.dll.

Все данные, которые необходимы для получения адреса подпрограммы, котораянаходится в таблице INIT, протектор хранит в массиве данных, выполненном в видедвух таблиц – Таблицы А и Таблицы В.

Page 24: распаковка Asprotect

Распаковка программ, защищенных Asprotect24

© <2009> <Некрылов Валентин>

Таблица А имеет следующий вид:

Протектор под эту таблицу выделяет отдельную область памяти, в нашей случае –02020000.

А Таблица В выглядит так:

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

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

Обратите внимание на то, что все эти области памяти идут подряд: 02020000,02030000 и 02040000. И именно в этой области памяти находится инструкция CALLREG, которая и выполняет раскриптованную подпрограмму:

Page 25: распаковка Asprotect

Распаковка программ, защищенных Asprotect 25

© <2009> <Некрылов Валентин>

В качестве REG может быть любой регистр: EAX, ECX, и т.д. Очевидно, что в этойобласти памяти нельзя устанавливать программные BreakPoint и изменять код,поскольку это приведет к неверным результатам при подсчете байтов в этой областипамяти, и, соответственно, к сбою программы. Единственно, что здесь можно делать– это устанавливать Hardware BreakPoint. Именно на этом принципе и былпостроен скрипт для восстановления таблицы INIT, описанный в первом выпускеданного цикла статей.

Однако этот скрипт работает медленно, и требуется несколько минут, чтобывосстановить таблицу INIT. VolX в своих скриптах предложил более лучшийвариант – это предварительно, с помощью специальной прививки, вычислить хэшкаждой подпрограммы таблицы INIT, используя данные, находящиеся в таблицах Аи В. При вычислении хэшей, естественно, используется область памяти, где записанCALL REG. Вычисленные хэши записываются в специально выделенную областьпамяти, и затем, с помощью константы, имеющейся в области памяти CALL REG,раскриптовываются адреса подпрограмм, которые были записаны в оригинальнойтаблице INIT. Теперь здесь можно изменять код, дописывать свой код, и делать сним любые действия, какие мы пожелаем. Эти изменения уже не будут влиять нарезультаты нашей работы.

Если мы возьмем, например, самые первые данные из таблиц А и В, и вычтем иззначения таблицы B значение таблицы A, то получим следующий результат:

7383E5FF - 7383E2EE = 00000311

А если к этому результату мы прибавим ImageBase области памяти, где находитсяCALL REG, то получим следующий результат:

00000311 + 02040000 = 02040311

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

Далее обнуляется регистр EAX, и из него вычисляются первые 4 байта, находящиесяв начале области памяти, где находится CALL REG:

00000000 - 02EBF352 = FD140CAE

Page 26: распаковка Asprotect

Распаковка программ, защищенных Asprotect26

© <2009> <Некрылов Валентин>

Затем из этой области памяти мы берем очередные 4 байта, на которые указываетзначение смещения выборки, и вычитаем их из полученного значения регистра EAX:

FD140CAE - CD02EBF3 = 301120BB

Этот цикл вычислений продолжается до тех пор, пока не будет достигнут нижнийпорог области памяти для этой подпрограммы таблицы INIT – 02040311. Когдадостигнут этот порог, то к вычисленному значению регистра EAX прибавляетсязначение из таблицы А, и мы получаем хэш первой подпрограммы из таблицы INIT:

8CFE4BBA + 7383E2EE = 00822EA8

Вычисленные хэши подпрограмм таблицы INIT, после выполнения кода прививки,выглядит так:

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

Для раскриптовки значения хэша используются три константы - C1FF0493,C281A541 и 4E. Сам процесс раскриптовки выглядит следующим образом:

00822EA8 + C1FF0493 = C281333B

C281333B - C281A541 = FFFF8DFA

1 - FFFF8DFA = 00007206

00007206 + 4E = 00007254

А теперь, если мы прибавим к вычисленному значению ImageBase программы00400000, то получим требуемый адрес подпрограммы из таблицы INIT:

00007254 + 00400000 = 00407254

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

Page 27: распаковка Asprotect

Распаковка программ, защищенных Asprotect 27

© <2009> <Некрылов Валентин>

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

К этой части статьи мной приложен скрипт “Восстановление таблицы INIT.osc”. Ксожалению, этот скрипт получился достаточно большим по размеру, посколькузначительный объем занимает вычисление инструкций, находящихся после CALLREG, и которые мы должны перенести в область кода прививки. Дело заключается втом, что мы должны на месте инструкции CALL REG записать безусловный прыжокв прививку, который имеет размер 5h байтов. Инструкция CALL REG имеет размер2h байта, и нам надо занять еще три байта у инструкций, расположенных нижеинструкции CALL REG. Но поскольку ниже этой инструкции расположен мусорныйкод, который все время меняется, при каждой перезагрузке программы, топриходится в скрипте учитывать все эти изменения.

Однако полученный скрипт работает очень быстро, и полностью восстанавливаеттаблицу INIT во всех версиях Asprotect.dll. Восстановленная таблица INIT можетбыть вставлена на свое родное место, после восстановления таблицы импорта (IAT)и переадресованных вызовов APIs, перед дампированием памяти программы.Однако восстановленную таблицу INIT можно вставить на ее родное место, и вполученный дамп памяти программы, что зависит только от желания cracker's.Поэтому, чтобы выполнить эту работу, нам необходимо записать, для памяти, вседанные о таблице INIT. Эти данные скрипт записывает в журнал регистрацииотладчика, при завершении своей работы, в следующем виде:

Дамп таблицы INIT скрипт сохраняет с именем “table_INIT.bin”, который находитсяв той же папке, где находится и упакованная программа.

Если мы посмотрим на таблицу INIT после работы скрипта, то увидим следующее:

Page 28: распаковка Asprotect

Распаковка программ, защищенных Asprotect28

© <2009> <Некрылов Валентин>

На рисунке мы видим полностью восстановленную таблицу INIT, враспаковываемом файле.

Приложение: Скрипт для восстановления таблицы INIT программы - “Восстановление таблицы INIT.osc”.

2.5 Восстановление таблицы IAT

В этой части мы рассмотрим восстановление таблицы IAT и инструкций вызововэмулируемых APIs. Но, предварительно, рассмотрим немного теории. Все функции изразных DLL, которые нужны для работы программы, компиляторы собирают в одномместе, и это место называется Таблицей Импортируемых Адресов, или простоТаблицей IAT. Если мы посмотрим на на таблицу IAT какого-либо не упакованногофайла, то там увидим следующее (для примера я взял программу DeDe, котораянаписана на Borland Delphi):

А если мы изменим формат отображения, то это место будет выглядеть так:

Здесь мы видим функции из двух библиотек – ntdll.dll и kernel32.dll, адреса которыхпривязаны к конкретной (моей) машине. Т.е., в каждой ячейке этой таблицы IATзаписан адрес используемых программой APIs, на нашей машине.

Page 29: распаковка Asprotect

Распаковка программ, защищенных Asprotect 29

© <2009> <Некрылов Валентин>

А если мы немного прокрутим код вверх, в самое начало этой области памяти, тоувидим так называемую Import Table (Таблицу Импорта):

На этом рисунке я разными цветами выделил данные для разных библиотек,используемых программой DeDe. Некоторые пользователи путают эти два понятия -Таблица IAT и Таблица Импорта. Ссылка на Таблицу Импорта имеется в PE-заголовке файла, а вот на таблицу IAT ссылок в PE-заголовке файла - нет, но на неекак раз имеются ссылки в Таблице Импорта. Кстати, на каждую библиотеку вТаблице Импорта отводится место в 14h байтов.

Теперь давайте рассмотрим, а что означают два значения, которые находятся вТаблице Импорта для каждой библиотеки. Возьмем, к примеру, первую библиотеку,которая выделена Ярко-зеленым цветом:

На этом рисунке Красным цветом выделен адрес, который указывает на то место, гдезаписано имя библиотеки, а Вишневым цветом выделен первый адрес в таблице IAT, в котором записаны адреса APIs из этой библиотеки на нашей машине. (Здесьзаписаны значения VirtualOffset этих адресов, а чтобы получить значенияVirtualAddress, к значениям VirtualOffset надо прибавить значение ImageBaseпрограммы). Давайте перейдем на адрес 005B1A28 (VirtualOffset = 001B1A28):

На этом рисунке Розовым цветом выделен последний адрес API в таблице IAT,Желтым цветом – разделительные ноли в конце таблицы IAT, Бирюзовым цветом –имя DLL (kernel32.dll), Золотистым цветом – имена APIs, которые входят в этубиблиотеку, и Сиреневым цветом – адрес из Таблицы Импорта.

А теперь давайте перейдем на адрес 005B11B8 (VirtualOffset = 001B11B8):

Page 30: распаковка Asprotect

Распаковка программ, защищенных Asprotect30

© <2009> <Некрылов Валентин>

На этом рисунке Бирюзовым цветом выделены последние 14h байтов ТаблицыИмпорта, которые заполнены нолями. И поскольку программа скомпилирована наBorland Delphi, то после Таблицы Импорта идет Таблица IAT. Ярко-зеленымцветом выделена область таблицы IAT, которая содержит адреса APIs из библиотеки kernel32.dll, и Сиреневым цветом – адрес из Таблицы Импорта.

А если мы посмотрим на это место в исполняемом файле, то увидим следующее:

На нем вместо адресов APIs на нашей машине мы видим VirtualOffset на их имена. Анемного ниже мы видим:

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

Таким образом, в программах, написанных на Borland Delphi, импорт APIsорганизован следующим образом:- сначала идет таблица Импорта;- затем идет таблица IAT;- и после нее расположена область с именами DLLs и APIs.

Поэтому компилятор Borland Delphi выделяет для импорта APIs отдельную секциюфайла, которую он называет .idata.

Немного иначе организован импорт в программах, написанных, например, наMicrosoft Visual C++ | C/C++. Так, например, в файле Mtk_Res1.4.exe, таблица IATрасположена в начале секции .rdata:

Page 31: распаковка Asprotect

Распаковка программ, защищенных Asprotect 31

© <2009> <Некрылов Валентин>

Таблица Импорта расположена в этой же секции файла, но намного ниже таблицыIAT:

На этом рисунке Ярко-зеленым и Бирюзовым цветами выделены блок данных втаблице Импорта о первых двух DLLs, используемых этой программой.

Конец таблицы Импорта выделен Сиреневым цветом. Затем идет блок указателей на Original First Thunk, а уже после блока этих указателей, идет область с именамиDLLs и APIs:

Здесь, как мы видим, таблица Импорта немного отличается от таблицы Импортапрограмм, написанных на Borland Delphi. Эта таблица вначале содержит указательOriginal First Thunk, который в свою очередь указывает на параметр Hint,находящийся перед именем API:

Page 32: распаковка Asprotect

Распаковка программ, защищенных Asprotect32

© <2009> <Некрылов Валентин>

На этом рисунке Красным цветом выделен параметр Hint, а Бирюзовым цветом –имя API.

Таким образом, в программах, написанных на Microsoft Visual C++ | C/C++, импортAPIs организован следующим образом:- сначала идет таблица IAT;- затем идет код программы;- далее идет таблица Импорта;- за ней идет блок указателей на Hint;- и после этого блока указателей расположена область с именами DLLs и APIs.

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

В программах, скомпилированных другими компиляторами, таблица IAT и таблицаИмпорта могут находиться в разных секциях файла, но принципы их построенияобусловлены требованиями к формату PE-файлов, и поэтому они одинаковы.

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

Теперь перейдем к нашей теме – восстановление таблицы IAT в программах,защищенных Asprotect. Для выполнения этой работы, нам надо выяснить, какимобразом ASProtect заполняет таблицу IAT адресами APIs.

Если мы пройдем на OEP (SBOEP) программы, упакованной ASProtect, и посмотримна таблицу импорта (IAT), то увидим там следующее:

На этом рисунке мы видим поврежденную протектором таблицу IAT.

Page 33: распаковка Asprotect

Распаковка программ, защищенных Asprotect 33

© <2009> <Некрылов Валентин>

Разделительные ноли перед началом таблицы IAT выделены Розовым цветом;Бирюзовым цветом выделены APIs, которые принадлежат первой DLL (kernel32.dll), Желтым цветом выделены APIs, которые принадлежат второй DLL (user32.dll).Разделительные ноли между этими DLL выделены Зеленым цветом, а Сиреневымцветом выделены эмулируемые APIs, реальные адреса которых заполнены мусорнымкодом. Адрес начала таблицы IAT выделен Золотистым цветом.

Давайте кратко рассмотрим процесс заполнения таблицы IAT. Как известно, призапуске программы, протектор Asprotect распаковывает код программы и таблицуимпорта (IAT) с помощью Asprotect.dll.

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

Давайте теперь посмотрим на массив данных, который содержит информацию,необходимую для заполнения таблицы IAT. Этот массив содержит закриптованныеимена всех APIs, которые используются в данной программе, причем APIs в этойтаблице сгруппированы по соответствующим DLLs, в которых находятся эти APIs.Фрагмент такого массива данных приведен на следующем рисунке:

На этом рисунке Бирюзовым цветом выделен размер всего массива данных о таблице IAT, Серым цветом выделены указатели на типы закриптовки имен APIs,применяемые в этом массиве данных. Ярко-зеленым цветом выделен адрес таблицыIAT, по которому должна находиться первая API (этот адрес часто является началомтаблицы IAT, но не всегда). Сиреневым цветом выделен размер данных для первойDLL, затем идут два байта, которые идентифицируют конкретную DLL в массиведанных, и они выделены Розовым цветом. За этими двумя байтами идет незакриптованное имя DLL, которое выделено Золотистым цветом. И, наконец,Коричнево-зеленым цветом выделено закриптованное имя первой API.

Теперь давайте посмотрим на закриптованное имя API:

Page 34: распаковка Asprotect

Распаковка программ, защищенных Asprotect34

© <2009> <Некрылов Валентин>

На этом рисунке Коричнево-зеленым цветом выделен тип закриптовки имени API,Красным цветом выделен уникальный идентификатор закриптованной API, Ярко-зеленым цветом выделен размер закриптованного имени API, и Бирюзовым цветомвыделено само закриптованное имя API.

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

Теперь нам надо определить ту волшебную точку, которая позволит нам заполнитьтаблицу IAT фактическими адресами APIs на нашей машине. Посколькуподпрограмма заполнения таблицы IAT адресами APIs практически не меняется вразных версиях Asprotect.dll, то такой волшебной точкой является следующий адрес:

Этот адрес легко находится по байтам опкода инструкций "INC EAX", "MOVDWORD PTR DS:[EBX],EAX" и "ADD EDI,4", расположенных в подпрограммезаполнения таблицы IAT адресами APIs.

Подпрограмма заполнения таблицы IAT адресами APIs является одинаковой для всехверсий Asprotect.dll, за исключением версии 1.32, поскольку в версии 1.32используется другая строка константы для раскриптовки закриптованных имен APIs.Это отличие используется для указания необходимого кода прививки, применяемойдля раскриптовки закриптованных имен эмулируемых APIs, что видно наприведенном фрагменте скрипта для восстановления таблицы IAT:

Следует отметить, что разработчики этого протектора много внимания уделяютвыявлению нарушений целостности кода программы, и встроили в Asprotect.dllмного ловушек, которые не позволяют восстановить таблицу IAT. Здесь я хочу

Page 35: распаковка Asprotect

Распаковка программ, защищенных Asprotect 35

© <2009> <Некрылов Валентин>

показать эти ловушки:

1-я ловушка (в некоторых версиях, протектор дважды использует этот вид ловушки):

На этом рисунке сравнивается значение регистра EAX с заданным контрольнымзначением, после чего выполняется или не выполняется условный прыжок. Намнадо, чтобы этот прыжок выполнялся всегда, поэтому скрипт меняет условныйпрыжок JE SHORT 00F064B0 на безусловный прыжок JMP SHORT 00F064B0, апосле восстановления таблицы IAT, он все возвращает назад условный прыжок JESHORT 00F064B0.

2-я ловушка:

При восстановленной таблице IAT (при этом даже не затронуты вызовыэмулированных APIs), в регистре ESI появляется значение, отличное от ноля,условный прыжок JE SHORT 00F1008B не выполняется, и мы получаемтрадиционное сообщение о повреждении программы. Здесь решение заключается впринудительном обнулении регистра ESI, что и делает скрипт.

Устранение этих двух проверок позволяет нормально запуститься программе свосстановленной таблицей IAT и восстановленными вызовами эмулированныхAPIs.

И еще один момент. Для работы протектора нужны APIs RaiseException иGetProcAddress. Эти APIs протектор также эмулирует, но очень хитро, и, например,эмулированная API RaiseException выглядит так:

Page 36: распаковка Asprotect

Распаковка программ, защищенных Asprotect36

© <2009> <Некрылов Валентин>

Найти адреса расположения эмулированных APIs RaiseException и GetProcAddressможно легко, выполнив поиск по маске следующей цепочки байтов – “Eb01??B8????????”:

А если мы пройдем по мусорному прыжку JMP SHORT 00F06471, то увидим:

Здесь Ярко-зеленым цветом выделен адрес расположения эмулированной APIRaiseException.

Если имеется одна цепочка вышеуказанных байтов, то протектор эмулирует толькоAPI RaiseException, а если имеется две таких цепочки байтов, то протекторэмулирует обе APIs - RaiseException и GetProcAddress. Причем сначала указан адресAPI RaiseException, а затем адрес API GetProcAddress.

Я не буду здесь описывать работу скрипта по восстановлению таблицы IAT,поскольку он снабжен подробными комментариями, и не нуждается в каких-либодополнительных пояснениях. Единственное, что я хочу отметить, так это то - чтоадреса расположения всех APIs в таблице IAT, и соответствующие идентификаторыAPIs (по которым протектор определяет тип вызываемой API), скрипт заносит втаблицу, создаваемой в специально выделенной области памяти. Данные этойтаблицы используются для восстановления вызовов эмулируемых APIs, используяпри этом значения идентификаторов закриптованных APIs в массиве данных длятаблицы IAT.

Page 37: распаковка Asprotect

Распаковка программ, защищенных Asprotect 37

© <2009> <Некрылов Валентин>

На нижнем рисунке приведен предыдущий фрагмент таблицы IAT свосстановленными значениями APIs на конкретной машине:

Разделительные ноли перед началом таблицы IAT выделены Розовым цветом;Бирюзовым цветом выделены APIs, которые принадлежат первой kernel32.dll,Желтым цветом выделены APIs, которые принадлежат второй user32.dll.Разделительные ноли между DLL выделены Зеленым цветом. Адрес начала таблицыIAT выделен Золотистым цветом. Сиреневым цветом выделен адрес ссылки наобласть пакера. Как видно на рисунке, скрипт восстановил все элементы таблицыIAT.

А на следующем рисунке приведен фрагмент вспомогательной таблицы,расположенной в специально созданной области памяти, данные которойиспользуются для восстановления вызовов эмулируемых APIs, используя при этомзначения идентификаторов закриптованных APIs в массиве данных для таблицы IAT.

Эта вспомогательная таблица содержит идентификаторы закриптованныхэмулируемых APIs (выделены Ярко-зеленым цветом), и позиции этих APIs в таблице IAT (выделены Бирюзовым цветом). Еще раз хочу подчеркнуть, что данные этойвспомогательной таблицы используются только для восстановления инструкцийвызова эмулируемых APIs.

Этот скрипт также предусматривает дампирование таблицы IAT (table_IAT.bin) ивспомогательной таблицы (add_table_IAT.bin), которые могут потребоваться длякаких-либо особых случаев при распаковке программ.

Page 38: распаковка Asprotect

Распаковка программ, защищенных Asprotect38

© <2009> <Некрылов Валентин>

2.6 Восстановление вызовов эмулируемых APIs

Теперь, когда у нас имеется полностью восстановленная таблица IAT, намнеобходимо восстановить инструкции вызова тех APIs, которые я назвалэмулируемыми APIs.

Немного напомню о вызове эмулируемых APIs. Если мы пройдем на OEP (SBOEP)программы, и посмотрим, как вызываются APIs из таблицы IAT, то мы увидимследующее:

Вверху мы видим стандартный вызов API CreateFileA для программ, написанных наBorland Delphi. А ниже мы видим несколько инструкций CALL 02270000, которые иявляются инструкциями вызова эмулируемых APIs. Работу подпрограмм вызоваэмулированных APIs я подробно описывал в своих предыдущих статьях, поэтому ине буду здесь повторяться. Единственное, что хочу здесь отметить, так это действия,которые выполняет подпрограмма вызова эмулируемых APIs: - путем сложных манипуляций определяются идентификаторы эмулируемой API и

библиотеки DLL, в которой находится данная API; - по этим идентификаторам подпрограмма находит в массиве данных для таблицы

IAT закриптованное имя нужной API;- затем подпрограмма раскриптовывает имя этой API;- по раскриптованному имени определяется фактический адрес API на конкретной

машине;- выполняется эта API.

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

Page 39: распаковка Asprotect

Распаковка программ, защищенных Asprotect 39

© <2009> <Некрылов Валентин>

Здесь, вместо инструкции CALL 02270000, используется инструкция CALL 02300004. И таких разных инструкций для вызова эмулируемых APIs может быть несколько.Все это запутывает и сильно затрудняет распаковку программы.

Как я писал в предыдущих статьях, для записи инструкций вызова эмулируемых APIsв главной области кода программы, Asprotect.dll использует подпрограммуадресации, которая практически не меняется в разных версиях Asprotect.dll. Поэтомуволшебная точка находится здесь:

Эта точка легко находится по байтам опкода следующих инструкций: "MOV EAX,DWORD PTR DS:[EBX+2C]", "SUB EAX,EBP" и "SUB EAX,5".

Когда программа остановлена на инструкции “INC EBP”, в регистре EBX записанадрес массива данных, который управляет записью инструкций вызова эмулируемыхAPIs в главный код программы. Если мы посмотрим на этот массив данных, тоувидим следующее:

На этом рисунке Оранжевым цветом выделено значение ImageBase программы,Сиреневым цветом выделено число инструкций вызова эмулируемых APIs, Розовымцветом выделено значение начала области кода программы. Голубым цветомвыделено значение инструкции CALL, которая используется для вызоваэмулируемых APIs, Желтым цветом выделены значения дополнительныхинструкций CALL, используемых для определения фактических адресов APIs нанашей машине. Серым цветом выделены значения, используемые для указания

Page 40: распаковка Asprotect

Распаковка программ, защищенных Asprotect40

© <2009> <Некрылов Валентин>

адресов назначения инструкций CALL EBP и CALL EDX, которые применяются дляизвлечения значений из массива данных. И, наконец, Ярко-зеленым цветом выделенадрес начала массива данных, а Бирюзовым цветом выделен адрес конца массиваданных для вызовов эмулированных APIs, который одновременной является началоммассива данных для эмулированных инструкций, которые следуют непосредственноза инструкциями вызовов APIs (при дополнительной защите импорта). Краснымцветом выделено довольно интересное значение, которое используется для указания,выполнять ли корректировку стека при выполнении эмулированной API, или невыполнять:- это значение сравнивается со значением, имеющемся в массиве данных для

вызываемой эмулируемой API, и, если они не равны, то в инструкциях вызововAPIs используются байты опкода “FF25”, которые применяются в программах,написанных на языке Borland Delphi;

- если же эти значения равны, то в инструкциях вызовов APIs используются байтыопкода “FF15”, которые применяется в программах, написанных на других языкахпрограммирования.

И Светло-оранжевым цветом выделены идентификаторы типа эмулированныхинструкций, которые следуют непосредственно за инструкциями вызовов APIs (придополнительной защите импорта).

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

На этом рисунке Ярко-зеленым цветом здесь выделено число вызовов эмулируемыхAPIs, Желтым цветом выделено значение константы, используемой дляраскриптовки значений из массива данных, а Сиреневым цветом выделено числобайтов, которые выделены для каждой эмулируемой API. Бирюзовым цветомвыделены байты для первой эмулируемой API.

Скрипт для восстановления инструкций вызовов APIs состоит из трех прививок:- первая прививка восстанавливает инструкции CALL вызовов эмулируемых APIs

второго типа (в нашем примере - CALL 02300004);- вторая прививка восстанавливает инструкции CALL вызовов эмулируемых APIs

первого типа, адрес назначения которых указан в массиве данных для инструкцийвызовов эмулируемых APIs (в нашем примере - CALL 02270000);

- третья прививка восстанавливает код эмулированных инструкций, которыеследуют за инструкциями вызовов эмулируемых APIs (при использовании опциидополнительной защиты импорта протектора).

Page 41: распаковка Asprotect

Распаковка программ, защищенных Asprotect 41

© <2009> <Некрылов Валентин>

В качестве кода первой прививки фактически используется код подпрограммызаписи инструкций вызова эмулируемых APIs из Asprotect.dll, а в качестве кодавторой прививки используется код инструкции вызова эмулируемых APIs первоготипа вызовов. Код этих прививок доработан, чтобы можно было найтиидентификаторы APIs во вспомогательной таблице, и записать восстановленныеинструкции вызова APIs в главный код программы.

Я также не буду подробно описывать работу этой части скрипта, поскольку скриптснабжен подробными комментариями. А как работают прививки, Вы можетепосмотреть, запустив скрипт на распаковке какой-либо программы, упакованнойAsprotect, и остановившись на инструкции RUN, записанной после корректировкикода прививок. И хочу отметить, что все необходимые данные о таблице IAT изначение OEP (SBOEP) программы скрипт записывает в журнал регистрацииOllyDbg, что облегчает получение необходимых данных для дальнейшей работы.

И, здесь мне хотелось бы упомянуть еще об одной защите – это дополнительнойзащите импорта. Если мы посмотрим, например, на восстановленный код вызованекоторых APIs, то можем увидеть следующее:

На этом рисунке Ярко-зеленым цветом выделен мусорный код, который записан наместе украденных инструкций, расположенных после восстановленного вызова APIRegCloseKey. Если мы посмотрим на этот код после восстановления украденногокода, то увидим следующее:

На этом рисунке Желтым цветом выделен тот же самый адрес, но с ужевосстановленными инструкциями.

Протектор эмулирует восемь типов инструкций, которые следуют за инструкциейвызова API – JMP, CMP, OR и MOV. Здесь я указал 4 основных типа инструкций,поскольку имеются разные варианты инструкций сравнения CMP – типа CMP + Jcc,сравнение операнда с разного типа константами, а также имеются разные типыинструкции MOV – копирование регистров, копирование в указанную областьпамяти, и т.д. Каждый тип эмулированной инструкции имеет свой идентификатор,

Page 42: распаковка Asprotect

Распаковка программ, защищенных Asprotect42

© <2009> <Некрылов Валентин>

который на нижнем рисунке указан Светло-оранжевым цветом:

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

данных для эмулированных инструкций, и находит массив данных для техинструкций, которые должны быть выполнены после выполнения вызваннойAPI;

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

- после этого выполняется раскриптовка скопированного блока массива данных длявыполняемой эмулированной инструкции;

- и, наконец, выполняется эта эмулированная инструкция.

Для восстановления кода таких эмулированных инструкций, в конце скрипта “Восстановление таблицы IAT и вызовов APIs.osc” имеется специальная прививка,которая восстанавливает оригинальный код эмулированных инструкций. Код этойпрививки фактически является кодом подпрограммы выполнения эмулированныхинструкций, но доработанным для записи восстановленного кода эмулированныхинструкций.

Данный скрипт снабжен очень подробными комментариями, которые описываютработу скрипта, а работу прививок можно посмотреть при распаковке любойпрограммы, упакованной Asprotect.

Примечание: К этой части я не прилагаю скрипт для восстановления таблицыIAT и вызовов эмулированных APIs, поскольку этот скриптсодержит также код для эмуляции APIs Asprotect, которыевызываются из Asprotect.dll. Этот скрипт будет приложен к частиIV данного цикла статей, в котором и будет рассмотрена эмуляцииAPIs Asprotect, вызываемых из Asprotect.dll.

Page 43: распаковка Asprotect

Распаковка программ, защищенных Asprotect 43

© <2009> <Некрылов Валентин>

2.7 Эмуляция APIs Asprotect

Разработчики протектора ASProtect разработали несколько специальных APIs, такназываемых APIs Asprotect, которые используются для выполнения несколькихзадач: чтения регистрационного ключа защищенной протектором программы,установки сроков тестового периода защищенной программы, закриптовки ипоследующей раскриптовки некоторых участков кода, и т.д. Получить болееподробную информацию об этих APIs Asprotect можно в справке, котораяприлагается к дистрибутиву этого протектора. Здесь я сразу же хочу отметить, что,несмотря на одинаковые названия APIs Asprotect, и выполняемые ими функции влинейке ASProtect с длинным ключом (версии 1.хх), и с коротким ключом (версии 2.xx SKE), процесс их поиска и обработки в распаковываемых программах - разный.

2.7.1 Эмуляция APIs Asprotect в ASProtect с коротким ключом (версии 2.xxSKE)

Давайте сначала рассмотрим процесс поиска и обработки APIs Asprotect впрограммах, которые защищены версиями ASProtect с коротким ключом (версии 2.xxSKE).

В ASProtect с коротким ключом (версии 2.xx SKE) разработчики сначала применяли12 APIs Asprotect:

SetRegistrationKey, GetRegistrationInformation, CheckKey, CheckKeyAndDecrypt,GetKeyDate, GetKeyExpirationDate, GetTrialDays, GetTrialExecs, GetExpirationDate,GetModeInformation, GetHardwareID, SetUserKey.

Затем они заменили некоторые APIs Asprotect, и увеличили их количество до 13:

SetRegistrationKey, GetRegistrationInformation, SaveKey, CheckKey, CheckKeyAndDecrypt,GetKeyDate, GetKeyExpirationDate, GetTrialDays, GetTrialExecs, GetExpirationDate,GetModeInformation, GetHardwareID, SetUserKey.

И в последних версиях протектора, разработчики стали использовать 14 APIsAsprotect:

SetRegistrationKey, GetRegistrationInformation, RemoveKey, CheckKey,CheckKeyAndDecrypt, GetKeyDate, GetKeyExpirationDate, GetTrialDays, GetTrialExecs,GetExpirationDate, GetModeInformation, GetHardwareID, GetHardwareIDEx, SetUserKey,

В Asprotect.dll имеется волшебная точка, где можно найти вызов всех этих APIsAsprotect:

Page 44: распаковка Asprotect

Распаковка программ, защищенных Asprotect44

© <2009> <Некрылов Валентин>

На приведенном выше рисунке Красным цветом выделен адрес, по которомурасположены адреса вызовов всех APIs Asprotect (выделены на рисунке Бирюзовымцветом).

Очевидно, что найти эту волшебную точку можно по маске “BA01000000B9????????8B”.

Программисты, для защиты своих программ, используют от 1-й до 6-ти APIsAsprotect. Причем вызов этих APIs Asprotect выполняется из таблицы IAT.

Очевидно, что нам нужно выполнить эмуляцию всех APIs Asprotect, чтобыобеспечить нормальную работу программы. Эту работу прекрасно сделал VolX всвоих скриптах для автоматической распаковки программ, упакованных Asprotect,поэтому эмуляцию APIs Asprotect я опишу, опираясь на материалы VolX.

Давайте рассмотрим подпрограммы эмуляции всех APIs Asprotect.

API GetRegistrationInformation:

API RemoveKey, API CheckKey, API CheckKeyAndDecrypt:

API GetKeyDate:

Page 45: распаковка Asprotect

Распаковка программ, защищенных Asprotect 45

© <2009> <Некрылов Валентин>

API GetKeyExpirationDate:

API GetTrialDays, API GetTrialExecs:

API GetExpirationDate:

API GetModeInformation:

API GetHardwareID, API GetHardwareIDEx:

Page 46: распаковка Asprotect

Распаковка программ, защищенных Asprotect46

© <2009> <Некрылов Валентин>

Разработанный мной скрипт “Эмуляция APIs Asprotect, вызываемых из кодапрограммы.osc”, выполняет следующие работы:- находит адрес расположения вызовов всех APIs Asprotect в Asprotect.dll;- находит адреса в таблице IAT, из которых вызываются APIs Asprotect;- определяет имя APIs Asprotect;- записывает код эмуляции APIs Asprotect на свободное место в коде программы;- корректирует адреса вызовов эмулированных APIs Asprotect в таблице IAT;- регистрирует в журнале регистрации отладчика адреса вызовов эмулированных

APIs Asprotect в таблице IAT, адрес расположения кода эмулированных APIsAsprotect, и их названия.

Запись эмулированных APIs Asprotect в код распакованной программы необходимовыполнять после завершения работы скрипта “Восстановление таблицы IAT ивызовов APIs.osc”, и, не перезагружая программу в отладчике OllyDbg.

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

А если мы пройдем на адрес 00584A5C (первый адрес вызовов APIs Asprotect втаблице IAT), то увидим там следующее:

На рисунке Бирюзовым цветом выделены откорректированные адреса вызововэмулированных APIs Asprotect, Желтым цветом – разделительные ноли между DLL,а Ярко-зеленым и Сиреневым цветами – разные DLLs в таблице IAT.

А если мы посмотрим, например, на первую эмулированную API Asprotect, котораянаходится по адресу 00566940, то увидим там следующее:

Page 47: распаковка Asprotect

Распаковка программ, защищенных Asprotect 47

© <2009> <Некрылов Валентин>

Здесь Сиреневым цветом записана эмулированная API GetHardwareIDEx, аРозовым цветом – эмулированный HWiD жесткого диска. А сам код этойэмулированной API выглядит так:

И еще бы мне хотелось отметить одну немало важную деталь: эти APIs Asprotectвызываются из кода программы, после прохождения на OEP (SBOEP) программы.

2.7.2 Эмуляция APIs Asprotect в ASProtect с длинным ключом (версии 1.xx)

А теперь давайте рассмотрим процесс поиска и обработки APIs Asprotect впрограммах, которые защищены версиями ASProtect с длинным ключом (версии 1.xx). Для иллюстрации этой части статьи я буду использовать программу PasswordProv2.5.1.0, которая защищена Asprotect 1.41 build 04.01 Beta.

В ASProtect с длинным ключом (версии 1.xx), подпрограмма вызова APIs Asprotectрасположена в Asprotect.dll, и имеет следующий вид:

Как видно из приведенного рисунка, эта подпрограмма полностью эмулирована, иона вызывается из подпрограммы заполнения таблицы INIT:

На верхнем рисунке показан фрагмент подпрограммы заполнения таблицы INIT.Если не выполняется прыжок JE SHORT 00698972, то мы проходим на

Page 48: распаковка Asprotect

Распаковка программ, защищенных Asprotect48

© <2009> <Некрылов Валентин>

подпрограмму заполнения таблицы INIT, которая, в таком случае, поврежденапротектором. А когда мы выполняем инструкцию RET, то попадаем наподпрограмму вызовов APIs Asprotect. Обратите на это внимание – здесь вызов APIsAsprotect выполняется до прохождения OEP (SBOEP) программы.

Примечание: Кстати, этот нюанс очень неплохо используют разработчикипрограмм, которые, для защиты своих продуктов, заказываютспециальные варианты протектора Asprotect, в которых, вместостандартных подпрограмм APIs Asprotect применяют свои,специальные подпрограммы APIs Asprotect. Причем, разработчикимогут эмулировать эти специальные подпрограммы, защищать их кодпроверками целостности (CRC), и делать прочие гадости. Все этозначительно усложняет процесс распаковки таких программ.

Чтобы мы не могли исследовать эту подпрограмму, а также откорректироватьнекоторые данные, связанные с тестовым периодом защищенной программы,разработчики протектора полностью ее эмулируют. Поэтому разработанный мнойскрипт “Восстановление таблицы IAT и вызовов APIs.osc” включает в себявиртуальную машину, которая восстанавливает оригинальный код эмулированныхинструкций. После восстановления оригинального кода этой подпрограммы, мыувидим следующее:

Если мы выполним трассирование кода подпрограммы вызова API Asprotect, тоувидим первое интересное место:

Здесь мы получаем HWiD нашего жесткого диска (значение HWiD для моей машиныпоказано в справочном окне отладчика). Значение HWiD жесткого диска получаетсяс помощью API GetHardwareID или API GetHardwareIDEx.

Далее имеется второе интересное место:

Page 49: распаковка Asprotect

Распаковка программ, защищенных Asprotect 49

© <2009> <Некрылов Валентин>

Здесь, по адресу, указанному в регистре ESI, записываются адреса подпрограмм,которые должны быть выполнены в Asprotect.dll, до прохождения на OEP (SBOEP),т.е. адреса подпрограмм вызова APIs Asprotect. Таких адресов может быть записано0Eh (15 dec), или 0Fh (16 dec), и область записи этих адресов на рисунке выделенаЖелтым цветом (эта область, для показанной программы, имеет размер – 3Chбайтов). Если мы, до прохождения на OEP(SBOEP) не выполним подпрограммы,записанные в выделенной области, то не сможем запустить дамп распакованнойпрограммы.

Протектор Asprotect с длинным регистрационным ключом использует 12 APIsAsprotect, и плюс еще 2 APIs (процедуры), которые обрабатывают закриптованныеучасти кода программы. Эти процедуры называются GetEncryptProc иGetDecryptProc, и они выполняются только в зарегистрированном режиме.

Примечание: Здесь я еще раз хотел бы отметить, что Asprotect с длиннымирегистрационными ключами (v1.32, 1.35, 1.40, 1.41, 1.50), иAsprotect SKE с короткими регистрационными ключами (v2.0, 2.11,2.20, 2.3, 2.4, 2.41, 2.50), имеют разные APIs Asprotect (хотя частьэтих APIs является одинаковой), поэтому эту разницу и нужноучитывать при распаковке программ.

Порядок расположения APIs Asprotect в выделенной области памяти, показанной наверхнем рисунке, следующий:

Смещение отрегистра ESI

API Asprotect

00 SetRegistrationKey

04 GetRegistrationInformation

08 GetKeyExpirationDate

0C CheckTrial

10 GetHardwareID

Page 50: распаковка Asprotect

Распаковка программ, защищенных Asprotect50

© <2009> <Некрылов Валентин>

14 GetTrialDays

18 GetTrialExecs

1C GetExpirationDate

20 ExecuteApplication

24 ExecuteTrial

28 GetRunApplicationFunction

2C SetDecryptionKey

30 GetEncryptProc

34 GetDecryptProc

Следует отметить, что в некоторых версиях Asprotect.dll, вместо регистра ESI можетиспользоваться регистр EDI.

Понимание порядка расположения APIs Asprotect в этой области памяти имеетбольшое значение, поскольку нам необходимо правильно эмулировать эти APIs.

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

На нижних рисунках приведены примеры использования APIs Asprotect, вместе саргументами, которые необходимы для выполнения этих APIs.

API SetRegistrationKey:

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

API GetRegistrationInformation:

Page 51: распаковка Asprotect

Распаковка программ, защищенных Asprotect 51

© <2009> <Некрылов Валентин>

Эта API имеет только один аргумент – текстовую строку с регистрационнымиданными программы.

API GetKeyExpirationDate и GetExpirationDate:

Эти две APIs имеют три аргумента – день, месяц и год. На этом рисунке:1Eh – 30-й день;0Ch – 12-й месяц (декабрь);807h – 2055 год.

Т.е., эти три цифры обозначают – 30 декабря 2055 года.

API CheckTrial:

Эта API имеет только один аргумент – текстовую строку с информацией озавершении срока тестирования программы (как образец).

API GetHardwareID:

Page 52: распаковка Asprotect

Распаковка программ, защищенных Asprotect52

© <2009> <Некрылов Валентин>

Эта API имеет только один аргумент – текстовую строку с информацией о HWiDжесткого диска.

API GetTrialDays и GetTrialExecs:

Функция API GetTrialDays имеет два аргумента – число дней для тестированияпрограммы, и число оставшихся дней тестирования. На этом рисунке:1Eh – 30 дней для тестирования программы;1Eh – 30 оставшихся дней для тестирования программы.

Функция API GetTrialExecs имеет два аргумента – число запусков программы для еетестирования, и число оставшихся запусков. На этом рисунке:1Eh – 30 запусков для тестирования программы;1Eh – 30 оставшихся запусков для тестирования программы.

API GetRunApplicationFunction:

Эта API работает вместе с APIs ExecuteApplication и ExecuteTrial. Если закончилсясрок тестирования программы, то API GetRunApplicationFunction вызовет APIExecuteTrial, которая покажет нам сообщение об окончании срока тестированияпрограммы. Если срок тестирования программы не истек, или программа работает взарегистрированном режиме, то API GetRunApplicationFunction вызывает APIExecuteApplication.

Поэтому API GetRunApplicationFunction применяет один аргумент – это указательна API ExecuteApplication или ExecuteTrial.

Page 53: распаковка Asprotect

Распаковка программ, защищенных Asprotect 53

© <2009> <Некрылов Валентин>

API GetDecryptProc:

Эта API работает вместе с API GetEncryptProc. Эти APIs имеют по одному аргументу- это указатель на выполняемую подпрограмму, при запуске программы.

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

2.7.3 Эмуляция APIs Asprotect, вызываемых из Asprotect.dll

Эмуляцию APIs Asprotect, вызываемых из Asprotect.dll, выполняет скрипт “Восстановление таблицы IAT и вызовов APIs.osc”. Этот скрипт делает следующее:- находит в Asprotect.dll адрес подпрограммы выполнения APIs Asprotect;- восстанавливает оригинальный код этой подпрограммы, поскольку разработчики

протектора полностью эмулируют эту подпрограммы;- определяет имя API Asprotect;- регистрирует в журнале регистрации отладчика адрес вызова эмулированной API

Asprotect.

Итак, поскольку мы разобрались с эмуляцией APIs Asprotect, то продолжим нашуработу. После пары инструкций CMP EBX,0F, JNZ SHORT 00699A6E, начинаетсяобласть кода, в которой и вызываются эти APIs Asprotect:

Сначала проверяется, записан ли адрес подпрограммы по адресу, указанномупараметром [ESI+Value]. Если здесь записан ноль, то выполняется условный прыжокна проверку вызова очередной API Asprotect. Если же здесь записан адрес

Page 54: распаковка Asprotect

Распаковка программ, защищенных Asprotect54

© <2009> <Некрылов Валентин>

подпрограммы, то условный прыжок не выполняется, и далее определяютсяаргументы для выполнения заданной подпрограммы, которые с помощьюинструкции PUSH EAX помещаются в стек.

Затем выполняется вызов API Asprotect с помощью инструкции CALL EAX. Взависимости от типа вызываемой API Asprotect, она может иметь разное числоаргументов, помещаемых в стек.

Для показанной здесь программы, мы должны, до прохождения на OEP/SBOEP,выполнить две подпрограммы, расположенные по адресам 00427A30 и 004275B0(эти адреса мы видим в области, выделенной Желтым цветом). В соответствии сприведенной таблицей, по этим адресам вызываются APIs SetRegistrationKey иGetRegistrationInformation.

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

Инструкция CALL 00699460, которая расположена на адресе 00699BAC, ничего незагружает в стек, поэтому ее можно не учитывать в нашей работе. А затемвыполняется инструкция CALL EBX, где регистр EBX = 00427A30. Этаподпрограмма считывает информацию из ключа PasswordsPro.key (который долженбыть в зарегистрированной версии программы).

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

По адресу [ESI+4] записан адрес подпрограммы 004275B0. Перед выполнением этойподпрограммы, в стек, с помощью инструкции PUSH EAX, загружается аргумент,

Page 55: распаковка Asprotect

Распаковка программ, защищенных Asprotect 55

© <2009> <Некрылов Валентин>

который содержит регистрационную информацию, полученную из регистрационногоключа. Эта инструкция расположена по адресу 00699DBD.

А если мы полностью выполним скрипт “Восстановление таблицы IAT и вызововAPIs.osc” на этой программе, и посмотрим журнал регистрации отладчика, то тамувидим:

На этом рисунке Бирюзовым цветом выделен адрес записи эмулированной APIGetRegistrationInformation в главном коде программы, Ярко-зеленым цветомвыделены адреса вызовов APIs Asprotect, а Сиреневым цветом – адресподпрограммы вызовов APIs Asprotect.

Если мы пройдем на адрес записи эмулированной API GetRegistrationInformation,то там увидим:

Здесь Оранжевым цветом выделено число символов в зарегистрированном имени, а Бирюзовым цветом выделено само имя, которое должно быть показано в окне “About”.

Правда, может возникнуть вопрос, а почему мы не можем эмулировать APIsAsprotect после прохождения на OEP (SBOEP) программы. Разработчики протекторапредусмотрели такую возможность, и в конце подпрограммы вызова APIs Asprotect,они полностью удаляют таблицу их вызовов, заполняя ее нолями.

Приложения: 1. Скрипт для восстановления таблицы IAT и вызовов эмулированных APIs в

распаковываемых программах - “Восстановление таблицы IAT и вызовов APIs.osc”.

2. Виртуальная машина для восстановления кода эмулированных инструкций вAsprotect.dll – “recovery_emulate_inst_Asprotect_dll.bin”.

Примечание: В скрипте предусмотрена команда для редактирования пути квиртуальной машине “recovery_emulate_inst_Asprotect_dll.bin”.При желании, Вы можете непосредственно в скрипте, на строке

Page 56: распаковка Asprotect

Распаковка программ, защищенных Asprotect56

© <2009> <Некрылов Валентин>

1328, указать нужный путь к этой виртуальной машине.

2.7.4 Эмуляция APIs Asprotect, вызываемых из кода программы

Немного выше я описал APIs Asprotect, и их вызовы из защищенной протекторомпрограммы. Как было указано ранее, для программ, защищенных Asprotect сдлинным ключом (версии Asprotect 1.xx), APIs Asprotect эмулируются в процессевосстановления таблицы IAT и вызовов эмулированных APIs. Это обусловлено тем,что протектор, после выполнения вызовов APIs Asprotect, заполняет нолями таблицуих вызовов, и поэтому выполнить эмуляцию этих APIs Asprotect, находясь на OEP(SBOEP) программы, уже невозможно.

Иначе обстоит дело с программами, защищенными Asprotect с коротким ключом(версии Asprotect 2.xx SKE). В этих программах, APIs Asprotect вызываются ужепосле прохождения программой OEP (SBOEP), в процессе ее запуска. В этом случаепоявляется возможность выполнить эмуляцию APIs Asprotect, когда программаостановлена на OEP (SBOEP). Тем более что эту операцию целесообразновыполнять до получения дампа памяти программы, чтобы можно было получитьфайл с уже эмулированными APIs Asprotect. Для этих целей и предназначен скрипт “Эмуляция APIs Asprotect, вызываемых из кода программы.osc”. Этот скрипт надозапускать только после выполнения скрипта “Восстановление таблицы IAT ивызовов APIs.osc”, без перезагрузки программы в отладчике OllyDbg, поскольку длясвоей работы скрипт использует файл “main_parameters.bin”, который загружается впамять программы, и содержит все необходимые данные для работы скрипта. Вскрипте “Восстановление таблицы IAT и вызовов APIs.osc”, я указываю всообщениях, которые выводит скрипт, выполнить 4 скрипта:

- для эмуляции APIs Asprotect; - устранения проверок целостности кода (CRC) программы; - восстановления эмулированных инструкций; - восстановления секции импорта (.idata).

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

2.8 Устранение проверок целостности кода (CRC) враспакованной программе

Как я уже писал раньше, протектор в максимальной степени пытается усложнитьжизнь cracker's, создавая для нас большое количество разных пакостей. Одной из нихявляется проверка целостности кода распакованной программы (CRC). Проверкацелостности кода распакованной программы основана на проверке измененияпервого байта инструкций вызова эмулированных APIs. Как мы помним из 3-й части

Page 57: распаковка Asprotect

Распаковка программ, защищенных Asprotect 57

© <2009> <Некрылов Валентин>

этого выпуска, для вызова эмулированных APIs протектор использует подпрограммытипа CALL XXXXXXXX:

На этом рисунке показан нормальный вызов APIs kernel32.CreateFileA иCloseHandle, и вызов эмулированных APIs kernel32.GetFileType и GetSystemTime,которые выполняются с помощью инструкции CALL 01FE0000. Протекторпредусматривает в программе проверку 1-го байта опкода инструкции E8h нанекоторых инструкциях вызова эмулированных APIs. И, если вместо этого байтабудет записан байт FFh, то программа покажет исключение, и не будет работать.Такая проверка выглядит следующим образом:

На рисунке Ярко-зеленым цветом выделен адрес вызова эмулируемой APIs, аСиреневым цветом выделена инструкция, которая проверяет значение первого байтаопкода инструкции по этому адресу - FF или E8. Здесь мы видим запутанный код,

Page 58: распаковка Asprotect

Распаковка программ, защищенных Asprotect58

© <2009> <Некрылов Валентин>

который вычисляет значение этого байта. Если первый байт опкода был изменен, тов регистре EDI будет записано значение 17h (0FF – 0E8 = 17h), и тогда не будетвыполнен условный прыжок JE 0051FDD5, который расположен по адресу0051FDAF, что вызовет сбой при запуске или работе программы.

В основу скрипта “Проверка целостности кода (CRC) в программе.osc”, заложенпоиск байтов инструкций, выделенных на рисунке Бирюзовым цветом. Этиинструкции находятся в конце подпрограммы проверки целостности кода, и легконаходятся по маске “E9000000005?5?E9”. При нахождении такой цепочки байтов,скрипт устраняет ее путем замены условного прыжка JE_xxxxxxxx безусловнымпрыжком JMP_xxxxxxxx. Поскольку некоторые программы имеют исполняемый коди во второй секции файла, то скрипт предусматривает такую проверку CRC и в этойсекции файла.

Скрипт “Проверка целостности кода (CRC) в программе.osc” надо запускать послевыполнения скрипта “Восстановление таблицы IAT и вызовов APIs.osc”, безперезагрузки программы в отладчике OllyDbg. Для своей работы скрипт используетфайл “main_parameters.bin”, который загружается в память программы, и содержитвсе необходимые данные для работы скрипта.

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

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

На этом рисунке мы видим традиционное начало подпрограммы, затем идут триинструкции PUSH, после которых следует инструкция CALL 00EF7710, которая

Page 59: распаковка Asprotect

Распаковка программ, защищенных Asprotect 59

© <2009> <Некрылов Валентин>

вызывает виртуальную машину для выполнения инструкций этой подпрограммы изAsprotect.dll.

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

Сама виртуальная машина (VM) для выполнения эмулированных инструкций имеетсложный и запутанный вид. Кроме того, в последних версиях протектора,разработчики встроили в эту VM еще одну виртуальную машину, которая выполняетэмулированные инструкции MOV, ADD и SUB, что еще усложняет процессвосстановления такого эмулированного кода. Я не буду описывать VM длявыполнения эмулированных инструкций, поскольку это не является задачей даннойстатьи. Здесь я лишь кратко расскажу об алгоритме ее работы.

1. Сначала из массива данных для эмулированных инструкций, VM извлекает ираскриптовывает первый байт опкода выполняемой эмулированной инструкции.

2. По этому байту опкода, VM определяет тип эмулированной инструкции (MOV,JMP, SUB, и т.д.), и определяет ветку кода для выполнения этой инструкции.

3. Выполняет прыжок на эту ветку кода, и извлекает остальные байты опкода длявыполняемой эмулированной инструкции. Некоторые байты опкода могут бытьтакже закриптованными.

4. Выполняет эту эмулированную инструкцию в специально выделенной областипамяти, и переходит к выполнению следующей инструкции.

5. При появлении эмулированных инструкций MOV, ADD и SUB, имеющихспециальную метку, передает их выполнение во вторую VM.

Я написал код VM для восстановления таких эмулированных инструкций, взяв забазу код VM для выполнения эмулированных инструкций. На момент написаниякода VM для восстановления эмулированных инструкций, последней версиейпротектора была версия 2.41 SKE build 02.26 Beta, которую я и использовал вкачестве базовой версии. Из кода VM для выполнения эмулированных инструкций явыбросил мусорный код, выбросил код, связанный с выполнением эмулированныхинструкций, и дописал код, который записывает извлеченный код из массиваданных по адресу расположения эмулированной инструкции. Но разработчикипротектора, видимо понимали, что найдется кто-то, кто проанализирует их VM, инайдет способ восстановления оригинального кода эмулированных инструкций.Видимо, для этих целей они предусмотрели следующую защиту:

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

Page 60: распаковка Asprotect

Распаковка программ, защищенных Asprotect60

© <2009> <Некрылов Валентин>

2. Изменение порядка расположения данных в заголовке массива данных дляэмулированных инструкций.

3. Изменение порядка расположения данных для закриптованных инструкций вмассиве данных.

4. Изменение порядка данных в массиве данных для эмулированных инструкций вовторой VM.

5. Изменение идентификатора инструкций MOV, ADD и SUB во второй VM. Если взять одну и ту же программу, и два раза подряд упаковать той же самойверсией протектора ASProtect 2.41 SKE build 02.26 Beta, то VM для восстановленияэмулированных инструкций не будет работать, поскольку протектор изменяетвышеуказанные параметры, которые нужны для работы VM.

Для обеспечения совместимости кода VM для восстановления эмулированныхинструкций с разными версиями протектора, я добавил в нее следующиеподпрограммы:

1. Для восстановления оригинального первого байта опкода эмулированныхинструкций. Эта подпрограмма, по сути, представляет собой самостоятельнуюVM, которая извлекает первый байт опкода из массива данных, раскриптовываетего, и преобразует в нормальный первый байт опкода инструкции (типа E8 –инструкция CALL, E9 – инструкция JMP, 8B – инструкция MOV, и т.д.).

2. Для перезаписи заголовка массива данных. Эта подпрограмма переписываетзаголовок массива данных для эмулированных инструкций применительно кбазовой VM, построенной на коде ASProtect 2.41 SKE build 02.26 Beta.

3. Для перезаписи данных в массиве данных для каждой восстанавливаемойинструкции применительно к базовой VM.

4. Для перезаписи данных в массиве данных для эмулированных инструкций вовторой VM.

5. Для изменения идентификатора инструкций MOV, ADD и SUB во второй VM.

Код этой VM в виде файла “VM_Machine_main_code.exe” я прикладываю к этойчасти, и он должен храниться у Вас в неизмененном виде. Корректировка этого кодадолжна выполняться с помощью скрипта “Создание кода VM, используемой длявосстановления эмулированных инструкций в области кода.osc”, который создаетотдельный файл прививки с именем “recovery_emulate_inst_main_code.bin”, которыйработает в скрипте “Восстановление эмулированных подпрограмм в кодепрограммы.osc”.Если все предыдущие скрипты работают, практически, без участия пользователя, тодля корректировки VM, которая восстанавливает эмулированные инструкции,потребуется немного серого вещества, именуемого в народе “мозгом”, и терпения. Япостараюсь более подробно описать весь процесс работы по подготовке ккорректировке VM. К этой части статьи я также прикладываю файл “Asprotect_241_0226.dll”, который, вместе с файлом “VM_Machine_main_code.exe”должны храниться у Вас в неизменном виде.

Page 61: распаковка Asprotect

Распаковка программ, защищенных Asprotect 61

© <2009> <Некрылов Валентин>

2.9.1 Получение файла Asprotect.dll из распаковываемой программы

Итак, приступаем к работе. Сначала мы должны получить файл Asprotect.dll израспаковываемой программы. В этом файле должны быть восстановлены всеэмулированные подпрограммы, поскольку вторая VM для выполненияэмулированных инструкций MOV, ADD и SUB, также полностью эмулирована.Имеется прекрасная утилита от deroko “AsprDllDumper.exe”, которая дампируетAsprotect.dll из распаковываемой программы, но, к сожалению, она невосстанавливает эмулированные инструкции в Asprotect.dll. Для получения файла вAsprotect.dll, я написал три скрипта “Восстановление эмулированных подпрограммв Asprotect_dll на OEP (SBOEP).osc”, “Создание файла Asprotect_dll.osc” и “Восстановление секции импорта (.idata) в Asprotect_dll.osc”. Эти скрипты такжеприложены к этой части выпуска 2.

Итак, загружаем распаковываемую программу в отладчик, и запускаем скрипт “Восстановление таблицы IAT и вызовов APIs.osc”, который позволяет нам пройтина OEP (SBEOP) программы. Можно, конечно, для этих целей использовать скрипт “Поиск OEP (SBOEP).osc” или скрипт для восстановления таблицы INIT, но тогдадолжен быть предварительно создан файл “main_parameters.bin”, который создаетсяскриптом для восстановления таблицы IAT и вызовов эмулированных APIs. Когдапрограмма загружена в отладчик, запускаем скрипт “Восстановлениеэмулированных подпрограмм в Asprotect_dll на OEP (SBOEP).osc”, которыйвосстанавливает все эмулированные инструкции в Asprotect.dll.

Далее, не перезагружая программу в отладчике, запускаем скрипт “Создание файлаAsprotect_dll.osc”, который практически полностью подготавливает к дампированиюфайла Asprotect.dll, в котором пока отсутствует секция импорта (хотя в немполностью восстановлена таблица IAT). И опять, не перезагружая программу вотладчике, запускаем скрипт “Восстановление секции импорта (.idata) вAsprotect_dll.osc”, который восстанавливает секцию импорта в файле Asprotect.dll, идампирует его с именем “Asprotect.dll”. В итоге мы получаем файл Asprotect.dll, вкотором восстановлены все эмулированные инструкции, находятся массивы данныхкак для эмулированных инструкций, так и для APIs и вызовов эмулированных APIs.Этот файл можно проанализировать то ли в отладчике OllyDbg, то ли вдизассемблере IDA, кому что нравится. И я рекомендую, после создания файлаAsprotect.dll, переименовать его таким образом, чтобы его можно было легко найтисреди других аналогичных файлов, если Вы занимаетесь распаковкой многихпрограмм, защищенных этим протектором. Я переименовал созданный файл как “Asprotect_251_0922.dll”, который указывает, что эта “Asprotect.dll” была созданапротектором Asprotect v2.51 SKE build 09.22.

2.9.2 Получение таблицы соответствия первого байта опкодаэмулированных инструкций для распаковываемой программы

Итак, нами получен файл “Asprotect_251_0922.dll”, который мы должны сравнить сбазовым файлом “Asprotect_241_0226.dll”, чтобы откорректировать код VM для

Page 62: распаковка Asprotect

Распаковка программ, защищенных Asprotect62

© <2009> <Некрылов Валентин>

восстановления эмулированных инструкций. Для этого мы запускаем два отладчикаOllyDbg, и в первый отладчик загружаем файл “Asprotect_241_0226.dll”, а во второйотладчик – наш подопытный файл “Asprotect_251_0922.dll”. Нажимаем клавишиCtrl+A, чтобы отладчик проанализировал эти файлы. Нажимаем в обоих отладчикахклавиши Ctrl+B, и в появившееся окно двоичного поиска вводим следующие байты “6089E09C5A5589E583C52431C9648B0981ECB80B0000FF7508FF750C525150FF7504”, которые являются байтами опкода подпрограммы, из которой можно войти в VMдля выполнения эмулированных инструкций. Для нашей подопытной программы этобудет выглядеть так:

Здесь я хочу отметить, что имеется две таких подпрограмм:

1. Вход в VM для выполнения эмулированных инструкций в области кодапрограммы;2. Вход в VM для выполнения эмулированных инструкций в Asprotect.dll.

При двоичном поиске вышеуказанной цепочки байтов мы попадаем на 1-юподпрограмму, но, для дополнительной проверки, входим в CALL 00EFAB18, иищем инструкцию XOR EAX,CONST:

На рисунке эта инструкция выделена Ярко-зеленым цветом, и находится недалеко отначала этой подпрограммы. Эта инструкция раскриптовывает адрес первойэмулированной инструкции из всех эмулированных подпрограмм, и, для нашейработы, нам нужно запомнить константу в инструкции XOR EAX,6CB02433. Именноэту константу для нас нашел, и сохранил в переменной Const_EAX скрипт “Восстановление таблицы IAT и вызовов APIs.osc”. Эта константа необходима для

Page 63: распаковка Asprotect

Распаковка программ, защищенных Asprotect 63

© <2009> <Некрылов Валентин>

корректировки кода VM, которая будет восстанавливать оригинальный кодэмулированных инструкций.

Немного ниже этой инструкции находится следующий CALL 00EF7F84, в которыймы также должны войти:

Отличительной особенность этого CALL является наличие инструкции TEST AL,AL, которая находится ниже него.

Входим в CALL 00EF7F84 с клавишей Enter, и ищем CALL 00EFAFDC:

Это и есть VM для выполнения эмулированных инструкций. Отличительнойособенность этого CALL является наличие инструкции INC EAX, которая находитсяниже него, и, кроме того, этот CALL находится в конце этой подпрограммы.

Входим в CALL 00EFAFDC с клавишей Enter, и немного прокручиваем код вниз, доблока ключей, которые выполняют прыжки на разные ветки кода:

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

Page 64: распаковка Asprotect

Распаковка программ, защищенных Asprotect64

© <2009> <Некрылов Валентин>

На этом рисунке Ярко-зеленым цветом выделены зашифрованные hex-числа первойполовинки байта опкода эмулированной инструкции (как известно, байт опкодасостоит из комбинации двух hex-чисел: 0h, 1h, …, 0Fh). А инструкции CALL,которые находятся ниже этих “Событий”, и являются теми областями кода VM, вкоторых выполняются эмулированные инструкции. Для удобства контроляобрабатываемых hex-значений, устанавливаем на каждый CALL BreakPoint – длямаркировки.

И теперь мы должны заполнить следующую таблицу:

Hex-числа Зашифрованные значения

Asprotect_241_0226.dll Asprotect_251_0922.dll

0h D4h 9Dh

1h E0h F7h

2h 4Eh C7h

3h 8Dh E0h

4h 07h F6h

5h 5Bh EBh

6h 5Eh 4Eh

7h 99h DCh

8h C7h F9h

9h FCh D2h

Ah A0h 08h

Bh 49h 57h

Ch 8Bh CDh

Page 65: распаковка Asprotect

Распаковка программ, защищенных Asprotect 65

© <2009> <Некрылов Валентин>

Dh 93h 10h

Eh 4Ah D0h

Fh 9Ah 72h

Я здесь привел уже заполненную таблицу соответствия зашифрованных значенийhex-чисел в Asprotect_241_0226.dll и Asprotect_251_0922.dll. ДляAsprotect_241_0226.dll Вы должны сохранить эти значения, а для Вашей подопытнойпрограммы – найти эти соответствия. К моему сожалению, я не нашел никакогодругого метода поиска этих соответствий, как визуальное сравнение CALL, в которыхвыполняются эмулированные инструкции. На приведенных ниже рисунках, ястрелками указал те отличительные особенности этих CALL, на которые надообращать внимание при этом сравнении. И, после нахождения соответствия, нужноснимать с CALL установленные на них BreakPoint, чтобы не просматривать ихнесколько раз при поиске очередных соответствий hex-чисел.

Событие C7h:

На этом рисунке я Красной рамкой выделил группу, инструкций, на которую нужнообратить внимание при визуальном сравнении (для уменьшения размера, я непривожу рисунки для Asprotect_241_0226.dll),Вы сами можете посмотреть на этуподпрограмму по hex-значению 4Eh.

Событие E0h:

Page 66: распаковка Asprotect

Распаковка программ, защищенных Asprotect66

© <2009> <Некрылов Валентин>

Событие F6h:

Событие EBh:

Это – самая короткая подпрограмма в VM, и практически совпадает с аналогичнойподпрограммой в Asprotect_241_0226.dll.

Событие CDh:

Page 67: распаковка Asprotect

Распаковка программ, защищенных Asprotect 67

© <2009> <Некрылов Валентин>

Событие DCh:

Эта подпрограмма практически совпадает с аналогичной подпрограммой вAsprotect_241_0226.dll.

Событие 72h:

Событие 9Dh:

Page 68: распаковка Asprotect

Распаковка программ, защищенных Asprotect68

© <2009> <Некрылов Валентин>

Начало этой подпрограммы практически совпадает с началом аналогичнойподпрограммы в Asprotect_241_0226.dll.

Событие 08h:

Расположение инструкций, помеченных Красной стрелкой, может меняться, но онивсегда имеются только в этой подпрограмме.

Событие D2h:

Page 69: распаковка Asprotect

Распаковка программ, защищенных Asprotect 69

© <2009> <Некрылов Валентин>

Начало этой подпрограммы практически совпадает с началом аналогичнойподпрограммы в Asprotect_241_0226.dll.

Событие F7h:

Начало этой подпрограммы практически совпадает с началом аналогичнойподпрограммы в Asprotect_241_0226.dll.

Событие 10h:

Начало этой подпрограммы практически совпадает с началом аналогичнойподпрограммы в Asprotect_241_0226.dll.

Событие D0h:

Page 70: распаковка Asprotect

Распаковка программ, защищенных Asprotect70

© <2009> <Некрылов Валентин>

Начало этой подпрограммы практически совпадает с началом аналогичнойподпрограммы в Asprotect_241_0226.dll.

Событие 4Eh:

Расположение инструкций, помеченных Красной стрелкой, может меняться, но онивсегда имеются только в этой подпрограмме.

Событие 57h:

Событие F9h:

Page 71: распаковка Asprotect

Распаковка программ, защищенных Asprotect 71

© <2009> <Некрылов Валентин>

Начало этой подпрограммы практически совпадает с началом аналогичнойподпрограммы в Asprotect_241_0226.dll.

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

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

Приложения: 1. Скрипт для эмуляции APIs Asprotect, вызываемых из кода программы - “

Эмуляция APIs Asprotect, вызываемых из кода программы.osc”.2. Скрипт для устранения проверок целостности кода (CRC) в программе - “

Устранение проверки целостности кода (CRC) программы.osc”.3. Скрипт для восстановления эмулированных инструкций в Asprotect.dll, когда

программа остановлена на OEP (SBOEP) - “Восстановление эмулированныхподпрограмм в Asprotect_dll на OEP (SBOEP).osc”.

4. Скрипт для получения файла Asprotect.dll - “Создание файла Asprotect_dll.osc”.5. Скрипт для восстановления секции импорта в Asprotect.dll - “ Восстановление

секции импорта (.idata) в Asprotect_dll.osc ”.6. Файл базовой Asprotect.dll - “Asprotect_241_0226.dll”.7. Файл подопытной Asprotect.dll - “Asprotect_251_0922.dll”.8. Виртуальная машина для восстановления кода эмулированных инструкций в коде

программы – “ VM_Machine_main_code.exe”.

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

Как я уже писал выше, протектор также изменяет расположение данных в заголовкемассива данных для эмулированных инструкций. Давайте посмотрим на заголовокмассива данных в базовой программе Asprotect v2.41 build 02.26. Для этого мыдолжны загрузить в отладчик эту программу, пройти на OEP (SBOEP), перейти вобласть кода программы, и найти любую эмулированную подпрограмму, выполнивдвоичный поиск по маске “68????????68????????68????????E8”:

Page 72: распаковка Asprotect

Распаковка программ, защищенных Asprotect72

© <2009> <Некрылов Валентин>

Отличительной особенностью таких подпрограмм является инструкция CALL сдистанцией прыжка на Asprotect.dll.

Чтобы получить адрес массива данных для эмулированных инструкций, мы должныустановить регистр EIP на первой инструкции PUSH, нажав клавиши Ctrl+*, ивыполнить эти четыре инструкции. Причем, при выполнении инструкции CALL, мыдолжны войти в эту инструкцию с F7, и выполнить ее до инструкции RETN 0C.После выполнения инструкции RETN 0C, мы возвращаемся в код программы, новидим уже немного другую картину:

По адресу 00F90CC8 и располагается заголовок массива данных для эмулированныхинструкций:

На нижнем рисунке я привел рисунок заголовка массива данных для подопытнойпрограммы Asprotect v2.51 build 09.22, который находится по адресу 00FA3634:

Page 73: распаковка Asprotect

Распаковка программ, защищенных Asprotect 73

© <2009> <Некрылов Валентин>

Заголовок массива данных для эмулированных инструкций имеет фиксированныйразмер 20h байтов, и содержит следующие данные (на рисунках выделены разнымицветами): Желтым цветом выделен заголовок массива данных с идентификаторами482h, Серым цветом выделено значение ImageBase программы, Красным цветом –PiD процесса, Розовым цветом – число эмулированных инструкций в этом массиведанных. Сиреневым цветом выделено значение константы для раскриптовкиданных, Коричнево-зеленым цветом – указатель на блок данных для первойэмулированной инструкции, и Золотистым цветом – указатель на конец массиваданных, который применяется для выполнения эмулированных инструкций SUB,ADD и MOV во второй VM для выполнения эмулированных инструкций. Описаниеназначения данных в заголовке облегчает поиск их соответствия в разныхпрограммах, защищенных Asprotect.

Зеленым цветом выделены данные для первой эмулированной инструкции, аБирюзовым цветом выделены данные для второй эмулированной инструкции.

Здесь я сразу же хочу отметить, что в программе восстановления оригинального кодаэмулированных инструкций не используются значения идентификатора массиваданных и PiD процесса, и, кроме того, значения, находящиеся по адресам +00h и+1Ch от начала заголовка массива данных – не меняют своего расположения.

Для удобства работы опять сводим эти данные в таблицу:

Параметр Смещение от начала заголовка массива данных

Asprotect_241_0226.dll Asprotect_251_0922.dll

DWORD_00h + 00h + 00h

DWORD_04h + 04h + 0Ch

DWORD_08h + 08h + 18h

DWORD_0Сh + 0Сh + 14h

DWORD_10h + 10h + 10h

DWORD_14h + 14h + 08h

DWORD_18h + 18h + 04h

DWORD_1Ch + 1Ch + 1Ch

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

Page 74: распаковка Asprotect

Распаковка программ, защищенных Asprotect74

© <2009> <Некрылов Валентин>

2.9.4 Получение таблицы расположения данных в массиве данных дляэмулированных инструкций

Чтобы получить таблицу соответствия расположения данных в массиве, нам надоопять загрузить” в отладчик файлы “Asprotect_241_0226.dll” и “Asprotect_251_0922.dll. После загрузки этих файлов переходим на таблицу ключей VM для выполненияэмулированных инструкций.

Asprotect_241_0226.dll:

Asprotect_251_0922.dll:

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

Инструкции MOV EAX,DWORD PTR DS:[EBX+89] и MOV EAX,DWORD PTR DS:[EBX+23] записывают в регистр EAX адрес блока данных для текущей выполняемойэмулированной инструкции. Давайте выполним поиск константы 89h вAsprotect_241_0226.dll, и 23h в Asprotect_251_0922.dll.

Page 75: распаковка Asprotect

Распаковка программ, защищенных Asprotect 75

© <2009> <Некрылов Валентин>

Asprotect_251_0922.dll:

Таких констант в файле может быть много, но нас интересуют только те адреса,которые находятся возле метки “Первоначальный выбор в CPU”. Причем обратитевнимание на то, что я установил BreakPoint только на инструкции записи врегистры указателя на массив данных для текущей эмулированной инструкции. Этонам позволит заполнить таблицу соответствия расположения данных в массиведанных для программ “Asprotect_241_0226.dll” и “Asprotect_251_0922.dll.

Делаем таблицу:

Page 76: распаковка Asprotect

Распаковка программ, защищенных Asprotect76

© <2009> <Некрылов Валентин>

Параметр Зашифрованные значения

Asprotect_241_0226.dll Asprotect_251_0922.dll

DWORD_00h + 00h + 12h

DWORD_04h + 04h + 0Eh

BYTE_08h + 08h + 17h

BYTE_09h + 09h + 05h

BYTE_0Ah + 0Ah + 08h

BYTE_0Bh + 0Bh + 01h

BYTE_0Ch + 0Ch + 16h

DWORD_0Dh

+ 0Dh + 0Ah

BYTE_11h + 11h + 00h

BYTE_12h + 12h + 02h

BYTE_13h + 13h + 03h

BYTE_14h + 14h + 09h

BYTE_15h + 15h + 06h

BYTE_16h + 16h + 07h

BYTE_17h + 17h + 04h

Давайте заполним эту таблицу для нашего подопытного файла Asprotect_251_0922.dll.

Итак, первое значение:

В Asprotect_241_0226.dll мы находим четыре аналогичные ссылки:

Page 77: распаковка Asprotect

Распаковка программ, защищенных Asprotect 77

© <2009> <Некрылов Валентин>

Какая же из ссылок соответствует нашему значению. Для этого посмотрим, из какойветки VM вызывается наша инструкция. Это легко сделать, поскольку отладчик, прианализе программы, показывает в справочном окне, откуда вызываетсяподпрограмма:

Переходя в отладчике по этим ссылкам в справочном окне, мы очень быстроприходим сюда:

Событие 72h соответствует событию 9Ah в Asprotect_241_0226.dll. Выполниваналогичные переходы в этой DLL, мы обнаруживаем, что значение + 05hсоответствует значению + 09h. Убираем маркеры с найденных соответствий.

Второе значение:

Page 78: распаковка Asprotect

Распаковка программ, защищенных Asprotect78

© <2009> <Некрылов Валентин>

Нам оно не интересно, поскольку здесь указывается адрес массива данных дляследующей эмулированной инструкции (для каждой эмулированной инструкцииразмер блока данных четко фиксирован – 18h байтов). Поэтому просто удаляем этотмаркер.

Третье значение:

В Asprotect_241_0226.dll мы находим две аналогичные ссылки:

Опять переходим в отладчике по ссылкам в справочном окне, и очень быстроприходим сюда:

Этот байт является флажком для включения второй VM, в которой выполняютсяэмулированные инструкции MOV, ADD и SUB. Т.е., значение + 16h соответствуетзначению + 0Ch. Убираем маркеры с найденных соответствий.

Четвертое значение:

Page 79: распаковка Asprotect

Распаковка программ, защищенных Asprotect 79

© <2009> <Некрылов Валентин>

В Asprotect_241_0226.dll мы находим одну аналогичную ссылку (здесь правдаимеется и вторая ссылка, начало которой одинаково с этой ссылкой, однако далееидет очень сильное отличие):

Таким образом, значение + 0Eh соответствует значению + 04h. Убираем маркеры снайденных соответствий.

Пятое значение:

В Asprotect_241_0226.dll мы находим одну аналогичную ссылку (именно об этойссылке я указывал в четвертом значении, и эта ссылка имеет сильное отличие):

Таким образом, значение + 12h соответствует значению + 00h. Убираем маркеры снайденных соответствий.

Шестое значение:

Опять переходим в отладчике по ссылкам в справочном окне, и очень быстроприходим сюда:

Page 80: распаковка Asprotect

Распаковка программ, защищенных Asprotect80

© <2009> <Некрылов Валентин>

Таким образом, значение + 04h соответствует значению + 17h. Убираем маркеры снайденных соответствий.

Седьмое значение:

В Asprotect_241_0226.dll у нас осталась только одна аналогичная ссылка:

Таким образом, значение + 09h соответствует значению + 14h. Убираем маркеры снайденных соответствий. Здесь нужно отметить, что за этими ссылками идет ссылка+ 10h, которая соответствует значению + 15h. Прямого указания на эти адреса нет, аимеется указатель INC AL. По адресам + 09h (+ 14h) находится первая половиназакриптованного первого байта опкода эмулированной инструкции (здесь речь идетоб инструкциях с опкодом типа 66:8B4346). Причем здесь записана первая половина(8h) закриптованного байта 8Bh. А вторая половина этого закриптованного байта (Bh) как раз и определяется инструкцией INC AL. В вышеприведенной таблице такиепарные значения выделены Желтым цветом.

Далее у нас отмечены инструкции, которая находятся перед входом во вторую VMдля выполнения эмулированных инструкций:

Page 81: распаковка Asprotect

Распаковка программ, защищенных Asprotect 81

© <2009> <Некрылов Валентин>

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

А вот далее идут нужные для нас адреса:

Page 82: распаковка Asprotect

Распаковка программ, защищенных Asprotect82

© <2009> <Некрылов Валентин>

В Asprotect_241_0226.dll:

Таким образом, значение + 00h соответствует значению + 11h, значение + 02hсоответствует значению + 12h, значение + 01h соответствует значению + 0Bh, изначение + 06h соответствует значению + 15h. Последнее значение также имеетпарное значение, поскольку оно является первой половиной байта опкодаэмулированной инструкции, поэтому значение + 07h соответствует значению + 16h.Убираем маркеры с найденных соответствий.

Тринадцатое значение:

Опять переходим в отладчике по ссылкам в справочном окне, и очень быстроприходим сюда:

Таким образом, значение + 08h соответствует значению + 0Ah. Убираем маркеры снайденных соответствий.

Четырнадцатое значение:

Page 83: распаковка Asprotect

Распаковка программ, защищенных Asprotect 83

© <2009> <Некрылов Валентин>

Поскольку в Asprotect_241_0226.dll осталась выделенной только одна ссылка, то мыпопадаем сюда:

Таким образом, значение + 17h соответствует значению + 08h. Убираем маркеры снайденных соответствий.

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

Входим в CALL 00EFA340:

Page 84: распаковка Asprotect

Распаковка программ, защищенных Asprotect84

© <2009> <Некрылов Валентин>

В Asprotect_241_0226.dll:

Таким образом, значение + 0Ah соответствует значению + 0Dh. Убираем маркеры снайденных соответствий.

2.9.5 Получение таблицы расположения данных в массиве дляэмулированных инструкций, выполняемых во второй VM

Итак, мы закончили поиск соответствий в первой VM для выполненияэмулированных инструкций, и нам надо найти соответствия во второй VM.

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

Входим в CALL 00EF544C, видим несколько инструкций CALL 00EF4E6C, которыеи определяют, что должна делать эта вторая VM:

Page 85: распаковка Asprotect

Распаковка программ, защищенных Asprotect 85

© <2009> <Некрылов Валентин>

Следует отметить, что во всех предыдущих выпусках Asprotect, разработчики неменяли вторую VM, но, начиная с Asprotect v1.51 build 09.22 и Asprotect v2.51 SKEbuild 09.22, они изменили порядок расположения данных в массиве данных, иидентификаторы выполняемых инструкций.

Давайте в заголовке массива для программы Asprotect v2.41 SKE build 02.26,пройдем на адрес, выделенный Золотистым цветом (который указывает конецмассива данных для эмулированных инструкций, которые выполняются во второйVM). Теперь немного прокрутим дамп вверх, до появления значений FFFFFFFF,которые обозначают конец массива данных для эмулированных инструкций,выполняемых в первой VM, и увидим следующее:

На рисунке Красным цветом выделен конец массива данных для эмулированныхинструкций, выполняемых в первой VM, Ярко-зеленым цветом выделены данныедля первой эмулированной инструкции, выполняемой во второй VM, а Бирюзовымцветом выделены данные для второй эмулированной инструкции, выполняемой вэтой же VM. Размер данных для каждой эмулированной инструкции жесткофиксирован, и составляет 0Dh байтов.

Именно в этом массиве данных, разработчики изменили порядок их расположениядля каждой эмулированной инструкции. Указатель на массив данных для текущейвыполняемой эмулированной инструкции записан в регистрах ESI и EDI, поэтомувнимание надо обращать на эти регистры (для того, чтобы не загромождать лишнийраз текст рисунками, я приведу необходимые места только для Asprotect v2.51 SKEbuild 09.22):

Page 86: распаковка Asprotect

Распаковка программ, защищенных Asprotect86

© <2009> <Некрылов Валентин>

Таблица соответствия данных в массиве для эмулированных инструкций,выполняемых во второй VM, будет следующей:

Параметр Зашифрованные значения

Asprotect_241_0226.dll Asprotect_251_0922.dll

BYTE_00h + 00h + 00h

BYTE_01h + 01h + 0Ch

BYTE_02h + 02h + 05h

BYTE_03h + 03h + 06h

BYTE_04h + 04h + 0Bh

Page 87: распаковка Asprotect

Распаковка программ, защищенных Asprotect 87

© <2009> <Некрылов Валентин>

BYTE_05h + 05h + 07h

BYTE_06h + 06h + 08h

BYTE_07h + 07h + 09h

BYTE_08h + 08h + 0Ah

BYTE_08h + 09h + 01h

BYTE_0Ah + 0Ah + 02h

BYTE_0Bh + 0Bh + 03h

BYTE_0Ch + 0Ch + 04h

2.9.6 Получение таблицы идентификаторов эмулированных инструкций,выполняемых во второй VM

Ниже кода извлечения данных из массива, располагается проверка идентификатороввыполняемых эмулированных инструкций и последнее извлекаемое значение измассива данных:

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

Page 88: распаковка Asprotect

Распаковка программ, защищенных Asprotect88

© <2009> <Некрылов Валентин>

инструкций, который на рисунке помечен как EDI+0.

Таблица соответствия идентификаторов выполняемых эмулированных инструкцийво второй VM будет следующей:

Инструкция Зашифрованные значения

Asprotect_241_0226.dll Asprotect_251_0922.dll

CMP BYTE [EBP-1D],0 00h 05h

CMP BYTE [EBP-1D],6 06h 00h

CMP BYTE [EBP-1D],8 08h 07h

CMP BYTE [EBP-1D],5 05h 04h

CMP BYTE [EBP-1D],9 09h 09h

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

2.9.7 Корректировка кода VM для восстановления эмулированныхинструкций в коде программы

Поскольку объем корректировки кода VM для восстановления эмулированныхинструкций достаточно большой, и можно легко сделать ошибку в этой работе, янаписал скрипт “Корректировка VM для восстановления эмулированныхинструкций в коде программы.osc”, который прекрасно справляется с этой задачей.При использовании этого скрипта придется немного поработать руками, вводяданные из таблиц соответствий, которые мы ранее составили. Скрипт состоит издвух частей:1. Первая часть скрипта предназначена для получения дампов таблиц соответствий,

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

VM, и изготавливает бинарный файл VM, с помощью которого работает скрипт “Восстановление эмулированных подпрограмм в коде программы.osc”.

Для выполнения этой работы необходимо:1. Скопировать файл “main_parameters.bin” в папку, где находится этот скрипт.2. Скопировать файл “VM_recovery_main_code.exe” в эту же папку.3. Загрузить файл “VM_recovery_main_code.exe” в отладчик OllyDbg.

Теперь можно начать корректировку VM для восстановления эмулированныхинструкций. В скрипте я привел примеры таблиц соответствия в том порядке, вкотором будут скриптом создаваться дампы этих таблиц:1. Таблицу закриптованных значений первого байта опкода.2. Таблица параметров заголовка массива данных.

Page 89: распаковка Asprotect

Распаковка программ, защищенных Asprotect 89

© <2009> <Некрылов Валентин>

3. Таблица массива данных для эмулированных инструкций.4. Таблицу массива данных для второй VM.5. Таблица идентификаторов инструкций для второй VM.

Я обычно копирую все эти таблицы в вышеуказанном порядке в Блокнот,разворачиваю его на весь экран, открываю окно скриптов plugin ODbgScript,загружаю скрипт “Корректировка VM для восстановления эмулированныхинструкций в коде программы.osc”, и запускаю его. В появляющиеся окна вводаввожу данные из таблиц для распаковываемой программы. После ввода последнегопараметра, появляется сообщение с предложением проверить корректностьвведенных данных.

Когда введены все данные из этих пяти таблиц, скрипт показывает сообщение спредложением ввести имя VM, которая будет использована в скрипте “Восстановление эмулированных подпрограмм в коде программы.osc”. Я обычноиспользую в качестве имени VM имя самой распаковываемой программы спрефиксом VM. Но это – уже дело вкуса. После чего скрипт создает бинарный дампVM, которая восстанавливает все эмулированные инструкции в коде программы.

Приложение: Скрипт для корректировки VM, которая восстанавливает эмулированныеинструкции в коде программы - “Корректировка VM для восстановленияэмулированных инструкций в коде программы.osc”.

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

Итак, благодаря титаническим усилиям, описанным в части 5 выпуска 2 данногоцикла статей, мы создали бинарный файл VM для восстановления эмулированныхинструкций в коде распаковываемой программы. Если нам пришлось перезагружатьпрограмму, то мы должны сначала запустить скрипт “Восстановление таблицы IATи вызовов APIs.osc”, и теперь, в любой последовательности, скрипты “ЭмуляцияAPIs Asprotect, вызываемых из кода программы.osc”, “Устранение проверкицелостности кода (CRC) программы.osc” и “Восстановление эмулированныхподпрограмм в коде программы.osc”.

Скрипт “Восстановление эмулированных подпрограмм в коде программы.osc” какраз и использует бинарный файл VM для восстановления эмулированныхинструкций в коде распаковываемой программы. Этот скрипт находит в кодепрограммы эмулированные инструкции, и восстанавливает их. Поиск этихинструкций скрипт производит по маске “68????????68????????68????????E8”, икогда находит такую цепочку байтов, то определяет, в какую область памяти прыгаетинструкция CALL, которая находится после трех инструкций PUSH. И, если прыжоквыполняется в область памяти, где находится Asprotect.dll (т.е., на VM длявыполнения эмулированных инструкций), то скрипт распознает найденный адрескак эмулированные инструкции, и начинает процесс восстановления их

Page 90: распаковка Asprotect

Распаковка программ, защищенных Asprotect90

© <2009> <Некрылов Валентин>

оригинального кода.

Сам процесс восстановления оригинального кода выполняется очень быстро, а вотпроцесс поиска эмулированных инструкций осуществляется достаточно медленно,особенно кода программа имеет много инструкций PUSH, в конце которых находитсяинструкция CALL. Иногда может возникнуть подозрение, что программа зависла,поскольку компьютер может не реагировать до 1 минуты. Однако это не так, простоскрипт перебирает все встреченные им инструкции, указанные в маске, и выполняетих оценку. Поэтому наберитесь терпения, и немного подождите. В результате Выполучите следующее:

На этом рисунке мы видим код подпрограммы до работы скрипта. А после егоработы мы видим следующее:

Как видно из приведенного рисунка, оригинальный код эмулированных инструкцийполностью восстановлен.

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

Page 91: распаковка Asprotect

Распаковка программ, защищенных Asprotect 91

© <2009> <Некрылов Валентин>

корректный вид. Ведь мы могли где-то допустить ошибку при корректировке кодаVM (причиной может быть ошибка при вводе данных в скрипт “Корректировка VMдля восстановления эмулированных инструкций в коде программы.osc”, илиошибка при создании таблиц соответствия распаковываемой и базовой программ).Если к восстановленному коду у Вас нет замечаний, тогда запускайте скрипт, ивосстанавливайте все подпрограммы с эмулированными инструкциями. Если же уВас имеются замечания, то тогда найдите и устраните допущенные ошибки.

Приложение: Скрипт для восстановления оригинального кода эмулированных инструкций - “Восстановление эмулированных подпрограмм в коде программы.osc”.

2.10 Восстановление секции импорта в распаковываемойпрограмме

Итак, к этому моменту у нас должно быть выполнено следующее:1. Распаковываемая программа загружена в отладчик OllyDbg, и в ней

восстановлены таблица IAT и вызовы эмулированных APIs. 2. Выполнена эмуляция APIs Asprotect.3. Удалены все проверки целостности кода (CRC).4. Восстановлены все эмулированные инструкции в распаковываемой программе.

И теперь мы можем приступить к восстановлению секции импорта враспаковываемой программе. Для этих целей имеется прекрасная утилита ImportREConstructor, которая прекрасно справляется с этой задачей. Но мне не нравится,что она секцию импорта прикручивает к концу распаковываемого файла, а ведь нам,для красоты, нужно удалить секции, созданные протектором Asprotect, которые ужене нужны в распакованной программе. Мне очень понравился скрипт,разработанный pavka, который позволяет манипулировать секцией импорта, ивосстановить ее на то место, где она находилась до защиты программы протекторомAsprotect. Правда, следует отметить, что утилита Import REConstructor, работаетнамного быстрее, чем скрипт, но, как говорят в народе, “красота требует жертв”, иможно затратить немного времени на то, чтобы получить красивый распакованныйфайл. В этом разделе я опишу два метода восстановления секции импорта:1. С помощью скрипта от pavka.2. С помощью утилиты Import REConstructor.

2.10.1 Восстановление секции импорта с помощью скрипта “Восстановлениесекции импорта (.idata) в распакованных программах.osc”

Немного раньше, я вкратце описал, что такое таблица IAT, и что такое таблицаИмпорта. Там же были приведены рисунки, которые иллюстрировали таблицу IAT итаблицу Импорта для программ, скомпилированных компиляторами Borland Delphiи Microsoft Visual C++ | C/C++. Давайте теперь посмотрим на таблицу IAT и таблицу Импорта в программах, защищенных Asprotect.

Page 92: распаковка Asprotect

Распаковка программ, защищенных Asprotect92

© <2009> <Некрылов Валентин>

Для программы Asprotect v2.51 SKE build 09.22, которая написана на Borland Delphi, мы видим:

Здесь показана таблица Импорта, которая находится перед таблицей IAT (здесьпрограмма остановлена на SBOEP с помощью скрипта “Поиск OEP (SBOEP).osc”), вней не восстановлена таблица IAT и вызовы эмулированных APIs. Как видим,таблица Импорта протектором не повреждена. Здесь разными цветами выделеныданные, которые относятся к разным DLLs, используемых данной программой.Кстати, здесь можно определить размер таблицы Импорта, который равен 1E0hбайтов.

Теперь спустимся немного ниже, на таблицу IAT:

На этом рисунке Ярко-зеленым цветом выделены данные в таблице Импорта дляпоследней DLL, используемой программой, Бирюзовым цветом выделеныразделительные ноли между таблицей Импорта и таблицей IAT. Желтым цветомвыделены данные в таблице IAT, которые относятся к первой DLL, используемойэтой программой, а Сиреневым цветом выделены переадресованные API.

А если мы спустимся в конец таблицы IAT, то там увидим следующее:

На этом рисунке Розовым цветом выделены разделительные ноли между DLLs,Ярко-зеленым и Бирюзовым цветами выделены адреса API из разных DLLs. А Желтым цветом выделен мусорный код, которым протектор заполнил область, где

Page 93: распаковка Asprotect

Распаковка программ, защищенных Asprotect 93

© <2009> <Некрылов Валентин>

были записаны имена DLLs и APIs.

А если мы посмотрим в заголовок файла на адрес, где записаны параметры таблицыИмпорта, то там увидим следующее:

Протектор изменил данные таблицы Импорта, и указывает ее адрес – 0060EC48 (0020EC48 + 00400000), и размер – 4C0h байтов (вместо 1E0h байтов).

Давайте посмотрим, что имеется по адресу 0060EC48:

Здесь мы видим традиционную таблицу Импорта (стандарт PE-файла ненарушается), но с очень интересными ссылками. Самая первая ссылка находится чутьвыше таблицы Импорта:

И по этой ссылке мы видим имя библиотеки – kernel32.dll, и имена трех APIs из этойбиблиотеки. А если мы пройдем по ссылкам второй записи в таблице Импорта, тоувидим:

По первому адресу мы видим сгруппированные имена всех библиотек, а по второмуадресу:

Page 94: распаковка Asprotect

Распаковка программ, защищенных Asprotect94

© <2009> <Некрылов Валентин>

Сначала идет несколько адресов APIs на нашей машине, а затем несколько имен APIs.И все.

Теперь давайте посмотрим, а что делает протектор с секцией импорта в программах,скомпилированных на Microsoft Visual C++ | C/C++. В качестве подопытнойпрограммы возьмем программу SpiderMan.

Здесь, в начале секции импорта, сначала расположена таблица IAT. Здесь пока нетпереадресованных APIs, которые находятся немного ниже, в других библиотеках.Теперь давайте попытаемся найти таблицу Импорта, для чего выполним двоичныйпоиск первого адреса из таблицы IAT, вычитая из него ImageBase программы:

0048F000 – 00400000 = 0008F000

Обратный порядок байтов для двоичного поиска – 00F00800. К нашему сожалению,этот адрес три раза записан в данной программе. Тогда попробуем первый адрес изтаблицы IAT для второй библиотеки:

0048F01C – 00400000 = 0008F01C

Обратный порядок байтов для двоичного поиска – 1CF00800. И этот адрес записантолько один раз (я еще раз хочу напомнить, что в таблице Импорта ссылка на адресочередной библиотеки в таблице IAT записывается в конце области, выделенной дляданной библиотеки):

Page 95: распаковка Asprotect

Распаковка программ, защищенных Asprotect 95

© <2009> <Некрылов Валентин>

На рисунке Сиреневым цветом выделен найденный адрес таблицы IAT, а Ярко-зеленым и Бирюзовым цветами выделены данные для двух библиотек. Очевидно, чтомы находимся в таблице Импорта, и достаточно легко, зная ее устройство, можнонайти начало этой таблицы. Для этого прокручиваем дамп немного вверх:

Как видно из рисунка, таблица Импорта начинается с адреса 004C67F0. Здесь такжеможно очень легко определить ее размер (по последним разделительным нулям вконце таблицы Импорта, не забывая о том, что для каждой записи отводится место в 14h байтов) – 17Ch байтов. Т.е., и здесь протектор не повреждает таблицу Импорта.

За таблицей Импорта следует блок указателей на Original First Thunk, а послеблока этих указателей, идет область с именами DLLs и APIs. У нас мы видимследующее:

На рисунке Ярко-зеленым цветом выделены данные для последней библиотеки втаблице Импорта, Бирюзовым цветом – разделительные ноли перед блокомуказателей на Original First Thunk, а вместо указателей на Original First Thunk, мывидим мусорный код. И этот мусорный код находится также в области записи именбиблиотек и APIs.

Значит, поскольку протектор не повреждает таблицу Импорта, то мы можем найтиее начало и размер. Затем, после последних разделительных нолей таблицы Импорта, мы можем удалить мусорный код, и на его месте записать восстановленные именабиблиотек и APIs. В итоге, мы можем получить полностью восстановленную секциюимпорта в распакованном файле, без прикручивания дополнительной секции, чтоделает Import REConstructor.

Именно для этих целей и предназначен скрипт “Восстановление секции импорта (.idata) в распакованных программах.osc”, который разработан pavka, и доработанмной. Этот скрипт адаптирован для восстановления секции импорта враспакованных программах, написанных на Borland Delphi и Microsoft Visual C++ |C/C++. Причем, если программа написана на Borland Delphi, то скрипт сам

Page 96: распаковка Asprotect

Распаковка программ, защищенных Asprotect96

© <2009> <Некрылов Валентин>

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

Если же программа написана на Microsoft Visual C++ | C/C++, то скрипт запроситВас указать адрес начала таблицы Импорта, после чего он сам определит размертаблицы Импорта, а также область, куда будут записываться имена библиотек иAPIs. При этом скрипт полностью очищает от мусорного кода секцию импорта как впрограммах, написанных на Borland Delphi, так и в программах, написанных наMicrosoft Visual C++ | C/C++.

После восстановления секции импорта, скрипт дампирует память распакованнойпрограммы, и прописывает в PE-заголовок файла данные о таблице Импорта, и Выполучаете полностью распакованный файл. В этом файле восстановлены всеэмулированные инструкции, выполнена эмуляция APIs Asprotect, удалены всепроверки целостности кода программы (CRC), не говоря уже о том, что враспакованной программе полностью восстановлена секция импорта. И, если бы небыло украденного кода, который выполняется в специально выделенныхпротектором областях памяти, то такой файл мог бы нормально запуститься, иработать. Именно по этой причине, этот скрипт нужно запускать последним, послевыполнения всех предыдущих скриптов.

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

1. Отладчик не всегда определяет имена APIs, используемые программой. Так,например, на этом рисунке я привожу таблицу IAT, в котором отладчик неопределил имя двух APIs:

Здесь отладчик не указывает имена APIs WSAGetLastError и WSARecvEx, которыенаходятся в библиотеке wsock32.dll. Естественно, что скрипт здесь сделает сбой всвоей работе. Для этих целей, я ввел в скрипт проверку определения имени API ибиблиотеки, и выдачу соответствующего сообщения Пользователю. В этом случае, ярекомендую параллельно применить Import REConstructor, который распознает

Page 97: распаковка Asprotect

Распаковка программ, защищенных Asprotect 97

© <2009> <Некрылов Валентин>

такие имена, и Вы можете вручную ввести имя API или библиотеки, после чегоскрипт продолжит свою работу. Возможно, что кому-то это покажется неудобным,но, в таком случае, имеется утилита Import REConstructor, которая прикрутитсекцию импорта к концу распакованного файла. Правда, pavka подсказал такоерешение: перед запуском этого скрипта нужно открыть карту памятираспаковываемой программы, нажав кнопку М на панели кнопок отладчика. Послеэтого имена библиотек и APIs определяются нормально.

2. Иногда, после работы скрипта, и попытке загрузки полученного дампа в отладчик,Вы можете получить такое сообщение:

Причиной этой ошибки является то, что полное имя этой DLL - SLA_Challenge.dll –0Dh символов (до расширения файла .dll), а Windows имеет ограничение на длинуимени – 8h символов, и при получении имени DLL считывается только 8h символов.Естественно, что загрузчик импорта не находит DLL с таким именем, и показываетошибку. Для устранения таких ошибок, я ввел в скрипт фильтр, который всегдаможно добавлять и корректировать, при необходимости:

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

Page 98: распаковка Asprotect

Распаковка программ, защищенных Asprotect98

© <2009> <Некрылов Валентин>

изменять или переносить куда-либо таблицу IAT, хотя в первом цикле статей ярекомендовал это делать с помощью утилиты Universal Import Fixer v1.2. Дело втом, что мне попадались программы, особенно защищенные заказными версиямипротектора, которые в украденном и замусоренном коде вызывали APIs из таблицыIAT. Найти такие вызовы было очень сложно, а при перестроенной таблице IAT,такая программа просто не работала, и показывала сообщения о своем сбое. Поэтому,поскольку Asprotect не повреждает таблицу IAT, как это делает, например, Armadillo,то целесообразно ее не трогать.

Приложение: Скрипт для восстановления секции импорта в распакованном файле - “Восстановление секции импорта (.idata) в распакованных программах.osc”.

2.10.2 Восстановление секции импорта с помощью утилиты ImportREConstructor

Если Вы решили, что восстанавливать секцию импорта на ее родное место для Васне интересно, и решили использовать для этих целей утилиту Import REConstructor,то скрипт “Восстановление таблицы IAT и вызовов APIs.osc” предоставляет Вамнеобходимую справочную информацию для этой утилиты:

Я не рекомендую на этом этапе восстанавливать таблицу Импорта для программ,написанных на Borland Delphi, поскольку целесообразно секцию импорта, которуюсоздает Import REConstructor, размещать после секции файла с украденным кодом(Stolen Code). При этом целесообразно удалить две последние секции файла, которыйсоздает протектор Asprotect при защите программы. Но об этом мы поговоримнемного позже.

А вот для программ, написанных на Microsoft Visual C++ | C/C++ (а также и надругих языках программирования, в которых компилятор создает отдельную областьдля таблицы Импорта и имен библиотек и APIs), здесь можно восстановить импорт,разместив его на родное место. Как это сделать, я покажу на примере программыSpiderMan, о которой мы уже говорили немного выше.

Итак, после выполнения скриптов “Восстановление таблицы IAT и вызовов APIs.osc”, “Эмуляция APIs Asprotect, вызываемых из кода программы.osc”, “Устранениепроверки целостности кода (CRC) программы.osc” и “Восстановлениеэмулированных подпрограмм в коде программы.osc”, у нас имеется два файлараспакованной программы с именами “dumped.exe” и “dumped_control.exe”. Работатьмы будем с файлом “dumped.exe”, а файл “dumped_control.exe” оставим для

Page 99: распаковка Asprotect

Распаковка программ, защищенных Asprotect 99

© <2009> <Некрылов Валентин>

восстановления секции ресурсов. В файле “dumped.exe” этими скриптами уже удаленадрес Import Table из РЕ-заголовка, поэтому этот файл нормально загружается вотладчик OllyDbg. Загружаем этот файл в отладчик, и находим в нем таблицуИмпорта способом, который я описал немного выше (она находится в этом файле поадресу 004C67F0). Выделяем весь блок от этого адреса и до конца секции, ивыбираем команду заполнения выделенного блока нолями:

Таким образом мы очистили от мусорного кода всю область, в которую утилитаImport REConstructor запишет имена библиотек и APIs. Сохраняем эти изменения вфайле:

И выгружаем этот файл из отладчика.

Теперь запускаем утилиту Import REConstructor, и подключаем ее к запущенномупроцессу:

Вводим в соответствующие окна значения начала таблицы IAT, и ее размер, апараметр OEP мы оставим без изменения, который откорректируем позже:

Page 100: распаковка Asprotect

Распаковка программ, защищенных Asprotect100

© <2009> <Некрылов Валентин>

И нажимаем кнопку “Get Imports”. Затем нажимаем кнопку “Show Invalid”, и удаляемссылки на APIs Asprotect (если они имеются).

Вводим найденный адрес таблицы Импорта, сняв флажок “Add New Section”:

И нажимаем кнопку “Fix Dump”. В появившемся окне выбираем наш исправленныйфайл “dumped.exe”, и нажимаем кнопку “Открыть”:

И утилита Import REConstructor сохранила этот файл с именем “dumped_.exe”. Еслимы откроем этот файл в отладчике, и пройдем на адрес таблицы Импорта, тоувидим:

Здесь мы видим восстановленную таблицу Импорта. А ниже этой таблицы мывидим:

Page 101: распаковка Asprotect

Распаковка программ, защищенных Asprotect 101

© <2009> <Некрылов Валентин>

Здесь мы видим имена библиотек и APIs. И, на всякий случай, проверяем, записаныли имена библиотек и APIs, для чего переходим на таблицу IAT, и выбираем команду“Вид исполняемого файла”:

Мы видим, что утилита Import REConstructor откорректировала все ссылки насозданную ее область имен библиотек и APIs в распакованном файле.

В программах, написанных на Borland Delphi, между таблицей Импорта и областьюс именами библиотек и APIs, расположена таблица IAT. Поэтому, если оставитьтаблицу Импорта на ее родном месте, то Import REConstructor повредит таблицуIAT, а если разместить таблицу Импорта ниже таблицы IAT, то для записи именбиблиотек и APIs просто не хватит места, и эта область будет заполнена неполностью. Было бы неплохо откорректировать Import REConstructor, и ввести внего еще одно окно для ввода области, в которую бы он записывал имена библиотеки APIs.

2.11 Борьба с переносом кода в специальные области памяти

В предыдущих частях этого цикла статей мы научились восстанавливать таблицуINIT, вызовы эмулированных APIs, подпрограммы с эмулированнымиинструкциями, эмулировать APIs Asprotect, и восстанавливать секцию импортапрограммы. После всех этих действий мы получили дампы памяти программы сименем dumped.exe и dumped_control.exe, которые бы можно было бы запускать накомпьютере. Но, к нашему сожалению, протектор применяет еще один метод анти-дампирования – это перенос кода программы в специально выделенные областипамяти, и выполнение этого кода в этих областях памяти (так называемыйукраденный код).

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

Page 102: распаковка Asprotect

Распаковка программ, защищенных Asprotect102

© <2009> <Некрылов Валентин>

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

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

2.11.1 Поиск подпрограммы адресации прыжков в области памяти Asprotect исоздание таблицы прыжков

Во всех версиях Asprotect.dll используется одна и та же подпрограмма адресациипрыжков в области памяти Asprotect. Эта подпрограмма записывает в кодпрограммы прыжки на области памяти, создаваемые протектором Asprotect. Длянаших целей интерес представляет следующая часть этой подпрограммы:

Когда программа остановлена на этой волшебной точке, то в регистре EBX записанадрес расположения прыжка в области кода программы, а в регистре ECX записанадрес назначения этого прыжка:

Page 103: распаковка Asprotect

Распаковка программ, защищенных Asprotect 103

© <2009> <Некрылов Валентин>

Найти эту волшебную точку можно по байтам опкода следующих инструкций: "MOVBYTE PTR DS:[EBX],0E9" и "LEA EDX,DWORD PTR DS:[EBX+1]".

Целесообразно записать адреса расположения прыжков и адреса соответствующихобластей памяти со Stolen Code в таблицу, которая нам потребуется дляпереадресации этих прыжков. Эту задачу, наряду с другими задачами выполняетскрипт “Поиск областей со Stolen Code и восстановление в них эмулированныхинструкций.osc”:

На этом рисунке Ярко-зеленым цветом выделены адреса расположения прыжков вобласти кода программы, а Бирюзовым цветом выделены адреса областей со StolenCode, на которые выполняются эти прыжки.

Примечание:Здесь я привел рисунок таблицы прыжков для другой программы,защищенной протектором Asprotect, а не для программы Asprotectv2.51 SKE build 09.22, поскольку разработчики этого протекторасейчас практически не применяют этот метод защиты, а широкоприменяют использование подпрограмм с эмулированнымиинструкциями.

После записи всех прыжков, скрипт дампирует таблицу прыжков, и сохраняет ее сименем "table_JMP.bin". Здесь я еще раз хочу подчеркнуть, что разработчикипротектора, для защиты своего программного продукта, очень интенсивноиспользуют эмуляцию инструкций в большом числе подпрограмм, с которойбороться значительно труднее. Так, например, в последней версии Asprotect 2.52SKE build 12.08 от 12 декабря 2009 г., они не только усложнили защиту VM второготипа, но и значительно увеличили число подпрограмм, содержащих эмулированныеинструкции.

Зачем нам нужен дамп этой таблицы прыжков? Дело заключается в том, что при

Page 104: распаковка Asprotect

Распаковка программ, защищенных Asprotect104

© <2009> <Некрылов Валентин>

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

Приложение: Скрипт для поиска областей со Stolen Code и восстановление в них эмулированныхинструкций - “Поиск областей со Stolen Code и восстановление в нихэмулированных инструкций.osc”.

2.11.2 Поиск адресов массивов данных с эмулированными инструкциями вобластях памяти Asprotect с украденным кодом

Как я уже писал раньше, протектор в максимальной степени пытается усложнитьжизнь cracker's, используя разные опции защиты программы. Одной из таких опцийявляется программная эмуляция следующих инструкций – CALL, JMP, Jcc (условныепрыжки) и CMP+Jcc (инструкции сравнения с условными прыжками). Программнаяэмуляция этих инструкций выглядит так (здесь показана область SBOEPрассматриваемой нами программы):

На этом рисунке стрелками показаны подпрограммы, которые выполняютэмулированные инструкции. Всю информацию, необходимую для выполнения этихинструкций, протектор сохраняет в специальных массивах данных, которыеиспользует VM для выполнения этих эмулированных инструкций. Массив данныхдля эмулированных инструкций имеет следующий вид:

Page 105: распаковка Asprotect

Распаковка программ, защищенных Asprotect 105

© <2009> <Некрылов Валентин>

На этом рисунке Оранжевым цветом выделено значение ImageBase программы,Сиреневым цветом выделено число эмулированных инструкций, Розовым цветомвыделено значение начала области кода протектора с украденным кодом. Синимцветом выделен адрес VM для выполнения эмулированных инструкций, а Желтымцветом выделены адреса инструкций CALL, которые извлекают информацию измассива данных. Серым цветом выделены идентификаторы для указания адресов вмассиве данных, из которых извлекаются значения. И, наконец, Ярко-зеленымцветом выделен начальный адрес массива данных, а Бирюзовым цветом выделенразмер блока данных для каждой эмулированной инструкции. Красным цветомвыделено значение константы, используемой для раскриптовки данных, аКоричнево-зеленым цветом выделен байт, который дает команду на включение VM сдополнительной защитой, которая выполняет эмулированные инструкции.

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

На этом рисунке Бирюзовым цветом размер блока данных для каждойэмулированной инструкции, Красным цветом выделено значение константы,используемой для раскриптовки значений из массива данных, а Сиреневым цветомчисло эмулированных инструкций. Ярко-зеленым цветом выделены байты дляпервой эмулированной инструкции.

Получить адреса массивов данных об эмулированных инструкциях можно наследующей волшебной точке:

Эту волшебную точку можно найти по байтам опкода следующих инструкций: "MOVESI,EAX", "MOV DWORD PTR DS:[EBX+10],ESI", "MOV EAX,DWORD PTR DS:[EBX+C]" и "MOV DWORD PTR DS:[ESI+8],EAX". Поскольку значения константмогут быть разными, то эти инструкции мы ищем по маске "8BF08973??8B43??89".

Адреса массивов данных потребуются для VM, которая будет восстанавливать

Page 106: распаковка Asprotect

Распаковка программ, защищенных Asprotect106

© <2009> <Некрылов Валентин>

оригинальный код эмулированных инструкций CALL, JMP, Jcc и CMP+Jcc.

Скрипт для создания таблицы прыжков и восстановления эмулированныхинструкций с названием “Поиск областей со Stolen Code и восстановление в нихэмулированных инструкций.osc”, состоит из трех частей:- первая часть скрипта создает таблицу прыжков из области кода программы на

области со Stolen Code, и находит адреса массивов данных для эмулированныхинструкций;

- вторая часть скрипта содержит код VM, которая восстанавливает эмулированныеинструкции, и записывает их в конце каждой области с украденным кодом;

- третья часть скрипта также содержит код VM, которая в специально созданнойобласти памяти записывает адреса расположения эмулированных инструкций,рассортированных по их типу - CALL, JMP, Jcc (условные прыжки) и CMP+Jcc(инструкции сравнения с условными прыжками). Эти адреса требуются припереносе кода из областей со Stolen Code в специально создаваемую секциюфайла.

Фактически, в качестве кода VM, используется код VM Asprotect для выполненияэмулированных инструкций, который доработан для восстановления оригинальныхинструкций CALL, JMP, Jcc и CMP+Jcc. Я не буду описывать работу этой VM,поскольку работа VM для выполнения эмулированных инструкций была мнойописана в предыдущих статьях. Здесь же я хочу обратить внимание на следующиемоменты:

1. Asprotect может использовать как обычную VM для выполнения эмулированныхинструкций, так и VM с усиленной защитой. Как правило, VM с усиленнойзащитой имеет эмулированные инструкции. Включение этой VMосуществляется байтом, который находится в массиве данных по адресу 74h отего начала. Если этот байт имеет значение 00h, то используется обычная VM, аесли этот байт имеет значение 01h, то используется VM с усиленной защитой.Поэтому скрипт проверяет значение этого байта, и, если используется VM сусиленной защитой, то корректирует прививку.

2. До появления Asprotect v1.41 build 04.01 и Asprotect v2.41 SKE build 04.01, дляидентификации инструкций CALL, JMP, Jcc (условные прыжки) и CMP+Jcc(инструкции сравнения с условными прыжками), использовались следующиезначения:- 00h – инструкция CALL;- 01h – инструкция JMP;- 02h – инструкция Jcc;- 03h – инструкция CMP+Jcc

В Asprotect v1.41 build 04.01 и Asprotect v2.41 SKE build 04.01 разработчикиприменили другую идентификацию инструкций:

Page 107: распаковка Asprotect

Распаковка программ, защищенных Asprotect 107

© <2009> <Некрылов Валентин>

- 00h – инструкция CMP+Jcc- 01h – инструкция CALL;- 02h – инструкция JMP;- 03h – инструкция Jcc;

3. В Asprotect v1.41 build 04.01 и Asprotect v2.41 SKE build 04.01 также измененаидентификация типов сравнения. Если в предыдущих версиях Asprotectиспользовалась такая идентификация типов сравнения:

ID типасравнения

ЭМУЛИРУЕМОЕ СРАВНЕНИЕ

00 CMP DWORD [АДР_ПАМЯТИ_1],АДР_ПАМЯТИ_2

01 CMP DWORD АДР_ПАМЯТИ_1,PTR DS:[АДР_ПАМЯТИ_2]

02 CMP BYTE PTR DS:[АДР_ПАМЯТИ_1],АДР_ПАМЯТИ_2

03 CMP BYTE АДР_ПАМЯТИ_1,[АДР_ПАМЯТИ_2]

04 CMP DWORD АДР_ПАМЯТИ_1,АДР_ПАМЯТИ_2

То в Asprotect v1.41 build 04.01 и Asprotect v2.41 SKE build 04.01 используетсяследующая идентификация типов сравнения:

ID типа сравнения ЭМУЛИРУЕМОЕ СРАВНЕНИЕ

00 CMP DWORD АДР_ПАМЯТИ_1,АДР_ПАМЯТИ_2

01 CMP DWORD [АДР_ПАМЯТИ_1],АДР_ПАМЯТИ_2

02 CMP DWORD АДР_ПАМЯТИ_1,PTR DS:[АДР_ПАМЯТИ_2]

03 CMP BYTE PTR DS:[АДР_ПАМЯТИ_1],АДР_ПАМЯТИ_2

04 CMP BYTE АДР_ПАМЯТИ_1,[АДР_ПАМЯТИ_2]

Поэтому скрипт проверяет эти изменения, и делает соответствующие корректировкив коде VM для выполнения эмулированных инструкций. Ниже приведены дварисунка, которые иллюстрируют эту проверку:

a) старые версии Asprotect:

Page 108: распаковка Asprotect

Распаковка программ, защищенных Asprotect108

© <2009> <Некрылов Валентин>

b) новые версии Asprotect:

Примечание: Здесь следует отметить, что в последующих версиях Asprotectразработчики опять вернулись к старой идентификации инструкцийCALL, JMP, Jcc и CMP+Jcc. Однако я рекомендую всегда выполнятьпроверку этого байта, поскольку разработчики могут неоднократноменять идентификаторы вышеуказанных инструкций.

Я не буду подробно описывать работу скрипта, поскольку он снабженкомментариями. А работу VM для выполнения эмулированных инструкций Выможете посмотреть, запустив скрипт на распаковке какой-либо программы,упакованной Asprotect, и остановившись на инструкции RUN, записанной послекорректировки кода прививки, выполнить трассирование кода VM.

И еще я бы хотел обратить Ваше внимание на одну очень интересную особенностьAsprotect. Если Asprotect ворует код из области OEP, и переносит его в областьSBOEP, то в конце области SBOEP протектор создает таблицу прыжков из кодапрограммы в область SBOEP. Эта таблица прыжков имеет следующий вид:

На этом рисунке Розовым цветом выделен конец области ссылок, после которогоначинается таблица прыжков. Сиреневым цветом выделены разделительные нулиперед началом таблицы прыжков. Ярко-зеленым цветом выделены значения RVAрасположения прыжков в коде программы (RVA + ImageBase_Programm = AddressJMP), и Бирюзовым цветом выделены RVA дистанции прыжков на области SBOEP(RVA + SBOEP = Address JMP). Так, например, самым первым значением являетсяRVA прыжка, который записан в коде программы по следующему адресу:

000071F0 + 00400000 = 004071F0

Page 109: распаковка Asprotect

Распаковка программ, защищенных Asprotect 109

© <2009> <Некрылов Валентин>

А в коде программы, по этому адресу, мы видим:

Справа, в таблице прыжков, записана дистанция прыжка относительно SBOEPпрограммы. Для нашего примера:

00000179 + 01FD04AA = 01FD0623

И, наконец, Красным цветом выделен очень интересный адрес – адрес концаукраденного протектором кода, и перенесенного в область SBOEP. Этот адрес всегданаходится на расстоянии 0Ch от конца таблицы прыжков, и используется скриптами“Перенос Stolen Code в секцию файла ADATA.osc” и “Перенос Stolen Code в секциюфайла RSRC.osc” для определения размера переносимого кода в дополнительнуюсекцию файла.

Используя эту таблицу прыжков, скрипты “Поиск областей со Stolen Code ивосстановление в них эмулированных инструкций.osc” и “Восстановлениетаблицы IAT и вызовов APIs.osc” определяют адрес OEP в коде программы.

Итак, перезагружаем программу в отладчике, и запускаем скрипт “Поиск областей соStolen Code и восстановление в них эмулированных инструкций.osc”, которыйнаходит все прыжки из области кода программы в области со Stolen Code, ивосстанавливает эмулированные инструкции в этих областях памяти.

2.11.3 Объединение всех областей со Stolen Code в одну секцию файла

Итак, после завершения работы скрипта “Поиск областей со Stolen Code ивосстановление в них эмулированных инструкций.osc”, в программе полностьювосстановлены все эмулированные инструкции в областях со Stolen Code (включая иобласть памяти SBOEP, если она имеется). Кроме того, скриптом также создана исдампирована таблица прыжков из кода программы в области со Stolen Code.Программа остановлена на OEP (или SBOEP) программы, и теперь нам надообъединить все области со Stolen Code в одну область, которая будет являться однойиз секций распакованного файла. Эта объединенная область со Stolen Code в дампераспакованной программы может находиться на месте секции ресурсов файла(секция .rsrc), или на месте предпоследней секции файла, которая созданапротектором (секция .data). Это очень важно для корректной записи всехвосстановленных эмулированных инструкций, адрес назначения которых привязан кначальному адресу конкретной области со Stolen Code.

Для лучшего понимания вышесказанного приведу следующий пример:

Page 110: распаковка Asprotect

Распаковка программ, защищенных Asprotect110

© <2009> <Некрылов Валентин>

На рисунке показана часть кода SBOEP с восстановленными инструкциями CALL.Если мы перенесем этот код, например, на место секции файла .rsrc, то увидимследующее:

Как видно на нижнем рисунке, изменились адреса дистанции инструкций CALL, итакие инструкции просто невозможно выполнить. Естественно, что скрипт долженвыполнить привязку адресов дистанции этих инструкций к конкретной секциифайла. Мной разработаны два скрипта – “Перенос Stolen Code в секцию файлаADATA.osc” и “Перенос Stolen Code в секцию файла RSRC.osc”. Первый скриптвыполняет привязку адресов дистанции инструкций применительно кпредпоследней секции файла, которая создана протектором (секция .data). А второйскрипт выполняет привязку адресов дистанции инструкций применительно к секцииресурсов файла (секция .rsrc). Здесь я оставляю свободу выбора для Пользователя,который распаковывает конкретную программу. Лично я предпочитаю перенос кодаиз областей со Stolen Code выполнять в секцию .rsrc, потому что, при локализации(переводе) ресурсов на другой язык, секция ресурсов увеличивается в размере, иповреждает код в следующей секции. В результате чего, локализованная программапросто не будет работать. Эти скрипты работают следующим образом:- сначала скрипт создает область памяти, размер которой равен сумме размеров все

областей со Stolen Code;- затем скрипт переносит код из всех областей со Stolen Code в созданную область

памяти;- и, наконец, дампирует область памяти с перенесенным кодом.

Скрипты “Перенос Stolen Code в секцию файла ADATA.osc” или “Перенос StolenCode в секцию файла RSRC.osc” нужно запускать сразу же, после завершения работы

Page 111: распаковка Asprotect

Распаковка программ, защищенных Asprotect 111

© <2009> <Некрылов Валентин>

предыдущего скрипта “Поиск областей со Stolen Code и восстановление в нихэмулированных инструкций.osc ”, без перезагрузки программы в отладчике.

После завершения работы этих скриптов, мы получаем следующие дампы:- “table_JMP.bin” – дамп таблицы прыжков из кода программы в области со Stolen

Code;- “table_massive_data.bin” – дамп таблицы адресов массивов данных для

эмулированных инструкций;- “table_ImageBase_Stolen_Code.bin” – дамп таблицы ImageBase и адресов

свободного места областей со Stolen Code;- “section_ASPR_RSRC.bin” или “section_ASPR_ADATA.bin” – дамп новой секции

файла, в котором находится код из всех областей со Stolen Code, и который мыдолжны прикрутить к полученному дампу распакованной программы;

- “table_StolenCode_RSRC.bin” или “table_StolenCode_ADATA.bin” – дамптаблицы соответствия адресов областей со Stolen Code и новой секции файла.

Здесь я хотел бы отметить следующую особенность переноса кода из областей соStolen Code в новую секцию файла. Скрипт “Поиск областей со Stolen Code ивосстановление в них эмулированных инструкций.osc”, записываетвосстановленные инструкции Jcc и CMP + Jcc на свободное место в конце областейсо Stolen Code. Для этого, как правило, свободное место в конце области со StolenCode должно иметь размер примерно 30% от размера области со Stolen Code. Однакобывают случаи, когда область со Stolen Code не имеет нужного размера, поэтомускрипт записывает восстановленные инструкции в последнюю секцию файла (.adata), которая ничем не заполнена, и прекрасно служит для наших целей. Однако здесьвозникает необходимость отдельного переноса данных из последней секции файла (.adata), сразу же, после переноса кода области со Stolen Code, и корректировкидистанции всех прыжков из области со Stolen Code на новый адрес данных изсекции (.adata), и корректировки всех прыжков из секции (.adata) в область со StolenCode. Это потребовало ввода дополнительной прививки в скрипты “Перенос StolenCode в секцию файла ADATA.osc” и “Перенос Stolen Code в секцию файла RSRC.osc”, которая автоматически выполняет все эти действия. Скрипты “Перенос StolenCode в секцию файла ADATA.osc” и “Перенос Stolen Code в секцию файла RSRC.osc” снабжен комментариями, которые объясняют работу, а работу прививок Выможете посмотреть при распаковке любой программы, упакованной Asprotect.

Приложение: Скрипты для переноса областей со Stolen Code в новую секцию распакованногофайла - “Перенос Stolen Code в секцию файла ADATA.osc” и “Перенос Stolen Code всекцию файла RSRC.osc”.

2.12 Сборка распакованного файла

Итак, после выполнения действий, изложенных в предыдущих частях данноговыпуска статей, мы имеем:1. Файлы dumped.exe и dumped_control.exe, в которых восстановлена таблица INIT,

Page 112: распаковка Asprotect

Распаковка программ, защищенных Asprotect112

© <2009> <Некрылов Валентин>

восстановлена секция импорта (таблица Импорта, таблица IAT, и имена DLLs иAPIs), вызовы APIs в коде программы, подпрограммы с эмулированнымиинструкциями, выполнена эмуляция APIs Asprotect, и устранены проверкицелостности кода (CRC).

2. Файлы section_ASPR_RSRC.bin или section_ASPR_ADATA.bin, которыесодержат украденный протектором код с восстановленными эмулированнымиинструкциями CALL, JMP, Jcc (условные прыжки) и CMP+Jcc (сравнение сусловными прыжками).

И теперь нам необходимо прикрутить к файлу dumped.exe файл section_ASPR_RSRC.bin или section_ASPR_ADATA.bin (в зависимости от того какое мы принялирешение). Файл dumped_control.exe нам нужен для восстановления секции ресурсов.

2.12.1 Подготовка файла dumped.exe к прикручиванию секции с украденнымкодом

Итак, первое, что нам надо сделать – это удалить из файла dumped.exe две последниесекции, созданные ASProtect, и секцию ресурсов .rsrc, на место которой мы должныприкрутить секцию section_ASPR_RSRC.bin или section_ASPR_ADATA.bin.

Примечание: В некоторых программах, между секциями .rsrc и .data (созданнойпротектором Asprotect) могут находиться еще другие секции файла,которые также нужно удалить из файла. Эти секции можно затемсдампировать из файла dumped_control.exe, и вставить эти дампы вфайл dumped.exe на их родное место.

Для выполнения этой задачи будем использовать утилиту PE Tools v1.5 RC7:

Page 113: распаковка Asprotect

Распаковка программ, защищенных Asprotect 113

© <2009> <Некрылов Валентин>

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

Page 114: распаковка Asprotect

Распаковка программ, защищенных Asprotect114

© <2009> <Некрылов Валентин>

После этого нам необходимо пройти на вкладку Directory Editor, и откорректироватьзначения Base Relocation Table, и TLS Directory:

На этом рисунке Сиреневым цветом выделены корректируемые значения BaseRelocation Table, а Голубым цветом – корректируемые значения TLS Directory (воригинальной программе адреса этих директорий находятся в секции .data,созданной протектором Asprotect).

Данные этих директорий протектор, при упаковке программы, переносит в своюсекцию из соответствующих секций оригинальной неупакованной программы,поэтому нам нужно просто найти эти данные в оригинальных секцияхраспакованной программы. Для этого загружаем упакованную программу в OllyDbg,и переходим в окне DUMP на адрес 0060EBD4, где находятся данные BaseRelocation Table (а рядом с этими данными находятся данные TLS Directory):

Page 115: распаковка Asprotect

Распаковка программ, защищенных Asprotect 115

© <2009> <Некрылов Валентин>

На этом рисунке Сиреневым цветом выделены значения Base Relocation Table, аГолубым цветом – значения TLS Directory, которые находятся в секции .data,созданной протектором Asprotect.

С помощью функции бинарного поиска отладчика сначала ищем данные BaseRelocation Table в секциях файла на вкладке Memory Map, и находим их по адресу0057289C:

И теперь, помощью функции бинарного поиска отладчика ищем данные TLSDirectory, и находим их по адресу 00588000:

Корректируем значения адресов директорий Base Relocation Table и TLS Directory(не забывая при этом из найденных адресов вычесть значение ImageBaseпрограммы):

2.12.2 Прикручивание секции с украденным кодом к файлу dumped.exe

Теперь мы можем прикрутить к полученному дампу секцию section_ASPR_RSRC.bin(как я писал ранее, я предпочитаю размещать секцию с украденным кодом на местосекции файла .rsrc):

Page 116: распаковка Asprotect

Распаковка программ, защищенных Asprotect116

© <2009> <Некрылов Валентин>

И корректируем имя прикрученной секции (я предпочитаю использовать имя .aspr):

2.12.3 Восстановление секции ресурсов .rsrc

Как известно, протектор крадет несколько ресурсов из секции ресурсов .rsrc, ипереносит их в свою секцию .data. Поэтому нам нужно не только вернуть этиукраденные ресурсы в их родную секцию .rsrc, но выполнить их привязку к новомуRVA, поскольку на месте секции ресурсов мы разместили секцию с украденнымкодом. Для восстановления секции ресурсов мы будем использовать утилитуResource Binder v3.1. Но, перед запуском этой утилиты, мы должны определитьновое значение RVA секции ресурсов. Сделать это довольно просто. Навышеприведенном рисунке, где показана прикрученная секция файла с украденнымкодом, Золотистым цветом выделен VirtualSize прикрученной секции, а Ярко-

Page 117: распаковка Asprotect

Распаковка программ, защищенных Asprotect 117

© <2009> <Некрылов Валентин>

зеленым цветом – VirtualOffset этой секции. Следовательно, VirtualOffset секции .rsrc будет равен:

0019D000 + 00001000 = 0019E000

Теперь запускаем утилиту Resource Binder v3.1, выбираем резервный файлdumped_control.exe, в окне “Действие” выбираем “Создать бинарный файл секцииресурсов”, нажимаем кнопку “Сделать”, и в появившемся окне вводим вычисленноезначение VirtualOffset секции .rsrc:

Утилита работает очень быстро, и мы получаем бинарный дамп секции ресурсов сименем dumped_control0019E000.rsrc.

Теперь можно прикрутить полученный дамп секции ресурсов к файлу dumped.exe, иоткорректировать имя секции ресурсов:

Page 118: распаковка Asprotect

Распаковка программ, защищенных Asprotect118

© <2009> <Некрылов Валентин>

Корректируем новый адрес секции ресурсов на вкладке Directory Editor:

2.12.4 Переадресация прыжков из кода программы на секцию с украденнымкодом .aspr

И теперь нам осталось выполнить переадресацию прыжков из кода программы наприкрученную секцию .aspr. Для этих целей будем использовать скрипт “Перенаправление прыжков из кода программы в новую секцию файла.osc”,который приложен к данной статье. Этот скрипт, в своей работе, используетследующие два дампа:

- “table_JMP.bin” – дамп таблицы прыжков из кода программы в области со StolenCode;

- “table_StolenCode_RSRC.bin” или “table_StolenCode_ADATA.bin” – дамптаблицы соответствия адресов областей со Stolen Code и новой секции файла .aspr.

Этот скрипт загружает в память вышеуказанные два дампа, с помощью специальнойпрививки находит в коде программы адреса прыжков в области со Stolen Code, иизменяет дистанцию этих прыжков. Этот скрипт снабжен комментариями, и ненуждается в каких-либо дополнительных пояснениях. А на работу прививки можнопосмотреть, остановившись на инструкции RUN, и выполнить трассирование кодапрививки.

Итак, загружаем наш файл dumped.exe в отладчик:

Запускаем этот скрипт. После завершения работы скрипта мы видим:

Page 119: распаковка Asprotect

Распаковка программ, защищенных Asprotect 119

© <2009> <Некрылов Валентин>

Теперь выделяем всю область дизассемблированного кода программы, и выбираемкоманду “Copy to executable 0 Selection”.

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

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

Приложение: Скрипт для переадресации прыжков из кода программы в новую секциюраспакованного файла - “Перенаправление прыжков из кода программы в новуюсекцию файла.osc”.

2.12.5 Устранение проверок целостности кода второго типа

Но, к сожалению, не все обстоит так просто. Дело в том, что разработчики данногопротектора предусмотрели еще одну проверку целостности кода (проверка второготипа), которая не определяется скриптом “Устранение проверки целостности кода(CRC) программы.osc”:

На этом рисунке приведена одна такая проверка целостности кода, которая выделенаЗолотистым цветом. В качестве контрольного адреса здесь взят адрес:

00556A64 + 7Ch = 00556AE0

Содержимое этого адреса прибавляется к значению регистра ESI. Если мы пройдемна этот адрес в программе, в которой не восстановлены эмулированные инструкции,

Page 120: распаковка Asprotect

Распаковка программ, защищенных Asprotect120

© <2009> <Некрылов Валентин>

то увидим:

Здесь находится мусорный код. Суммирование двух значений:

48068748 + B7F978B8 = 0000000

И прибавление ноля к значению регистра ESI, не меняет этого значения.

А теперь посмотрим на этот код после восстановления оригинального кодаэмулированных инструкций:

Суммирование двух значений:

B1E8008B + B7F978B8 = 69E17943

И прибавление значения 69E17943 к значению регистра ESI, запишет такое значениерегистра ESI, которого нет в памяти распакованной программы. И программаAsprotect v2.51 SKE build 09.22 имеет 11 таких проверок.

Здесь я хочу привести еще пару рисунков, которые показывают разные вариантыреализации этой проверки целостности кода:

На этом рисунке приведена еще одна такая проверка целостности кода, котораявыделена Золотистым цветом. В качестве контрольного адреса здесь взят адрес

Page 121: распаковка Asprotect

Распаковка программ, защищенных Asprotect 121

© <2009> <Некрылов Валентин>

00550D66. Содержимое этого адреса также прибавляется к значению регистра ESI.Но, как видно из рисунка, здесь, между инструкциями LEA ESI,DWORD PTR DS:[ESI+ECX+F067B3A2] и POP EDX еще расположена инструкция SUB ESI,ECX.

А на этом рисунке приведена еще одна реализация такой проверки:

Здесь, в качестве контрольного адреса здесь взят адрес 004A5909.

Здесь я могу порекомендовать следующий метод поиска таких проверок целостностикода. Для поиска таких мест можно использовать следующие маски: “8D??????????5?EB”, “8D????????????5?EB”, “8D???????????03??5?EB”, “8D????????????03??5?EB”, “8D????????????2B??5?EB”, “8D????????????2B??03??5?EB”. Посленахождения группы инструкций, надо проверить, относятся ли они к проверкецелостности кода, или нет. Если здесь находится проверка целостности кода, то онаустраняется заполнением всей этой области инструкциями NOP (включаябезусловный прыжок JMP, и все мусорные инструкции, находящиеся между этимпрыжком и инструкцией, на которую выполняется этот прыжок):

2.13 Очистка областей со Stolen Code от мусорного кода

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

Page 122: распаковка Asprotect

Распаковка программ, защищенных Asprotect122

© <2009> <Некрылов Валентин>

кода в областях со Stolen Code затрудняет такую проверку, и делает ее несколькотрудоемкой. Для очистки областей со Stolen Code от мусорного кода broncoразработал скрипт, который мной немного доработан, в части добавления ещенекоторых типов мусорных прыжков. Этот скрипт – “Очистка мусорного кода вобластях со Stolen Code.osc” относительно простой. Он выполняет поискбезусловных прыжков по указанным байтам опкода, и заполняет найденныемусорные прыжки инструкциями NOP. Но этот скрипт не удаляет весь мусорный кодиз областей со Stolen Code, поскольку протектор, используя специальныеподпрограммы, по определенному алгоритму разбавляет нужный код мусорнымкодом:

На вышеприведенном рисунке показаны подпрограммы, которые заполняютмусорным кодом области с украденным кодом, при защите программы протекторомAsprotect. Вообще, процесс создания Asprotect.dll, с разными опциями защитыпрограммы, очень интересный процесс, и желающие могут выполнить егоисследование. Ведь очень неплохо можно изучить процессы создания SBOEP,эмуляции разных инструкций, вызовов APIs Asprotect, и т.д., что позволит лучшепонять работу этого замечательного протектора.

Page 123: распаковка Asprotect

Распаковка программ, защищенных Asprotect 123

© <2009> <Некрылов Валентин>

Итак, загружаем наш распакованный файл в отладчик, и запускаем скрипт “Очисткамусорного кода в областях со Stolen Code.osc”. Этот скрипт работает довольнобыстро, и, по завершению его работы, мы получаем следующий вид кода в областяхсо Stolen Code:

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

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

Приложение: Скрипт для очистки мусорного кода в областях со Stolen Code - “Очистка мусорногокода в областях со Stolen Code.osc”.

Page 124: распаковка Asprotect

Top Level IntroThis page is printed before a new

top-level chapter starts

Part

III

Page 125: распаковка Asprotect

Практика распаковки программ 125

© <2009> <Некрылов Валентин>

3 Практика распаковки программ

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

3.1 Распаковка программы Sticky Password v4.0.0.148

Для тренинга я решил привести пример распаковки программы Sticky Passwordv4.0.0.148, которую можно скачать по ссылке http://www.stickypassword.com/files/SP40/stpsinst400148.exe. Эта программа защищена относительно свежей версиейпротектора ASProtect v2.5 build 03.31 Release.

3.1.1 Определение протектора и языка программирования

Процесс распаковки программы мы начинаем с выяснения того, защищена липрограмма каким-либо протектором, и на каком языке программирования онанаписана. Для этого сначала загружаем программу в PEiD v0.95:

Итак, программа упакована Asprotect. Уточняем версию протектора, используяутилиту ASPrINFO v1.6 Beta:

Page 126: распаковка Asprotect

Распаковка программ, защищенных Asprotect126

© <2009> <Некрылов Валентин>

Программа защищена сравнительно свежей версией Asprotect 2.5 SKE build 03.31Release. И теперь нам надо определить компилятор, с помощью которого быласкомпилирована эта программа. Для этого будем использовать утилиту DiE v0.64:

Мы видим, что программа скомпилирована с помощью Borland Delphi.

3.1.2 Определение опций защиты программы

Теперь нам нужно определить, какие опции защиты разработчик применил для своейпрограммы. Для этого загружаем программу в отладчик OllyDbg, и запускаем скрипт“Поиск OEP (SBOEP).osc”. При своей работе, этот скрипт показываетдиагностические сообщения, а все выявленные им опции защиты записывает вжурнал регистрации отладчика:

Page 127: распаковка Asprotect

Практика распаковки программ 127

© <2009> <Некрылов Валентин>

Как видно из полученной информации, защита этой программы весьма слабенькая.Разработчик использовал только эмуляцию вызываемых APIs и вызовы APIsAsprotect. Он даже не защитил таблицу INIT и OEP программы, а также неиспользовал перенос части кода программы в области с украденным кодом (StolenCode). Это намного упрощает процесс распаковки программы. Смотрим на OEPпрограммы:

Как видим, разработчик программы не защитил ее OEP.

3.1.3 Восстановление таблицы IAT и вызовов эмулированных APIs

Ну что же! Приступаем к распаковке программы. Перезагружаем программу вотладчике, и запускаем скрипт “Восстановление таблицы IAT и вызовов APIs.osc”.

Примечание: Если у Вас имеются сомнения о том, повреждена ли таблица INIT,или нет, Вы можете запустить скрипт “Восстановление таблицыINIT.osc”, который Вам покажет сообщение “Было восстановлено‘XXh’ подпрограмм инициализации и деинициализации.”, илисообщение “Программа не имеет таблицу INIT, или она неповреждена протектором.”.

Этот скрипт выполняет следующие действия:

- сначала он восстанавливает таблицу IAT, и определяет ее начало, конец и размер;- затем скрипт восстанавливает вызовы эмулированных APIs;- после этого скрипт восстанавливает эмулированные инструкции, при

дополнительной защите импорта;- вставляет ранее полученный дамп таблицы INIT на ее родное место (файл “

table_INIT.bin”);- сохраняет все основные параметры распаковываемой программы в файле “

main_parameters.bin”, который используется при работе скриптов “Восстановление эмулированных подпрограмм в коде программы.osc”, “Устранение проверки целостности кода (CRC) программы.osc”, “ЭмуляцияAPIs Asprotect, вызываемых из кода программы.osc” и “Восстановление секцииимпорта (.idata) в распакованных программах.osc”.

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

Page 128: распаковка Asprotect

Распаковка программ, защищенных Asprotect128

© <2009> <Некрылов Валентин>

регистрации отладчика:

Здесь мы видим адрес OEP программы, а также адрес начала таблицы IAT, и ееразмер.

3.1.4 Устранение проверок целостности кода CRC) программы

Теперь, не перезагружая программу в отладчике, запускаем скрипт “Устранениепроверки целостности кода (CRC) программы.osc”:

Да, и с проверками целостности кода тоже не густо – всего одна проверка CRC..

3.1.5 Эмуляция APIs Asprotect, вызываемых из кода программы

И опять, не перезагружая программу в отладчике, запускаем скрипт “ЭмуляцияAPIs Asprotect, вызываемых из кода программы.osc”, и смотрим в журналрегистрации отладчика:

Разработчик программы использует три APIs Asprotect – GetRegistrationInformation, CheckKey и GetTrialDays.

3.1.6 Восстановление секции импорта в распакованной программе

И теперь не перезагружая программу в отладчике, запускаем скрипт “Восстановление секции импорта (.idata) в распакованных программах.osc”. Посленескольких минут работы скрипта получаем сообщение:

Page 129: распаковка Asprotect

Практика распаковки программ 129

© <2009> <Некрылов Валентин>

Итак, мы получили два дампа памяти распакованной программы с полностьювосстановленной секцией импорта, эмулированными APIs Asprotect, и устраненнойпроверкой целостности кода (CRC) - "dumped.exe" и "dumped_control.exe".Проверяем, нет ли ошибок при работе скрипта “Восстановление секции импорта (.idata) в распакованных программах.osc”, для чего загружаем файл "dumped.exe" вотладчик (если были допущены какие-либо ошибки, то при загрузке файла "dumped.exe" мы получим сообщение об ошибке):

Программа остановилась не на OEP, а на системной DLL. Это означает, что у нас непрописано значение Entry Point в полученном дампе:

Page 130: распаковка Asprotect

Распаковка программ, защищенных Asprotect130

© <2009> <Некрылов Валентин>

Ну, это легко поправить в PE Tools v1.8.800.2006 RC7:

Опять пытаемся загрузить файл "dumped.exe" в отладчик:

И он, без каких-либо ошибок, нормально загружается в отладчик. Но, очевидно, чтонужно откорректировать скрипт “Восстановление секции импорта (.idata) враспакованных программах.osc”, который должен записать в PE-заголовок значение Entry Point программы.

Page 131: распаковка Asprotect

Практика распаковки программ 131

© <2009> <Некрылов Валентин>

3.1.7 Поиск областей со Stolen Code и восстановление в них эмулированныхинструкций

Итак, несмотря на то, что скрипт “Поиск OEP (SBOEP).osc”, показал, что впрограмме нет областей со Stolen Code, мы все-таки запустим скрипт “Поискобластей со Stolen Code и восстановление в них эмулированных инструкций.osc”,и посмотрим, что он нам покажет:

Итак, распаковываемая программа не имеет областей со Stolen Code, что облегчаетнашу работу.

3.1.8 Подготовка файла dumped.exe к восстановлению секции ресурсов

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

Page 132: распаковка Asprotect

Распаковка программ, защищенных Asprotect132

© <2009> <Некрылов Валентин>

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

Page 133: распаковка Asprotect

Практика распаковки программ 133

© <2009> <Некрылов Валентин>

Теперь проходим на вкладку Directory Editor, и корректируем значения BaseRelocation Table, и TLS Directory:

На этом рисунке Сиреневым цветом выделены корректируемые значения BaseRelocation Table, а Голубым цветом – корректируемые значения TLS Directory (воригинальной программе адреса этих директорий находятся в секции .data,созданной протектором Asprotect).

Данные этих директорий протектор, при упаковке программы, переносит в своюсекцию из соответствующих секций оригинальной неупакованной программы,поэтому нам нужно просто найти эти данные в оригинальных секцияхраспакованной программы. Для этого загружаем упакованную программу в OllyDbg,и переходим в окне DUMP на адрес 0098BBD4, где находятся данные BaseRelocation Table (а рядом с этими данными находятся данные TLS Directory):

Page 134: распаковка Asprotect

Распаковка программ, защищенных Asprotect134

© <2009> <Некрылов Валентин>

На этом рисунке Сиреневым цветом выделены значения Base Relocation Table, аГолубым цветом – значения TLS Directory, которые находятся в секции .data,созданной протектором Asprotect.

С помощью функции бинарного поиска отладчика сначала ищем данные BaseRelocation Table в секциях файла на вкладке Memory Map, и находим их по адресу0098BBD4, т.е. в секции, созданной протектором Asprotect. Значит, оригинальнаяпрограмма не имеет Base Relocation Table, и поэтому мы можем удалить знвченияиз этой секции.

Теперь, помощью функции бинарного поиска отладчика ищем данные TLS Directory,и находим их по адресу 006FC000:

Корректируем значения адресов директорий Base Relocation Table и TLS Directory(не забывая при этом из найденных адресов вычесть значение ImageBaseпрограммы):

3.1.9 Восстановление секции ресурсов .rsrc

Как известно, протектор крадет несколько ресурсов из секции ресурсов .rsrc, ипереносит их в свою секцию .data. Поэтому нам нужно вернуть эти украденныересурсы в их родную секцию .rsrc. Для восстановления секции ресурсов мы будемиспользовать утилиту Resource Binder v3.1, учитывая то, что секцию ресурсов мывосстанавливаем на ее родное место. Запускаем утилиту Resource Binder v3.1,выбираем резервный файл dumped_control.exe, в окне “Действие” выбираем “Создать бинарный файл секции ресурсов”, нажимаем кнопку “Сделать”, и впоявившемся окне вводим оригинальное значение VirtualOffset секции .rsrc:

Page 135: распаковка Asprotect

Практика распаковки программ 135

© <2009> <Некрылов Валентин>

Утилита работает очень быстро, и мы получаем бинарный дамп секции ресурсов сименем dumped_control0032C000.rsrc.

Теперь можно прикрутить полученный дамп секции ресурсов к файлу dumped.exe, иоткорректировать имя секции ресурсов:

3.1.10 Дампирование секции JCLDEBUG

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

Page 136: распаковка Asprotect

Распаковка программ, защищенных Asprotect136

© <2009> <Некрылов Валентин>

И прикручиваем полученный дамп к файлу dumped.exe:

3.1.11 Запуск полученного дампа программы

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

Распакованная программа нормально запустилась. Теперь нам осталось толькоизменить имя файла dumped.exe на родное имя файла - stpass.exe, и, на всякийслучай, сохранить оригинальный упакованный файл с другим именем, например,stpass_orig.exe.

Page 137: распаковка Asprotect

Практика распаковки программ 137

© <2009> <Некрылов Валентин>

3.2 Распаковка программы LanAgent v3.0.0.0

В этой части мы продолжим практику распаковки программ, защищенных Asprotect.Для тренинга я решил привести пример распаковки программы LanAgent v3.0.0.0,которую можно скачать по ссылке http://www.lanagent.ru. Эта программа защищенастарой версией протектора ASProtect v1.35 build 04.25 Release.

3.2.1 Определение протектора и языка программирования

Как всегда, процесс распаковки программы мы начинаем с выяснения того,защищена ли программа каким-либо протектором, и на каком языкепрограммирования она написана. Для этого сначала загружаем программу в PEiDv0.95:

Итак, программа упакована Asprotect. Уточняем версию протектора, используяутилиту ASPrINFO v1.6 Beta:

Программа защищена сравнительно уже устаревшей версией Asprotect 1.35 build04.25 Release. И теперь нам надо определить компилятор, с помощью которого была

Page 138: распаковка Asprotect

Распаковка программ, защищенных Asprotect138

© <2009> <Некрылов Валентин>

скомпилирована эта программа. Для этого будем использовать утилиту DiE v0.64:

Мы видим, что программа скомпилирована с помощью Borland Delphi.

3.2.2 Определение опций защиты программы

Теперь нам нужно определить, какие опции защиты разработчик применил для своейпрограммы. Для этого загружаем программу в отладчик OllyDbg, и запускаем скрипт“Поиск OEP (SBOEP).osc”. При своей работе, этот скрипт показываетдиагностические сообщения, а все выявленные им опции защиты записывает вжурнал регистрации отладчика:

Как видно из полученной информации, разработчик, для защиты своей программы,использовал эмуляцию вызываемых APIs, вызовы APIs Asprotect, закриптовалтаблицу INIT, и использовал SBOEP (украл код из области OEP программы).

Смотрим на SBOEP программы:

Page 139: распаковка Asprotect

Практика распаковки программ 139

© <2009> <Некрылов Валентин>

Видим мусорный код и использование эмулированных инструкций CALL, JMP, Jcc(условные прыжки) и CMP+Jcc (сравнение с условными прыжками). На наличиеэмулированных инструкций нам указывает CALL 01B80000, который вызывает VM,для выполнения таких инструкций.

3.2.3 Восстановление таблицы INIT

Ну что же! Приступаем к распаковке программы. Перезагружаем программу вотладчике, и запускаем скрипт “Восстановление таблицы INIT.osc”.

Этот скрипт выполняет следующие действия:

- восстанавливает таблицу INIT;- дампирует эту таблицу с созданием файла “table_INIT.bin”, который используется

при работе скрипта “Восстановление таблицы IAT и вызовов APIs.osc”.

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

Смотрим в журнал регистрации отладчика:

Здесь мы видим адрес SBOEP программы, а также адрес начала таблицы INIT, и ее

Page 140: распаковка Asprotect

Распаковка программ, защищенных Asprotect140

© <2009> <Некрылов Валентин>

размер.

3.2.4 Восстановление таблицы IAT и вызовов эмулированных APIs

Опять перезагружаем программу в отладчике, и запускаем скрипт “Восстановлениетаблицы IAT и вызовов APIs.osc”.

Этот скрипт выполняет следующие действия:

- сначала он восстанавливает таблицу IAT, и определяет ее начало, конец и размер;- затем скрипт восстанавливает вызовы эмулированных APIs;- после этого скрипт восстанавливает эмулированные инструкции, при

дополнительной защите импорта;- вставляет ранее полученный дамп таблицы INIT на ее родное место (файл “

table_INIT.bin”);- сохраняет все основные параметры распаковываемой программы в файле “

main_parameters.bin”, который используется при работе скриптов “Восстановление эмулированных подпрограмм в коде программы.osc”, “Устранение проверки целостности кода (CRC) программы.osc”, “ЭмуляцияAPIs Asprotect, вызываемых из кода программы.osc” и “Восстановление секцииимпорта (.idata) в распакованных программах.osc”.

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

Здесь мы видим адрес таблицы INIT, SBOEP программы, а также адрес начала

Page 141: распаковка Asprotect

Практика распаковки программ 141

© <2009> <Некрылов Валентин>

таблицы IAT, и ее размер. Мы также видим, что разработчик применил, для защитысвоей программы 7 APIs Asprotect, вызываемых из Asprotect.dll. Скрипт выполнилэмуляцию двух APIs Asprotect – GetHardwareID и GetRegistrationInformation, а дляAPIs Asprotect – GetTrialDays, GetTrialExecs, ExecuteApplication и ExecuteTrial, онвнес непосредственные изменения в код программы.

3.2.5 Устранение проверок целостности кода CRC) программы

Теперь, не перезагружая программу в отладчике, запускаем скрипт “Устранениепроверки целостности кода (CRC) программы.osc”:

Здесь разработчик не предусмотрел проверку целостности кода программы.

3.2.6 Эмуляция APIs Asprotect, вызываемых из кода программы

Поскольку программа защищена Asprotect с длинным регистрационным ключом, то вней нет вызовов APIs Asprotect из кода программы, поэтому мы не запускаем скрипт“Эмуляция APIs Asprotect, вызываемых из кода программы.osc”.

3.2.7 Восстановление секции импорта в распакованной программе

И теперь, не перезагружая программу в отладчике, запускаем скрипт “Восстановление секции импорта (.idata) в распакованных программах.osc”. Посленескольких минут работы скрипта получаем сообщение:

Итак, мы получили два дампа памяти распакованной программы с полностьювосстановленной секцией импорта, эмулированными APIs Asprotect, ивосстановленной таблицей INIT - "dumped.exe" и "dumped_control.exe". Проверяем,нет ли ошибок при работе скрипта “Восстановление секции импорта (.idata) в

Page 142: распаковка Asprotect

Распаковка программ, защищенных Asprotect142

© <2009> <Некрылов Валентин>

распакованных программах.osc”, для чего загружаем файл "dumped.exe" в отладчик(если были допущены какие-либо ошибки, то при загрузке файла "dumped.exe" мыполучим сообщение об ошибке):

Программа остановилась на OEP, и при загрузке импорта мы не получили никакихошибок. Значит, первая часть работы нами выполнена успешно.

3.2.8 Поиск областей со Stolen Code и восстановление в них эмулированныхинструкций

Итак, поскольку скрипт “Поиск OEP (SBOEP).osc”, показал, что в программе естьобласти со Stolen Code, мы перезагружаем в отладчике программу, и запускаемскрипт “Поиск областей со Stolen Code и восстановление в них эмулированныхинструкций.osc”.

Этот скрипт выполняет следующие действия:

- сначала он находит все прыжки из кода программы в области со Stolen Code,создает таблицу этих прыжков, и дампирует ее в файл с именем “table_JMP.bin”;

- затем он находит все массивы данных для эмулированных инструкций CALL,JMP, Jcc (условные прыжки) и CMP+Jcc (сравнение с условными прыжками),создает таблицу массивов, и дампирует ее в файл с именем “table_massive_data.bin”;

- одновременно скрипт находит свободное место в конце областей со Stolen Code,которое используется для записи восстановленных эмулированных инструкцийCALL, JMP, Jcc и CMP+Jcc, создает таблицу адресов этих свободным мест, идампирует ее в файл с именем “table_ImageBase_Stolen_Code.bin”;

- затем, с помощью специальной VM, скрипт восстанавливает эмулированныеинструкций CALL, JMP, Jcc и CMP+Jcc, и записывает их на свободные места вобластях со Stolen Code;

- далее, с помощью специальной VM, скрипт записывает в таблицу адресарасположения эмулированных инструкций CALL, JMP, Jcc и CMP+Jcc вобластях со Stolen Code, и создает файл с именем “recovery_emul_inst.bin”. Этотфайл содержит все данные, необходимые для работы скриптов “Перенос StolenCode в секцию файла ADATA.osc” и “Перенос Stolen Code в секцию файлаRSRC.osc”.

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

Page 143: распаковка Asprotect

Практика распаковки программ 143

© <2009> <Некрылов Валентин>

Итак, мы видим, что распаковываемая программа имеет только одну область соStolen Code – это область SBOEP.

3.2.9 Перенос области SBOEP на место секции файла .rsrc

Как я уже писал раньше, я предпочитаю переносить области памяти со Stolen Codeна место секции ресурсов файла - .rsrc. Поэтому, не перезагружая программу вотладчике, запускаем скрипт “Перенос Stolen Code в секцию файла RSRC.osc”.

Этот скрипт выполняет следующие действия:

- сначала он создает промежуточную область памяти, куда переносит код из всехобластей со Stolen Code. Причем, самым первым переносимым кодом являетсякод из области SBOEP”;

- затем скрипт выполняет привязку эмулированных инструкций CALL, JMP, Jcc иCMP+Jcc применительно к секции файла .rsrc для всех областей со Stolen Code;

- одновременно скрипт создает таблицу соответствия адресов областей со StolenCode и новой секции файла, которая будет размещена на месте секции .rsrc файла;

- и, в конце своей работы, он дампирует промежуточную область памяти сперенесенным кодом из областей со Stolen Code, и сохраняет его в файле сименем “section_ASPR_RSRC.bin”.

После завершения работы этого скрипта мы можем приступить к сборкераспакованного файла.

3.2.10 Подготовка файла dumped.exe к его сборке

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

Page 144: распаковка Asprotect

Распаковка программ, защищенных Asprotect144

© <2009> <Некрылов Валентин>

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

Page 145: распаковка Asprotect

Практика распаковки программ 145

© <2009> <Некрылов Валентин>

Теперь проходим на вкладку Directory Editor, и корректируем значения BaseRelocation Table, и TLS Directory:

На этом рисунке Сиреневым цветом выделены корректируемые значения BaseRelocation Table, а Голубым цветом – корректируемые значения TLS Directory (воригинальной программе адреса этих директорий находятся в секции .data,созданной протектором Asprotect).

Данные этих директорий протектор, при упаковке программы, переносит в своюсекцию из соответствующих секций оригинальной неупакованной программы,поэтому нам нужно просто найти эти данные в оригинальных секцияхраспакованной программы. Для этого загружаем упакованную программу в OllyDbg,и переходим в окне DUMP на адрес 009C49DC, где находятся данные BaseRelocation Table (а рядом с этими данными находятся данные TLS Directory):

Page 146: распаковка Asprotect

Распаковка программ, защищенных Asprotect146

© <2009> <Некрылов Валентин>

На этом рисунке Сиреневым цветом выделены значения Base Relocation Table, аГолубым цветом – значения TLS Directory, которые находятся в секции .data,созданной протектором Asprotect.

С помощью функции бинарного поиска отладчика сначала ищем данные BaseRelocation Table в секциях файла на вкладке Memory Map, и находим их по адресу009C49DC, т.е. в секции, созданной протектором Asprotect. Значит, оригинальнаяпрограмма не имеет Base Relocation Table, и поэтому мы можем удалить значения изэтой секции.

Теперь, помощью функции бинарного поиска отладчика ищем данные TLS Directory,и находим их по адресу 00761000:

Корректируем значения адресов директорий Base Relocation Table и TLS Directory(не забывая при этом из найденных адресов вычесть значение ImageBaseпрограммы):

3.2.11 Прикручивание секции с украденным кодом к файлу dumped.exe

Теперь мы можем прикрутить к полученному дампу секцию section_ASPR_RSRC.bin:

Page 147: распаковка Asprotect

Практика распаковки программ 147

© <2009> <Некрылов Валентин>

И корректируем имя прикрученной секции (я предпочитаю использовать имя .aspr):

3.2.12 Восстановление секции ресурсов .rsrc

Как известно, протектор крадет несколько ресурсов из секции ресурсов .rsrc, ипереносит их в свою секцию .data. Поэтому нам нужно не только вернуть этиукраденные ресурсы в их родную секцию .rsrc, но выполнить их привязку к новомуRVA, поскольку на месте секции ресурсов мы разместили секцию файла сукраденным кодом. Для восстановления секции ресурсов мы будем использоватьутилиту Resource Binder v3.1. Но, перед запуском этой утилиты, мы должныопределить новое значение RVA секции ресурсов. Сделать это довольно просто. Навышеприведенном рисунке, где показана прикрученная секция файла с украденнымкодом, Золотистым цветом выделен VirtualSize прикрученной секции, а Ярко-зеленым цветом – VirtualOffset этой секции. Следовательно, VirtualOffset секции .

Page 148: распаковка Asprotect

Распаковка программ, защищенных Asprotect148

© <2009> <Некрылов Валентин>

rsrc будет равен:00398000 + 00002000 = 0039A000

Теперь запускаем утилиту Resource Binder v3.1, выбираем резервный файлdumped_control.exe, в окне “Действие” выбираем “Создать бинарный файл секцииресурсов”, нажимаем кнопку “Сделать”, и в появившемся окне вводим вычисленноезначение VirtualOffset секции .rsrc:

Утилита работает очень быстро, и мы получаем бинарный дамп секции ресурсов сименем dumped_control0039A000.rsrc.

Теперь можно прикрутить полученный дамп секции ресурсов к файлу dumped.exe, иоткорректировать имя секции ресурсов:

И корректируем новый адрес секции ресурсов на вкладке Directory Editor:

Page 149: распаковка Asprotect

Практика распаковки программ 149

© <2009> <Некрылов Валентин>

3.2.13 Переадресация прыжков из кода программы на секцию с украденнымкодом .aspr

И теперь нам осталось выполнить переадресацию прыжков из кода программы наприкрученную секцию .aspr. Для этих целей будем использовать скрипт “Перенаправление прыжков из кода программы в новую секцию файла.osc”,который приложен к данной статье. Этот скрипт, в своей работе, используетследующие два дампа:

- “table_JMP.bin” – дамп таблицы прыжков из кода программы в области со StolenCode;

- “table_StolenCode_RSRC.bin” или “table_StolenCode_ADATA.bin” – дамптаблицы соответствия адресов областей со Stolen Code и новой секции файла .aspr.

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

Итак, загружаем наш файл dumped.exe в отладчик:

Запускаем этот скрипт. После завершения работы скрипта мы видим:

Теперь выделяем всю область дизассемблированного кода программы, и выбираемкоманду “Copy to executable 0 Selection”.

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

Page 150: распаковка Asprotect

Распаковка программ, защищенных Asprotect150

© <2009> <Некрылов Валентин>

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

3.2.14 Очистка мусорного кода в секции файла с украденным кодом .aspr

Поскольку рабочий код в секции с .aspr сильно перемешан с мусорным кодом, товыполним его очистку с помощью скрипта “Очистка мусорного кода в областях соStolen Code.osc”. Еще раз обращаю Ваше внимание на то, что этот скрипт можетповредить некоторые рабочие инструкции. Этот скрипт работает достаточно быстро,и в результате его работы мы получаем следующее:

Мы видим, что код секции .aspr полностью очищен от мусорных прыжков, чтонамного облегчает процесс трассирования программы. И еще одно примечание, приработе скрипта “Перенаправление прыжков из кода программы в новую секциюфайла.osc”, он помещает комментарии возле прыжков в область с украденным кодом.Поэтому я рекомендую с помощью команды отладчика “Searh for 0 User-definedcomment” найти эти комментарии, и установить на этих прыжка BreakPoint, чтопозволяет быстрее определить область кода, в котором появляется ошибка:

3.2.15 Выявление причины появления ошибки при запуске распакованнойпрограммы

Начинаем трассирование программы, и достаточно быстро приходим сюда:

Page 151: распаковка Asprotect

Практика распаковки программ 151

© <2009> <Некрылов Валентин>

Запускаем второй отладчик OllyDbg, загружаем в него упакованную программу,запускаем скрипт “Поиск областей со Stolen Code и восстановление в нихэмулированных инструкций.osc”, и находим в области SBOEP инструкцию CALLDWORD PTR DS:[759440]. Устанавливаем на этой инструкции BreakPoint, изапускаем программу:

Очевидно, что нам надо исправить файл dumped.exe, и по адресу 00759440 записатьуказатель на адрес 00745080:

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

Page 152: распаковка Asprotect

Распаковка программ, защищенных Asprotect152

© <2009> <Некрылов Валентин>

Итак, мы сняли довольно сильный протектор с защищенной им программы.

Однако возникает вопрос, почему в программу не был записан адрес 00745080? Делозаключается в том, что разработчик здесь использовал API Asprotect –GetRunApplicationFunction. Эта API применяет только один аргумент – указатель наAPI ExecuteApplication или ExecuteTrial, о чем я писал в четвертой части данноговыпуска. Я не выяснял, по каким причинам здесь это произошло, но при запускескрипта “Восстановление таблицы IAT и вызовов APIs.osc”, когда восстановлены в Asprotect.dll все подпрограммы с эмулированными инструкциями, при выполненииAPI GetRunApplicationFunction, она по адресу 00759440, записывает ноли. В тожевремя, при запуске скрипта “Поиск областей со Stolen Code и восстановление в нихэмулированных инструкций.osc”, при выполнении API GetRunApplicationFunction, по адресу 00759440 записывается адрес 00745080, откуда продолжается выполнениепрограммы:

Итак, нам осталось только изменить имя файла dumped.exe на родное имя файла -LanAgent.exe, и, на всякий случай, сохранить оригинальный упакованный файл сдругим именем, например, LanAgent_orig.exe.

3.3 Распаковка программы Asprotect v2.5 SKE build 04.08 Demo

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

Page 153: распаковка Asprotect

Практика распаковки программ 153

© <2009> <Некрылов Валентин>

своих продуктов, в полной мере использовать все опции защиты, которые предлагаетэтот очень мощный протектор. Поэтому, как правило, защита получается довольнослабой. Наиболее сильно построена защита у разработчиков самого протектораAsprotect, которые, для защиты своих продуктов, используют Asprotect последнихверсий, с включением практически всех опций защиты. Поэтому, для тренинга, ярешил привести пример распаковки программы Asprotect v2.5 SKE build 04.08 Demo,которую можно скачать по ссылке http://www.aspack.com/files/aspr25_demo.zip. Ведь намнадо попрактиковаться с восстановлением подпрограмм с эмулированнымиинструкциями в коде программы, извлечь из упакованной программы Asprotect.dll, атакже выполнить все остальные действия, чтобы получить рабочий дампраспакованной программы. Эта программа защищена новой версией протектораAsprotect v2.5 SKE build 04.08 Release.

3.3.1 Определение протектора и языка программирования

Как всегда, процесс распаковки программы мы начинаем с выяснения того,защищена ли программа каким-либо протектором, и на каком языкепрограммирования она написана. Для этого сначала загружаем программу в PEiDv0.95:

Итак, программа упакована Asprotect. Уточняем версию протектора, используяутилиту ASPrINFO v1.6 Beta:

Page 154: распаковка Asprotect

Распаковка программ, защищенных Asprotect154

© <2009> <Некрылов Валентин>

Программа защищена сравнительно новой версией Asprotect v2.5 SKE build 04.08Release. И теперь нам надо определить компилятор, с помощью которого быласкомпилирована эта программа. Для этого будем использовать утилиту DiE v0.64:

Мы видим, что программа скомпилирована с помощью Borland Delphi.

3.3.2 Определение опций защиты программы

Теперь нам нужно определить, какие опции защиты разработчик применил для своейпрограммы. Для этого загружаем программу в отладчик OllyDbg, и запускаем скрипт“Поиск OEP (SBOEP).osc”. При своей работе, этот скрипт показываетдиагностические сообщения, а все выявленные им опции защиты записывает вжурнал регистрации отладчика:

Page 155: распаковка Asprotect

Практика распаковки программ 155

© <2009> <Некрылов Валентин>

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

Смотрим на SBOEP программы:

Видим мусорный код и использование эмулированных инструкций CALL, JMP, Jcc(условные прыжки) и CMP+Jcc (сравнение с условными прыжками). На наличиеэмулированных инструкций нам указывает CALL 01E60000, который вызывает VM,для выполнения таких инструкций.

3.3.3 Восстановление таблицы INIT

Ну что же! Приступаем к распаковке программы. Перезагружаем программу вотладчике, и запускаем скрипт “Восстановление таблицы INIT.osc”.

Этот скрипт выполняет следующие действия:

- восстанавливает таблицу INIT;- дампирует эту таблицу с созданием файла “table_INIT.bin”, который используется

при работе скрипта “Восстановление таблицы IAT и вызовов APIs.osc”.

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

Page 156: распаковка Asprotect

Распаковка программ, защищенных Asprotect156

© <2009> <Некрылов Валентин>

Смотрим в журнал регистрации отладчика:

Здесь мы видим адрес SBOEP программы, а также адрес начала таблицы INIT, и ееразмер.

3.3.4 Получение файла Asprotect.dll

Поскольку у нас имеются подпрограммы с эмулированными инструкциями, то, передвосстановлением таблицы IAT, и выполнением других действий по распаковкепрограммы, нам надо получить файл Asprotect.dll. Этот файл нам потребуется длякорректировки кода VM для восстановления эмулированных инструкций в кодепрограммы.

Для получения файла Asprotect.dll, мы сначала запускаем скрипт “Восстановлениетаблицы IAT и вызовов APIs.osc”, который создает файл “main_parameters.bin”,необходимый для работы скрипта “Восстановление эмулированных подпрограмм вAsprotect_dll на OEP (SBOEP).osc”.

После завершения работы этого скрипта, и поскольку программа остановлена наSBOEP, мы запускаем скрипт “Восстановление эмулированных подпрограмм вAsprotect_dll на OEP (SBOEP).osc”, который восстановит все подпрограммы сэмулированными инструкциями в Asprotect.dll. Еще раз напомню, что этиподпрограммы имеют следующий вид:

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

Page 157: распаковка Asprotect

Практика распаковки программ 157

© <2009> <Некрылов Валентин>

Как видно из рисунка, скрипт восстановил все подпрограммы с эмулированнымиинструкциями. Теперь, не перезагружая программу в отладчике, запускаем сначаласкрипт “Создание файла Asprotect_dll.osc”, а затем скрипт “Восстановление секцииимпорта (.idata) в Asprotect_dll.osc”. После завершения их работы, мы получаемфайл с именем Asprotect.dll, который переименуем как Asprotect_250_0408.dll, чтобыне путать его с базовым файлом Asprotect_241_0226.dll (этот файл приложен к статьеРаспаковка Asprotect (часть 5, выпуск 2)).

3.3.5 Получение таблиц соответствия для корректировки VM

Здесь нам предстоит выполнить самую сложную работу – это составить таблицысоответствия двух Asprotect.dll – Asprotect_250_0408.dll и Asprotect_241_0226.dll. Вчасти 5 второго выпуска, я довольно подробно показал, как это можно сделать.Здесь же я приведу только таблицы соответствия, и по этим таблицам Вы сможетесамостоятельно проверить мои действия. Единственное, что я еще раз хотел быподчеркнуть – Asprotect.dll имеет две VM для выполнения эмулированныхинструкций. Одна VM предназначена для выполнения эмулированных инструкций всамой Asprotect.dll, а вторая VM – для выполнения эмулированных инструкций вкоде распаковываемой программы. Вторая VM имеет следующую инструкцию, покоторой ее можно отличить от первой VM:

Константа в инструкции XOR EAX,A74AD28A, для разных программ имеет свое,уникальное значение. А VM – для выполнения эмулированных инструкций в кодераспаковываемой программы, находится здесь:

Page 158: распаковка Asprotect

Распаковка программ, защищенных Asprotect158

© <2009> <Некрылов Валентин>

В этой таблице приведены зашифрованные значения hex-чисел от 00h до 0Fh:

Hex-числа Зашифрованные значения

Asprotect_241_0226.dll Asprotect_250_0408.dll

0h D4h 2Ah

1h E0h 31h

2h 4Eh E0h

3h 8Dh 4Bh

4h 07h EFh

5h 5Bh 3Bh

6h 5Eh 5Fh

7h 99h 06h

8h C7h 28h

9h FCh 8Eh

Ah A0h BAh

Bh 49h EAh

Ch 8Bh FBh

Dh 93h 18h

Eh 4Ah 00h

Fh 9Ah FDh

А в этой таблице приведены данные для заголовков массивов данных сравниваемыхAsprotect.dll (эти данные нужно получать на загруженных в отладчик упакованныхпрограммах ASProtect 2.41 SKE build 02.26 Beta и ASProtect SKE 2.5 build 04.08Demo):

Параметр Смещение от начала заголовка массива данных

Asprotect_241_0226.dll Asprotect_250_0408.dll

Page 159: распаковка Asprotect

Практика распаковки программ 159

© <2009> <Некрылов Валентин>

DWORD_00h + 00h + 00h

DWORD_04h + 04h + 18h

DWORD_08h + 08h + 0Ch

DWORD_0Сh + 0Сh + 04h

DWORD_10h + 10h + 10h

DWORD_14h + 14h + 14h

DWORD_18h + 18h + 08h

DWORD_1Ch + 1Ch + 1Ch

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

Параметр Зашифрованные значения

Asprotect_241_0226.dll Asprotect_250_0408.dll

DWORD_00h + 00h + 0Ah

DWORD_04h + 04h + 12h

BYTE_08h + 08h + 10h

BYTE_09h + 09h + 00h

BYTE_0Ah + 0Ah + 16h

BYTE_0Bh + 0Bh + 09h

BYTE_0Ch + 0Ch + 01h

DWORD_0Dh + 0Dh + 05h

BYTE_11h + 11h + 17h

BYTE_12h + 12h + 0Eh

BYTE_13h + 13h + 0Fh

BYTE_14h + 14h + 02h

BYTE_15h + 15h + 03h

BYTE_16h + 16h + 04h

BYTE_17h + 17h + 11h

А в этой таблице приведено расположение данных в массиве для каждойэмулированной инструкции, выполняемой в VMDelay (в ней выполняютсянекоторые инструкции ADD, SUB и MOV):

Page 160: распаковка Asprotect

Распаковка программ, защищенных Asprotect160

© <2009> <Некрылов Валентин>

Параметр Зашифрованные значения

Asprotect_241_0226.dll Asprotect_250_0408.dll

BYTE_00h + 00h + 0Ch

BYTE_01h + 01h + 02h

BYTE_02h + 02h + 01h

BYTE_03h + 03h + 07h

BYTE_04h + 04h + 00h

BYTE_05h + 05h + 08h

BYTE_06h + 06h + 09h

BYTE_07h + 07h + 0Ah

BYTE_08h + 08h + 0Bh

BYTE_08h + 09h + 03h

BYTE_0Ah + 0Ah + 04h

BYTE_0Bh + 0Bh + 05h

BYTE_0Ch + 0Ch + 06h

И в последней таблице приведены идентификаторы выполняемых инструкций вVMDelay:

Инструкция Зашифрованные значения

Asprotect_241_0226.dll Asprotect_250_0408.dll

CMP BYTE [EBP-1D],0 00h 05h

CMP BYTE [EBP-1D],6 06h 04h

CMP BYTE [EBP-1D],8 08h 02h

CMP BYTE [EBP-1D],5 05h 06h

CMP BYTE [EBP-1D],9 09h 09h

3.3.6 Корректировка кода VM для восстановления подпрограмм сэмулированными инструкциями

После заполнения этих пяти таблиц, мы уже можем откорректировать код VM длявосстановления подпрограмм с эмулированными инструкциями. Для этих целейбудем использовать скрипт “Корректировка VM для восстановленияэмулированных инструкций в коде программы.osc”.

Загружаем в отладчик файл “VM_recovery_main_code.exe” (он приложен к 5-й части

Page 161: распаковка Asprotect

Практика распаковки программ 161

© <2009> <Некрылов Валентин>

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

Скрипт запросит ввести имя для файла VM, и я советую присвоить ему имя “recovery_emulate_inst_main_code_250_0408.bin”, которое указывает, для какого файлаоткорректирован код VM:

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

После корректировки кода VM целесообразно ее запустить для восстановления кодахотя бы одной подпрограммы с эмулированными инструкциями, чтоб посмотреть, недопущены ли нами какие-либо ошибки при заполнении таблиц соответствия иликорректировке кода VM. Обычно я делаю это так: загружаю упакованную программув отладчик, и запускаю скрипт “Восстановление таблицы IAT и вызовов APIs.osc”.После завершения работы этого скрипта, загружаю скрипт “Восстановлениеэмулированных подпрограмм в коде программы.osc”, и устанавливаю BreakPoint наинструкцию RUN:

Запускаю скрипт, при его запросе ввожу имя VM, и когда скрипт останавливается наBreakPoint, нажимаю клавишу S, чтобы выполнить инструкцию RUN. Затемпрохожу на адрес 004A3FF2, и смотрю, нет ли каких-либо непонятных инструкций ввосстановленной подпрограмме. Если к коду нет никаких претензий, то можно снять

Page 162: распаковка Asprotect

Распаковка программ, защищенных Asprotect162

© <2009> <Некрылов Валентин>

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

3.3.8 Эмуляция APIs Asprotect, вызываемых из кода программы

Поскольку программа защищена Asprotect с коротким ключом, то здесь APIs Asprotectвызываются из кода программы. Поэтому, не перезагружая программу в отладчике,запускаем скрипт “Эмуляция APIs Asprotect, вызываемых из кода программы.osc”.После завершения работы скрипта, проходим в окно журнала отладчика, и там видимследующее:

Здесь вызывается только одна API Asprotect – CheckKey.

3.3.9 Устранение проверок целостности кода программы

Теперь, не перезагружая программу в отладчике, запускаем скрипт “Устранениепроверки целостности кода (CRC) программы.osc”, чтобы удалить возможныепроверки целостности кода программы. После завершения работы скрипта видимследующее:

3.3.10 Восстановление секции импорта программы

И, наконец, не перезагружая программу в отладчике, запускаем скрипт “Восстановление секции импорта (.idata) в распакованных программах.osc”. Послезавершения его работы получаем следующее сообщение:

Page 163: распаковка Asprotect

Практика распаковки программ 163

© <2009> <Некрылов Валентин>

Итак, мы получили два дампа памяти распакованной программы с полностьювосстановленной секцией импорта, эмулированными APIs Asprotect,восстановленной таблицей INIT, восстановленными подпрограммами сэмулированными инструкциями и устраненными проверками целостности кодапрограммы – "dumped.exe" и "dumped_control.exe". Проверяем, нет ли ошибок приработе скрипта “Восстановление секции импорта (.idata) в распакованныхпрограммах.osc”, для чего загружаем файл "dumped.exe" в отладчик (если былидопущены какие-либо ошибки, то при загрузке файла "dumped.exe" мы получимсообщение об ошибке):

Программа остановилась на OEP, и при загрузке импорта мы не получили никакихошибок. Значит, первая часть работы нами выполнена успешно.

3.3.11 Поиск областей со Stolen Code и восстановление в них эмулированныхинструкций

Итак, поскольку скрипт “Поиск OEP (SBOEP).osc”, показал, что в программе естьобласти со Stolen Code, мы перезагружаем в отладчике программу, и запускаемскрипт “Поиск областей со Stolen Code и восстановление в них эмулированныхинструкций.osc”.

Этот скрипт выполняет следующие действия:

- сначала он находит все прыжки из кода программы в области со Stolen Code,создает таблицу этих прыжков, и дампирует ее в файл с именем “table_JMP.bin”;

- затем он находит все массивы данных для эмулированных инструкций CALL,JMP, Jcc (условные прыжки) и CMP+Jcc (сравнение с условными прыжками),создает таблицу массивов, и дампирует ее в файл с именем “table_massive_data.bin”;

Page 164: распаковка Asprotect

Распаковка программ, защищенных Asprotect164

© <2009> <Некрылов Валентин>

- одновременно скрипт находит свободное место в конце областей со Stolen Code,которое используется для записи восстановленных эмулированных инструкцийCALL, JMP, Jcc и CMP+Jcc, создает таблицу адресов этих свободным мест, идампирует ее в файл с именем “table_ImageBase_Stolen_Code.bin”;

- затем, с помощью специальной VM, скрипт восстанавливает эмулированныеинструкций CALL, JMP, Jcc и CMP+Jcc, и записывает их на свободные места вобластях со Stolen Code;

- далее, с помощью специальной VM, скрипт записывает в таблицу адресарасположения эмулированных инструкций CALL, JMP, Jcc и CMP+Jcc вобластях со Stolen Code, и создает файл с именем “recovery_emul_inst.bin”. Этотфайл содержит все данные, необходимые для работы скриптов “Перенос StolenCode в секцию файла ADATA.osc” и “Перенос Stolen Code в секцию файлаRSRC.osc”.

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

Итак, мы видим, что распаковываемая программа имеет только одну область соStolen Code – это область SBOEP.

3.3.12 Перенос области SBOEP на место секции файла .rsrc

Как я уже писал раньше, я предпочитаю переносить области памяти со Stolen Codeна место секции ресурсов файла - .rsrc. Поэтому, не перезагружая программу вотладчике, запускаем скрипт “Перенос Stolen Code в секцию файла RSRC.osc”.

Этот скрипт выполняет следующие действия:

- сначала он создает промежуточную область памяти, куда переносит код из всехобластей со Stolen Code. Причем, самым первым переносимым кодом являетсякод из области SBOEP”;

- затем скрипт выполняет привязку эмулированных инструкций CALL, JMP, Jcc иCMP+Jcc применительно к секции файла .rsrc для всех областей со Stolen Code;

- одновременно скрипт создает таблицу соответствия адресов областей со StolenCode и новой секции файла, которая будет размещена на месте секции .rsrc файла;

- и, в конце своей работы, он дампирует промежуточную область памяти сперенесенным кодом из областей со Stolen Code, и сохраняет его в файле сименем “section_ASPR_RSRC.bin”.

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

Page 165: распаковка Asprotect

Практика распаковки программ 165

© <2009> <Некрылов Валентин>

распакованного файла.

3.3.13 Подготовка файла dumped.exe к его сборке

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

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

Page 166: распаковка Asprotect

Распаковка программ, защищенных Asprotect166

© <2009> <Некрылов Валентин>

Теперь проходим на вкладку Directory Editor, и корректируем значения BaseRelocation Table, и TLS Directory:

На этом рисунке Сиреневым цветом выделены корректируемые значения BaseRelocation Table, а Голубым цветом – корректируемые значения TLS Directory (воригинальной программе адреса этих директорий находятся в секции .data,созданной протектором Asprotect).

Данные этих директорий протектор, при упаковке программы, переносит в своюсекцию из соответствующих секций оригинальной неупакованной программы,поэтому нам нужно просто найти эти данные в оригинальных секцияхраспакованной программы. Для этого загружаем упакованную программу в OllyDbg,и переходим в окне DUMP на адрес 009C49DC, где находятся данные BaseRelocation Table (а рядом с этими данными находятся данные TLS Directory):

Page 167: распаковка Asprotect

Практика распаковки программ 167

© <2009> <Некрылов Валентин>

На этом рисунке Сиреневым цветом выделены значения Base Relocation Table, аГолубым цветом – значения TLS Directory, которые находятся в секции .data,созданной протектором Asprotect.

С помощью функции бинарного поиска отладчика сначала ищем данные BaseRelocation Table в секциях файла на вкладке Memory Map, и находим их по адресу0055076C:

Теперь, помощью функции бинарного поиска отладчика ищем данные TLS Directory,и находим их по адресу 00567000:

Корректируем значения адресов директорий Base Relocation Table и TLS Directory(не забывая при этом из найденных адресов вычесть значение ImageBaseпрограммы):

3.3.14 Прикручивание секции с украденным кодом к файлу dumped.exe

Теперь мы можем прикрутить к полученному дампу секцию section_ASPR_RSRC.bin:

Page 168: распаковка Asprotect

Распаковка программ, защищенных Asprotect168

© <2009> <Некрылов Валентин>

И корректируем имя прикрученной секции (я предпочитаю использовать имя .aspr):

3.3.15 Восстановление секции ресурсов .rsrc

Как известно, протектор крадет несколько ресурсов из секции ресурсов .rsrc, ипереносит их в свою секцию .data. Поэтому нам нужно не только вернуть этиукраденные ресурсы в их родную секцию .rsrc, но выполнить их привязку к новомуRVA, поскольку на месте секции ресурсов мы разместили секцию файла сукраденным кодом. Для восстановления секции ресурсов мы будем использоватьутилиту Resource Binder v3.1. Но, перед запуском этой утилиты, мы должныопределить новое значение RVA секции ресурсов. Сделать это довольно просто. Навышеприведенном рисунке, где показана прикрученная секция файла с украденнымкодом, Золотистым цветом выделен VirtualSize прикрученной секции, а Ярко-зеленым цветом – VirtualOffset этой секции. Следовательно, VirtualOffset секции .rsrc будет равен:

0017A000 + 00002000 = 17C000

Теперь запускаем утилиту Resource Binder v3.1, выбираем резервный файлdumped_control.exe, в окне “Действие” выбираем “Создать бинарный файл секцииресурсов”, нажимаем кнопку “Сделать”, и в появившемся окне вводим вычисленноезначение VirtualOffset секции .rsrc:

Page 169: распаковка Asprotect

Практика распаковки программ 169

© <2009> <Некрылов Валентин>

Утилита работает очень быстро, и мы получаем бинарный дамп секции ресурсов сименем dumped_control0017C000.rsrc.

Теперь можно прикрутить полученный дамп секции ресурсов к файлу dumped.exe, иоткорректировать имя секции ресурсов:

И корректируем новый адрес секции ресурсов на вкладке Directory Editor:

Page 170: распаковка Asprotect

Распаковка программ, защищенных Asprotect170

© <2009> <Некрылов Валентин>

3.3.16 Переадресация прыжков из кода программы на секцию с украденнымкодом .aspr

И теперь нам осталось выполнить переадресацию прыжков из кода программы наприкрученную секцию .aspr. Для этих целей будем использовать скрипт “Перенаправление прыжков из кода программы в новую секцию файла.osc”. Он, всвоей работе, использует следующие два дампа:

- “table_JMP.bin” – дамп таблицы прыжков из кода программы в области со StolenCode;

- “table_StolenCode_RSRC.bin” или “table_StolenCode_ADATA.bin” – дамптаблицы соответствия адресов областей со Stolen Code и новой секции файла .aspr.

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

Итак, загружаем наш файл dumped.exe в отладчик и запускаем скрипт. Послезавершения работы скрипта мы видим:

Теперь выделяем всю область дизассемблированного кода программы, и выбираемкоманду “Copy to executable 0 Selection”.

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

И программа нормально запускается. Итак, мы сняли довольно сильный протектор сзащищенной им программы. Переименовываем распакованный файл как “UnASProtect_250_0408.exe”.

Page 171: распаковка Asprotect

Практика распаковки программ 171

© <2009> <Некрылов Валентин>

Однако, при запуске распакованного (и упакованного) файлов, мы получаемследующее сообщение:

Это сообщение вызывается здесь:

Устраняем появление этого сообщения очень просто – перепрыгиваем через него:

Page 172: распаковка Asprotect

Top Level IntroThis page is printed before a new

top-level chapter starts

Part

IV

Page 173: распаковка Asprotect

Эпилог 173

© <2009> <Некрылов Валентин>

4 Эпилог

На этом я завершаю данный выпуск статей по распаковке Asprotect. В качестветренировки Вы можете распаковать еще одну программу - ASProtect 1.5 build 04.08Demo, которую можно скачать с сайта разработчика по ссылке http://www.aspack.com/files/aspr15demo.zip. Это поможет Вам лучше понять механизм поиска данных,необходимых для корректировки VM, которая восстанавливает подпрограммы сэмулированными инструкциями.

Page 174: распаковка Asprotect

Endnotes 2... (after index)

Распаковка программ, защищенных Asprotect174

© <2009> <Некрылов Валентин>

Page 175: распаковка Asprotect

Back Cover