Nasm Assembly ile Döngüler ve Koşullu/Koşulsuz Karşılaştırmalar

Durum
Üzgünüz bu konu cevaplar için kapatılmıştır...
Üye
Katılım
3 Nis 2023
Mesajlar
1
Tepki puanı
1
3 HİZMET YILI
X86 NASM Assembly ile Döngüler ve Karşılaştırmalar


Merhabalar. İlk konum olarak, Assembly'de döngülerden ve Koşullu ve Koşulsuz karşılaştırmaları ele alacağım. Bu iki konuyu neden tek bir çatı altında anlattığımı ilerideki dakikalarda bahsedeceğim.

1 – Conditionals (Karşılaştırmalar)
Teorik olarak karşılaştırmalardan bahsetmeyeceğim ancak ufak bir tanım yapmak gerekirse, belirtilen koşula bağlı olarak programın akışını değiştirilmesini sağlar.

Yüksek seviyeli birçok dilde karşılaştırmalar için if-else kullanılır bunu zaten biliyorsunuzdur. Assembly'de karşılaştırmalar diğer dillere göre farklıdır.

Assembly'de karşılaştırma durumu ikiye ayrılır: Conditional Jump (Koşullu Atlama) ve Unconditional Jump (Koşulsuz Atlama) olarak ikiye ayrılır. Bu konuda ikisini de detaylandırmaya çalışacağım.

Conditional Jump yani koşullu zıplamanın isminden de anlaşıldığı gibi koşulun sağlanması durumunda programın akışını değiştirmesini sağlar. Unconditional Jump yani koşulsuz zıplama ise direkt bir koşul olmadan programın akışını değiştirir. Özellikle Binary Exploitation tarafıyla ilgileniyorsanız bufferoverflow saldırılarında unconditional jump önemli bir konudur programın akışını değiştirmek açısından.


1.1 - CMP Instruction
Assembly'de karşılaştırma yapmak için cmp Instruction'u kullanıyoruz. Bu cmp Instruction’u iki işleneni karşılaştırmak için kullanılır. Program bu Instruction'u kullanırken, iki işlenenin eşit olup olmadığını anlamak için birbirinden çıkarır. ‘Çıkarmak’ derken ikisi arasında bir çıkarma işlemi yapar. Bu karşılaştırma sonucunu ZF (Zero Flag) ile anlayabiliriz. Eğer cmp sonucunda Zero Flag 0 olarak resetlenmişse karşılaştıranların eşit olmadığını gösterir ancak Zero flag 1 olarak setlenirse iki tarafın eşit olduğunu gösterir.

Burada Zero Flag’ın ne olduğunu anlamamız gerekiyor. Zero Flag, herhangi bir işlem sonucunun sıfır olması durumunda 1 değerini alır. Ancak herhangi bir işlem sonucu sıfır ile sonuçlanmazsa 0 ile resetlenir.

Konu biraz karışık olduğu için örnek kod ile detaylandıralım:

Kod:
section .data
    msg: db "Memory Hackers",0
    len: equ $ - msg

section .text
    global _start

_start:
    mov ah,5    ; ah register'a 5 yükle
    mov al,5    ; al register'a 5 yükle
    cmp ah,al   ; ah ile al register'ı karşılaştır
    jz _printMessage  ; karşılaştırma sonucu 0 ise _printMessage fonksiyonuna git

_exit:
    ; programı bitir
    mov eax,1
    xor ebx,ebx
    int 0x80

_printMessage:
    ; msg'ı ekrana bastır
    mov eax,4
    mov ebx,1
    mov ecx,msg
    mov edx,len
    int 0x80

    ;  _exit fonksiyonuna git
    jmp _exit

Bu programda ah ile al register'a 5 değerini gönderilir. Ardından yukarıda bahsettiğim cmp aracılığıyla karşılaştırma yapılır. Eğer bu karşılaştırma sonucu 0 ile sonuçlanırsa program _printMessage adlı fonksiyona gönderiliyor değil ise _exit fonksiyonuna gidip program bitirilir.

Burada karşılaştırmanın 0 olması demek, karşılaştırılan iki değerin de eşit olduğunu gösterir. Mesela ah register'a 3 ve al register'a 5 gönderip tekrar karşılaştırmaya tabii tuttuğumuzda Zero Flag set edilmez. Çünkü cmp Instruction'ın yaptığı çıkartma işlemi sonucu 0 olmayacak.

Şimdi ise karşılaştırma sonucunda Zero Flag, gerçekten set edilmiş mi gdb ile ona bakalım:

Kod:
gdb-peda$ disas _start
Dump of assembler code for function _start:
   0x0000000000401000 <+0>:    mov    ah,0x5
   0x0000000000401002 <+2>:    mov    al,0x5
   0x0000000000401004 <+4>:    cmp    ah,al
   0x0000000000401006 <+6>:    je     0x401011 <_printMessage>
End of assembler dump.

gdb ile _start içeriğine baktığımızda bu kodlar bizi karşılıyor. Şimdi ise break *0x0000000000401006 yazıp karşılaştırmanın sonucuna bakalım. Programın breakpoint koyduğum kısma dikkat edin. Program tam _printMessage adlı fonksiyona gitmeden duracak:

Kod:
gdb-peda$ disas
Dump of assembler code for function _start:
   0x0000000000401000 <+0>:    mov    ah,0x5
   0x0000000000401002 <+2>:    mov    al,0x5
   0x0000000000401004 <+4>:    cmp    ah,al
=> 0x0000000000401006 <+6>:    je     0x401011 <_printMessage>
End of assembler dump.

Programın nerede olduğunu => işareti ile anlayabiliriz. Bu işaret, çalıştırılacak kodu gösterir. Şimdi ise info registers $eflags ile hangi flag'ların set edildiğine bakalım:

Kod:
gdb-peda$ i r $eflags
eflags         0x246               [ PF ZF IF ]

eflags register'ın içerisinde gördüğünüz flag'lar, set edilen flag'lardır. Dolayasıyla programın şuan ki kısmında PF, ZF ve IF flag'ları set edilmiş olduğunu görebiliyoruz. Yani programı devam ettirdiğimizde, jz karşılaşmayı sağladığı için _printMessage adlı fonksiyona gidecek ve mesajı ekrana bastıracak.

jz veya jmp gibi şeyler kafanızı karıştırmasın şimdi ise bunları detaylandıracağım. Burada sadece anlamız gereken şey cmp'ın mantığı ve Zero Flag'ın ne işe yaradığı.



1.2 - Conditional Jump (Koşullu Atlama)
Koşullu zıplamanın zaten adıyla ne olduğunu anlamışsınızdır. Belirli koşulun sağlanması durumunda programın akışını değiştirmesini sağlar.

Koşullu işlemler için bir çok Instruction bulunmaktadır. Koşullar için kullanılan genellike arimetiksel Instruction'lardır. Bu konumda ise sadece bunlara yer vereceğim. Aritmetik koşullar için kullanılan Instruction'lar aşağıda sıralanmıştır:


Instruction
Açıklama
JE/JZ
Jump Equal (Eşit ise Atla) / Jump Zero (Sıfır ise Atla)​
JNE/JNZ
Jump not Equal (Eşit değilse Atla) / Jump not Zero (Sıfır değilse Atla)​
JG/JNLE
Jump Greater (Büyükse Atla) / Jump not Less or Equal (Küçük değilse veya eşitse Atla)​
JGE/JNL
Jump Greater Equal (Büyük Eşitse Atla) / Jump not Less (Küçük Değilse Atla)​
JL/JNGE
Jump Less (Küçükse Atla) / Jump not Greater or Equal (Büyük değilse veya eşitse Atla)​
JLE/JNG
Jump Less Equal (Küçük Eşitse Atla) / Jump not Greater (Büyük değilse Atla)​


Sadece bu kadar Instruction ile sınırlı değil. Daha fazlası için
Bağlantıları görmek için lütfen Giriş Yap
göz atabilirsiniz.

Yaygın olarak kullanılan Instruction'ları açıklamaları ile sıraladım. Fark ettiyseniz tüm sıralamalarda 2 tane Instruction yer alıyor. Bu, o iki Instruction'unda aynı amaca hizmet ettiğini gösterir. Örnek olarak, mesela siz bir programın belirli bir bölümünde Zero Flag'ın set edilebileceği bir yere JE veya JZ kullanabilirsiniz.


Bu kadar şeyden sonra yukarıdaki örnek Assembly koduna tekrar dönelim:

Kod:
_start:
    mov ah,5    ; ah register'a 5 yükle
    mov al,5    ; al register'a 5 yükle
    cmp ah,al   ; ah ile al register'ı karşılaştır
    jz _printMessage  ; karşılaştırma sonucu 0 ise _printMessage fonksiyonuna git

Bu kodda JZ Instruction'u kullandım. Siz burada JZ değil de JE'de kullansanız program aynı sonucu gösterir.


1.3 - Unconditional Jump (Koşulsuz Atlama)

Yep, şimdi ise asıl önemli konuya geldik.

Conditional için koşullu olarak programın akışını değiştirdiğini söylemiştim. Unconditional'da ise koşula bağlı olmadan direkt programın akışını değiştirir.

Unconditional için sadece jmp Instruction kullanılır. Örnek Assembly kodunu ele alayım:

Kod:
_printMessage:
    mov eax,4
    mov ebx,1
    mov ecx,msg
    mov edx,len
    int 0x80

    jmp _exit

_printMessage adlı fonksiyon içerisine baktığımızda write syscall ile bir ekrana bastırma işlemi yapılıyor ardından jmp aracılığıyla program, _exit fonksiyona gidiyor ve program sonlanıyor.

Yani kısaca jmp ile koşula bağlı olmadan programın akışını değiştirebilirsiniz.



2 – Loops (Döngüler)
Gel gelelim asıl konumuza, döngülerrr.

Bilirsiniz döngüler, programlamada dillerinde önemli bir konudur. Assembly'de ise bambaşka bir yeri var.

Eğer Assembly ile döngü oluşturmak isterseniz ya yukarıda bahsettiğim koşullu atlama yöntemi ile ya da loop Instruction'u ile yapabilirsiniz. Bu konu da ikisinden de bahsedeceğim.


2.1 - Loop Instruction
loop Instruction'u, döngüler için kullandığımız bir komuttur. İşlevli bir Instruction olsa da kendi görüşüme göre pek yaygın bir kullanımı yok. Daha çok yukarıda bahsettiğim, koşullu atlamalar ile döngüler oluşturmak daha yaygındır.

Her şeyden önce loop Instruction'un çalışma mantığını anlamak gerek. Bu Instruction, ecx (Extended Control Register) register'ına verilen değere göre komutu çalıştırır. Peki, 'neden ecx register? Farklı register'a değer veremez miyiz?' diye bir soru gelebilir, Hayır. Eğer loop instruction ile çalışacaksanız sadece ecx'e değer vererek döngü sayısını belirleyebilirsiniz. ecx'in işlemcide döngünün sayacını tutmak gibi görevleri vardır.

Aynı zamanda loop instruction, her çalıştığında ecx'den bir değer azaltır. Mesela siz bir mesajı 10 defa ekrana bastırmak istiyorsunuz ve ecx'e 10 değerini verdiniz. loop komutu her çalıştığında ecx'i 1 azaltır. Kafanız karışmasın örnek ile detaylandıracağım.

Şimdi ise basit bir örnek yapalım. Örneğimiz, "Memory Hackers" mesajını 10 kere bastırmak olsun:

Kod:
BITS 32

section .data
    msg: db "Memory Hackers", 0
    len: equ $ - msg

section .text
    global _start

_start:
    mov ecx,10 ; döngü sayısı 10 olarak belirtildi
    jmp _loop   ; programı _loop fonksiyona yönelt

_exit:
    ; programı bitir
    mov eax,1
    xor ebx,ebx
    int 0x80

_loop:
    push ecx ; ecx'in değerini stack' gönder
    ; ecx'in değerini stack'e gönderme sebebimiz, kodun devamında ekrana bastırma işlemi için ecx'i kullanacağız dolayasıyla bu değeri kaybetmemek için stack'e gönderiyoruz.
    
    ; mesajı ekrana bastır
    mov eax,4
    mov ebx,1
    mov ecx,msg
    mov edx,len
    int 0x80

    pop ecx ; stack'e gönderilen değeri al
    loop _loop  ; _başa dön

    cmp ecx,0 ; ecx'in değeri 0 ile karşılaştırılıyor
    jmp _exit   ; eğer ecx'in değeri 0 olmuşsa jmp ile programı _exit fonksiyona yönelt

Bu program, 10 kez 'Memory Hackers' mesajını ekrana bastırır.

Programda başta ecx'e 10 değeri gönderilir. Buradaki 10, döngünün kaç defa çalışacağını temsil eder. Siz buraya 10 değil de mesela 3 girseniz 3 defa çalışacaktır. Ardından jmp aracılığıyla program, _loop fonksiyonuna yönlendiriliyor. Bu fonksiyon içerisinde ise mesaj bastırılmadan hemen önce ecx'in değeri stack'e gönderiliyor. Bunun sebebi, ilerideki kodlarda write syscall ile ekrana mesaj bastırma işlemi gerçekleştirelecek. Eğer ecx'in değeri stack'e gönderilmeden direkt mesajı ekrana bastırırsak, döngü sayısını kaybedebiliriz.

Mesaj ekrana bastırıldıktan sonra pop aracılığıyla stack'e gönderilen değer geri alınıyor ve loop instruction ile bu işlemler tekrar ediyor. Taaa ki, ecx register içerisinde değer 0 olana kadar. Hatırlayın, loop instruction'u ecx'a bağlı çalışır ve her çalıştığında ecx'den 1 değer azaltır.

Özellikle bu kodda, conditionals ve unconditionals konuların daha anlaşılır olması için jmp ve cmp komutlarını da dahil ettim.

Arka plana bakmak için gdb kullanalım:

Kod:
gdb-peda$ disas _start
Dump of assembler code for function _start:
   0x0000000000401000 <+0>:    mov    ecx,0xa
   0x0000000000401005 <+5>:    jmp    0x401010 <_loop>
End of assembler dump.

_start fonksiyonu disassemble ettiğimiz zaman bu kodları görüyoruz. Yukarıda bahsettiğim gibi, ecx'e hexdecimal olarak 10 gönderiliyor ve program jmp ile _loop'a yönlendiriliyor. Şimdi ise _loop'u disassemble edelim:

Kod:
gdb-peda$ disas _loop
Dump of assembler code for function _loop:
   0x0000000000401010 <+0>:     push   rcx
   0x0000000000401011 <+1>:     mov    eax,0x4
   0x0000000000401016 <+6>:     mov    ebx,0x1
   0x000000000040101b <+11>:    mov    ecx,0x402000
   0x0000000000401020 <+16>:    mov    edx,0xf
   0x0000000000401025 <+21>:    int    0x80
   0x0000000000401027 <+23>:    pop    rcx
   0x0000000000401028 <+24>:    loop   0x401010 <_loop>
   0x000000000040102a <+26>:    cmp    ecx,0x0
   0x000000000040102d <+29>:    jmp    0x401007 <_exit>
End of assembler dump.

_loop içerisine başta baktığımızda başta rcx değeri - program arka planda rcx kullanmış. Burada ecx'in değeri bulunmaktadır - stack'e gönderildiği ardından ekrana bastırma işlemi yapıldığı görülmektedir. Daha sonra pop ile stack'e gönderilen değer geri alınıyor ve loop komutu çalıştırılıyor.

loop instruction'un her çalıştığında ecx'den bir değer azaltığını söylemiştim. Şimdi ise canlı canlı bir de buradan bakalım. Başta break *0x0000000000401028 ile loop komutunun olduğu yerde programı durduralım ve ardından çalıştıralım:

Kod:
gdb-peda$ disas
Dump of assembler code for function _loop:
   0x0000000000401010 <+0>:   push   rcx
   0x0000000000401011 <+1>:   mov    eax,0x4
   0x0000000000401016 <+6>:   mov    ebx,0x1
   0x000000000040101b <+11>:  mov    ecx,0x402000
   0x0000000000401020 <+16>:  mov    edx,0xf
   0x0000000000401025 <+21>:  int    0x80
   0x0000000000401027 <+23>:  pop    rcx
=> 0x0000000000401028 <+24>:  loop   0x401010 <_loop>
   0x000000000040102a <+26>:  cmp    ecx,0x0
   0x000000000040102d <+29>:  jmp    0x401007 <_exit>
End of assembler dump.
Program, tam loop komutu çalıştırılmadan hemen durdu. Tam burada info registers $ecx aracılığıyla ecx'in durumuna bir bakalım:

Kod:
gdb-peda$ info registers $ecx
ecx            0xa                 0xa

0xa'nın decimal karşılığı 10'dur. Dolayasıyla şuan ecx'in içerisinde 10 değeri var. Şimdi programı ni aracılığıyla devam ettirelim ve loop komutu çalıştırıldıktan sonra tekrar bakalım:

Kod:
gdb-peda$ disas
Dump of assembler code for function _loop:
=> 0x0000000000401010 <+0>:    push   rcx
   0x0000000000401011 <+1>:    mov    eax,0x4
   0x0000000000401016 <+6>:    mov    ebx,0x1
   0x000000000040101b <+11>:   mov    ecx,0x402000
   0x0000000000401020 <+16>:   mov    edx,0xf
   0x0000000000401025 <+21>:   int    0x80
   0x0000000000401027 <+23>:   pop    rcx
   0x0000000000401028 <+24>:   loop   0x401010 <_loop>
   0x000000000040102a <+26>:   cmp    ecx,0x0
   0x000000000040102d <+29>:   jmp    0x401007 <_exit>
End of assembler dump.

Göründüğü gibi, _loop fonksiyonun başına tekrar dönüldü. Aynı şekilde tekrar info registers $ecx ile ecx'in durumuna tekrar bakalım:


Kod:
gdb-peda$ info registers $ecx
ecx            0x9                 0x9

Programın şuan ki kısmında ise ecx'in içerisinde 9 değeri var. Yani ecx'in 1 değer azaltıldığını görebiliyoruz. Bu program böyle devam edecek ve en sonunda 0 olduğunda program bitecek.

Genel olarak loop instruction'un çalışma mantığı bu şekilde. Şimdi ise diğer konuya geçelim.



2.1 - Loops with Conditionals

Şimdi ise en çok tercih ettiğimiz yönteme geldik.

Koşullarla döngü oluşturmak sıklıkla tercih edilen bir yöntemdir.

Konuyu aydınlatmak için basit bir örnek yapalım. Yukarıdaki uygulamanın tersini yapalım. Bu sefer ecx'i 0 değerinden başlatalım ve 10 olana kadar 'Memory Hackers' mesajını ekrana bastırsın:

Kod:
section .data
        msg: db "Memory Hackers", 0
        len: equ $ - msg

section .text
        global _start

_start:
        mov ecx,1
        jmp _loop

_exit:
        mov eax,1
        xor ebx,ebx
        int 0x80

_loop:
        cmp ecx, 10 ; ecx'in değeri 10 ile karşılaştırılıyor
        jz _exit  ; eğer ecx'in değeri 10 ile eşitse, program _exit fonksiyonuna yönlendirilerek program bitiriliyor
        
        ; bu kısımda msg ekrana bastırılır
        mov eax,4  
        mov ebx,1
        mov ecx,msg
        mov edx,len
         int 0x80
        jmp _loop ; _loop'un başına dön

bu program, ecx'in değeri 10 olana kadar 'Memory Hackers' mesajını ekrana bastırır.

Aslında bu program, loop instruction konusunda örnek olarak verdiğim assembly kodunun tam tersi. Loop instruction'u verilen değeri azaltırken burada arttırma yapılarak koşullar ile programı yönetiyoruz.


Umarım bu konular, sizin için güzel bir kaynak olur. Hepinize iyi çalışmalar dilerim!


Post automatically merged:

Bu arada konunun bir çok yerinde Conditions yazmak yerine Conditionals olarak yazmışım. Hatadan dolayı kusura bakmayın. İngilizce zayıf olunca böyle oluyor işte..
 
Admin
Katılım
9 Eki 2017
Mesajlar
13,542
Çözümler
1,051
Tepki puanı
3,384
Ödüller
22
8 HİZMET YILI
Birkaç anlamadığım yer var ama daha iyi okursan anlayacağım bu tarz içerikleri seviyorum gerçekten teşekkür ederim kendi adıma
 
Onaylı Üye
Katılım
22 Haz 2022
Mesajlar
53
Tepki puanı
2
Ödüller
1
Yaş
22
3 HİZMET YILI
bi ara denemeyi düşünüyorum biraz uzun üşendim açıkçası ama teşekkür ederim
 
neither false nor fake
Emektar Üye
Katılım
21 Nis 2020
Mesajlar
2,807
Çözümler
595
Tepki puanı
825
Ödüller
9
Sosyal
6 HİZMET YILI
ugrasilmis yararli tesekkurler
 
Onaylı Üye
Katılım
29 Mar 2022
Mesajlar
50
Tepki puanı
4
Ödüller
3
Yaş
26
4 HİZMET YILI
X86 NASM Assembly ile Döngüler ve Karşılaştırmalar


Merhabalar. İlk konum olarak, Assembly'de döngülerden ve Koşullu ve Koşulsuz karşılaştırmaları ele alacağım. Bu iki konuyu neden tek bir çatı altında anlattığımı ilerideki dakikalarda bahsedeceğim.

1 – Conditionals (Karşılaştırmalar)
Teorik olarak karşılaştırmalardan bahsetmeyeceğim ancak ufak bir tanım yapmak gerekirse, belirtilen koşula bağlı olarak programın akışını değiştirilmesini sağlar.

Yüksek seviyeli birçok dilde karşılaştırmalar için if-else kullanılır bunu zaten biliyorsunuzdur. Assembly'de karşılaştırmalar diğer dillere göre farklıdır.

Assembly'de karşılaştırma durumu ikiye ayrılır: Conditional Jump (Koşullu Atlama) ve Unconditional Jump (Koşulsuz Atlama) olarak ikiye ayrılır. Bu konuda ikisini de detaylandırmaya çalışacağım.

Conditional Jump yani koşullu zıplamanın isminden de anlaşıldığı gibi koşulun sağlanması durumunda programın akışını değiştirmesini sağlar. Unconditional Jump yani koşulsuz zıplama ise direkt bir koşul olmadan programın akışını değiştirir. Özellikle Binary Exploitation tarafıyla ilgileniyorsanız bufferoverflow saldırılarında unconditional jump önemli bir konudur programın akışını değiştirmek açısından.


1.1 - CMP Instruction
Assembly'de karşılaştırma yapmak için cmp Instruction'u kullanıyoruz. Bu cmp Instruction’u iki işleneni karşılaştırmak için kullanılır. Program bu Instruction'u kullanırken, iki işlenenin eşit olup olmadığını anlamak için birbirinden çıkarır. ‘Çıkarmak’ derken ikisi arasında bir çıkarma işlemi yapar. Bu karşılaştırma sonucunu ZF (Zero Flag) ile anlayabiliriz. Eğer cmp sonucunda Zero Flag 0 olarak resetlenmişse karşılaştıranların eşit olmadığını gösterir ancak Zero flag 1 olarak setlenirse iki tarafın eşit olduğunu gösterir.

Burada Zero Flag’ın ne olduğunu anlamamız gerekiyor. Zero Flag, herhangi bir işlem sonucunun sıfır olması durumunda 1 değerini alır. Ancak herhangi bir işlem sonucu sıfır ile sonuçlanmazsa 0 ile resetlenir.

Konu biraz karışık olduğu için örnek kod ile detaylandıralım:

Kod:
section .data
    msg: db "Memory Hackers",0
    len: equ $ - msg

section .text
    global _start

_start:
    mov ah,5    ; ah register'a 5 yükle
    mov al,5    ; al register'a 5 yükle
    cmp ah,al   ; ah ile al register'ı karşılaştır
    jz _printMessage  ; karşılaştırma sonucu 0 ise _printMessage fonksiyonuna git

_exit:
    ; programı bitir
    mov eax,1
    xor ebx,ebx
    int 0x80

_printMessage:
    ; msg'ı ekrana bastır
    mov eax,4
    mov ebx,1
    mov ecx,msg
    mov edx,len
    int 0x80

    ;  _exit fonksiyonuna git
    jmp _exit

Bu programda ah ile al register'a 5 değerini gönderilir. Ardından yukarıda bahsettiğim cmp aracılığıyla karşılaştırma yapılır. Eğer bu karşılaştırma sonucu 0 ile sonuçlanırsa program _printMessage adlı fonksiyona gönderiliyor değil ise _exit fonksiyonuna gidip program bitirilir.

Burada karşılaştırmanın 0 olması demek, karşılaştırılan iki değerin de eşit olduğunu gösterir. Mesela ah register'a 3 ve al register'a 5 gönderip tekrar karşılaştırmaya tabii tuttuğumuzda Zero Flag set edilmez. Çünkü cmp Instruction'ın yaptığı çıkartma işlemi sonucu 0 olmayacak.

Şimdi ise karşılaştırma sonucunda Zero Flag, gerçekten set edilmiş mi gdb ile ona bakalım:

Kod:
gdb-peda$ disas _start
Dump of assembler code for function _start:
   0x0000000000401000 <+0>:    mov    ah,0x5
   0x0000000000401002 <+2>:    mov    al,0x5
   0x0000000000401004 <+4>:    cmp    ah,al
   0x0000000000401006 <+6>:    je     0x401011 <_printMessage>
End of assembler dump.

gdb ile _start içeriğine baktığımızda bu kodlar bizi karşılıyor. Şimdi ise break *0x0000000000401006 yazıp karşılaştırmanın sonucuna bakalım. Programın breakpoint koyduğum kısma dikkat edin. Program tam _printMessage adlı fonksiyona gitmeden duracak:

Kod:
gdb-peda$ disas
Dump of assembler code for function _start:
   0x0000000000401000 <+0>:    mov    ah,0x5
   0x0000000000401002 <+2>:    mov    al,0x5
   0x0000000000401004 <+4>:    cmp    ah,al
=> 0x0000000000401006 <+6>:    je     0x401011 <_printMessage>
End of assembler dump.

Programın nerede olduğunu => işareti ile anlayabiliriz. Bu işaret, çalıştırılacak kodu gösterir. Şimdi ise info registers $eflags ile hangi flag'ların set edildiğine bakalım:

Kod:
gdb-peda$ i r $eflags
eflags         0x246               [ PF ZF IF ]

eflags register'ın içerisinde gördüğünüz flag'lar, set edilen flag'lardır. Dolayasıyla programın şuan ki kısmında PF, ZF ve IF flag'ları set edilmiş olduğunu görebiliyoruz. Yani programı devam ettirdiğimizde, jz karşılaşmayı sağladığı için _printMessage adlı fonksiyona gidecek ve mesajı ekrana bastıracak.

jz veya jmp gibi şeyler kafanızı karıştırmasın şimdi ise bunları detaylandıracağım. Burada sadece anlamız gereken şey cmp'ın mantığı ve Zero Flag'ın ne işe yaradığı.



1.2 - Conditional Jump (Koşullu Atlama)
Koşullu zıplamanın zaten adıyla ne olduğunu anlamışsınızdır. Belirli koşulun sağlanması durumunda programın akışını değiştirmesini sağlar.

Koşullu işlemler için bir çok Instruction bulunmaktadır. Koşullar için kullanılan genellike arimetiksel Instruction'lardır. Bu konumda ise sadece bunlara yer vereceğim. Aritmetik koşullar için kullanılan Instruction'lar aşağıda sıralanmıştır:


Instruction
Açıklama
JE/JZ
Jump Equal (Eşit ise Atla) / Jump Zero (Sıfır ise Atla)​
JNE/JNZ
Jump not Equal (Eşit değilse Atla) / Jump not Zero (Sıfır değilse Atla)​
JG/JNLE
Jump Greater (Büyükse Atla) / Jump not Less or Equal (Küçük değilse veya eşitse Atla)​
JGE/JNL
Jump Greater Equal (Büyük Eşitse Atla) / Jump not Less (Küçük Değilse Atla)​
JL/JNGE
Jump Less (Küçükse Atla) / Jump not Greater or Equal (Büyük değilse veya eşitse Atla)​
JLE/JNG
Jump Less Equal (Küçük Eşitse Atla) / Jump not Greater (Büyük değilse Atla)​


Sadece bu kadar Instruction ile sınırlı değil. Daha fazlası için
Bağlantıları görmek için lütfen Giriş Yap
göz atabilirsiniz.

Yaygın olarak kullanılan Instruction'ları açıklamaları ile sıraladım. Fark ettiyseniz tüm sıralamalarda 2 tane Instruction yer alıyor. Bu, o iki Instruction'unda aynı amaca hizmet ettiğini gösterir. Örnek olarak, mesela siz bir programın belirli bir bölümünde Zero Flag'ın set edilebileceği bir yere JE veya JZ kullanabilirsiniz.


Bu kadar şeyden sonra yukarıdaki örnek Assembly koduna tekrar dönelim:

Kod:
_start:
    mov ah,5    ; ah register'a 5 yükle
    mov al,5    ; al register'a 5 yükle
    cmp ah,al   ; ah ile al register'ı karşılaştır
    jz _printMessage  ; karşılaştırma sonucu 0 ise _printMessage fonksiyonuna git

Bu kodda JZ Instruction'u kullandım. Siz burada JZ değil de JE'de kullansanız program aynı sonucu gösterir.


1.3 - Unconditional Jump (Koşulsuz Atlama)

Yep, şimdi ise asıl önemli konuya geldik.

Conditional için koşullu olarak programın akışını değiştirdiğini söylemiştim. Unconditional'da ise koşula bağlı olmadan direkt programın akışını değiştirir.

Unconditional için sadece jmp Instruction kullanılır. Örnek Assembly kodunu ele alayım:

Kod:
_printMessage:
    mov eax,4
    mov ebx,1
    mov ecx,msg
    mov edx,len
    int 0x80

    jmp _exit

_printMessage adlı fonksiyon içerisine baktığımızda write syscall ile bir ekrana bastırma işlemi yapılıyor ardından jmp aracılığıyla program, _exit fonksiyona gidiyor ve program sonlanıyor.

Yani kısaca jmp ile koşula bağlı olmadan programın akışını değiştirebilirsiniz.




2 – Loops (Döngüler)
Gel gelelim asıl konumuza, döngülerrr.

Bilirsiniz döngüler, programlamada dillerinde önemli bir konudur. Assembly'de ise bambaşka bir yeri var.

Eğer Assembly ile döngü oluşturmak isterseniz ya yukarıda bahsettiğim koşullu atlama yöntemi ile ya da loop Instruction'u ile yapabilirsiniz. Bu konu da ikisinden de bahsedeceğim.


2.1 - Loop Instruction
loop Instruction'u, döngüler için kullandığımız bir komuttur. İşlevli bir Instruction olsa da kendi görüşüme göre pek yaygın bir kullanımı yok. Daha çok yukarıda bahsettiğim, koşullu atlamalar ile döngüler oluşturmak daha yaygındır.

Her şeyden önce loop Instruction'un çalışma mantığını anlamak gerek. Bu Instruction, ecx (Extended Control Register) register'ına verilen değere göre komutu çalıştırır. Peki, 'neden ecx register? Farklı register'a değer veremez miyiz?' diye bir soru gelebilir, Hayır. Eğer loop instruction ile çalışacaksanız sadece ecx'e değer vererek döngü sayısını belirleyebilirsiniz. ecx'in işlemcide döngünün sayacını tutmak gibi görevleri vardır.

Aynı zamanda loop instruction, her çalıştığında ecx'den bir değer azaltır. Mesela siz bir mesajı 10 defa ekrana bastırmak istiyorsunuz ve ecx'e 10 değerini verdiniz. loop komutu her çalıştığında ecx'i 1 azaltır. Kafanız karışmasın örnek ile detaylandıracağım.

Şimdi ise basit bir örnek yapalım. Örneğimiz, "Memory Hackers" mesajını 10 kere bastırmak olsun:

Kod:
BITS 32

section .data
    msg: db "Memory Hackers", 0
    len: equ $ - msg

section .text
    global _start

_start:
    mov ecx,10 ; döngü sayısı 10 olarak belirtildi
    jmp _loop   ; programı _loop fonksiyona yönelt

_exit:
    ; programı bitir
    mov eax,1
    xor ebx,ebx
    int 0x80

_loop:
    push ecx ; ecx'in değerini stack' gönder
    ; ecx'in değerini stack'e gönderme sebebimiz, kodun devamında ekrana bastırma işlemi için ecx'i kullanacağız dolayasıyla bu değeri kaybetmemek için stack'e gönderiyoruz.
   
    ; mesajı ekrana bastır
    mov eax,4
    mov ebx,1
    mov ecx,msg
    mov edx,len
    int 0x80

    pop ecx ; stack'e gönderilen değeri al
    loop _loop  ; _başa dön

    cmp ecx,0 ; ecx'in değeri 0 ile karşılaştırılıyor
    jmp _exit   ; eğer ecx'in değeri 0 olmuşsa jmp ile programı _exit fonksiyona yönelt

Bu program, 10 kez 'Memory Hackers' mesajını ekrana bastırır.

Programda başta ecx'e 10 değeri gönderilir. Buradaki 10, döngünün kaç defa çalışacağını temsil eder. Siz buraya 10 değil de mesela 3 girseniz 3 defa çalışacaktır. Ardından jmp aracılığıyla program, _loop fonksiyonuna yönlendiriliyor. Bu fonksiyon içerisinde ise mesaj bastırılmadan hemen önce ecx'in değeri stack'e gönderiliyor. Bunun sebebi, ilerideki kodlarda write syscall ile ekrana mesaj bastırma işlemi gerçekleştirelecek. Eğer ecx'in değeri stack'e gönderilmeden direkt mesajı ekrana bastırırsak, döngü sayısını kaybedebiliriz.


Mesaj ekrana bastırıldıktan sonra pop aracılığıyla stack'e gönderilen değer geri alınıyor ve loop instruction ile bu işlemler tekrar ediyor. Taaa ki, ecx register içerisinde değer 0 olana kadar. Hatırlayın, loop instruction'u ecx'a bağlı çalışır ve her çalıştığında ecx'den 1 değer azaltır.

Özellikle bu kodda, conditionals ve unconditionals konuların daha anlaşılır olması için jmp ve cmp komutlarını da dahil ettim.

Arka plana bakmak için gdb kullanalım:

Kod:
gdb-peda$ disas _start
Dump of assembler code for function _start:
   0x0000000000401000 <+0>:    mov    ecx,0xa
   0x0000000000401005 <+5>:    jmp    0x401010 <_loop>
End of assembler dump.

_start fonksiyonu disassemble ettiğimiz zaman bu kodları görüyoruz. Yukarıda bahsettiğim gibi, ecx'e hexdecimal olarak 10 gönderiliyor ve program jmp ile _loop'a yönlendiriliyor. Şimdi ise _loop'u disassemble edelim:

Kod:
gdb-peda$ disas _loop
Dump of assembler code for function _loop:
   0x0000000000401010 <+0>:     push   rcx
   0x0000000000401011 <+1>:     mov    eax,0x4
   0x0000000000401016 <+6>:     mov    ebx,0x1
   0x000000000040101b <+11>:    mov    ecx,0x402000
   0x0000000000401020 <+16>:    mov    edx,0xf
   0x0000000000401025 <+21>:    int    0x80
   0x0000000000401027 <+23>:    pop    rcx
   0x0000000000401028 <+24>:    loop   0x401010 <_loop>
   0x000000000040102a <+26>:    cmp    ecx,0x0
   0x000000000040102d <+29>:    jmp    0x401007 <_exit>
End of assembler dump.

_loop içerisine başta baktığımızda başta rcx değeri - program arka planda rcx kullanmış. Burada ecx'in değeri bulunmaktadır - stack'e gönderildiği ardından ekrana bastırma işlemi yapıldığı görülmektedir. Daha sonra pop ile stack'e gönderilen değer geri alınıyor ve loop komutu çalıştırılıyor.

loop instruction'un her çalıştığında ecx'den bir değer azaltığını söylemiştim. Şimdi ise canlı canlı bir de buradan bakalım. Başta break *0x0000000000401028 ile loop komutunun olduğu yerde programı durduralım ve ardından çalıştıralım:

Kod:
gdb-peda$ disas
Dump of assembler code for function _loop:
   0x0000000000401010 <+0>:   push   rcx
   0x0000000000401011 <+1>:   mov    eax,0x4
   0x0000000000401016 <+6>:   mov    ebx,0x1
   0x000000000040101b <+11>:  mov    ecx,0x402000
   0x0000000000401020 <+16>:  mov    edx,0xf
   0x0000000000401025 <+21>:  int    0x80
   0x0000000000401027 <+23>:  pop    rcx
=> 0x0000000000401028 <+24>:  loop   0x401010 <_loop>
   0x000000000040102a <+26>:  cmp    ecx,0x0
   0x000000000040102d <+29>:  jmp    0x401007 <_exit>
End of assembler dump.
Program, tam loop komutu çalıştırılmadan hemen durdu. Tam burada info registers $ecx aracılığıyla ecx'in durumuna bir bakalım:

Kod:
gdb-peda$ info registers $ecx
ecx            0xa                 0xa

0xa'nın decimal karşılığı 10'dur. Dolayasıyla şuan ecx'in içerisinde 10 değeri var. Şimdi programı ni aracılığıyla devam ettirelim ve loop komutu çalıştırıldıktan sonra tekrar bakalım:

Kod:
gdb-peda$ disas
Dump of assembler code for function _loop:
=> 0x0000000000401010 <+0>:    push   rcx
   0x0000000000401011 <+1>:    mov    eax,0x4
   0x0000000000401016 <+6>:    mov    ebx,0x1
   0x000000000040101b <+11>:   mov    ecx,0x402000
   0x0000000000401020 <+16>:   mov    edx,0xf
   0x0000000000401025 <+21>:   int    0x80
   0x0000000000401027 <+23>:   pop    rcx
   0x0000000000401028 <+24>:   loop   0x401010 <_loop>
   0x000000000040102a <+26>:   cmp    ecx,0x0
   0x000000000040102d <+29>:   jmp    0x401007 <_exit>
End of assembler dump.

Göründüğü gibi, _loop fonksiyonun başına tekrar dönüldü. Aynı şekilde tekrar info registers $ecx ile ecx'in durumuna tekrar bakalım:

Kod:
gdb-peda$ info registers $ecx
ecx            0x9                 0x9

Programın şuan ki kısmında ise ecx'in içerisinde 9 değeri var. Yani ecx'in 1 değer azaltıldığını görebiliyoruz. Bu program böyle devam edecek ve en sonunda 0 olduğunda program bitecek.

Genel olarak loop instruction'un çalışma mantığı bu şekilde. Şimdi ise diğer konuya geçelim.



2.1 - Loops with Conditionals


Şimdi ise en çok tercih ettiğimiz yönteme geldik.

Koşullarla döngü oluşturmak sıklıkla tercih edilen bir yöntemdir.

Konuyu aydınlatmak için basit bir örnek yapalım. Yukarıdaki uygulamanın tersini yapalım. Bu sefer ecx'i 0 değerinden başlatalım ve 10 olana kadar 'Memory Hackers' mesajını ekrana bastırsın:

Kod:
section .data
        msg: db "Memory Hackers", 0
        len: equ $ - msg

section .text
        global _start

_start:
        mov ecx,1
        jmp _loop

_exit:
        mov eax,1
        xor ebx,ebx
        int 0x80

_loop:
        cmp ecx, 10 ; ecx'in değeri 10 ile karşılaştırılıyor
        jz _exit  ; eğer ecx'in değeri 10 ile eşitse, program _exit fonksiyonuna yönlendirilerek program bitiriliyor
        
        ; bu kısımda msg ekrana bastırılır
        mov eax,4  
        mov ebx,1
        mov ecx,msg
        mov edx,len
         int 0x80
        jmp _loop ; _loop'un başına dön

bu program, ecx'in değeri 10 olana kadar 'Memory Hackers' mesajını ekrana bastırır.

Aslında bu program, loop instruction konusunda örnek olarak verdiğim assembly kodunun tam tersi. Loop instruction'u verilen değeri azaltırken burada arttırma yapılarak koşullar ile programı yönetiyoruz.


Umarım bu konular, sizin için güzel bir kaynak olur. Hepinize iyi çalışmalar dilerim!


Post automatically merged:

Bu arada konunun bir çok yerinde Conditions yazmak yerine Conditionals olarak yazmışım. Hatadan dolayı kusura bakmayın. İngilizce zayıf olunca böyle oluyor işte..
kk bana bu olayları anlatcak varmı
 
Onaylı Üye
Katılım
10 Nis 2016
Mesajlar
51
Tepki puanı
3
Ödüller
7
10 HİZMET YILI
aşırı detaylı olmuş böyle konular görmeye hasrett kaldık
 
Onaylı Üye
Katılım
26 Haz 2023
Mesajlar
72
Tepki puanı
13
Yaş
24
Sosyal
2 HİZMET YILI
Cidden güzel olmuş favorilerime ekliyorum
 
Onaylı Üye
Katılım
24 Ağu 2022
Mesajlar
51
Tepki puanı
3
Ödüller
1
Yaş
23
3 HİZMET YILI
buney anlamadım (azeriyim)
 
Onaylı Üye
Katılım
6 Şub 2021
Mesajlar
52
Tepki puanı
3
Ödüller
3
Yaş
28
5 HİZMET YILI
Cidden güzel olmuş favorilerime ekliyorum
 
Üye
Katılım
30 Kas 2023
Mesajlar
5
Tepki puanı
0
Yaş
26
2 HİZMET YILI
MemoryHackers.org 2015 yılında kurulmuş memory hacking topluluğudur. Bünyesinde Dword Team ve birçok profesyonel coder bulundurmaktadır. Amaçları pay2win olan oyunlardaki parayı öde , birinci ol ayrımcılığını kaldırmak için yazılımlar üretip / paylaşmaktır. Paylaşılan yazılımların memoryhackers.org ile bir alakası olmayıp, memoryhackers.org yasalara göre sadece "yer sağlayıcı" olarak hizmet etmektedir. 5651 kanunda belirtildiği gibi "Yer sağlayıcı, yer sağladığı içeriği kontrol etmek veya hukuka aykırı bir faaliyetin söz konusu olup olmadığını araştırmakla yükümlü değildir." Ayriyetten aynı maddenin devamında "“yer sağlayıcının, yer sağladığı hukuka aykırı içeriğin kanunen belirli suçları içermesi halinde yer sağlayıcının haberdar edilmesi hâlinde bu içeriği yayından çıkarmakla yükümlüdür.” sözleri yer almaktadır. Eğer ürününüzün / programınızın sitemiz aracılığıyla kötüye kullanıldığını düşünüyorsanız lütfen "İletişim" sekmesinden şirketinizin resmi elektronik adresinden veyahut avukatınız aracılığı ile gerekli müracaatı yapınız. Yapmış olduğunuz istekler yoğunluğa göre 3 iş günü içerisinde incelenip haklı bulunmanız neticesinde hak sahibinin belirttiği kötüye kullanım olan konu 7 iş günü içerisinde sitemizden kaldırılır. Sitede bir çok oyun
 
Seçkin Üye
Katılım
3 Ara 2023
Mesajlar
527
Tepki puanı
29
Ödüller
2
Sosyal
2 HİZMET YILI
bilgilendirmeler için saolun
 
Durum
Üzgünüz bu konu cevaplar için kapatılmıştır...
Üst