Impulzus

 
A Budapesti Műszaki és Gazdaságtudományi Egyetem Villamosmérnöki és Informatikai Kar Hallgatói Képviseletének lapja

10 éves a vírus

Az előző számban megjelent, nosztalgikus, múltidéző történeti cikk folytatásaként álljon itt egy programozói szemmel nézve szakmaibb, amolyan kedvcsináló írás arról, hogy vajon hogyan is működnek a vírusok. A teljesség igénye nélkül, a file-vírusok példáján keresztül próbálok meg tippeket adni azoknak, akik késztetést éreznek arra, hogy egy-egy netről letöltött konzervvírust, avagy szőke titkárnő gépének rendberakása közben talált szerzeményt alaposabban megvizsgáljanak.

Amennyiben emulátorban dolgozunk (pl. VMware, vagy Linux dosemu), és partíció elérés nélkül, diskimage-be írunk, különösebb veszélye nincs a dolognak. A bátrabbak persze csinálhatják közvetlenül egy DOS ablakból, itt csak arra kell figyelni, hogy debugolás közben nehogy elszabaduljon a vírus (tipikusan popf utasítás vagy INT 1 vektor állítása szokott ilyet eredményezni). Az, hogy debugolás közben rezidenssé válik a vírus, nem gond, mert a debuggerek mindig szorgalmasan lementik/visszatöltik az interrupt vektorokat.

Vegyünk egy egyszerű, com-okat fertőző vírust. Ezek többsége a file végéhez írja be magát, a file elejére pedig lerak egy JMP vagy CALL utasítást, amely a vírustestre mutat. Némi ellenőrzés és inicializálás után a vírus visszamásolja a file elejére az eredeti program byte-jait (amelyeket a JMP felülírt), és futtatja a fertőzött programot, mintha mi sem történt volna. Mivel a hordozó programtól függ, hogy a vírus milyen offszetcímre kerül, ezért a vírus a saját változóihoz általában BP relatív címzéssel fér hozzá. Egy tipikus fertőzött file:

0100  JMP   12E3........              # a hordozó program kódja....12E3  CALL  12E6  # praktikus megoldás az                  # offszet meghatározásához12E6  POP   BP....                 # inicializálás12E7  MOV   SI,BP12E9  SUB   SI,010912ED  MOV   DI,0100  # a program elejének a                     # visszaállítása12F0  MOVSW12F1  MOVSB12F2  PUSH  0100 # a hordozó program futtatása12F5  RET

Az inicializáló rész tartalma is meglehetősen kötött, például:

– Itt szokás ellenőrizni a rendszerdátumot. Vajon bekövetkezett-e az az előre beprogramozott időpont, amikor rombolni támad kedve a vírusnak? Ha igen, indul egy ciklus, amely teleírja szeméttel a merevlemez elejét, a BIOS INT 13 megszakítását felhasználva.

MOV AH,2AINT 21       # a DOS dátum szolgáltatásaCMP DX,0208  # február 8-a?

Mókás példa a Nov17 vírus esete (legalábbis az F-Prot nevezi így), amely még véletlenül sem 17-én rombol, mert abban CMP DL,17 van, azaz hexa-decimális 17. :)

– Meg kell vizsgálni, hogy már aktív-e a vírus. Ez egy INT 21 hívással történhet, amely egy nem definiált függvényre hivatkozik. Az aktív vírus persze ezt figyeli, és visszaad egy megfelelő konstanst. Egyébként aktívvá kell tennie magát a vírusnak, bemásolja magát a 640K-s határ alá, és magára állít néhány interrupt vektort (pl. 21-eset, így figyelni tudja a file-ok megnyitását, írását, futtatását). Pici, trükkös vírusok máshol is elbújhatnak a memóriában, például egy nem használt DOS puffer-területben.

Láttam olyat egy vírusban, hogy egy 80 byte-os területet hexa 80 hosszúságúként kezelt. Ilyen okai vannak annak, hogy vírusos környezetben a gép a szokásosnál kissé instabilabb...

– Kikódolás. A vírusok kódoltan is tárolódhatnak. Ez lehet egy szimpla XOR egy konstannsal, de lehet egészen összetett is: véletlenszámtól függő algoritmuskiválasztás, alakváltoztató kódoló ciklus, változó, hogy melyik regiszterrel kódol stb. Így elérhető, hogy két különböző generációs vírus egyetlen byte-ban sem hasonlít, de mégis ugyanúgy fut le.

Miután az inicializálás lefutott, a vírus már figyeli is a file-műveleteket. Általában futtatáskor fertőznek, de van olyan is (pl. Trident), amelyik egy dir parancs hatására végigfertőzi az egész könyvtárat. Persze egy jó vírus nem tesz ilyet, ennél sokkal körültekintőbb. Kevesebbszer fertőz, és akkor is jól megnézi, hogy mit. Például COMMAND.COM-ot, Norton Commandert nem, vírus-keresőket, túl kicsi file-okat sem. Rááll a 24-es interruptra is, hogy némileg átvegye a DOS-tól a hibakezelést. (Az Androméda ezt nem teszi, így egy írásvédett lemezen egy futtatás során kaphatunk write errort is. Abort, Retry, Fail?)

Cseles kódrészlet a Trident vírusból:

0200  MOV   AX,2501  # INT 1 vektor beállítása                     # (trap, utasításonkénti                     # végrehajtás)0203  INT   210205  PUSHF0206  PUSH  CS0207  PUSH  0219     # innen fog folytatódni020A  PUSHF020B  POP   AX020C  OR    AX,0100  # trap bit beállítása a                     # flagben020F  PUSH  AX0210  PUSH  word ptr [0300]   # INT 21 vektor0214  PUSH  word ptr [0302]0218  IRET       # INT 21                 # végrehajtása utasításonként0219  ......     # itt folytatódik a köv.                 # IRET után

Ez az akció arra jó, hogy a vírus megkeresse az INT 21 igazi belépési címét a DOS kernelben, és így lecselezzen mindenfajta aktív vírusvédőt, amely figyeli az INT 21-et. Ha megvan a belépési cím, a vírus csak azt hívja meg a fertőzési műveletnél az INT 21 helyett. Persze ez ellen az antivírus is védekezhet, nem engedi magát trap-elni, azaz extrábbnál extrább módokon állítja vissza a flag-et. Hogy melyik győz? Amelyiknek az írója több időt, kódot és trükköt szánt erre a kis momentumra...

Látható, hogy egy jó vírus megírása kreatív dolog, nem véletlen, hogy tízezerszámra gyártják őket a sportemberek (avagy a számítógépes alvilág, amolyan Kókusz Plusssz stílusban fogalmazva). Jó keresőt írni azonban nagyságrendekkel nehezebb feladat. Akik erre nem vállalkoznak, egyszerűen csak érdekli őket a programozás eme változatos színfoltja, azok számára a vírus nem más, mint egy művészi alkotás egy művészien gagyi operációs rendszer környezetében: igazi bitfaragós játék.

bereg