Cyber-Warrior.Org \ Doküman \ Web Güvenlik Açıkları > Assembler (7)
| Madde |
| |
Yazar : «¥¡g¡t€®» |
| |
Date : 23.11.2004 16:16:30 |
| |
# Assembler (7) |
| |
Mantiksal Bit çevirme ve kaydirma komutlari Bit çevirme ve kaydirma komutlari pek çok alanda kullanilir. Grafiksel islemlerde, çevrim islemlerinde, sayaçlarda,... Bit kaydirma kendi arasinda kaydirma komutlari ve çevirme komutlari olarak ikiye ayrilir. Kaydirma komutlarida aritmetik ve logical olarak ikiye ayrilirlar. Bunlarin arasinda islevsel bir farklilik vardir. Kaydirma komutlari biti sonuç 0 oluncaya kadar saga yada sola dogru kaydirir. Kaydirilan bit yokolur ve tersine islem yapilsa bile geriye dön emez. Çevirme komutlari ise bitleri çevirerek dönüsüm yapar ve bit sayisina bagli olarak tekrar eski degerine ulasir. Çevirme komutlarinda hiçbir bitin degeri kaybolmaz. Daima çevrimiçi olarak kalir. Iki komut grubunda da saga ve sola kaydirma mevcuttur ve ingilizcedeki left, right kelimelerinin basharfleri ile belirtilirler. Bu komutlar yardimci register ile kullanilarak blok kaydirma veya çevirme islemlerine tabi tutulabilirler. Yardimci register degismez olarak CL registerdir ve burada bir sayaç görevini üstlenir. Registerdeki sayinin bitini su kadar kaydir diye komut verebiliriz. Özellikle aritmatiksel kaydirma komutlari register-register kullanilimi ile kaydirmak islevine sahiptirler. Burada kaydirma sayisi registeri 0-31 sayilari olmak zorunda çünkü su anda bu komutlar en fazla 32 bitlik registerleri kullanabiliyor.
Mantiksal kaydirma ve çevirme komutlari bildigimiz matematiksel bölme ve çarpma islemlerinin aynisi yaparlar. Saga dogru yapilirsa çarpma, sola dogru yapilirsa bölme isleminin aynisini yapmis olurlar.
Asagidaki örnekler ile sanirim bunlar daha iyi anlasilacak.
Mantiksal kaydirma komutlari
Örnek olarak elimizde eax registerde 00111000 seklinde bir sayimiz var. Bu sayiyi 1 bitlik kaydirma islemine tabi tutuyoruz:
mov eax,00111000 ; eax = 00111000 shl eax,1 ; eax = 01110000
shl eax,1 komutu ile eax registerdeki bitleri sola dogru (shl= sola , shr = saga) kaydirdik. Örnektede görüldügü gibi ilk bit 0 oldu ve ilk set olan bit sola dogru kaydi. Sonuçta sayinin degeri iki katina çikmis oldu. Çünkü basamak atladi.
Eger biz bu islemi 5 kere daha yaparsak bütün bitler sola dogru kayacagi ve yerlerin resetleyecegi için sonuç 0 olacaktir. Yani sayi döngü içinde mutlaka 0 degerine ulasacaktir. Buradaki 0 degeri olarak bahsettigim bitlerin tamaminin sifirlanmasi ve sayinin degerini tamamen kaybetmesi oluyor.
shl eax,1 ; 01110000 <- shl eax,1 ; 11100000 <- shl eax,1 ; 11000000 <- shl eax,1 ; 10000000 <- shl eax,1 ; 00000000 <-
Eger sayiya shr islemine (saga kaydirma) tabi tutarsak:
shr eax,1 ; 01110000 -> shr eax,1 ; 00111000 -> shr eax,1 ; 00011100 -> shr eax,1 ; 00001110 -> shr eax,1 ; 00000111 -> shr eax,1 ; 00000011 -> shr eax,1 ; 00000001 -> shr eax,1 ; 00000000 ->
Görüldügü gibi sonuç eger sayinin toplam biti kadar yapilirsa saga yada sola olmasi farketmezsizin daima 0 olacaktir.
Aritmatik kaydirmalara örnek vermek gerekirse:
mov ax,1234 ; ax = 1234 mov cl,4 ; Kaç bitlik kaydirma islemi yapacak? sar ax,cl ; saga dogru kombine 4 bit kayacak
Diger bir örnek :
mov ax,9978 mov cl,7 sal ax,cl ; sola dogru 7 bit kaydirilir.
Ayni sekilde SHR ve SHL komutlarida yardimci register olmadan yanina verilen parametre kadar kaydirilabilir.
mov ax,4523 shr ax,5
yada
mov eax,9742 shl eax,2
Ayrica 64 bitlik islemler için SHLD ve SHRD komutlarida vardir. Bunlar ayni SHL ve SHR seklinde çalisir ancak bit alanlari 64 bite kadar çikar.
Mantiksal Döndürme komutlari
Mantiksal döndürme komutlari ayni kaydirma komutlari gibi bitleri saga yada sola kaydirir yalniz bitlerin degeri kaybolmaz her kayan bitin yerine bir önceki bit gelir. Son bit ilk bir ile yer degistirir veya ilk bir son bit ile yer degistirir. Eger döndürülecek registerin degeri 0 degilse ve degerini yokedecek baska bir islem yapilmiyorsa degeri asla 0 olmaz. Çevrimi bir daire gibi düsünebiliriz. Ayni dünyanin günes etrafinda dönüsü gibi belli bir süre sonra bitler tekrar ayni yerlerine gelecektir. Yine kaydirma komutari gibi tek tek yada yardimci register vasitasiyla birden fazla kombine çevrim mümkündür.
Örnegin:
mov ax,0111000 ; eax = 1110000 rol ax,1 ; eax = 1100001
görüldügü gibi bastaki bit sola dogru çevrilir ve tasan bir ilk bitin yerine koyulur.
mov ax,0111000 ; 0111000 <- rol ax,1 ; 1100001 <- rol ax,1 ; 1000011 <- rol ax,1 ; 0000111 <-
tam terside yapilabilir.
mov ax,0111000 ; 0111000 -> ror ax,1 ; 0011100 -> ror ax,1 ; 0001110 -> ror ax,1 ; 0000111 ->
Ayrica RCR ve RCL çevirme komutlarida CL register ile kombine kullanilir. Islevleri aynidir ancak C bayragi ile birlikte kullanilir. Bu sayede döndürme islemini bayrak bazinda kontrol altina alabiliriz. Örnegin döndürülen sayinin 0 olmasi durumda.
mov ax,0111000 mov cl,5 rcl ax,cl
yada
mov ax,0111000 mov cl,5 rcr ax,cl
gibi rahatça kullanabiliriz.
Mantiksal komutlarin kombine kullanilimi
Buraya kadar anlattigim mantiksal komutlari beraber ve kombine olarak kullanabiliriz. Sayisal olarak verdigimiz CL register degeri biz bir degisiklik yapmadigimiz süre ayni kalir ve birden fazla komutta kullanabiliriz. Yine kaydirma ve çevirme komutlarini beraber kullanabiliriz. Bu sayede ortaya hem degisik hesaplamalar hemde kisa yoldan güçlü algoritmalar çikabilir.
Daha hizli oldugu ve yer kapladigi opkod sayi daha az oldugu için register temizlemelerinde veya atlama komutlarinda da karsilastirici olarak kullanabiliriz.
Örnegin bir registerin degerini 0 yapmak için XOR REG,REG dememiz yeterli. Buradaki REG olarak belirttigim sembollerin ikiside mutlaka ayni register olmak zorunda. Register kendi kendine XOR islemine tabi tuttugu için bütün bitleri reset olacaktir.Ayni sekilde bir döngü içinde sayinin yada döngünün bitip bitmedigini (0 olmasini) kontrol için OR REG,REG komutunu kullanabiliriz. Iki yöntemide asagidaki örnekte kullandim.
mov eax,12345678 xor ebx,ebx dongu: shr eax,1 inc ebx or eax,eax jnz dongu
Ayni sekilde 32 bitlik bir sayida istedigimiz 16 bitlik yada 8 bitlik bölümü resetleyebiliriz. Bunuda AND komutu ile yapiyoruz.
mov eax,12345678h ; eax = 12345678 and eax,0ffff0000h ; eax = 12340000
yada tam tersi diger 16 bitlik blok için
mov eax,12345678h ; eax = 12345678h and eax,0000ffffh ; eax = 00005678h
NOP Komutu
NOP komutu islem yok komutudur. Bu komut normalde herhangi bir islem yapmasada donanim bazinda hafizayi yenileme gibi küçük bir islevi vardir. Hiçbir register, bayrak yada adres bu komuttan etkilenmez.
CLI - STI KomutlariBu komutlar gerçek modda interruptlarin açilip kapanmasindan önemli bir role sahiptirler. EFLAG içerisinden Interrupt bayragi sisteme interruptlar ile ilgili kesmeleri ve maskelemeler bildirir. Eger bir kesmeyi ele geçireceksek (hook) ve bu islemler herhangi bir kesme yada debug olayina maruz kalmamasi gerekiyorsa(genel olarak böyledir) ilk olarak CLI komutu çalistirilmali ve gerekli kritik islem yapildiktan sonra STI ile eski haline (kesmeler açik) döndürülmeli. Normalde korumali modda dola yisiyla windows altinda bir islevi yoktur.
INC - DEC komutlari
INC ve DEC komutlari registerleri, adresleri, yada degerleri azaltmak - arttirmak içindir. Bu komutlar 8,16 ve 32 bit adreslenebilmekte ve bu bit degerlerinde azaltma- arttirma islemleri yapabilmektedir. Her iki komutta her çalismasinda sadece 1 bytelik azaltma veya arttirma yapmaktadir. Daha fazla adimlarda azaltma-arttirma yapmak için ADD ve SUB komutlarini kullanmaliyiz. Genel kullanilis sekilleri söyledir:
inc byte ptr [402300h] ; 402300h adresindeki degeri +1 arttirir dec byte ptr [sayi] ; sayi isimli hafiza bölgesini -1 düsürür. inc eax ; EAX registeri +1 arttirir dec cl ; CL registeri -1 düsürür inc dword ptr [label1] ; label1 isimli bölgeyi dword (32bit) cinsinden arttirir dec dword ptr [sonuc] ; Sonuç isimli hazifa adresini dword (32bit) cinsinden düsürür.
Burada direkt hafiza adresi adresleniyorsa ve belirtigimiz yer istedigimiz bit cinsinde degilse program derlenirken hata verir ve dosyayi olusturmaz. Eger DEBUG gibi bir programla direkt kod olarak yaziyorsak ne kadarlik deger adreslediysek o kadar bit üzerinde islem olur.
DEC ve INC komutlari olusturduklari yeni degerlere göre bayrak registeri etkilerler. Bu sayede degerleri ve islemleri kontrol altinda tutabiliriz.
Örnegin:
mov eax,1000 dongu1: dec eax jnz dongu1
Burada karsilastirma komutu kullanmadan bir DEC EAX komutunun hemen ardindan bir kontrol olusturabiliyoruz. Böylece EAX = 0 oluncaya kadar döngü devam ediyor.
Baska bir örnek:
xor ebx,ebx dongu1: inc ebx cmp ebx,1234 jnz dongu1
Burada da arttirilan EBX register degerini kontrol ediyoruz ve özel olarak bekledigimiz 1234 degerine ulasincaya kadar arttirma yapiyoruz. EBX = 1234 olunca döngü bitiyor ve program jnz dongu1 komutundan sonraya devam ediyor.
IN / OUT Komutlari
Önceki konularda kisaca bahsettigim "portlar" sistemin kaynaklarina ulasmanin en son noktasidir. Örnegin sistemimizde takili olan bir ekran karti donanim olarak bir ID (isaret) içerir. Bu isareti bulan donanim bu kartin kaynaklarini sisteme açar ve ilgili bölüme portlar tahsis eder. Böylece sistem ekran kartina bir bilgi gönderecegi zaman bu portlari kullanir. Portlar sistem ile sistem birimleri arasindaki haberlesme yollaridir. Bu yollar CPU tarafindan kullaniciya açilmistir. Bunun olmasi mecburidir çünkü isletim sistemleri ve ROM bu portlar ile haberlesmeyi saglarlar.
CPU bize 8,16 ve 32 bitlik port haberlesmelerine olanak saglamistir. Bu haberlesme hem okuma hemde yazma yönlüdür. Bütün portlarin status denilen öndegerlerin belirtildigi bir status portu vardir. Örnegin diskin bir sektörünü okumamiz gerektiginde önce hangi sürücü, sectör,track gibi bilgileri vermemiz gerekir. Sonra okuma islemi için IN komutunu kullanabiliriz.
Gerçek modda portlar okuma ve yazma için serbertçe kullanildigi halde Korumali modda bu ancak en yüksek hassasiyet (ring0) ortaminda mümkün olmaktadir. Bu ortami VXD ile veya w9x tabanli sistemlerde kisitlida olsa DLL ile olusturabiliriz. Gerçek modda sistem programlamasi mümkün hale gelmesi tamamen portlarin kosulsuz çalisabilmesinden dir. Örnegin bir DOS tabanli program bütün islemlerini portlar ve direkt adresleme ile yapabilir. Yazilari VideoRom\'a yazabilir ve sesleri portlar ile çikarabilir.
IN komutu, sistem ile haberlesmede \'al\' komutudur. Bu komut ile port okunur. Kullanilisi : IN AL,DX gibidir. Burada DX register port numarasini ve AL register ise okunan degerin yüklenecegi registeri gösterir. Fakat A ve DX register sabittir. Yani biz IN BL,CX diyemeyiz. IN/OUT komutlari için A ve DX registerler ayrilmis ve asil kullanilandirlar.
IN komutu ile 8,16 ve 32 bitlik okuma yapabiliriz. Bunun için IN AL,DX örnegindeki AL registerin degerini 16 ve 32 bitlik register degerleri olarak arttiririz. 16 bitlik okuma için INSW AX,DX ve 32 bitlik okuma için INSD EAX,DX seklinde kullaniriz. Burada dikkat ederseniz DX hiçbir zaman degismez. DX register okunacak portun adresini verir ve bu deger 16 bitten (65535) büyük olamaz. Zaten su anda kullandigimiz sistemler bunun binde birini bile kullanmiyorlar.
OUT komutu, sistem ile haberlesmede \'gönder\' komutudur. OUT komutu ile DX register ile belirttigimiz porta 8,16 veya 32 bitlik bir deger gönderebiliriz. Aynen IN komutunda oldugu gibi A ve DX registerler asil olarak kullanilir ve degismez. Yine OUT komutu port adresi olarak en büyük 16 bit bir deger kullanabilir. OUTSW 16 bit gönderme ve OUTSD 32 bitlik bir gönderme yapar.
Ayrica hem IN hemde OUT komutunu DX register olmadan port degeri vererek de islem yapmak mümkündür. Örnegin : IN AL,03f8h gibi.
BSWAP komutu
Bu komut sadece 32 bit olarak çalisir.Bu komut birkaç komutla yapilabilecek bir islevi tek basina ve hizli olarak yerine getirir. Görevi ise bir registerin bitlerini tersden yer degistirmektir. Örnegin:
mov eax,001110110b eax = 001110110b bswap eax <---eax---> eax = 011011100b
Yukarida örnekte görüldügü gibi bitler bastan sona yerdegisir. Bu komut ASCII den onaltilik yada onluk degerlere dönüsümlerde çok kullanilir. Ayrica lojik islemlerde vazgeçilmezdir.
CBW ve CBWE komutlari:
Bu komutl ar yine bswap komutu optimize için önemli bir komuttur.A register asil kullanilandir ve amaç A register üzerinde islem yapmaktir. CBW komutu 16 bitlik degeri 8 bitlik degere dönüstürür. Elimizde eger 0aa55h gibi bir deger varsa CBW komutundan sonra registerde sadece 055h degeri kalir. 0aah CBW komutu tarafindan resetlenir. Ayni sekilde CBWE komutuda registerin yüksek bitini resetleyerek elimzde 16 bitlik bir deger olmasini saglar.
Örnegin :
mov ax,0aa55h ax = 0aa55h cbw ax = 0055h
CBSW komutunu örneklemek gerekirse:
mov eax,12345678h ax = 12345678h cwde ax = 00005678h olacaktir.
CDW ve CDQ komutlari
Bu komutlarda CWD ve CBSW gibi ancak islemleri tam tersdir. Asil olarak AX ve DX registeri alirlar. CWD komutu 16 bitlik bir degeri 32 bit degerini çikarir. Ancak bu deger ayarlamasi DX registerde olur. Burada önemli bir konu ise negatif sayilar ve pozitif sayilardir. Normalde 7fffh kadar olan sayilar negatif sayili r ve DX registeri bütün bitleri reset (0) olacaktir. 8000h ile 0FFFFh arasi ise pozitif sayilar olarak kabul görür ve DX registerin bitleri set (1) olacaktir. Örnegin:
mov ax,0aa55h ax = 0aa55h, dx = 0000 cdw ax = 0aa55h, dx = 0FFFFh
CDQ komutu ise ayni CDW komutu gibi genisletme islemi yapar. Bu genisletme 32 bitten 64 bite dogru olur ve yine CDW komutu gibi sonuç EDX register üzerinde olur.
mov eax,12345678h eax = 12345678h, edx = 0 cdq eax = 12345678h, edx = 0 (negatif oldugu için, pozitif olsa 0fffffffh olacakti)
CLC, STC, CLD, STD komutlari
Bu komutlar tamamen Carry flag (bayrak) üzerinde etkilidir. CLC komutu C bayragini 0 (reset) yapar. Bu sayede atlama komutlari istenilen yere atlamayi saglayabilir. Ayni sekilde STC komutuda C bayragini 1 (set) yapar.
Bu iki komut prosedürler için anahtar olarak kullanilabilir. Örnegin :
call proc1 jc jumpproc1 .....
proc1: mov al,[data1] cmp al,0ffh je setcarry stc ret setcarry: clc ret
Burada call proc1 ile program alt dizini çagriliyor. Hatirlarsaniz bu komut ret komutu ile kendisinden sonra geri döner ve islemine devam ederdi. Proc1\' de data1 isimli adresten al register bir deger yükleniyor. Ancak deger herhangi bir deger olabilir. Eger yüklenen deger 0FF ise setcarry isimli yere atlama yapar ve C bayragini resetler. Eger degilse C bayragi set olacaktir. Durum ne olursa olsun sonlarindaki RET komutlari çagrildiklari yerden sonraya yani JC JUMPPROC1 a dresine dönecektir. Bu atlama komutuda C bayraginin durumu test edecek ve set ise atlama islemini gerçeklestirecektir.
CLD ve STD komutlari ise Direction Flag (yön bayragini) sifirlar yada 1 yapar. D bayragi string islemlerinde islem yönünü tayin eder. Daha önceden anlattigim SCAS,MOVS gibi blok islem komutlarinda SI ve DI registerlerin yönünü degistirir. Yani normalde D bayragi reset ise verdigimiz adresten sonraya (ileriye) dogru islem yapar. Ancak D bayragi set ise geriye dogru islem yapar.
CLI ve STI k omutlari
Bu komutlar I bayragi ( interrupt = kesme bayragi) üzerinde set veya reset islemi yapar. Bu komutlar kritik islemlerde interrupt çagrimlarini kapatip-açmak için kullanilir. Dolayisiyla bu iki komut gerçek modda daha fazla kullanim alani bulur. Örnegin bir TSR yapmak için interrupt degerini alip yerine kendi adresimizi koymak isteriz. Bu islem esnasinda olusabilecek en küçük kesme çagrimi sistemin kilitlenmesine ve veri kaybina neden olabilir. Bunun için önce CLI komutu ile kesme bayragi kapatilir . Isimizi bitince tekrar STI komutu ile bayragi açariz. Bu komutlar kullanilmadan TSR vektör alimi (hook) yapilamaz mi ? Yapilabilir ancak her zaman risk tasir. En güvenli yol kesme bayragini açip kapatmaktir.
cli xor ax,ax mov ds,eax mov ax,[21*4] mov bx,[[21*4+2] mov word ptr [21*4],myproc mov word ptr [21*4+2],cs sti |
| |
|
| |
|
|