GAC中的DLL识别

时间:2017-01-13 17:22:50

标签: .net dll clr gac

我试图通过解析StackOverflow问题中的最高投票答案来理解GAC中的DLL识别:What is the GAC in .NET?

作者带我们浏览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收到错误“受保护的模块 - 无法反汇编

3 个答案:

答案 0 :(得分:0)

  

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

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

实际上每个托管模块(dll或exe)都由四部分组成:

  • PE32或PE32 +标头(Windows使用的信息)
  • CLR标题(CLR使用的信息)
  • 元数据(这是介绍此主题的blog post)。主要有三种类型的元数据表:

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

答案 1 :(得分:0)

如果您知道格式,则可以通过编程方式阅读元数据。这是一些代码。 Link

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

答案 2 :(得分:0)

您需要的大部分信息都可以从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

如果你不想为此编写程序,你也可以使用a PowerShell script做同样的事情:

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