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

ВИДЕОКУРС ВЗЛОМ
выпущен 12 ноября!


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

Создание лоадера для программы, защищённой ASProtect’ом

Обсудить статью на форуме

Хорошая подборка видеоуроков, инструментов крэкера, книг и статей - здесь.

Автор: Dr. Hacker <kostjaermolaev@gmail.com>

Автор не несёт ответственности за возможное противозаконное использование материалов этой статьи.

Струмент:
PEiD и Protection ID (оба необязательны)
OllyDbg
Плагин IsDebugPresent (необязательно)
MASM32 (ml.exe + link.exe)

Нашей жертвой будет программа Abexo Registry Cleaner, неплохой чистильщик реестра. Работает она… 5 дней, после чего начинает трубить о покупке полной версии. Защита –ASProtect весьма солидной версии – 2.0 (такие показания дали PEiD и Protection ID, первый даже выдал 2.0x Registered). Если поначалу я ещё надеялся снять защиту, то в конце концов понял – этот путь для меня закрыт, кишка тонка. Вообще с аспром я не в ладах, хотя и читал некоторые статьи. Представьте мою радость, когда я увидел программу ASProtect stripper, способную убрать аспр первых версий. Хотя все, даже самые свежие, версии его давно уже распакованы, что побуждает Солодовникова (автора) создавать новые, которые со временем, естественно, тоже ломают, в итоге автор опять начинает стараться… Я это называю «естественной эволюцией протектората». Закон философии гласит: «Нет такой защиты, которую нельзя было бы сломать». Защиту я, однако, так и не сломал. Однако в процессе неудачной распаковки я неожиданно нашёл другой путь к взлому – пропатчить пару байт в области памяти, выделенной VirtualAlloc (я уж думаю, аспр использует её, какую же ещё?). Такой патч заставит программу грузиться дальше, а не вылетать в ExitProcess. Почему этот код находится в выделенном регионе, а не в секции кода? Это задумка Солодовникова, призванная затруднить распаковку. Даже OEP, судя по всему, находится не в секции кода, а в таком вот регионе. Хотя полноценным OEP’ом это не назовёшь, так как аспр подмешивает к оригинальным инструкциям массу своего путаного кода, изменяя их до неузнаваемости. Противные jmp и xor мешают их трассировать. Вот иногда и называют точку входа не OEP, а VOEP – виртуальная OEP. Итак, стартуем.

В OllyDbg откроем arc.exe и увидем такую картину:


00401000    68 01B05A00         PUSH    005AB001
00401005    E8 01000000         CALL    0040100B
0040100A    C3                  RET
0040100B    C3                  RET


В задачи этой статьи не входит поиск OEP, поэтому все исключения можно сразу передать аспру: на вкладке Exceptions окна Options следует поставить флажки INT3 breaks и memory access violation. Тыркните F9, и тогда выползет MessageBox c сообщением: “Thank you for trying an Abexo product”. (Здесь и далее я предполагаю, что испытательный срок 5 дней уже вышел, а то иначе вместо MessageBox вы бы увидели нормальное рабочее окно программы.) Нажмите OK, и программа, к сожалению закроется.

НО: если вы увидите собщение “Debugger detected – please close it down and restart!”, значит сработал антиотладочный приём Солодовникова. Проще всего выйти из положения – установить плагин IsDebugPresent, и с его помощью скрыть отладчик от обнаружения. Но если плагина нет – можно всё сделать и своими, не такими уж слабыми руками. Попытки патчить (т.е. вносить изменения) функцию IsDebuggerPresent в kernel32.dll заранее обречены на провал, т.к. Солодовников сам умеет замечать присутствие отладчика, вызывая эту функцию лишь для маскировки. Сделать можно так: будучи в окне дампа, нажмите Ctrl-G и введите fs:[30] (и нажмите Enter). Теперь присмотритесь к окну дампа. Видите третий по счёту байт? Он должен равняться 01, никак не иначе. (Если он равен 00, значит, плагин у вас всё-таки стоит.) Именно этот байт определяет присутствие отладчика. Измените байт на 00. Всё – отладчик теперь у нас, подобно самолёту Стелс, невидим. (Правда, процедуру придётся проделывать после каждого перезапуска программы – скажите за это спасибо компании Microsoft).

Итак, что же делать со всем этим? Первым делом надо узнать, куда MessageBox («Thank you for trying an Abexo product») возвращает управление. Пришёл в голову аппаратный бряк? Не выйдет, к сожалению. Солодовников нашёл способ обходить такие бряки. Насколько знаю, они ставятся через отладочные регистры DR0-DR7, как он их обходит – беспонятие. Это, однако, не снимает вопроса – как нам перехватить MessageBox? Предлагаю следующий способ – во время работы этой функции нажать кнопку паузы, и «вытрассироваться» из функции. В итоге мы окажемся на адресе возврата. Нажатие паузы приведёт к остановке в местечке где-то глубоко в NTDLL, в той области кода, которая используется для вызова Native API. (В Win9x вы остановитесь в kernel32.dll вместо ntdll.dll и совсем в другой области, но это не суть.) Вот это место (для Windows XP):


7C90EB8B    8BD4                MOV     EDX, ESP
7C90EB8D    0F34                SYSENTER
7C90EB8F    90                  NOP
7C90EB90    90                  NOP
7C90EB91    90                  NOP
7C90EB92    90                  NOP
7C90EB93    90                  NOP
7C90EB94    C3                  RET	   <---здесь будем стоять мы


Окно MessageBox станет невозможно активизировать, т.к. программа стоит на паузе. Нажмите пару-тройку раз Ctrl-F9 (это трассировка до команды RET). Функция продолжит работу и только теперь вы сможете нажать кнопку OK. Нажмите её. Далее: надо вернуться в OllyDbg и нажимать Ctrl-F9 до тех пор, пока вы не покинете функцию MessageBox. В заголовке окна отладчика можно видеть “CPU – main thread, module user32”. Вот пока надпись module user32 не исчезнет, надо нажимать Ctrl-F9. (Объяснять, почему module user32, думаю, вам не надо. А вот потом эта надпись исчезнет совсем. Это потому, что код находится в выделенном регионе памяти, а не в секции кода. Если бы он был в секции кода, в заголовке появилось бы “module arc”.) Итак, мы вышли из функции и стоим на адресе возврата. Это ключевое для нас место, присмотритесь к нему:


00B253DB    A1 0488B300         MOV     EAX, [B38804]	     <-- Здесь мы. Это адрес возврата.
00B253E0    8B00                MOV     EAX, [EAX]
00B253E2    8B00                MOV     EAX, [EAX]
00B253E4    8BD0                MOV     EDX, EAX
00B253E6    0350 3C             ADD     EDX, [EAX+3C]
00B253E9    8BC2                MOV     EAX, EDX
00B253EB    F640 17 20          TEST    BYTE PTR [EAX+17], 20
00B253EF    74 21               JE      SHORT 00B25412         ;здесь будем патчить...
00B253F1    A1 0488B300         MOV     EAX, [B38804]
00B253F6    8B00                MOV     EAX, [EAX]
00B253F8    8B40 1C             MOV     EAX, [EAX+1C]
00B253FB    8945 FC             MOV     [EBP-4], EAX
00B253FE    837D FC 00          CMP     DWORD PTR [EBP-4], 0
00B25402    75 07               JNZ     SHORT 00B2540B
00B25404    6A 00               PUSH    0
00B25406    E8 2103FFFF         CALL    00B1572C               ; JMP to kernel32.ExitProcess
00B2540B    8B65 FC             MOV     ESP, [EBP-4]
00B2540E    61                  POPAD
00B2540F    31C0                XOR     EAX, EAX
00B25411    C3                  RET				    ; равносильно выходу из программы
00B25412    6A 01               PUSH    1
00B25414    E8 1303FFFF         CALL    00B1572C               ; JMP to kernel32.ExitProcess
00B25419    59                  POP     ECX			    ;а вот это – выход из функции, нам
00B2541A    5D                  POP     EBP			    ;как раз сюда
00B2541B    C3                  RET


Место чрезвычайно интересное. Если сейчас просто его трассировать, то мы вылетим в ExitProcess c адреса B25414. Эта RET между двумя вызовами ExitProcess – тоже ловушка, если выйти на неё, мы тоже вылетим из программы. (Правда, на сей раз в kernel32.dll, откуда лихо вызывается ExitThread, что тоже равносильно выходу из программы; под Windows 95/98 там не вызывается ExitThread, а идёт прямой вызов ядра системы.) Поэтому придётся искусственно «не дать программе засохнуть» - поставить указатель eip в самый конец этого места, на команду POP ECX. Так можно обойти вызовы ExitProcess и «губительную» команду RET. Проделайте это (щёлкните правой кнопкой по инструкции pop ecx и нажмите New origin here и OK) и отпустите программу нажатием F9. Она заработает! Другой способ – заменить инструкцию je short b25412 на jmp short b25419, что заставит программу всегда прыгать на pop ecx, pop ebx и далее ret. Вот так мы и будем делать в нашем крэке. Заменять инструкцию мы будем лоадером. (Это проще, чем менять значение EIP, нам ведь надо сделать работающий крэк.) После выполнения последней RET программа заработает дальше. Что интересно – дак это то, что ASProtect позже опять возмёт управление. Получается, что не закончив работу, он как бы даёт программе немного поработать, а потом снова берётся за дело? Ведь этот MessageBox – плод явно самой программы, а не протектора. Может, профессиональны что-нибудь знают на этот счёт?

Прекрасно, дыра в защите найдена. Теперь надо делать лоадер. Как сделать лоадер? Ну, загрузить программу легко можно функцией CreateProcess, вносить изменения в код – WriteProcessMemory… Однако встаёт вопрос: как поймать нужный момент для внесения патча? Ведь наш код не сразу появляется в памяти, а только после сложного процесса распаковки, которым руководит ASProtect во главе с Солодовниковым. Ответ: патчить удобно, когда на экране находится окно сообщения MessageBox. А уже когда патч будет внесён, окно сообщения можно насильно закрыть и пропатчённый код тут же выполнится, так, как нам нужно. Правда, этот участок кода изначально не был рассчитан на запись (т.е. на внесение нашего патча). Поэтому придётся вызвать «сложнейшую» функцию VirtualProtectEx, с помощью которой мы дадим региону памяти доступ PAGE_EXECUTE_READWRITE, вместо былого PAGE_EXECUTE_READ. После этого мы спокойно вызовем WriteProcessMemory. Ну а насильно закрыть окно сообщения – дело грубой техники. SendMessage(hWnd,WM_CLOSE,0,0) с этим прекрасно справится. Мы запатчим всего 2 байта, нужные значения можно подсмотреть в отладчике, если заменить je short b25412 на jmp short b25419. Лоадер я решил написать на ассемблере. Вот его код:


REGION_BASE	equ		00B10000h
PATCH_ADDRESS	equ		00B253EFh
CMDLINE		textequ		<'c:\program files\abexocleaner\arc.exe'>

	.386
	.model	flat, stdcall
	option	casemap:none

include		windows.inc
include		kernel32.inc
include		user32.inc
includelib	kernel32.lib
includelib	user32.lib

SZPtr	macro	txt
	local	s
	.const
s	db	txt,0
	.code
	exitm	<offset s>
endm

	.code
stinf	STARTUPINFO		<sizeof stinf,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>
pi	PROCESS_INFORMATION	<>

oldProtect	dd	?
newBytes	db	0EBh,28h

start:
	invoke	CreateProcess,0,SZPtr(CMDLINE),0,0,0,0,0,0,addr stinf,addr pi
	.repeat
		invoke	FindWindow,SZPtr('#32770'),SZPtr('Evaluation Version')
		mov	edi,eax
		invoke	Sleep,100
	.until	edi
	invoke	VirtualProtectEx,pi.hProcess,REGION_BASE,32000h,PAGE_EXECUTE_READWRITE,addr oldProtect
	invoke	WriteProcessMemory,pi.hProcess,PATCH_ADDRESS,addr newBytes,sizeof newBytes,0
	invoke	SendMessage,edi,WM_CLOSE,0,0
	invoke	CloseHandle,pi.hProcess
	ret
	end	start


Этот код следует компилировать так:

ml /c /coff loader.asm
link /subsystem:windows /libpath:<ваш каталог с lib-файломи> /section:.text,rwe

Вся соль - в /section:.text,rwe он даёт секции кода доступ на запись, т.к. данные у меня именно в этой секции. CreateProcess записывает значения в структуры. Если ключа не указать, то программа рухнет уже на первом вызове функции.
На моём компе это работает, уверяю вас. Если вы хотите, чтобы заработало и на вашем, скорее всего придётся изменить константы в начале программы. Дело в том, что базовый адрес региона может меняться, а вместе с ним и адрес вносимого патча. (Я правда не знаю, указывает ли ASProtect какой-нибудь конкретный адрес при вызове VirtualAlloc или нет.) Чтобы получить базовый адрес региона памяти, можно нажать клавишу Home, находясь в этом регионе, и тогда OllyDbg выскочит на начало региона. PATCH_ADDRESS – это адрес инструкции je short 00B25412, помните её? (Можете вернуться в середину статьи и посмотреть на то «интересное место» кода.) Этот адрес тоже меняется в зависимости от базового адреса региона (REGION_BASE). Как его найти – я только что показал – клавиша Home. Ну а как в деталях работает программа, вы сможете понять сами. Для этого надо знать MASM32. (А также фундаментальные принципы работы Windows…)

Ну вот, вроде как бы и всё… Видите, даже не пришлось особо вникать в логику ASProtect’a (в этом вся прелесть лоадеров). Вообще ASProtect представляет собой какой-то сплошной алогизм, к которому неприменим здравый смысл. Ну да ладно, остаётся только поблагодарить авторов за Abexo Registry Cleaner (очень прилично чистит), Алексея Солодовникова за его АСПротекты, а Oleh’а Yuschuk’а за OllyDbg.




Обсуждение статьи: Создание лоадера для программы, защищённой ASProtect’ом >>>


Комментарии к статье: Создание лоадера для программы, защищённой ASProtect’ом

PE_Kill 20.10.2006 11:54:27
Чтобы работало на всех машинах надо искать место патча по сигнатуре...
---
coderess 01.02.2009 01:15:02
PE_Kil абсолютно согласен с тобой
---

Материалы находятся на сайте https://exelab.ru



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


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