Автор не несет никакой
ответственности за использование или неиспользование данной
статьи, за возможный моральный или материальный ущерб, так или иначе связанный
с этой статьей. Данная статья приведена
исключительно в образовательных целях, и Вы не должны использовать полученные
знания в нарушение действующего законодательства.
РАСПАКОВКА .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, и… И ничего, кроме Can’t 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