SlideShare a Scribd company logo
1 of 177
X86 TERSİNE
MÜHENDİSLİK
EĞİTİMİ
BÖLÜM-1
İSTANBUL
blog.btrisk.com @btrisk /btrisktv /btrisk
BTRİSK HAKKINDA
TANIŞMA
Pentest & BT Denetimi
ISO27001 Danışmanlık
Hizmetleri
BG Operasyon
Hizmetleri
Göreviniz, Deneyiminiz ve Eğitimden Beklentileriniz
Nelerdir?
TANIŞMA
GİRİŞ
TERSİNE MÜHENDİSLİK NEDİR?
GENEL ANLAMIYLA TERSİNE MÜHENDİSLİK;
• Üretilmiş bir sistemin nasıl çalıştığının analiz edilmesidir. Bunun
için sistemin bütünlüğünü kaybetmeyecek en küçük birimlerine
ayrıştırılması ve bu birimler arasındaki etkileşimlerin anlaşılması
gerekir.
MAKİNA DİLİNE DERLENMİŞ YAZILIMLAR İÇİN TERSİNE
MÜHENDİSLİK;
• Assembly dili içindeki üst seviye (high level) algoritmaların ve veri
yapılarının keşfidir.
"ALGORİTMALAR + VERİ YAPILARI = PROGRAMLAR"
Niklaus Wirth (Pascal v.d. uygulama dillerinin tasarımcısı)
TERSİNE MÜHENDİSLİK NEDİR?
DERLEME LİNKLEME
TERSİNE MÜHENDİSLİK
NEDEN İHTİYACIMIZ OLABİLİR?
Tersine analize neden ihtiyaç olabilir dendiğinde genellikle yasa dışı
hedefler akla gelir. Ancak bu yönteme yasal nedenlerle de ihtiyaç
duyabiliriz:
• Bir zararlı yazılımın amaçlarının anlaşılması, bulaştığı diğer
sistemlerin tespiti için işaretlerin [Indicators of Compromise –
IoC] belirlenmesi
• Uygulama güvenlik testleri sırasında;
• Uygulamanın içinde gömülü hassas verilerin incelenmesi
• Kullanılmayan ancak kritik olabilecek fonksiyonların tespit
edilmesi
• Hata alan veya çalışmayan bir uygulama ile ilgili problemin
tespit edilmesi
EĞİTİMİN KAPSAMI
Tersine mühendisliğin 2 temel aracı;
• Dinamik Analiz ve
• Statik Analiz'dir.
Ancak eğitimimizin odaklandığı analiz yöntemi STATİK ANALİZ
yöntemi olacaktır.
Bu dinamik analiz yöntemini hiç kullanmayacağız anlamına
gelmiyor. Ancak kullanacağımız uygulamanın hataya yer
vermeyecek doğası, deneme yanılma yöntemini dolayısıyla da
dinamik analizi daha az kullanışlı kılacak.
Eğitimin ana hedefi X86 Mimarisi ve Assembly Dili üzerinde
yetkinlik kazanmak olacaktır.
ALGORİTMALAR
Assembly koduna baktığımızda tanımaya alışmamız gereken
algoritmalara örnekler:
• Atama [Assignment] "="
• Aritmetik Operatörler [Arithmetic Operators] "+,-,*,/,|,& v.d."
• Koşullar [Conditionals]
o if, else
o switch .. case
• Döngüler [Loops]
o for
o do .. while / while
• Özyineleme [Recursion]
• Sıralama [Sorting]
• v.d.
VERİ TİPLERİ VE YAPILARI
Assembly instruction'larını okurken tanımamız gereken veri
tiplerine örnekler
• pointer [X86 mimaride 4 byte'lık veri alanı, belli bir veri alanının
adresini içerir]
• integer [X86 mimaride 4 byte'lık veri alanı]
• char [1 byte'lık veri alanı]
• C string'i [null "x00" karakterle biten bir veri bloğuna işaret
eden Pointer]
• array [herhangi bir veri tipinden veri alanlarının oluşturduğu bir
dizi]
• struct [2 veya daha fazla veri tipini barındıran veri bloğu]
• linked list [barındırdığı link pointer veri tipleri ile birbirine
bağlanan veri yapılarından oluşan dizi]
• object [class'lardan oluşturulmuş veri yapıları], v.d.
DERLEME VE
PORTABLE
EXECUTABLE
[PE] DOSYA
FORMATI
DERLEME, YÜKLEME VE LİNKLEME
Kaynak
Kod
1
Kaynak
Kod
2
Kaynak
Kod
3
Kod
Üretimi
Sözdizim
Analizi
Ara Kod
Üretimi
Sözcük
Analizi
Optimi-
zasyon
DERLEME
Object
Dosyası
1
Object
Dosyası
2
Object
Dosyası
3
DERLEME, YÜKLEME VE LİNKLEME
LİNKLEME
Object Dosyası A
Başlıklar
Kod Bölümü 1
Kod Bölümü 2
Veri Bölümü
Diğer Bölüm
Object Dosyası B
Başlıklar
Kod Bölümü
Veri Bölümü
Diğer Bölüm 1
Diğer Bölüm 2
EXE veya DLL
Başlıklar
Kod Bölümü 1A
Kod Bölümü 2A
Kod Bölümü B
Veri Bölümü A
Veri Bölümü B
Diğer Bölüm A
Diğer Bölüm 1B
Diğer Bölüm 2B
DERLEME, YÜKLEME VE LİNKLEME
Uygulama.exe
Kod
Veri
Import ABC.dll
Import DEF.dll
ABC.dll
Kod
Veri
....
DEF.dll
Kod
Veri
....
SABİT DİSK
Sanal Hafıza’sı
Kernel Space
User Space
Uygulama.exe
ABC.dll
DEF.dll
OS
LOADER
Uygulama.exe’nin
DERLEME, YÜKLEME VE LİNKLEME
Fiziksel Hafıza
Proses A’nın
Sanal Hafıza Alanı
Proses B’nin
Sanal Hafıza Alanı
Proses A
Kod
Proses B
Kod
Proses A
Veri (Data)
Proses B
Veri (Data)
DLL A
Kod
DLL B
Kod
Proses A
Kod 2
DLL A
Kod
DLL B
Kod
Proses B
Veri (Data)
Proses B
Kod
Proses A
Veri (Data)
Proses A
Kod
Proses A
Kod 2
DLL A
Kod
DLL B
Kod
PORTABLE EXECUTABLE (PE)
#include<stdio.h>
int add(int prm1, int prm2)
{
int result;
result = prm1 + prm2;
return result;
}
int main()
{
int i = 10;
int j = 20;
int sonuc;
sonuc = add(i, j);
printf("Sonuc = %d", sonuc);
getchar();
}
PE dosya formatını açıklamak için yukarıda gördüğünüz
basit bir C uygulamasını kullanacağız.
PORTABLE EXECUTABLE (PE)
IMAGE DOS HEADER
PE formatında bulunan ilk bölümde modern Windows
sistemleri için çok da önemli olmayan bilgiler yer alır.
PEView
PORTABLE EXECUTABLE (PE)
IMAGE DOS HEADER
Bu bölümün başında da ASCII "MZ" karakterlerinden oluşan bir
signature bölümü yer alır. Bu harfler MSDOS işletim sisteminin
mimarlarından Mark Zbikowski'nin ad ve soyadının ilk harfleridir.
PORTABLE EXECUTABLE (PE)
IMAGE DOS HEADER
Bu bölümde bizim için önemli tek alan en sonda yer alan
ve NT exe başlığının başladığı alanın dosya içindeki
offset'ini içeren bölümdür.
PORTABLE EXECUTABLE (PE)
IMAGE DOS HEADER
• Soru: Madem içinde işimize yarayan hiçbir şey yok neden bu
bölüm var?
• Cevap: Çünkü; Microsoft bu dosya formatının MSDOS işletim
sistemi üzerinde çalıştırıldığında hata üretmek yerine bir mesaj
vererek sonlanmasını istemiştir. [Ne demek istediğimiz bir
sonraki sayfada açıklığa kavuşacaktır.]
PORTABLE EXECUTABLE (PE)
MS-DOS Stub Program
Burada gördüğümüz bölüm içinde Real Mode (16 bitlik) bir DOS
işletim sistemi kodu içerir.
Özetle bu bölümdeki DOS uygulamasının tek işlevi bu dosyanın bir
DOS uygulaması olmadığını (ironik biçimde aslında biraz öyle
olmasına rağmen) belirtmek ve uygulamayı sonlandırmaktır.
PORTABLE EXECUTABLE (PE)
IMAGE NT HEADERS [Signature]
Dosyanın geri kalanının
hangi formatta olduğunu
belirten bölüm bu alandır.
Günümüz Windows
uygulamalarında bu alan NT
signature olarak
belirtilmektedir.
PORTABLE EXECUTABLE (PE)
IMAGE NT HEADERS [Signature]
Signature alanında olabilecek diğer değerler aşağıdaki gibidir:
• #define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
• #define IMAGE_OS2_SIGNATURE 0x454E // NE
• #define IMAGE_OS2_SIGNATURE_LE 0x454C // LE
• #define IMAGE_NT_SIGNATURE 0x00004550 // PE00
Not: OS/2 Microsoft'un 90'lı yılların başlarında IBM ile birlikte
geliştirdiği bir işletim sisteminin adıdır.
PORTABLE EXECUTABLE (PE)
IMAGE FILE HEADER
Uygulama kodunun uyumlu
olduğu işlemci mimarisini
belirtir
PORTABLE EXECUTABLE (PE)
IMAGE FILE HEADER
Dosya içinde kaç section bulunduğunu belirtir.
Aşağıda görülen section header'lar bu sayıya göre
parse edilecektir.
PORTABLE EXECUTABLE (PE)
IMAGE FILE HEADER
Saldırgana dair az da olsa fikir verebilecek bu alan
zararlı uygulamanın ne zaman linklendiğini belirtir.
PORTABLE EXECUTABLE (PE)
IMAGE FILE HEADER
Optional Header alanının büyüklüğü bu alandan sonra
gelecek section header'ların başlangıç adresini bulmak
için kullanılır.
PORTABLE EXECUTABLE (PE)
IMAGE FILE HEADER
Bu bölümde dosyanın çalıştırılabilir bir dosya olduğunu anlayabiliyoruz.
Eğer bu dosya bir DLL olsaydı IMAGE_FILE_EXECUTABLE_IMAGE yerine
IMAGE_FILE_DLL işareti aktif olacaktı.
PORTABLE EXECUTABLE (PE)
IMAGE OPTIONAL HEADER
Optional Header ile ilgili söylenmesi gereken ilk şey aslında
optional olmadığı, çünkü içinde uygulamanın belleğe yüklenmesi
ve çalıştırılması ile ilgili kritik bilgiler barındırıyor.
Bunlardan "Address of Entry Point" uygulamanın çalıştırılacak ilk
instruction'ının RVA adresine işaret eder.
PORTABLE EXECUTABLE (PE)
Adres of Entry Point Hakkında
Bu ifade yanlış anlaşılmaya müsait olacağı için şu açıklamayı
yapmakta fayda bulunmaktadır:
• Uygulama modülü içinde çalıştırılacak ilk kod zannedilebileceği
gibi "main()" fonksiyonunun ilk instruction'ı değildir. "main()"
fonksiyonu çağrılmadan önce derleyici tarafından yazılım
geliştiricinin seçtiği subsystem'e göre çevresel koşulları
düzenleyen kodlar uygulamaya eklenmektedir.
• Immunity Debugger gibi bir binary debugger ile bir uygulamayı
başlattığınızda debugger'ın ilk breakpoint'i koyduğu yer ilk
çalışan kod olan NTDLL kütüphanesi içindeki bir initial stub (kod
parçası)'dır.
PORTABLE EXECUTABLE (PE)
Adres of Entry Point Hakkında (devamı)
• NTDLL'deki bu initial stub önce belleğe yüklenen diğer
kütüphanelerin entry point'lerini çalıştırır, en son da
uygulamanın ilk instruction'ını çalıştırır.
• Özetle uygulamanın "main()" fonksiyonundan önce tüm
DLL'lerin initial kodları, bunlardan sonra da uygulamanın kendi
hazırlık kodları çalışır.
PORTABLE EXECUTABLE (PE)
IMAGE OPTIONAL HEADER
Image Base alanı uygulama belleğe yüklendiğinde yerleştirilmeyi arzu ettiği
baz sanal adresi (Virtual Address – VA) ifade eder. Biraz önce uygulama
başlangıç adresi için RVA kavramını kullanmıştık, burada ise VA kavramından
söz ediyoruz.
Bu noktada sanal adres kavramını ve adres kavramlarını açıklamakta fayda
bulunmaktadır.
PORTABLE EXECUTABLE (PE)
Modül Kavramı Nedir?
Bir çalıştırılabilir dosya OS loader tarafından belleğe yüklenirken bu
dosyanın kullanacağı kütüphaneler de bu prosesin adres alanına
haritalanır (map'lenir).
Yüklenen çalıştırılabilir dosyanın kendisi (PE dosyamız) ve yüklenen
kütüphaneler (DLL'ler)'in her birisi modül olarak adlandırılırlar.
PORTABLE EXECUTABLE (PE)
Modül Kavramı Nedir?
PE modülümüzün
bellekteki imajı
Uygulamamızın
kullandığı DLL modülleri
Uygulamamızın adres
alanında kendi kod ve
verileri bulunduğu gibi
kullandığı kütüphanelerin
modülleri de hazır
bulunmaktadır.
PORTABLE EXECUTABLE (PE)
Yükleme, Fiziksel ve Mantıksal Adresler
PE Dosyamızın disk
üzerindeki hali. PEView
bizim için başlangıç
adresinin VA cinsinden
değerini belirtiyor.
PORTABLE EXECUTABLE (PE)
Yükleme, Fiziksel ve Mantıksal Adresler
PE Dosyamızın bellek
üzerindeki hali.
PORTABLE EXECUTABLE (PE)
Adres Kavramları
ÖNEMLİ: Bir PE dosyası çalıştırılmak üzere OS Loader tarafından
belleğe yüklenirken PE dosyasında gördüğünüz veriler ve yerleri
büyük oranda değişmeden belleğe aktarılır.
• File Offset: PE dosyasındaki verinin disk üzerindeki dosyada
bulunduğu offset değerini belirtir.
• Relative Virtual Address [RVA]: PE dosyasında gördüğümüz
verinin belleğe yüklendiğinde modülün yüklendiği baz sanal
adresten itibaren bulunduğu offset değerini belirtir.
• Virtual Address [VA]: PE dosyasında gördüğümüz verinin
belleğe yüklendiğinde bulunacağı sanal adrestir.
PORTABLE EXECUTABLE (PE)
Adres Kavramları [File Offset]
.text section'ının
Disk üzerindeki dosya
içindeki offset adresi
PORTABLE EXECUTABLE (PE)
Adres Kavramları - RVA [Relative Virtual Address]
.text section'ının
bellekte modülün
başlangıç adresine göre
offset adresi
PORTABLE EXECUTABLE (PE)
Adres Kavramları - VA [Virtual Address]
.text section'ının
bellekte bulunacağı sanal
adres
PORTABLE EXECUTABLE (PE)
Adres Kavramları – Bellekten Görüntü
.text section'ının bellekte disassemble edilmiş hali [adres
bilgilerinin yanında opcode'ları görebilirsiniz]
PORTABLE EXECUTABLE (PE)
IMAGE OPTIONAL HEADER
Section'ların belleğe yerleştiklerinde align olmaları gereken adres periyodu.
Yani her section'ın Virtual Adresi Hex 1000 byte'ın katları olan adreslerden
başlayabilir. Bu nedenle ".text" section'ı disk üzerinde 0x400 offset'te iken
belleğe yüklendiğinde 0x401000 VA adresinden başlamaktaydı.
PORTABLE EXECUTABLE (PE)
IMAGE OPTIONAL HEADER
Section'ların disk üzerindeki hallerinin (raw hallerinin) başlaması gereken
offset adreslerinin hangi sayının katı olması gerektiğini belirtir. Bu nedenle
section sonu bu sayının katına erişmek için "0x00" byte'ları ile pad'lenir.
PORTABLE EXECUTABLE (PE)
IMAGE OPTIONAL HEADER
".text" section'ının sonunda 0x200
byte'ın katı olacak biçimde yapılmış
0x00 byte'larıyla yapılmış padding'i
görebilirsiniz.
Son adres: 0x401E00
PORTABLE EXECUTABLE (PE)
IMAGE OPTIONAL HEADER
DLL Characteristics alanı isminde DLL geçse de tüm PE dosyalarıyla ilgilidir.
Daha sonra örneğini uygulayacağımız ASLR desteği, DEP desteği, v.d.
özellikleri modülümüzün taşıyıp taşımadığını belirtir. Bu örnekte ASLR
desteğimiz bulunmamaktadır.
PORTABLE EXECUTABLE (PE)
IMAGE OPTIONAL HEADER
Data Directories dizisi OS loader'ın işlevini yerine getirebilmesi için önemli
çeşitli bilgileri barındırır. Bu örnekte IAT'nin yerini ve büyüklüğünü görüyoruz.
PORTABLE EXECUTABLE (PE)
IMAGE OPTIONAL HEADER
IAT Data Directory'sinin RVA adresine
gittiğimizde IAT'nin içeriğine ulaşabiliriz.
PORTABLE EXECUTABLE (PE)
PE Dosya Organizasyonu Temel Referanslar
PE dosya organizasyonunun içinde OS loader'ın görevini yerine
getirebilmesi için kod / veri alanlarını ve özelliklerini tanımlayan 2
tür referans bulunmaktadır:
1. Section Header'ları: Section'ların dosya içindeki yerleri, disk
üzerinde ve bellekte kaplayacakları alan büyüklükleri ve erişim
kuralları gibi özellikleri tanımlarlar [henüz değinmedik].
2. Data Directory kayıtları: Import Address Table gibi, Base
Relocation Table (modül Image Base alanında belirtilen adrese
oturmamışsa değişmesi gereken adreslerin yerleri) gibi OS
loader için önemli ve farklı section'ların içlerinde yer alan veri
alanlarının RVA adreslerini ve büyüklüklerini tanımlarlar.
PORTABLE EXECUTABLE (PE)
IMAGE OPTIONAL HEADER
Eğer bir DLL yazmış olsaydık bir takım fonksiyonları da Export
edecektik. Bu örnek basit bir EXE uygulaması olduğu için Export Table
RVA adresi 0 olarak görülüyor. Bu bilgiye özellikle shellcode yazarken
çok ihtiyacımız olacaktır, çünkü shellcode uygulamaları bu veri
yapılarını kullanarak bellekteki fonksiyon adreslerini tespit ederler.
PORTABLE EXECUTABLE (PE)
IMAGE SECTION HEADER
Data Directory'lerle birlikte 2 önemli referans noktasından birisi olan Section
Header'ların ilk 8 byte'ı section ismi için kullanılır. Belli section'lar için
derleyicilerin kullandığı geleneksel isimler olsa da section'ın Characteristics
alanı belirleyicidir. Yani isimlerin hiçbir önemi yoktur makine (işlemci) için.
PORTABLE EXECUTABLE (PE)
IMAGE SECTION HEADER
Size of Raw Data bu section'ın disk üzerindeki dosya içinde kapladığı alanı
belirtir. Image Optional Header'daki File Alignment değerini hatırlarsanız Raw
Data boyutunun 0x200 byte'ın katları olması gerektiğini bilebiliriz. Derleyici
bunu sağlamak için section'ın son bölümlerini 0x00 ile pad'lemeli.
PORTABLE EXECUTABLE (PE)
IMAGE SECTION HEADER
Görüldüğü gibi 0xCC3
offset'inden 0xE00
offset'ine kadar olan alan
0x00 ile pad'lenmiş.
PORTABLE EXECUTABLE (PE)
IMAGE SECTION HEADER
Virtual Size değeri bu section'ın uygulama belleğe yüklendiğinde bellekte
kaplayacağız alanı ifade ediyor. Bu section için bellekteki alanın diskteki
alanından daha küçük olduğunu görüyoruz. Ancak UPX örneğinde olduğu gibi
bunun tersi de mümkün [UPX diskte hiç yer kaplamayan bir section için
bellekte geniş bir alan istemekteydi].
PORTABLE EXECUTABLE (PE)
IMAGE SECTION HEADER
Padding öncesinde son
verinin 0xCC3 adresinde
bulunduğunu .text
section'ının son bölümüne
göz attığımızda görebiliriz.
PORTABLE EXECUTABLE (PE)
IMAGE SECTION HEADER
RVA adres kavramını daha önce konuşmuştuk, bu section'ın EXE modülünün
başlangıç adresinden itibaren 0x1000 offset'ten başlatılacağını bu alandan
anlıyoruz. Yine Image Optional Header'dan hatırlarsak bu değerin 0x1000 olan
section alignment değerinin katı olması gerektiğini söyleyebiliriz.
PORTABLE EXECUTABLE (PE)
IMAGE SECTION HEADER
.text section'ının adres
formatını File Offset'ten
RVA'e değiştirdiğimizde
PEView bize olması
gereken 0x1000 değerini
gösteriyor.
PORTABLE EXECUTABLE (PE)
IMAGE SECTION HEADER
Section'ın bellekte başlayacağı adres ile disk üzerinde bulunduğu File Offset değeri
farklı. Burada bu section'ın 0x400 File Offset'inde bulunduğunu anlıyoruz. Bellekte
0x400 ve 0x1000 offset'leri arasındaki boşluk ne olacak derseniz bellekteki
adreslerini Virtual adresler olduğunu ve bu adreslerin fiziksel karşılıklarının farklı
olduklarını hatırlamamız gerekir. Yani aslında bir boşluk olmayacak, sadece bu sanal
adresler için herhangi bir fiziksel alan kullanılmayacaktır.
PORTABLE EXECUTABLE (PE)
IMAGE SECTION HEADER
.text section'ının adres
formatını File Offset'e
değiştirdiğimizde PEView
bize 0x400 değerini
gösteriyor.
PORTABLE EXECUTABLE (PE)
IMAGE SECTION HEADER
Section isimlerinin aslında işlemci için hiçbir anlamı olmadığını, section'ın
özellikleri hakkında Characteristics alanının belirleyici olduğunu daha önce
söylemiştik. Geleneksel olarak uygulamanın kod bölümlerinin yerleştirildiği .text
section'ının Execute hakkı uygulama belleğe yüklenirken bu section için ayrılan
memory page'lerine atanacaktır. Yani bu alanlardaki veriler kod olarak
çalıştırılabilecektir.
PORTABLE EXECUTABLE (PE)
IMAGE SECTION HEADER
Yine geleneksel olarak .rdata alanı Read Only verilerin (yani constant string v.d.
veri tiplerinin) saklandığı section'dır. Tabi yine bu özellik aslında Characteristics
alanı tanımlarından gelmektedir.
PORTABLE EXECUTABLE (PE)
IMAGE SECTION HEADER
.data alanı belli bir alanı kaplayan ancak değiştirilebilecek Global değişkenlerin
tutulması için kullanılan alandır. Dolayısıyla bu alana yazma (Write) hakkı da
verilmiştir.
PORTABLE EXECUTABLE (PE)
IMAGE SECTION HEADER
Resource section'ı diğerlerinden biraz farklı. Diğer section'lar da kendi içlerinde
bazı özel veri yapıları barındırıyor (ör: IAT – Import Address Table, Export Table
gibi), ancak .rsrc section'ı bir bütün olarak bir directory yapısına sahip, yani tek bir
genel veri yapısına sahip.
PORTABLE EXECUTABLE (PE)
IMAGE SECTION HEADER
Basit PE dosyamızda tek bir
resource kaydı var:
MANIFEST
PORTABLE EXECUTABLE (PE)
IMAGE SECTION HEADER
Özellikle dropper (yani resource section'ından dosyaları alıp diske bağımsız
dosyalar olarak yazma) fonksiyonalitesine sahip zararlıları incelerken bu alana
özel bir araç kullanmakta fayda var: Resource Hacker. PEView'ın veriyi Raw
formatta göstermesi bize yeterli desteği vermiyor.
DERLEYİCİLER ARASINDAKİ FARKLAR
• Tüm derleyiciler derledikleri kodun üzerinde çalışacağı makina
mimarisine uygun kod üretmek zorundadırlar.
• Ancak bazı alanlarda kod üretme şekilleri birbirlerinden
farklılaşabilir. Örneğin;
• "X86 Mimarisine Giriş" bölümünde inceleyeceğimiz
uygulama Visual Studio ile derlenmiş bir uygulama ve bu bu
derleyici fonksiyon parametrelerini stack'e "PUSH"
instruction'ı ile yazıyor.
• Tersine mühendislik egzersizlerini yapmak için kullandığımız
uygulama ise Dev-C++ ile derlenmiş bir uygulama. Bu
derleyici ise fonksiyon parametrelerini ESP register'ının
işaret ettiği alana yerleştirmeyi tercih ediyor [egzersizleri
yaparken bu konu netleşecektir].
DERLEYİCİLER ARASINDAKİ FARKLAR
• İnceleyeceğimiz bir uygulamanın derleyicisini tahmin etmek
için Detect It Easy veya benzeri bir uygulamadan
faydalanabiliriz.
X86
MİMARİSİNE
GİRİŞ
X86 MİMARİSİNE GİRİŞ
İNCELEYECEĞİMİZ UYGULAMA
PE dosya formatını da inceleme için
kullandığımız bu basit C
uygulamasından derlenmiş kodu
Immunity Debugger üzerinde
incelerken temel X86 bilgilerine
değineceğiz.
X86 MİMARİSİNE GİRİŞ
ANA KONULAR VE KAVRAMLAR
Daha Önce Değindiklerimiz
• Derleme ve linkleme
• OS Loader'ın uygulamayı belleğe yüklemesi
• Executable imajı, DLL modülleri, Stack ve Heap
alanlarının bellekteki konumları [ASLR konusuyla
bağlantıları]
• Virtual Address kavramı
X86 MİMARİSİNE GİRİŞ
ANA KONULAR VE KAVRAMLAR (DEVAMI)
Bu Bölümde Değineceklerimiz
• Register'lar ve kullanım amaçları
• X86 instruction set'i
• Stack alanının kullanımı [fonksiyon çağırma, fonksiyon
içindeki ve fonksiyondan çıkış işlemleri sırasındaki
olaylar]
• Calling conventions [fonksiyon çağırma sırasında
parametrelerin fonksiyona aktarım yöntemleri,
fonksiyon dönüşünde stack'i temizleme görevleri]
X86 MİMARİSİNE GİRİŞ
X86 hakkındaki teorik bilgiler
üzerinde daha sonrak konuşmak
üzere, öncelikle uygulamamızın
Makine Kodu seviyesindeki
işleyişini inceleyelim.
Öncelikle main() fonksiyonu
içindeki ilk instruction'ın adresini
öğrenmek için Visual Studio'nun
"Go To Assembly" özelliğini
kullanacağız.
X86 MİMARİSİNE GİRİŞ
Visual Studio'da Disassembly view'ına
geçtiğimizde derleyicinin üreteceği
Assembly kodlarının yanı sıra bunların
adreslerini de görüyoruz.
Bu bilgiye şu nedenle ihtiyacımız var:
Derleyiciler kod üretmeye doğrudan
main() fonksiyonundan başlamazlar ve
Address of Entry Point'te main()
fonksiyonuna işaret etmez. Ancak bizim
X86 mimarisini anlama amaçlı
incelememizi main() fonksiyonundan
başlatmamız lazım.
İlk instruction olan "push ebp"
instruction'ının adresi 0x401060
X86 MİMARİSİNE GİRİŞ
Uygulama belleğe yüklendiğinde de
bu adreste olacağından emin
olabilmek için ASLR'ı bu ayarlarla
etkisiz hale getirdik.
X86 MİMARİSİNE GİRİŞ
Address of Entry Point'e koyduğumuz
breakpoint [0x401060] sonrası bir kaç
defa F9 tuşuna basılarak main()
fonksiyonunun başına geliyoruz.
X86 MİMARİSİNE GİRİŞ
main() fonksiyonunun ilk instruction'ları
"function prologue" adı da verilen önceki
fonksiyon frame pointer'ın saklanması ve
mevcut stack pointer'ın yeni fonksiyonun
frame pointer'ı olarak belirlenmesidir.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
STACK
DEĞİŞEN
REGISTER'LAR
ESP 0x0018FF40
ESP
Yüksek Adres
Düşük Adres
Buradaki stack gösterimimiz ile Immunity
Debugger'ın stack penceresindeki büyüme
yönleri farklı, bu nedenle biraz kafanız
karışabilir !
X86 MİMARİSİNE GİRİŞ
"function prologue"un ikinci adımında
mevcut stack pointer [ESP] main()
fonksiyonunun stack base pointer'ı [EBP]
olarak atanıyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
STACK EBP 0x0018FF40
ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
main() fonksiyonunun lokal değişkenleri için
stack'te 12 byte'lık [0x0C] yer ayrılıyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
XXXXXXXX
XXXXXXXX
XXXXXXXX
STACK ESP 0x0018FF34
ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
[EBP-8] adresindeki lokal değişkene 10
[0x0A] değeri atanıyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
XXXXXXXX
0x0000000A
XXXXXXXX
STACK ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
[EBP-4] adresindeki lokal değişkene 20
[0x14] değeri atanıyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
XXXXXXXX
STACK ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
[EBP-4] adresindeki lokal değişken EAX
register'ına atanıyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
XXXXXXXX
STACK ESP
EAX 0x00000014
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
EAX register'ının değeri Stack'e push
ediliyor. Bu değer "add" fonksiyonu için bir
parametre olarak kullanılacak.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
XXXXXXXX
0x00000014 [Arg 2]STACK
ESP
ESP 0x0018FF30
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
[EBP-8] adresindeki lokal değişken ECX
register'ına atanıyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
XXXXXXXX
0x00000014 [Arg 2]STACK
ESP
ECX 0x0000000A
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
ECX register'ının değeri Stack'e push
ediliyor. Bu değer "add" fonksiyonu için bir
diğer parametre olarak kullanılacak.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
XXXXXXXX
0x00000014 [Arg 2]
0x0000000A [Arg 1]
STACK
ESP
ESP 0x0018FF2C
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
Immunity Debugger debug sembollerine
sahip olduğu bir executable için bize
fonksiyon adı ve bu fonksiyona verilen
parametrelerle ilgili bilgi sağlıyor.
X86 MİMARİSİNE GİRİŞ
"call add" instruction'ı çalıştığında EIP
değeri add fonksiyonuna işaret edecek
şekilde değişiyor, ancak main() fonksiyonu
içindeki bir sonraki instruction'ın adresi
stack'e yazılıyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
XXXXXXXX
0x00000014 [Arg 2]
0x0000000A [Arg 1]
0x00401081 [EIP]
STACK
ESP
ESP 0x0018FF28
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
add() fonksiyonunun prologue'unın ilk
instruction'ı çalıştığında main()
fonksiyonunun stack base pointer'ı stack'e
yazılıyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
XXXXXXXX
0x00000014 [Arg 2]
0x0000000A [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
STACK
ESP
ESP 0x0018FF24
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
add() fonksiyonunun prologue'unın ikinci
instruction'ı çalıştığında ESP register'ının
değeri add() fonksiyonunun stack base
pointer'ına [EBP] yazılıyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
XXXXXXXX
0x00000014 [Arg 2]
0x0000000A [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
STACK
ESP
EBP 0x0018FF24
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
add() fonksiyonu lokal değişkenler için
sadece 4 byte'lık bir alan kullandığından
"push ecx" instruction'ı ile stack'te yeterli
alan ayrılmış oluyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
XXXXXXXX
0x00000014 [Arg 2]
0x0000000A [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
XXXXXXXX
STACK
ESP
ESP 0x0018FF20
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
add() fonksiyonunun stack'te hazır bulunan
birinci parametresi [EAX] register'ına
atanıyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
XXXXXXXX
0x00000014 [Arg 2]
0x0000000A [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
XXXXXXXX
STACK
ESP
EAX 0x0000000A
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
add() fonksiyonunun stack'te hazır bulunan
ikinci parametresi [EAX] register'ına [add]
instruction'ı ile ekleniyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
XXXXXXXX
0x00000014 [Arg 2]
0x0000000A [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
XXXXXXXX
STACK
ESP
EAX 0x0000001E
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
[EAX] register'ının değeri stack'te add()
fonksiyonu için ayrılmış 4 byte'lık lokal
değişken alanına atanıyor. Uygulamamızı
optimizasyon ayarları ile derlemiş olsaydık
muhtemelen bu adımı görmeyecektik. Çünkü
zaten return değeri [EAX] register'ı ile
döndürülecek.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
XXXXXXXX
0x00000014 [Arg 2]
0x0000000A [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
0x0000001E
STACK
ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
Bu adımda gereksiz bir biçimde lokal
değişken tekrar [EAX] register'ına atanıyor.
Ancak register değeri zaten aynı olduğu için
değişmiyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
XXXXXXXX
0x00000014 [Arg 2]
0x0000000A [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
0x0000001E
STACK
ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
add() fonksiyonun epilogue'unun ilk
adımında add() fonksiyonunun stack base
pointer'ı [ESP] register'ına atanıyor. Bu
adımda add() fonksiyonu için stack'ten
almış olduğumuz alan geri veriliyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
XXXXXXXX
0x00000014 [Arg 2]
0x0000000A [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
0x0000001E
STACK ESP 0x0018FF24
ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
add() fonksiyonun epilogue'unun ikinci
adımında main() fonksiyonunun stack'te
saklanmış olan [EBP] register değeri tekrar
yükleniyor. pop instruction'ı ile birlikte stack
de 4 byte daha azaltılmış oluyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
XXXXXXXX
0x00000014 [Arg 2]
0x0000000A [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
0x0000001E
STACK EBP 0x0018FF40
ESP 0x0018FF28
ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
"retn" instruction'ı çalıştığında stack'in en
üstünde bulunan saklanmış [EIP] değeri
"pop" edilecek ve uygulama akışı bu
adresten devam edecektir.
X86 MİMARİSİNE GİRİŞ
"retn" instruction'ı çalıştığında sadece
saklanmış EIP değerine atlamıyoruz aynı
zamanda stack'de 4 byte küçültülmüş
oluyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
XXXXXXXX
0x00000014 [Arg 2]
0x0000000A [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
0x0000001E
STACK ESP 0x0018FF2C
ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
"add esp, 8" instruction'ı ile stack'te add()
fonksiyon parametreleri için kullanmış
olduğumuz 8 byte'lık alanı geri veriyoruz. Bu
işlemde çağıran [caller] stack'i temizliyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
XXXXXXXX
0x00000014 [Arg 2]
0x0000000A [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
0x0000001E
STACK ESP 0x0018FF34
ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
[EAX] register'ında bulunan toplama işlemi
sonucu main() fonksiyonunun lokal
değişkenine atanıyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
0x0000001E
0x00000014 [Arg 2]
0x0000000A [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
0x0000001E
STACK ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
Lokal değişkenimizde bulunan toplama
sonucu [EDX] register'ına atanıyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
0x0000001E
0x00000014 [Arg 2]
0x0000000A [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
0x0000001E
STACK EDX 0x0000001E
ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
Optimizasyon uygulamadığımız için printf()
fonksiyonunun ikinci parametresi olarak
(parametreler yine sağdan sola doğru
stack'e yazılıyor) [EDX] register'ında
bulunan toplam değerini stack'e yazıyoruz
(halbuki bu değer zaten stack'te mevcuttu)
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
0x0000001E
0x0000001E [Arg 2]
0x0000000A [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
0x0000001E
STACK ESP 0x0018FF30
ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
Buradaki Arg 2 printf()'in ikinci
parametresi
X86 MİMARİSİNE GİRİŞ
Bu instruction'da printf() fonksiyonu için
format string'in bulunduğu adresi stack'e
yazıyoruz. Stack penceresinde bu değerin
Sonuc = "%d" olduğunu görebiliriz.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
0x0000001E
0x0000001E [Arg 2]
0x00403000 [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
0x0000001E
STACK ESP 0x0018FF2C
ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
printf() fonksiyonu çağrılmadan önce
konsol penceresini görünteleyelim ve
henüz birşey yazılmadığını görelim.
X86 MİMARİSİNE GİRİŞ
printf fonksiyonunun içine girmeden "step over" şeklinde bu
fonksiyonu çalıştırıyoruz, çünkü bu API fonksiyonunu
incelemek istemiyoruz. Bu çağrıdan sonra Sonuc = 30
ifadesini görmemizin yanında ilginç olan bir nokta [EAX],
[ECX] ve [EDX] register'larımızın değişmiş olması.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
0x0000001E
0x0000001E [Arg 2]
0x00403000 [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
0x0000001E
STACK EAX 0x0018FF2C
ECX 0x0018FF2C
EDX 0x0018FF2CESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
"caller saved" registers kavramına
"calling conventions" bölümünde
değineceğiz.
X86 MİMARİSİNE GİRİŞ
printf() fonksiyonuna verilen parametreler
için tüketilen stack alanı geri veriliyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
0x0000001E
0x0000001E [Arg 2]
0x00403000 [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
0x0000001E
STACK ESP 0x0018FF34
ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
getchar() API fonksiyonunun
çalışabilmesi için konsol penceresinden
bir girdi vermemiz gerekecek. Bu
yüzden "step over" komutu ile bir
instruction daha atlamaya çalıştıktan
sonra konsolu tekrar ön plana alalım.
X86 MİMARİSİNE GİRİŞ
Konsol penceresinde "Enter" tuşuna
bastıktan sonra getchar() fonksiyonu
tamamlanarak dönüyor. [ECX] ve [EDX]
register'larının değiştiğini gözlemliyoruz.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
0x0000001E
0x0000001E [Arg 2]
0x00403000 [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
0x0000001E
STACK ECX 0x683D60B0
EDX 0x0000000A
ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
main() fonksiyonundan çıkmadan önce
[EAX] register'ı return değeri olarak
"0"lanmak amacıyla kendisiyle XOR'lanıyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
0x0000001E
0x0000001E [Arg 2]
0x00403000 [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
0x0000001E
STACK EAX 0x00000000
ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
main() fonksiyonundan çıkmadan önce
epilogue adımlarından main() fonksiyonu
için alınmış olan stack alanını geri veren
"mov esp, ebp" instruction'ı çalıştırılıyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
0x0000001E
0x0000001E [Arg 2]
0x00403000 [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
0x0000001E
STACK ESP 0x0018FF40
ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
main() fonksiyonu 2. epilogue adımında
main() fonksiyonunu çağıran bir üst
fonksiyonun [EBP] register'ı restore ediliyor.
X86 MİMARİSİNE GİRİŞ
Stack ve Registry Değişim Özeti
0x0018FF88 [EBP]
0x00000014
0x0000000A
0x0000001E
0x0000001E [Arg 2]
0x00403000 [Arg 1]
0x00401081 [EIP]
0x0018FF40 [EBP]
0x0000001E
STACK EBP 0x0018FF88
ESP 0x0018FF44
ESP
DEĞİŞEN
REGISTER'LAR
Yüksek Adres
Düşük Adres
X86 MİMARİSİNE GİRİŞ
main() fonksiyonunun sonunda "retn"
instruction'ı çalıştığında saklanmış olan
[EIP] adresinden uygulama akışı devam
ediyor.
X86 MİMARİSİNE GİRİŞ
Uygulamanın devam etmesine izin
verdiğimizde "0" exit değeri ile
sonlandığını görüyoruz.
X86 MİMARİSİNE GİRİŞ
İNCELEYEDİĞİMİZ UYGULAMA
Assembly kodlarının üzerinden
geçtikten sonra kaynak kodumuzu
tekrar hatırlamak isteyebilirsiniz.
(Aslında her aşamada bu kaynak koda
göz atmak disassembly'yi anlamak için
size yardımcı olabilir.)
X86 MİMARİSİNE GİRİŞ
REGISTER'LAR VE KULLANIM AMAÇLARI
EIP [Extended Instruction Pointer]
Bir sonra çalışacak olan instruction’ın adresi (sadece makine tarafından değiştirilir)
EBP [Extended Base Pointer] ve ESP [Extended Stack Pointer]
İçinde bulunulan fonksiyonun stack frame’inin taban ve tavan adreslerini
barındıran register’lar
EAX, EBX, ECX, EDX, ESI, EDI
Genel amaçlı register’lar (ancak geleneksel olarak belli amaçlarla kullanılabilirler)
EFLAGS
Çeşitli instruction’lar tarafından etkilenen ve kullanılan bayrakları barındıran 32
bit’lik bir register
X86 MİMARİSİNE GİRİŞ
REGISTER'LAR VE KULLANIM AMAÇLARI
• EAX – Accumulator Register: Genellikle fonsiyonların return değerlerini tutar.
Hesaplamaların sonuçları da genellikle bu register'da tutulur.
• EBX – Base Register: Genellikle belli bir özel amaç için kullanılmaz.
• ECX – Counter Register: Genellikle döngülerde ve string işlemlerinde sayaç
değişkenini (yani meşhur "i" değerini) tutmak için kullanılır.
• EDX – Data Register: Çarpma ve bölme gibi işlemlerde EAX'in yetersiz kalması
nedeniyle işlem sonuçlarının most significant bit'lerini tutmak için kullanılır.
• ESI – Source Index: Genellikle string yazma işlemlerinde kopyalanacak string'den
okunacak adresi tutar (read pointer).
• EDI – Destination Index: Genellikle string yazma işlemlerinde yazılacak adresi tutar
(write pointer).
Önemli: ESP ve EBP register'ları ile birlikte yukarıdaki genel amaçlı register'lar assembly
yazan uygulama geliştirici veya derleyici tarafından istenildiği gibi kullanılabilir. Ancak
yukarıda belirtilen kullanımlar geleneksel kullanımlardır.
X86 MİMARİSİNE GİRİŞ
REGISTER'LAR VE KULLANIM AMAÇLARI
EAX
EBX
ECX
EDX
AX
BX
CX
DX
078151631
32 Bit
Register'lar
16 Bit
Register'lar
8 Bit
Register'lar
Bu bölümleme sadece EAX,
EBX, ECX ve EDX'e özeldir
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Assembly Syntax'ları
Intel AT&T
Prefix'ler mov eax, 1 movl $1, %eax
Operand yönü instr dest, source instr source, dest
Bellek operand'ları mov eax, [ebx] movl (%ebx), %eax
Suffix'ler mov al, bl movb %bl, %al
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Bellek adresleme yöntemleri
Instruction Anlamı
mov eax, [ebx] EBX register'ının içerdiği adresteki 4 byte'lık değeri EAX
register'ına atama
mov [var], ebx EBX register'ının değerini 32bit'lik bir değişkenin içerdiği adrese
yazma
mov eax, [esi-4] ESI + (-4) adresindeki 4 byte'lık değeri EAX register'ına atama
mov [esi+eax], cl CL register'ının taşıdığı bir byte'lık değeri ESI+EAX adresine
yazma
mov edx, [esi+4*ebx] ESI+4*EBX adresinde bulunan 4 byte'lık değeri EDX register'ına
atama
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Size Directive'leri
Register adlarının geçtiği instruction'lardan okunacak ve/veya yazılacak verinin
büyüklüğü anlaşılabilir. Ancak immediate (sabit) verilerin yazıldığı durumlarda
yazılacak verinin kaplayacağı alanın belirtilmesi gerekir.
Instruction Anlamı
mov BYTE PTR [ebx], 2 2 sabit değerini EBX register'ında saklı adresteki 1 byte'lık
alan yaz
mov WORD PTR [ebx], 2 2 sabit değerinin 16 bit'lik gösterimini EBX register'ında saklı
adresten başlayan 2 byte'lık alana yaz
mov DWORD PTR [ebx], 2 2 sabit değerinin 32 bit'lik gösterimini EBX register'ında saklı
adresten başlayan 2 byte'lık alana yaz
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Instruction'lar
Şu ana kadar pek çok assembly instruction'ı ile karşılaştık. Açıkçası belli bir
instruction set'i kullanılan veya derleyicilerin ürettiği assembly kodlarının önemli
bir bölümünü kapsar.
Bu bölümde daha önce de karşılaştığımız çok kullanılan Assembly
Instruction'larının üzerinden geçeceğiz.
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Instruction'lar [Data Movement Instruction'ları]
mov
Move (Opcodes: 88, 89, 8A, 8B, 8C, 8E, ...)
Bellekten belleğe mov instruction'ı ile veri kopyalamak mümkün değildir.
Syntax
mov <reg>,<reg>
mov <reg>,<mem>
mov <mem>,<reg>
mov <reg>,<imm>
mov <mem>,<imm>
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Instruction'lar [Data Movement Instruction'ları]
push
Push stack (Opcodes: FF, 89, 8A, 8B, 8C, 8E, ...)
Syntax
push <reg32>
push <mem>
push <imm32>
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Instruction'lar [Data Movement Instruction'ları]
pop
Pop stack
Syntax
pop <reg32>
pop <mem>
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Instruction'lar [Data Movement Instruction'ları]
lea
Load effective address
Bu instruction diğerlerine nazaran biraz kafa karıştırıcı olabilir. "lea"
instruction'ın da kaynak değer mutlaka köşeli parantezler arasındadır, ancak
"mov" instruction'ı için bu köşeli parantezler arasında adresi bulunan bellek
alanındaki değer anlamına gelirken "lea" instruction'ı doğrudan adres değerini
kullanır. Bu imkan zaman zaman adres bilgisini kullanmaktan ziyade hesaplama
amacıyla kullanılmaktadır.
Örnek
lea edi, [ebx+4*esi] - EBX+4*ESI hesaplamasının sonucu EDI register'ına atanır
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Instruction'lar [Aritmetik ve Mantık Instruction'ları]
add
Integer Addition
Toplama instruction'ında en fazla bir operand bellek alanı olabilir.
Syntax
add <reg>,<reg>
add <reg>,<mem>
add <mem>,<reg>
add <reg>,<imm>
add <mem>,<imm>
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Instruction'lar [Aritmetik ve Mantık Instruction'ları]
sub
Integer Subtraction
Toplama instruction'ında olduğu gibi çıkarma instruction'ında da en fazla bir
operand bellek alanı olabilir.
Syntax
sub <reg>,<reg>
sub <reg>,<mem>
sub <mem>,<reg>
sub <reg>,<imm>
sub <mem>,<imm>
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Instruction'lar [Aritmetik ve Mantık Instruction'ları]
inc, dec
Increment, Decrement
Artırma instruction'ı registry veya bellek alanını bir artırırken azaltma
instruction'ı da tam tersini gerçekleştirir.
Syntax
inc <reg>
inc <mem>
dec <reg>
dec <mem>
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Instruction'lar [Aritmetik ve Mantık Instruction'ları]
imul
Integer Multiplication
2 veya 3 operand'la çalışır. 2 operand'lı kullanımda iki değer çarpılıp sonuç
birinci operand'da saklanır. 3 operand'lı kullanımda 2. ve 3. operand'lar çarpılıp
sonuç birinci operand'da saklanır. Birinci operand (destination) her zaman
registry olmak zorundadır, 3 operand'lı kullanımda 3. operand her zaman bir
immediate (sabit) değer olmak zorundadır.
Syntax
imul <reg32>,<reg32>
imul <reg32>,<mem>
imul <reg32>,<reg32>,<imm>
imul <reg32>,<mem>,<imm>
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Instruction'lar [Aritmetik ve Mantık Instruction'ları]
idiv
Integer Division
EDX:EAX registerlarında bulunan 64 bit'lik integer değeri operand değerine
böler. Bölüm EAX'e kalan ise EDX register'ına yazılır.
Syntax
idiv <reg32>
idiv <mem>
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Instruction'lar [Aritmetik ve Mantık Instruction'ları]
and, or, xor
Bitwise logical and, or and exclusive or
Operand'lar üzerinde belirtilen işlemleri gerçekleştirdikten sonra sonucu birinci
operand'a yazarlar.
Syntax
and <reg>,<reg>
and <reg>,<mem>
and <mem>,<reg>
and <reg>,<imm>
and <mem>,<imm>
or <reg>,<reg>
or <reg>,<mem>
or <mem>,<reg>
or <reg>,<imm>
or <mem>,<imm>
xor <reg>,<reg>
xor <reg>,<mem>
xor <mem>,<reg>
xor <reg>,<imm>
xor <mem>,<imm>
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Instruction'lar [Aritmetik ve Mantık Instruction'ları]
shl, shr
Shift Left, Shift Right
Birinci operand'ı sola veya sağa kaydırırken boşalan bit pozisyonlarına 0 yazılır.
Kaç bit kaydırma yapılacağı 8 bit'lik bir immediate değerde veya CL register'ı ile
verilir.
Syntax
shl <reg>,<imm8>
shl <mem>,<imm8>
shl <reg>,<cl>
shl <mem>,<cl>
shr <reg>,<imm8>
shr <mem>,<imm8>
shr <reg>,<cl>
shr <mem>,<cl>
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Instruction'lar [Akış Kontrol Instruction'ları]
jmp
Jump
Uygulama akışını koşulsuz olarak operand ile belirtilen adrese yönlendirir.
Syntax
jmp <label>
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Instruction'lar [Akış Kontrol Instruction'ları]
jcondition (Conditional Jump)
EFLAGS register'ında tutulan ve son aritmetik işlemin (bunlar add, sub gibi instruction'lar olabileceği
gibi cmp ve test gibi çıkarma işleminin türevleri olan karşılaştırma instruction'ları da olabilir)
sonuçlarına bağlı olarak uygulama akışını operand'da belirtilen adrese yönlendirir veya akışın bir
sonraki instruction'dan devam etmesine izin verir. ZF - zero flag yapılan işlem veya karşılaştırmanın
sonucu "0" ise "1" değerini alır. SF - sign flag yapılan işlemin sonucu negatif ise "1" değerini alır.
Syntax
je <label> (jump when equal)
jne <label> (jump when not equal)
jz <label> (jump when last result was zero)
jg <label> (jump when greater than)
jge <label> (jump when greater than or equal to)
jl <label> (jump when less than)
jle <label> (jump when less than or equal to)
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Instruction'lar [Akış Kontrol Instruction'ları]
cmp
Compare
CMP instruction'ı SUB instruction'ına benzer ancak çıkartma işleminin sonucu
birinci operand'a yazılmaz, sadece işlemin sonucu negatif ise Sign Flag "1" olarak
işaretlenir.
Syntax
cmp <reg>,<reg>
cmp <reg>,<mem>
cmp <mem>,<reg>
cmp <reg>,<imm>
X86 MİMARİSİNE GİRİŞ
X86 ASSEMBLY GİRİŞ
Instruction'lar [Akış Kontrol Instruction'ları]
call, ret (Subroutine call and return)
CALL instruction'ı operand ile verilen adrese uygulama akışını yönlendirirken bir yandan da
kendisinden bir sonra gelen instruction'ın adresini STACK'e yazar, JMP instruction'ından temel farkı
da budur.
RET instruction'ı ise önce STACK'in o anda en üstünde bulunan adres değerini restore eder, yani
uygulama akışını daha önce CALL instruction'ı ile saklanmış olan adrese yönlendirir. Dolayısıyla RET
instruction'ından önce function epilog bölümü gerçekleştirilerek çalıştırılan fonksiyon için STACK'te
ayrılmış olan tüm alanın SUB ESP, 0x??? instruction'ı veya benzeri bir işlem ile geri verilmiş olması
gerekir.
Syntax
call <label>
ret
X86 MİMARİSİNE GİRİŞ
STACK ALANININ KULLANIMI
Stack Alanının Çalışma Mekanizması
• Stack yüksek bir adresten düşük adreslere doğru büyür.
• Stack'e veri yazma (PUSH) ve bu veriyi bir register'a okuyarak silme (POP)
işlemi LIFO (Last In First Out) yöntemiyle stack'e veri yazılması ve silinmesine
yol açar. Bu stack'teki herhangi bir alan okunarak (MOV instruction'ı ile) bir
register'a atanamaz ve tam tersi şekilde bir register veya immediate değeri
stack'e yazılamaz anlamına gelmez, LIFO yöntemi ile sadece stack'in alan
tüketimi ve iadesine ilişkin yöntemi ifade ediyoruz.
• Stack sadece PUSH instruction'ı ile büyümez ve POP instruction'ı ile
küçülmez. [SUB ESP, 0x20] benzeri instruction'larla ESP register değeri
küçültülerek büyüyebilir ve [ADD ESP, 0x20] benzeri instruction'larla ESP
değeri artırılarak küçülebilir.
• Stack ASLR uygulanırsa her yüklemede farklı bir adresten başlatılır.
X86 MİMARİSİNE GİRİŞ
STACK ALANININ KULLANIMI
Stack'te Saklanan Veriler
• Fonksiyon parametreleri: fastcall gibi calling convention'larda
register'lar da fonksiyonlara parametre vermek için kullanılabilmekle
birlikte diğer convention'larda ve bu iş için ayrılmış register'ların
sayısının yetmediği durumlarda parametreler "CALL" instruction'ı ile
fonksiyon çağrılmadan önce stack'e yazılır. Parametreler genellikle
sağdan sola doğru stack'e yerleştirilir ("printf" gibi değişken sayıda
parametre kabul eden fonksiyonlar için format string parametresinde
olduğu gibi diğer parametreleri tanımlayan bir string başta olduğundan
bu yaklaşım oldukça mantıklıdır).
• Bazı derleyiciler parametrenin stack'ye yazılması işlemini PUSH
instruction'ı ile gerçekleştirir, bazıları ise stack'in en uç noktasını
kullanarak parametreleri doğru sırada yerleştirir.
X86 MİMARİSİNE GİRİŞ
STACK ALANININ KULLANIMI
Stack'te Saklanan Veriler [devamı]
• Fonksiyon dönüş adresi: "CALL" instruction'ı çalıştığı anda bu
instruction'dan bir sonraki instruction adresi fonksiyondan "RET"
instruction'ı ile dönüldüğünde EIP register'ına atanmak üzere stack'te
saklanır. Bellek taşma açıklıklarında uygulama akışını manipüle etmek
için hedef alınan başlıca pointer değeri bu değerdir (diğerlerine SEH
pointer değeri, lokal değişken olarak saklanan object veri yapılarının ilk
alanında bulunan Virtual Table pointer değeri örnek verilebilir).
X86 MİMARİSİNE GİRİŞ
STACK ALANININ KULLANIMI
Stack'te Saklanan Veriler [devamı]
• Bir önceki fonksiyon frame pointer'ı: Fonksiyon "prolog"larında daha
önce de gördüğümüz gibi ilk yapılan işlem mevcut frame pointer
değeri (EBP) yeni fonksiyonun frame pointer değeri ile ezileceği için
"PUSH EBP" instruction'ı ile stack'e yazılır. Bu değer fonksiyon
"epilog"unda "POP EBP" instruction'ı ile EBP pointer'ını eski frame
pointer'ı haline getirmek için kullanılır.
• Fonksiyon lokal değişkenleri: Fonksiyon "prolog"undan sonra
genellikle fonksiyon lokal değişkenleri için ESP değeri düşürülerek yer
ayrılır. Daha sonra lokal değişkenler için ayrılan bu alana lokal
değişkenler yazılmaya ve bu alandan gerektiğinde okunmaya başlanır.
X86 MİMARİSİNE GİRİŞ
CALLING CONVENTIONS
CALLING CONVENTION'LARI NEDEN ANLAMALIYIZ?
Calling convention'lar çağıranın mı çağrılanın mı parametreler için
kullanılan alanı geri vereceği ve hangi register'ların korunmasının
kimin sorumluluğunda olduğu ile ilgilidir.
İyi Niyetli Cevap
Bu sorunun iyi niyetli cevabı farklı compiler'ların ürettikleri kodların
bir arada uyum içinde çalışabilmeleri için stack yönetimi ve
register'ların korunması için aynı yaklaşımları izleme ihtiyacıdır.
X86 MİMARİSİNE GİRİŞ
CALLING CONVENTIONS
CALLING CONVENTION'LARI NEDEN ANLAMALIYIZ? [devamı]
Kötü Niyetli Cevap
Inline assembly ile bir kod yazarken veya virüs benzeri bir kodu
mevcut bir uygulamaya yerleştirirken assembly içinden çağrılan
Windows API'lerinin calling convention'ına uygun olarak hareket
edilmezse Stack yapısının düzeni bozulacak, dolayısıyla da
uygulama stack frame'i ile ilgili bu düzensizlikten dolayı hata alarak
sonlanacaktır.
Windows API'leri için "stdcall" convention'ına uygun bir biçimde
stack'teki parametreleri yönetmezsek kodumuzun içinde çalıştığı
proses hata alacaktır.
X86 MİMARİSİNE GİRİŞ
CALLING CONVENTIONS
stdcall
Adının çağrıştırabileceğinin aksine aslında tüm derleyiciler için standart
convention değildir ve Microsoft Win32 API tarafından kullanılır. İlk olarak bu
convention'dan söz etmemizin sebebi de budur.
• Stack'in temizlenmesinden çağırılan (callee) sorumludur. Yani çağıran (caller)
parametreleri stack'e push eder, ancak temizleme işlemini gerçekleştirmez.
• Parametreler stack'e sağdan sola doğru push edilir.
• EAX, ECX ve EDX register'ları fonksiyon içinde kullanılır, dolayısıyla
fonksiyondan geri dönüldüğünde farklılaşmış olma ihtimalleri yüksektir. Yani
bunlar caller saved register'lardır.
• Fonksiyon return değeri EAX register'ına yazılır.
X86 MİMARİSİNE GİRİŞ
CALLING CONVENTIONS
cdecl
C declaration'ın kısaltması olan bu convention çoğu C derleyicileri tarafından
kullanılır.
• Stack'in temizlenmesinden çağıran (caller) sorumludur. Bu yaklaşım
stdcall'unkinden farklıdır.
• Parametreler stack'e sağdan sola doğru push edilir.
• EAX, ECX ve EDX register'ları fonksiyon içinde kullanılır, dolayısıyla
fonksiyondan geri dönüldüğünde farklılaşmış olma ihtimalleri yüksektir. Yani
bunlar caller saved register'lardır.
• Fonksiyon return değeri EAX register'ına yazılır.
X86 MİMARİSİNE GİRİŞ
CALLING CONVENTIONS
Microsoft fastcall
Parametre aktarımında register kullanımına da bir örnek olması amacıyla fastcall
convention'ından da bahsedelim. Bir fonksiyonun bu convention'a göre
derlenmesi için __fastcall anahtar kelimesinin kullanılması gerekir.
• Soldan sağa ilk iki parametre ECX ve EDX register'larında aktarılır.
• Diğer parametreler (bu defa sağdan sola) stack'e yazılır.
• Stack'in temizlenmesinden stdcall'da olduğu gibi çağırılan (callee)
sorumludur.
TEMEL
ADIMLAR
TERSİNE MÜHENDİSLİK TEMEL
ADIMLAR
• İlk bilgi toplama
 Import Address Table'ın incelenmesi
 String'lerin incelenmesi
 Temel dinamik analiz
• İncelenecek fonksiyonun bulunması
• Bu fonksiyondan çağrılan - "call" edilen fonksiyonların tespit
edilmesi
• Algoritma ve veri yapılarının tespiti
• Tespit edilen algoritmaların kavramsal olarak (pseudo)
kodlanması
• Fonksiyonların, parametrelerin, değişkenlerin adlarının
değiştirilmesi ("rename" edilmesi)
• Analiz edilen kod bölümlerine yorum (comment) eklenmesi
BTRisk X86 Tersine Mühendislik Eğitim Sunumu - Bölüm-1

More Related Content

What's hot

Web Uygulama Güvenliği Ve Güvenli Kod Geliştirme Eğitim Notlarım
Web Uygulama Güvenliği Ve Güvenli Kod Geliştirme Eğitim NotlarımWeb Uygulama Güvenliği Ve Güvenli Kod Geliştirme Eğitim Notlarım
Web Uygulama Güvenliği Ve Güvenli Kod Geliştirme Eğitim NotlarımNur Yesilyurt
 
Log Yönetimi ve Saldırı Analizi Eğitimi -1
Log Yönetimi ve Saldırı Analizi Eğitimi -1Log Yönetimi ve Saldırı Analizi Eğitimi -1
Log Yönetimi ve Saldırı Analizi Eğitimi -1BGA Cyber Security
 
Open Source Soc Araçları Eğitimi 2020-II
Open Source Soc Araçları Eğitimi 2020-IIOpen Source Soc Araçları Eğitimi 2020-II
Open Source Soc Araçları Eğitimi 2020-IIBGA Cyber Security
 
Snort IPS(Intrusion Prevention System) Eğitimi
Snort IPS(Intrusion Prevention System) EğitimiSnort IPS(Intrusion Prevention System) Eğitimi
Snort IPS(Intrusion Prevention System) EğitimiBGA Cyber Security
 
Arp protokolu ve guvenlik zafiyeti
Arp  protokolu ve guvenlik zafiyetiArp  protokolu ve guvenlik zafiyeti
Arp protokolu ve guvenlik zafiyetiBGA Cyber Security
 
Zararlı Yazılım Analizi Eğitimi Lab Kitabı
Zararlı Yazılım Analizi Eğitimi Lab KitabıZararlı Yazılım Analizi Eğitimi Lab Kitabı
Zararlı Yazılım Analizi Eğitimi Lab KitabıBGA Cyber Security
 
Beyaz Şapkalı Hacker CEH Eğitimi - Bölüm 4, 5, 6
Beyaz Şapkalı Hacker CEH Eğitimi - Bölüm 4, 5, 6Beyaz Şapkalı Hacker CEH Eğitimi - Bölüm 4, 5, 6
Beyaz Şapkalı Hacker CEH Eğitimi - Bölüm 4, 5, 6BGA Cyber Security
 
Kurumsal Ağlarda Log İnceleme Yöntemiyle Saldırı Analizi
Kurumsal Ağlarda Log İnceleme Yöntemiyle Saldırı AnaliziKurumsal Ağlarda Log İnceleme Yöntemiyle Saldırı Analizi
Kurumsal Ağlarda Log İnceleme Yöntemiyle Saldırı AnaliziBGA Cyber Security
 
Nmap101 Eğitim Sunumu - Nmap Kullanım Kılavuzu
Nmap101 Eğitim Sunumu - Nmap Kullanım KılavuzuNmap101 Eğitim Sunumu - Nmap Kullanım Kılavuzu
Nmap101 Eğitim Sunumu - Nmap Kullanım KılavuzuMehmet Caner Köroğlu
 
Beyaz Şapkalı Hacker CEH Eğitimi - Bölüm 1, 2, 3
Beyaz Şapkalı Hacker CEH Eğitimi - Bölüm 1, 2, 3Beyaz Şapkalı Hacker CEH Eğitimi - Bölüm 1, 2, 3
Beyaz Şapkalı Hacker CEH Eğitimi - Bölüm 1, 2, 3BGA Cyber Security
 
Siber Güvenlik ve Etik Hacking Sunu - 10
Siber Güvenlik ve Etik Hacking Sunu - 10Siber Güvenlik ve Etik Hacking Sunu - 10
Siber Güvenlik ve Etik Hacking Sunu - 10Murat KARA
 
İleri Seviye Ağ Güvenliği Lab Kitabı
İleri Seviye Ağ Güvenliği Lab Kitabıİleri Seviye Ağ Güvenliği Lab Kitabı
İleri Seviye Ağ Güvenliği Lab KitabıBGA Cyber Security
 
Linux İşletim Sistemi - Güncelleme-2018
Linux İşletim Sistemi - Güncelleme-2018Linux İşletim Sistemi - Güncelleme-2018
Linux İşletim Sistemi - Güncelleme-2018Murat KARA
 

What's hot (20)

Sizma testi bilgi toplama
Sizma testi bilgi toplamaSizma testi bilgi toplama
Sizma testi bilgi toplama
 
Web Uygulama Güvenliği Ve Güvenli Kod Geliştirme Eğitim Notlarım
Web Uygulama Güvenliği Ve Güvenli Kod Geliştirme Eğitim NotlarımWeb Uygulama Güvenliği Ve Güvenli Kod Geliştirme Eğitim Notlarım
Web Uygulama Güvenliği Ve Güvenli Kod Geliştirme Eğitim Notlarım
 
Log Yönetimi ve Saldırı Analizi Eğitimi -1
Log Yönetimi ve Saldırı Analizi Eğitimi -1Log Yönetimi ve Saldırı Analizi Eğitimi -1
Log Yönetimi ve Saldırı Analizi Eğitimi -1
 
Uygulamali Sizma Testi (Pentest) Egitimi Sunumu - 1
Uygulamali Sizma Testi (Pentest) Egitimi Sunumu - 1Uygulamali Sizma Testi (Pentest) Egitimi Sunumu - 1
Uygulamali Sizma Testi (Pentest) Egitimi Sunumu - 1
 
Uygulamali Sizma Testi (Pentest) Egitimi Sunumu - 2
Uygulamali Sizma Testi (Pentest) Egitimi Sunumu - 2Uygulamali Sizma Testi (Pentest) Egitimi Sunumu - 2
Uygulamali Sizma Testi (Pentest) Egitimi Sunumu - 2
 
Metasploit El Kitabı
Metasploit El KitabıMetasploit El Kitabı
Metasploit El Kitabı
 
Open Source Soc Araçları Eğitimi 2020-II
Open Source Soc Araçları Eğitimi 2020-IIOpen Source Soc Araçları Eğitimi 2020-II
Open Source Soc Araçları Eğitimi 2020-II
 
BTRİSK Web Uygulama Güvenliği Denetimi Eğitim Sunumu
BTRİSK Web Uygulama Güvenliği Denetimi Eğitim SunumuBTRİSK Web Uygulama Güvenliği Denetimi Eğitim Sunumu
BTRİSK Web Uygulama Güvenliği Denetimi Eğitim Sunumu
 
Snort IPS(Intrusion Prevention System) Eğitimi
Snort IPS(Intrusion Prevention System) EğitimiSnort IPS(Intrusion Prevention System) Eğitimi
Snort IPS(Intrusion Prevention System) Eğitimi
 
Arp protokolu ve guvenlik zafiyeti
Arp  protokolu ve guvenlik zafiyetiArp  protokolu ve guvenlik zafiyeti
Arp protokolu ve guvenlik zafiyeti
 
Zararlı Yazılım Analizi Eğitimi Lab Kitabı
Zararlı Yazılım Analizi Eğitimi Lab KitabıZararlı Yazılım Analizi Eğitimi Lab Kitabı
Zararlı Yazılım Analizi Eğitimi Lab Kitabı
 
Beyaz Şapkalı Hacker CEH Eğitimi - Bölüm 4, 5, 6
Beyaz Şapkalı Hacker CEH Eğitimi - Bölüm 4, 5, 6Beyaz Şapkalı Hacker CEH Eğitimi - Bölüm 4, 5, 6
Beyaz Şapkalı Hacker CEH Eğitimi - Bölüm 4, 5, 6
 
Kurumsal Ağlarda Log İnceleme Yöntemiyle Saldırı Analizi
Kurumsal Ağlarda Log İnceleme Yöntemiyle Saldırı AnaliziKurumsal Ağlarda Log İnceleme Yöntemiyle Saldırı Analizi
Kurumsal Ağlarda Log İnceleme Yöntemiyle Saldırı Analizi
 
Nmap101 Eğitim Sunumu - Nmap Kullanım Kılavuzu
Nmap101 Eğitim Sunumu - Nmap Kullanım KılavuzuNmap101 Eğitim Sunumu - Nmap Kullanım Kılavuzu
Nmap101 Eğitim Sunumu - Nmap Kullanım Kılavuzu
 
BTRisk Android Mobil Uygulama Denetimi Eğitimi
BTRisk Android Mobil Uygulama Denetimi EğitimiBTRisk Android Mobil Uygulama Denetimi Eğitimi
BTRisk Android Mobil Uygulama Denetimi Eğitimi
 
Web Uygulama Güven(siz)liği
Web Uygulama Güven(siz)liğiWeb Uygulama Güven(siz)liği
Web Uygulama Güven(siz)liği
 
Beyaz Şapkalı Hacker CEH Eğitimi - Bölüm 1, 2, 3
Beyaz Şapkalı Hacker CEH Eğitimi - Bölüm 1, 2, 3Beyaz Şapkalı Hacker CEH Eğitimi - Bölüm 1, 2, 3
Beyaz Şapkalı Hacker CEH Eğitimi - Bölüm 1, 2, 3
 
Siber Güvenlik ve Etik Hacking Sunu - 10
Siber Güvenlik ve Etik Hacking Sunu - 10Siber Güvenlik ve Etik Hacking Sunu - 10
Siber Güvenlik ve Etik Hacking Sunu - 10
 
İleri Seviye Ağ Güvenliği Lab Kitabı
İleri Seviye Ağ Güvenliği Lab Kitabıİleri Seviye Ağ Güvenliği Lab Kitabı
İleri Seviye Ağ Güvenliği Lab Kitabı
 
Linux İşletim Sistemi - Güncelleme-2018
Linux İşletim Sistemi - Güncelleme-2018Linux İşletim Sistemi - Güncelleme-2018
Linux İşletim Sistemi - Güncelleme-2018
 

Similar to BTRisk X86 Tersine Mühendislik Eğitim Sunumu - Bölüm-1

Kurumsal Yazılım Geliştirme ve Visual Studio 2008
Kurumsal Yazılım Geliştirme ve Visual Studio 2008Kurumsal Yazılım Geliştirme ve Visual Studio 2008
Kurumsal Yazılım Geliştirme ve Visual Studio 2008mtcakmak
 
İleri Seviye T-SQL Programlama - Chapter 21
İleri Seviye T-SQL Programlama - Chapter 21İleri Seviye T-SQL Programlama - Chapter 21
İleri Seviye T-SQL Programlama - Chapter 21Cihan Özhan
 
Osman kurt & zahide aytar
Osman kurt & zahide aytarOsman kurt & zahide aytar
Osman kurt & zahide aytarOsman Kurt
 
cofaso Kullanım Kılavuzu
cofaso Kullanım Kılavuzucofaso Kullanım Kılavuzu
cofaso Kullanım KılavuzuVitorCordova
 
Algoritmalarve programlamai ders_1
Algoritmalarve programlamai ders_1Algoritmalarve programlamai ders_1
Algoritmalarve programlamai ders_1atasss
 
ARM Mimarisinde Exploit Geliştirme
ARM Mimarisinde Exploit GeliştirmeARM Mimarisinde Exploit Geliştirme
ARM Mimarisinde Exploit GeliştirmeSignalSEC Ltd.
 
Web Uygulamalarında Kaynak Kod Analizi - 1
Web Uygulamalarında Kaynak Kod Analizi - 1Web Uygulamalarında Kaynak Kod Analizi - 1
Web Uygulamalarında Kaynak Kod Analizi - 1Mehmet Ince
 
Office 2010 Araçları
Office 2010 AraçlarıOffice 2010 Araçları
Office 2010 AraçlarıEren Caner
 
Mühendislik problemlerinin bilgisayar ortamında sayısal analiz yöntemleriyle...
Mühendislik problemlerinin  bilgisayar ortamında sayısal analiz yöntemleriyle...Mühendislik problemlerinin  bilgisayar ortamında sayısal analiz yöntemleriyle...
Mühendislik problemlerinin bilgisayar ortamında sayısal analiz yöntemleriyle...Abdurrahman Tunç
 
İleri Seviye T-SQL Programlama - Chapter 02
İleri Seviye T-SQL Programlama - Chapter 02İleri Seviye T-SQL Programlama - Chapter 02
İleri Seviye T-SQL Programlama - Chapter 02Cihan Özhan
 
İleri Seviye Programlama 2
İleri Seviye Programlama 2İleri Seviye Programlama 2
İleri Seviye Programlama 2Caner Bovatekin
 

Similar to BTRisk X86 Tersine Mühendislik Eğitim Sunumu - Bölüm-1 (20)

Kurumsal Yazılım Geliştirme ve Visual Studio 2008
Kurumsal Yazılım Geliştirme ve Visual Studio 2008Kurumsal Yazılım Geliştirme ve Visual Studio 2008
Kurumsal Yazılım Geliştirme ve Visual Studio 2008
 
İleri Seviye T-SQL Programlama - Chapter 21
İleri Seviye T-SQL Programlama - Chapter 21İleri Seviye T-SQL Programlama - Chapter 21
İleri Seviye T-SQL Programlama - Chapter 21
 
delphi
delphidelphi
delphi
 
14
1414
14
 
delphi xe5
delphi xe5 delphi xe5
delphi xe5
 
Osman kurt & zahide aytar
Osman kurt & zahide aytarOsman kurt & zahide aytar
Osman kurt & zahide aytar
 
Visual Studio Developer Tools
Visual Studio Developer ToolsVisual Studio Developer Tools
Visual Studio Developer Tools
 
cofaso Kullanım Kılavuzu
cofaso Kullanım Kılavuzucofaso Kullanım Kılavuzu
cofaso Kullanım Kılavuzu
 
Sunu algo02
Sunu algo02Sunu algo02
Sunu algo02
 
yazılımmuh10.pptx
yazılımmuh10.pptxyazılımmuh10.pptx
yazılımmuh10.pptx
 
Algoritmalarve programlamai ders_1
Algoritmalarve programlamai ders_1Algoritmalarve programlamai ders_1
Algoritmalarve programlamai ders_1
 
ARM Mimarisinde Exploit Geliştirme
ARM Mimarisinde Exploit GeliştirmeARM Mimarisinde Exploit Geliştirme
ARM Mimarisinde Exploit Geliştirme
 
Web Uygulamalarında Kaynak Kod Analizi - 1
Web Uygulamalarında Kaynak Kod Analizi - 1Web Uygulamalarında Kaynak Kod Analizi - 1
Web Uygulamalarında Kaynak Kod Analizi - 1
 
Cisco packet tracer
Cisco packet tracer Cisco packet tracer
Cisco packet tracer
 
Office 2010 Araçları
Office 2010 AraçlarıOffice 2010 Araçları
Office 2010 Araçları
 
Mühendislik problemlerinin bilgisayar ortamında sayısal analiz yöntemleriyle...
Mühendislik problemlerinin  bilgisayar ortamında sayısal analiz yöntemleriyle...Mühendislik problemlerinin  bilgisayar ortamında sayısal analiz yöntemleriyle...
Mühendislik problemlerinin bilgisayar ortamında sayısal analiz yöntemleriyle...
 
ders bilgi
ders bilgiders bilgi
ders bilgi
 
Delphi 7
Delphi 7Delphi 7
Delphi 7
 
İleri Seviye T-SQL Programlama - Chapter 02
İleri Seviye T-SQL Programlama - Chapter 02İleri Seviye T-SQL Programlama - Chapter 02
İleri Seviye T-SQL Programlama - Chapter 02
 
İleri Seviye Programlama 2
İleri Seviye Programlama 2İleri Seviye Programlama 2
İleri Seviye Programlama 2
 

More from BTRisk Bilgi Güvenliği ve BT Yönetişim Hizmetleri

More from BTRisk Bilgi Güvenliği ve BT Yönetişim Hizmetleri (15)

Yazıcı Güvenliği
Yazıcı GüvenliğiYazıcı Güvenliği
Yazıcı Güvenliği
 
BTRISK ISO27001 UYGULAMA EGITIMI SUNUMU
BTRISK ISO27001 UYGULAMA EGITIMI SUNUMUBTRISK ISO27001 UYGULAMA EGITIMI SUNUMU
BTRISK ISO27001 UYGULAMA EGITIMI SUNUMU
 
Kali Linux Hakkında Herşey
Kali Linux Hakkında HerşeyKali Linux Hakkında Herşey
Kali Linux Hakkında Herşey
 
BTRisk iOS Mobil Uygulama Denetimi Eğitimi
BTRisk iOS Mobil Uygulama Denetimi EğitimiBTRisk iOS Mobil Uygulama Denetimi Eğitimi
BTRisk iOS Mobil Uygulama Denetimi Eğitimi
 
Unix Denetim Dokümanı
Unix Denetim DokümanıUnix Denetim Dokümanı
Unix Denetim Dokümanı
 
BTRisk Yazılım Güvenliği Yönetimi Eğitimi
BTRisk Yazılım Güvenliği Yönetimi EğitimiBTRisk Yazılım Güvenliği Yönetimi Eğitimi
BTRisk Yazılım Güvenliği Yönetimi Eğitimi
 
BTRisk Android Uygulamalara Malware Yerleştirme Sunumu
BTRisk Android Uygulamalara Malware Yerleştirme SunumuBTRisk Android Uygulamalara Malware Yerleştirme Sunumu
BTRisk Android Uygulamalara Malware Yerleştirme Sunumu
 
BTRisk ISO 27001:2013 Bilgilendirme ve İç Denetim Eğitimi Sunumu
BTRisk ISO 27001:2013 Bilgilendirme ve İç Denetim Eğitimi SunumuBTRisk ISO 27001:2013 Bilgilendirme ve İç Denetim Eğitimi Sunumu
BTRisk ISO 27001:2013 Bilgilendirme ve İç Denetim Eğitimi Sunumu
 
Bilgi Güvenliği Farkındalık Eğitimi Sunumu
Bilgi Güvenliği Farkındalık Eğitimi SunumuBilgi Güvenliği Farkındalık Eğitimi Sunumu
Bilgi Güvenliği Farkındalık Eğitimi Sunumu
 
BTRisk Adli Bilişim Eğitimi Sunumu
BTRisk Adli Bilişim Eğitimi SunumuBTRisk Adli Bilişim Eğitimi Sunumu
BTRisk Adli Bilişim Eğitimi Sunumu
 
BTRİSK Web Uygulama Güvenliği Denetimi Eğitimi
BTRİSK Web Uygulama Güvenliği Denetimi EğitimiBTRİSK Web Uygulama Güvenliği Denetimi Eğitimi
BTRİSK Web Uygulama Güvenliği Denetimi Eğitimi
 
BTRWATCH ISO27001 Yazılımı
BTRWATCH ISO27001 YazılımıBTRWATCH ISO27001 Yazılımı
BTRWATCH ISO27001 Yazılımı
 
Jmeter ile uygulama katmanında yük testi gerçekleştirme
Jmeter ile uygulama katmanında yük testi gerçekleştirmeJmeter ile uygulama katmanında yük testi gerçekleştirme
Jmeter ile uygulama katmanında yük testi gerçekleştirme
 
ISO 27001:2013 versiyonu ile gelen değişiklikler
ISO 27001:2013 versiyonu ile gelen değişikliklerISO 27001:2013 versiyonu ile gelen değişiklikler
ISO 27001:2013 versiyonu ile gelen değişiklikler
 
Android Uygulamaların Tersine Mühendislik Yöntemi ile İncelenmesi
Android Uygulamaların Tersine Mühendislik Yöntemi ile İncelenmesiAndroid Uygulamaların Tersine Mühendislik Yöntemi ile İncelenmesi
Android Uygulamaların Tersine Mühendislik Yöntemi ile İncelenmesi
 

BTRisk X86 Tersine Mühendislik Eğitim Sunumu - Bölüm-1

  • 2. BTRİSK HAKKINDA TANIŞMA Pentest & BT Denetimi ISO27001 Danışmanlık Hizmetleri BG Operasyon Hizmetleri
  • 3. Göreviniz, Deneyiminiz ve Eğitimden Beklentileriniz Nelerdir? TANIŞMA
  • 5. TERSİNE MÜHENDİSLİK NEDİR? GENEL ANLAMIYLA TERSİNE MÜHENDİSLİK; • Üretilmiş bir sistemin nasıl çalıştığının analiz edilmesidir. Bunun için sistemin bütünlüğünü kaybetmeyecek en küçük birimlerine ayrıştırılması ve bu birimler arasındaki etkileşimlerin anlaşılması gerekir. MAKİNA DİLİNE DERLENMİŞ YAZILIMLAR İÇİN TERSİNE MÜHENDİSLİK; • Assembly dili içindeki üst seviye (high level) algoritmaların ve veri yapılarının keşfidir. "ALGORİTMALAR + VERİ YAPILARI = PROGRAMLAR" Niklaus Wirth (Pascal v.d. uygulama dillerinin tasarımcısı)
  • 6. TERSİNE MÜHENDİSLİK NEDİR? DERLEME LİNKLEME TERSİNE MÜHENDİSLİK
  • 7. NEDEN İHTİYACIMIZ OLABİLİR? Tersine analize neden ihtiyaç olabilir dendiğinde genellikle yasa dışı hedefler akla gelir. Ancak bu yönteme yasal nedenlerle de ihtiyaç duyabiliriz: • Bir zararlı yazılımın amaçlarının anlaşılması, bulaştığı diğer sistemlerin tespiti için işaretlerin [Indicators of Compromise – IoC] belirlenmesi • Uygulama güvenlik testleri sırasında; • Uygulamanın içinde gömülü hassas verilerin incelenmesi • Kullanılmayan ancak kritik olabilecek fonksiyonların tespit edilmesi • Hata alan veya çalışmayan bir uygulama ile ilgili problemin tespit edilmesi
  • 8. EĞİTİMİN KAPSAMI Tersine mühendisliğin 2 temel aracı; • Dinamik Analiz ve • Statik Analiz'dir. Ancak eğitimimizin odaklandığı analiz yöntemi STATİK ANALİZ yöntemi olacaktır. Bu dinamik analiz yöntemini hiç kullanmayacağız anlamına gelmiyor. Ancak kullanacağımız uygulamanın hataya yer vermeyecek doğası, deneme yanılma yöntemini dolayısıyla da dinamik analizi daha az kullanışlı kılacak. Eğitimin ana hedefi X86 Mimarisi ve Assembly Dili üzerinde yetkinlik kazanmak olacaktır.
  • 9. ALGORİTMALAR Assembly koduna baktığımızda tanımaya alışmamız gereken algoritmalara örnekler: • Atama [Assignment] "=" • Aritmetik Operatörler [Arithmetic Operators] "+,-,*,/,|,& v.d." • Koşullar [Conditionals] o if, else o switch .. case • Döngüler [Loops] o for o do .. while / while • Özyineleme [Recursion] • Sıralama [Sorting] • v.d.
  • 10. VERİ TİPLERİ VE YAPILARI Assembly instruction'larını okurken tanımamız gereken veri tiplerine örnekler • pointer [X86 mimaride 4 byte'lık veri alanı, belli bir veri alanının adresini içerir] • integer [X86 mimaride 4 byte'lık veri alanı] • char [1 byte'lık veri alanı] • C string'i [null "x00" karakterle biten bir veri bloğuna işaret eden Pointer] • array [herhangi bir veri tipinden veri alanlarının oluşturduğu bir dizi] • struct [2 veya daha fazla veri tipini barındıran veri bloğu] • linked list [barındırdığı link pointer veri tipleri ile birbirine bağlanan veri yapılarından oluşan dizi] • object [class'lardan oluşturulmuş veri yapıları], v.d.
  • 12. DERLEME, YÜKLEME VE LİNKLEME Kaynak Kod 1 Kaynak Kod 2 Kaynak Kod 3 Kod Üretimi Sözdizim Analizi Ara Kod Üretimi Sözcük Analizi Optimi- zasyon DERLEME Object Dosyası 1 Object Dosyası 2 Object Dosyası 3
  • 13. DERLEME, YÜKLEME VE LİNKLEME LİNKLEME Object Dosyası A Başlıklar Kod Bölümü 1 Kod Bölümü 2 Veri Bölümü Diğer Bölüm Object Dosyası B Başlıklar Kod Bölümü Veri Bölümü Diğer Bölüm 1 Diğer Bölüm 2 EXE veya DLL Başlıklar Kod Bölümü 1A Kod Bölümü 2A Kod Bölümü B Veri Bölümü A Veri Bölümü B Diğer Bölüm A Diğer Bölüm 1B Diğer Bölüm 2B
  • 14. DERLEME, YÜKLEME VE LİNKLEME Uygulama.exe Kod Veri Import ABC.dll Import DEF.dll ABC.dll Kod Veri .... DEF.dll Kod Veri .... SABİT DİSK Sanal Hafıza’sı Kernel Space User Space Uygulama.exe ABC.dll DEF.dll OS LOADER Uygulama.exe’nin
  • 15. DERLEME, YÜKLEME VE LİNKLEME Fiziksel Hafıza Proses A’nın Sanal Hafıza Alanı Proses B’nin Sanal Hafıza Alanı Proses A Kod Proses B Kod Proses A Veri (Data) Proses B Veri (Data) DLL A Kod DLL B Kod Proses A Kod 2 DLL A Kod DLL B Kod Proses B Veri (Data) Proses B Kod Proses A Veri (Data) Proses A Kod Proses A Kod 2 DLL A Kod DLL B Kod
  • 16. PORTABLE EXECUTABLE (PE) #include<stdio.h> int add(int prm1, int prm2) { int result; result = prm1 + prm2; return result; } int main() { int i = 10; int j = 20; int sonuc; sonuc = add(i, j); printf("Sonuc = %d", sonuc); getchar(); } PE dosya formatını açıklamak için yukarıda gördüğünüz basit bir C uygulamasını kullanacağız.
  • 17. PORTABLE EXECUTABLE (PE) IMAGE DOS HEADER PE formatında bulunan ilk bölümde modern Windows sistemleri için çok da önemli olmayan bilgiler yer alır. PEView
  • 18. PORTABLE EXECUTABLE (PE) IMAGE DOS HEADER Bu bölümün başında da ASCII "MZ" karakterlerinden oluşan bir signature bölümü yer alır. Bu harfler MSDOS işletim sisteminin mimarlarından Mark Zbikowski'nin ad ve soyadının ilk harfleridir.
  • 19. PORTABLE EXECUTABLE (PE) IMAGE DOS HEADER Bu bölümde bizim için önemli tek alan en sonda yer alan ve NT exe başlığının başladığı alanın dosya içindeki offset'ini içeren bölümdür.
  • 20. PORTABLE EXECUTABLE (PE) IMAGE DOS HEADER • Soru: Madem içinde işimize yarayan hiçbir şey yok neden bu bölüm var? • Cevap: Çünkü; Microsoft bu dosya formatının MSDOS işletim sistemi üzerinde çalıştırıldığında hata üretmek yerine bir mesaj vererek sonlanmasını istemiştir. [Ne demek istediğimiz bir sonraki sayfada açıklığa kavuşacaktır.]
  • 21. PORTABLE EXECUTABLE (PE) MS-DOS Stub Program Burada gördüğümüz bölüm içinde Real Mode (16 bitlik) bir DOS işletim sistemi kodu içerir. Özetle bu bölümdeki DOS uygulamasının tek işlevi bu dosyanın bir DOS uygulaması olmadığını (ironik biçimde aslında biraz öyle olmasına rağmen) belirtmek ve uygulamayı sonlandırmaktır.
  • 22. PORTABLE EXECUTABLE (PE) IMAGE NT HEADERS [Signature] Dosyanın geri kalanının hangi formatta olduğunu belirten bölüm bu alandır. Günümüz Windows uygulamalarında bu alan NT signature olarak belirtilmektedir.
  • 23. PORTABLE EXECUTABLE (PE) IMAGE NT HEADERS [Signature] Signature alanında olabilecek diğer değerler aşağıdaki gibidir: • #define IMAGE_DOS_SIGNATURE 0x5A4D // MZ • #define IMAGE_OS2_SIGNATURE 0x454E // NE • #define IMAGE_OS2_SIGNATURE_LE 0x454C // LE • #define IMAGE_NT_SIGNATURE 0x00004550 // PE00 Not: OS/2 Microsoft'un 90'lı yılların başlarında IBM ile birlikte geliştirdiği bir işletim sisteminin adıdır.
  • 24. PORTABLE EXECUTABLE (PE) IMAGE FILE HEADER Uygulama kodunun uyumlu olduğu işlemci mimarisini belirtir
  • 25. PORTABLE EXECUTABLE (PE) IMAGE FILE HEADER Dosya içinde kaç section bulunduğunu belirtir. Aşağıda görülen section header'lar bu sayıya göre parse edilecektir.
  • 26. PORTABLE EXECUTABLE (PE) IMAGE FILE HEADER Saldırgana dair az da olsa fikir verebilecek bu alan zararlı uygulamanın ne zaman linklendiğini belirtir.
  • 27. PORTABLE EXECUTABLE (PE) IMAGE FILE HEADER Optional Header alanının büyüklüğü bu alandan sonra gelecek section header'ların başlangıç adresini bulmak için kullanılır.
  • 28. PORTABLE EXECUTABLE (PE) IMAGE FILE HEADER Bu bölümde dosyanın çalıştırılabilir bir dosya olduğunu anlayabiliyoruz. Eğer bu dosya bir DLL olsaydı IMAGE_FILE_EXECUTABLE_IMAGE yerine IMAGE_FILE_DLL işareti aktif olacaktı.
  • 29. PORTABLE EXECUTABLE (PE) IMAGE OPTIONAL HEADER Optional Header ile ilgili söylenmesi gereken ilk şey aslında optional olmadığı, çünkü içinde uygulamanın belleğe yüklenmesi ve çalıştırılması ile ilgili kritik bilgiler barındırıyor. Bunlardan "Address of Entry Point" uygulamanın çalıştırılacak ilk instruction'ının RVA adresine işaret eder.
  • 30. PORTABLE EXECUTABLE (PE) Adres of Entry Point Hakkında Bu ifade yanlış anlaşılmaya müsait olacağı için şu açıklamayı yapmakta fayda bulunmaktadır: • Uygulama modülü içinde çalıştırılacak ilk kod zannedilebileceği gibi "main()" fonksiyonunun ilk instruction'ı değildir. "main()" fonksiyonu çağrılmadan önce derleyici tarafından yazılım geliştiricinin seçtiği subsystem'e göre çevresel koşulları düzenleyen kodlar uygulamaya eklenmektedir. • Immunity Debugger gibi bir binary debugger ile bir uygulamayı başlattığınızda debugger'ın ilk breakpoint'i koyduğu yer ilk çalışan kod olan NTDLL kütüphanesi içindeki bir initial stub (kod parçası)'dır.
  • 31. PORTABLE EXECUTABLE (PE) Adres of Entry Point Hakkında (devamı) • NTDLL'deki bu initial stub önce belleğe yüklenen diğer kütüphanelerin entry point'lerini çalıştırır, en son da uygulamanın ilk instruction'ını çalıştırır. • Özetle uygulamanın "main()" fonksiyonundan önce tüm DLL'lerin initial kodları, bunlardan sonra da uygulamanın kendi hazırlık kodları çalışır.
  • 32. PORTABLE EXECUTABLE (PE) IMAGE OPTIONAL HEADER Image Base alanı uygulama belleğe yüklendiğinde yerleştirilmeyi arzu ettiği baz sanal adresi (Virtual Address – VA) ifade eder. Biraz önce uygulama başlangıç adresi için RVA kavramını kullanmıştık, burada ise VA kavramından söz ediyoruz. Bu noktada sanal adres kavramını ve adres kavramlarını açıklamakta fayda bulunmaktadır.
  • 33. PORTABLE EXECUTABLE (PE) Modül Kavramı Nedir? Bir çalıştırılabilir dosya OS loader tarafından belleğe yüklenirken bu dosyanın kullanacağı kütüphaneler de bu prosesin adres alanına haritalanır (map'lenir). Yüklenen çalıştırılabilir dosyanın kendisi (PE dosyamız) ve yüklenen kütüphaneler (DLL'ler)'in her birisi modül olarak adlandırılırlar.
  • 34. PORTABLE EXECUTABLE (PE) Modül Kavramı Nedir? PE modülümüzün bellekteki imajı Uygulamamızın kullandığı DLL modülleri Uygulamamızın adres alanında kendi kod ve verileri bulunduğu gibi kullandığı kütüphanelerin modülleri de hazır bulunmaktadır.
  • 35. PORTABLE EXECUTABLE (PE) Yükleme, Fiziksel ve Mantıksal Adresler PE Dosyamızın disk üzerindeki hali. PEView bizim için başlangıç adresinin VA cinsinden değerini belirtiyor.
  • 36. PORTABLE EXECUTABLE (PE) Yükleme, Fiziksel ve Mantıksal Adresler PE Dosyamızın bellek üzerindeki hali.
  • 37. PORTABLE EXECUTABLE (PE) Adres Kavramları ÖNEMLİ: Bir PE dosyası çalıştırılmak üzere OS Loader tarafından belleğe yüklenirken PE dosyasında gördüğünüz veriler ve yerleri büyük oranda değişmeden belleğe aktarılır. • File Offset: PE dosyasındaki verinin disk üzerindeki dosyada bulunduğu offset değerini belirtir. • Relative Virtual Address [RVA]: PE dosyasında gördüğümüz verinin belleğe yüklendiğinde modülün yüklendiği baz sanal adresten itibaren bulunduğu offset değerini belirtir. • Virtual Address [VA]: PE dosyasında gördüğümüz verinin belleğe yüklendiğinde bulunacağı sanal adrestir.
  • 38. PORTABLE EXECUTABLE (PE) Adres Kavramları [File Offset] .text section'ının Disk üzerindeki dosya içindeki offset adresi
  • 39. PORTABLE EXECUTABLE (PE) Adres Kavramları - RVA [Relative Virtual Address] .text section'ının bellekte modülün başlangıç adresine göre offset adresi
  • 40. PORTABLE EXECUTABLE (PE) Adres Kavramları - VA [Virtual Address] .text section'ının bellekte bulunacağı sanal adres
  • 41. PORTABLE EXECUTABLE (PE) Adres Kavramları – Bellekten Görüntü .text section'ının bellekte disassemble edilmiş hali [adres bilgilerinin yanında opcode'ları görebilirsiniz]
  • 42. PORTABLE EXECUTABLE (PE) IMAGE OPTIONAL HEADER Section'ların belleğe yerleştiklerinde align olmaları gereken adres periyodu. Yani her section'ın Virtual Adresi Hex 1000 byte'ın katları olan adreslerden başlayabilir. Bu nedenle ".text" section'ı disk üzerinde 0x400 offset'te iken belleğe yüklendiğinde 0x401000 VA adresinden başlamaktaydı.
  • 43. PORTABLE EXECUTABLE (PE) IMAGE OPTIONAL HEADER Section'ların disk üzerindeki hallerinin (raw hallerinin) başlaması gereken offset adreslerinin hangi sayının katı olması gerektiğini belirtir. Bu nedenle section sonu bu sayının katına erişmek için "0x00" byte'ları ile pad'lenir.
  • 44. PORTABLE EXECUTABLE (PE) IMAGE OPTIONAL HEADER ".text" section'ının sonunda 0x200 byte'ın katı olacak biçimde yapılmış 0x00 byte'larıyla yapılmış padding'i görebilirsiniz. Son adres: 0x401E00
  • 45. PORTABLE EXECUTABLE (PE) IMAGE OPTIONAL HEADER DLL Characteristics alanı isminde DLL geçse de tüm PE dosyalarıyla ilgilidir. Daha sonra örneğini uygulayacağımız ASLR desteği, DEP desteği, v.d. özellikleri modülümüzün taşıyıp taşımadığını belirtir. Bu örnekte ASLR desteğimiz bulunmamaktadır.
  • 46. PORTABLE EXECUTABLE (PE) IMAGE OPTIONAL HEADER Data Directories dizisi OS loader'ın işlevini yerine getirebilmesi için önemli çeşitli bilgileri barındırır. Bu örnekte IAT'nin yerini ve büyüklüğünü görüyoruz.
  • 47. PORTABLE EXECUTABLE (PE) IMAGE OPTIONAL HEADER IAT Data Directory'sinin RVA adresine gittiğimizde IAT'nin içeriğine ulaşabiliriz.
  • 48. PORTABLE EXECUTABLE (PE) PE Dosya Organizasyonu Temel Referanslar PE dosya organizasyonunun içinde OS loader'ın görevini yerine getirebilmesi için kod / veri alanlarını ve özelliklerini tanımlayan 2 tür referans bulunmaktadır: 1. Section Header'ları: Section'ların dosya içindeki yerleri, disk üzerinde ve bellekte kaplayacakları alan büyüklükleri ve erişim kuralları gibi özellikleri tanımlarlar [henüz değinmedik]. 2. Data Directory kayıtları: Import Address Table gibi, Base Relocation Table (modül Image Base alanında belirtilen adrese oturmamışsa değişmesi gereken adreslerin yerleri) gibi OS loader için önemli ve farklı section'ların içlerinde yer alan veri alanlarının RVA adreslerini ve büyüklüklerini tanımlarlar.
  • 49. PORTABLE EXECUTABLE (PE) IMAGE OPTIONAL HEADER Eğer bir DLL yazmış olsaydık bir takım fonksiyonları da Export edecektik. Bu örnek basit bir EXE uygulaması olduğu için Export Table RVA adresi 0 olarak görülüyor. Bu bilgiye özellikle shellcode yazarken çok ihtiyacımız olacaktır, çünkü shellcode uygulamaları bu veri yapılarını kullanarak bellekteki fonksiyon adreslerini tespit ederler.
  • 50. PORTABLE EXECUTABLE (PE) IMAGE SECTION HEADER Data Directory'lerle birlikte 2 önemli referans noktasından birisi olan Section Header'ların ilk 8 byte'ı section ismi için kullanılır. Belli section'lar için derleyicilerin kullandığı geleneksel isimler olsa da section'ın Characteristics alanı belirleyicidir. Yani isimlerin hiçbir önemi yoktur makine (işlemci) için.
  • 51. PORTABLE EXECUTABLE (PE) IMAGE SECTION HEADER Size of Raw Data bu section'ın disk üzerindeki dosya içinde kapladığı alanı belirtir. Image Optional Header'daki File Alignment değerini hatırlarsanız Raw Data boyutunun 0x200 byte'ın katları olması gerektiğini bilebiliriz. Derleyici bunu sağlamak için section'ın son bölümlerini 0x00 ile pad'lemeli.
  • 52. PORTABLE EXECUTABLE (PE) IMAGE SECTION HEADER Görüldüğü gibi 0xCC3 offset'inden 0xE00 offset'ine kadar olan alan 0x00 ile pad'lenmiş.
  • 53. PORTABLE EXECUTABLE (PE) IMAGE SECTION HEADER Virtual Size değeri bu section'ın uygulama belleğe yüklendiğinde bellekte kaplayacağız alanı ifade ediyor. Bu section için bellekteki alanın diskteki alanından daha küçük olduğunu görüyoruz. Ancak UPX örneğinde olduğu gibi bunun tersi de mümkün [UPX diskte hiç yer kaplamayan bir section için bellekte geniş bir alan istemekteydi].
  • 54. PORTABLE EXECUTABLE (PE) IMAGE SECTION HEADER Padding öncesinde son verinin 0xCC3 adresinde bulunduğunu .text section'ının son bölümüne göz attığımızda görebiliriz.
  • 55. PORTABLE EXECUTABLE (PE) IMAGE SECTION HEADER RVA adres kavramını daha önce konuşmuştuk, bu section'ın EXE modülünün başlangıç adresinden itibaren 0x1000 offset'ten başlatılacağını bu alandan anlıyoruz. Yine Image Optional Header'dan hatırlarsak bu değerin 0x1000 olan section alignment değerinin katı olması gerektiğini söyleyebiliriz.
  • 56. PORTABLE EXECUTABLE (PE) IMAGE SECTION HEADER .text section'ının adres formatını File Offset'ten RVA'e değiştirdiğimizde PEView bize olması gereken 0x1000 değerini gösteriyor.
  • 57. PORTABLE EXECUTABLE (PE) IMAGE SECTION HEADER Section'ın bellekte başlayacağı adres ile disk üzerinde bulunduğu File Offset değeri farklı. Burada bu section'ın 0x400 File Offset'inde bulunduğunu anlıyoruz. Bellekte 0x400 ve 0x1000 offset'leri arasındaki boşluk ne olacak derseniz bellekteki adreslerini Virtual adresler olduğunu ve bu adreslerin fiziksel karşılıklarının farklı olduklarını hatırlamamız gerekir. Yani aslında bir boşluk olmayacak, sadece bu sanal adresler için herhangi bir fiziksel alan kullanılmayacaktır.
  • 58. PORTABLE EXECUTABLE (PE) IMAGE SECTION HEADER .text section'ının adres formatını File Offset'e değiştirdiğimizde PEView bize 0x400 değerini gösteriyor.
  • 59. PORTABLE EXECUTABLE (PE) IMAGE SECTION HEADER Section isimlerinin aslında işlemci için hiçbir anlamı olmadığını, section'ın özellikleri hakkında Characteristics alanının belirleyici olduğunu daha önce söylemiştik. Geleneksel olarak uygulamanın kod bölümlerinin yerleştirildiği .text section'ının Execute hakkı uygulama belleğe yüklenirken bu section için ayrılan memory page'lerine atanacaktır. Yani bu alanlardaki veriler kod olarak çalıştırılabilecektir.
  • 60. PORTABLE EXECUTABLE (PE) IMAGE SECTION HEADER Yine geleneksel olarak .rdata alanı Read Only verilerin (yani constant string v.d. veri tiplerinin) saklandığı section'dır. Tabi yine bu özellik aslında Characteristics alanı tanımlarından gelmektedir.
  • 61. PORTABLE EXECUTABLE (PE) IMAGE SECTION HEADER .data alanı belli bir alanı kaplayan ancak değiştirilebilecek Global değişkenlerin tutulması için kullanılan alandır. Dolayısıyla bu alana yazma (Write) hakkı da verilmiştir.
  • 62. PORTABLE EXECUTABLE (PE) IMAGE SECTION HEADER Resource section'ı diğerlerinden biraz farklı. Diğer section'lar da kendi içlerinde bazı özel veri yapıları barındırıyor (ör: IAT – Import Address Table, Export Table gibi), ancak .rsrc section'ı bir bütün olarak bir directory yapısına sahip, yani tek bir genel veri yapısına sahip.
  • 63. PORTABLE EXECUTABLE (PE) IMAGE SECTION HEADER Basit PE dosyamızda tek bir resource kaydı var: MANIFEST
  • 64. PORTABLE EXECUTABLE (PE) IMAGE SECTION HEADER Özellikle dropper (yani resource section'ından dosyaları alıp diske bağımsız dosyalar olarak yazma) fonksiyonalitesine sahip zararlıları incelerken bu alana özel bir araç kullanmakta fayda var: Resource Hacker. PEView'ın veriyi Raw formatta göstermesi bize yeterli desteği vermiyor.
  • 65. DERLEYİCİLER ARASINDAKİ FARKLAR • Tüm derleyiciler derledikleri kodun üzerinde çalışacağı makina mimarisine uygun kod üretmek zorundadırlar. • Ancak bazı alanlarda kod üretme şekilleri birbirlerinden farklılaşabilir. Örneğin; • "X86 Mimarisine Giriş" bölümünde inceleyeceğimiz uygulama Visual Studio ile derlenmiş bir uygulama ve bu bu derleyici fonksiyon parametrelerini stack'e "PUSH" instruction'ı ile yazıyor. • Tersine mühendislik egzersizlerini yapmak için kullandığımız uygulama ise Dev-C++ ile derlenmiş bir uygulama. Bu derleyici ise fonksiyon parametrelerini ESP register'ının işaret ettiği alana yerleştirmeyi tercih ediyor [egzersizleri yaparken bu konu netleşecektir].
  • 66. DERLEYİCİLER ARASINDAKİ FARKLAR • İnceleyeceğimiz bir uygulamanın derleyicisini tahmin etmek için Detect It Easy veya benzeri bir uygulamadan faydalanabiliriz.
  • 68. X86 MİMARİSİNE GİRİŞ İNCELEYECEĞİMİZ UYGULAMA PE dosya formatını da inceleme için kullandığımız bu basit C uygulamasından derlenmiş kodu Immunity Debugger üzerinde incelerken temel X86 bilgilerine değineceğiz.
  • 69. X86 MİMARİSİNE GİRİŞ ANA KONULAR VE KAVRAMLAR Daha Önce Değindiklerimiz • Derleme ve linkleme • OS Loader'ın uygulamayı belleğe yüklemesi • Executable imajı, DLL modülleri, Stack ve Heap alanlarının bellekteki konumları [ASLR konusuyla bağlantıları] • Virtual Address kavramı
  • 70. X86 MİMARİSİNE GİRİŞ ANA KONULAR VE KAVRAMLAR (DEVAMI) Bu Bölümde Değineceklerimiz • Register'lar ve kullanım amaçları • X86 instruction set'i • Stack alanının kullanımı [fonksiyon çağırma, fonksiyon içindeki ve fonksiyondan çıkış işlemleri sırasındaki olaylar] • Calling conventions [fonksiyon çağırma sırasında parametrelerin fonksiyona aktarım yöntemleri, fonksiyon dönüşünde stack'i temizleme görevleri]
  • 71. X86 MİMARİSİNE GİRİŞ X86 hakkındaki teorik bilgiler üzerinde daha sonrak konuşmak üzere, öncelikle uygulamamızın Makine Kodu seviyesindeki işleyişini inceleyelim. Öncelikle main() fonksiyonu içindeki ilk instruction'ın adresini öğrenmek için Visual Studio'nun "Go To Assembly" özelliğini kullanacağız.
  • 72. X86 MİMARİSİNE GİRİŞ Visual Studio'da Disassembly view'ına geçtiğimizde derleyicinin üreteceği Assembly kodlarının yanı sıra bunların adreslerini de görüyoruz. Bu bilgiye şu nedenle ihtiyacımız var: Derleyiciler kod üretmeye doğrudan main() fonksiyonundan başlamazlar ve Address of Entry Point'te main() fonksiyonuna işaret etmez. Ancak bizim X86 mimarisini anlama amaçlı incelememizi main() fonksiyonundan başlatmamız lazım. İlk instruction olan "push ebp" instruction'ının adresi 0x401060
  • 73. X86 MİMARİSİNE GİRİŞ Uygulama belleğe yüklendiğinde de bu adreste olacağından emin olabilmek için ASLR'ı bu ayarlarla etkisiz hale getirdik.
  • 74. X86 MİMARİSİNE GİRİŞ Address of Entry Point'e koyduğumuz breakpoint [0x401060] sonrası bir kaç defa F9 tuşuna basılarak main() fonksiyonunun başına geliyoruz.
  • 75. X86 MİMARİSİNE GİRİŞ main() fonksiyonunun ilk instruction'ları "function prologue" adı da verilen önceki fonksiyon frame pointer'ın saklanması ve mevcut stack pointer'ın yeni fonksiyonun frame pointer'ı olarak belirlenmesidir.
  • 76. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] STACK DEĞİŞEN REGISTER'LAR ESP 0x0018FF40 ESP Yüksek Adres Düşük Adres Buradaki stack gösterimimiz ile Immunity Debugger'ın stack penceresindeki büyüme yönleri farklı, bu nedenle biraz kafanız karışabilir !
  • 77. X86 MİMARİSİNE GİRİŞ "function prologue"un ikinci adımında mevcut stack pointer [ESP] main() fonksiyonunun stack base pointer'ı [EBP] olarak atanıyor.
  • 78. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] STACK EBP 0x0018FF40 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 79. X86 MİMARİSİNE GİRİŞ main() fonksiyonunun lokal değişkenleri için stack'te 12 byte'lık [0x0C] yer ayrılıyor.
  • 80. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] XXXXXXXX XXXXXXXX XXXXXXXX STACK ESP 0x0018FF34 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 81. X86 MİMARİSİNE GİRİŞ [EBP-8] adresindeki lokal değişkene 10 [0x0A] değeri atanıyor.
  • 82. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] XXXXXXXX 0x0000000A XXXXXXXX STACK ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 83. X86 MİMARİSİNE GİRİŞ [EBP-4] adresindeki lokal değişkene 20 [0x14] değeri atanıyor.
  • 84. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX STACK ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 85. X86 MİMARİSİNE GİRİŞ [EBP-4] adresindeki lokal değişken EAX register'ına atanıyor.
  • 86. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX STACK ESP EAX 0x00000014 DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 87. X86 MİMARİSİNE GİRİŞ EAX register'ının değeri Stack'e push ediliyor. Bu değer "add" fonksiyonu için bir parametre olarak kullanılacak.
  • 88. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2]STACK ESP ESP 0x0018FF30 DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 89. X86 MİMARİSİNE GİRİŞ [EBP-8] adresindeki lokal değişken ECX register'ına atanıyor.
  • 90. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2]STACK ESP ECX 0x0000000A DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 91. X86 MİMARİSİNE GİRİŞ ECX register'ının değeri Stack'e push ediliyor. Bu değer "add" fonksiyonu için bir diğer parametre olarak kullanılacak.
  • 92. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] STACK ESP ESP 0x0018FF2C DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 93. X86 MİMARİSİNE GİRİŞ Immunity Debugger debug sembollerine sahip olduğu bir executable için bize fonksiyon adı ve bu fonksiyona verilen parametrelerle ilgili bilgi sağlıyor.
  • 94. X86 MİMARİSİNE GİRİŞ "call add" instruction'ı çalıştığında EIP değeri add fonksiyonuna işaret edecek şekilde değişiyor, ancak main() fonksiyonu içindeki bir sonraki instruction'ın adresi stack'e yazılıyor.
  • 95. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] STACK ESP ESP 0x0018FF28 DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 96. X86 MİMARİSİNE GİRİŞ add() fonksiyonunun prologue'unın ilk instruction'ı çalıştığında main() fonksiyonunun stack base pointer'ı stack'e yazılıyor.
  • 97. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] STACK ESP ESP 0x0018FF24 DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 98. X86 MİMARİSİNE GİRİŞ add() fonksiyonunun prologue'unın ikinci instruction'ı çalıştığında ESP register'ının değeri add() fonksiyonunun stack base pointer'ına [EBP] yazılıyor.
  • 99. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] STACK ESP EBP 0x0018FF24 DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 100. X86 MİMARİSİNE GİRİŞ add() fonksiyonu lokal değişkenler için sadece 4 byte'lık bir alan kullandığından "push ecx" instruction'ı ile stack'te yeterli alan ayrılmış oluyor.
  • 101. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] XXXXXXXX STACK ESP ESP 0x0018FF20 DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 102. X86 MİMARİSİNE GİRİŞ add() fonksiyonunun stack'te hazır bulunan birinci parametresi [EAX] register'ına atanıyor.
  • 103. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] XXXXXXXX STACK ESP EAX 0x0000000A DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 104. X86 MİMARİSİNE GİRİŞ add() fonksiyonunun stack'te hazır bulunan ikinci parametresi [EAX] register'ına [add] instruction'ı ile ekleniyor.
  • 105. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] XXXXXXXX STACK ESP EAX 0x0000001E DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 106. X86 MİMARİSİNE GİRİŞ [EAX] register'ının değeri stack'te add() fonksiyonu için ayrılmış 4 byte'lık lokal değişken alanına atanıyor. Uygulamamızı optimizasyon ayarları ile derlemiş olsaydık muhtemelen bu adımı görmeyecektik. Çünkü zaten return değeri [EAX] register'ı ile döndürülecek.
  • 107. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 108. X86 MİMARİSİNE GİRİŞ Bu adımda gereksiz bir biçimde lokal değişken tekrar [EAX] register'ına atanıyor. Ancak register değeri zaten aynı olduğu için değişmiyor.
  • 109. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 110. X86 MİMARİSİNE GİRİŞ add() fonksiyonun epilogue'unun ilk adımında add() fonksiyonunun stack base pointer'ı [ESP] register'ına atanıyor. Bu adımda add() fonksiyonu için stack'ten almış olduğumuz alan geri veriliyor.
  • 111. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP 0x0018FF24 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 112. X86 MİMARİSİNE GİRİŞ add() fonksiyonun epilogue'unun ikinci adımında main() fonksiyonunun stack'te saklanmış olan [EBP] register değeri tekrar yükleniyor. pop instruction'ı ile birlikte stack de 4 byte daha azaltılmış oluyor.
  • 113. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK EBP 0x0018FF40 ESP 0x0018FF28 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 114. X86 MİMARİSİNE GİRİŞ "retn" instruction'ı çalıştığında stack'in en üstünde bulunan saklanmış [EIP] değeri "pop" edilecek ve uygulama akışı bu adresten devam edecektir.
  • 115. X86 MİMARİSİNE GİRİŞ "retn" instruction'ı çalıştığında sadece saklanmış EIP değerine atlamıyoruz aynı zamanda stack'de 4 byte küçültülmüş oluyor.
  • 116. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP 0x0018FF2C ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 117. X86 MİMARİSİNE GİRİŞ "add esp, 8" instruction'ı ile stack'te add() fonksiyon parametreleri için kullanmış olduğumuz 8 byte'lık alanı geri veriyoruz. Bu işlemde çağıran [caller] stack'i temizliyor.
  • 118. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP 0x0018FF34 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 119. X86 MİMARİSİNE GİRİŞ [EAX] register'ında bulunan toplama işlemi sonucu main() fonksiyonunun lokal değişkenine atanıyor.
  • 120. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 121. X86 MİMARİSİNE GİRİŞ Lokal değişkenimizde bulunan toplama sonucu [EDX] register'ına atanıyor.
  • 122. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK EDX 0x0000001E ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 123. X86 MİMARİSİNE GİRİŞ Optimizasyon uygulamadığımız için printf() fonksiyonunun ikinci parametresi olarak (parametreler yine sağdan sola doğru stack'e yazılıyor) [EDX] register'ında bulunan toplam değerini stack'e yazıyoruz (halbuki bu değer zaten stack'te mevcuttu)
  • 124. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x0000001E [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP 0x0018FF30 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres Buradaki Arg 2 printf()'in ikinci parametresi
  • 125. X86 MİMARİSİNE GİRİŞ Bu instruction'da printf() fonksiyonu için format string'in bulunduğu adresi stack'e yazıyoruz. Stack penceresinde bu değerin Sonuc = "%d" olduğunu görebiliriz.
  • 126. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x0000001E [Arg 2] 0x00403000 [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP 0x0018FF2C ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 127. X86 MİMARİSİNE GİRİŞ printf() fonksiyonu çağrılmadan önce konsol penceresini görünteleyelim ve henüz birşey yazılmadığını görelim.
  • 128. X86 MİMARİSİNE GİRİŞ printf fonksiyonunun içine girmeden "step over" şeklinde bu fonksiyonu çalıştırıyoruz, çünkü bu API fonksiyonunu incelemek istemiyoruz. Bu çağrıdan sonra Sonuc = 30 ifadesini görmemizin yanında ilginç olan bir nokta [EAX], [ECX] ve [EDX] register'larımızın değişmiş olması.
  • 129. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x0000001E [Arg 2] 0x00403000 [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK EAX 0x0018FF2C ECX 0x0018FF2C EDX 0x0018FF2CESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres "caller saved" registers kavramına "calling conventions" bölümünde değineceğiz.
  • 130. X86 MİMARİSİNE GİRİŞ printf() fonksiyonuna verilen parametreler için tüketilen stack alanı geri veriliyor.
  • 131. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x0000001E [Arg 2] 0x00403000 [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP 0x0018FF34 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 132. X86 MİMARİSİNE GİRİŞ getchar() API fonksiyonunun çalışabilmesi için konsol penceresinden bir girdi vermemiz gerekecek. Bu yüzden "step over" komutu ile bir instruction daha atlamaya çalıştıktan sonra konsolu tekrar ön plana alalım.
  • 133. X86 MİMARİSİNE GİRİŞ Konsol penceresinde "Enter" tuşuna bastıktan sonra getchar() fonksiyonu tamamlanarak dönüyor. [ECX] ve [EDX] register'larının değiştiğini gözlemliyoruz.
  • 134. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x0000001E [Arg 2] 0x00403000 [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ECX 0x683D60B0 EDX 0x0000000A ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 135. X86 MİMARİSİNE GİRİŞ main() fonksiyonundan çıkmadan önce [EAX] register'ı return değeri olarak "0"lanmak amacıyla kendisiyle XOR'lanıyor.
  • 136. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x0000001E [Arg 2] 0x00403000 [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK EAX 0x00000000 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 137. X86 MİMARİSİNE GİRİŞ main() fonksiyonundan çıkmadan önce epilogue adımlarından main() fonksiyonu için alınmış olan stack alanını geri veren "mov esp, ebp" instruction'ı çalıştırılıyor.
  • 138. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x0000001E [Arg 2] 0x00403000 [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP 0x0018FF40 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 139. X86 MİMARİSİNE GİRİŞ main() fonksiyonu 2. epilogue adımında main() fonksiyonunu çağıran bir üst fonksiyonun [EBP] register'ı restore ediliyor.
  • 140. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x0000001E [Arg 2] 0x00403000 [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK EBP 0x0018FF88 ESP 0x0018FF44 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  • 141. X86 MİMARİSİNE GİRİŞ main() fonksiyonunun sonunda "retn" instruction'ı çalıştığında saklanmış olan [EIP] adresinden uygulama akışı devam ediyor.
  • 142. X86 MİMARİSİNE GİRİŞ Uygulamanın devam etmesine izin verdiğimizde "0" exit değeri ile sonlandığını görüyoruz.
  • 143. X86 MİMARİSİNE GİRİŞ İNCELEYEDİĞİMİZ UYGULAMA Assembly kodlarının üzerinden geçtikten sonra kaynak kodumuzu tekrar hatırlamak isteyebilirsiniz. (Aslında her aşamada bu kaynak koda göz atmak disassembly'yi anlamak için size yardımcı olabilir.)
  • 144. X86 MİMARİSİNE GİRİŞ REGISTER'LAR VE KULLANIM AMAÇLARI EIP [Extended Instruction Pointer] Bir sonra çalışacak olan instruction’ın adresi (sadece makine tarafından değiştirilir) EBP [Extended Base Pointer] ve ESP [Extended Stack Pointer] İçinde bulunulan fonksiyonun stack frame’inin taban ve tavan adreslerini barındıran register’lar EAX, EBX, ECX, EDX, ESI, EDI Genel amaçlı register’lar (ancak geleneksel olarak belli amaçlarla kullanılabilirler) EFLAGS Çeşitli instruction’lar tarafından etkilenen ve kullanılan bayrakları barındıran 32 bit’lik bir register
  • 145. X86 MİMARİSİNE GİRİŞ REGISTER'LAR VE KULLANIM AMAÇLARI • EAX – Accumulator Register: Genellikle fonsiyonların return değerlerini tutar. Hesaplamaların sonuçları da genellikle bu register'da tutulur. • EBX – Base Register: Genellikle belli bir özel amaç için kullanılmaz. • ECX – Counter Register: Genellikle döngülerde ve string işlemlerinde sayaç değişkenini (yani meşhur "i" değerini) tutmak için kullanılır. • EDX – Data Register: Çarpma ve bölme gibi işlemlerde EAX'in yetersiz kalması nedeniyle işlem sonuçlarının most significant bit'lerini tutmak için kullanılır. • ESI – Source Index: Genellikle string yazma işlemlerinde kopyalanacak string'den okunacak adresi tutar (read pointer). • EDI – Destination Index: Genellikle string yazma işlemlerinde yazılacak adresi tutar (write pointer). Önemli: ESP ve EBP register'ları ile birlikte yukarıdaki genel amaçlı register'lar assembly yazan uygulama geliştirici veya derleyici tarafından istenildiği gibi kullanılabilir. Ancak yukarıda belirtilen kullanımlar geleneksel kullanımlardır.
  • 146. X86 MİMARİSİNE GİRİŞ REGISTER'LAR VE KULLANIM AMAÇLARI EAX EBX ECX EDX AX BX CX DX 078151631 32 Bit Register'lar 16 Bit Register'lar 8 Bit Register'lar Bu bölümleme sadece EAX, EBX, ECX ve EDX'e özeldir
  • 147. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Assembly Syntax'ları Intel AT&T Prefix'ler mov eax, 1 movl $1, %eax Operand yönü instr dest, source instr source, dest Bellek operand'ları mov eax, [ebx] movl (%ebx), %eax Suffix'ler mov al, bl movb %bl, %al
  • 148. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Bellek adresleme yöntemleri Instruction Anlamı mov eax, [ebx] EBX register'ının içerdiği adresteki 4 byte'lık değeri EAX register'ına atama mov [var], ebx EBX register'ının değerini 32bit'lik bir değişkenin içerdiği adrese yazma mov eax, [esi-4] ESI + (-4) adresindeki 4 byte'lık değeri EAX register'ına atama mov [esi+eax], cl CL register'ının taşıdığı bir byte'lık değeri ESI+EAX adresine yazma mov edx, [esi+4*ebx] ESI+4*EBX adresinde bulunan 4 byte'lık değeri EDX register'ına atama
  • 149. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Size Directive'leri Register adlarının geçtiği instruction'lardan okunacak ve/veya yazılacak verinin büyüklüğü anlaşılabilir. Ancak immediate (sabit) verilerin yazıldığı durumlarda yazılacak verinin kaplayacağı alanın belirtilmesi gerekir. Instruction Anlamı mov BYTE PTR [ebx], 2 2 sabit değerini EBX register'ında saklı adresteki 1 byte'lık alan yaz mov WORD PTR [ebx], 2 2 sabit değerinin 16 bit'lik gösterimini EBX register'ında saklı adresten başlayan 2 byte'lık alana yaz mov DWORD PTR [ebx], 2 2 sabit değerinin 32 bit'lik gösterimini EBX register'ında saklı adresten başlayan 2 byte'lık alana yaz
  • 150. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar Şu ana kadar pek çok assembly instruction'ı ile karşılaştık. Açıkçası belli bir instruction set'i kullanılan veya derleyicilerin ürettiği assembly kodlarının önemli bir bölümünü kapsar. Bu bölümde daha önce de karşılaştığımız çok kullanılan Assembly Instruction'larının üzerinden geçeceğiz.
  • 151. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Data Movement Instruction'ları] mov Move (Opcodes: 88, 89, 8A, 8B, 8C, 8E, ...) Bellekten belleğe mov instruction'ı ile veri kopyalamak mümkün değildir. Syntax mov <reg>,<reg> mov <reg>,<mem> mov <mem>,<reg> mov <reg>,<imm> mov <mem>,<imm>
  • 152. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Data Movement Instruction'ları] push Push stack (Opcodes: FF, 89, 8A, 8B, 8C, 8E, ...) Syntax push <reg32> push <mem> push <imm32>
  • 153. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Data Movement Instruction'ları] pop Pop stack Syntax pop <reg32> pop <mem>
  • 154. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Data Movement Instruction'ları] lea Load effective address Bu instruction diğerlerine nazaran biraz kafa karıştırıcı olabilir. "lea" instruction'ın da kaynak değer mutlaka köşeli parantezler arasındadır, ancak "mov" instruction'ı için bu köşeli parantezler arasında adresi bulunan bellek alanındaki değer anlamına gelirken "lea" instruction'ı doğrudan adres değerini kullanır. Bu imkan zaman zaman adres bilgisini kullanmaktan ziyade hesaplama amacıyla kullanılmaktadır. Örnek lea edi, [ebx+4*esi] - EBX+4*ESI hesaplamasının sonucu EDI register'ına atanır
  • 155. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Aritmetik ve Mantık Instruction'ları] add Integer Addition Toplama instruction'ında en fazla bir operand bellek alanı olabilir. Syntax add <reg>,<reg> add <reg>,<mem> add <mem>,<reg> add <reg>,<imm> add <mem>,<imm>
  • 156. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Aritmetik ve Mantık Instruction'ları] sub Integer Subtraction Toplama instruction'ında olduğu gibi çıkarma instruction'ında da en fazla bir operand bellek alanı olabilir. Syntax sub <reg>,<reg> sub <reg>,<mem> sub <mem>,<reg> sub <reg>,<imm> sub <mem>,<imm>
  • 157. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Aritmetik ve Mantık Instruction'ları] inc, dec Increment, Decrement Artırma instruction'ı registry veya bellek alanını bir artırırken azaltma instruction'ı da tam tersini gerçekleştirir. Syntax inc <reg> inc <mem> dec <reg> dec <mem>
  • 158. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Aritmetik ve Mantık Instruction'ları] imul Integer Multiplication 2 veya 3 operand'la çalışır. 2 operand'lı kullanımda iki değer çarpılıp sonuç birinci operand'da saklanır. 3 operand'lı kullanımda 2. ve 3. operand'lar çarpılıp sonuç birinci operand'da saklanır. Birinci operand (destination) her zaman registry olmak zorundadır, 3 operand'lı kullanımda 3. operand her zaman bir immediate (sabit) değer olmak zorundadır. Syntax imul <reg32>,<reg32> imul <reg32>,<mem> imul <reg32>,<reg32>,<imm> imul <reg32>,<mem>,<imm>
  • 159. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Aritmetik ve Mantık Instruction'ları] idiv Integer Division EDX:EAX registerlarında bulunan 64 bit'lik integer değeri operand değerine böler. Bölüm EAX'e kalan ise EDX register'ına yazılır. Syntax idiv <reg32> idiv <mem>
  • 160. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Aritmetik ve Mantık Instruction'ları] and, or, xor Bitwise logical and, or and exclusive or Operand'lar üzerinde belirtilen işlemleri gerçekleştirdikten sonra sonucu birinci operand'a yazarlar. Syntax and <reg>,<reg> and <reg>,<mem> and <mem>,<reg> and <reg>,<imm> and <mem>,<imm> or <reg>,<reg> or <reg>,<mem> or <mem>,<reg> or <reg>,<imm> or <mem>,<imm> xor <reg>,<reg> xor <reg>,<mem> xor <mem>,<reg> xor <reg>,<imm> xor <mem>,<imm>
  • 161. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Aritmetik ve Mantık Instruction'ları] shl, shr Shift Left, Shift Right Birinci operand'ı sola veya sağa kaydırırken boşalan bit pozisyonlarına 0 yazılır. Kaç bit kaydırma yapılacağı 8 bit'lik bir immediate değerde veya CL register'ı ile verilir. Syntax shl <reg>,<imm8> shl <mem>,<imm8> shl <reg>,<cl> shl <mem>,<cl> shr <reg>,<imm8> shr <mem>,<imm8> shr <reg>,<cl> shr <mem>,<cl>
  • 162. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Akış Kontrol Instruction'ları] jmp Jump Uygulama akışını koşulsuz olarak operand ile belirtilen adrese yönlendirir. Syntax jmp <label>
  • 163. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Akış Kontrol Instruction'ları] jcondition (Conditional Jump) EFLAGS register'ında tutulan ve son aritmetik işlemin (bunlar add, sub gibi instruction'lar olabileceği gibi cmp ve test gibi çıkarma işleminin türevleri olan karşılaştırma instruction'ları da olabilir) sonuçlarına bağlı olarak uygulama akışını operand'da belirtilen adrese yönlendirir veya akışın bir sonraki instruction'dan devam etmesine izin verir. ZF - zero flag yapılan işlem veya karşılaştırmanın sonucu "0" ise "1" değerini alır. SF - sign flag yapılan işlemin sonucu negatif ise "1" değerini alır. Syntax je <label> (jump when equal) jne <label> (jump when not equal) jz <label> (jump when last result was zero) jg <label> (jump when greater than) jge <label> (jump when greater than or equal to) jl <label> (jump when less than) jle <label> (jump when less than or equal to)
  • 164. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Akış Kontrol Instruction'ları] cmp Compare CMP instruction'ı SUB instruction'ına benzer ancak çıkartma işleminin sonucu birinci operand'a yazılmaz, sadece işlemin sonucu negatif ise Sign Flag "1" olarak işaretlenir. Syntax cmp <reg>,<reg> cmp <reg>,<mem> cmp <mem>,<reg> cmp <reg>,<imm>
  • 165. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Akış Kontrol Instruction'ları] call, ret (Subroutine call and return) CALL instruction'ı operand ile verilen adrese uygulama akışını yönlendirirken bir yandan da kendisinden bir sonra gelen instruction'ın adresini STACK'e yazar, JMP instruction'ından temel farkı da budur. RET instruction'ı ise önce STACK'in o anda en üstünde bulunan adres değerini restore eder, yani uygulama akışını daha önce CALL instruction'ı ile saklanmış olan adrese yönlendirir. Dolayısıyla RET instruction'ından önce function epilog bölümü gerçekleştirilerek çalıştırılan fonksiyon için STACK'te ayrılmış olan tüm alanın SUB ESP, 0x??? instruction'ı veya benzeri bir işlem ile geri verilmiş olması gerekir. Syntax call <label> ret
  • 166. X86 MİMARİSİNE GİRİŞ STACK ALANININ KULLANIMI Stack Alanının Çalışma Mekanizması • Stack yüksek bir adresten düşük adreslere doğru büyür. • Stack'e veri yazma (PUSH) ve bu veriyi bir register'a okuyarak silme (POP) işlemi LIFO (Last In First Out) yöntemiyle stack'e veri yazılması ve silinmesine yol açar. Bu stack'teki herhangi bir alan okunarak (MOV instruction'ı ile) bir register'a atanamaz ve tam tersi şekilde bir register veya immediate değeri stack'e yazılamaz anlamına gelmez, LIFO yöntemi ile sadece stack'in alan tüketimi ve iadesine ilişkin yöntemi ifade ediyoruz. • Stack sadece PUSH instruction'ı ile büyümez ve POP instruction'ı ile küçülmez. [SUB ESP, 0x20] benzeri instruction'larla ESP register değeri küçültülerek büyüyebilir ve [ADD ESP, 0x20] benzeri instruction'larla ESP değeri artırılarak küçülebilir. • Stack ASLR uygulanırsa her yüklemede farklı bir adresten başlatılır.
  • 167. X86 MİMARİSİNE GİRİŞ STACK ALANININ KULLANIMI Stack'te Saklanan Veriler • Fonksiyon parametreleri: fastcall gibi calling convention'larda register'lar da fonksiyonlara parametre vermek için kullanılabilmekle birlikte diğer convention'larda ve bu iş için ayrılmış register'ların sayısının yetmediği durumlarda parametreler "CALL" instruction'ı ile fonksiyon çağrılmadan önce stack'e yazılır. Parametreler genellikle sağdan sola doğru stack'e yerleştirilir ("printf" gibi değişken sayıda parametre kabul eden fonksiyonlar için format string parametresinde olduğu gibi diğer parametreleri tanımlayan bir string başta olduğundan bu yaklaşım oldukça mantıklıdır). • Bazı derleyiciler parametrenin stack'ye yazılması işlemini PUSH instruction'ı ile gerçekleştirir, bazıları ise stack'in en uç noktasını kullanarak parametreleri doğru sırada yerleştirir.
  • 168. X86 MİMARİSİNE GİRİŞ STACK ALANININ KULLANIMI Stack'te Saklanan Veriler [devamı] • Fonksiyon dönüş adresi: "CALL" instruction'ı çalıştığı anda bu instruction'dan bir sonraki instruction adresi fonksiyondan "RET" instruction'ı ile dönüldüğünde EIP register'ına atanmak üzere stack'te saklanır. Bellek taşma açıklıklarında uygulama akışını manipüle etmek için hedef alınan başlıca pointer değeri bu değerdir (diğerlerine SEH pointer değeri, lokal değişken olarak saklanan object veri yapılarının ilk alanında bulunan Virtual Table pointer değeri örnek verilebilir).
  • 169. X86 MİMARİSİNE GİRİŞ STACK ALANININ KULLANIMI Stack'te Saklanan Veriler [devamı] • Bir önceki fonksiyon frame pointer'ı: Fonksiyon "prolog"larında daha önce de gördüğümüz gibi ilk yapılan işlem mevcut frame pointer değeri (EBP) yeni fonksiyonun frame pointer değeri ile ezileceği için "PUSH EBP" instruction'ı ile stack'e yazılır. Bu değer fonksiyon "epilog"unda "POP EBP" instruction'ı ile EBP pointer'ını eski frame pointer'ı haline getirmek için kullanılır. • Fonksiyon lokal değişkenleri: Fonksiyon "prolog"undan sonra genellikle fonksiyon lokal değişkenleri için ESP değeri düşürülerek yer ayrılır. Daha sonra lokal değişkenler için ayrılan bu alana lokal değişkenler yazılmaya ve bu alandan gerektiğinde okunmaya başlanır.
  • 170. X86 MİMARİSİNE GİRİŞ CALLING CONVENTIONS CALLING CONVENTION'LARI NEDEN ANLAMALIYIZ? Calling convention'lar çağıranın mı çağrılanın mı parametreler için kullanılan alanı geri vereceği ve hangi register'ların korunmasının kimin sorumluluğunda olduğu ile ilgilidir. İyi Niyetli Cevap Bu sorunun iyi niyetli cevabı farklı compiler'ların ürettikleri kodların bir arada uyum içinde çalışabilmeleri için stack yönetimi ve register'ların korunması için aynı yaklaşımları izleme ihtiyacıdır.
  • 171. X86 MİMARİSİNE GİRİŞ CALLING CONVENTIONS CALLING CONVENTION'LARI NEDEN ANLAMALIYIZ? [devamı] Kötü Niyetli Cevap Inline assembly ile bir kod yazarken veya virüs benzeri bir kodu mevcut bir uygulamaya yerleştirirken assembly içinden çağrılan Windows API'lerinin calling convention'ına uygun olarak hareket edilmezse Stack yapısının düzeni bozulacak, dolayısıyla da uygulama stack frame'i ile ilgili bu düzensizlikten dolayı hata alarak sonlanacaktır. Windows API'leri için "stdcall" convention'ına uygun bir biçimde stack'teki parametreleri yönetmezsek kodumuzun içinde çalıştığı proses hata alacaktır.
  • 172. X86 MİMARİSİNE GİRİŞ CALLING CONVENTIONS stdcall Adının çağrıştırabileceğinin aksine aslında tüm derleyiciler için standart convention değildir ve Microsoft Win32 API tarafından kullanılır. İlk olarak bu convention'dan söz etmemizin sebebi de budur. • Stack'in temizlenmesinden çağırılan (callee) sorumludur. Yani çağıran (caller) parametreleri stack'e push eder, ancak temizleme işlemini gerçekleştirmez. • Parametreler stack'e sağdan sola doğru push edilir. • EAX, ECX ve EDX register'ları fonksiyon içinde kullanılır, dolayısıyla fonksiyondan geri dönüldüğünde farklılaşmış olma ihtimalleri yüksektir. Yani bunlar caller saved register'lardır. • Fonksiyon return değeri EAX register'ına yazılır.
  • 173. X86 MİMARİSİNE GİRİŞ CALLING CONVENTIONS cdecl C declaration'ın kısaltması olan bu convention çoğu C derleyicileri tarafından kullanılır. • Stack'in temizlenmesinden çağıran (caller) sorumludur. Bu yaklaşım stdcall'unkinden farklıdır. • Parametreler stack'e sağdan sola doğru push edilir. • EAX, ECX ve EDX register'ları fonksiyon içinde kullanılır, dolayısıyla fonksiyondan geri dönüldüğünde farklılaşmış olma ihtimalleri yüksektir. Yani bunlar caller saved register'lardır. • Fonksiyon return değeri EAX register'ına yazılır.
  • 174. X86 MİMARİSİNE GİRİŞ CALLING CONVENTIONS Microsoft fastcall Parametre aktarımında register kullanımına da bir örnek olması amacıyla fastcall convention'ından da bahsedelim. Bir fonksiyonun bu convention'a göre derlenmesi için __fastcall anahtar kelimesinin kullanılması gerekir. • Soldan sağa ilk iki parametre ECX ve EDX register'larında aktarılır. • Diğer parametreler (bu defa sağdan sola) stack'e yazılır. • Stack'in temizlenmesinden stdcall'da olduğu gibi çağırılan (callee) sorumludur.
  • 176. TERSİNE MÜHENDİSLİK TEMEL ADIMLAR • İlk bilgi toplama  Import Address Table'ın incelenmesi  String'lerin incelenmesi  Temel dinamik analiz • İncelenecek fonksiyonun bulunması • Bu fonksiyondan çağrılan - "call" edilen fonksiyonların tespit edilmesi • Algoritma ve veri yapılarının tespiti • Tespit edilen algoritmaların kavramsal olarak (pseudo) kodlanması • Fonksiyonların, parametrelerin, değişkenlerin adlarının değiştirilmesi ("rename" edilmesi) • Analiz edilen kod bölümlerine yorum (comment) eklenmesi