CATEGORII DOCUMENTE |
Bulgara | Ceha slovaca | Croata | Engleza | Estona | Finlandeza | Franceza |
Germana | Italiana | Letona | Lituaniana | Maghiara | Olandeza | Poloneza |
Sarba | Slovena | Spaniola | Suedeza | Turca | Ucraineana |
DOCUMENTE SIMILARE |
|
Konwencje stosowane przez programy antywirusowe - standard CARO
12.1. Skaning
Historycznie jest to najstarsza technika stosowana przez programy antywirusowe. Skaning polega na wyszukiwaniu w zainfekowanym obiekcie zadanej sekwencji bajtów (sygnatury wirusa).
Poniżej przedstawiono kilka przykładowych sygnatur istniejących wirusów:
B8 ED FE CD 21 A3 03 01 0E 8F 06 6F 01 BA ; sygnatura wirusa Atomie 1.0
BE 30 01 8B 16 17 01 B9 35 01 2E 31 14 83 ; sygnatura wirusa Human Greed
8B FC 36 8B 2D 81 ED 03 01 44 44 1E 06 OE ; sygnatura wirusa DOOM!
5D 83 ED 03 E8 15 00 EB 27 90 E8 OF 00 B4 ; sygnatura wirusa Ethernity
5D 81 ED 03 01 EB 1B 90 B8 24 35 CD 21 ; sygnatura wirusa OLG
Jak widać, tradycyjna sygnatura jest to ciąg bajtów o nieustalonej z góry długości, zapisanych heksalnie, które program antywirusowy konwertuje na rozumianą przez siebie postać binarną (maszynową) i dopiero taki łańcuch poszukiwany jest w przeszukiwanym obiekcie. Z czasem pojęcie sygnatury rozszerzono. Dzisiejsze skanery potrafią interpretować różne symbole oraz znaki globalne (ang. wildcards) np. ? czy *. Poniżej podano przykłady kilku prostych, nieznacznie rozszerzonych sygnatur używających znaków globalnych:
BB ?2 B9 10 01 81 37 ?2 81 77 02 ?2 83 C3 04 E2 F2 ; sygnatura wirusa FireFly
B9 CC 01 BB ?2 2E 81 07 ?2 83 C3 02 ; sygnatura wirusa K-CMOS
1E 06 OE OE 1F 07 2E FE 06 ?2 2E A1 ; sygnatura wirusa Geodesic Propagation
33 CO 8E D8 BE ?2 FF 34 FF 74 02 C7 04 ; sygnatura wirusa 1984
Poniżej zamieszczono listing programu, który umożliwia wyszukiwanie zadanego ciągu bajtów w podanym jako parametr pliku. Zadany ciąg bajtów może być podany Jako łańcuch w apostrofach lub jako zapisane heksalnie dane (możliwa jest także kombinacja podanych metod).
;
Czesc ksiazki : 'Nowoczesne techniki wirusowe i antywirusowe' ;
;
SKANER v1.0, Autor : Adam Blaszczyk 1997 ;
;
Program sluzy do przeszukiwania plikow w celu znalezienia zadanego ;
lancucha bajtow (np. stalej sygnatury wirusa) podanego jako parametr ;
przy wywolaniu programu. ;
;
DANE TECHNICZNE ;
;
; _ Wywolanie: SKANER NazwaPliku CiagBajtow ;
; _ Ciag moze skladac sie z liczb zapisanych heksalnie lub zwyklego tekstu ;
np: ;
_ CD 21 - szuka wywolania przerwania 21h ;
_ 'wirus' - szuka slowa 'wirus' ;
_ 'abc'80C5'def'EE F6 - szuka lancucha 'abc╟+def_≈' ;
; _ Maksymalna dlugosc wyszukiwanego ciagu = 128 bajtow. ;
; _ Dlugosc jednorazowo odczytywanych danych z pliku = 65024 bajtow ;
65024=512*127=127 sektorow, 512 bajtowych ;
; _ Maksymalna ilosc zliczanych wystapien ciagu = 2^32 razy ;
; _ Pliki z atrybutami Hidden, System przed odczytem maja zmieniany atrybut ;
na Archive; po skonczeniu programu przywracany jest oryginalny atrybut ;
; _ Procedura obslugi INT 24h <dialog ARIF-Abort,Retry,Ignore,Fail> ;
zastapiona zostala sekwencja sygnalizujaca blad programowi ;
; _ Wyszukiwane sa wszystkie mozliwe wystapenia ciagu ;
(takze zachodzace na siebie) ;
;
; Definicje Stalych
JUMPS
;stale logiczne
Falsz equ 00h ; definicja dwoch stalych logicznych
Prawda equ Falsz+1 ; / 0=Falsz i 1=Prawda
; stale ogolne
RozmiarStosu equ 128 ; rozmiar stosu w slowach dwubajtowych
RozmiarCiagu equ 128 ; rozmiar bufora na wyszukiwany ciag
RozmiarBuforaDanych equ 127*512 ; rozmiar bufora na dane = segment 64K-512
DlugNazwyPliku equ 128 ; dlugosc pelnej nazwy pliku
LiniaPolecen equ 80h ; adres (w PSP) do parametrow
; stale znakowe
ZnakTabulacji equ 09h ;
ZnakSpacji equ ' ' ;
ZnakKoncaLinii equ 0Dh ; - stale znakowe
CR equ 0Dh ; /
LF equ 0Ah ; /
; stale bledow
; na ich podstawie nastepuje obliczenie ofsetu komunikatu o bledzie
BlBezBledu equ 00h ; nie ma bledu
BlBrakParametrow equ 01h ; blad : nie ma parametrow
BlBrakNazwyPliku equ 02h ; blad : brak nazwy pliku w parametrach
BlBrakCiagu equ 03h ; blad : brak ciagu do wyszukania
BlZlyCiag equ 04h ; blad : ciag zawiera bledy
BlBrakPlikuNaDysku equ 05h ; blad : brak pliku podanego jako parametr
BlBlad_ARIF equ 06h ; blad : brak dostepu do pliku (int 24h)
BlZlyAtrybutPliku equ 07h ; blad : nie plik tylko etykieta dysku lub katalog
BlBrakDostepuDoPliku equ 08h ; blad : nie mozna zmienic atrybutow na archive
BlNieMogeOtworzyc equ 09h ; blad : nie moge otworzyc pliku
BlNieMogeCzytac equ 0Ah ; blad : nie moge czytac pliku
BlNieMogeZamknac equ 0Bh ; blad : nie moge zamknac pliku
BlPlikZaKrotki equ 0Ch ; blad : plik krotszy niz dlugosc ciagu
; stale drukowania wrostkow
7 bit=1 wywolaj procedure konwersji, ktorej adres w [si+1]
7 bit=0 wyswietl tekst, ktorego adres jest pod [si+1]
DrPlik equ 01h ; stala dla wrostka NazwaPliku
DrCiag equ 02h ; stala dla wrostka Ciag
DrUnIntDec equ 83h ; stala dla wrostka - liczby bez znaku typu Int (dziesietne)
DrUnIntHex equ 84h ; stala dla wrostka - liczby bez znaku typu Int (szesnastkowo)
IleWrostkow equ 04h ; ile maksymalnie wrostkow
; stale DOS-owe
TrybOtwarciaPliku equ 00000000b ; oznacza otwarcie pliku tylko do odczytu
AtReadOnly equ 00000001b ;
AtHidden equ 00000010b ;
AtSystem equ 00000100b ;
AtVolumeID equ 00001000b ; - atrybuty pozycji katalogu
AtDirectory equ 00010000b ; /
AtArchive equ 00100000b ; /
AtAll equ 00111111b ; /
; definicja bufora DTA (Disk Transfer Area)
DTA_STRUC struc ; struktura potrzebna dla funkcji
NieWazne db 21 dup(?) ; 4E i 4F sluzacych do poszukiwania
Atrybut db ? ; pierwszego (4E) i nastepnego (4F)
Czas dw ? ; wystapienia w katalogu (pliku, katalogu,itp.)
Data dw ? ; opisuje wszystkie parametry pliku
Dlugosc dd ? ; zawarte w FAT z wyjatkiem pierwszego numeru JAP
Nazwa db 13 dup(?)
DTA_STRUC ends
; Segment Kodu
SKANER SEGMENT
ASSUME CS:SKANER, ds:SKANER
Start: ; poczatek programu
Call UstawParametrySystemu ; ustaw DS+nowe (DTA i int 24h)
mov si,Offset TeCopyRight ;
Call DrukLn ; wyswietl komunikat o programie
Call CzytajParametry ; Wez z PSP:80h parametry : Plik+Ciag
jc Blad ; gdy CF=1, to blad
Call SprawdzPlik ; czy plik istnieje ?
jc blad
Call SzukajLancuch ; Szukaj lancucha w pliku
jc Blad
mov NumerBledu,BlBezBledu ; wszystko OK !
Blad: ; skacz tu, jesli jakis blad
Call PrzywrocParametrySystemu ; stare DTA+INT 24h
Call OstatniKomunikat ; zwraca 0=bez bledu lub FF=blad
mov ah, 4Ch ; funkcja powrotu do systemu DOS
int 21h ; wywolaj funkcje
OstatniKomunikat proc near ; wyswietla komunikat na koncu programu
pushf ; zachowaj znaczniki, potrzebne pozniej
mov ax,seg SKANER
mov ds,ax ; DS=segment danych
mov al, NumerBledu ; al=numer bledu
cbw ; ax=numer bledu
shl ax,1 ; ax=ax*2, bo kazdy ofset=2 bajty
add ax,Offset OffsetyKomunikatow ; ax=tablica z adresami komunikatow bledow
xchg ax,bx ; bx=tablica z adresami komunikatow bledow
; [bx]=tablica[blad]
mov si,[bx] ; dx=offset do komunikatu o bledzie (lub 'OK')
Call DrukLn ; wypisz komunikat
popf ; przywroc znaczniki
mov al,0 ; w al przekaz kod bledu, 0=bez bledu
sbb al,0 ; jezeli blad, to al=FF
ret
OstatniKomunikat endp
SzukajLancuch proc near ; otwiera plik i szuka zadany ciag
; w calym pliku
mov ax,seg ProgDTA ; ustaw ES na segment, do ktorego beda
mov es,ax ; wczytywane dane =127 sektorow
mov ax,word ptr [BufDTA.Dlugosc] ; -DX:AX = dlugosc pliku
mov dx,word ptr [BufDTA.Dlugosc+2] ; /
or dx,dx ; czy b. znacz. czesc dlugosci =0
jnz DlugiPlik ; nie -> dlugosc<>0
cmp ax,DlugoscCiagu ; b. znacz. czesc=0, czy mniej znacz. czesc
jae DlugiPlik ; dlugosci > dlugosc ciagu
mov NumerBledu,BlPlikZaKrotki ; Blad : plik krotszy od ciagu !
jmp short NieMogeOtworzyc ; wyswietl blad
DlugiPlik:
mov si,offset TeSzukamCiagu ; wyswietl informacje o szukaniu
Call DrukLn ; lancuchu w pliku
mov NumerBledu,BlNieMogeOtworzyc ; ewentualny numer bledu
mov dx,Offset NazwaPliku ; nazwa pliku w DS:DX, tryb dostepu w AL
mov ax,3D00h+TrybOtwarciaPliku ; funkcja DOS - otworz plik
int 21h ; DOS : otworz plik
jc NieMogeOtworzyc ; CF=1 -> blad
xchg ax,bx ; BX=uchwyt pliku
Call CzytajSzukaj ; szukaj lancucha w calym pliku
jc NieMogeOtworzyc
mov ah,3Eh ; zamknij plik
int 21h ;
mov ax,word ptr [IleZnalezionych] ; wyswietl, ile razy ciag
mov dx,word ptr [IleZnalezionych+2] ; wystapil w pliku
mov si, offset TeZnalazlem
or dx,dx ; sprawdz, czy przynajmniej
jnz CosZnalazl ; raz, jak ani razu to
or ax,ax ; / inny komunikat
jnz CosZnalazl ; /
mov si, offset TeNieZnalazlem
CosZnalazl:
Call DrukLn ; wyswietl komunikat spod DS:SI
clc ; nie ma bledu
NieMogeOtworzyc:
ret ; powrot z procedury
SzukajLancuch endp
CzytajSzukaj proc near ; czytaj w pliku i szukaj lancuch
; na wejsciu numer pliku w BX
xor ax,ax ;
mov word ptr [IleZnalezionych] ,ax ;
mov word ptr [IleZnalezionych+2],ax ; - wyzeruj zmienne
mov word ptr [AdresCzytania],ax ; /
mov word ptr [AdresCzytania+2],ax ; /
mov NumerBledu,BlNieMogeCzytac ; ewent. blad
xor bp,bp ; BP oznacza odstep od poczatku bufora,
; pod ktory wczytujemy dane, na poczatku=0
dec DlugoscCiagu ; zmniejsz o 1 dlugosc ciagu potrzebne
; w pozniejszej operacji porownania
cld ; w oper. lancuchowych INC(SI,DI)
CzytajDoBufora: ; petla glowna
push ds ; zachowaj DS na stosie
mov ax,es
mov ds,ax ; DS=ES=segment na dane z pliku
mov cx,RozmiarBuforaDanych ; ile czytac danych
mov dx,offset BuforDanych ; DS:DX = tu wczytuj dane
add dx,bp ; dodaj dlug. danych, ktore zostaly z poprz. odczytu
mov ah,3Fh ; DOS : funkcja czytania
int 21h ; DOS : wykonaj funkcje
pop ds ; przywroc DS
jc NieMogeCzytac ; gdy CF=1, to blad
add word ptr [AdresCzytania],ax ; dodaj do pozycji odczytu ilosc
adc word ptr [AdresCzytania+2],0 ; /odczytanaych bajtow
mov [Przeczytane],ax
add ax,bp ; do ilosci odczytanych bajtow dodaj dlugosc danych
; /pozostalych z poprzedniego odczytu
cmp ax,DlugoscCiagu ; ax=dlugosc danych do porownania
jb KoniecPliku ; - jesli mniej niz ciag, to nie trzeba porownywac
; / bo i tak ciag sie nie znajdzie
xchg ax,cx ; cx=dlugosc danych do porownania
push cx ; zachowaj do pozniejszego porownania
mov di,offset BuforDanych ; poczatek danych
SzukajPierwszej:
mov si,Offset Ciag ; ofset do wyszukiwanego ciagu
lodsb ; al=pierwsza litera ciagu, INC(SI)
repnz scasb ; szukaj, az znajdzie w danych pierwsza litere
jnz NieMaPierwszej ; jesli nie znalazl, to czytaj dalej z pliku
cmp cx,DlugoscCiagu ; czy wystarczy danych w buforze do porownania ?
jae PorownajCaly ; jest co najmniej tyle lub wiecej to OK
inc cx ; - za malo danych
dec di ; - cofnij DI,CX na poprzednie wartosci
mov si,di ; - skopiuj koncowke bufora na poczatek
mov di,offset BuforDanych ; - zachowaj w BP dlugosc tej koncowki
mov bp,cx ; - w nastepnym odczycie dane wczytane
rep movs byte ptr es:[di],es:[si] ; - umieszczone beda za ta koncowka
jmp short NieMaPierwszej ; - a porownywanie sie powtorzy, ale teraz beda dane
PorownajCaly: ; - do porownania, po skoku czytaj dalej dane
push cx ;
push di ; zachowaj aktualna pozycje w buforze i licznik
mov cx,DlugoscCiagu ; dokladniej : dlugosc ciagu-1 bo nie musimy porownywac
; pierwszej litery, ktora juz byla sprawdzona
jcxz JednoLiterowy ; jesli CX=0, to ciag byl jednoliterowy
rep cmpsb ; porownaj cx bajtow
jne NieMaLancucha ; jesli ZF=0, nie znalazl ciagu
JednoLiterowy:
mov ax,word ptr [AdresCzytania] ; DX:AX=32 bitowa pozycja odczytu pliku
mov dx,word ptr [AdresCzytania+2]
sub ax,[Przeczytane]
sbb dx,0
sub ax,bp
sbb dx,0
pop di ; przywroc odleglosc od poczatku bufora
push di ; zachowaj di
dec di ; zmniejsz wskaznik, zeby wskazywal na pierwsza litere
add ax,di
adc dx,0 ; dodawanie 32 bitowe
; DX:AX = adres fizyczny wzgledem pocz. pliku
mov word ptr [AdresZnalezienia],ax ; -zapamietaj ten adres w zmiennej, bo procedura
mov word ptr [AdresZnalezienia+2],dx; /konwersji korzysta z ofsetu do zmiennej, zeby ja wyswietlic
mov si,offset TeZnalezionyNaPozycji ; -wyswietl tekst ze znalazl
Call DrukLn ; /adres : wyswietl szesnastkowo i dziesiatkowo
add word ptr [IleZnalezionych],1 ; -zwieksz 32 bitowy licznik wystapien
adc word ptr [IleZnalezionych+2],0 ; /dodaj ewentualne przeniesienie z 15 na 16 bit
NieMaLancucha:
pop di ;
pop cx ; przywroc aktualna pozycje w buforze+licznik
jcxz NieMaPierwszej ; czy juz caly bufor pusty ?
; xor bp,bp ; zeruj dlugosc koncowki
jmp short SzukajPierwszej ; skocz i szukaj nastepnego wystapienia
NieMaPierwszej:
pop ax ; zdejmij ilosc odczytanych danych ze stosu
cmp ax,RozmiarBuforaDanych ; i porownaj, czy tyle ile bylo wczytywanych
jb KoniecPliku ; jesli nie tyle samo, to koniec pliku
; jesli tyle samo, to czytaj dalej
jmp CzytajDoBufora ; skocz i czytaj dalej dane
KoniecPliku: ; dane sie skonczyly
clc ; nie ma bledu
NieMogeCzytac:
ret ; wroc z procedury
CzytajSzukaj endp
PrzywrocParametrySystemu proc near ; przywraca stare adresy DTA+Int 24h
; i ewentualnie atrybuty pliku
; (jezeli sytemowy, ukryty)
pushf ; zachowaj flagi z ew. bledem
cmp ZmienAtrPliku,Prawda ; czy przywrocic atrybut ?
jne NiePrzywracajAtrybutu ; skocz jesli nie
mov ax,4301h ; DOS: funkcja 43xxh wez(xx=0)/ustaw(xx=1) atr. pliku
xor ch,ch ; ch=0
mov cl,[BufDTA.Atrybut] ; cx=stare atrybuty
mov dx,Offset NazwaPliku ; DS:DX =nazwa pliku
int 21h ; DOS : zmien atrybuty
NiePrzywracajAtrybutu:
push ds ; zachowaj segment danych
push ds ; 2 razy -> na pozniej
lds dx,dword ptr [StareI24Ofs] ; przywroc stara obsluge bledow
mov ax,2524h ; ustaw Int 24h
int 21h ; funkcja 25h - ustaw wektor (numer w AL)
pop ds ; przywroc segment danych
lds dx,dword ptr [StareDTAOfs] ; przywroc stare DTA
mov ah,1Ah ; funkcja 1Ah - ustaw DTA
int 21h ; wywolaj funkcje
pop ds ; przywroc segment danych
popf ; przywroc znaczniki z ew. bledem
ret ; powrot z procedury
PrzywrocParametrySystemu endp
UstawParametrySystemu proc near ; ustaw obsluge przerwania 24h
; nowy bufor DTA
mov ax,seg SKANER
mov ds,ax ; DS=segment danych
mov MojAdresPSP,es ; zachowaj PSP
mov ax,3524h ; funkcja wez adres przerwania (num. w AL)
int 21h ; wez stare INT 24h do rejestrow ES:BX
mov StareI24Ofs,bx ; - zachowaj stare przerwanie
mov StareI24Seg,es ; / ES=segment, BX=offset
mov ah,2Fh ; wez stare DTA do rejestrow ES:BX
int 21h
mov StareDTAOfs,bx
mov StareDTASeg,es ; ES=segment, BX=ofset
mov dx,Offset BufDTA
mov ah,1Ah ; ustaw nowe DTA na adres zawarty w DS:DX
int 21h
push ds ; zachowaj DS
push cs ; -DS=CS
pop ds ; /
mov dx,offset NoweInt24 ; ustaw nowe przerwanie 24h
mov ax,2524h ; w DS:DX
int 21h
pop ds ; przywroc DS
ret ; powrot z procedury
UstawParametrySystemu endp
NoweInt24 proc near ; procedura obslugi przerwania programowego bledow
; krytycznych wywolywana przez DOS w razie bledu
push ds ;
push ax ; -zachowaj DS i AX
mov ax,seg SKANER
mov ds,ax ; ds=segment danych
mov NumerBledu,BlBlad_ARIF ; zachowaj numer bledu
pop ax ;
pop ds ; -przywroc DS i AX
mov al,3 ; pomin blad-program sam zadecyduje co dalej
iret ; nie wywoluj standardowego dialogu ARIF
NoweInt24 endp ; powrot z procedury obslugi przerwania programowego
SprawdzPlik proc near ; szukaj plik podany jako parametr
mov ZmienAtrPliku,Falsz ; na razie nie znamy atrybutow, wiec nie trzeba
; przywracac oryginalnych
mov NumerBledu,BlBrakPlikuNaDysku ; ustaw ew. numer bledu
mov ah,4Eh ; funkcja szukaj pozycji katalogu
mov dx,offset NazwaPliku ; DS:DX nazwa pliku
mov cx,AtAll ; w CX podaj atrybut szukanej pozycji
int 21h ; wywolaj funkcje
jc NieMaPliku ; gdy CF=1, to blad
mov si,offset BufDTA ; nie ma bledu , info o pliku jest w buforze DTA
mov al,[BufDTA.Atrybut] ; wez atrybut pliku
mov NumerBledu,BlZlyAtrybutPliku ; ewent. blad
test al,AtVolumeID+AtDirectory ; sprawdz, czy etykieta lub katalog (testuj bity)
stc ; ustaw ewent. blad
jnz NieMaPliku ; skocz, bo etykieta lub dysk
test al,AtHidden+AtSystem ; testuj bity : ukryty lub system
mov NumerBledu,BlBrakDostepuDoPliku ; ewent. blad
jz NieZmienAtr ; nie sa ustawione, to skocz dalej
mov ZmienAtrPliku,Prawda ; trzeba zmienic atrybut, zeby mozna bylo odczytac
mov ax,4301h ; funkcja ustaw atrybut pliku
mov cx,AtArchive ; cx=atrybyt jaki ustawic
mov dx,Offset NazwaPliku ; DS:DX nazwa pliku
int 21h ; wywolaj funkcje
jc NieMaPliku ; gdy CF=1, to blad
NieZmienAtr:
clc ; nie ma bledu, plik gotowy do odczytu
NieMaPliku:
ret ; wroc z procedury
SprawdzPlik endp
CzytajParametry proc near ; wez parametry z PSP:80h
push ds ; zachowaj DS
mov ax,ds ; ES=DS=segment z danymi
mov es,ax
mov ds,MojAdresPSP ; DS=blok PSP
mov si,LiniaPolecen ; ofset w PSP do linii polecen
mov es:NumerBledu,BlBrakParametrow ; ewentualny numer bledu
cmp byte ptr ds:[si],0 ; dlugosc linii polecen
je BladParametrow ; jezeli pusta, to nie ma parametrow
inc si ; pomin licznik
inc si ; pomin spacje
cld ; INC(SI,DI) w oper. na lancuchach
Call OpuscSpacje ; czytaj az znak <> SPACJA lub TAB
mov es:NumerBledu,BlBrakNazwyPliku ; ewentualny numer bledu
cmp al,ZnakKoncaLinii ; czy koniec parametrow ?
je BladParametrow ;- jesli tak, to powrot z procedury
mov di, offset NazwaPliku ; es:di : tu zapisz wyniki
Call KopiujDoSpacji ; kopiuj nazwe pliku
mov es:NumerBledu,BlBrakCiagu ; ewentualny numer bledu
cmp al,ZnakKoncaLinii ; czy koniec parametrow ?
je BladParametrow ;- jesli tak, to powrot z procedury
xor al,al ; plik ASCIIZ, wiec dodaj zero
stosb
Call OpuscSpacje ; czytaj az znak <>SPACJA lub TAB
cmp al,ZnakKoncaLinii ; czy koniec parametrow
je BladParametrow ; jesli tak, to blad
mov es:NumerBledu,BlZlyCiag ; ewentualny numer bledu
mov di, offset Ciag ; es:di : tu zapisz ciag
Call KopiujCiagDoKonca ; kopiuj parametr : ciag
jc BladParametrow ; jesli TAK, to blad
mov ax,di
sub ax,offset Ciag
jz BladParametrow ; jesli TAK, to lancuch pusty
mov es:DlugoscCiagu ,ax ; - zachowaj dlugosc ciagu
mov es:AbsDlugoscCiagu ,ax ; - zachowaj 2-i raz dlugosc ciagu
clc ; nie ma bledu
jmp short $+3 ; skocz i pomin rozkaz STC
BladParametrow:
stc ; jest blad
pop ds
ret ; wroc z procedury
CzytajParametry endp
OpuscSpacje proc near
lodsb ; czytaj znak z ds:[si], inc si
cmp al,ZnakSpacji ;
je OpuscSpacje ; czy spacja lub znak tabulacji ?
cmp al,ZnakTabulacji ; / jezeli tak, to czytaj nastepny znak
je OpuscSpacje ;/
dec si ; zmniejsz wskaznik na poprzedni znak
ret ; powroc z procedury
OpuscSpacje endp
KopiujDoSpacji proc near
KopiujZnak:
lodsb ; czytaj znak z ds:[si], inc si
cmp al,ZnakSpacji ;
je NieKopiuj ; czy spacja lub znak tabulacji
cmp al,ZnakTabulacji ; lub koniec linii polecen
je NieKopiuj ; /jezeli tak, to koncz kopiowanie
cmp al,ZnakKoncaLinii ; /
je NieKopiuj ;/
stosb ; skopiuj znak
jmp short KopiujZnak ; skocz i wez nastepny znak
NieKopiuj:
dec si ; zmniejsz wskaznik na poprzedni znak
ret ; powroc z procedury
KopiujDoSpacji endp
KopiujCiagDoKonca proc
Pa_Nic = 00
Pa_Apostrof = 01
mov bl,Pa_Nic ; nie bylo znaku specjalnego
mov bh,0
KopiujParamZnak:
lodsb ; czytaj znak z ds:[si], inc si
cmp bl,Pa_Apostrof ; czy tekst w apostrofach ?
jne ZwyklyTekst ; NIE - dane heksalne
cmp al,39 ; czy znak apostrofu ?
jne NieKoniecTekstu ; Nie - idz dalej
mov bl,Pa_Nic ; koniec tekstu w apostrofach
jmp KopiujParamZnak ; idz po kolejny znak
NieKoniecTekstu:
stosb ; kopiuj zwykly tekst
jmp KopiujParamZnak ; wez kolejny znak
ZwyklyTekst:
cmp al,39 ; czy apostrof poczatkowy
jne NiePoczatektekstu ; NIE - sprawdzaj dalej
mov bl,Pa_Apostrof ; ustaw flage
jmp KopiujParamZnak ; idz po nastepny znak
NiePoczatektekstu:
cmp al,ZnakKoncaLinii ; pomin, gdy znak=CR
je KoniecParamTekstu ; /
cmp al,ZnakSpacji ; pomin, gdy znak=spacja
je KopiujParamZnak ; /
cmp al,ZnakTabulacji ; pomin, gdy znak=TAB
je KopiujParamZnak ; /
cmp al,'0' ; czy znak >=0 ?
jb KoniecParamTekstuBlad ; < blad
cmp al,'9' ; czy znak 0..9 ?
jbe ToCyfra09 ; TAK - cyfra
and al,0DFh ; 'a'..'z'->'A'..'Z'
cmp al,'A' ; czy znak <'A' ?
jb KoniecParamTekstuBlad ; TAK - blad
cmp al,'F' ; czy znak >'F' ?
ja KoniecParamTekstuBlad ; TAK - blad
; znak '0'..'F'
ToCyfra09:
cmp bh,0 ; czy licznik znakow=0 ?
je ToPierwszyZnak ; TAK - zachowaj znak na pozniej
cmp al,'9' ; czy znak to cyfra ?
jbe ALJest09 ;
sub al,'A'-'0'-10 ; konwertuj na liczbe
ALJest09:
cmp ah,'9' ; czy drugi znak to cyfra ?
jbe AHJest09
sub ah,'A'-'0'-10 ; konwertuj na liczbe
AHJest09:
sub ax,'00' ;
mov bh,al ; konwersja liczby
mov al,16 ; heksalnej zapisanej
mul ah ; / jako lancuch, na zwykla
add al,bh ; / liczbe (znak ASCII)
stosb ; / i zapisz znak
mov bh,0 ; licznik znakow znow=0
mov bl,Pa_Nic ; 'czyste' wyjscie
jmp KopiujParamZnak ; wez nastepny znak
ToPierwszyZnak:
mov ah,al ; zachowaj pierwszy znak liczby
mov bh,1 ; jest juz jeden znak
jmp KopiujParamZnak ; idz po nastepny znak
KoniecParamTekstu:
cmp bx,Pa_Nic ; czy 'czyste' wyjscie ?
je KoniecParamTekstu2 ; jezeli nie, to blad
dec si ; zmniejsz wskaznik na poprzedni znak
KoniecParamTekstuBlad:
stc ; gdy CF=1, to nie ma bledu
jmp $+3 ; przeskocz 'CLC'
KoniecParamTekstu2:
clc ; gdy CF=0, to nie ma bledu
ret ; powrot z procedury
KopiujCiagDoKonca endp
DrukLn proc near ; drukowanie tekstu ACSIIZ spod DS:SI
; z przejsciem do nastepnej linii
Call Druk ; wydrukuj tekst
push si ;
mov si,Offset TeCRLF ;
Call Druk ;
pop si ; --- przejdz do nastepnej linii
ret ; powrot z procedury
DrukLn endp
Druk proc near ; drukowanie tekstu ACSIIZ spod DS:SI
push ax ;
push bx ;
push cx ;
push si ; --- zachowaj zmieniane rejestry
DrukZnak: ; petla drukowania jednego znaku
cmp si,offset CiagStart ;
jb ToNieParamtekst ; jezeli drukowany jest
cmp si,offset CiagKoniec ; w obszarsze lancucha 'CiagBajtow'
jae ToNieParamtekst ; to pozwol drukowac kazdy znak
mov cx,AbsDlugoscCiagu ;
add cx,offset CiagStart ; /
cmp si,cx ; /
jae KoniecDruku ; /
lodsb ; /
jmp short ToParamtekst ; /
ToNieParamtekst:
lodsb ; wez kolejny znak z lancucha
or al,al ; sprawdz, czy ostatni znak ?
jz KoniecDruku ; jesli tak, to wszystko wydrukowane
mov cx,IleWrostkow ; Ile zdefiniowanych wrostkow
mov bx,Offset TablicaWrostkow ; tablica z definicjami
SzukajWrostka: ; -sprawdz, czy al nie oznacza wrostka
cmp ds:[bx],al ; /
jne NastepnyWrostek ; jesli nie, to sprawdz nastepny w tablicy
test al,80h ; czy 7 bit ustawiony ?
jz NormalnyDruk ; nie - to ofset do tekstu
Call ds:[bx+1] ; tak - to procedura konwersji
xor al,al ; zeruj dla pozniejszego porownania
inc si ; - pomin ofset do liczby do konwrsji
inc si ; /
jmp short NastepnyWrostek ; sprawdz nastepny wrostek w tablicy
NormalnyDruk:
push si ; wrostek to tekst spod ofsetu w tablicy
mov si,ds:[bx+1] ; wrostkow
Call Druk ; wyswietl wrostek
pop si
xor al,al ; zeruj dla pozniejszego porownania
NastepnyWrostek:
add bx,3 ; zwieksz index do tablicy wrostkow
loop SzukajWrostka ; powtorz cx razy
or al,al ; czy to byl wrostek (al=0) ?
jz DrukZnak ; jesli tak, to wez nastepny znak
ToParamtekst:
mov ah,02h ; wyprowadz znak na
mov dl,al ; standardowe wyjscie DOSa
int 21h
jmp short DrukZnak ; skocz i wez nastepny znak lancucha
KoniecDruku:
pop si ; --- przywroc zmienione rejestry
pop cx ; /
pop bx ; /
pop ax ; /
ret ; wracaj
Druk endp
Bin2HexUnInt32 proc near ; procedura wyswietla 32 bitowa liczbe szesnastkowa
; ofset do liczby znajduje sie w si
push ax ;
push bx ;
push dx ;
push si ; --- zachowaj zmieniane rejestry
mov bx,[si] ; wez ofset do liczby 32 bitowej
mov ax,[bx] ; - wczytaj liczbe do DX:AX
mov dx,[bx+2] ; /
mov si,offset Hex2DecBufor ; ustaw na poczatek bufora
mov bx,offset HexChars ; wez ofset do tablicy z cyframi szesnastkowymi
push ax ; zapamietaj mniej znacz. slowo
mov ax,dx ; najpierw bar. znacz. slowo
Call Bin2HexUnInt16 ; konwertuj liczbe 16 bitowa
pop ax ; przywroc mniej znacz. slowo
Call Bin2HexUnInt16 ; terax mniej znacz. slowo
mov word ptr [si],'h' ; ustaw na koncu znak 'h' i 0
mov si,offset Hex2DecBufor ; - wyswietl liczbe
Call Druk ; /
pop si ; --- przywroc zmienione rejestry
pop dx ; /
pop bx ; /
pop ax ; /
ret ; powrot
Bin2HexUnInt16: ; wewnetrzna procedura wywoluje 'zstepujaco'
; kolejne nizsze ranga procedury konwersji
push ax
mov al,ah ; konwertuj b. znacz. czesc AX
Call Bin2HexUnInt8
pop ax ; konwertuj m. znacz. czesc AX
Bin2HexUnInt8: mov ah,al
shr al,1 ;
shr al,1 ; wyizoluj 4 bity (4..7)
shr al,1 ; / al=gorna polowa liczby
shr al,1 ; / szesnastkowej
Call Bin2HexUnInt4 ; konwertuj b. znacz. bity (4..7)
mov al,ah
and al,15 ; wyizoluj 4 bity (0..3)
Bin2HexUnInt4:
xlatb ; al=byte ptr ds:[bx+al]
mov [si],al ; zachowaj znak w buforze
inc si ; zwieksz indeks
ret ; powrot z wen. procedury
Bin2HexUnInt32 endp
Bin2DecUnInt32 proc near ; wyswietla liczbe 32 bitowa bez znaku dziesietnie
push ax ;
push bx ;
push dx ;
push si ; --- zachowaj zmieniane rejestry
mov si,[si] ; wez ofset do liczby 32 bitowej
mov ax,[si] ; - wczytaj liczbe do DX:AX
mov dx,[si+2] ; /
mov si,offset Hex2DecBufor+10 ; ustaw na koniec bufora, bo zapis od konca
mov byte ptr ds:[si],0 ; utworz ASCIIZ (dodaj zero na koncu)
DzielPrzez10:
mov bx,10 ; dziel DX:AX przez BX
Call Dziel32 ; w bx reszta z dzielenia
add bl,'0' ; dodaj ASCII '0'
dec si ; zmniejsz indeks do tablicy
mov byte ptr ds:[si],bl ; zapisz cyfre
or dx,dx ;
jnz DzielPrzez10 ;
or ax,ax ;
jnz DzielPrzez10 ; --- czy liczba jest juz 0 ?
Call Druk ; wyswietl lancuch z liczba po konwersji
pop si ; --- przywroc zmienione rejestry
pop dx ; /
pop bx ; /
pop ax ; /
ret ; powrot
Bin2DecUnInt32 endp
Dziel32 proc near ; dziel (dx:ax)/bx
push bp ; zachowaj bp
push ax ; zachowaj mniejsza czesc liczby 32 bitowej
mov ax,dx ; przenies b. znacz. czesc do mniej. znacz.
xor dx,dx ; i wyzeruj dx , dx:ax = > 0:dx
div bx ; podziel (0:dx)/bx
mov bp,ax ; calosc z dzielenia, to wieksza czesc wyniku
pop ax ; przywroc do AX mniej znaczaca liczbe z poczatku
div bx ; dx jest reszta z dzielenia b. znacz. czesci przez BX
mov bx,dx ; w bx reszta z dzielenia
mov dx,bp ; dx:ax=liczba podzielona przez bx,
pop bp ; a w bx reszta z dzielenia
ret
Dziel32 endp
; (teksty komunikatow+zmienne ogolne)
TeCopyRight db CR,LF,'SKANER v1.0, Autor : Adam Blaszczyk 1997'
db CR,LF
db CR,LF,' Wywolanie: SKANER NazwaPliku CiagBajtow'
db CR,LF
db CR,LF,' CiagBajtow moze skladac sie z liczb zapisanych heksalnie lub zwyklego'
db CR,LF,' tekstu np: '
db CR,LF,' _ CD 21 - szuka wywolania przerwania 21h'
db CR,LF,' _ ''wirus'' - szuka slowa 'wirus''
db CR,LF,' _ ''abc''80C5''def''EE F6 - szuka lancucha 'abc╟+def_≈''
TeCRLF db CR,LF,0
TeSzukamCiagu db 'Szukam lancuch '',DrCiag ,'' w pliku '',DrPlik,''',0
TeBezBledu db 'OK !',0
TeBrakParametrow db 'BLAD : Podaj Parametry !',0
TeBrakNazwyPliku db 'BLAD : Podaj nazwe pliku !',0
TeBrakCiagu db 'BLAD : Podaj ciag do wyszukania',0
TeZlyCiag db 'BLAD : Podany ciag zawiera bledy !',0
TeBrakPlikuNaDysku db 'BLAD : Nie moge znalezc pliku '',DrPlik,''',0
TeBlad_ARIF db 'BLAD : Brak dostepu do pliku '',DrPlik,'' (int 24h) !',0
TeZlyAtrybutPliku db 'BLAD : '',DrPlik,'' to etykieta dysku lub katalog !',0
TeBrakDostepuDoPliku db 'BLAD : Brak dostepu do pliku - nie mozna chwilowo zmienic atrybutow ! ',0
TeNieMogeOtworzyc db 'BLAD : Nie moge otworzyc pliku '',DrPlik,''',0
TeNieMogeCzytac db 'BLAD : Nie moge czytac pliku '',DrPlik,''',0
TeNieMogeZamknac db 'BLAD : Nie moge zamknac pliku '',DrPlik,''',0
TePlikZaKrotki db 'BLAD : Plik '',DrPlik,'' jest krotszy niz ciag !',0
OffsetyKomunikatow dw offset TeBezBledu ; BlBezBledu equ 00h
dw offset TeBrakParametrow ; BlBrakParametrow equ 01h
dw offset TeBrakNazwyPliku ; BlBrakNazwyPliku equ 02h
dw offset TeBrakCiagu ; BlBrakCiagu equ 03h
dw offset TeZlyCiag ; BlZlyCiag equ 04h
dw offset TeBrakPlikuNaDysku ; BlBrakPlikuNaDysku equ 05h
dw offset TeBlad_ARIF ; BlBlad_ARIF equ 06h
dw offset TeZlyAtrybutPliku ; BlZlyAtrybutPliku equ 07h
dw offset TeBrakDostepuDoPliku ; BlBrakDostepuDoPliku equ 08h
dw offset TeNieMogeOtworzyc ; BlNieMogeOtworzyc equ 09h
dw offset TeNieMogeCzytac ; BlNieMogeCzytac equ 0Ah
dw offset TeNieMogeZamknac ; BlNieMogeZamknac equ 0Bh
dw offset TePlikZaKrotki ; BlPlikZaKrotki equ 0Ch
TeNieZnalazlem db 'Nie znalazlem lancucha '',DrCiag ,'' w pliku '',DrPlik,'' !',0
TeZnalazlem db 'Ciag '',DrCiag ,'' wystapil '
db DrUnIntDec
dw offset IleZnalezionych
db ' raz(y) w pliku '',DrPlik,'' !',0
TeZnalezionyNaPozycji db 'Ciag '',DrCiag ,'' wystapil na pozycji '
db DrUnIntHex
dw offset AdresZnalezienia
db ','
db DrUnIntDec
dw offset AdresZnalezienia
db 0
HexChars db '0123456789ABCDEF'
TablicaWrostkow db DrPlik
dw offset NazwaPliku
db DrCiag
dw offset Ciag
db DrUnIntDec
dw offset Bin2DecUnInt32
db DrUnIntHex
dw offset Bin2HexUnInt32
NumerBledu db ?
MojAdresPSP dw ?
AdresCzytania dd ?
AdresZnalezienia dd ?
Przeczytane dw ?
IleZnalezionych dd ?
DlugoscCiagu dw ?
AbsDlugoscCiagu dw ?
StareDTAOfs dw ?
StareDTASeg dw ?
StareI24Ofs dw ?
StareI24Seg dw ?
ZmienAtrPliku db ?
Hex2DecBufor db 11 dup(?)
CiagStart:
Ciag db RozmiarCiagu dup(?)
CiagKoniec:
NazwaPliku db DlugNazwyPliku dup(?)
BufDTA DTA_STRUC <>
SKANER ENDS
; Segment DTA
; do wczytywania danych (127 sektorow 512 bajtowych=65024 bajtow)
ProgDTA SEGMENT
BuforDanych db RozmiarBuforaDanych dup(?) ; bufor na dane z pliku
ProgDTA ENDS
; Segment Stosu
ProgStos segment word stack 'STACK' ; ustaw STOS
dw RozmiarStosu dup(?)
ProgStos ends
end start
12.2. Heurystycze wyszukiwanie wirusów
Jak wspomniano we wstępie, większość istniejących wirusów to najczęściej przeróbki, stąd techniki wykorzystywane w pierwowzorach są bez większych zmian implementowane w kolejnych, nowych pokoleniach wirusów.
Wykorzystując ten fakt, twórcy programów antywirusowych zaczęli stosować technikę heurystycznego wykrywania kodu, polegającą na tym, iż na podstawie znajomości charakterystycznych, klasycznych sekwenqi instrukcji zawartych w typowych wirusach, można znaleźć nieznane jeszcze, ale wykorzystujące je wirusy. Typowe instrukcje wykorzystywane przez wirusy zostały wymienione w poprzednich rozdziałach, np. przy okazji omawiania instalacji w systemie i przejmowania przerwań. Poniżej pokazano kilka instrukcji podatnych na heurystykę lub sekwencji znajdujących się najczęściej w kodzie typowego wirusa plikowego. Jeżeli program antywirusowy, przeszukując pamięć lub plik, zidentyfikuje je (lub też inne), najczęściej informuje o tym użytkownika. Często wykrycie nawet kilku charakterystycznych bajtów w pamięci może umożliwić wykrycie nieznanego jeszcze wirusa. Poszukiwanie sekwencji może być prowadzone bądź to przy okazji zwykłego skaningu, bądź też podczas kontrolowanego uruchamiania programów (tryb krokowy, emulacja procesora).
CMP AX, 4B00h ; sprawd czy jest uruchamiany jaki£ program
; 3D,00,4B kod maszynowy rozkazu
CMP DS:[0],Z ; czy ostatni blok pamiΩci
; 80,3E,00,00, 5A kod maszynowy rozkazu
MOV AX, 2521h ; funkcja DOS ustaw adres przerwania 21h
INT 21h ; wywo│aj funkcjΩ B8,21,25,CD,21 kod maszynowy
; sekwencji
MOV WORD PTR [l],0008 ; ustaw blok jako systemowy w nag│≤wku MCB
; C7,06,01,00,08,00 kod maszynowy instrukcji
CALL NEXT ; we relatywny offset NEXT:
; E8,00,00 kod instrukcji
Zamieszczony poniżej program stara się znaleźć w całej wykorzystywanej przez programy użytkowe pamięci operacyjnej sekwencje, które zwykle są wykorzystywane przez wirusy.
;
Czesc ksiazki : 'Nowoczesne techniki wirusowe i antywirusowe' ;
;
HEUR v1.0, Autor : Adam Blaszczyk 1997 ;
;
; Program przeglada bloki MCB obecne w systemie i poszukuje w ;
; nich kilku standardowo wystepujacych w wirusach sekwencji ;
; Przy jego uzyciu mozna wykryc w pamieci niektore wirusy ;
; rezydetne ;
; Dane techniczne ;
;
; Pierwszy bajt sygnatury jest w pliku zXORowany z wartoscia 0AAh, a po ;
; uruchomieniu programu przywraca oryginalna wartosc pierwszego bajtu ;
; Dzieki temu program nie wykryje sygnatur np. w buforach dyskowych lub ;
; buforach programow cache (np. SMARTDRV) ;
;
; Program nie sprawdza blokow wolnych (wskaznik PSP w polu bloku MCB=0) ;
;; ;; ;;
JUMPS
HEUR SEGMENT
ORG 100h
ASSUME CS:HEUR, DS:HEUR
NUL = 00h ;
LF = 0Ah ; - stale znakow
CR = 0Dh ; /
IleSygnZebyAlarm = 10 ; okresla, ile sygnatur musi wystapic
; w badanym bloku MCB, aby potraktowac
; jego zawartosc za podejrzana
; i wyswietlic ostrzezenie
DlugProgPara = (Offset Koniec-Offset Start+15)/16+10h
; okresla dlugosc programu w pamieci
Sygn struc ;
SygnNazwa db 45 dup (?) ;
SygnDlug dw 0 ;
Sygn00 db 0 ;
Sygn01 db 0 ;
Sygn02 db 0 ; struktura opisujaca
Sygn03 db 0 ; / sygnature wirusa
Sygn04 db 0 ; /
Sygn05 db 0 ; /
Sygn06 db 0 ; /
Sygn07 db 0 ; /
Sygn ends ; /
DlugoscSygnatury = Size Sygn ; dlugosc struktury
Start:
lea si,TeCopyRight ; SI=ofset do informacji o programie
Call DrukLn ; wyswietl info o programie
Call SzukajHeur ; szukaj sekwencji w pamieci
mov ax,4C00h ; funkcja DOS - koncz program
int 21h ; wywolaj funkcje
SzukajHeur:
push es ax bx cx dx ; zachowaj zmieniane rejestry
mov bx,IleSygnatur ; ile sygnatur do odXORowania
lea si,Sygnatury ; skad pobierac sygnatury
add si,size SygnNazwa+size SygnDlug
; i gdzie XORowac bajt
XORujSygnature:
xor byte ptr [si],0AAh ; przywroc prawdziwy bajt sygnatury
add si,DlugoscSygnatury ; wez kolejna sygnature
dec bx ; zmniejsz licznik sygnatur
jnz XORujSygnature ; powtarzaj dla kazdej sygnatury
mov IloscSygn,0
mov ax,5802h ; funkcja DOS - czy UMB dolaczone ?
int 21h ; wywolaj funkcje
push ax ; zachowaj informacje na pozniej
mov ax,5803h ; funkcja DOS - dolacz/odlacz bloki UMB
mov bx,1 ; sprobuj dolaczyc bloki UMB
int 21h ; wywolaj funkcje
mov ah,52h ; funkcja DOS - wez adres listy list LL
int 21h ; wywolaj funkcje
mov ax,es:[bx-2] ; wez adres pierwszego bloku MCB
NastepnyMCB: ; kolejne bloki MCB
mov es,ax ; ES=MCB
mov bl,byte ptr es:[0] ; zachowaj info o znaczniku bloku
mov dx,es:[0003] ; DX=rozmiar bloku MCB
mov cx,es:[0001] ; CX=adres PSP z bloku MCB
Call SzukajWBloku
stc ; +1 w dodawaniu ponizej
adc ax,word ptr es:[0003] ; dodaj rozmiar bloku MCB+1
; AX=nastepny blok MCB
cmp bl,'M' ; czy to posredni blok ?
je NastepnyMCB ; TAK - przegladaj
cmp bl,'Z' ; czy to ostatni blok ?
je OstatniBlokMCB ; TAK - zakoncz przegladanie
; zly blok MCB - naruszona struktura
lea si,TeZlyMCB ; wyswietl komunikat
Call DrukLN ; / o blednym bloku MCB
OstatniBlokMCB:
pop bx ; przywroc info o UMB
mov bh,0 ; BX=BL
mov ax,5803h ; funkcja DOS - dolacz/odlacz bloki UMB
int 21h ; wywolaj funkcje
pop dx cx bx ax es ; przywroc zmieniane rejestry
cmp IloscSygn,0 ;
jne SzukajHeurPowrot ;
; - jezeli nie znalazl zadnej
lea si,TeNieMaSygnatur ; / sygnatury to wyswietl komunikat
Call DrukLN ; /
SzukajHeurPowrot:
ret ; powrot
SzukajWBloku: ; szuka sygnatury w bloku MCB
; AX=blok MCB
; DX=dlugosc bloku w paragrafach
push ds es ax bx cx dx si di ; zachowaj zmieniane rejestry
or cx,cx ; czy blok jest nieuzywany ?
je SzukajWBlokuPowrot ; TAK - nie sprawdzaj i powroc
mov AdresMCB,ax ; zapamietaj adres MCB
inc ax ; ES:0= MCB+1:0
mov es,ax ; ES wskazuje na dane w bloku
lea si,TeSprawdzam ;
Call Druk ;
lea si,TeBlokMCB ;
Call Druk ;
mov ax,AdresMCB ;
Call DrukHEX16 ; wypisz info o szukaniu
lea si,TeRozmiar ; / w bloku MCB i podaj jego
Call Druk ; / adres, dlugosc
mov ax,dx ; /
Call DrukHex16 ; /
lea si,TeParagraf ; /
Call DrukLn ; /
mov bx,cs ;
mov ax,es ; czy to MCB programu HEUR ?
cmp ax,bx ; / TAK-nie sprawdzaj kodu programu
jne InnyBlok ; / ale sprawdz poza nim
mov ax,DlugProgPara
sub dx,ax ; odejmij dlugosc kodu
or dx,dx ; czy nie odjete za duzo ?
jz SzukajWBlokuPowrot ; /
add ax,AdresMCB ; ES=dane poza kodem programu
mov es,ax ; /
InnyBlok:
or dx,dx ; pomin blok, gdy dlugosc =0
je SzukajWBlokuPowrot ; /
mov IloscBiezSygn,0 ; licznik wystapien w bloku
cld ; SI:=SI+1, DI:=DI+1 po oper. lancuchowych
xor di,di ; dane sa pod ES:0000
SzukajDalej:
mov bx,IleSygnatur ; ustaw licznik sygnatur
lea si,Sygnatury ; podaj, skad pobierac sygnatury
SzukajSygnature:
push si ; zachowaj zmieniane SI
mov bp,si ; zachowaj ofset do nazwy sygnatury
add si,size SygnNazwa+size SygnDlug
; dodaj ofset do sygnatury
lodsb ; wez 1-szy bajt sygnatury
scasb ; czy=bajt w pamieci ?
jnz NastepnaSygnatura ; NIE - sprawdz kolejna sygnature
; TAK - porownaj cala sygnature
mov cx,word ptr ds:[si-3] ; wez dlugosc sygnatury
dec cx ; pierwszego bajtu nie trzeba
; porownywac
push di ; DI jest pozniej potrzebne wiec zachowaj
rep cmpsb ; porownaj sygnature z pamiecia
pop di ; przywroc DI
jnz NastepnaSygnatura ; NIE - nie ma sygnatury
; TAK - sygnatura znaleziona
inc IloscSygn ; zwieksz ilosc wystapien (globalna)
inc IloscBiezSygn ; zwieksz ilosc wystapien (w MCB)
lea si,TeAdres ;
Call Druk ; wyswietl jaka sygnatura
mov ax,es ; zostala znaleziona
Call DrukHEX16 ; i pod jakim adresem
mov ax,0E3Ah ;
int 10h ;
mov ax,di ;
dec ax ; /
Call DrukHex16 ; /
lea si,TeSygnatura ; /
Call Druk ; /
mov si,bp ; /
add si,SygnNazwa ; /
Call DrukLn ; /
NastepnaSygnatura:
pop si ; przywroc SI
add si,DlugoscSygnatury ; i ustaw na nastepna sygnature
dec di ; ustaw wskaznik na poprzedni bajt
dec bx ; zmniejsz licznik sygnatur
jnz SzukajSygnature ; jezeli nie, to sprawdz kolejna sygnature
NastepnyBajt:
inc di ; wskaznik na nastepny bajt w bloku
and di,15 ; czy ofset>15
jnz SzukajDalej ; NIE - szukaj sygnatur
; TAK - zwieksz numer segmentu
mov di,es ;
inc di ; ES:DI=ES:0010:=ES+1:0
mov es,di ; /
xor di,di ; /
NieZmienSeg:
dec dx ; zmniejsz ilosc paragrafow w bloku
jnz SzukajDalej ; NIE - kontynuuj sprawdzanie
cmp IloscBiezSygn,IleSygnZebyAlarm
; czy ilosc wykrytych sygnatur jest
; odpowiednio duza ?
jb SzukajWBlokuPowrot ; NIE - powrot
lea si,TePrawdopodWirus ; TAK - wypisz o tym komunikat
Call DrukLn ; /
SzukajWBlokuPowrot:
pop di si dx cx bx ax es ds ; przywroc zmieniane rejestry
ret ; powrot
DrukLn:
push si ; zachowaj zmieniany rejestr
call Druk ; wyswietl tekst z CS:SI
lea si,TeCRLF ; i przejdz do nastepnej linii
Call Druk ; /
pop si ; przywroc zmieniany rejestr
ret ; powrot
Druk:
push ax si ; zachowaj zmieniane rejestry
DrukPetla:
lods byte ptr cs:[si] ; wez kolejny znak tekstu
or al,al ; czy NUL ?
jz DrukPowrot ; TAK - koniec tekstu
mov ah,0Eh ; funkcja BIOS - wyswietl znak
int 10h ; wywolaj funkcje
jmp short DrukPetla ; pobierz kolejny znak tekstu
DrukPowrot:
pop si ax ; przywroc zmieniane rejestry
ret ; powrot
DrukHEX16:
push ax ; zachowaj 8 dolnych bitow
mov al,ah ; AL=AH=wyzsze 8 bitow
Call DrukHEX8 ; wyswietl wyzsze 8 bitow
pop ax ; przywroc 8 dolnych bitow
DrukHEX8:
push ax ; zachowaj 4 dolne bity
shr al,1 ; wez 4 gorne bity
shr al,1 ; do AL (podziel przez 16)
shr al,1 ; /
shr al,1 ; /
Call DrukHEX4 ; wyswietl 4 gorne bity
pop ax ; przywroc 4 dolne bity
and al,15 ; utworz z nich liczbe 0..F
DrukHEX4:
push bx ; BX bedzie potrzebne wiec zachowaj
lea bx,HexZnaki ; ustaw BX na tablice konwersji
xlatb ; konwertuj 0..F na '0'..'Z','A'..'Z'
; AL=cyfra
mov ah,0Eh ; funkcja BIOS - wyswietl znak z AL
int 10h ; wywoluje funkcje
pop bx ; przywroc BX
ret ; powrot
HexZnaki db '0123456789ABCDEF' ; tablica konwersji
TeCopyRight db CR,LF,'HEUR v1.0, Autor : Adam Blaszczyk 1997'
db CR,LF
db CR,LF,'_ Szukam sygnatur ',NUL
db CR,LF
TeCRLF db CR,LF,NUL
TeZlyMCB db CR,LF,'_ Struktura blokow MCB pamieci jest zaklocona !',NUL
TeSygnatura db ': Znaleziona sygnatura : ',NUL
TeNieMaSygnatur db CR,LF,'_ Nie znalazlem zadnej sygnatury !',NUL
TePrawdopodWirus db CR,LF,'_ UWAGA : W ostatnio sprawdzanym bloku MCB moze byc wirus !'
db CR,LF,' Swiadczy o tym ilosc znalezionych w nim sygnatur !',NUL
TeAdres db ' Adres=',NUL
TeBlokMCB db ' MCB=',NUL
TeRozmiar db ', Rozmiar MCB=',NUL
TeParagraf db ' paragrafow',NUL
TeSprawdzam db '_ Sprawdzam',NUL
Sygnatury:
Sygn <'CALL $+3; POP BX ',4,0E8h xor 0AAh,000h,000h,05Bh>
Sygn <'CALL $+3; POP BP ',4,0E8h xor 0AAh,000h,000h,05Dh>
Sygn <'CALL $+3; POP SI ',4,0E8h xor 0AAh,000h,000h,05Eh>
Sygn <'CALL $+3; POP DI ',4,0E8h xor 0AAh,000h,000h,05Fh>
Sygn <'CMP AX,4B00h; JZ ?? ',4,03Dh xor 0AAh,000h,04Bh,074h>
Sygn <'CMP AX,4B00h; JNZ ?? ',4,03Dh xor 0AAh,000h,04Bh,075h>
Sygn <'CMP AX,'MZ' ',4,03Dh xor 0AAh,05Ah,04Dh,075h>
Sygn <'CMP AX,'ZM' ',4,03Dh xor 0AAh,04Dh,05Ah,075h>
Sygn <'MOV AX,2521h; INT 21h ',5,0B8h xor 0AAh,021h,025h,0CDh,021h>
Sygn <'MOV AH,52h; INT 21h ',4,0B4h xor 0AAh,052h,0CDh,021h>
Sygn <'MOV AX,4300h; CALL NEAR [] ',4,0B8h xor 0AAh,000h,043h,0E8h>
Sygn <'MOV AX,4300h; PUSHF; CALL D PTR CS:[]',6,0B8h xor 0AAh,000h,043h,02Eh,09Ch,0FFh>
Sygn <'MOV AX,4301h; CALL NEAR [] ',4,0B8h xor 0AAh,001h,043h,0E8h>
Sygn <'MOV AX,4301h; PUSHF; CALL D PTR CS:[]',6,0B8h xor 0AAh,001h,043h,02Eh,09Ch,0FFh>
Sygn <'MOV AX,5700h; CALL NEAR [] ',4,0B8h xor 0AAh,000h,057h,0E8h>
Sygn <'MOV AX,5700h; PUSHF; CALL D PTR CS:[]',6,0B8h xor 0AAh,000h,057h,02Eh,09Ch,0FFh>
Sygn <'MOV AX,5701h; CALL NEAR [] ',4,0B8h xor 0AAh,001h,057h,0E8h>
Sygn <'MOV AX,5701h; PUSHF; CALL D PTR CS:[]',6,0B8h xor 0AAh,001h,057h,02Eh,09Ch,0FFh>
Sygn <'MOV AX,3D02h; CALL NEAR [] ',4,0B8h xor 0AAh,002h,03Dh,0E8h>
Sygn <'MOV AX,3D02h; PUSHF; CALL D PTR CS:[]',6,0B8h xor 0AAh,002h,03Dh,02Eh,09Ch,0FFh>
Sygn <'MOV AX,4200h; CALL NEAR [] ',4,0B8h xor 0AAh,000h,042h,0E8h>
Sygn <'MOV AX,4200h; PUSHF; CALL D PTR CS:[]',6,0B8h xor 0AAh,000h,042h,02Eh,09Ch,0FFh>
Sygn <'MOV AX,4202h; CALL NEAR [] ',4,0B8h xor 0AAh,002h,042h,0E8h>
Sygn <'MOV AX,4202h; PUSHF; CALL D PTR CS:[]',6,0B8h xor 0AAh,002h,042h,02Eh,09Ch,0FFh>
Sygn <'MOV AH,3Fh; CALL NEAR [] ',3,048h xor 0AAh,03Fh,0E8h>
Sygn <'MOV AH,3Fh; PUSHF; CALL D PTR CS:[] ',5,0B4h xor 0AAh,03Fh,02Eh,09Ch,0FFh>
Sygn <'MOV AH,40h; CALL NEAR [] ',3,048h xor 0AAh,040h,0E8h>
Sygn <'MOV AH,40h; PUSHF; CALL D PTR CS:[] ',5,0B4h xor 0AAh,040h,02Eh,09Ch,0FFh>
Sygn <'CMP DS:[0],'Z'; JZ ?? ',4,080h xor 0AAh,03Fh,05Ah,074h>
Sygn <'CMP DS:[0],'Z'; JNZ ?? ',4,080h xor 0AAh,03Fh,05Ah,075h>
Sygn <'CMP ES:[0],'Z'; JZ ?? ',5,026h xor 0AAh,080h,03Fh,05Ah,074h>
Sygn <'CMP ES:[0],'Z'; JNZ ?? ',5,026h xor 0AAh,080h,03Fh,05Ah,075h>
Sygn <'MOV DS:[1],0008h ',6,0C7h xor 0AAh,006h,001h,000h,008h,000h>
Sygn <'MOV ES:[1],0008h ',7,026h xor 0AAh,0C7h,006h,001h,000h,008h,000h>
Sygn <'MOV DS:[100h],???? ',4,0C7h xor 0AAh,006h,000h,001h>
Sygn <'MOV ES:[100h],???? ',5,026h xor 0AAh,0C7h,006h,000h,001h>
Sygn <'MOV AX, 100h; PUSH AX; RET ',5,0B8h xor 0AAh,000h,001h,050h,0C3h>
Sygn <'MOV CX, 100h; PUSH CX; RET ',5,0B9h xor 0AAh,000h,001h,051h,0C3h>
Sygn <'MOV DX, 100h; PUSH DX; RET ',5,0BAh xor 0AAh,000h,001h,052h,0C3h>
Sygn <'MOV BX, 100h; PUSH BX; RET ',5,0BBh xor 0AAh,000h,001h,053h,0C3h>
Sygn <'MOV AX, 100h; JMP AX ',5,0B8h xor 0AAh,000h,001h,0FEh,0E0h>
Sygn <'MOV CX, 100h; JMP CX ',5,0B9h xor 0AAh,000h,001h,0FEh,0E1h>
Sygn <'MOV DX, 100h; JMP DX ',5,0BAh xor 0AAh,000h,001h,0FEh,0E2h>
Sygn <'MOV BX, 100h; JMP BX ',5,0BBh xor 0AAh,000h,001h,0FEh,0E3h>
Sygn <'MOV DS:[0086],CS ',4,08Ch xor 0AAh,00Eh,086h,000h>
Sygn <'MOV ES:[0086],CS ',5,026h xor 0AAh,08Ch,00Eh,086h,000h>
Sygn <'MOV AX,DS; DEC AX; MOV DS,AX ',5,08Ch xor 0AAh,0D8h,048h,08Eh,0D8h>
Sygn <'MOV AX,ES; DEC AX; MOV ES,AX ',5,08Ch xor 0AAh,0C0h,048h,08Eh,0C0h>
Sygn <'MOV AL,3; IRET ',3,0B4h xor 0AAh,003h,0CFh>
IleSygnatur = ($-offset Sygnatury)/DlugoscSygnatury
AdresMCB dw ?
IloscBiezSygn dw ?
IloscSygn dw ?
Koniec:
HEUR ENDS
END Start
12.3. Tryb krokowy
Do wykrywania zaawansowanych polimorficznych wirusów nie można stosować zwykłego skaningu, gdyż kod wirusa za każdym razem wygląda zupełnie inaczej. Możliwym wyjściem jest w tej sytuacji wykorzystanie trybu krokowego procesora. Program antywirusowy uruchamia sprawdzany program w trybie krokowym pod kontrolą odpowiedniego monitora tego przerwania przy użyciu np. (4B01/21). Po każdej wykonanej instrukcji wywoływany jest monitor, który sprawdza, czy np. aktualnie wykonywana instrukcja pasuje do listy chararakterystycznych, stałych instrukcji wirusa (jego wersji odszyfrowanej). Jeżeli instrukcja spełnia wymagania, monitor - przy użyciu dozwolonego w tym przypadku skaningu - sprawdza, czy w kodzie jest już odszyfrowany wirus. Jeżeli po przekroczeniu jakiejś wartości granicznej wykonanych instrukcji monitor nie wykryje żadnego podejrzanego kodu, sztucznie kończy program i sygnalizuje, iż nie ma w nim wirusa.
12.4. Emulacja procesora
Ze względu na to, iż omówiony w poprzednim punkcie tryb krokowy można oszukać, autorzy programów AV musieli zastosować inną metodę kontrolowanego uruchamiania programów. W tym celu wbudowali w swe programy interpretator asemblera, dzięki któremu mogą emulować wykonywanie początkowych intrukcji programu, mając jednocześnie nad nim pełną kontrolę. Ze względu na ciągły rozwój procesorów linii 80x86 interpretator asemblera musi być stale rozwijany. Nieuwzględnienie instrukcji wszystkich procesorów spowoduje bowiem, iż przy najbliższym wystąpieniu instrukcji, której monitor jeszcze nie potrafi rozpoznać, jego działanie zostanie zakończone z wynikiem negatywnym. Do niedawna sprawa miała się tak na przykład z kodami 66h, 67h, będącymi interfejsem rozszerzoych instrukcji dla procesorów 386 i wyższych. Niektóre wirusy celowo wykorzystywały je do oszukiwania programów antywirusowych, które po ich napotkaniu kończyły sprawdzanie pliku.
12.5. Przynęty (ang. baits, decoys)
Jedną z technik używanych do łapania prostych wirusów są przynęty. Są to programy, dające się zainfekować ewentualnemu wirusowi. Najczęściej na kod takiego programu składa się kilkaset lub kilka tysięcy razy powtórzona operacja NOP oraz instrukcja zakończenia programu. Program antywirusowy może tworzyć kilka lub więcej takich plików i następnie wykonywać z nimi różne operacje: uruchamiać, otwierać, czytać i zapisywać do nich na różne sposoby, aby dać szansę ewentualnemu wirusowi na ich zainfekowanie.
Wygenerowana przynęta powinna jak najbardziej przypominać typowy program, i to zarówno pod względem długości, jak i zawartości. Jeżeli bowiem długość pliku jest znacząca, tzn. np. wynosi jakąś wielokrotność liczb 10 czy 16, wirus może nie zainfekować takiego pliku.
12.6. Odświeżanie programów systemowych w sektorach
Ta dość trywialna technika służy do nadpisywania programów istniejących w BOOT-sektorach lub Głównych Rekordach Ładujących. Jednym z efektów wykonania takiego odświeżania może być usunięcie nieznanego jeszcze wirusa z zajmowanego przez niego sektora. Podczas przeprowadzania operacji odświeżania należy pamiętać, iż niektóre wirusy całkowicie przejmują kontrolę nad danymi zawartymi w sektorach systemowych, tak więc zamazanie wirusa może spowodować, iż podczas następnego startu systemu system nie będzie się ładował z twardego dysku lub też - co gorsza - nie będzie można odczytać zapisanych na dysku danych.
Możliwe wyjście z tej sytuacji polega na zapisaniu aktualnego stanu dysku (zawartości sektorów) w kopii bezpieczeństwa np. na czystej dyskietce, aby można było później odtworzyć operację odświeżania. Ze względu na możliwość stosowania przez wirusa techniki stealth odczyty najlepiej, byłoby wykonywać przez porty.
12.7. Blokowanie programów używających trybu krokowego
Niektóre monitory antywirusowe posiadają wbudowane mechanizmy blokowania wirusów, które używają trybu krokowego do znalezienia oryginalnych wejść do przerwań.
Zainstalowany monitor przejmuje najbardziej narażone na tracing przerwania (13h, 21h, 2Fh) i podczas ich wywoływania ustawia procedurę obsługi przerwania INT 0lh (trybu krokowego) na pustą procedurę, zakończoną rozkazem IRET, a po wywołaniu oryginalnej procedury chronionego przez siebie przerwania przywraca starą procedurę przerwania l. Dzięki temu wirus próbujący znaleźć oryginalną procedurę przerwania znajdzie adres będący częścią monitora antywirusowego. W efekcie wszystkie wykonywane przez wirusa czynności będą przechodzić przez monitor, który nie pozwoli na niebezpieczne działania.
Powyższą technikę demonstruje poniższy program.
;
Czesc ksiazki : 'Nowoczesne techniki wirusowe i antywirusowe' ;
;
; ANTYTRAC v1.0, Autor : Adam Blaszczyk 1997 ;
;
; Program nie pozwala przejsc w trybie krokowym ;
; przez przerwania 13h i 21h. ;
; W efekcie wirusy uzywajace tracingu do odnalezienia ;
; oryginalnych procedur obslugi tych przerwan nie znajda ;
; ostatniego elementu lancucha, a tylko element posredni. ;
;
; Kompilacja : ;
; TASM ANTYTRAC.ASM ;
; TLINK /t ANTYTRAC.OBJ ;
;
NUL = 00h ;
LF = 0Ah ; - stale potrzebne do deklaracji
CR = 0Dh ; / lancuchow napisowych
ANTYTRAC SEGMENT ; segment kodu i danych
ORG 100h ; program jest typu COM
ASSUME CS:ANTYTRAC, DS:ANTYTRAC, ES:ANTYTRAC, SS:ANTYTRAC
DlugoscKoduTSR = (offset KoniecKoduTSR-offset PoczatekKoduTSR+15)/16+10h
; oblicza, ile pamieci zajmie TSR
PoczatekKoduTSR:
Start: ; tu zaczyna sie program
jmp Poczatek ; skocz i zainstaluj lub odinstaluj program
NoweInt21h:
cmp ax,3521h ; czy to funkcja 3521h ?
jne Nie3521 ; NIE - skocz na koniec obslugi
cmp bp,0BACAh ; czy to ponownie uruchomiony program ?
; wywolal te funkcje ?
jne Nie3521 ; NIE - skocz na koniec obslugi
; TAK - odinstaluj wirusa
push es ds ; zachowaj zmieniane rejestry
lds dx,dword ptr cs:[StareInt21] ; pobierz stary adres INT 21h
mov ax,2521h ; funkcja DOS - ustaw nowe przerwanie
int 21h ; wywolaj funkcje (rekurencyjnie)
lds dx,dword ptr cs:[StareInt13] ; pobierz stary adres INT 13h
mov ax,2513h ; funkcja DOS - ustaw nowe przerwanie
int 21h ; wywolaj funkcje
push cs
pop es ; ES=zwalniany segment
mov ah,49h ; funkcja DOS - zwolnij blok pamieci
int 21h ; wywolaj funkcje
pop ds es ; przywroc zmieniane rejestry
mov ax,bp ; przekaz informacje do wywolujacego
; programu
iret ; powrot z przerwania
Nie3521:
Call Wylacz_TF ; jezeli bit TF=1, ustaw TF=0
db 0EAh ; czesc rozkazu JMP FAR
StareInt21 dd ? ; koncowka rozkazu JMP FAR
NoweInt13h:
Call Wylacz_TF ; jezeli TF=1, ustaw TF=0
db 0EAh ; czesc rozkazu JMP FAR
StareInt13 dd ? ; koncowka rozkazu JMP FAR
Wylacz_TF:
cli ; zablokuj przerwania
push ax bx ds ; zachowaj zmieniane rejestry
push ss ; za pomoca tej sztuczki zwykle
pop ss ; mozna pobrac 'prawdziwy' obraz
pushf ; / rejestru znacznikow
pop ax ; /
test ah,1 ; czy TF ustawiony ?
jz TF_NieUstawiony ; NIE - nie trzeba nic robic
mov ax,0123h ;
push ax ; ss:[sp]:=0123
pop ax ; ax:=ss:[sp]:=0123
dec sp ; sp=sp-2-wskazuje na wartosc,
dec sp ; ktora byla sciagana ze stosu
pop ax ; ax:=ss:[sp]:=0123 jezeli TF=0
cmp ax,0123h
jz TF_NieUstawiony ; NIE - nie trzeba nic robic
xor ax,ax ; DS wskazuje na tablice przerwan
mov ds,ax ; /
lds bx,ds:[01h*4] ; DS:BX wskazuje na adres obslugi
; przerwania krokowego INT 1
mov al,0CFh ; kod 0CFh oznacza IRET
xchg al,ds:[bx] ; wymien pierwszy bajt w procedurze
; obslugi INT 1 - teraz jest tylko
; IRET
push ax ; zachowaj pierwszy bajt procedury
pushf ;
pop ax ; zeruj TF
and ah,0FEh ; -
push ax ; /
popf ; /
pop ax ; przywroc pierwszy bajt
mov ds:[bx],al ; i zapisz go z powrotem
TF_NieUstawiony:
pop ds bx ax ; przywroc zmieniane rejestry
ret ; powrot z procedury
KoniecKoduTSR:
Poczatek:
mov es,ds:[2Ch] ; ES=blok otoczenia programu
mov ah,49h ; funkcja DOS - zwolnij blok pamieci
int 21h ; wywolaj funkcje
lea si,TeCopyRight ; pokaz info o programie
Call Print ; /
mov bp,0BACAh ; wez stare INT 21h i jednoczesnie
mov ax,3521h ; - odinstaluj program, jezeli juz
int 21h ; / byl wczesniej zainstalowany
cmp ax,0BACAh ; czy zostal odinstalowany ?
je Deinstal ; TAK - wyswietl komunikat i koncz
mov word ptr [StareInt21],bx ; zachowaj stare INT 21
mov word ptr [StareInt21+2],es ; /
mov ax,3513h ; funkcja DOS - wez stare INT 13h
int 21h ; wywolaj funkcje
mov word ptr [StareInt13],bx ; zachowaj stare INT 13
mov word ptr [StareInt13+2],es ; /
lea si,TeZainstalowany ; pokaz info o programie
Call Print ; /
lea dx,NoweInt21h ; DS:DX wskazuje na nowa procedure
mov ax,2521h ; funkcja DOS - ustaw nowa INT 21
int 21h ; wywolaj funkcje
lea dx,NoweInt13h ; DS:DX wskazuje na nowa procedure
mov ax,2513h ; funkcja DOS - ustaw nowa INT 13
int 21h ; wywolaj funkcje
mov dx,DlugoscKoduTSR ; ile kodu zostanie jako TSR
mov ah,31h ; funkcja DOS - koncz i zostaw TSR
int 21h ; wywolaj funkcje
Deinstal:
lea si,TeOdinstalowany ; pokaz info o deinstalacji
Call Print ; /
mov ax, 4C00h ; funkcja DOS - koncz program
int 21h ; wywolaj funkcje
Print proc near ; procedura wyswietla tekst ASCIIZ
; spod adresu CS:SI
push ax ; zachowaj zmieniane rejestry
push si ; /
GetNextChar:
lods byte ptr cs:[si] ; wez kolejny znak
or al,al ; czy znak jest zerem ?
jz PrintExit ; tak=koniec napisu; wyjdz z petli
Call PrintChar ; nie=wyswietl znak w AL
;
jmp short GetNextChar ; i wez nastepny znak
PrintExit:
pop si ; przywroc zmieniane rejestry
pop ax ; /
ret ; powrot z procedury
Print endp
PrintChar proc near ; procedura wyswietla znak w AL
push ax ; zachowaj zmieniany rejestr
mov ah,0Eh ; funkcja BIOS
int 10h ; wyswietl znak w AL
pop ax ; przywroc zmieniany rejestr
ret ; powrot z procedury
PrintChar endp
TeCopyRight db CR,LF,'ANTYTRAC v1.0, Autor : Adam Blaszczyk 1997'
TeCRLF db CR,LF,NUL
TeZainstalowany db CR,LF,' _ ANTYTRAC zainstalowany!',NUL
TeOdinstalowany db CR,LF,' _ ANTYTRAC odinstalowany!',NUL
ANTYTRAC ENDS ; koniec segmentu kodu i danych
END Start ; koniec programu, pierwsza instrukcja
; pod etykieta Start
12.8. Pobieranie wielkości pamięci operacyjnej
Ze względu na to, iż większość wirusów rezydentnych instaluje się w pamięci poprzez modyfikację nagłówków pamięci MCB, możliwe jest wykrycie większości takich intruzów poprzez obliczenie wielkości dostępnej pamięci na różne sposoby i następnie na porównaniu, czy uzyskane wartości zgadzają się ze sobą. Poniższy program pobiera na cztery sposoby wielkość pamięci operacyjnej poniżej 640K i następnie rozmiar ten wyświetla na ekranie.
;
Czesc ksiazki : 'Nowoczesne techniki wirusowe i antywirusowe' ;
;
MEM640 v1.0, Autor : Adam Blaszczyk 1997 ;
;
; Programik pobiera i wyswietla rozmiar pamieci ponizej 640kb ;
; Wielkosc pamieci jest pobierana kilkoma metodami ;
; Przy jego uzyciu mozna wykryc w pamieci obecnosc wirusa ;
; rezydetnego (gdy odczytane dlugosci pamieci beda rozne) ;
;
PROG SEGMENT
ORG 100h
ASSUME CS:PROG, DS:PROG
NUL = 00h ;
LF = 0Ah ; - stale znakow
CR = 0Dh ; /
Start:
lea si,TeCopyRight ; SI=ofset do info o programie
Call DrukLn ; wyswietl info o programie
Call Pokaz_CMOS ; ile zapisane w CMOS
call Pokaz_ZmiennaBIOS ; ile w komorce 0000:0413
call Pokaz_Int12 ; ile zwraca INT 12
Call Pokaz_MCB ; ile z sumy MCB
mov ax,4C00h ; funkcja DOS - koncz program
int 21h ; wywolaj funkcje
Pokaz_CMOS:
push ax dx si ; zachowaj zmieniane rejestry
lea si,TeCMOS ; wyswietl info skad czytany
Call Druk ; / rozmiar pamieci
mov al,16h ; wez z CMOS starsza czesc
Call WezCMOS ; / rozmiaru pamieci
mov ah,al ; i przepisz do AH
mov al,15h ; wez z CMOS starsza czesc
Call WezCMOS ; / rozmiaru pamieci
; AX= rozmiar w CMOS w kilobajtach
mov dx,1024 ; oblicz ile bajtow
mul dx ; /
Call DrukDec32 ; wyswietl ile bajtow
pop si dx ax ; przywroc zmieniane rejestry
ret ; powrot
WezCMOS:
out 70h,al ; zapisz do portu CMOS,
; ktora komorke czytac
jmp $+2 ; czekaj
in al,71h ; czytaj z CMOS
ret ; powrot
Pokaz_Int12:
push ax dx si ; zachowaj zmieniane rejestry
lea si,TeInt12 ; wyswietl info skad czytany
Call Druk ; / rozmiar pamieci
int 12h ; przerwanie BIOS - dostepna pamiec
; AX=rozmiar pamieci w kilobajtach
mov dx,1024 ; oblicz ile bajtow
mul dx ; /
call DrukDec32 ; wyswietl ile bajtow
pop dx ax si ; przywroc zmieniane rejestry
ret ; powrot
Pokaz_ZmiennaBIOS:
push es ax dx si ; zachowaj zmieniane rejestry
lea si,TeZmiennaBIOS ; wyswietl info skad czytany
Call Druk ; / rozmiar pamieci
xor ax,ax ; czytaj zmienna BIOS 0000:0413
mov es,ax ; ES=0000
mov ax,es:[413h] ; AX=0000:0413= rozmiar pamieci
; w kilobajtach
mov dx,1024 ; oblicz ile bajtow
mul dx ; /
Call DrukDec32 ; wyswietl ile bajtow
pop si dx ax es ; przywroc zmieniane rejestry
ret ; powrot
Pokaz_MCB:
push es ax bx cx dx ; zachowaj zmieniane rejestry
lea si,TeMCB ; wyswietl info skad czytany
Call Druk ; / rozmiar pamieci
mov ax,5802h ; funkcja DOS - czy UMB dolaczone ?
int 21h ; wywolaj funkcje
push ax ; zachowaj informacje na pozniej
mov ax,5803h ; funkcja DOS - dolacz/odlacz bloki UMB
mov bx,1 ; sprobuj dolaczyc bloki UMB
int 21h ; wywolaj funkcje
mov ax,5802h ; funkcja DOS - czy UMB dolaczone ?
int 21h ; wywolaj funkcje
xor cx,cx ; CX=0 - UMB nieobecne w systemie
or al,al ; 01=jezeli UMB sa dolaczone
jz UMB_NieDolaczone ; 00=jezeli UMB nie sa dolaczone
inc cx ; CX=1 - UMB obecne w systemie
mov ax,5803h ; funkcja DOS - dolacz/odlacz bloki UMB
xor bx,bx ; odlacz bloki UMB
int 21h ; wywolaj funkcje
UMB_NieDolaczone:
mov ah,52h ; funkcja DOS - wez adres listy list LL
int 21h ; wywolaj funkcje
mov ax,es:[bx-2] ; wez adres pierwszego bloku MCB
NastepnyMCB: ; kolejne bloki MCB
cmp ax,0A000h ; czy >640kB ?
jae Tylko640 ; TAK - pomin
mov es,ax ; ES=MCB
stc ; +1 w dodawaniu ponizej
adc ax,word ptr es:[3] ; dodaj rozmiar bloku MCB+1
; AX=nastepny blok MCB
cmp byte ptr es:[0],'Z' ; czy to ostatni blok MCB ?
jne NastepnyMCB ; NIE - dodaj koleny blok
; TAK - wyswietl sume
Tylko640:
add ax,cx ; dodaj ewentualny blok MCB
; opisujacy bloki MCB w pamieci UMB
; AX=pamiec w paragrafach
mov bx,16 ;
mul bx ; / oblicz ile bajtow
call DrukDec32 ; wyswietl ile bajtow
pop bx ; przywroc info o UMB
mov bh,0 ; BX=BL
mov ax,5803h ; funkcja DOS - dolacz/odlacz bloki UMB
int 21h ; wywolaj funkcje
pop dx cx bx ax es ; przywroc zmieniane rejestry
ret ; powrot
DrukDec32: ; wyswietl liczbe w DX:AX
push ax bx dx si ; zachowaj zmieniane rejestry
mov si,offset Hex2DecBufor+10 ; ustaw na koniec bufora, bo zapis od konca
mov byte ptr [si],0 ; utworz ASCIIZ dodaj zero na koncu
DzielPrzez10:
mov bx,10 ; dziel DX:AX przez BX
Call Dziel32 ; w BX reszta z dzielenia
add bl,'0' ; dodaj ASCII '0'
dec si ; zmniejsz index w tablicy
mov byte ptr ds:[si],bl ; zapisz cyfre
or dx,dx ;
jnz DzielPrzez10 ;
or ax,ax ;
jnz DzielPrzez10 ; --- czy liczba jest juz rowna 0
; NIE - dziel dalej
call DrukLn ; TAK - wyswietl bufor
pop si dx bx ax ; przywroc zmieniane rejestry
ret ; powrot
Dziel32: ; dziel (DX:AX)/BX
push bp ; zachowaj BP
push ax ; zachowac mniejsza czesc liczby 32 bitowej
mov ax,dx ; przenies b. znacz. czesc do mniej. znacz.
xor dx,dx ; i wyzeruj DX, DX:AX = > 0:DX
div bx ; podziel (0:DX)/BX
mov bp,ax ; calosc z dzielenia to wieksza czesc wyniku
pop ax ; przywroc do AX mniej znaczaca liczbe z poczatku
div bx ; DX jest reszta z dzielenia b. znacz. czesci przez BX
mov bx,dx ; w BX reszta z dzielenia
mov dx,bp ; DX:AX=liczba podzielona przez BX,
; a w BX reszta z dzielenia
pop bp ; przywroc zmieniany rejestr
ret ; powrot
DrukLn:
push si ; zachowaj zmieniany rejestr
call Druk ; wyswietl tekst z CS:SI
lea si,TeCRLF ; i przejdz do nastepnej linii
Call Druk ; /
pop si ; przywroc zmieniany rejestr
ret ; powrot
Druk:
push ax si ; zachowaj zmieniane rejestry
DrukPetla:
lods byte ptr cs:[si] ; wez kolejny znak tekstu
or al,al ; czy NUL ?
jz DrukPowrot ; TAK - koniec tekstu
mov ah,0Eh ; funkcja BIOS - wyswietl znak
int 10h ; wywolaj funkcje
jmp short DrukPetla ; pobierz kolejny znak tekstu
DrukPowrot:
pop si ax ; przywroc zmieniane rejestry
ret ; powrot
TeCopyRight db CR,LF,'MEM640 v1.0, Autor : Adam Blaszczyk 1997'
db CR,LF
db CR,LF,'Wielkosc pamieci w bajtach :',NUL
TeCMOS db ' _ CMOS : ',NUL
TeInt12 db ' _ INT 12 : ',NUL
TeZmiennaBIOS db ' _ Zmienna BIOS 0000:0412 : ',NUL
TeMCB db ' _ Suma blokow MCB (<640kB) : ',NUL
TeCRLF db CR,LF,NUL
Hex2DecBufor db 11 dup(?) ; bufor na liczbe dzisietna
PROG ENDS
END Start
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 667
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved