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

 

РАСПАКОВКА .DLL ЗАЩИЩЕННЫХ ASProtect ПОСЛЕДНИХ ВЕРСИЙ

 

(на примере Agnitum Outpost Firewall)

 

By QIce [TSRh]

 

                                                                                                                                                         «Мяч круглый, игра длится 90минут.

                                                                                                                                                         Это – факты. Все остальное – теория»

                                                                                                                                                         © «LOLA RENNT»

 

            ИСПОЛЬЗУЕМЫЕ ИНСТРУМЕНТЫ:

 

1.      LordPE RoyalTS 1.31 by yoda

2.      HIEW 6.81 by SEN

3.      ImpREC 1.42+ by MackT

4.      OllyDbg 1.07 by Oleh Yuschuk

5.      ToPo 1.1 by Mr.Crimson

6.      Visual Studio 6.0 ©®Microsoft

7.      ResourceHacker 3.4.0.79 by Angus Johnson

 

ВСТУПЛЕНИЕ:

 

Не пугайтесь большого количества вспомогательного софта, он действительно необходим ;)

 

ЧАСТЬ 1. «Содрать и исправить»

 

            Для препарирования возьмем, к примеру, запакованную dll из пакета Agnitum Outpost Firewall v1.0.1617.1854, http://outpost.agnitum.com. На момент написания статьи (30 мая 2002) общеизвестная утилита Caspr v1.110 многоуважаемого SAC проблемы не решала, сославшись на незнакомую версию защиты. Ну и ладно, сделаем все

руками…

 

            Запустив outpost.exe и LordPE, выбираем в списке LordPE данного процесса нужную нам opst_ui.dll. Элементарно дампим ее полностью, например в dumped1.dll. Никаких проблем.

 

            Так, берем в руки ImpREC… СТОП! Еще рано… На кой черт нам нужен мусор в реверсируемой длл’ке? Сначала исправим каталог ресурсов (аспротект немного «модифицирует» его таким образом, что иконка приложения и version info оказываются в секциях защиты, а ведь их мы собираемся откусить). Стартуем Visual Studio, загружаем в нее dumped1.dll

как Resources, далее просто сохраняем превосходно открывшиеся ресурсы как файл rsrc.RES. Выходим из Visual Studio.

           

Стартуем ResourceHacker (эта чудесная утилита напрочь не понимает ресурсы после аспротекта, зато прекрасно берет их после VS), загружаем в него dumped1.dll, выбираем в меню пункт Action -> Update all resources, где указываем rsrc.RES. Сохраняем файл в меню File -> Save. Удаляем созданный RH файл dumped1_original.dll, он нам не нужен. Итак, в dumped1.dll мы получили нормальный каталог ресурсов.

 

Удалим мусор из дампа? Удалим! Стартуем LordPE, открываем в его PE Editor’е наш dumped1.dll и делаем Truncate и Wipe section header двум последним секциям. Так, следов аспротекта в файле больше не наблюдается. Едем дальше.

 

ЧАСТЬ 2. «Принеси то, не знаю что…»

 

Стартовав ImpREC и попытавшись найти импорт получаем агроменный облом, в виде невозможности автоматического его поиска. Посмотрев на дамп в HIEW, сразу видим характерные для VC-программ адреса системных функций в начале второй секции дампа. Пока это действует для всех VC-программ, без исключения. Ага! Подставляем RVA секции в ImpREC, нажимаем GetImports, и… И ничего, кроме Cant read memory of the process! Мда, силен все-таки Солодовников, крут… Да пошло оно все… СТОП! Да пошел он сам! Ща выправим!

Стартуем ToPo, загружаем в него outpost.exe. Да, именно его! Добавляем новую секцию размером эдак с 0x1000. Выходим из ToPo.

Стартуем OllyDbg, загружаем в него модифицированный нами outpost.exe, запускаем не обращая внимания на вопли OllyDbg… Все, загрузились (иконка с вопросом – все, загрузились (иконка с вопросом – в systemtray). Переходим в окне дампа OllyDbg на адрес нашей таблицы импорта, не забывая предварительно глянуть – по какой базе система впулила нашу dll (как, вы не знаете, что для dll база загрузки может быть отличной от той, что прописана в заголовке? Теперь знаете…). Дампим в clipboard (правый клик мыши à Binary à Binary copy), переходим в окне дампа OllyDbg на адрес нашей дополнительной секции в outpost.exe, отмечаем мышкой ровно 0xe70 байт от начала и делаем (правый клик мыши à Binary à Binary paste). Почему именно 0xe70? Попробуйте догадаться сами, глядя на дамп. Это конец таблицы ;) Так-с. Не трогая ничего, сразу стартуем ImpREC, указываем ему outpost.exe, в RVA указываем адрес новой секции outpost.exe за минусом базы, размер указываем 0xe70,  жмем Get Imports и видим нормально отсвеченный листбокс с импортом. Теперь остается только выполнить Auto Trace, и распознать неразресолвенные функции через правый клик мыши и Plugin Tracer (ASProtect 1.2x Emul). И, конечно, не забываем сохранить все сделанное по Save Tree.

Снова ничего не трогая, редактируем полученный текстовый файл с импортом. А именно – перестраиваем все Thunk’и (они сейчас базированы на начальный адрес новой секции outpost.exe, и их нужно изменить по базе второй секции dumped1.dll). Сделали? Отлично. Загружаем этот файл в ImpREC по Load Tree. Убираем галочку с Add New Section, в Options убираем галочку с Create New IAT. Это нужно сделать обязательно. Теперь интересный момент. Чтобы понять, что вписать в открывшуюся вторую ячейку RVA следует взять любую несжатую dll из Outpost и посмотреть, где расположена Import Table в Directory. Путем несложных умозаключений я пришел к выводу, что для dumped1.dll этим местом (по крайней мере в моем дампе) был RVA 0x5c228. Именно его и вводим во второй ячейке RVA в ImpREC. Жмем Fix Dump, указываем в качестве dll наш dumped1.dll, на выходе получаем dumped1_.dll, который скоренько переименовываем в dumped2.dll. Загрузив последний в HIEW видим прекрасно разресолвенные джампы, импортируемые функции и т ;)))

 

ЧАСТЬ 3. «Все бы было хорошо…»

 

...Вы спросите – как найти OEP? Да элементарно. В WinMain функе для dll вызывается _initterm из MSVCRT.DLL. Грузим dumped2.dll  в HIEW, находим jmp эту функу (0xFF,0x25,_initterm), затем по F6 ищем ссылку на этот jmp. Нашли? Двигаемся в HIEW вверх построчно, до инструкции

 

mov      eax,   [esp][08]

           

            Становимся на ее начало и жмем F6. Попадаем в WinMain, началом которой является код:

 

                        push        ebp                                    ß Это и есть наш OEP

mov         ebp,esp

push        ebx

mov         ebx,[ebp][08]

push        esi

mov         esi,[ebp][0C]

push        edi

mov         edi,[ebp][10]

test          esi,esi

jne           .010045089  ----- (1)

cmp         d,[100624A0],000 ;" "

jmps        .0100450AF  ----- (2)

cmp         esi,001 ;""

je              .010045093  ----- (3)

cmp         esi,002 ;"[1]"

jne           .0100450B5  ----- (4)

mov         eax,[1006100C]

test          eax,eax

je              .0100450A5  ----- (5)

push        edi

push        esi

push        ebx

call           eax

test          eax,eax

je              .0100450B1  ----- (6)

push        edi

push        esi

push        ebx

call           .010044FC2  ----- (7)

test           eax,eax

jne            .0100450B5  ----- (8)

 

Так, с OEP разобрались, пропишем его в заголовке dumped2.dll с помощью HIEW. Ну, что? Пробуем запустить? Переименовываем dumped2.dll в opst_ui.dll, предварительно сохранив под другим именем оригинальную opst_ui,

запускаем… И тишина… Аутпост просто вываливается безо всяких сообщений… «Мать твою, Маркус…» © Крутые Стволы

 

ЧАСТЬ 4. «Работа над ашипками…»

 

…ну и че мы забыли? А то, что секция данных у нас сдамплена УЖЕ ИНИЦИАЛИЗИРОВАННАЯ! А нужна – девственно чистая, сразу после распаковки. Переименовываем opst_ui.dll обратно в dumped2.dll, восстанавливаем оригинальную opst_ui.dll. Стартуем OllyDbg, загружаем outpost.exe, переходим в окне дампа OllyDbg на адрес третьей секции dumped2.dll и ставим бряку на запись в память на первый байт открывшейся области памяти (правый клик мыши à Breakpoint à Memory, on write). Запускаем процесс по F9, пропускаем крики OllyDbg об эксепшнах по Shift-F9, пока в строке статуса он не сообщит о попытке записи в нашу область памяти. В окне кода мы увидим что-то типа:

 

 00FB262B   F3:A5       REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>    ß мы здесь

00FB262D   89C1         MOV ECX,EAX

00FB262F   83E1 03    AND ECX,3

00FB2632   F3:A4         REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>

00FB2634   5F               POP EDI

00FB2635   5E               POP ESI

00FB2636   C3               RETN

 

Выполняем все до RETN, затем сохраняем область памяти в окне дампа (правый клик мыши à Backup à Save data to file) в файл, например DATA.

 

Перегружаем процесс в памяти OllyDbg по Ctrl-F2 для повторного запуска (нам еще нужно сдампить таким-же образом первую секцию нашей dll). Спросите - зачем? А вспомните, что dll может грузиться с адреса, отличного от базы… Соответственно секция кода перенастраивается на новую базу (дальние джампы и т.д.). Посему она у нас была сдамплена уже настроенная, а нам нужна девственно нетронутая, после распаковки ;) Итак, проделываем все вышеуказанные операции и для первой секции dll, только сохраняем ее в файл CODE.

 

После всего этого загружаем dumped2.dll в HIEW и перезаписываем блок первой секции файлом CODE, а блок третьей секции файлом DATA. Отлично.

 

Кстати! Если вы дампили в отладчике с OEP (до запуска программы), то вам все равно надлежит восстановить секцию кода по моему методу, т.к. на OEP в DLL вы попадаете уже после настройки ее системой и секция кода уже испорчена.

 

ЧАСТЬ 5. «Ну!...»

 

Хрен. Попытавшись снова подставить dumped2.dll в opst_ui.dll и запустить программу, получаем свой GPF «паёк на сегодня»… И какого, спрашивается? Думаем ровно 10 минут (или меньше), пока не падаем, осененные мыслью – а как система настраивает нашу dll, если мы нифига ей для этого не дали? А! О! Есс! Надо-ж что-то подсунуть гадовке, чтобы все заработало. А что? А таблицу Relocations, которая сидит в последней секции нашей dumped2.dll. Так, грузим ее в HIEW, переходим в Hex-режим, жмем F8, F6, смотрим RVA последней секции (.reloc), жмем Esc, F10 (Directory), переходим на Fixups, вбиваем запомненный RVA. В качестве Size указываем размер от начала этой секции до последнего ненулевого байта в ней + 2 байта. У меня получилось 0x6AF4. Вбиваем это значение в Fuxups size. Сохраняем…

 

ЧАСТЬ 6. «Телемаркет»

 

Перезаписываем dumped2.dll вместо opst_ui.dll и наслаждаемся загрузившимся, наконец, аутпостомМля, и все это – ради того, чтобы снять 30-дневный триал? ДА! ИМЕННО! ;)

 

ПОСЛЕСЛОВИЕ:

 

Метод, с вариантами, подходит и для распаковки dll, созданных Delphi, CBuilder. И, конечно, ваш путь по распаковке может варьироваться в неограниченных пределах, если я где был непонятен – исправляйте, не стесняйтесь ;)

 

QIce [TSRh], 30.05.2002

E-Mail:qice@qice.cjb.net