Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Професиональное программирование


Информационный Канал Subscribe.Ru

Я вас приветствую.

Вот и заканчивается неделя ассемблерного программирования...
На следующей неделе к выходу планируются статьи по QNX от установки до драйверов.

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

А сегодня

Антиотладочные хитрости под Win32

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



[ Win98/NT: Обнаружение отладчиков уровня приложения с помощью функции IsDebuggerPresent
]

Этой функции нет в Win95, поэтому вам следует вначале выяснить, существует ли
она, и работает только с отладчиками уровня приложения (таким как TD32). Она
работает прекрасно. Давайте посмотрим, что написано о ней в справочнике по Win32
API.

Функция IsDebuggerPresent показывает, запущен ли вызывающий ее процесс в контексте
отладчика. Эта функция экспортируется из KERNEL32.DLL.


BOOL IsDebuggerPresent(VOID)
- Аргументы

У этой функции нет аргументов.

- Возвращаемое значение

Если текущий процесс запущен в контексте отладчика, возвращаемое значение не
равно нулю.
Если текущий процесс не запущен в контексте отладчика, возвращаемое значение
равно нулю.
Пример, демонстрирующий эту функцию очень прост. Вот он:


;---[ CUT HERE ]-------------------------------------------------------------

 .586p
 .model flat

extrn GetProcAddress:PROC
extrn GetModuleHandleA:PROC

extrn MessageBoxA:PROC
extrn ExitProcess:PROC

 .data
szTitle db "IsDebuggerPresent Demonstration",0
msg1 db "Application Level Debugger Found",0
msg2 db "Application Level Debugger NOT Found",0
msg3 db "Error: Couldn't get IsDebuggerPresent.",10
db "We're probably under Win95",0

@IsDebuggerPresent db "IsDebuggerPresent",0
K32 db "KERNEL32",0

 .code

antidebug1:
push offset K32 ; Получаем адрес базы KERNEL32
call GetModuleHandleA
or eax,eax ; Проверяем на ошибки
jz error

push offset @IsDebuggerPresent ; Теперь проверяем, существует
push eax ; ли IsDebuggerPresent. Если
call GetProcAddress ; GetProcAddress возвращает
or eax,eax ; ошибку, мы считаем, что мы
jz error ; в Win95

call eax ; Вызываем IsDebuggerPresent

or eax,eax ; Если она возвращает не 0,
jnz debugger_found ; нас отлаживают

debugger_not_found:
push 0 ; Показываем "Debugger not found"
push offset szTitle
push offset msg2
push 0
call MessageBoxA
jmp exit

error:
push 00001010h ; Show "Error! We're in Win95"
push offset szTitle
push offset msg3
push 0
call MessageBoxA
jmp exit

debugger_found:
push 00001010h ; Show "Debugger found!"
push offset szTitle
push offset msg1
push 0
call MessageBoxA

exit:
push 00000000h ; Exit program
call ExitProcess

end antidebug1

;---[ CUT HERE ]-------------------------------------------------------------
Не правда ли, это красиво? Micro$oft сделал эту работу за нас :). Но, конечно,
не ждите, что этот метод будет работать с SoftIce'ом, богом отладки.

[ Win32: Другой путь, как узнать, что мы находимся в контесте отладчика ]

Если вы смотрели статью "Wub95 Structure and Secrets", которая была написана
Murkry/iKX, и опубликована в Xin-3, вы сообразите, что в регистре FS находится
очень крутая структура. Давайте взглянем в поле FS:[20h]... Это 'DebugContext'.
Всего лишь сделаем следующее:


mov ecx,fs:[20h]
jecxz not_being_debugger
[...]
<--- делайте, что хотите, нас отлаживают :)
Потому, если FS:[20h] равен нулю, нас не отлаживают. Наслаждайтесь этим маленьким
и простым методом для обнаружения отладчиков! Конечно, это не сработает против
SoftICE...

[ Win32: Остановка отладчиков уровня приложения с помощью SEH ]

Я не знаю почему, но отладчики уровня приложения умирают, если программа использует
SEH. Эмуляторы код, если мы делаем ошибки, умирают тоже :). SEH, как я писал
в своей статье для DDT#1, используется для многих интересных целей. Хорошо, так
как я не хочу рассказывать все это заново, я просто скопирую и вставлю мое старое
описание :).

--[DDT#1.2_6]---------------------------------------------------------------

Хорошо, это очень простой туториал о Structured Exception Handler. Когда я увидел
SEH, реализованный в вирусе, я подумал "Хорошо, это большая работа. Наверное,
это было сложно реализовать". Поэтому я просто пропустил это. Но, как только
мой Destiny сделал General Protection Fault'ы под NT, я понял, что я должен сделать
что-то. И SEH - это единственный путь. Хорошо, мы можем сделать этоу очень сложным
или очень простым для понимания. Конечно, я предпочитаю сделать это попроще :).

% Установка фрейма SEH %

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


push dword ptr fs:[0]
А теперь надо установить указатель на наш обработчик (например, представьте,
что мы используем call для вызова настройки SEH, а наш обработчик идет непосредственно
после этой инструкции call: мы можем использовать смещение ret).


push offset SEH_Handler
mov fs:[0],esp
Ок, просто как только возможно. Что насчет восстановления исходного SEH. Еще
проще. Просто вызовите инструкцию, обратную первой.


pop dword ptr fs:[0]
Удивительно, что может сделать эта простая для реализации вещь для наших вирусов.
Для меня (и мне было важно именно это использование SEH) наиболее главным было
то, что я смог избежать всех этих отвратительных голубых экранов, когда мы запускаем
наш Win95-вирус в среде NT.

% Пример использования SEH %

Мы можем скомпилировать данный пример следующим образом:


tasm32 /m3 /ml sehtest,,;
tlink32 /Tpe /aa sehtest,sehtest,,import32.lib

;---[ CUT HERE ]-------------------------------------------------------------

 .386p
 .model flat ; 32 бита рулят

extrn MessageBoxA:PROC ; Определенные API
extrn ExitProcess:PROC

 .data

szTitle db "Structured Exception Handler example",0
szMessage db "Intercepted General Protection Fault!",0

 .code

start:
call setupSEH


exceptionhandler:
mov esp,[esp+8] ; Ошибка дает нам старый ESP
; в [ESP+8]

push 00000000h ; Аргументы для MessageBoxA
push offset szTitle
push offset szMessage
push 00000000h
call MessageBoxA

push 00000000h
call ExitProcess ; Выходим из приложения

setupSEH:
push dword ptr fs:[0] ; Push'им оригинальный
; обработчик SEH
mov fs:[0],esp ; И помещаем новый (который
; находится после первого
; call)

mov ebx,0BFF70000h ; Пытаемся писать в ядро (что
mov eax,012345678h ; вызовет исключение)
xchg eax,[ebx]

end start
;---[ CUT HERE ]-------------------------------------------------------------
[...]

--[DDT#1.2_6]---------------------------------------------------------------

Я надеюсь, что вы поняли все это. Если нет... Ладно, забудьте об этом :). Также
как и другие методы, представленные выше, он не работает по отношению к SoftICE.

[ Win9X: Обнаружение SoftICE (I) ]

Здесь я должен поблагодарить Super/29A, потому что именно он рассказал мне об
этом методе. Я разделил его на две части: в этой мы рассмотрим, как использовать
его из вирусов Rin-0. Я не буду помещать здесь программу-пример целиком, потому
что она займет лишнее место, но вы должны знать, что этот метод должен выполняться
в Rin-0, а VxDCall должен быть восстановлен из-за проблемы обратного вызова (вы
помните о ней?).

Ок, мы будем использовать сервис менеджера виртуальных машин (VMM) Get_DDB, поэтому
сервис будет 00010146h (VMM_Get_DDB). Давайте посмотрим, что говорится об этом
сервисе в SDK.


mov eax, Device_ID
mov edi, Device_Name
int 20h ; VMMCall Get_DDB
dd 00010146h
mov [DDB], ecx
Определяет, установлен или нет VxD определенного устройства, и если установлен,
возвращает DDB для этого устройства.
Использует ECX, флаги.
Возвращает DDB для определенного устройства, если функция была выполнена успешно.
В противном случае возвращает ноль.
Device_ID: Идентификатор устройства. Этот параметр может быть равен нулю для
именованных устройств.
Device_Name: Восьмибуквенное имя устройства, которое дополнено (в случае необходимости)
пустыми символами. Этот параметр требуется только тогда, когда Device_ID равен
нулю. Имя устройства чувствительно к регистру.
Ладно, вы наверняка удивляетесь, о чем идет разговор. Очень просто, поле Device_ID
VxD SoftICE постоянно для всех программ, а так как оно зарегистрировано в Micro$oft'е,
у нас есть оружие против этого отладчика. Его Device_ID всегда равно 202h. Поэтому
мы можем использовать следующий код:


mov eax,00000202h
VxDCall VMM_Get_DDB
xchg eax,ecx
jecxz NotSoftICE
jmp DetectedSoftICE
Где NotSoftICE должно быть продолжением кода вируса, а метка DetectedSoftICE
должна обрабатывать тот случай, если наш враг жив :). Я не предполагаю здесь
никакой деструкции, так как, например, на моем компьютере SoftICE всегда активен
:).

[ Win9X: Обнаружение SoftICE (II) ]

Ладно, теперь идет другой метод для обнружения моего возлюбленного SoftICE'а,
но основанный на той же самой идее, что и выше: 202h ;). Снова я должен поблагодарить
Super :). Ладно, в Ralph Brown Interrupt list мы можем найти очень крутой сервис:
прерывание 2Fh, функция 1684h.


На входе:

AX = 1684h
BX = virtual device (VxD) ID (see #1921)
ES:DI = 0000h:0000h

На выходе:

ES:DI -> входная точка VxD API, или 0:0, если VxD не поддерживает этот
API.

N.B.: некоторые виртуальные устройства в улучшенном режиме Windows
предоставляют сервисы, которые могут использовать приложения.
Например, Virtual Display Device предоставляет API, используемый
WINOLDAP.
Поэтому вы поместите 202h в BX, запустите эту функцию. А потом скажете... "Эй,
Билли... Через какое место я могу использовать прерывания?". Мой ответ... ИСПОЛЬЗУЙТЕ
VxDCALL0!!!

[ Win32: Обнаружение SoftICE (III) ]

И наконец, чудесный трюк, которого вы ждали... Универсальный способ найти SoftICE
и Win9x и в WinNT! Это очень просто, 100% основанно на API и без всяких "грязных"
трюков, которые не идут на пользу совместимости. И ответ находится не так далеко,
как вы думаете... ключ заключается в API, который вы уже использовали раньше:
CreateFile. Да, именно эта функция... Разве это не прекрасно? Ладно, мы можем
попытаться открыть следующее:


+ SoftICE для Win9x : ".SICE"
+ SoftICE для WinNT : ".NTICE"
Если функция возвращает нам что-нибудь, отличное от -1 (INVALID_HANDLE_VALUE),
SoftICE запущен! Далее следует демонстрационная программа:


;---[ CUT HERE ]-------------------------------------------------------------

 .586p
 .model flat

extrn CreateFileA:PROC
extrn CloseHandle:PROC
extrn MessageBoxA:PROC
extrn ExitProcess:PROC

 .data

szTitle db "SoftICE detection",0

szMessage db "SoftICE for Win9x : "
answ1 db "not found!",10
db "SoftICE for WinNT : "
answ2 db "not found!",10
db "(c) 1999 Billy Belcebu/iKX",0

nfnd db "found! ",10

SICE9X db ".SICE",0
SICENT db ".NTICE",0

 .code

DetectSoftICE:
push 00000000h ; Проверяем наличии
push 00000080h ; SoftICE для среды Win9x
push 00000003h
push 00000000h
push 00000001h
push 0C0000000h
push offset SICE9X
call CreateFileA

inc eax
jz NoSICE9X
dec eax

push eax ; Закрываем открытый файл
call CloseHandle

lea edi,answ1 ; SoftICE найден!
call PutFound
NoSICE9X:
push 00000000h ; А теперь пытаемся открыть
push 00000080h ; SoftICE для WinNT...
push 00000003h
push 00000000h
push 00000001h
push 0C0000000h
push offset SICENT
call CreateFileA

inc eax
jz NoSICENT
dec eax

push eax ; Закрываем хэндл файла
call CloseHandle

lea edi,answ2 ; SoftICE для WinNT найден!
call PutFound
NoSICENT:
push 00h ; Показываем MessageBox с
push offset szTitle ; результатами
push offset szMessage
push 00h
call MessageBoxA

push 00h ; Завершаем программу
call ExitProcess

PutFound:
mov ecx,0Bh ; Меняем "not found" на
lea esi,nfnd ; "found"; адрес, где нужно
rep movsb ; изменить, находится в EDI
ret

end DetectSoftICE

;---[ CUT HERE ]-------------------------------------------------------------
Это действительно работает, поверьте мне :). Тот же метод можно применить к "враждебным"
драйверам, просто проведите небольшое исследование.



Вот на сегодня и все.
Удачим вам.
Громозека.
http://shelek.com/club
http://shelek.com/
http://shelek.com/bn


http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное