Rehber › Kategori Rehberleri
Kategori Rehberleri

Tersine Mühendislik (Reversing) CTF Rehberi: Sıfırdan Başlangıç

Reversing, kaynak kodu elinde olmayan bir programın ne yaptığını sökerek anlama sanatıdır. Bu rehber, bir rev challenge'ına ilk kez oturan birinin "aa, demek böyle çalışıyormuş" demesi için gereken temel düşünme biçimini ve okuma tekniklerini sıfırdan anlatır.

Özet
  • Reversing = derlenmiş bir programı geri okuyup mantığını çıkarmak; amaç genelde onu "doğru" diyecek girdiyi bulmak.
  • Her rev challenge'ının bir yerinde girdini bir şeyle kıyaslayan bir kontrol vardır; önce o kontrolü bul.
  • XOR tersine çevrilebilir bir işlemdir: aynı anahtarla iki kez uygulanınca metin geri gelir.
  • Ghidra gibi bir decompiler karmaşık makine kodunu okunur pseudo-koda çevirir; asıl iş o pseudo-kodu okumaktır.
  • Basit VM/bytecode challenge'larında önce opcode'ları çözersin, sonra bytecode'u elle takip edersin.

Reversing (Tersine Mühendislik) Nedir?

Bir yazılımcı kod yazar, derleyici o kodu bilgisayarın anladığı makine diline çevirir. Reversing, bu yolu tersten yürümektir: elinde sadece derlenmiş program (ya da bir bytecode) varken, kaynak koda bakmadan programın ne yaptığını anlamaya çalışırsın.

CTF'te tipik bir rev challenge'ı sana bir dosya verir. Bu program senden bir parola ister ve "Doğru!" ya da "Yanlış!" der. Görevin basit görünür ama düşündürücüdür: bu programı hangi girdi mutlu eder? Yani flag'i bulmak için programın içindeki kontrol mantığını sökmen gerekir. CTF'in ne olduğunu merak ediyorsan önce CTF Nedir? sayfasına göz atmanı öneririm.

Reverser Gibi Düşünmek

Yeni başlayanların en büyük hatası, programın her satırını anlamaya çalışmaktır. Gerek yok. Bir program yemek tarifi gibidir; sen sadece "sonunda kimin geçtiğine karar veren" adımı ararsın.

Neredeyse her rev challenge'ında şu iskelet vardır:

  1. Kullanıcıdan bir girdi al.
  2. Girdiye bir işlem uygula (ya da olduğu gibi bırak).
  3. Sonucu gizli bir değerle karşılaştır.
  4. Eşitse "doğru", değilse "yanlış" de.

Doğru düşünme biçimi şudur: önce 3. adımdaki karşılaştırmayı bul, sonra geriye sar. "Program benim girdimi neyle kıyaslıyor ve o hâle gelmesi için başta ne girmeliyim?" sorusu, çözümlerin büyük kısmının anahtarıdır.

İlk Adım: Statik Okuma ve Pseudo-Kod

Analiz iki türlüdür. Statik analiz, programı çalıştırmadan içine bakmaktır. Dinamik analiz ise çalıştırıp davranışını izlemektir. Başlangıçta statik okuma en güvenli ve öğretici yoldur; kendi indirdiğin, yetkili/eğitim amaçlı dosyalar üzerinde rahatça çalışabilirsin.

İlk iki komut çoğu zaman büyük ipucu verir:

Makine kodunu tek tek okumak zordur. Bu yüzden bir decompiler kullanırız: makine kodunu C benzeri, okunabilir bir "pseudo-koda" çevirir. Ücretsiz ve en yaygın olanı Ghidra'dır. Karşına şuna benzer bir şey çıkar:

giris = kullanicidan_al();
if (kontrol(giris) == 1) {
    yazdir("Dogru!");
} else {
    yazdir("Yanlis!");
}

Amacın, kontrol fonksiyonunun içine girip mantığını okumaktır. Değişken adları anlamsız (örneğin iVar1) olsa da korkma; sen sadece akışı takip et: hangi döngü var, girdinin her karakterine ne yapılıyor, neyle karşılaştırılıyor.

XOR ve Karşılaştırma Kontrolleri

Başlangıç seviyesinde iki desen çok sık çıkar.

1) Sabit metinle karşılaştırma

En basiti: program girdini kod içine gömülü bir metinle kıyaslar.

if (strcmp(giris, "gizli_parola") == 0)
    yazdir("Dogru!");

Böyle bir durumda çoğu zaman strings komutu ya da pseudo-kod sana o metni doğrudan gösterir. Bulduğun metin ya cevabın kendisidir ya da onu bir adım işleyip flag'e çeviren ipucudur.

2) XOR ile gizleme

Geliştirici parolayı açıkça yazmak istemez, onu basitçe gizler. En çok kullanılan yöntem XOR'dur, çünkü tersine çevrilebilir. Kural şudur: bir baytı bir anahtarla iki kez XOR'larsan başa dönersin. Yani a ^ k ^ k = a.

Küçük bir örnek: 'A' harfi 0x41 sayısıdır. Anahtar 0x10 ile:

0x41 ^ 0x10 = 0x51  (yani 'Q' harfi)
0x51 ^ 0x10 = 0x41  (tekrar 'A')

CTF'te tipik kontrol şuna benzer:

for i in range(len(giris)):
    if giris[i] ^ 0x42 != beklenen[i]:
        return "Yanlis"

Burada program, senin her karakterini 0x42 ile XOR'layıp sabit bir beklenen diziyle karşılaştırıyor. Sen de tersini yaparsın: doğru girdiyi bulmak için beklenen[i] ^ 0x42 hesaplarsın. Anahtarı (0x42) ve beklenen diziyi pseudo-kodda okur, çözümü genelde birkaç satır Python ile geri getirirsin. XOR'un mantığını daha derinden görmek istersen kripto challenge'larına da bakabilirsin; oradaki mantık burada da işine yarar.

Basit VM ve Bytecode

Biraz daha ileri challenge'larda geliştirici, kontrolü doğrudan yazmak yerine küçük bir sanal makine (VM) kurar. Program içinde minik bir yorumlayıcı vardır: bir sayı listesini ("bytecode") sırayla okur ve her sayıya göre bir iş yapar.

Bu iş parçalarına opcode denir. Genelde büyük bir switch gibi görünür:

while (True):
    op = bytecode[ip]
    if op == 1: yigin.push(...)   # yukle
    if op == 2: topla()          # iki degeri topla
    if op == 3: xorla()          # xor uygula
    if op == 4: karsilastir()    # kontrol
    ip = ip + 1

Korkutucu görünür ama yöntem hep aynıdır: önce her opcode'un ne yaptığını çöz (yani 1 = yükle, 2 = topla gibi bir tablo çıkar), sonra bytecode listesini elle takip et. Sanki bir masa oyunu oynar gibi taşı adım adım ilerletirsin. Bir süre sonra dizinin girdine hangi işlemleri uyguladığını görürsün.

Not: Bazı challenge'lar Python ile yazılır ve derlenmiş .pyc dosyası verir. Python'ın kendi dis modülü bu bytecode'u okunur hâle getirir; bu da pratik bir başlangıç kapısıdır.

Nasıl Başlamalı? Araç Çantası ve İpuçları

Yeni başlayan biri için sade bir akış şu şekildedir:

  1. file ile türü öğren.
  2. strings ile kolay ipuçlarını topla.
  3. Ghidra'da aç, main fonksiyonunu bul, akışı oku.
  4. Karşılaştırmayı bul, geriye sararak doğru girdiyi hesapla.

Birkaç pratik ipucu:

Bu tekniklerin gerçekten oturması için tek yol pratiktir. Anlattığımız desenleri (sabit karşılaştırma, XOR, basit VM) sırayla denemek için reversing challenge'larına göz at, kolaydan zora doğru ilerle. Diğer kategorileri ve genel yol haritasını görmek istersen Rehber ana sayfası iyi bir başlangıç noktası.

Sıkça Sorulan Sorular

Programlama bilmeden reversing yapabilir miyim?

Temel seviyede evet, çünkü decompiler kodu okunur hâle getiriyor. Ama en azından bir dilde (özellikle C veya Python) if, döngü ve değişken mantığını okuyabilmek işini çok kolaylaştırır. Zamanla okudukça bu okuma refleksi kendiliğinden gelişir.

Hangi araçla başlamalıyım?

Yeni başlayanlar için ücretsiz ve güçlü bir decompiler olan Ghidra ideal bir başlangıçtır. Yanına file ve strings gibi basit komut satırı araçlarını eklersen çoğu başlangıç challenge'ını çözecek çantayı kurmuş olursun.

Assembly öğrenmem şart mı?

Başlangıçta şart değil; pseudo-kod okuyarak epey yol alabilirsin. Ama challenge'lar zorlaştıkça, decompiler'ın takıldığı yerleri anlamak için temel assembly bilgisi çok işine yarar. Bunu ihtiyaç duydukça, adım adım öğrenmen en sağlıklısı.

Statik ve dinamik analiz arasındaki fark ne?

Statik analiz programı çalıştırmadan kodunu okumaktır; güvenli ve öğreticidir. Dinamik analiz ise programı çalıştırıp davranışını (değişkenlerin anlık değerlerini) izlemektir. Yeni başlayan biri genellikle statik okumayla başlar, gerektiğinde dinamik analize geçer.

Bir challenge'da nereden başlamalıyım?

Önce file ve strings çalıştır, sonra Ghidra'da main fonksiyonunu aç. Girdinin nerede alındığını ve neyle karşılaştırıldığını bul; çözüm neredeyse her zaman o karşılaştırmayı geriye sarmaktan geçer.

Hadi pratiğe dök

Bu rehberdeki teknikleri Tersine Mühendislik kategorisindeki gerçek challenge’larda dene.

Tersine Mühendislik Challenge’ları →

Devam et