Disassembler ile akış okumak
- Disassembler makine kodunu assembly satırlarına çevirir; sen de bir yordamı baştan okumak yerine çapa atıp doğru yere atlamayı öğrenirsin.
- Ghidra, IDA, radare2 ve rizin aynı işi farklı arayüzle yapar.
- Bu derste karşılaştırma ile atlamayı birlikte okumayı ve geri derleyiciyi assembly ile doğrulamayı öğrenirsin.
Puan bütün etkinlikleri cevaplayınca hesaba yazılır. Bu dersi tamamlayınca +55 XP alacaksın. Giriş yapmadan ilerlersen puan yalnız bu tarayıcıda durur.
Statik okuma bir noktada baytların kendisine iner. Disassembler baytları işlemcinin anladığı komutlara, yani assembly satırlarına çevirir. Sonra o komutları bloklara böler ve bloklar arası atlamaları çizer.
Ortaya çıkan grafiğe akış grafiği denir ve programın karar yapısını gösterir. Bu derste bir parola denetiminin assembly satırlarını okur ve hangi yolun doğru parolaya gittiğini çıkarırsın. Hiçbir adım dosyayı çalıştırmaz; yalnız kodu okursun.
Karşılaştırma ve koşullu atlama
Birkaç komut assembly okumanın belkemiğidir. mov bir değeri bir kayıtçıya taşır. lea bir adresi hesaplayıp kayıtçıya koyar, değeri değil adresi.
cmp iki değeri çıkarma yaparak karşılaştırır ve sonucu bayrak kaydına yazar. test bit düzeyinde ve işlemi yapar; test eax, eax deyimi, eax sıfır mı diye sormanın kısa yoludur. Karşılaştırmadan sonra gelen koşullu atlama (je, jne, jle, jg) bu bayraklara bakar ve akışı iki yola böler.
Kayıtçılar işlemcinin elinin altındaki küçük, çok hızlı belleklerdir. Bir çağrıya argümanların hangi kayıtçıyla geçtiği bir sözleşmeye bağlıdır. Linux'ta ilk altı tam sayı argüman sırayla rdi, rsi, rdx, rcx, r8 ve r9 kayıtçılarına konur.
Windows'ta sıra farklıdır: rcx, rdx, r8, r9. İki sistemde de dönen değer eax ya da rax kayıtçısında bekler. Bu sözleşmeyi bilmek, bir çağrının hangi argümanla yapıldığını okumana yarar: strcmp'in iki argümanını görmek için Linux'ta rdi ve rsi kayıtçılarına bakarsın. Sözleşmeyi karıştırırsan argümanları yanlış eşler ve kodun anlamını kaçırırsın.
Bir yordam çağrısından dönen değer genelde eax kayıtçısında durur. Karşılaştırma yapan kütüphane yordamları bu kurala uyar. strcmp iki dizeyi karşılaştırır ve eşitlikte sıfır, farkta sıfırdan başka bir değer döndürür.
Çağrının hemen ardından gelen cmp ya da test komutu bu dönen değeri okur, sonraki atlama da ona göre karar verir. Bu küçük mantık her parola ve her lisans denetiminde tekrar eder.
$ r2 -A -q -c 'pdf @ sym.parola_kontrol' parola mov rdi, qword [s1] ; girilen parola lea rsi, str.Kargo_2026 ; "Kargo-2026" call sym.imp.strcmp cmp eax, 0 jne 0x100157a ; parola yanlış dalı mov dword [var_4h], 1 ; doğru dal: 1 döndür jmp 0x1001581 mov dword [var_4h], 0 ; yanlış dal: 0 döndür
Bu çıktıyı satır satır oku. İlk mov kullanıcının girdiği parolayı rdi kayıtçısına koyar; strcmp'in ilk argümanı budur. lea ise beklenen parolanın, yani Kargo-2026 dizesinin adresini rsi'ye koyar; ikinci argüman budur. call strcmp iki dizeyi karşılaştırır.
cmp eax, 0 dönen değeri sıfırla kıyaslar. jne sıfır değilse, yani diziler farklıysa yanlış dala atlar. Atlamayan yol, yani diziler eşit olduğunda düşülen yol, doğru parola yoludur ve 1 döndürür. Not: derleyici burada cmp eax, 0 yerine aynı işi yapan test eax, eax deyimini de üretebilir.
Bir şeye daha dikkat et: beklenen parola kodun içinde düz metin olarak duruyor. lea satırındaki Kargo-2026 dizesi, dosyanın salt okunur veri bölümünde yazılı. Bu, parolayı koda gömmenin neden kötü bir fikir olduğunu gösterir. Dizeyi strings ile de görürdün, disassembler ile de buldun.
Gerçek bir denetim parolayı koda gömmez; onun yerine girilenin özetini alır ve önceden saklanmış bir özetle karşılaştırır. O zaman kodda düz parola görünmez, yalnız bir özet ve bir karşılaştırma durur. Bir ikilide gömülü düz parola bulmak, tasarımın zayıf olduğunu söyleyen bir bulgudur.
Her yordam aynı iskeletle açılır ve kapanır. Başta push rbp ve mov rbp, rsp komutlarını görürsün; bunlar yordamın yerel değişkenleri için bir çerçeve kurar ve bu desene prolog denir. sub rsp komutu yığında yerel değişkenlere yer açar.
Yordam biterken pop rbp ve ret komutları çerçeveyi kapatır ve çağırana döner; bu da epilogtur. Prolog ile epilogu tanımak yordamın nerede başlayıp nerede bittiğini bir bakışta söyler. Arada kalan satırlar yordamın asıl işidir; sen de dikkatini oraya verirsin.
Etkinlik 1 / 6
Parolayı karşılaştıran koşulu kuran satırı bul.
Eşik mantığı: cmp ve jle
Her karşılaştırma eşitlik sormaz; çoğu bir eşik denetler. cmp bir değeri bir sabitle kıyaslar, sonra büyüklük atlaması gelir. jle küçük ya da eşitse atlar, jg büyükse atlar, jl küçükse atlar.
Atlayan yol ile atlamayan yolu ayırt etmek için komutun hangi koşulda atladığını bilmen gerekir. Küçük bir dikkat hatası, kodun anlamını tersine çevirir ve dakikalarca yanlış yolu okursun.
Döngüleri tanımak da bir alışkanlıktır. Geriye doğru bir atlama görürsen orada döngü vardır: akış daha önceki bir adrese döner. Sayaç kayıtçısını ve sınır karşılaştırmasını bulursan döngünün kaç kez döneceğini çıkarırsın.
İleriye doğru bir atlama ise çoğu zaman bir koşulu geçmek içindir, yani bir if bloğunu atlamaktır. Bu iki deseni ayırmak, grafiği okurken yönünü kaybetmeni önler.
Etkinlik 2 / 6
Geri derleyici bu kodu nasıl özetler?
Önce kodu oku, sonra çıktıyı seç.
cmp dword [rbp-0x4], 0xa jle 0x401180 mov eax, 1 ret
Araçla okumak: radare2
Araç seçimi büyük ölçüde zevk meselesidir. Ghidra ücretsizdir ve güçlü bir geri derleyici taşır. IDA uzun yıllardır ticari standarttır.
radare2 ile ondan çatallanarak doğan rizin komut satırında çalışır ve betiklemeye çok uygundur. Dördü de aynı işi yapar: baytları komuta çevirir, yordamları bulur ve akış grafiğini çıkarır. Komut adları radare2 ile rizin arasında büyük ölçüde aynıdır, bu yüzden birini öğrenmek diğerini de verir.
$ r2 -A -q -c 'afl' parola 0x01001550 4 58 sym.parola_kontrol 0x01001590 7 109 main $ r2 -A -q -c 'pdf @ main' parola / 109: int main (int argc, char **argv); | 0x01001590 push rbp | 0x01001594 mov rbp, rsp
Bu iki komutu birlikte kullanırsın. İlk komuttaki -A bayrağı otomatik analizi koşar: dosyayı tarar, yordamları bulur ve çapraz başvuruları çıkarır. -q sessiz çalışır, -c ise verdiğin komutu uygular.
afl bulunan bütün yordamları adres, blok sayısı ve boyutla listeler. İlginç bir yordam adı görünce ikinci komutla ona odaklanırsın: pdf, geçerli yordamı disassembly olarak basar. Böylece bütün dosyayı değil, yalnız seni ilgilendiren yordamı okursun.
Etkinlik 3 / 6
radare2 ile ornek.bin dosyasını analiz et ve main yordamını disassembly olarak yaz.
Baştan okuma, çapa ile atlama
Tanımadığın bir ikiliyi baştan sona okumak zaman kaybıdır. Bunun yerine çapa ararsın. Çapa, seni ilgilendiren yere götüren bir izdir.
En iyi çapalar dizeler ve kütüphane çağrılarıdır. Yöntem şudur: ilginç bir dize bul, o dizeye kimin dokunduğuna bak, oradaki yordamı oku. Araçlar buna çapraz başvuru der; tek adımda dizeden koda geçer ve doğrudan ilgili bölüme düşersin.
Kütüphane kodunu ayırmak büyük zaman kazandırır. Statik bağlanmış bir ikilide yordamların çoğu, senin aradığın kod değil, standart kütüphanenin kopyalanmış parçalarıdır.
İmza veritabanları bu bilinen yordamları tanır ve otomatik adlandırır; radare2'de buna zignature, IDA'da FLIRT denir. Bu eşleme sonrası grafikte yüzlerce yordam yerine yalnız yazarın kendi kodu kalır. Benzer biçimde, bilinen şifreleme algoritmalarının kendine özgü sabitleri vardır; kodda o sabiti görmek hangi algoritmanın kullanıldığını tek bakışta söyler ve seni doğrudan ilgili yordama götürür.
Okuma kısa turlar halinde yürür. Her turda tek bir soruya yanıt ararsın: bu yordam ne döndürüyor, bu koşul neyi sınıyor, bu döngü kaç kez dönüyor. Soru olmadan okumak dikkati dağıtır ve zaman yakar. Anladığın her yordamın adını araçta değiştirirsin ve yanına kısa bir not bırakırsın.
Analiz uzun sürer; dün anladığın şeyi bugün unutursun. Not bırakmayan analist aynı yordamı iki kez okur ve ikinci okuma ilkinden hızlı olmaz. Çapraz başvuru komutu bu okumanın can damarıdır: bir dizeye ya da yordama kimin dokunduğunu listeler ve seni çağıran koda atlatır.
Çağrı grafiği bütün resmi verir. Grafik hangi yordamın kimi çağırdığını gösterir; sen de düğümlere bakarak yolunu çizersin. Yaprak yordamlar, yani kimseyi çağırmayan uç düğümler, çoğu zaman küçük yardımcı işlerdir.
Çok çağrılan orta düğümler ise ortak altyapıdır: bir kez anlaşılınca birçok yeri aydınlatır, bu yüzden onlara öncelik verirsin. Anahtar sözcük aramaları da hızlı sonuç getirir: kod içinde bir kayıt defteri yolu, bir protokol adı ya da bir hata iletisi aratırsın ve bulunan her eşleşme bir yordama çapa atar.
Etkinlik 4 / 6
Tanımadığın bir ikilide akışı okuma sırasını kur.
Bir öğeye odaklan, yukarı ve aşağı ok tuşlarıyla taşı. Home tuşu en üste, End tuşu en alta alır.
- 1Şüpheli yordamı satır satır oku
- 2Dizelerin hangi yordamda kullanıldığını izle
- 3İçe aktarılan kütüphane çağrılarına bak
- 4Giriş noktasını bul
- 5Çağrı grafiğinden büyük yordamları çıkar
Geri derleyici: yapı ama kesinlik değil
Geri derleyici assembly kodunu okunabilir, C'ye benzer bir gösterime çevirir. Bu gösterim okumayı çok hızlandırır: döngüler, koşullar ve değişkenler ekranda belirir. Ama bu çıktı özgün kaynak dosya değildir.
Araç tip ve akış tahmin eder; değişken adları uydurmadır ve bazı satırlar yanlış olabilir. Karartılmış ya da elle yazılmış kodda geri derleyici daha sık yanılır. Bu yüzden kritik bir satırı her zaman assembly ile karşılaştırırsın.
Statik okuma her zaman sonuca ulaşmaz. Kod çalışma anında üretiliyorsa, disassembler ekranda anlamsız baytlar gösterir.
Baytların anlamlı komuta dönüşmediği yerde geri derleyici de çöker ve okuma tıkanır. O nokta dinamik analize geçme işaretidir: kodu belleğe açtıktan sonra okumak gerekir. Statik ve dinamik birbirinin yerine geçmez; biri okur, öteki açar.
Derinleş:Geri derleyici neden yakın tarihli bir araç
Disassembler onlarca yıldır var ama güvenilir geri derleyici görece yenidir. Uzun süre ticari IDA'nın Hex-Rays eklentisi bu alanın en güçlü seçeneğiydi ve fiyatı birçok analisti dışarıda bırakıyordu. Mart 2019'da ABD Ulusal Güvenlik Ajansı, kendi geliştirdiği Ghidra'yı RSA Konferansı'nda ücretsiz olarak yayımladı. Bir ay sonra kaynak kodunu da açtı.
Ücretsiz ve çok mimarili bir geri derleyicinin herkese açılması, tersine mühendisliği bir avuç uzmanın işi olmaktan çıkardı. Bugün bir öğrenci de bir kurum analisti de aynı sınıf araca erişiyor. Yine de araç ne kadar iyi olursa olsun çıktısı bir yorumdur; son sözü assembly söyler.
Etkinlik 5 / 6
Ghidra'nın geri derleyici penceresi ne üretir?
Etkinlik 6 / 6
Doğru mu, yanlış mı?
Bir strcmp çağrısından sonra test eax, eax ve jne geliyorsa, jne'nin atlamadığı yol doğru parolanın yoludur.
Okumayı istediğin sırayla sürdürebilirsin. Ders, bütün etkinlikleri cevapladığında tamamlanır.