User Space Dedektifi: ltrace ile Kütüphane Çağrılarını (Library Calls) Yakalamak
strace her şeyi göstermez. Parola kontrolleri, şifreleme ve string işlemleri User Space'te, gözlerden uzak gerçekleşir. ltrace ile kapalı kutu uygulamaların içine sızıyor, strcmp ve malloc gibi kütüphane çağrılarını canlı izliyoruz.
Sistem yöneticilerinin ve güvenlik uzmanlarının alet çantasında strace vazgeçilmez bir İsviçre çakısıdır. Bir önceki yazılarımızda, strace ile Kernel’ın kapısını çaldık, ağ bağlantılarını (connect) dinledik ve dosya izinlerini (access) kontrol ettik.
Ama bazen… strace yetmez.
Önünüzde kapalı kaynaklı (closed-source) bir binary dosya var. Program çalışıyor, sizden bir parola istiyor, giriyorsunuz ve “Hatalı Parola” deyip kapanıyor. Hemen hevesle strace ./program yazıyorsunuz. Beklentiniz, programın o parolayı nereyle karşılaştırdığını, dosyamı okuduğunu yoksa ağa mı sorduğunu görmek.
Ama strace çıktısı size sadece şunu söylüyor:
1
2
3
read(0, "deneme123\n", 1024) = 10
write(1, "Hatalı Parola!\n", 15) = 15
exit_group(1)
Bu kadar. Parolayı nereyle kıyasladı? Doğru parola neydi? Neden reddetti? Kernel bunların hiçbirini bilmez. Çünkü “String Karşılaştırma” (strcmp), matematlsel işlemler, şifreleme veya veri ayrıştırma (parsing) işlemleri User Space (Kullanıcı Alanı) içinde, işlemci ve RAM arasında sessizce gerçekleşir. Devlet dairesine (Kernel) dilekçe gitmez.
İşte bu noktada strace‘i kınına sokup, daha sinsi, daha derinlere inen bir ajanı sahneye çağırmamız gerekir: ltrace.
Bu yazıda, uygulamaların kullandığı kütüphanelerin (libc, openssl, libcurl) içine sızacağız. Parola kontrolü yapan fonksiyonları suçüstü yakalayacak, dinamik kütüphanelerin (Shared Libraries) çalışma mantığını anlayacak ve User Space ile Kernel Space arasındaki o kalın çizgiyi netleştireceğiz.
🧱 1. Büyük Resim: Syscall vs Library Call
Linux’ta bir programın dış dünyayla (Donanım, Ağ, Dosya Sistemi) konuşmasının tek yolu System Call (Syscall) yapmaktır. strace bunları yakalar.
Ancak programlar, tekerleği yeniden icat etmezler. Hazır fonksiyon kütüphanelerini kullanırlar (Shared Libraries).
- Ekrana yazı yazmak için
printf(C kütüphanesi - libc) - İki metni kıyaslamak için
strcmp(libc) - Şifreleme yapmak için
AES_encrypt(OpenSSL)
Bu fonksiyonlara Library Call (Kütüphane Çağrısı) denir.
Metafor: Restoran ve Aşçı
- Programınız: Müşteri.
- Kernel: Garson. (Sadece siparişi mutfağa iletir ve yemeği getirir).
- Library (Kütüphane): Masadaki tuzluk, biberlik veya müşterinin kendi çatal bıçağı.
strace (Garsonu izleyen kamera), müşterinin garsona ne sipariş verdiğini görür (“Bana makarna getir” -> read()). Ama strace, müşterinin makarnayı yerken üzerine ne kadar tuz döktüğünü, yemeği kaç parçaya böldüğünü veya arkadaşıyla ne konuştuğunu GÖREMEZ. Bunlar masada (User Space) olur. Garsonu ilgilendirmez.
ltrace, masaya yerleştirilmiş gizli bir mikrofondur. Müşterinin “Tuzu uzatır mısın?” (malloc) veya “Bu yemek çok tuzlu olmuş” (strcmp) gibi kendi içindeki (veya kütüphane ile olan) etkileşimlerini kaydeder.
🔬 2. Nasıl Çalışır? (PLT ve Dinamik Linkleme)
Linux’ta modern programların çoğu Dinamik Linkleme (Dynamic Linking) kullanır. Yani printf fonksiyonunun kodu, programın kendi içinde (.exe dosyasında) bulunmaz. Sistemdeki /lib64/libc.so.6 dosyasında durur.
Program çalışırken printf çağırdığında, aslında doğrudan o adrese gitmez. PLT (Procedure Linkage Table) denen bir sıçrama tahtasına gider. ltrace tam olarak buraya kancayı (hook) takar. Programın PLT tablosuna bir kesme noktası (breakpoint) koyar. Program printf çağırmaya yeltendiğinde, ltrace araya girer:
- Programı durdurur.
- Fonksiyonun adını (
printf) ve parametrelerini (“Merhaba Dünya”) kaydeder. - Fonksiyonun çalışmasına izin verir.
- Fonksiyon bitince geri dönen sonucu (
return value) kaydeder.
Bu sayede, kaynak kodunu görmediğiniz bir programın, hangi fonksiyonları hangi parametrelerle çağırdığını canlı izleyebilirsiniz.
🕵️♂️ 3. Vaka Analizi: Gizli Parolayı Bulmak (CTF Tarzı)
Hadi basit bir senaryo üzerinden gidelim. Elimizde gizli_kasa adında derlenmiş bir program var. Kaynak kodu yok.
1
2
3
./gizli_kasa
Parolayı Girin: 12345
Yanlış Parola!
strace ile baktık, bir şey çıkmadı. Şimdi ltrace zamanı.
1
ltrace ./gizli_kasa
Çıktı akar:
1
2
3
4
5
6
7
__libc_start_main(...)
printf("Parolayı Girin: ") = 16
fgets("12345\n", 100, 0x7f...) = 0x7ffe...
strcspn("12345\n", "\n") = 5
strcmp("12345", "SusamAcil") = -1
printf("Yanlış Parola!\n") = 15
exit(1)
BINGO!
- satıra dikkat edin:
strcmp("12345", "SusamAcil")Program, bizim girdiğimiz “12345” değerini, kendi içindeki “SusamAcil” değeriyle kıyaslıyor (strcmp- String Compare). Ve sonuç-1(Eşit değil) dönüyor.
strace bunu asla göremezdi çünkü karşılaştırma işlemi CPU’nun register’larında yapıldı. Kernel’a bir iş düşmedi. Ama ltrace, strcmp fonksiyonunun (libc kütüphanesi) arasına girerek parametreleri yakaladı.
💡 Kullanım Alanı: Bu yöntem, tersine mühendislik (Reverse Engineering), Malware analizi ve kaybedilen konfigürasyon şifrelerinin kurtarılması için son derece güçlüdür.
4. malloc ve Bellek Sızıntısı (Memory Leak) Takibi
Bir programın çok RAM tükettiğini düşünüyorsunuz ama top dışında elinizde kanıt yok. Programın ne kadar bellek istediğini ve bunu iade edip etmediğini görmek istiyorsunuz. Bellek ayırma işlemi (malloc, calloc) ve iade işlemi (free) birer kütüphane çağrısıdır.
1
2
# Sadece malloc ve free çağrılarını izleyelim (-e filtresi)
ltrace -e malloc+free ./memory_hog
Çıktı:
1
2
3
4
malloc(1024) = 0x55a1...
malloc(2048) = 0x55a2...
free(0x55a1...) = <void>
... (Program devam ediyor) ...
Eğer sürekli malloc görüyor ama hiç free görmüyorsanız, tebrikler, bir Memory Leak (Bellek Sızıntısı) buldunuz. Yazılımcıya bu çıktıyı göndererek “Bak, sürekli yer ayırıyorsun ama temizlemiyorsun” diyebilirsiniz.
5. Konfigürasyon Dosyası Nereye Gitti? (getenv)
Bazen programlar dosya yollarını (Path) çevre değişkenlerinden (Environment Variables) okur. Program çalışıyor ama config dosyasını bulamıyor. strace ile open çağrılarına bakıyorsunuz, hiçbir şey yok. Çünkü program dosya yolunu oluşturamadığı için open çağırma aşamasına gelemiyor bile!
ltrace ile getenv çağrılarını izleyelim:
1
ltrace -e getenv ./myapp
Çıktı:
1
2
getenv("MYAPP_CONFIG_PATH") = NULL
getenv("HOME") = "/home/ali"
Program MYAPP_CONFIG_PATH değişkenini okumaya çalışmış ama NULL (Boş) dönmüş. Demek ki bu değişkeni set etmeyi unuttunuz! Program da varsayılan bir yol olmadığı için sessizce hata moduna geçti. strace bunu gösteremezdi çünkü getenv sadece process’in kendi hafızasındaki environment bloğunu okur, kernel’a gitmez.
⚠️ 6. Karanlık Taraf: ltrace’in Sınırları ve Riskleri
Her kahramanın bir zayıf noktası vardır. ltrace her derde deva değildir.
A. Statik Derlenmiş Programlar (Statically Linked Binaries)
Eğer bir program (özellikle Go programları), kütüphaneleri kendi içine gömülerek (static linking) derlendiyse, ltrace ÇALIŞMAZ. Çünkü ortada dışarıdan çağrılacak bir libc.so yoktur. printf kodu programın içindedir. PLT tablosu yoktur. ltrace kanca atacak yer bulamaz. (Not: Go programları için user space probing veya uprobes gerekir, bu başka bir yazının konusu).
B. Aşırı Yavaşlık
strace, kernel seviyesinde çalıştığı için performansı nispeten az etkiler. Ancak ltrace, programı her fonksiyonda durdurur (sıçrama yapar). Eğer programınız saniyede milyonlarca kez döngü içinde strcmp veya memcpy yapıyorsa, ltrace ile çalıştırdığınızda programın hızı kağnıya döner. Production ortamında ltrace çalıştırırken çok dikkatli olun.
C. Güvenlik Kısıtlamaları
Bazı Linux dağıtımları (Ubuntu, Fedora), güvenlik gereği bir kullanıcının başka süreçleri “trace” etmesini kısıtlar (ptrace_scope). Root olmanız gerekebilir.
🛠️ Profesyonel İpuçları ve Filtreleme
Gerçek hayatta ltrace çıktısı binlerce satır olabilir. Samanlıkta iğne aramamak için filtreleme şarttır.
- Sadece Belirli Kütüphaneyi İzle (
-l): Sadece OpenSSL çağrılarını görmek istiyorsanız:1
ltrace -l libssl.so* ./https_client
- Sadece Belirli Fonksiyonları İzle (
-e): Sadece string işlemlerini gör:1
ltrace -e "str*+mem*" ./text_processor
Çağrı İç İçe Derinliğini Sınırla (
-n): Çıktı çok içeri giriyorsa okunabilirliği artırmak için indentasyonu ayarlayın.- Zaman Damgası (
-T): Hangi kütüphane çağrısı ne kadar sürdü? Performans analizi için.1
Connect(...) = 0 <0.502> (500ms sürmüş)
7. ltrace ve strace Ne Zaman Birlikte Kullanılır?
En iyi debug yöntemi, ikisini birleştirmektir. Bazen bir problemin kökü User Space’te başlar (ltrace), Kernel Space’te biter (strace).
Örnek: DNS Çözümleme.
- User Space (
ltrace): Programgetaddrinfo("google.com")fonksiyonunu çağırır. - Library Logic:
libc,/etc/resolv.confdosyasını okur (User Space logic). - Kernel Space (
strace): Kernel, DNS sunucusuna (8.8.8.8) UDP paketi (syscallsendto) gönderir.
Bu akışı tam anlamak için bazen iki aracı da kullanmak, hatta “Hangi parametreyle girdi, hangi syscall’a dönüştü?” sorusunu cevaplamak gerekir.
👋 Son Söz: Dedektiflik Seviye Atlıyor
Linux sistem programlama serisinin bu bölümünde, Kernel’ın güvenli ama sınırlı dünyasından çıkıp, uygulamaların kaotik ve karmaşık User Space dünyasına adım attık.
Öğrendik ki:
- Syscall (Kernel) her şey değildir. Mantık ve Karar Mekanizmaları User Space’tedir.
stracedışarıyı,ltraceiçeriyi izler.strcmp, parolaları bulmanın anahtarıdır.malloc/freedengesi, bellek sağlığı için kritiktir.
Bir sonraki yazımızda, bu işi bir adım daha ileri götüreceğiz. Hazır araçların yetmediği, kaynak kodunu değiştiremediğimiz ve Production’ı durduramadığımız durumlarda, canlı dokuya müdahale etmemizi sağlayan eBPF ve Dynamic Tracing teknolojilerini konuşacağız.
O zamana kadar, kütüphaneleriniz güncel, sembolleriniz (Debug Symbols) açık olsun. Saklanacak bir şeyiniz yoksa, ltrace‘den korkmanıza da gerek yok :)
