Yürütülebilir dosya anatomisi: PE ve ELF
- Bir ikili dosyayı çalıştırmadan başlığını okuyup PE mi ELF mi olduğunu, bölüm izinlerini ve paketleme izini tanımayı öğrenirsin.
- Windows tarafında PE biçimi, Linux tarafında ELF biçimi işler; ikisini de aynı mantıkla okursun.
- Bu derste Altay Kargo'ya e-postayla düşen şüpheli bir dosyayı, tek satır kod çalıştırmadan yalnız baytlarını okuyarak değerlendirirsin.
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 ikili dosya rastgele bayt yığını değildir. Başlığı, bölümleri ve bir giriş noktası olan düzenli bir yapıdır. Bu derste Altay Kargo'nun güvenlik ekibine e-postayla düşen şüpheli bir dosyayı örnek alırsın. Dosyayı hiç çalıştırmadan, yalnız baytlarını okuyarak ilk kararını verirsin: bu dosya hangi biçim, hangi işletim sistemi için derlenmiş, bölümleri normal mi duruyor.
Windows tarafında PE (Portable Executable) biçimi, Linux tarafında ELF (Executable and Linkable Format) biçimi işler. İkisini de aynı mantıkla okursun. Önce sihirli sayıya bakarsın, sonra bölüm tablosuna, en sonda giriş noktasının konumuna. Üç kontrol birlikte paketli ya da bozulmuş bir dosyayı ilk dakikada ele verir.
Sihirli sayı: ilk dört bayt
Her yürütülebilir dosya bir sözleşmeyle açılır. İlk baytlar işletim sistemine dosyanın türünü söyler. Windows dosyaları MZ harfleriyle, Linux dosyaları 7f ELF dizisiyle başlar. Bu ilk baytlara sihirli sayı (magic number) denir.
Sihirli sayı uzantıdan bağımsızdır. Bir dosyanın adı belge.pdf olabilir ama ilk baytları MZ ise o dosya bir Windows çalıştırılabiliridir. Yükleyici uzantıya bakmaz, ilk baytlara bakar. Analize her zaman buradan başlarsın, çünkü bu ilk karar bütün araç seçimini belirler.
MZ imzasının ardından eski bir DOS başlığı durur. O başlığın 0x3c uzaklığındaki dört bayt bir sayı tutar. Bu sayı, asıl PE başlığının dosyada nerede başladığını söyler ve adı e_lfanew olur. Yükleyici önce 0x3c adresini okur, oradaki değeri alır ve dosyada o uzaklığa gider.
Orada dört baytlık PE imzasını bulur: 50 45 00 00, yani P harfi, E harfi ve iki sıfır bayt. Bu imza gerçek PE başlığının başladığı yerdir. DOS başlığı bugün yalnız bir köprüdür; içindeki minik program dosya DOS ortamında açılırsa kısa bir uyarı yazıp çıkar.
$ xxd -l 16 ornek.exe 00000000: 4d5a 9000 0300 0000 0400 0000 ffff 0000 MZ.............. $ xxd -l 16 ornek.elf 00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF............
$ xxd -s 0x3c -l 4 ornek.exe 0000003c: e800 0000 .... $ xxd -s 0xe8 -l 4 ornek.exe 000000e8: 5045 0000 PE..
xxd komutu dosyanın baytlarını onaltılık düzende ekrana döker. Sol sütun bayt değerlerini, sağ sütun onların yazdırılabilir karşılığını gösterir. -s bayrağı okumaya kaçıncı bayttan başlayacağını, -l kaç bayt okuyacağını söyler.
Küçük uçlu (little-endian) okuma burada önemlidir: e8 00 00 00 baytları sayı olarak 0xe8 eder, ters sırayla değil. x86 dünyasında çok baytlı sayılar bellekte düşük bayt önce durur. Bu kuralı bir kez oturtursan başlıktaki her uzaklık alanını doğru çözersin.
Etkinlik 1 / 8
Komut bir dosyanın ilk baytlarını okur. Çıktı ne der?
Önce kodu oku, sonra çıktıyı seç.
$ xxd -l 16 ornek.exe 00000000: 4d5a 9000 0300 0000 0400 0000 ffff 0000 MZ..............
İlk dört bayt biçimi verdi. PE başlığına ulaşmak içinse e_lfanew alanını okuman gerekir ve bu alan tek başına bir kontrol noktasıdır. Sağlıklı bir dosyada değer küçük bir sayıdır ve dosyanın içini gösterir.
Değer dosya boyutundan büyükse ya da gösterdiği yerde PE imzası yoksa, dosya bozulmuştur ya da elle düzenlenmiştir. Bozuk başlıklar kimi analiz araçlarını yanıltmak için bilerek de üretilir. Bu yüzden imzayı araca bırakmaz, kendi gözünle de doğrularsın.
Etkinlik 2 / 8
PE imzasının dosyadaki yerini gösteren e_lfanew alanı, DOS başlığında hangi onaltılık uzaklıkta durur? 0x____
PE bölümleri: ada değil izne bak
PE başlığı dosyayı bölümlere ayırır. Her bölümün bir adı, bir boyutu ve bir izin kümesi olur. Kod bölümü okunur ve yürütülür.
Veri bölümü okunur ve yazılır. Standart adları ezbere bilmek işini hızlandırır. .text derlenmiş makine kodunu taşır ve okunur artı yürütülür izniyle gelir.
.data ilk değeri verilmiş yazılabilir değişkenleri tutar. .rdata salt okunur veriyi tutar; Microsoft derleyicisinin çıktısında içe aktarma tablosu da çoğu zaman buradadır, kimi derleyiciler ise ayrı bir .idata bölümü açar. .rsrc ikon, dizge tablosu ve gömülü dosyaları taşır. Bu adlar bir sözleşmedir, zorunluluk değil.
İzin kümesi ise yükleyicinin uyduğu gerçek kuraldır. Bu yüzden bölümün ne işe yaradığını addan daha doğru anlatır. Bir dosyayı incelerken önce adları görürsün ama kararı izinler verir.
Bir dosya kod bölümüne istediği adı verebilir. Paketleyiciler (packer) bunu sık yapar. UPX gibi bir paketleyici özgün bölümleri sıkıştırır ve yerine UPX0, UPX1 gibi adlar bırakır. Böyle bir dosyada .text bölümü ya boştur ya çok küçüktür; asıl kod çalışma anında açılıp yazılabilir bir bölüme yerleşir.
Karar verirken ada değil izne ve boyuta bakarsın. Diskte boyutu sıfır görünen ama bellekte büyük yer ayrılan bir bölüm, açılma anında dolacak demektir.
Paketlemeyi ele veren bir ölçü daha vardır: entropi. Entropi bir bölümdeki baytların ne kadar düzensiz dağıldığını ölçer ve bayt başına en çok 8 bit olur. Derleyicinin ürettiği düz kod ve metin tekrar eden kalıplar taşır, bu yüzden değeri orta düzeyde kalır. Sıkıştırılmış ya da şifrelenmiş veri ise 8'e çok yaklaşır.
Diskte küçük, bellekte büyük, W artı X izinli ve entropisi tavana yakın bir bölüm, paketleme şüphesini güçlendirir. Sık yapılan hata tek bir ölçüyle karar vermektir. Sıkıştırılmış bir ikon ya da gömülü bir arşiv de yüksek entropi verir. Bu yüzden işaretlerin birlikte görünmesine bakarsın.
Etkinlik 3 / 8
PE bölümünü taşıdığı içerikle eşleştir.
Bölüm adlarını ve izinleri elle okumak işin mantığını öğretir. Günlük işte ise önce hızlı bir araç çalıştırır, biçimi ve mimariyi tek satırda öğrenirsin. Bu aracın adı file'dır.
Dosyanın baştaki sihirli baytlarını senin yerine okur ve türünü söyler. Dosyayı çalıştırmaz, o yüzden ilk adım risksizdir. Çıktı biçimi, mimariyi ve bağlama türünü özetler.
ELF için 64 bit mi, konum bağımsız mı, dinamik mi bağlı olduğunu görürsün. PE için konsol programı mı, grafik arayüzlü program mı, DLL mi olduğunu görürsün. Bir dosyayla ilk karşılaşmanda çalıştıracağın komut çoğu zaman budur ve uzantıya değil onun çıktısına güvenirsin.
Etkinlik 4 / 8
ornek.bin dosyasının türünü tek komutla öğren.
ELF tarafı: iki ayrı tablo
ELF tarafında iki ayrı tablo vardır ve ikisi ayrı okura seslenir. Program başlıkları (program headers) yükleyiciye hitap eder; hangi parçanın belleğin neresine gideceğini ve hangi izinle duracağını yazar. Yükleme kayıtları PT_LOAD tipindedir.
Bölüm başlıkları (section headers) ise bağlayıcıya ve hata ayıklayıcıya hitap eder; .text, .data gibi bölümleri adlandırır ve sembol tablolarını gösterir. Yükleyici çalışırken bölüm başlıklarına ihtiyaç duymaz. İki tabloyu ayrı ayrı okursun: readelf -l program başlıklarını, readelf -S bölüm başlıklarını döker.
Bu ayrım bir noktada işine yarar. Bölüm başlıkları silinmiş bir ELF dosyası yine de çalışır, çünkü yükleyici program başlıklarını okur. Araçlar ise şaşırır: readelf bölüm göremediğini söyler, hata ayıklayıcı sembol bulamaz.
Bu basit ama etkili bir analiz karşıtı hiledir. Karşılığı da bellidir; program başlıklarından yola çıkıp bölümleri yeniden kuran araçlar dosyayı yine çözer. Bir dosyada bölüm tablosu boşsa hemen pes etmezsin, program başlıklarına dönersin.
ELF dosyaları da paketlenir; UPX Linux ikililerini de sıkıştırır. Başlığın 0x10 uzaklığındaki e_type alanı dosyanın tipini söyler: yeniden konumlanabilir nesne, çalıştırılabilir dosya ya da paylaşımlı nesne.
Bugünkü çoğu Linux çalıştırılabiliri konum bağımsız (PIE) derlenir ve başlıkta paylaşımlı nesne tipini taşır. Bu yüzden paylaşımlı nesne etiketi tek başına dosyanın bir kütüphane olduğunu kanıtlamaz. Tipi başlıktan okur, ama kararı giriş noktasının ve bölümlerin durumuyla birlikte verirsin.
Etkinlik 5 / 8
Her terimi ait olduğu biçime koy.
Ö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/5 seçenek yerleşti.
Başlıktaki öteki ipuçları
İçe aktarma tablosu (import table) başlığın en konuşkan parçasıdır. Tablo, dosyanın hangi kütüphaneden hangi yordamı istediğini listeler. Tek başına bu liste bile niyet hakkında çok şey söyler.
Ağ çağrıları, dosya çağrıları ve kayıt defteri çağrıları yan yana durur. socket ve connect ağ demektir; RegSetValueEx kayıt defterine yazma, yani kalıcılık demektir; CreateFile ile WriteFile dosya yazma demektir.
Bir dosyayı çalıştırmadan, yalnız bu listeyi okuyarak ne yapmaya niyetli olduğunu kabaca çıkarırsın. Listenin kısalığı da bir işarettir. Tabloda yalnız LoadLibrary ile GetProcAddress gibi bir avuç yordam varsa, dosya asıl çağrılarını çalışma anında adıyla arıyor olabilir. Bu, içe aktarma listesini gizlemenin bilinen bir yoludur ve paketli dosyalarda sık görülür.
Giriş noktası (entry point) her iki biçimde de vardır. Yükleyici dosyayı belleğe yerleştirdikten sonra o adrese atlar ve ilk komutu orada çalıştırır. Normal bir derleyici çıktısında giriş noktası kod bölümünün içinde durur. Paketli dosyada ise çoğu zaman açılıcı kodun bulunduğu son bölümü gösterir.
Giriş noktasının hangi bölümün adres aralığına düştüğüne bakmak bu yüzden ilk şüpheyi doğurur. Aralığı bulmak için bölümün başlangıç adresinden başlar, boyutu kadar ilerlersin.
Zaman damgası (TimeDateStamp) ve dijital imza da başlıktadır. Zaman damgası dosyanın derlendiği anı 1970'ten bu yana geçen saniye olarak tutar. Değer elle değiştirilebilir, o yüzden kesin kanıt sayılmaz; yine de aynı damgayı taşıyan örnekleri birbirine bağlar.
Kimi derleyiciler tekrarlanabilir derleme için bu alana zaman yerine bir özet değeri yazar. Bu yüzden anlamsız bir tarih gösteren damga tek başına sahtecilik kanıtı değildir. Dijital imza alanı ise dosyayı imzalayan sertifikayı gösterir.
İmzanın varlığı değil, kimin imzaladığı ve imzanın geçerli olması önemlidir. Bir başka ince nokta da şudur: imza tablosunun adresi bellek adresi değil, doğrudan dosya uzaklığıdır, çünkü sertifika belleğe yüklenmez.
Başlığı okumanın bir faydası da adla içeriği karşılaştırmaktır. Altay Kargo'ya düşen dosyanın adı fatura.pdf olabilir. İlk baytları MZ ise o dosya bir PDF değil, bir Windows çalıştırılabiliridir. Saldırganlar bu farkı sık kullanır.
fatura.pdf.exe gibi çift uzantı, Windows'un bilinen uzantıları gizleyen varsayılan ayarıyla birleşince kullanıcıya masum bir belge gösterir. Tespit tarafında kural basittir: ekleri adıyla değil ilk baytlarıyla sınıflarsın. Uzantısı belge, başlığı çalıştırılabilir olan eki karantinaya alan bir e-posta ağ geçidi kuralı, bu hilenin büyük kısmını kapıda durdurur ve olay kaydı bırakır.
Derinleş:MZ ve Mark Zbikowski
PE dosyasının ilk iki baytı neden MZ? Bu iki harf, MS-DOS'un baş geliştiricilerinden Mark Zbikowski'nin baş harfleridir. Biçim DOS çağında doğdu ve 16 bitlik DOS programlarını taşıdı.
1985'te Windows 1.0 ile gelen NE biçimi eski başlığı atmadı. Onu korudu ve yeni başlığın yerini DOS başlığındaki bir uzaklık alanıyla gösterdi. Windows NT 3.1 ile gelen PE biçimi de aynı yolu izledi. Böylece bir Windows programını DOS altında açan biri çökme yerine kısa bir uyarı görür: "This program cannot be run in DOS mode."
Bugün her PE dosyasının başında duran o küçük DOS programı, kırk yıllık bir geriye dönük uyumluluk kararının izidir. ELF ise başka bir soydan gelir. İlk kez Unix System V Release 4 için yayımlanan ikili arayüz belgesinde tanımlandı. 1999'da da x86 üzerindeki Unix benzeri sistemlerin ortak ikili biçimi olarak benimsendi.
Derinleş:Çalınmış sertifikayla imza
Kod imzalama güven kurar: imzalı bir dosya, işletim sistemi ve güvenlik ürünleri gözünde bir adım öne geçer. Bu güven saldırı yüzeyine dönüşebilir. 2010'da ortaya çıkan Stuxnet solucanı, sürücülerini gerçek ama çalınmış sertifikalarla imzalamıştı; geçerli imza, zararlı sürücünün itirazsız yüklenmesini sağladı.
Ders şudur: bir dosyanın imzalı olması onu güvenli yapmaz. Analizde imzanın varlığına değil, sertifikanın sahibine, geçerlilik zincirine ve iptal durumuna bakarsın.
Microsoft'un Authenticode belgeleri bu alanların nasıl doğrulandığını tanımlar. Aynı ders bir savunma kuralına dönüşür: imzalı diye beyaz listeye almak yerine, imzalayanın kimliğini ve sertifikanın iptal edilip edilmediğini kontrol eden bir doğrulama kurarsın. Saldırganlar sertifikayı çalmak yerine kimi zaman kendi adlarına edinir de. Bu yüzden tanıdık görünen bir imzacı adı da tek başına yetmez.
Etkinlik 6 / 8
Doğru mu, yanlış mı?
Bir dosyanın uzantısı .txt olsa bile içeriği yürütülebilir olabilir.
Demek ki uzantı yalnız bir etikettir; kararı içerik verir. İçerikte en çok işine yarayan alanlardan biri de giriş noktasıdır. Sık yapılan bir hata, giriş noktasını programın main yordamı sanmaktır.
Derleyici giriş noktasına çalışma zamanı kitaplığının başlatma kodunu koyar. Bu kod ortamı hazırlar ve main yordamını sonra çağırır. Giriş noktasının ne olduğunu ve ne olmadığını doğru kurarsan, paketleme şüphesini de doğru kurarsın ve sağlıklı bir dosyayı şüpheli sanmazsın.
Etkinlik 7 / 8
Giriş noktası (entry point) adresi ne işe yarar?
İlk beş dakikanın akışı
Biçimi tanımak neden bu kadar önemli? Çünkü her araç belirli bir biçimi bekler. Yanlış biçimi zorlarsan araç anlamsız çıktı üretir ve saatlerce yanlış yolda yürürsün.
İlk beş dakikayı başlığı okumaya ayırmak, sonraki beş saati kurtarır. Şüpheli bir dosya geldiğinde sıra bellidir.
Önce sihirli sayıya bakıp biçimi belirlersin. Sonra bölüm adlarına ve izinlerine bakarsın. Ardından içe aktarma tablosunu okursun. En sonda giriş noktasının hangi bölüme düştüğünü kontrol edersin.
Bu adımların hepsi dosyayı hiç çalıştırmadan yapılır. Tek satır kod koşmaz, laboratuvar kurmana gerek kalmaz. İlk değerlendirme risksizdir. Ancak burada topladığın ipuçları kanıt değil, yalnız yön verir.
W artı X izinli bir bölüm ya da tek bir socket çağrısı seni bir sonraki adıma, dinamik analize hazırlar. Statik okuma soruyu keskinleştirir; kesin cevabı dinamik analiz verir. İyi analist bu iki aşamayı karıştırmaz ve statik bulguyu dinamik kanıtla ayırır.
Etkinlik 8 / 8
Şüpheli bir dosyanın statik ilk değerlendirmesini doğru sıraya koy.
Bir öğeye odaklan, yukarı ve aşağı ok tuşlarıyla taşı. Home tuşu en üste, End tuşu en alta alır.
- 1Bölüm adlarına ve izinlerine bak
- 2Giriş noktasının hangi bölüme düştüğünü kontrol et
- 3İçe aktarma tablosundan niyeti oku
- 4Sihirli sayıdan biçimi belirle
Okumayı istediğin sırayla sürdürebilirsin. Ders, bütün etkinlikleri cevapladığında tamamlanır.
- Etkinlik 1· Sihirli sayı: ilk dört bayt
- Etkinlik 2· Sihirli sayı: ilk dört bayt
- Etkinlik 3· PE bölümleri: ada değil izne bak
- Etkinlik 4· PE bölümleri: ada değil izne bak
- Etkinlik 5· ELF tarafı: iki ayrı tablo
- Etkinlik 6· Başlıktaki öteki ipuçları
- Etkinlik 7· Başlıktaki öteki ipuçları
- Etkinlik 8· İlk beş dakikanın akışı