  Ŀ
  Ŀ
   PS 21  Nisan'95                                                       
             "Trkiye in alyoruz"  Virsler III                    
                                                                          
  ٳ
   Recep Tezkol 
  



> Merhaba Dostlar,

  Boot virsleri ile baladmz VRSLER sohpetimizi bu ay dosya
  virsleriyle iyice koyulatracaz. Dikkat ettiyseniz Boot virsleri
  konusunda pek ayrntya girmedim. nk bu tr virslere kar nlem almak
  ve temizlemek olduka kolaydr. Sevgili dostum Hakan Baykara'nn deyimiyle
  yle hafif nemli bir bez ile temizlenebilecek trden virsler ile zaman
  kaybetmek istemedim.

  Benim gzmde gerek bela dosya virsleridir. te bu nedenle dosya
  virslerinde hi bir konuyu atlamamaya zen gstereceiz. Dizi boyunca
  anlayamadnz veya bizim atladmz bir konuyla karlatnzda ltfen
  bunu bildiriniz.


  PSAV 3.0 Yolda
  
  Bu arada PSAV 3.0 iin almalarmz iyice younlatrdmz da sylemek
  isterim. PSAV'n yararlln arttrmak iin virs katklarnz
  bekliyorum. Gndereceiniz yeni km herhangi bir ad olmayan virslerin
  isim babal hakk sizindir ve bu PSAV'da belirtilecektir.

  Yaknda sizlere sunacamz Programlama Sanat Anti Virs programnn
  kaynak kodunu bir seferde vermek sanrm g olacaktr. Assembly dilinde
  yazdm bu programn kaynak kodu u anda 8000 satr buldu. Bu nedenle
  her ay virsler yazmzn sonunda PSAV'n baz blmlerinin kaynak kodu
  verilerek anti virs almas yapan programclarn kullanmna
  sunulacaktr.

  Virsler yaz dizimiz sresince PSAV'n tm kaynak kodunu vereceiz. Bu ay
  komut satrndan parametre alm ile ilgili fonksiyonlarn bulunduu
  GETPARAM.ASM dosyas verilmitir. Verilen bu blm zerinde dzeltmeler
  yaplmamtr. Bu rutinlerden yararlanmak isteyenler program incelemeli ve
  gerekli dzeltmeleri yapmaldr.



  PSAV'n YAZARLARINDAN BR OLMAK STER MSNZ?
  
  Verdiim blmlerin kontroln yaparak eski durumundan daha gvenilir hale
  getirenler arasndan seilecek imdilik 1 kiiye mouse hediye edeceim.
  (Daha byk bir hediye vermek isterdim ama maddi durumum ancak buna
  yetiyor.) Bunun yannda PSAV iin neri ve dzenleme yapan her programc
  arkadam, PSAV 3.0'n program yazanlar blmnde yer alacaktr.

              Bu listede sizin adnz da grmek isterim...





 Virsler Yaz Dizisi III 




                           DOSYA VRSLER
                           

  Bildiiniz gibi dosya virsleri ok eitli yaplarda karmza kyorlar.
  ncelememizi srasyla aadaki dzende yapacaz.


     1Dosya Virslerinde Kullanlan Teknikler:
         a.Virs koduna JMP ile dallanma
           a1. JMP komutu
           a2. CALL komutu
           a3. Virs verisine eriim
         b.Sabit offsetli virsler
           b1. RETF komutu
           b2. JMP  FAR komutu
         c.EXE dosyalarn yaps
           c1.exe balnn yaps
           c2.exe balndaki bilgilerinin deerlendirilmesi
    
       2TSR Olmayan Virsler:
         - PSP nedir?
         - DTA nedir?
         - Virslerin kulland DOS fonksiyonlar
            a.COM virsler
            b.EXE virsler
            c.COM-EXE virsler
            d.ifreli virsler
    
       3TSR Virsler:
         - Virslerin bellekte yerleik kalmak iin kulland yntemler
         - MCB nedir ?
            a.COM virsler
              a1. Virs kodu dosya banda olanlar
              a2. Virs kodu dosya sonunda olanlar
              a3. ifreli virsler
            b.EXE virsler
              b1. Yasal TSR olanlar
              b2. Yasa d TSR olanlar
              b3. sifreli virsler
            c.COM-EXE virsler
              a ve b blmlerinin birleimi
    
      4.Eitim Amal Virs Kodlar







  
  1Dosya Virslerinde Kullanlan Teknikler
  


  1a.JMP Komutu
  
  COM tipi dosyalara bulaan bir ok virs, bu komutu kullanarak bulatklar
  dosyalarda kontrolu ele geirir.Bu nedenle bir anti-virs yazar,
  temizleyecei virsn dosya zerindeki yerini bulabilmek iin JMP komutunun
  yapsn bilmelidir.

  Ayn segment iinde atlamay gerekletiren JMP komutu, atlanacak adresin
  uzaklna bal olarak 2 veya 3 byte uzunluunda olacaktr.

        0EBh  2 byte uzunluundaki JMP komutunun makina dili kodu
        0E9h  3 byte uzunluundaki JMP komutunun makina dili kodu




  2 Byte'lk JMP Komutu: (JMP SHORT)
  
  Yukarda da belirttiim gibi 2 byte uzunluundaki bir JMP komutu 0EBh ile
  balar.0EBh komutunu takiben atlamann ne kadar olaca, iaretli, bir byte
  uzunluunda say ile verilir( -128 ile +127 ). aretli saylarn
  ayrntlaryla boumak ile zaman kaybetmeden (bu konuda bilginiz yoksa
  en ksa zamanda edinmenizi neririm.) bu problemi pratik bir yntemle
  halletmek en dorusu olacak.

  Bu makina kodunun yannda bulunan bir byte uzunluundaki deer atlamann
  ynn ve uzunluunu belirtir. buradaki say negatif (-) ise geriye,
  pozitif (+) ise ileriye atlanacan belirler. Ama burada taban noktann
  jmp komutundan ve onun 1 byte'lk parametresinden sonra gelen adres olduunu
  unutmayn.

  Buna bir assembly program ile rnek verelim:
Ŀ
.model  tiny                                                                
.code                                                                       
        org 100h                                                            
basla:                                                                      
        db 0EBh             ;JMP komutunun makina dili karl            
        db 8                ; 8 byte ileri atla                             
                                                                            
        db 0,0,0,0,0,0,0,0  ; 8 byte                                        
                                                                            
etiket:                                                                     
        db 0EBh             ;JMP komutunun makina dili karl            
        db -(2+8+2)         ;2   bu jmp komutunun uzunluu +                
                            ;8   yukardaki 8 adet 0    +                   
                            ;2   basla: etiketindeki jmp komutununuzunluu  
                            ; - iareti buradan geriye atlanacan gsterir
end basla                                                                   


  Bu program debug ile incelenmek iin dzenlendiinden, derlendikten sonra
  direkt olarak altrmaynz. Programa  ornek.asm adn verdiinizi kabul
  edersek,nce tasm.exe ve tlink.exe ile program derleyelim.

         C:\> tasm ornek
         C:\> tlink ornek /t

  Sonucu grmek iin debug programn kullanacaz.

         C:\>debug ornek.com
         -u
         1238:0100 EB08          JMP     010A
         1238:0102 0000          ADD     [BX+SI],AL
         1238:0104 0000          ADD     [BX+SI],AL
         1238:0106 0000          ADD     [BX+SI],AL
         1238:0108 0000          ADD     [BX+SI],AL
         1238:010A EBF4          JMP     0100





  3 Byte'lk JMP Komutu:
  
  Yukarda yaplan ilemler buradada aynen geerlidir. Tek fark bu JMP komutu
  1 word uzunluunda (2 byte) atlama deerine sahiptir. Bu komuta (0E9h),
  atlama bilgisi olarak -32768 ile +32767 deerleri verilebilir. Bu da bize
  bir segmentin herhangi bir noktasna dallanma imkan tanr.

  Eer iaretli saylar konusunda bilginiz yoksa (benim gibi) aklnza yle
  bir soru gelebilir. JMP komutunun bulunduu offset 0 ise ve yukardada
  - iaret geri, + ileri atlamay belirttiini sylediine gre biz 32767
  bayt'tan daha ileri atlamay  nasl yapacaz?.

  Burada atlama uzunluu olarak dnlen say 32767'den fazla ise, bu zaten
  negatif bir saydr ve atlama bulunulan offsetten geriye doru olacaktr.
  hex 8000 = dec -32768 = (32767 + 1)

  Not: bir saynn en yksek bit'i o saynn iaretini verir. Bu bit 1 ise
  say negatif, 0 ise say pozitif'tir.

  rnek:
  0. offsette  0e9h 00 80h byte'lar bulunsa, ki buna debug ile bakarsak
  bu baytlar "JMP 8003" eklinde assembly komutu olarak grlecektir.
  Daha ncede dediimiz gibi atlamann yaplaca taban JMP komutundan sonraki
  offset alnacaktr.JMP komutumuz 3 byte olduuna gre 3 byte geri gidersek
  3-3 = 0.offsete geliriz. Geriye gitmek iin daha 32765 byte'mz var.
  0 dan sonra -1 yani hex 0ffffh geldiini biliyoruz(yoksa bilmiyormuyuz).
  imdi 0' dan 32765 byte daha geriye gittiimizde 8003h.offsetine gelmi
  olacaz.

  Ben matematik uzman deilim, o nedenle bunlar bilimsel olarak anlatp
  ikigene! eviremiyorum ama siz bunlar dert etmeyip atlayacanz uzunluun
  iaretine bakmadan koy verin gitsin, o gidecei yeri bilir.


  Biraz da Pratik Yapalm (ok teorik yaptk!)
  
  Virs, bulaaca dosyann boyunu bulduktan sonra dosyann sonuna kendinin
  (virsn) tm kodunu ekleyerek bu noktaya dallanma yapacak bir JMP komutunu
  dosyann bana konulandrr.Normalde dosyalar 127 byte'tan uzun olaca
  iin dosya bana koyduu JMP komutu 3 byte 'lk olacaktr. Yukarda JMP
  komutunu aklarken rendiklerimiz ile dosya bana;

        db 0E9h
        dw dosya_boyu - 3

  eklinde 3 byte'lk bir bilgi kopyalanacan syleyebiliriz.Biraz fazla
  olacak ama yine tekrar edelim, dosya boyundan 3 eksiltmemizin amac JMP
  komutunun atlama olarak kendisinden sonra gelen offseti taban almasndandr.


                Ŀ
                 db 0e9h         
                 dw (1000 - 3)   
                -------------------
                                   
                                   
                     COM           
                    dosya          
                (boyu 1000 byte)   
                                   
                  
                Ŀ <
                                 
                      virs      
                                 
                


  Dosya altrldnda virsn dosya bana yerletirdii JMP komutu
  nedeniyle kontrol virse geecektir.Tam bu aamada virsn karsna
  ok nemli bir problem kacaktr.


  Kontrol Virsn Elinde Ama Virs Nerede?
  
  Virs bulunduu offseti bilemez ise hi bir ey yapamayacaktr.
  JMP, CALL, JZ, vb.. gibi komutlar iin gerekmiyor ama virsn iinde
  bulunacak,

                mov ax,[500]

  gibi bir komut yanl adresten bilgi almaya neden olacaktr. nk bu adres
  orjinal dosyann bulunduu bellek blgesinde yer almaktadr.

  Aslnda bu zm olmayan bir problem deildir. imdi gelin buna bir zm
  bulalm.


  ...DERSE DEVAM


  CALL Komutu:
  
  CALL komutu bir adrese dallanmadan nce kendisinden sonra gelen komutun
  ofsetini STACK'a atarak dallanmay gerekletirir. Dallanlan alt programda
  kullanlan bir RET komutu STACK'ta bulunan adresi IP yazmacna aktarr.
  Bu durum, ileyiin kalnan yerden devam etmesine neden olur.


  IP Yazmac?
  
  Mikro ilemcimizin (CPU) 'IP' diye adlandrlan ve dier yazmalar gibi
  direkt olarak eriilemeyen bir yazmac vardr.

  IP (Instruction Pointer) yazmac ilenecek komutlarn adreslerini takip eden
  zel bir yazmatr.

  Virs bu yazmacn ieriini renerek kodunun segment iindeki yerini bulur.

                        Call  alttaki_komut
             alttaki_komut:
                        Pop   Si

  Yukardaki rnekte CALL ile bir sonraki satra dallanma yaplmtr.Burada
  dallanma ncesi 'alttaki_komut' ile isimlendirilen adres STACK'a konulduunu
  bildiimizden  POP ile bu adresi bir yazma zerine alabiliriz. Artk virs
  iindeki data alanlarna, bu yazmata bulunan deeri taban olarak kullanarak
  eriebiliriz.


  rnek
Ŀ
Virsbasi  label word                                                       
        ....                                                                
        ....                                                                
        call    alttaki_komut                                               
alttaki_komut:                                                              
                                                                            
Farkuzunluk  equ $-virsbasi  ;virsbasi ile bu nokta arasnda bulunan      
                              ;byte saysn bulur.                         
        Pop     Si                                                          
        sub     Si,Farkuzunluk;bu deer Si'den karldnda Virsbasi'nn 
                              ;offseti bulunur.                             
        mov     ax,[si+veri]  ;virs bandan veri kadar ilerideki word' al
        .....                                                               
        .....                                                               
veri    equ $-virsbasi                                                     
        dw 1111h                                                            




  CALL komutu hakknda son bir ka bilgi
  
  CALL komutunun yannda bulunacak 1 word'lk deer 3 byte uzunluundaki JMP
  komutundaki ile ayn yapda ve bu komutun makina dili karl 0E8h'dir.

        db 0e8h
        dw  (-+)(atlanacak byte says)






  1b.Sabit Offset'li Virsler
  
  COM tipi dosyalara bulaan baz virsler(yazarlar) kodunun segment iindeki
  yerinin (offsetinin) sabit olmasn ister. Olabilir tercih meselesi,
  onlarada saygmz var. Bildiiniz gibi 1 mega byte'lk bellein herhangi bir
  noktasn gstermek iin bir segment ve bu segmentin ierisinde bulunan
  offset adresine ihtiyacmz vardr. Bir yanllk yapmyorsam bir bellek
  hcresi iin 4000'den fazla deiik segment:offset adres bileimi
  kullanabiliriz(baz durumlarda bu yanl olabilir,fazla ciddiye almayn).

  1000h:0000h ile verilen bir adresin segmentinden her 1 azaltlmasna
  karlk offsetine 16 eklenmesiyle ayn adres hcresi gsterilebilir.


  PRATIK
  
  Virs kodunun balangcn segmentin 100h. offsetinde olmasn istiyorsa ve
  uzunluu 1000h olan bir COM dosyaya bulam ise bu virsn kodu o segmentin
  1100h. offsetinde olacaktr.(100h fazlalk PSP uzunluundan kaynaklanyor)
  virs kendi koduna bir jmp ile atlama yapsada offset uygun olmadndan
  dzenlenme ekli nedeniyle almas imkanszdr.Virs yazarda bunu
  bildiinden virse dallanmay JMP yerine CS ve IP yazmalarnn ieriini
  deitiren bir rutini programn bana yerletirir.

        mov     ax,cs
        add     ax, (dosya uzunluu / 16)
        push    ax                            ;yeni CS  -> stack
        mov     ax,100h
        push    ax                            ;yeni IP  -> stack
        retf                                  ;virs bana..


  Burada yaplan iin doru olabilmesi iin dosya uzunluunun 16'ya
  blndnde kalann olmamas gereklidir. Dosya uzunluu 16'nn kat
  olmaldr. ki virs kendi kodunu dosyaya eklemeden nce bunu kontrol eder ve
  gerektiinde dosyaya eklemeler yaparak bunu salar. Bu konuyu daha sonra ele
  almak zere bir kenara brakp u RETF nedir ne deildir ona bakalm.


  ..DERSE DEVAM
  
  Getiimiz ay CALL komutunun ileyiini renmitik. CALL komutu bir adrese
  dallanmadan nce bir sonraki komutun adresini STACK'ta saklyordu. Bunun
  tamamlaycs RET komutu ise STACK'taki bu adresi alarak IP yazmacna
  aktarr. IP yazmac ilenecek komutun adresini gsterdiinden bu bir nevi
  JMP komutuna edeerdir. Bir alt programdan dnmek iin RET
  kullanlabilecei gibi bunun yerine ;

        pop     ax
        jmp     ax

  kullanabilirsiniz ama bunun pekte akllca olmayaca aktr. nk RET
  komutu 1 byte yer kaplamasna karlk yukardaki benzeri 3 byte yer
  kaplayacaktr. rendiimiz CALL komutu ayn segmentler iin dallanmalar
  gerekletiriyordu.Segmentler aras dallanma yapan CALL komutu ise dallanma
  ncesi  CS,ardndan IP yazmacnn deerini STACK'a push eder.Bu trden bir
  atlamann dnde RETF komutu ile olacaktr. RETF komutunun ileyii;

        pop     IP
        pop     CS

  eklinde dnlebilir. Yukardada verdiim rnekte bu zellik
  kullanlmtr. Bu trden bir atlama kullanan virse rnek olarak KEYPRESS
  verilebilir.

  Buna benzer ekilde dallanma yapan 1559 virs ise JMP FAR komutunu
  kullanr. isterseniz yukardaki rnei bir de bu ekilde dzenleyelim.


            mov     ax,cs
            add     word ptr cs:[viradr+2],ax    ;yeni segmenti hesapla
            jmp     dword ptr cs:[viradr]        ; jmp far [viradr]

    viradr  dw      100h                         ;offset
            dw      (dosya uzunluu /16)         ;segment


  JMP FAR  verilen adreste bulunan ilk word' IP yazmacna,arkasndan ikinci
  word' CS yazmacna aktararak dallanmay gerekletirir.


                             * * *

  Uykum Geldi!..
  
> u ana kadar virsleri incelememiz srasnda gerekecek noktalar gzden
  geirdik. Gelecek ay EXE dosyalarn balklarn, buradaki bilgilerin
  deerlendirilmesi virslerin buralarda yapt deiiklikler konusunda
  bilgilerle virsleri incelemeye  devam edeceiz.

  Saat bei oktan geti, ben yatmaya gidiyorum. Siz de yatsanz iyi olacak!.


                             * * *


   Ŀ
  ſ
                                                                       
                      PSAV 3.0'dan Blmler  1                        
                                                                       
  
   


GETPARAM.ASM / Assembly ksmnda yer alyor


;GETPARAM.ASM
        Jumps
        locals @@
.model  tiny
.data
__paramstr      db 255 dup(0)
.code
extrn _strlen : near                ; string.asm 'de
extrn _strcpy : near                ; string.asm 'de
extrn _PSP    : word                ; main.asm'de
;---------------------------------
;kullanm: push parametre_no
;          call _paramstr
;dn:    DS:AX="parametre",0
; parametre no 0=alan dosyann ismini verir.
;----------------------------------
public  _paramstr
_paramstr proc pascal no:byte
        push    bx si
        lea     bx,__paramstr
        mov     si,bx
        cmp     no,0
        jz      @@cik
        call    _paramcount
        xor     bx,bx
        cmp     no,al
        ja      @@cik
        mov     bl,no
        mov     bh,0
@@dongu:
        lodsb
        or      al,al
        jnz     @@dongu
        inc     bh
        cmp     bh,bl
        jnz     @@dongu
        mov     bx,si
@@cik:
        mov     ax,bx
        pop     si bx
        ret
_paramstr endp

;-------------------------
;bu alt program iseldir.
;program banda 1 kere arlr.
;_paramstr iin gerekli hazrlklar yapar.
;-------------------------------------------
public  _@paramstr
_@paramstr proc near
        push    bx cx dx di si ds es
        mov     es,_psp
        mov     es,es:[2ch]
        xor     di,di
@@dongu:
        mov     al,es:[di]
        inc     di
        or      al,al
        jnz     @@dongu
        cmp     byte ptr es:[di],0
        jnz     @@dongu
        add     di,3
        lea     bx,__paramstr
        call    _strcpy pascal,ds,bx,es,di
        call    _strlen pascal,ds,bx
        add     bx,ax
        inc     bx
        mov     di,bx
        push    ds
        pop     es
        mov     ds,_psp
        mov     si,81h
        xor     dx,dx
@@dongu1:
        lodsb
        cmp     al,13
        jz      @@bitti
        cmp     al,9
        jz      @@ara
        cmp     al,32
        jz      @@ara
        cmp     al,'/'
        jz      @@ara1
        stosb
        mov     dh,1
        jmp     @@dongu1
@@ara:
        or      dh,dh
        jz      @@dongu1
        xor     ax,ax
        stosb
        mov     dx,0001
        jmp     @@dongu1
@@ara1:
        or      dh,dh
        jz      @@dongu1
        xor     ax,ax
        stosb
        mov     al,'/'
        stosb
        mov     dx,0001
        jmp     @@dongu1
@@bitti:
        xor     ax,ax
        stosb
        pop     es ds si di dx cx bx
        ret
_@paramstr endp


;-------------------------------------
;dn: ax=kullanlan parametre says
;-------------------------------------
public  _paramcount
_paramCount proc near
        push    ds si bx cx dx
        mov     ds,_psp
        mov     si,81h
        xor     dx,dx
        xor     bx,bx
@@dongu:
        lodsb
        cmp     al,13
        jz      @@bitti
        cmp     al,9
        jz      @@ara
        cmp     al,32
        jz      @@ara
        cmp     al,'/'
        jz      @@ara1
        or      bl,bl
        jnz     @@dongu
        inc     dl
        mov     bl,1
        mov     bh,0
        jmp     @@dongu
@@ara:
        or      bl,bl
        jz      @@dongu
        or      bh,bh
        jnz     @@dongu
        mov     bl,0
        mov     bh,1
        jmp     @@dongu
@@ara1:
        or      bl,bl
        jz      @@dongu
        or      bh,bh
        jnz     @@dongu
        mov     bl,0
        mov     bh,1
        jmp     @@dongu
@@bitti:
        mov     al,dl
        cbw
        pop     dx cx bx si ds
        ret
_paramcount endp
end
