2011-12-21 27 views
6

64bit'e 32bit web uygulaması geçirme üzerinde çalışıyorum ve eklenti kodumuzda bazı sorunlar yaşıyorum.Doğrudan bir dll okuyarak bir dll bir geçersiz CLR dll olup olmadığını belirleme (64bit sorunu)

32bit sürümünde, tüm .net dll'ler için webapps depo dizini taranır, ardından eklenti özniteliklerimizin varlığını kontrol etmek için Assembly.Load ile yükleyin.

Biz kamu malı kodu kullanarak oldukça şık bir şekilde bu yaptı:

/// <summary> 
/// Returns true if the file specified is a real CLR type, 
/// otherwise false is returned. 
/// False is also returned in the case of an exception being caught 
/// </summary> 
/// <param name="file">A string representing the file to check for 
/// CLR validity</param> 
/// <returns>True if the file specified is a real CLR type, 
/// otherwise false is returned. 
/// False is also returned in the case of an exception being 
/// caught</returns> 
public static bool IsDotNetAssembly(String file) 
{ 
    Stream fs = new FileStream(@file, FileMode.Open, FileAccess.Read); 

    try 
    { 
     BinaryReader reader = new BinaryReader(fs); 
     //PE Header starts @ 0x3C (60). Its a 4 byte header. 
     fs.Position = 0x3C; 
     uint peHeader = reader.ReadUInt32(); 
     //Moving to PE Header start location... 
     fs.Position = peHeader; 
     uint peHeaderSignature = reader.ReadUInt32(); 
     ushort machine = reader.ReadUInt16(); 
     ushort sections = reader.ReadUInt16(); 
     uint timestamp = reader.ReadUInt32(); 
     uint pSymbolTable = reader.ReadUInt32(); 
     uint noOfSymbol = reader.ReadUInt32(); 
     ushort optionalHeaderSize = reader.ReadUInt16(); 
     ushort characteristics = reader.ReadUInt16(); 

     // PE Optional Headers 
     // To go directly to the datadictionary, we'll increase the stream's current position to with 96 (0x60). 
     // 28 bytes for Standard fields 
     // 68 bytes for NT-specific fields 
     // 128 bytes DataDictionary 
     // DataDictionay has 16 directories 
     // 8 bytes per directory (4 bytes RVA and 4 bytes of Size.) 
     // 15th directory consist of CLR header! (if its 0, it is not a CLR file) 

     uint[] dataDictionaryRVA = new uint[16]; 
     uint[] dataDictionarySize = new uint[16];    
     ushort dataDictionaryStart = Convert.ToUInt16(Convert.ToUInt16(fs.Position) + 0x60); 

     fs.Position = dataDictionaryStart; 
     for (int i = 0; i < 15; i++) 
     { 
      dataDictionaryRVA[i] = reader.ReadUInt32(); 
      dataDictionarySize[i] = reader.ReadUInt32(); 
     } 
     if (dataDictionaryRVA[14] == 0) 
     { 
      fs.Close(); 
      return false; 
     } 
     else 
     { 
      fs.Close(); 
      return true; 
     } 
    } 
    catch (Exception) 
    { 
     return false; 
    } 
    finally 
    { 
     fs.Close(); 
    } 
} 

Şimdi problem şimdi 64bit veya platform bağımsız DLL dosyaları işlemek zorunda olduğunu ve ofset değişmiş gibi görünüyor ve bu kod başarısız . Yukarıdaki kodda doğru 64 bit yalnızca geçerli VEYA platform bağımsız dll için doğru dönmek için doğru modifikasyonları bilen var mı?

+1

Yukarıdaki kodu kullanmak zorunda mısın? – Hans

+1

Nifty? Daha çok uygulamaya özgü, varsayım-yapma ve problemle başa çıkma gibi ... oh bekle, zaten yaptı. :) – bzlm

+0

web uygulaması büyük - bin dizininde 100'den fazla dlls ile. Dd'lerin çoğu uygulamamız için eklentiler değildir ve çoğu clr dll değildir, bu yüzden Assembly.Load kullanmak iyi bir seçenek değildir. – Vaevictus

cevap

7

bir x64 Bit DLL ve görüntü opsiyonel başlık boyutu x86 Bit DLL farklı olduğundan kodunuzu x64 Bit dll için çalışmıyor nedeni olduğunu corflags. Belirli bir DLL'nin bir .Net DLL dosyası olup olmadığını belirlemek için değerini belirlemek için farklı görüntü isteğe bağlı başlık boyutlarını hesaba katmanız gerekir. (Sizin kodda olduğu gibi)

ofset PE32 (x86) görüntüler için
  1. 0x60 ve
  2. :

    bölümünde PE file format specification describes 3.4 (Opsiyonel Başlık) farklı uzaklıklar

    veri dizinleri atlamak için PE32 + (x64) resimleri için
  3. ofset değeri 0x70'dir.

verilen bir DLL isteğe bağlı başlığının sihirli bayt okumak zorunda bir x64 Bit DLL olup olmadığını belirlemek amacıyla:

  1. 0x20b değeri PE32 + demektir
  2. 0x10b PE32 değeri. PE32/PE32 + isteğe başlıklar için tanımlanan yapılar da vardır, Windows SDK

    Stream fs = new FileStream(@file, FileMode.Open, FileAccess.Read); 
    
    try 
    { 
        BinaryReader reader = new BinaryReader(fs); 
        //PE Header starts @ 0x3C (60). Its a 4 byte header. 
        fs.Position = 0x3C; 
        uint peHeader = reader.ReadUInt32(); 
        //Moving to PE Header start location... 
        fs.Position = peHeader; 
        uint peHeaderSignature = reader.ReadUInt32(); 
        ushort machine = reader.ReadUInt16(); 
        ushort sections = reader.ReadUInt16(); 
        uint timestamp = reader.ReadUInt32(); 
        uint pSymbolTable = reader.ReadUInt32(); 
        uint noOfSymbol = reader.ReadUInt32(); 
        ushort optionalHeaderSize = reader.ReadUInt16(); 
        ushort characteristics = reader.ReadUInt16(); 
    
        long posEndOfHeader = fs.Position; 
        ushort magic = reader.ReadUInt16(); 
    
        int off = 0x60; // Offset to data directories for 32Bit PE images 
            // See section 3.4 of the PE format specification. 
        if (magic == 0x20b) //0x20b == PE32+ (64Bit), 0x10b == PE32 (32Bit) 
        { 
        off = 0x70; // Offset to data directories for 64Bit PE images 
        } 
        fs.Position = posEndOfHeader;  
    
        uint[] dataDictionaryRVA = new uint[16]; 
        uint[] dataDictionarySize = new uint[16]; 
        ushort dataDictionaryStart = Convert.ToUInt16(Convert.ToUInt16(fs.Position) + off); 
    
        fs.Position = dataDictionaryStart; 
    
        for (int i = 0; i < 15; i++) 
        { 
        dataDictionaryRVA[i] = reader.ReadUInt32(); 
        dataDictionarySize[i] = reader.ReadUInt32(); 
        } 
        if (dataDictionaryRVA[14] == 0) 
        { 
        fs.Close(); 
        return false; 
        } 
        else 
        { 
        fs.Close(); 
        return true; 
        } 
    } 
    catch (Exception) 
    { 
        return false; 
    } 
    finally 
    { 
        fs.Close(); 
    } 
    

    :

Ben senin örneğini genişlettik. Bu yapıların bir açıklaması burada MSDN bulunabilir.

Umut, bu yardımcı olur.

+0

+1. –

+0

Bu mükemmel çalışıyor gibi görünüyor, çok teşekkür ederim. – Vaevictus

2

Çerçevede yöntemleri kullanmamanın bir nedeni var mı? Aşağıdaki örnek kod:

 var assembly = Assembly.Load("path to assembly"); 
     ImageFileMachine machine; 
     PortableExecutableKinds peKind; 
     assembly.ManifestModule.GetPEKind(out peKind, out machine); 

GetPEKind method on MSDN ve PortableExecutableKinds başlamak gerekir. İkincisi temelde

+4

Çözüm değil, Load() yöntemi bir .NET derlemesi değilse veya yanlış .NET sürümünü veya bitliği hedefliyorsa bombalanır. Bacak işini yapmak için –

3

Yansıma kullanmayan ve derlemeleri doğrudan yüklemeyen bir alternatif için, Common Compiler Infrastructure Metadata API'u deneyin. Oldukça kolay load a PE assembly ve bir CLR modülü olup olmadığını belirlemek gibi görünüyor.

MetadataReaderHost host = new PeReader.DefaultHost(); 
var module = host.LoadUnitFrom(args[0]) as IModule; 
if (module == null) 
{ 
    Console.WriteLine(args[0]+" is not a PE file containing a CLR module or assembly."); 
    return; 
}