Tersine mühendislik / rehber
"Stripped ELF dosyalarını anlamlandırmak"
İsimler silindiğinde kalan semboller, unwind verisi ve ayrı debug dosyaları.
Bu sayfada
- 1. strip Komutu Neyi Siler, Neyi Silemez?
- 2. sstrip (Super Strip) ve Bölüm Tablosu Yanılsaması
- Runtime'da Bölümsüz Dosyayı Ortaya Çıkarmak:
- 3. Fonksiyon Sınırlarını Keşfetmenin Gizli Silahı: .eh_frame
- 4. Fonksiyon Giriş Heuristikleri (Prolog Analizi)
- x86-64 Geleneksel Prologue:
- Fonksiyon Bitişi (Epilogue):
- 5. Build-ID ve debuginfod ile Sembolleri Geri Kazanmak
- İncelemeyi Derinleştir
- Kaynaklar
Tersine mühendislik pratiğinde karşılaşılan ikili dosyaların neredeyse tamamı "stripped" (sembolleri arındırılmış) durumdadır. Bir dosya üzerinde strip komutu çalıştırıldığında fonksiyon adları, kaynak kod satır numaraları ve yerel değişken isimleri silinir.
Ancak "stripped" olmak, bir ikili dosyanın tamamen isimsiz veya okunamaz bir bayt yığınına dönüştüğü anlamına gelmez. Dinamik bağlama gereksinimleri, istisna yönetimi (exception handling) tabloları ve derleyicinin ürettiği yapısal izler, dosyanın mimarisini yeniden inşa etmek için zengin ipuçları sunar.
1. strip Komutu Neyi Siler, Neyi Silemez?#
Bir ELF dosyasında iki farklı sembol tablosu bulunabilir:
+-------------------------------------------------------------------------+
| .symtab ve .strtab (Statik Sembol Tablosu) |
| - Tüm fonksiyonların (statik/dahili dahil) ve yerel değişkenlerin adı. |
| - strip komutu bunu TAMAMEN SİLER. |
+-------------------------------------------------------------------------+
| .dynsym ve .dynstr (Dinamik Sembol Tablosu) |
| - Dışarıdan çağrılan veya dışarıya sunulan fonksiyonların adı. |
| - strip komutu bunu SİLEMEZ! Çünkü silinirse dinamik yükleyici |
| (ld-linux.so) çalışma anında sembolleri çözümleyemez. |
+-------------------------------------------------------------------------+
| .debug_* (DWARF Hata Ayıklama Bölümleri) |
| - Kaynak kod dosya yolları, satır numaraları, tip tanımları. |
| - strip komutu bunu TAMAMEN SİLER. |
+-------------------------------------------------------------------------+
| .eh_frame ve .eh_frame_hdr (Unwind Tabloları) |
| - C++ exception handling ve stack unwinding için gereklidir. |
| - strip komutu bunu SİLEMEZ! |
+-------------------------------------------------------------------------+
file ./ornek komutu çıktısında:
not stripped:.symtabmevcuttur.stripped:.symtabsilinmiştir, ancak dinamik bağlıysa.dynsymhâlâ yerindedir.
# Dinamik sembolleri listele (strip edilmiş olsa bile çalışır):
readelf --dyn-syms ./ornek
nm -D ./ornek
2. sstrip (Super Strip) ve Bölüm Tablosu Yanılsaması#
Standart GNU strip, sembolleri temizlese bile dosyanın sonundaki Section Header tablosunu korur. Ancak Brian Raiter'ın geliştirdiği klasik sstrip (Super Strip) aracı, ELF tersine mühendisliğinde çığır açan temel bir gerçeği ispatlamıştır:
Linux çekirdeğinin ELF yükleyicisi (
fs/binfmt_elf.c), dosyadaki Section Header tablosunu (.text,.data,.rodata) asla okumaz. Çekirdek sadece Program Header (PT_LOAD) segmentlerine bakar.
sstrip çalıştırıldığında veya e_shoff = 0 yapıldığında:
readelf -S ./ornekçıktısı "There are no sections in this file" der.- Ghidra, IDA ve statik araçlar bölümleri otomatik sınıflandırmakta zorlanır.
- Ancak çekirdek dosyayı kusursuz biçimde belleğe yükler ve çalıştırır.
Runtime'da Bölümsüz Dosyayı Ortaya Çıkarmak:#
Statik olarak bölüm başlığı olmayan bir ikilinin kod ve veri sınırları çalışma anında /proc/<pid>/maps üzerinden saniyeler içinde çıkarılır:
cat /proc/$PID/maps
Çıktıdaki r-xp izni taşıyan sayfa doğrudan kod (.text), rw-p izni taşıyan sayfa ise veri (.data / .bss) segmentidir. Bölüm adları olmasa dahi çekirdeğin bellek haritası yalan söylemez.
3. Fonksiyon Sınırlarını Keşfetmenin Gizli Silahı: .eh_frame#
C++ programlarında try/catch blokları, C programlarında ise pthread_cancel veya hata ayıklayıcıların çağrı yığını oluşturması (stack unwinding) için derleyici .eh_frame bölümünü oluşturur.
Bu bölüm DWARF Call Frame Information (CFI) kayıtlarını içerir. Her fonksiyon için bir FDE (Frame Description Entry) kaydı bulunur. Bu kaydın içinde:
- Fonksiyonun başlangıç sanal adresi (
initial_location) - Fonksiyonun bayt cinsinden tam uzunluğu (
address_range)
açıkça yer alır! Yani bir ELF stripped olsa dahi, .eh_frame okunarak programdaki neredeyse tüm fonksiyonların başlangıç ve bitiş adresleri kusursuz bir kesinlikle çıkarılabilir:
readelf --debug-dump=frames ./ornek | grep -E "FDE.*pc="
Örnek çıktı:
00000060 0000000000000014 00000064 FDE cie=00000000 pc=0x1140..0x1185
Burada pc=0x1140..0x1185 ifadesi, 0x1140 adresinde başlayıp 0x1185 adresinde biten (uzunluğu 0x45 bayt) kesin bir fonksiyon sınırını gösterir.
4. Fonksiyon Giriş Heuristikleri (Prolog Analizi)#
Eğer dosya -fno-asynchronous-unwind-tables ile derlenmiş ve .eh_frame de temizlenmişse, disassembler'lar fonksiyon sınırlarını mimariye özgü giriş kalıplarıyla (prologue) tespit eder:
x86-64 Geleneksel Prologue:#
endbr64 # f3 0f 1e fa (Intel CET Indirect Branch Tracking)
pushq %rbp # 55
movq %rsp, %rbp # 48 89 e5
subq $0x20, %rsp # Yığında yer açma
Fonksiyon Bitişi (Epilogue):#
leaveq # c9
retq # c3
[!NOTE] Modern derleyicilerde
-fomit-frame-pointervarsayılan olduğundanpush %rbpher zaman bulunmayabilir. Bunun yerine doğrudan yığın işaretçisini ayarlayansub $N, %rspveya sadecerettalimatları aranır.
5. Build-ID ve debuginfod ile Sembolleri Geri Kazanmak#
Modern Linux dağıtımlarında (Ubuntu, Fedora, Debian, Arch) derlenen ikililere benzersiz bir SHA-1 sağlama toplamı olan Build-ID gömülür:
readelf -n ./ornek | grep "Build ID"
Çıktı:
Build ID: a1b2c3d4e5f60718293a4b5c6d7e8f9012345678
Bu kimlik, Linux dünyasının küresel hata ayıklama sunucu protokolü olan debuginfod ile eşleşir. GDB veya debuginfod-find aracı, sistemde kurulu olmasa bile dağıtım depolarından bu ikiliye ait özgün sembol ve kaynak dosyalarını otomatik olarak indirebilir:
debuginfod-find debuginfo a1b2c3d4e5f60718293a4b5c6d7e8f9012345678
İncelemeyi Derinleştir#
Debug sembollerini ayırmayı, dosyayı strip etmeyi ve GDB ile ayrılmış sembolleri çalışma anında bağlamayı uygulamalı görmek için Debug bilgisi laboratuvarı sayfasını tamamlayın. Sürümler arası kod farklarını sembolsüz ortamda eşleştirmek için İkili fark analizi rehberine geçin.