Исследование программы Ulead Gif Animator v3.0

{codecitation class=»brush: pascal; gutter: false;» width=»600px»}

В центре Москвы очередная бандитская разборка. С братками, джипами, автоматной перестрелкой. Программист бросается на тротуар и машинально на асфальте: «IDDQD, IDDQD».

Введение

Целью нашего сегодняшнего исследования будет Ulead Gif Animaton v3.0. Программа защищена с помощью Vbox v4.10. Защитные алгоритмы реализованы в трех DLL: Vboxp410.dll, Vboxb410.dll и Vboxt410.dll (или Vboxc410.dll – в «коммерческой» версии). Все эти библиотеки , за исключением первой, упакованны, поэтому все модификации мы будем вносить в Vboxp410.dll.

Как осуществляется защита? Тело программы модифицируется так, что сначала вызывается процедура проверки, и, после ее прохождения, происходит переход на реальную точку входа программы, если проверка прошла успешно, или на выход, если отведенное для тестирования программы время истекло. В теле нашей программы это выглядит так (дизассемблерные листинги взяты из WinDASM’а):

* Reference To: vboxp410., Ord:0001h

|

:004A8020 Call dword ptr [004A8290]

:004A8026 push FFFFFFFF

:004A802B call eax

:004A802D ret 000C

Первое, что приходит на ум – «подсмотреть» нужное значение регистра EAX, и, подкорректировав стек, сделать переход (jmp) через процедуру проверки. Попробуйте… Не вышло? Это потому, что защита, кроме процедуры проверки, осуществляет восстановление заголовка и секций файла. Значит, нужно исследовать защиту. Думаю, многие пробовали это и до меня, но заканчивали с плачевным результатом. Защита действительно сильная. Модули проверяются на изменения в файле на диске (CRC), мало того, производится еще и проверка «развернутого» кода в памяти после запуска. Именно проверка кода в памяти и реагирует на установки контрольных точек (bpx) в SoftICE, ведь реально SoftICE заменяет код по нужному адресу на int 3 и выполняет i3here on. Следовательно, обычные контрольные точки применять нельзя – нарушим целостность кода в памяти.

Исследование

При запуске защищенной программы появляется окно, сообщающее об оставшемся времени. Находится это окно по адресу 070025C3 в Vboxt410.dll (которая нам недоступна) – поставьте в SoftICE контрольную точку bpmb 070025C3 x (это наша замена bpx) – и попадете в функцию DialogBoxParamA(). Вы убедитесь, что при нажатии кнопки «Quit» содержимое регистра ЕАХ будет равно 1, а при нажатии кнопки «Try» – нулю. Переведите часы на месяц вперед, и снова запустите программу. Нажав кнопку «Quit» вручную измените содержимое регистра ЕАХ на 0, и продолжите выполнение программы. Появится стандартный MessageBox с сообщением, что испытательный срок работы истек, и программа закрывается. Происходит это по адресу 7035629 (KERNEL32!EnterCriticalSection). Если же вместо вызова функции (сall) сделать переход через него с соответствующей коррекцией стека – программа будет работать. Попробуем проделать то же самое с DialogBoxParamA(), и Вы увидите, что здесь это не поможет – защита проверяет, выполнялась ли данная процедура, или нет, и реа

гирует соответствующим образом.

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

Обозначим наши цели:

Изменить DialogBoxParamA() – иммитировать нажатие кнопки «Try».

Выполнить обход процедуры KERNEL32!EnterCriticalSection.

Скрыть наши действия от программных проверок.

Проделывать мы все это будем с Vboxp410.dll, и начнем с ее заголовка. Запускаем ProcDump, нажимаем кнопку «PE Editor», и открываем нашу DLL. Нажимаем кнопку «Sections». В описании характеристик секции .text мы видим 60000020, что означает Code, Executable, Readable . Изменяем это значение на E0000020: нажимаем правой кнопкой мыши на .text, и выбираем пункт «Edit Section». Теперь секция .rdata, значение характеристик равно 40000040, что означает Initialized Data, Readable. Изменяем это значение на C0000040. Этим самым мы изменили параметр файла Readable (только чтение) на свободный доступ – чтение и запись. Если бы мы этого не сделали, то при работе нашего модуля, который будет изменять свой же код, мы бы получили ошибку Invalid Page Fault. Далее перед нами стоит задача найти свободное место для записи нашего кода. Эта DLL создана с помощь компилятора С , который включает в код кучу ненужного мусора. Свободное место нашлось, начиная с адреса 5021918.

Теперь описание нашей процедуры:

VBOXP410.DLL , точка входа:

5001F99 E97AF90100 jmp 05021918

Процедуры обработки:

5021918 C705991F0005B8960402 mov dword ptr [05001F99],020496B8

5021922 C6059D1F000505 mov byte ptr [05001F9D],05

5021929 A1AOB50205 mov eax,[0502B5A0]

502192E C705AOB5020554190205 mov dword ptr [0502B5A0],05021954

5021938 A344190205 mov [05021944],eax

502193D E95706FEFF jmp 05001F99

5021942 0000

5021944 0000

5021946 0000

5021948 0000

502194A 0000

502194C 0000

502194E 0000

5021950 0000

5021952 0000

5021954 66FF0542190205 inc word ptr [05021942]

502195B 66813D421902050040 cmp word ptr [05021942],4000

5021964 742B jz 05021991

5021966 66813D42190205002E cmp word ptr [05021942],2EOO

502196F 7534 jnz 050219A5

5021971 C70590890507AB190205 mov dword ptr [07058990],050219AB

502197B A1348A0507 mov eax,[07058A34]

5021980 A348190205 mov [05021948],eax

5021985 C705348A0507AE190205 mov dword ptr [07058A34],050219AE

502198F EB14 jmp 050219A5

5021991 A1E8760808 mov eax,[080876E8]

5021996 A348190205 mov [05021948],eax

502199B C705E8760808AE190205 mov dword ptr [080876E8],050219AE

50219A5 FF2544190205 jmp [05021944]

50219AB C21000 ret 0010

50219AE 8B442410 mov eax,[ESP 10]

50219B2 A34C190205 mov [0502194C],eax

50219B7 C7442410E1190205 mov dword ptr [esp 10],050219E1

50219BF 8F0550190205 pop dword ptr [05021950]

50219C5 68D0190205 push 050219DO

50219CA FF2548190205 jmp [05021948]

50219DO 33CO xor eax, eax

50219D2 66C70554190205EB4F mov word ptr [05021954],4FEB

50219DB FF2550190205 jmp [05021950]

50219E1 837C240818 cmp dword ptr [ESP 08],18

50219E6 7510 jnz 050219F8

50219E8 C744240811010000 mov dword ptr [ESP 08],00000111

50219FO C744240C95040000 mov dword ptr [esp OC],00000495

50219F8 FF254C190205 jmp [0502194C]

С точки входа (5001F99) переход осуществляется на нашу процедуру модификации. После загрузки DLL этот переход будет заменен оригинальным кодом, что сохранит нормальный вид DLL для прохождения программных проверок. Также наш код как бы ставит hook на вызов EnterCriticalSection(), и заменяет его на наш, новый обработчик. Этот обработчик ждет, пока не распакуется Vboxt410.dll, и после этого перенаправляет вызовы RaiseExeption() и DialogBoxParamA() на наши обработчики. Наш обработчик вызова RaiseException() представляет собой команду RET 10 – немедленный возврат с коррекцией стека. А вот обработчик DialogBoxParamA() немного сложнее: он вносит в стек значения, эмулирующие нормальный возврат из нормальной процедуры DialogBoxParamA(), и перехватывает процедуру передачи сообщений на диалог, подменяя ее своим обработчиком. Этот обработчик ждет, пока в окно не будет посланно сообщение WM_SHOWWINDOW, и заменяет его сообщением закрытия окна. После чего в регистр ЕАХ записывается ноль, и обработчик изолируется, записывая

в свое начало команду безусловного перехода (jmp) на настоящий Critical_Handler. После чего мы выходим из нашего обработчика обратно в защиту, которая пытается показать окно с сообщением об истечении срока действия программы (DialogBoxParamA), контроль над которым осуществляет наш код – окно лишь промелькнет на экране. После этого вызывается API-функция RaiseException(). Но она тоже контролируется нашим кодом, который просто делает возврат с коррекцией стека. После всего этого запускается защищенная программа.

Для тех, кто не понял, привожу указанное выше вкратце:

Загружается Vboxp410.dll, сразу же просходит безусловный переход на наш обработчик, который восстанавливает измененный код в точке входа (то место, откуда был JMP), и ставит HOOK на процедуру EnterCriticalSection() – для ожидания распаковки Vboxt410.dll.

Наш обработчик ждет окончания распаковки и проверки, и ставит hook на RaiseException() и DialogBoxParamA().

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

Новый обработчик RaiseException() осуществляет возврат, не производя никаких действий.

Ниже приведен тот же код в «структурном» виде:

Точка входа:

jmp Восстановление кода

Восстановление кода:

mov dword ptr [Точка входа],020496B8 – восстановление точки входа

mov byte ptr [Точка входа 4],05 – восстановление точки входа

mov eax,[KERNEL32!EnterCriticalSection]

mov dword ptr [KERNEL32!EnterCriticalSection], Новый обработчик EnterCriticalSection

– подмена обработчика

mov [Временный контейнер для EnterCriticalSection],eax

jmp Точка входа

Cчетчик:

dw 0

Временный контейнер для EnterCriticalSection:

dd 0

Контейнер для диалога:

dd 0

Контейнер для процедуры диалога:

dd 0

Контейнер возврата из диалога:

dd 0

Новый обработчик EnterCriticalSection:

inc word ptr [Счетчик]

cmp word ptr [Cчетчик],4000

jz Hook DialogBox для VBOXC410 – подмена обработчика DialogBoxParamA после распаковки

cmp word ptr [Cчетчик],2EOO

jnz Реальный обработчик EnterCriticalSection – еще не распакованна, обрабатывается

«родным» обработчиком

Обработчики для VBOXT410:

mov dword ptr [KERNEL32!RaiseException], Новый обработчик RaiseException

– подмена обработчика

mov eax,[USER32!DialogBoxParamA]

mov [Контейнер для диалога],eax

mov dword ptr [USER32!DialogBoxParamA], Указатель на новый обработчик

— подмена обработчика

jmp настоящий EnterCriticalSection

Обработчик для VBOXC410:

mov eax,[USER32!DialogBoxParamA]

mov [Контейнер диалога],eax

mov dword ptr [USER32!DialogBoxParamA], Указатель на новый обработчик диалога

– подмена обработчика

Настоящий EnterCriticalSection:

jmp [Контейнер для EnterCriticalSection]

Новый обработчик RaiseException:

ret 10

Новый обработчик диалога:

mov eax,[esp 1O]

mov [Контейнер процедуры диалога],eax

mov dword ptr [esp 1O],Новый обработчик процедуры диалога

pop dword ptr [Возврат из диалога]

push Call_возврат из диалога

jmp [Контейнер для диалога]

Call_возврат из диалога:

xor eax,eax

mov word ptr [Новый обработчик EnterCriticalSection],4feb

jmp [Возврат из диалога]

Указатель на новую процедуру диалога:

cmp dword ptr [esp 08],18

jnz Указатель на настоящую процедуру диалога

mov dword ptr [esp 08],111

mov dword ptr [esp OC],495

Указатель на настоящую процедуру диалога:

jmp [Контейнер для процедуры диалога]

Заключение

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

{/codecitation}

Добавить комментарий