我正在努力将32位Web应用程序迁移到64位,并且我的插件加载器代码存在一些问题.
在32位版本中,我们扫描所有.net dll的webapps bin目录,然后使用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位或平台独立的dll,并且偏移量似乎已经改变,并且此代码失败.有没有人知道对上述代码的正确修改,对于有效的64位唯一OR平台无关的dll返回true?
解决方法
您的代码不适用于x64-Bit DLL的原因是
因为图像可选的头部大小为x64-Bit DLL和
x86-Bit DLL是不同的.你必须采取不同的方式
图像可选的标题大小考虑在内以便确定
是否给定的DLL是.Net DLL.
因为图像可选的头部大小为x64-Bit DLL和
x86-Bit DLL是不同的.你必须采取不同的方式
图像可选的标题大小考虑在内以便确定
是否给定的DLL是.Net DLL.
3.4节(可选标题)中的PE file format specification describes
跳转到数据目录的不同偏移量:
>对于PE32(x86)图像,偏移量为0x60(就像在代码中一样)和
>对于PE32(x64)图像,偏移量为0x70.
为了确定给定的DLL是否是x64位DLL
你必须阅读可选标题的魔术字节:
>值0x20b表示PE32,
>值为0x10b PE32.
我扩展了你的例子:
Stream fs = new FileStream(@file,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(); }
在Windows SDK中,还为PE32 / PE32可选标头定义了结构.
这些结构的描述可以在这里找到MSDN.
希望这可以帮助.