Soru:
Makine kodu çözümleyicileri, örneğin CLR ve JVM için olanlardan neden daha az yeteneklidir?
Rolf Rolles
2013-03-27 15:12:24 UTC
view on stackexchange narkive permalink

Java ve .NET kod çözücüler (genellikle) neredeyse mükemmel bir kaynak kodu üretebilir, genellikle orijinaline çok yakın.

Neden aynı şey yerel kod için yapılamıyor? Birkaçını denedim ama ya işe yaramıyorlar ya da işaretçilerle bir sürü goto ve yayın üretiyorlar.

Bu yazıyı yazmış olmanız harika, ancak yine de bir Soru-Cevap şeklinde olması gerekiyor. Bunu bir dizi soruya dönüştürebilseydin, o zaman daha da iyi olurdu :)
Bu daha iyi mi?
Üst düzey kodun kurtarılmasını nasıl zorlaştıracağınız konusunda gerçekten genişliyor musunuz? Sorunun bu kısmını atlar ve bunu kod çözme ile ilgili yapardım. Cevabınız imo olsa da çok güzel.
@IgorSkochinsky Az önce Hex-Rays çözümleyicinizi bu düzenlemeyle boktan mı dediniz? : P
Pekala, bu tür soruların çoğunda okuyabileceğiniz genel duyarlılıkla gidiyordum :)
Daha güzel yapmaya çalıştım. Hala sorunun Rolf ruhunu yakalayıp yakalamadığından emin değil misiniz?
Evet, işe yarıyor. Temelde onu gelecekte bahsedilebilsin diye yazdım, bu yüzden başlığın ne olduğu umrumda değil. Bununla birlikte, başlığınız sorgulamanın ve cevabın ruhunu mükemmel bir şekilde yansıtıyor, bu yüzden bana harika görünüyor.
Iki yanıtlar:
#1
+40
Rolf Rolles
2013-03-27 15:12:24 UTC
view on stackexchange narkive permalink

TL; DR: makine kodu çözücüler çok kullanışlıdır, ancak yönetilen diller için sağladıkları mucizelerin aynısını beklemeyin. Birkaç sınırlamayı belirtmek gerekirse: Sonuç genellikle yeniden derlenemez, orijinal kaynak kodundaki isimler, türler ve diğer önemli bilgilerden yoksundur, orijinal kaynak kodu eksi yorumlardan çok daha zor okunabilir ve garip bırakabilir kod çözme listesindeki işlemciye özgü yapılar.

  1. Derleyici neden bu kadar popüler?

    Ayrıştırıcılar çok çekici ters mühendislik araçlarıdır çünkü çok fazla işten tasarruf etme potansiyeline sahipler. Aslında, Java ve .NET gibi yönetilen diller için o kadar mantıksız bir şekilde etkilidirler ki, "Java ve .NET tersine mühendislik" neredeyse bir konu olarak mevcut değildir. Bu durum, birçok yeni başlayan kişinin aynı şeyin makine kodu için de geçerli olup olmadığını merak etmesine neden olur. Maalesef durum bu değil. Makine kodu çözücüler mevcuttur ve analistin zamanından tasarruf etmede faydalıdır. Ancak, bunlar yalnızca çok manuel bir sürece yardımcı olurlar. Bunun doğru olmasının nedeni, bayt kodu dili ve makine kodu çözücülerinin farklı zorluklarla karşı karşıya kalmasıdır.

  2. Özgün değişken adlarını derlenmiş kaynakta görecek miyim? kod?

    Bazı zorluklar, derleme süreci boyunca anlamsal bilgi kaybından kaynaklanır. Yönetilen diller, genellikle bir nesne içindeki alanların adları gibi değişkenlerin adlarını korur. Bu nedenle, insan analisti programcının yarattığı ve anlamlı olmasını umduğu isimlerle sunmak kolaydır. Bu, derlenmiş makine kodunu anlama hızını artırır.

    Öte yandan, makine kodu programları derleyicileri, programı derlerken genellikle bu bilgilerin çoğunu yok ederler (belki de bir kısmını hata ayıklama bilgileri biçiminde geride bırakırlar). Bu nedenle, bir makine kodu çözücüsü her yönden mükemmel olsa bile, insan kavrama hızını yavaşlatan bilgilendirici olmayan değişken adları ("v11", "a0", "esi0" vb.) .

  3. Derlenmiş programı yeniden derleyebilir miyim?

    Bazı zorluklar programı sökmekle ilgilidir. Java ve .NET gibi bayt kodu dillerinde, derlenen nesne ile ilişkili meta veriler genellikle nesne içindeki tüm kod baytlarının konumlarını açıklayacaktır. Yani, tüm işlevler, nesnenin başlığındaki bazı tabloda bir girişe sahip olacaktır.

    Öte yandan, makine dilinde, örneğin, x86 Windows demontajını, bir PDB, demonte edici, ikili içerisindeki kodun nerede olduğunu bilmez. Programın giriş noktası gibi bazı ipuçları verilmiştir. Sonuç olarak, makine kodu çözücüler, ikili kod içindeki kod konumlarını keşfetmek için kendi algoritmalarını uygulamaya zorlanır. Genellikle iki algoritma kullanırlar: doğrusal tarama (genellikle bir işlevin başlangıcını belirten bilinen bayt dizilerini arayan metin bölümünde tarama) ve özyinelemeli geçiş (sabit bir konuma yönelik bir çağrı talimatıyla karşılaşıldığında, bu konumu kod içeriyor olarak düşünün ).

    Bununla birlikte, doğrusal süpürme bileşeninin başarısız olmasına neden olan işlev prologlarını değiştiren prosedürler arası kayıt tahsisi gibi derleyici optimizasyonları ve doğal olarak meydana gelen dolaylı kontrol akışı ( yani, işlev göstericisi aracılığıyla çağrı) özyinelemeli geçişin başarısız olmasına neden olur. Bu nedenle, bir makine kodu çözücüsü bunun dışında bir sorunla karşılaşmasa bile, genellikle bir programın tamamı için bir derleme oluşturamaz ve bu nedenle sonuç yeniden derlenemez.

    Kod / Yukarıda açıklanan veri ayırma problemi, Durdurma Problemi gibi diğer imkansız problemlerle paylaştığı "kararsız" problemler adı verilen özel bir teorik problem kategorisine girer. Bu nedenle, orijinal ikilinin bir klonunu elde etmek için yeniden derlenebilecek çıktılar üretecek otomatik bir makine kodu çözücü bulma umudunu bırakın.

  4. Şu konuda bilgi alacak mıyım? derlenmiş program tarafından kullanılan nesneler?

    C ve C ++ gibi dillerin, yönetilen dillere karşı nasıl derlendiğine ilişkin zorluklar da vardır; Tür bilgilerini burada tartışacağım. Java bayt kodunda, nesneleri ayırmak için 'yeni' adında özel bir talimat vardır. Ayrılacak nesneyi tanımlayan .class dosyası meta verilerine bir referans olarak yorumlanan bir tamsayı bağımsız değişkeni alır. Bu meta veriler sırasıyla sınıfın düzenini, üyelerin adlarını ve türlerini vb. Açıklar. Bu, sınıfa yapılan referansları insan müfettişinin hoşuna gidecek şekilde derlemeyi çok kolaylaştırır.

    Bir C ++ programı derlendiğinde ise, RTTI gibi hata ayıklama bilgilerinin yokluğunda, nesne oluşturma düzgün ve düzenli bir şekilde yapılmaz. Kullanıcı tanımlı bir bellek ayırıcı çağırır ve daha sonra ortaya çıkan işaretçiyi yapıcı işlevine bir argüman olarak iletir (bu da satır içi olabilir ve dolayısıyla bir işlev olmayabilir). Sınıf üyelerine erişen talimatlar sözdizimsel olarak yerel değişken referanslarından, dizi referanslarından vb. Ayırt edilemez. Ayrıca, sınıfın düzeni ikilinin herhangi bir yerinde saklanmaz. Aslında, ayıklanmış bir ikili dosyadaki veri yapılarını keşfetmenin tek yolu veri akışı analizidir. Bu nedenle, bir derleyicinin durumla başa çıkabilmek için kendi tür yeniden yapılandırmasını uygulaması gerekir. Aslında, popüler kod çözücü Hex-Rays, bu görevi çoğunlukla insan analiste bırakıyor (yine de insan için yararlı yardım sunuyor).

  5. Temelde ayrıştırma olacak mı? kontrol akışı yapısı açısından orijinal kaynak koduna benziyor mu?

    Bazı zorluklar derleyici optimizasyonlarının derlenmiş ikiliye uygulanmasından kaynaklanıyor. "Kuyruk birleştirme" olarak bilinen popüler optimizasyon, programın kontrol akışının, daha az agresif olan derleyicilere kıyasla bozulmasına neden olur, bu da genellikle kendini kod çözme içinde çok sayıda goto ifadesi olarak gösterir. Seyrek anahtar deyimlerinin derlenmesi benzer sorunlara neden olabilir. Öte yandan, yönetilen dillerde genellikle anahtar deyimi talimatları bulunur.

  6. İşlemcinin belirsiz yönleri söz konusu olduğunda kod çözücü anlamlı çıktılar verecek mi?

    Bazı zorluklar, söz konusu işlemcinin mimari özelliklerinden kaynaklanmaktadır. Örneğin, x86'daki yerleşik kayan nokta birimi bir çetin kabustu. Kayan nokta "kayıtları" yoktur, bir kayan nokta "yığını" vardır ve programın düzgün şekilde derlenebilmesi için tam olarak izlenmesi gerekir. Bunun tersine, yönetilen diller genellikle, kendileri de değişken olan kayan nokta değerleriyle başa çıkmak için özel talimatlara sahiptir. (Hex-Rays kayan nokta aritmetiğini gayet iyi idare eder.) Veya x86'da yüzlerce yasal talimat türü olduğunu düşünün; bunların çoğu, kullanıcı bunu açıkça belirtmeden normal bir derleyici tarafından asla üretilmez. içsel. Bir derleyici çözücü, yerel olarak desteklediği bu talimatlar için özel işlemler içermelidir ve bu nedenle çoğu derleyici, satır içi derleme veya (en iyi durumda) desteklemeyenler için iç bilgiler kullanarak derleyiciler tarafından en yaygın olarak oluşturulanlar için desteği içerir. >

Bunlar, makine kodu çözücüleri rahatsız eden erişilebilir zorluk örneklerinden yalnızca birkaçıdır. Öngörülebilir gelecekte sınırlamaların devam etmesini bekleyebiliriz. Bu nedenle, yönetilen dil çözümleyicileri kadar etkili sihirli bir madde aramayın.

Ek yönler için yeni bir cevap mı tercih edersiniz yoksa bunları cevabınızda düzenler misiniz? Genelde bu temsilci seviyesinde düzenleme yapmaktan rahatsız oluyorum (belki özel betalar için farklı mı?), Çünkü bir kuyrukta falan bitiyor. Fakat herneyse. Peki hangisi? :)
Düzenlemekte özgürsünüz veya yeni konular önerebilirsiniz, ben onu düzenleyeceğim.
6. Kod * boru hattı optimizasyonundan * geçtiğinde, tek işlemlerin mantıksal bir dizisi önceki ve / veya sonraki mantıksal işlem blokları ile karışabilir.
#2
+7
Ed McMan
2013-03-27 22:48:57 UTC
view on stackexchange narkive permalink

Derlemeyi çözme zordur çünkü derleyicilerin ikili / bayt kodu hedefinde eksik olan kaynak kodu soyutlamalarını kurtarması gerekir.

Birkaç tür soyutlama vardır:

  • İşlevler: Yüksek bir işleve karşılık gelen kodun girişi, bağımsız değişkenleri, dönüş değerleri ve çıkışı ile tanımlanması.
  • Değişkenler: Her işlevdeki yerel değişkenler ve herhangi bir genel veya statik değişken.
  • Türler: Her değişkenin türü ve her işlevin bağımsız değişkenleri ve dönüş değeri.
  • Yüksek düzey kontrol akışı: Bir programın kontrol akış şeması, ör. while (. ..) {if (...) {...} else {...}}

Bu soyutlamaların hiçbiri açıkça temsil edilmediğinden yerel kodun yeniden derlenmesi zordur yerel kodda. Bu nedenle, güzel derlenmiş kod üretmek için (yani, her yerde goto ’ları kullanmamak), kod çözücülerin bu soyutlamaları yerel kodun davranışına göre yeniden oluşturmaları gerekir. Bu zor bir süreçtir ve bu soyutlamaların nasıl çıkarılacağına dair birçok makale yazılmıştır. Başlangıç ​​olarak Balakrishnan ve Lee 'ye bakın.

Bunun tersine, bayt kodunun derlemesini çözmek daha kolaydır çünkü genellikle tür kontrolüne izin verecek kadar bilgi içerir . Sonuç olarak, bayt kodu tipik olarak işlevler (veya yöntemler), değişkenler ve her değişkenin türü için açık soyutlamalar içerir. Bayt kodunda eksik olan birincil soyutlama, yüksek seviyeli kontrol akışıdır.



Bu Soru-Cevap, otomatik olarak İngilizce dilinden çevrilmiştir.Orijinal içerik, dağıtıldığı cc by-sa 3.0 lisansı için teşekkür ettiğimiz stackexchange'ta mevcuttur.
Loading...