Kütüphane çağrılarından niyet çıkarmak
- İçe aktarma tablosu bir programın işletim sisteminden istediği her hizmeti listeler; bu listeyi okuyarak niyeti çalıştırmadan çıkarırsın.
- Çağrıları tek tek değil küme olarak okur, davranışa ve MITRE ATT&CK taktiklerine bağlarsın.
- Bu derste gizlenen çağrıyı tanımayı ve kısa tablonun ne anlattığını öğrenirsin.
Puan bütün etkinlikleri cevaplayınca hesaba yazılır. Bu dersi tamamlayınca +50 XP alacaksın. Giriş yapmadan ilerlersen puan yalnız bu tarayıcıda durur.
Bir program tek başına hiçbir şey yapamaz. Dosyaya, ağa, kayıt defterine ve belleğe işletim sistemi üstünden erişir.
Dosya açmak, soket kurmak, kayıt defterine yazmak, süreç başlatmak; hepsi tanımlı çağrılarla olur ve hepsi listelenebilir. Zararlı yazılım da bu kuralı değiştirmez; o da sıradan yazılım gibi sistemden hizmet ister. Bu derste bu isteklerin listesini okur ve dosyanın niyetini çalıştırmadan çıkarırsın.
İçe aktarma tablosu nedir
Bu liste içe aktarma tablosudur. PE dosyalarında başlıktaki bir yapı, hangi kütüphaneden hangi yordamın istendiğini sırayla yazar. Tabloyu okumak, programın yapabileceklerinin ilk resmini verir.
Tablonun dolu olması niyeti açık eder ama boş olması temizlik kanıtı değildir: bir çağrı çalışma anında da çözülebilir ve o zaman tabloda görünmez. Bu yüzden tabloyu bir başlangıç noktası sayarsın, son söz olarak değil.
Tablonun iki yüzü vardır ve ikisini ayırmak işine yarar. Ad tablosu, istenen yordamların adlarını tutar; bunu sen okursun. Adres tablosu diskte ad tablosunun bir kopyasıdır. Program yüklenirken yükleyici bu kopyanın üstüne her yordamın gerçek bellek adresini yazar; program çalışırken bu adresleri kullanır.
Diskteki dosyada adres tablosu henüz gerçek adresleri taşımaz. Bu ayrımı bilmek, ileride bir dosyayı bellekten döküp çözerken neyi onarman gerektiğini anlamana yardım eder: döküm sırasında adres tablosu gerçek adreslerle doludur ama ad bağları kopuktur. Araçlar tabloyu yeniden kurmadan dosyayı düzgün açamaz.
$ rabin2 -i ornek.exe KERNEL32.dll CreateFileW KERNEL32.dll WriteFile KERNEL32.dll CreateProcessW KERNEL32.dll VirtualAllocEx ADVAPI32.dll RegSetValueExW WININET.dll InternetOpenUrlW
Bu listeyi satır satır oku. İlk iki satır dosya işlemidir: aç ve yaz. Üçüncü satır yeni süreç başlatır. Dördüncü satır başka bir sürecin içinde bellek ayırır.
Beşinci satır kayıt defterine yazar, yani kalıcılık. Altıncı satır bir adrese ağ isteği gönderir. Tek tek bakıldığında her çağrının zararsız bir kullanımı var. Ama altısı bir arada görününce resim netleşir: bu dosya dışarıdan bir şey indirip diske yazan, kalıcı olan ve başka bir sürece dokunan bir yükleyicidir.
Çağrıları ailelere ayırmak okumayı hızlandırır. Ağ ailesi dışarıyla konuşur: WSAStartup ağ kütüphanesini başlatır, InternetOpenUrlW bir adrese istek gönderir, socket ile connect doğrudan bir sunucuya bağlanır. Kalıcılık ailesi yeniden başlatmadan sonra da çalışmayı sürdürür: RegSetValueExW bir Run anahtarına değer yazar, CreateServiceW yeni bir Windows hizmeti kurar.
Süreç ve bellek ailesi başka bir sürece dokunur: VirtualAllocEx hedef süreçte yer ayırır, WriteProcessMemory oraya veri yazar, CreateRemoteThread o veriyi çalıştırır. Hangi ailenin kaç üyesini gördüğün, dosyanın profilini çizer.
Etkinlik 1 / 6
Her API çağrısını anlattığı niyete göre ayır.
Önce bir seçeneğe, sonra aşağıdaki uygun kutuya bas. İstersen seçeneği kutuya sürükleyip bırak. Yerini değiştirmek için aynı işlemi tekrarla.
0/6 seçenek yerleşti.
Gizlenen çağrı: dinamik çözümleme
Tablo her zaman dolu olmaz. Program adresleri çalışma anında da çözebilir. LoadLibrary ile kütüphaneyi belleğe yükler, GetProcAddress ile yordamın adresini ada göre sorar. Böylece asıl çağrı, örneğin CreateProcess, içe aktarma tablosunda hiç görünmez; tabloda yalnız LoadLibrary ile GetProcAddress durur.
MITRE ATT&CK bu tekniği dinamik API çözümleme olarak adlandırır. Yalnız tabloya bakan analist bu çağrıyı tümden kaçırır.
Adı gizlemenin başka yolları da var. Gecikmeli yükleme bazı çağrıları ilk kullanımda çözer ve o ana kadar ayrı bir listede tutar.
Sıra numarasıyla içe aktarma, yordamın adını değil kütüphanedeki sıra numarasını yazar; tabloda ad yerine bir sayı durur. İki durumda da çözüm aynıdır: GetProcAddress'e verilen dizeyi ya da doğru sürümdeki kütüphanenin sıra tablosunu izleyerek sayıyı ada çevirirsin. Gizlemek çağrıyı yok etmez, yalnız bir adım geriye saklar.
GetProcAddress'e verilen adın kendisi de gizlenebilir. Program, CreateProcessA dizesini açık yazmak yerine bu dizeyi şifreli tutar ve çağrıdan hemen önce çözer. Ya da her yordam adının bir sayısal özetini saklar ve kütüphanedeki yordamları tek tek özetleyip eşleşeni bulur. Buna API özetleme denir.
Bu durumda strings tarama boş döner, çünkü ad hiçbir yerde düz durmaz. Çözüm, çözme yordamını okumaktır: hangi sayının hangi ada denk geldiğini çıkarmak için aynı özet işlevini bilinen kütüphane adlarına uygularsın. Zahmetli ama kesin bir yoldur.
Etkinlik 2 / 6
Dinamik çözümleme ile API adını gizleyen satırı bul.
Araçla yetenek çıkarma: CAPA
Çağrıları elle okumak güçlüdür ama yavaştır. CAPA bu okumanın bir bölümünü hızlandırır.
Araç, kod ve çağrı desenlerini bir kural kümesiyle eşleştirir ve dosyanın yeteneklerini çıkarır: Run anahtarıyla kalıcılık, RC4 ile veri şifreleme, süreç listesini gezme gibi. Daha da önemlisi, yetenekleri MITRE ATT&CK taktik ve tekniklerine bağlar. Çıktı hızlı bir harita verir ama kanıt değildir; her satırı kodda doğrularsın.
$ capa ornek.bin ATT&CK Tactic: Persistence Capability: persist via Run registry key [T1547.001] ATT&CK Tactic: Execution Capability: link function at runtime on Windows [T1129]
Bu çıktıyı oku. İlk blok kalıcılık taktiğini ve Run anahtarıyla kalıcılık yeteneğini söylüyor; parantezdeki numara ilgili ATT&CK tekniğidir.
İkinci blok yürütme taktiğini ve çalışma anında yordam bağlama yeteneğini söylüyor. Bu, LoadLibrary ile GetProcAddress deseninin araçtaki adıdır. İki satır sana nereye bakacağını söyledi: kayıt defteri yazan yordamı ve adresleri ada göre çözen yordamı. Araç yön verdi, kararı sen kodda doğrulayarak verirsin.
Etkinlik 3 / 6
CAPA ile ornek.bin dosyasının yeteneklerini çıkar.
Davranışı taktiğe bağlamak
MITRE ATT&CK, saldırgan davranışlarını ortak bir dile oturtan bir çerçevedir. En üst düzeyde taktikler durur: saldırganın o adımdaki amacı. Her taktiğin altında teknikler ve alt teknikler yer alır: o amaca ulaşmanın belirli yolları.
Kalıcılık bir taktiktir; Run anahtarına yazmak onun bir alt tekniğidir. Bu ortak dil sayesinde iki farklı analist aynı davranışı aynı etiketle anar ve raporlar birbirine bağlanır. Çerçeveyi kullanmak, bulgunu dünyanın geri kalanının anladığı bir biçime çevirir.
Davranışı taktiğe bağlamak raporu güçlendirir. Run anahtarına yazmak kalıcılık taktiğidir. Başka sürece kod yazmak savunmadan kaçınma taktiğidir.
Uzak uca düzenli istek atmak komuta ve kontrol taktiğidir. Belgeleri şifreleyip fidye notu bırakmak etki taktiğidir. Taktik, çağrının amacını anlatır; teknik adını ezberlemek yerine amacı yazmak, raporu okuyan kişiye ne yapacağını söyler.
Bu eşleme savunma ekibine doğrudan iş verir. Taktiği bilen ekip hangi kaydı toplayacağını ve hangi kuralı yazacağını bilir. Kalıcılık için Run anahtarındaki değişiklikleri izler.
Enjeksiyon için VirtualAllocEx ve WriteProcessMemory çağrı dizisini arar. Komuta ve kontrol için düzenli aralıklı dış bağlantıları işaretler. Yalnız çağrı adı yazan rapor bu adımı okuyucuya bırakır ve çoğu zaman kimse o adımı atmaz.
Uç nokta izleme araçları tam bu çağrı kümelerini dinler. Sysmon gibi bir araç süreç başlatmayı, uzak bir iş parçacığı oluşturmayı ve kayıt defteri değişimini ayrı olaylar olarak kaydeder.
EDR (uç nokta tespit ve müdahale) ürünleri bu olayları birleştirip bir desen arar. Aynı süreç önce başka bir süreçte bellek ayırıyor, sonra oraya yazıyor ve orada bir iş parçacığı başlatıyorsa bu enjeksiyon desenidir ve alarm üretir. Statik analizde içe aktarma tablosunda gördüğün üçlü, canlı sistemde bu telemetriye dönüşür. İki taraf aynı davranışa iki ayrı pencereden bakar; statik okuma, hangi pencereyi açacağını önceden söyler.
Etkinlik 4 / 6
Davranışı MITRE ATT&CK taktiğiyle eşleştir.
Çağrı kümeleri ve karar
Çağrıları tek tek değil küme olarak okursun. Tek bir dosya açma çağrısı hiçbir şey söylemez. Belirli kümeler ise belirli davranışları anlatır.
CreateToolhelp32Snapshot ile Process32Next ikilisi çalışan süreçleri gezer; bu, süreç keşfidir ve çoğu zaman ya hedef süreci bulmak ya da analiz araçlarını aramak için yapılır. VirtualAllocEx, WriteProcessMemory ve CreateRemoteThread üçlüsü başka bir sürece kod yerleştirmenin klasik yoludur. Kümeyi tanımak, tek çağrının söyleyemediğini söyler.
Çağrıların hangi sırayla kullanıldığı da anlam taşır. Aynı küme farklı sırayla bambaşka bir davranış üretir.
Bellek ayırıp sonra yazmak ve çalıştırmak enjeksiyondur; ama önce dosya okuyup sonra ağa göndermek veri sızdırmadır, oysa iki senaryo da benzer çağrıları içerir. Bu yüzden tabloyu okuduktan sonra koda inip çağrıların gerçek sırasını doğrularsın. Bir kütüphane dosyasını incelerken dışa aktarma tablosuna da bakarsın: o tablo, dosyanın dışarıya hangi yordamları açtığını yazar ve zararlı bir kütüphanede açılan tek bir yordam çoğu zaman asıl giriş noktasıdır.
Boş ya da çok kısa bir içe aktarma tablosu da bilgi taşır. Sıradan bir program onlarca kütüphaneden yüzlerce yordam ister.
Elinde yalnız birkaç çağrı varsa, çoğu zaman LoadLibrary, GetProcAddress ve bellek ayıran bir çağrı, dosya ya paketlidir ya da her şeyi çalışma anında çözer. İki durumda da statik tablo okuma tıkanır ve bir sonraki adıma, paketlemeyi tanımaya ya da dinamik analize geçersin. Kısa tablo temizlik değil, saklama işaretidir.
Derinleş:Kancanın altına inen çağrı: ntdll
Güvenlik ürünleri kullanıcı modundaki kütüphanelere kanca takar: bir çağrı geçtiğinde araya girip inceler. Kanca kernel32 gibi üst kütüphanelerde de, çekirdeğe en yakın kütüphane olan ntdll içinde de durabilir. Bazı örnekler üst katı atlar ve ntdll içindeki Nt ile başlayan yordamları doğrudan çağırır. MITRE ATT&CK bunu yerel API kullanımı olarak adlandırır.
Analizde bunun izi şudur: içe aktarma tablosunda tanıdık üst düzey çağrılar yoktur ama NtCreateFile, NtWriteVirtualMemory gibi düşük düzey adlar görünür. Bazı örnekler ntdll'i de atlayıp sistem çağrısını kendisi yapar. Savunma bu yüzden yalnız kullanıcı modundaki kancaya güvenmez; çekirdeğin kendi olay kaynaklarını da dinler, çünkü her yol sonunda çekirdek sınırından geçer.
Etkinlik 5 / 6
Bir örnekte CreateToolhelp32Snapshot ve Process32Next çağrıları birlikte görünüyorsa ilk yorum ne olur?
Etkinlik 6 / 6
Doğru mu, yanlış mı?
Birkaç satıra inmiş bir içe aktarma tablosu, dosyanın paketli olduğunu ya da çağrı adreslerini LoadLibrary ile GetProcAddress üzerinden çalışma anında çözdüğünü düşündürür.
Okumayı istediğin sırayla sürdürebilirsin. Ders, bütün etkinlikleri cevapladığında tamamlanır.