2011-12-21 14 views
6

पढ़ कर एक डीएल एक। Valid सीएलआर डीएल है, मैं 32 बिट वेब एप्लिकेशन को 64 बिट में माइग्रेट करने पर काम कर रहा हूं और हमारे प्लगइन लोडर कोड के साथ कुछ समस्याएं हैं।यह निर्धारित करना कि पीई सीधे (64 बिट अंक)

32 बिट संस्करण में, हम सभी .net dlls के लिए वेबपैस बिन निर्देशिका स्कैन करते हैं, फिर हमारे प्लगइन विशेषताओं की उपस्थिति की जांच के लिए उन्हें Assembly.Load के साथ लोड करें।

हम एक नहीं बल्कि गंधा तरह से ऐसा किया सार्वजनिक क्षेत्र कोड का उपयोग:

/// <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(); 
    } 
} 

अब समस्या अब हम 64 बिट या मंच स्वतंत्र DLLs को संभालने के लिए है और ऑफसेट बदल गया है लगता है और इस कोड में विफल रहता है । क्या कोई भी उपरोक्त कोड में सही 64 बिट केवल या मंच स्वतंत्र डीएलएस के लिए सही लौटने के लिए सही संशोधन जानता है?

+1

क्या आपको वास्तव में उपरोक्त कोड का उपयोग करना है? – Hans

+1

निफ्टी? कार्यान्वयन-विशिष्ट, धारणा बनाने और बाध्य करने के लिए परेशानी-जैसे-परेशानी की तरह ... ओह रुको, यह पहले से ही हुआ है। :) – bzlm

+0

वेब एप्लिकेशन विशाल है - बिन निर्देशिका में 100 से अधिक डीएलएस के साथ। कई डीएल हमारे ऐप के लिए प्लगइन्स नहीं हैं और कई क्लियर डीएलएस नहीं हैं, इसलिए असेंबली का उपयोग करना। लोड एक अच्छा विकल्प नहीं है। – Vaevictus

उत्तर

7

कारण अपने कोड 64-बिट DLLs के लिए काम नहीं कर रहा है, क्योंकि एक 64-बिट DLL और की छवि वैकल्पिक हैडर आकार एक 86-बिट DLL अलग है। आपको निर्धारित करने के लिए अलग-अलग छवि वैकल्पिक शीर्षलेख आकारों को ध्यान में रखना होगा चाहे दिया गया डीएलएल एक .NET DLL है या नहीं।

PE file format specification describes खंड में 3.4 (वैकल्पिक हैडर) अलग ऑफसेट डेटा निर्देशिका के लिए कूद करने के लिए:

  1. PE32 (x86) छवियों ऑफसेट लिए 0x60 है (क्योंकि यह अपने कोड में है) और
  2. पीई 32 + (x64) छवियों के लिए
  3. ऑफ़सेट 0x70 है।

आदेश में निर्धारित करने के लिए किया जाए या नहीं एक दिया DLL एक 64 बिट DLL आप वैकल्पिक हैडर का जादू बाइट्स पढ़ने के लिए है:

  1. 0x20b का मान का मतलब है PE32 +,
  2. 0x10b पीई 32 का मूल्य।

मैं अपने उदाहरण का विस्तार किया है:

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(); 
} 

विंडोज एसडीके में वहाँ भी कर रहे हैं PE32/PE32 + वैकल्पिक हेडर के लिए परिभाषित संरचनाओं। उन संरचनाओं का विवरण यहां MSDN पाया जा सकता है।

आशा है, इससे मदद मिलती है।

+0

+1। –

+0

ऐसा लगता है कि यह पूरी तरह से काम कर रहा है, बहुत बहुत धन्यवाद। – Vaevictus

2

क्या कोई कारण है कि आप ढांचे में विधियों का उपयोग नहीं कर सकते हैं? नीचे नमूना कोड:

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

GetPEKind method on MSDN और PortableExecutableKinds मिलना चाहिए आप शुरू कर दिया। बाद मूल रूप से है corflags

+4

कोई समाधान नहीं है, लोड() विधि बम होगा यदि यह .NET असेंबली नहीं है या यदि यह गलत .NET संस्करण या Bitness को लक्षित करता है। पैर-काम करने के लिए –

3

एक विकल्प के लिए जो प्रतिबिंब का उपयोग नहीं करता है और सीधे असेंबली लोड नहीं करता है, Common Compiler Infrastructure Metadata API आज़माएं। ऐसा लगता है कि आप काफी आसानी से load a PE assembly कर सकते हैं और यह निर्धारित कर सकते हैं कि उसके पास सीएलआर मॉड्यूल है या नहीं।

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; 
} 
संबंधित मुद्दे