1 puan yazan GN⁺ 2024-08-24 | 1 yorum | WhatsApp'ta paylaş
  • Bu Ghidra eklentisi, bir programın bir bölümünü object file olarak dışa aktarır; dışa aktarılan dosya, semboller ve relocation table gibi geçerli metadata içerdiği için toolchain içinde yeniden işlenebilir
  • Başlıca kullanım alanları ileri düzey binary patching, yazılım portlama, dosya biçimi dönüştürme, kütüphane oluşturma ve decompilation projelerinde programı birden çok object file'a bölerek yeniden uygulamadır
  • Desteklenen kombinasyonlar COFF x86/x86_64, ELF x86/x86_64/MIPS ve OMF x86; COFF MIPS, OMF x86_64 ve OMF MIPS desteklenmez
  • Kullanıcı, Ghidra Listing içinde çıkarılacak adres aralığını seçer, ardından Relocation table synthesizer analyzer'ını çalıştırır ve sonra File > Export Program… içinden relocatable object file exporter'ı çağırır
  • Relocation table sentezi, Ghidra veritabanı doğruluğuna bağlıdır; yanlış veya eksik bilgi varsa relocation'lar bozulabilir ya da eksik kalabilir, bu yüzden dışa aktarmadan hemen önce analyzer'ı yeniden çalıştırmak güvenlidir

Bu eklenti ne yapıyor?

  • Object file exporter extension for Ghidra, bir programın bir bölümünü object file olarak dışa aktarmayı sağlayan bir Ghidra eklentisidir
  • Oluşturulan object file, semboller ve relocation table gibi geçerli metadata içerir
  • Bu metadata sayesinde dışa aktarılan object file, toolchain içinde doğrudan yeniden kullanılarak ek işlemlerden geçirilebilir

Kullanım örnekleri

  • Advanced binary patching
    • Orijinal bölüm ile değiştirilmiş bölümü elle eşleştirmek yerine, bunların birlikte uyumlu hale gelmesi için linker kullanılabilir
  • Software ports
    • Programdan sistemden bağımsız kod ayrıştırılabilir ve geri kalan kısım değiştirilebilir
  • Programları veya object file'ları bir dosya biçiminden diğerine dönüştürebilir
  • Programın bir bölümünü çıkarma ve kütüphane oluşturma
    • Programın bir bölümü çıkarılıp başka bir bağlamda yeniden kullanılabilir
  • Decompilation projelerinde program, birden çok object file'a bölünebilir ve Ship of Theseus yaklaşımıyla yeniden uygulanabilir

Desteklenen mimariler ve object file biçimleri

  • Destek matrisi şöyledir
    • COFF: x86, x86_64 desteklenir / MIPS desteklenmez
    • ELF: x86, x86_64, MIPS desteklenir
    • OMF: x86 desteklenir / x86_64, MIPS desteklenmez

Derleme ve kurulum

  • CLI derleme adımları
    • Depo clone edilir
    • GHIDRA_INSTALL_DIR ortam değişkeni, Ghidra kurulum dizinine ayarlanır
    • gradle buildExtension çalıştırılır
    • Oluşturulan Ghidra eklenti arşivi dist/ dizininde üretilir
  • GitHub Maven deposundan paketi indirmek için kimlik doğrulama gerekir
    • read:packages yetkisine sahip bir GitHub classic token oluşturulur ve ${GRADLE_USER_HOME}/gradle.properties içine githubToken=ghp_xxx eklenir
    • Alternatif olarak gradle installStandaloneDeps çalıştırılarak submodule içindeki vendored dependency derlenip kurulur
  • Kurulum adımları
    • releases page üzerinden eklenti indirilir veya yerelde derlenir
    • Ghidra içinde File > Install Extensions… ile eklenti kurulur
    • CodeBrowser penceresinde File > Configure > Experimental altında RelocationTableSynthesizedPlugin eklentisi etkinleştirilir

Kullanım akışı ve dikkat edilmesi gerekenler

  • Temel kullanım adımları
    • Listing görünümünde çıkarılacak adres kümesi seçilir
    • one-shot mode olarak sunulan Relocation table synthesizer analyzer'ı çalıştırılır
    • File > Export Program… içinde relocatable object file exporter çağrılır
  • Yeniden oluşturulan relocation'lar Window > Relocation table (synthesized) içinde görüntülenebilir
  • Ayrıntılı değerlendirme raporu, Analysis > Auto Analyze... iletişim kutusunda Relocation table synthesizer analyzer'ının Evaluation report policy seçeneği ayarlanarak etkinleştirilebilir
  • Eklentiyi kullanmadan önce tüm programın baştan sona reverse engineering işleminden geçirilmesi gerekmez
  • Başarılı delinking genellikle dışa aktarılacak bölümdeki ve harici referanslardaki metadata'ya büyük ölçüde bağlıdır
    • relocation konumu olarak kullanılan fonksiyonlar ve pointer'lar
    • relocation hedefi olarak kullanılan symbol footprint
    • ikisi arasındaki referanslar
  • Relocation table synthesizer analyzer'ı, Ghidra veritabanının doğruluğuna bağlıdır
    • Hatalı veya eksik bilgi, analiz sırasında bozuk relocation'lara ya da eksik relocation'lara yol açabilir
  • Object file exporter, Relocation table synthesizer analiz sonuçlarına bağlıdır
    • Şüpheli bir durum varsa, relocation table'ın güncel olduğundan emin olmak için object file dışa aktarımından hemen önce analyzer çalıştırılmalıdır

Nasıl çalışıyor?

  • Object file üç bölümden oluşur
    • Relocatable section byte'ları
    • Symbol table

      • Relocation table
      • Linker'ın birden çok object file'dan executable oluştururken yaptığı işlemler
      • Section'ları belleğe yerleştirir
      • Sanal adres alanında symbol adreslerini hesaplar
      • Son symbol adreslerine göre section byte'larına relocation uygular
      • Genellikle bu işlem tamamlandıktan sonra relocation table atılır
      • Debugging symbol'ları korunmazsa symbol table de atılır ve geriye yalnızca relocate edilemeyen section byte'ları kalır
      • Bu eklenti, dikkatli analizle bu verileri yeniden oluşturabilir ve böylece programın yeniden object file olarak delink edilmesini sağlayabilir

1 yorum

 
GN⁺ 2024-08-24
Hacker News yorumları
  • Bunu burada görmek sevindirici. Gerçekten harika bir proje olduğunu düşünüyorum ve MS COFF desteği eklenmesine yardımcı oldum.
    Ancak ilk PR'ım mevcut ELF desteğine kıyasla epey yetersizdi; bu yüzden bir sorun çıkarsa muhtemelen benim hatam olabilir. Yine de geliştiğini görmek mümkün.
    Henüz büyük bir işte kullanmadım ama şimdiye kadarki en eğlenceli denemem, Visual Studio 2003 ile derlenmiş bir Hello World çalıştırılabilir dosyasını delink edip Linux x86 üzerinde GCC+glibc ile yeniden linklemek, sonra da MinGW+msvcrt ile tekrar linklemek oldu.
    Hello World'den daha büyük şeyler hâlâ zor; özellikle Ghidra'ya çok hâkim olmadığım için büyük ikili dosyalarda delink edilecek aralığı seçmenin iyi bir yolunu da henüz bulamadım.
    Tam da bugün bu aracın Nixpkgs türev paketi merge edildi; bu yüzden NixOS unstable'da ghidra.withExtensions ile kurulabiliyor. Konumu ghidra-extensions.ghidra-delinker-extension.
    Ancak birkaç gün önce yeni bir sürüm çıktı ve PR'ı rebase etmediğim için şu anda eski sürümde; yakında bir güncelleme göndermeyi deneyeceğim.

    • Delink edilecek hedefleri izlemenin bir yolu, program ağacındaki klasörleri ve fragment'leri kullanmak.
      Örneğin, özgün çalıştırılabilir dosyayı oluşturan çeşitli nesne dosyalarının adlarını ve aralıklarını saptamış bir Ghidra programınız varsa, ilgili klasöre veya fragment'e sağ tıklayıp Select Addresses ile tamamını seçebilirsiniz.
      Relocation synthesis analyzer ve dışa aktarma da sırasıyla betiklenebilir veya programın ağaç yöneticisi üzerinden otomatikleştirilebilir; böylece istenen aralığı elle seçme, analyzer'ı ve dışa aktarmayı manuel çalıştırma ihtiyacı azalır.
  • Oldukça ilginç görünüyor; birkaç yıl önce bıraktığım oyun reverse engineering projesine tekrar bakmak istememe neden oldu.
    Bunun nasıl kullanılacağını ve çıktısının nasıl değerlendirileceğini baştan sona gösteren eksiksiz bir örnek olsa iyi olurdu.

  • Çalıştırılabilir dosyanın hangi bölümünün dışa aktarılacağını belirlemenin ne kadar iş gerektirdiğini merak ediyorum.
    2008~2015 civarından görece modern bir Win32 oyununu nesne dosyası olarak dışa aktarıp birkaç saat içinde tekrar tam bir çalıştırılabilir dosya hâline derlemek/linklemek gerçekçi mi?

    • Bir değişkenin ya da fonksiyonun ortasından kesmediğiniz sürece oldukça serbest biçimde dışa aktarabilirsiniz; özgün nesne dosyası sınırlarını mutlaka takip etmek gerekmez.
      Neyi dışa aktaracağınız ayrı bir mesele ve program hakkında bilgi gerektirir. Debug sembolleri varsa iş çok daha kolaylaşır; yoksa bile Ghidra veritabanını dışa aktarılabilecek kadar doğru hâle getirdikten sonra genellikle nerede ne olduğuna dair bir fikir edinirsiniz.
      Gönderideki kullanıcı örneğinde, ilk issue Temmuz başında açılmıştı; Ağustos ortası civarında ise işlevsel olarak aynı şekilde çalışan yeniden linklenmiş bir çalıştırılabilir elde edilmişti.
      Ancak o sırada COFF dışa aktarımında düzeltilmesi gereken çok sayıda bug vardı ve i386 analyzer'ının da elden geçirilmesi gereken yerleri bulunuyordu; bu yüzden artık başkalarının aynı sorunlarla daha az karşılaşacağını umuyorum.
      Ne kadar süreceğini bilmiyorum ama debug sembolleri yoksa ve gerçekten çok şanslı değilseniz, birkaç saatten uzun sürme olasılığı yüksek. Deneyimli bir reverse engineer o süre içinde bir şeyleri çalışır hâle getirebilir; ama ilk yükleme ekranının ortasında çökebilir de. İş bitene kadar ne zaman biteceğini bilmediğiniz türden bir uğraşa daha yakın.
  • Güzel görünüyor. Bir gün mevcut programları daha kolay parçalara ayırıp istediğimiz şekilde kullanmamıza yardımcı olabilir.
    Meta'nın LLM Compiler'ı veya LLM kullanarak decompile etme gibi araştırmalar var; programı parçalamak ve bazı bölümleri değiştirmek, LLM'lerin keşfetmesi ve kendi kendini iyileştirmesi için de veri açısından zengin ve ilginç bir alan olabilir.
    Öğrenme açısından da içinde çok sayıda ilginç token saklı gibi görünüyor; bunlarla yapılabilecek şeyler de çok.

  • Dürüst olmak gerekirse kulağa sihir gibi geliyor. Bunun nasıl mümkün olduğunu anlamam lazım

    • Kısaca, bir nesne dosyası üç parçadan oluşur: yeniden konumlandırılabilir bölüm baytları, yeniden konumlandırma tablosu ve sembol tablosu.
      Bağlayıcı birden fazla nesne dosyasından çalıştırılabilir dosya oluştururken bölümleri belleğe yerleştirir, sanal adres alanında sembol adreslerini hesaplar ve ardından nihai sembol adreslerine dayanarak bölüm baytlarına yeniden konumlandırmaları uygular.
      Delink’in püf noktası, bu yeniden konumlandırmaların nereye uygulandığını bulup geri almak ve yeniden konumlandırılabilir baytları tekrar elde etmektir. Sonra geri alınan içeriğe dayanarak yeniden konumlandırma tablosu ve sembol tablosu oluşturup paketlerseniz nesne dosyası ortaya çıkar.
      Gerçekten zor kısım, yeniden konumlandırma noktalarını bulmaya yönelik analizdir. Bunun çoğunu Ghidra’ya bırakıyoruz ama referansları yeniden konumlandırma noktalarına dönüştürmek gerekiyor. x86’da nispeten kolay, MIPS’te ise kâbus gibi zor. Bu uzantıyı, bunun için gereken verileri toplama ve nesne dosyasını serileştirme işini de otomatikleştirmek için yaptım.
    • Her CPU mimarisinde kolay olmayacaktır ama göründüğü kadar akıl almaz bir iş de değil. Temelde bir nesne dosyası ile çalıştırılabilir dosya ya da paylaşımlı kütüphane arasındaki fark çok büyük değildir.
      Microsoft platformları dışında gerçek dosya biçiminin aynı olduğu durumlar da çoktur; örneğin ELF böyledir.
      Büyük fark yeniden konumlandırmadır. Nesne dosyalarında ince ayrıntılı yeniden konumlandırma bilgisi bulunur, çalıştırılabilir dosyalarda ise genellikle yoktur. Windows’un çalıştırılabilir imajlarında, çalıştırılabilir dosya yeniden konumlandırıldığında düzeltilmesi gereken kod ve veri adreslerini gösteren asgari yeniden konumlandırmalar vardır; imajın kendisi ise yalnızca tüm imaj taban adresi düzeyinde yeniden konumlandırılabilir.
      Buna karşılık nesne dosyalarında sembol düzeyinde yeniden konumlandırma bulunur. Bu bilgiyi doğru şekilde yeniden oluşturmak için disassembly’ye semboller hakkında epey doğru bilgi iliştirmek gerekir.
      Bir diğer büyük fark, nesne dosyasının henüz linklenmemiş olmasıdır. Hiçbir sembol çözümlenmiş durumda değildir. Bu aslında düzeltmesi daha kolay bir şeydir; delink sırasında mevcut kapsamın dışındaki bir sembol varsa çoğunlukla çözümlenmemiş sembole çevirmek yeterlidir. Daha sonra yeniden linkleme sırasında başka bir nesne dosyası veya kütüphane o sembolü sağlamalıdır ki tekrar bağlanabilsin.
      Giriş noktası olmaması gibi küçük farklar da vardır ama bunların büyük bir önemi yoktur.
      Dolayısıyla bir çalıştırılabilir imajdan veya paylaşımlı nesneden nesne dosyası kesip çıkaracağınız sınır fiilen keyfidir. İlk derlendiğinde muhtemelen çeviri birimlerine ayrılmıştı ama linkleme aşamasında bu sınırlar pek önemsenmez. Elbette eşleşen bir decompile istiyorsanız nesne dosyası sınırı yanlışsa işler çok zorlaşabilir; bu yüzden mümkünse bunu öğrenmek iyi olur.
      Bu sorunla pratikte uğraştım ama ayrıntılarda biraz yanılıyor olabilirim, o yüzden bunu kabaca böyle değerlendirmek gerekir. Nesne dosyaları hakkında bir blog yazısı yazmayı denemiştim; halihazırda birkaç iyi yazı da var.
  • Bu sürecin tamamen güvenli olup olmadığını merak ediyorum. Başarının her zaman garanti olup olmadığını, yoksa analizin muhafazakâr mı davrandığını bilmek istiyorum.
    Örneğin ELF’te bir parça, veri veya işlev eksikse Delink başarısız mı oluyor?

    • Yanıtlaması karmaşık.
      Analiz aracım, en azından dışa aktarmaya çalıştığınız kısım için doğru bir Ghidra veritabanına dayanıyor. Düzeltilmesi gereken çeşitli sorunları günlüklemek için epey uğraştım ama var olmayan şeyi göremem.
      Özellikle eksik referanslar ve kesilmiş değişkenler tespit edilmez ve tuhaf tanımsız davranışlara yol açabilir.
      Bu sorunların bir kısmını izlemenin yolları var. Şimdiye kadar bulduğum en iyi yöntem, çalıştırılabilir dosyayı farklı bir taban adresiyle yeniden linklemek ve özgün programın adres aralığının eşlenmemesini sağlamak. Böylece kaçırılan mutlak yeniden konumlandırma noktalarında segmentation fault oluşur ve bunlar debug edilebilir. Ancak bu yalnızca hedefte MMU varsa mümkündür.
      Kesilmiş değişkenleri, özellikle şüphelenmiyorsanız, izlemek son derece zahmetlidir. Çünkü bozulan şey kesilmiş değişkenden sonraki bellektir. Bir tamsayıyı pointer sanma durumunu izlemek de zordur. Çünkü tamsayı değeri, hedef sembolün yerleştirildiği adrese göre değişir ve program davranışı tutarsızlaşır; bu özellikle adres alanının çok düşük bir yerine yüklenen programlarda büyük sorun olur.
      Yine de Ghidra veritabanı yeterince doğruysa ve özgün olarak kullanılanla aynı nesne dosyası biçiminde tekrar dışa aktarıp aynı platformu ve aynı araç zincirini kullanırsanız, megabaytlar düzeyinde program kodu ve verisini başarıyla delink edebilirsiniz. Linker’ın yaptığı bir şeyse, geri almak da mümkün olmalı diye düşünüyorum.
      Buna karşılık Linux i386 ELF çalıştırılabilir dosyasından COFF nesne dosyasına delink edip bunu i386 Windows araç zincirinde kullanmak gibi, özgün programın platformu ve araç zinciriyle uyuşmayan çapraz delink işine başlarsanız durum değişir. Dışa aktarma yeniden konumlandırmayı ifade edebiliyorsa çalışan, yeniden konumlandırılabilir bir nesne dosyası elde edebilirsiniz; ama ABI uyumsuzluklarıyla da uğraşmanız gerekir. Mümkün, fakat ilk proje olarak önermem.
      Özetle, ne yaptığınıza ve Ghidra veritabanının doğruluğuna bağlı olarak durum “kendiliğinden çalışır” seviyesinden “Cthulhu’dan merhamet dileme” seviyesine kadar değişir.
    • Sorunun kastettiği anlamda tamamen güvenli değil; zaten olamaz da.
      Örneğin int getSpecialArrayElement(char *array, uint64 key) { i = computeOffset(key); return array[i]; } gibi bir fonksiyonu düşünün.
      computeOffset keyfi derecede karmaşık olabilir; obfuscation istiyorsanız bilerek analiz edilmesi zor hale de getirilebilir. Bu fonksiyonun bellekte keyfi bir konuma erişmesini engelleyen hiçbir şey yoktur.
      Olası tüm girdileri tek tek denemediğiniz sürece, linker’ın bellekte zaten tanımlamış olduğu bir sembole erişip erişmediğini bilemezsiniz; computeOffset içinde böyle bir denemeyi engelleyecek Turing tuzakları da bulunabilir.
  • Daha önce yalnızca hayal edip gerçekten yapmadığım bir fikirle bağlantı kurunca ilginç olabilir. Debug bilgisinden header dosyası üretmek ve gerekirse bunu LLM ile toparlatmak.

    • Aslında buna yönelik birkaç deneme var. Microsoft Program Database için şu var
      https://github.com/wbenny/pdbex
      LLM ile toparlama kısmına gelince, henüz tersine mühendislikte LLM modellerinin uygulanıp büyük başarı elde ettiği çok fazla örnek görünmüyor. Belki de bu alan, LLM mimarisinin sınırlarının ortaya çıktığı yerlerden biri olabilir diye de düşünüyorum
      Uzmanı değilim ama bahis oynayacak olsam, birçok tersine mühendislik kullanımında diffusion modelleri tarafının daha ilginç olacağını düşünürdüm
      Tam olarak aynı şey değil ama Binary Ninja’da, LLM ile disassembly’yi toparlamaya çalışan Sidekick adlı bir özellik var. Kişisel olarak beni pek etkilemedi ama birileri için faydalı olabilir
    • pahole, ELF DWARF bilgisinden derlenebilir C header dosyaları üretebiliyor
      Burada LLM pek ilgili görünmüyor. Header dosyası, çalıştırılabilir dosyanın dışa aktardığı tüm tipleri özgün değerleriyle doğru biçimde içeriyorsa kullanılabilir; aksi halde hatalı ya da eksiktir. LLM’in bir şeyler daha uydurması yardımcı olmaz
      Ghidra’da da veri yapılarını dışa aktarmak için yerleşik bir özellik var ve DWARF yapılarından üretim yapılabiliyor. Sağ tık -> Export to C header
    • Birkaç yıl önce DWARF bilgisinden C API’leri için tip farkında bir fuzzer’ı otomatik üreten ve enjekte eden bir araç yapmıştım: https://github.com/intel/fffc
      Header üretimi ve sonrasında tip kısıtlarına uyacak şekilde değiştirilebilen mutator üretimi de bunun bir parçasıydı
      LLM tarafını eklersek, anonim struct’lar gibi şeylere isim vermek mümkün görünüyor ama bunun iyi bir fikir olup olmadığından emin değilim. Daha ilginç olan, dokümantasyon amacıyla bilinen tip kısıtlarını LLM’in doğal dille açıp özetlemesini denemek olabilir
    • Biraz farklı bir konu ama dışa aktarılan nesne dosyası için, Ghidra veritabanı içeriğine dayanarak debugging sembolleri üretip debug deneyimini iyileştirmeyi düşünmüştüm
      Henüz uygulamamış olmamın nedeni, şimdiye kadar onsuz idare edebilmem. Üstelik epey derin bir tavşan deliği gibi geliyor; içinde bulunduğum tavşan delikleri de zaten yeterince büyük
  • Gerçekten harika görünüyor ve daha önce düşündüğüm oyun modlama fikriyle de bağlantılı. Tenchu decompilation blog serisi de güzeldi

    • Bir gün bu projeye geri dönmem gerekiyor. Üst üste çok fazla version tracking oturumu yaptığım için ara vermem gerekti; bu sırada delink yan görevi de durmadan kontrolden çıkıp büyümeye devam ediyor
  • Şu an yaptığım işte hemen kullanabileceğim bir yer yok ama geçmişte olsaydı gerçekten çok faydalı olacak bir araç gibi görünüyor
    Yakında denemek için zaman ya da fırsat bulabilirsem iyi olur