Статья
Версия для печати
Обсудить на форуме
Антиотладочные хитрости под 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, потому что именно он рассказал мне об этом методе. Я разделил его на две части: в этой мы рассмотрим, как использовать его из вирусов Ring-0. Я не буду помещать здесь программу-пример целиком, потому что она займет лишнее место, но вы должны знать, что этот метод должен выполняться в Ring-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 ]-------------------------------------------------------------

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

Заключительные слова


Ладно, вот я и рассказал о нескольких простых антиотладочных трюках. Я надеюсь, что вы сможете использовать их в своих вирусах без проблем. Пока!
Версия для печати
Обсудить на форуме