Путеводитель по написанию вирусов под Win32: 8. Антиотладка под Win32

Дата публикации 31 окт 2002

Путеводитель по написанию вирусов под Win32: 8. Антиотладка под Win32 — Архив WASM.RU

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

Win98/NT: обнаружение отладчиков уровня приложения (IsDebuggerPresent)

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

Код (Text):
  1.  
  2.  -·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·
  3.  Функция IsDebuggerPresent сообщает, запущен ли вызвавший ее процес в контексте
  4.  отладчика. Эта функция экспортируется из KERNEL32.DLL.
  5.  
  6.  BOOL IsDebuggerPresent(VOID)
  7.  
  8.  Параметры
  9.  ---------
  10.  
  11.  У этой функции нет параметров.
  12.  
  13.  Возвращаемое значение
  14.  ---------------------
  15.  
  16.  ¤ Если текущий процесс запущен в контексте отладчика, возвращаемое значение
  17.    не равно нулю.
  18.  
  19.  ¤ Если текущий процесс не запущен в контексте отладчика, возвращаемое значение
  20.    равно нулю.
  21.  -·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·

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

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

Разве не красиво? Micro$oft сделала за нас всю работу :smile3:. Но, конечно, не ожидайте, что этот метод будет работать с SoftICE ;).

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

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

Код (Text):
  1.  
  2.         mov     ecx,fs:[20h]
  3.         jecxz   not_being_debugger
  4.         [...]   &lt;--- делайте что угодно, нас отлаживают <img src="styles/smiles_s/smile3.gif" class="mceSmilie" alt=":smile3:" title="Smile3    :smile3:">

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

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

Я еще не знаю почему, но отладчики уровня приложения падают, если программа просто использует SEH. Также как и кодоэмуляторы, если вызываются исключения :smile3:. SEH, о котором я писал в DDT#1, используется для многих интересных вещей. Идите и прочитайте главу "Продвинутые Win32-техники", часть которой я посвятил SEH.

Вам потребуется сделать SEH-обработчик, который будет указывать на код, чье выполнение начнется после исключения, которого можно добиться, например, попытавшись записать что-нибудь по адресу 00000000h ;).

Хорошо, я надеюсь, что вы поняли это. Если нет... Гхрм, забудьте это ;). Также, как и методы, изложенные ранее, данный методы нельзя применить к SoftICE.

Win9X: Detect SoftICE (I)

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

Ок, мы собираемся использовать сервис VMM Get_DDB, т.е. сервис равен 00010146 (VMM_Get_DDB). Давайте посмотрим информацию об этом сервисе в SDK.

Код (Text):
  1.  
  2.  -·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·
  3.          mov    eax, Device_ID
  4.          mov    edi, Device_Name
  5.          int    20h                             ; VMMCall Get_DDB
  6.          dd     00010146h
  7.          mov    [DDB], ecx
  8.  
  9.  - Определяет, установлен или нет VxD для определенного устройства и возвращает
  10.    DDB для этого устройства, если он инсталлирован.
  11.  
  12.  - Использует ECX, флаги.
  13.  
  14.  - Возвращает DDB для указанного устройства, если вызов функции прошел успешно;
  15.  - в противном случае возвращается ноль.
  16.  
  17.  &curren; Device_ID: идентификатор устройства. Этот параметр может быть равен нулю
  18.    для именованных устройств.
  19.  
  20.  &curren; Device_Name: восьмисимвольное имя устройства (может выравниваться до этого
  21.    размера пробелами). Этот параметр требуется только, если Device_ID равен
  22.    нулю. Имя устройства чувствительно к регистру.
  23.  -·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·

Вы, наверное, думаете, что все это значит. Очень просто. Поле Device_ID в VxD SoftIce'а всегда постоянно, так как оно зарегистрировано в Micro$oft'е, что мы можем использовать в качестве оружия против чудесного SoftIce, Его 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 = виртуальное устройство (VxD) ID (смотри #1921)
  6.          ES:DI = 0000h:0000h
  7.  Возврат:ES:DI -&gt; входная точка VxD API или 0:0, если VxD не поддерживает
  8.             API
  9.  Обратите внимание: некоторые драйвера устройств предоставляют приложениям
  10.          определенные сервисы. Например, Virtual Display Device (VDD)
  11.          предоставляет API, используемый WINOLDAP.
  12.  -·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·

Таким образом, вы помещаете BX в 202h и запускаете эту функцию. А затем говорите... "Эй, Билли... Как мне использовать прерывания?". Мой ответ... ИСПОЛЬЗУЙТЕ 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                       ; Проверяем наличие SoftICE
  31.         push    00000080h                       ; для среды окружения 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                           ; совершить изменение находится
  81.                             ; в EDI
  82.         ret
  83.  
  84. end     DetectSoftICE
  85.  
  86. ;---[ CUT HERE ]-------------------------------------------------------------

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

Win9x: Убить хардверные брикпоинты отладчика

Если ваc беспокоят отладочные регистры (DR?), мы сталкиваемся с небольшой проблемой: они привилегированны в WinNT. Прием состоит в следующей простой вещи: обнулить DR0, DR1, DR2 и DR3 (они наиболее часто используются отладчиками в качестве хардверных брикпоинтов). Поэтому следующим кодом вы доставите отладчику немного неприятностей:

Код (Text):
  1.  
  2.         xor     edx,edx
  3.         mov     dr0,edx
  4.         mov     dr1,edx
  5.         mov     dr2,edx
  6.         mov     dr3,edx

Хаха, разве это не смешно? :smile3:

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

Я надеюсь, что вы сможете использовать эти несколько простых антиотладочных приемов в ваших вирусах без особых проблем. © Billy Belcebu, пер. Aquila


0 871
archive

archive
New Member

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