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

Дата публикации 27 июн 2002

Антиотладочные хитрости под Win32 — Архив WASM.RU

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

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

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

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

Код (Text):
  1.  
  2.  BOOL IsDebuggerPresent(VOID)

- Аргументы

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

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

  • Если текущий процесс запущен в контексте отладчика, возвращаемое значение не равно нулю.
  • Если текущий процесс не запущен в контексте отладчика, возвращаемое значение равно нулю.

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

Код (Text):
  1.  
  2. ;---[ CUT HERE ]-------------------------------------------------------------
  3.  
  4.        .586p
  5.        .model flat
  6.  
  7. extrn   GetProcAddress:PROC
  8. extrn   GetModuleHandleA:PROC
  9.  
  10. extrn   MessageBoxA:PROC
  11. extrn   ExitProcess:PROC
  12.  
  13.                 .data
  14. szTitle         db      "IsDebuggerPresent Demonstration",0
  15. msg1            db      "Application Level Debugger Found",0
  16. msg2            db      "Application Level Debugger NOT Found",0
  17. msg3            db      "Error: Couldn't get IsDebuggerPresent.",10
  18.                 db      "We're probably under Win95",0
  19.  
  20. @IsDebuggerPresent db   "IsDebuggerPresent",0
  21. K32             db      "KERNEL32",0
  22.  
  23.        .code
  24.  
  25. antidebug1:
  26.         push    offset K32                      ; Получаем адрес базы KERNEL32
  27.         call    GetModuleHandleA
  28.         or      eax,eax                         ; Проверяем на ошибки
  29.         jz      error
  30.  
  31.         push    offset @IsDebuggerPresent       ; Теперь проверяем, существует
  32.         push    eax                             ; ли IsDebuggerPresent. Если
  33.         call    GetProcAddress                  ; GetProcAddress возвращает
  34.         or      eax,eax                         ; ошибку, мы считаем, что мы
  35.         jz      error                           ; в Win95
  36.  
  37.         call    eax                             ; Вызываем IsDebuggerPresent
  38.  
  39.         or      eax,eax                         ; Если она возвращает не 0,
  40.         jnz     debugger_found                  ; нас отлаживают
  41.  
  42. debugger_not_found:
  43.         push    0                               ; Показываем "Debugger not found"
  44.         push    offset szTitle
  45.         push    offset msg2
  46.         push    0
  47.         call    MessageBoxA
  48.         jmp     exit
  49.  
  50. error:
  51.         push    00001010h                       ; Show "Error! We're in Win95"
  52.         push    offset szTitle
  53.         push    offset msg3
  54.         push    0
  55.         call    MessageBoxA
  56.         jmp     exit
  57.  
  58. debugger_found:
  59.         push    00001010h                       ; Show "Debugger found!"
  60.         push    offset szTitle
  61.         push    offset msg1
  62.         push    0
  63.         call    MessageBoxA
  64.  
  65. exit:
  66.         push    00000000h                       ; Exit program
  67.         call    ExitProcess
  68.  
  69. end     antidebug1
  70.  
  71. ;---[ CUT HERE ]-------------------------------------------------------------

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

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

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

Код (Text):
  1.  
  2.         mov     ecx,fs:[20h]
  3.         jecxz   not_being_debugger
  4.         [...]
<--- делайте, что хотите, нас отлаживают :smile3:

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

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

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

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

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

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

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

Код (Text):
  1.  
  2.                 push    dword ptr fs:[0]

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

Код (Text):
  1.  
  2.                 push    offset SEH_Handler
  3.                 mov     fs:[0],esp

Ок, просто как только возможно. Что насчет восстановления исходного SEH. Еще проще. Просто вызовите инструкцию, обратную первой.

Код (Text):
  1.  
  2.                 pop     dword ptr fs:[0]

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

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

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

Код (Text):
  1.  
  2.  tasm32 /m3 /ml sehtest,,;
  3.  tlink32 /Tpe /aa sehtest,sehtest,,import32.lib

Код (Text):
  1.  
  2. ;---[ CUT HERE ]-------------------------------------------------------------
  3.  
  4.         .386p
  5.         .model  flat                            ; 32 бита рулят
  6.  
  7. extrn   MessageBoxA:PROC                        ; Определенные API
  8. extrn   ExitProcess:PROC
  9.  
  10.         .data
  11.  
  12. szTitle         db      "Structured Exception Handler example",0
  13. szMessage       db      "Intercepted General Protection Fault!",0
  14.  
  15.         .code
  16.  
  17. start:
  18.         call    setupSEH
  19.  
  20.  
  21. exceptionhandler:
  22.         mov     esp,[esp+8]                     ; Ошибка дает нам старый ESP
  23.                                                 ; в [ESP+8]
  24.  
  25.         push    00000000h                       ; Аргументы для MessageBoxA
  26.         push    offset szTitle
  27.         push    offset szMessage
  28.         push    00000000h
  29.         call    MessageBoxA
  30.  
  31.         push    00000000h
  32.         call    ExitProcess                     ; Выходим из приложения
  33.  
  34. setupSEH:
  35.         push    dword ptr fs:[0]                ; Push'им оригинальный
  36.                                                 ; обработчик SEH
  37.         mov     fs:[0],esp                      ; И помещаем новый (который
  38.                                                 ; находится после первого
  39.                                                 ; call)
  40.  
  41.         mov     ebx,0BFF70000h                  ; Пытаемся писать в ядро (что
  42.         mov     eax,012345678h                  ; вызовет исключение)
  43.         xchg    eax,[ebx]
  44.  
  45. end     start
  46. ;---[ CUT HERE ]-------------------------------------------------------------

[...]

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

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

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

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

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

Код (Text):
  1.  
  2.          mov    eax, Device_ID
  3.          mov    edi, Device_Name
  4.          int    20h                             ; VMMCall Get_DDB
  5.          dd     00010146h
  6.          mov    [DDB], ecx
  • Определяет, установлен или нет VxD определенного устройства, и если установлен, возвращает DDB для этого устройства.
  • Использует ECX, флаги.
  • Возвращает DDB для определенного устройства, если функция была выполнена успешно.
  • В противном случае возвращает ноль.
  • Device_ID: Идентификатор устройства. Этот параметр может быть равен нулю для именованных устройств.
  • Device_Name: Восьмибуквенное имя устройства, которое дополнено (в случае необходимости) пустыми символами. Этот параметр требуется только тогда, когда Device_ID равен нулю. Имя устройства чувствительно к регистру.

Ладно, вы наверняка удивляетесь, о чем идет разговор. Очень просто, поле Device_ID VxD SoftICE постоянно для всех программ, а так как оно зарегистрировано в Micro$oft'е, у нас есть оружие против этого отладчика. Его Device_ID всегда равно 202h. Поэтому мы можем использовать следующий код:

Код (Text):
  1.  
  2.         mov     eax,00000202h
  3.         VxDCall VMM_Get_DDB
  4.         xchg    eax,ecx
  5.         jecxz   NotSoftICE
  6.         jmp     DetectedSoftICE

Где NotSoftICE должно быть продолжением кода вируса, а метка DetectedSoftICE должна обрабатывать тот случай, если наш враг жив :smile3:. Я не предполагаю здесь никакой деструкции, так как, например, на моем компьютере SoftICE всегда активен :smile3:.

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

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

Код (Text):
  1.  
  2.  На входе:
  3.  
  4.         AX = 1684h
  5.         BX = virtual device (VxD) ID (see #1921)
  6.         ES:DI = 0000h:0000h
  7.  
  8.  На выходе:
  9.  
  10.         ES:DI -> входная точка VxD API, или 0:0, если VxD не поддерживает этот
  11.         API.
  12.  
  13.  N.B.:  некоторые виртуальные устройства в улучшенном режиме Windows
  14.         предоставляют сервисы, которые могут использовать приложения.
  15.         Например, Virtual Display Device предоставляет API, используемый
  16.         WINOLDAP.

Поэтому вы поместите 202h в BX, запустите эту функцию. А потом скажете... "Эй, Билли... Через какое место я могу использовать прерывания?". Мой ответ... ИСПОЛЬЗУЙТЕ VxDCALL0!!!

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

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

Код (Text):
  1.  
  2.         + SoftICE для Win9x : "\\.\SICE"
  3.         + SoftICE для WinNT : "\\.\NTICE"

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

Код (Text):
  1.  
  2. ;---[ CUT HERE ]-------------------------------------------------------------
  3.  
  4.         .586p
  5.         .model  flat
  6.  
  7. extrn   CreateFileA:PROC
  8. extrn   CloseHandle:PROC
  9. extrn   MessageBoxA:PROC
  10. extrn   ExitProcess:PROC
  11.  
  12.         .data
  13.  
  14. szTitle         db      "SoftICE detection",0
  15.  
  16. szMessage       db      "SoftICE for Win9x : "
  17. answ1           db      "not found!",10
  18.                 db      "SoftICE for WinNT : "
  19. answ2           db      "not found!",10
  20.                 db      "(c) 1999 Billy Belcebu/iKX",0
  21.  
  22. nfnd            db      "found!    ",10
  23.  
  24. SICE9X          db      "\\.\SICE",0
  25. SICENT          db      "\\.\NTICE",0
  26.  
  27.         .code
  28.  
  29. DetectSoftICE:
  30.         push    00000000h                       ; Проверяем наличии
  31.         push    00000080h                       ; SoftICE для среды Win9x
  32.         push    00000003h
  33.         push    00000000h
  34.         push    00000001h
  35.         push    0C0000000h
  36.         push    offset SICE9X
  37.         call    CreateFileA
  38.  
  39.         inc     eax
  40.         jz      NoSICE9X
  41.         dec     eax
  42.  
  43.         push    eax                             ; Закрываем открытый файл
  44.         call    CloseHandle
  45.  
  46.         lea     edi,answ1                       ; SoftICE найден!
  47.         call    PutFound
  48. NoSICE9X:
  49.         push    00000000h                       ; А теперь пытаемся открыть
  50.         push    00000080h                       ; SoftICE для WinNT...
  51.         push    00000003h
  52.         push    00000000h
  53.         push    00000001h
  54.         push    0C0000000h
  55.         push    offset SICENT
  56.         call    CreateFileA
  57.  
  58.         inc     eax
  59.         jz      NoSICENT
  60.         dec     eax
  61.  
  62.         push    eax                             ; Закрываем хэндл файла
  63.         call    CloseHandle
  64.  
  65.         lea     edi,answ2                       ; SoftICE для WinNT найден!
  66.         call    PutFound
  67. NoSICENT:
  68.         push    00h                             ; Показываем MessageBox с
  69.         push    offset szTitle                  ; результатами
  70.         push    offset szMessage
  71.         push    00h
  72.         call    MessageBoxA
  73.  
  74.         push    00h                             ; Завершаем программу
  75.         call    ExitProcess
  76.  
  77. PutFound:
  78.         mov     ecx,0Bh                         ; Меняем "not found" на
  79.         lea     esi,nfnd                        ; "found"; адрес, где нужно
  80.         rep     movsb                           ; изменить, находится в EDI
  81.         ret
  82.  
  83. end     DetectSoftICE
  84.  
  85. ;---[ CUT HERE ]-------------------------------------------------------------

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

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

Ладно, вот я и рассказал о нескольких простых антиотладочных трюках. Я надеюсь, что вы сможете использовать их в своих вирусах без проблем. Пока! © Billy Belcebu/iKX, пер. Aquila


0 1.627
archive

archive
New Member

Регистрация:
27 фев 2017
Публикаций:
532