繁体   English   中英

GAC中的DLL识别

[英]DLL identification in the GAC

我试图通过解析此StackOverflow问题中投票最多的答案来理解GAC中的DLL标识: .NET中的GAC是什么?

作者向我们介绍了C:\\ Windows \\ assembly \\ GAC_64 \\ System.Data的树结构,并以结尾。

在这里您可以看到System.Data的版本2.0.0.0__b77a5c561934e089。

DLL由5个部分标识:

 Name Version Architecture Culture Public Key 

...这就是我不清楚的部分。 到达树上的叶子后,如何提取DLL标识的那5个部分,并且与程序集名称有任何关系?

在该示例中,我正在使用程序集的是具有以下名称的目录:

v4.0_2.0.6178.1045__d45c8e156fba2841

...在该目录中有一个DLL,其名称类似于

Ab3d.DXEngine.dll

...那么我该如何提取其识别的五个部分?

编辑:

下面的Lifu Huang建议,有一种方法可以从Visual Studio中访问ILDASM。 我没有内置的方法(VS 2013),但是有一种方法可以添加它,如下所述: http : //dailydotnettips.com/2016/01/05/did-you-know-you-can -launch-ildasm-tool-from-inside-visual-studio-itself-how // ...所以我这样做了,当我尝试在GAC中的DLL上运行ILDASM时,我从ILDASM收到一条错误消息,说“ 受保护的模块-不能拆卸

如何提取其标识的五个部分?

您可以在CLR标头和程序集的元数据中找到它们。

实际上,每个托管模块(dll或exe)都包含四个部分:

  • PE32或PE32 +标头 (Windows使用的信息)
  • CLR标头 (CLR使用的信息)
  • 元数据 (此处是介绍该主题的博客文章 )。 元数据表主要有三种类型:

    • 装配清单 (有关装配的全局信息)
    • 定义表 (有关此模块中定义的内容的信息,例如ModuleDef,TypeDef,MethodDef,PropertyDef)
    • 参考表 (有关此模块引用的内容的信息,例如AssemblyRef,ModuleRef,TypeRef,MemberRef)
  • IL代码 (从源代码生成的IL代码)

如果知道格式,则可以通过编程方式读取元数据。 这是一些执行此操作的代码。 链接

    public static CorFlagsReader ReadAssemblyMetadata(Stream stream)
    {
        if (stream == null)
        {
            throw new ArgumentNullException("stream");
        }

        long length = stream.Length;
        if (length < 0x40)
            return null;

        BinaryReader reader = new BinaryReader(stream);

        // Read the pointer to the PE header.
        stream.Position = 0x3c;
        uint peHeaderPtr = reader.ReadUInt32();
        if (peHeaderPtr == 0)
            peHeaderPtr = 0x80;

        // Ensure there is at least enough room for the following structures:
        //     24 byte PE Signature & Header
        //     28 byte Standard Fields         (24 bytes for PE32+)
        //     68 byte NT Fields               (88 bytes for PE32+)
        // >= 128 byte Data Dictionary Table
        if (peHeaderPtr > length - 256)
            return null;

        // Check the PE signature.  Should equal 'PE\0\0'.
        stream.Position = peHeaderPtr;
        uint peSignature = reader.ReadUInt32();
        if (peSignature != 0x00004550)
            return null;

        // Read PE header fields.
        ushort machine = reader.ReadUInt16();
        ushort numberOfSections = reader.ReadUInt16();
        uint timeStamp = reader.ReadUInt32();
        uint symbolTablePtr = reader.ReadUInt32();
        uint numberOfSymbols = reader.ReadUInt32();
        ushort optionalHeaderSize = reader.ReadUInt16();
        ushort characteristics = reader.ReadUInt16();

        // Read PE magic number from Standard Fields to determine format.
        PEFormat peFormat = (PEFormat)reader.ReadUInt16();
        if (peFormat != PEFormat.PE32 && peFormat != PEFormat.PE32Plus)
            return null;

        // Read the 15th Data Dictionary RVA field which contains the CLI header RVA.
        // When this is non-zero then the file contains CLI data otherwise not.
        stream.Position = peHeaderPtr + (peFormat == PEFormat.PE32 ? 232 : 248);
        uint cliHeaderRva = reader.ReadUInt32();
        if (cliHeaderRva == 0)
            return new CorFlagsReader(0,0,0, peFormat);

        // Read section headers.  Each one is 40 bytes.
        //    8 byte Name
        //    4 byte Virtual Size
        //    4 byte Virtual Address
        //    4 byte Data Size
        //    4 byte Data Pointer
        //  ... total of 40 bytes
        uint sectionTablePtr = peHeaderPtr + 24 + optionalHeaderSize;
        Section[] sections = new Section[numberOfSections];
        for (int i = 0; i < numberOfSections; i++)
        {
            stream.Position = sectionTablePtr + i * 40 + 8;

            Section section = new Section();
            section.VirtualSize = reader.ReadUInt32();
            section.VirtualAddress = reader.ReadUInt32();
            reader.ReadUInt32();
            section.Pointer = reader.ReadUInt32();

            sections[i] = section;
        }

        // Read parts of the CLI header.
        uint cliHeaderPtr = ResolveRva(sections, cliHeaderRva);
        if (cliHeaderPtr == 0)
            return null;

        stream.Position = cliHeaderPtr + 4;
        ushort majorRuntimeVersion = reader.ReadUInt16();
        ushort minorRuntimeVersion = reader.ReadUInt16();
        uint metadataRva = reader.ReadUInt32();
        uint metadataSize = reader.ReadUInt32();
        CorFlags corflags = (CorFlags)reader.ReadUInt32();

        // Done.
        return new CorFlagsReader(majorRuntimeVersion, minorRuntimeVersion, corflags, peFormat);
    }

您需要的许多信息都可以从System.Reflection AssemblyName对象中轻松获得。

该代码将获得System.Web.dll的强名,处理器体系结构,版本和公共密钥令牌:

var n = System.Reflection.AssemblyName.GetAssemblyName(@"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.web.dll");
Console.WriteLine(String.Format("{0} {1} {2} {3}", n.Name, n.Version, n.ProcessorArchitecture, BitConverter.ToString(n.GetPublicKeyToken())));

输出:

System.Web 4.0.0.0 Amd64 B0-3F-5F-7F-11-D5-0A-3A

如果您不想为此编写程序,则还可以使用PowerShell脚本执行相同的操作:

[reflection.assemblyname]::GetAssemblyName("${pwd}\System.Web.dll") | fl

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM