简体   繁体   English

GAC中的DLL识别

[英]DLL identification in the GAC

I'm trying to understand DLL identification in the GAC by parsing the top-voted answer in this StackOverflow question: What is the GAC in .NET? 我试图通过解析此StackOverflow问题中投票最多的答案来理解GAC中的DLL标识: .NET中的GAC是什么?

The writer walks us through the tree structure for C:\\Windows\\assembly\\GAC_64\\System.Data and concludes with . 作者向我们介绍了C:\\ Windows \\ assembly \\ GAC_64 \\ System.Data的树结构,并以结尾。 . .

Here you can see version 2.0.0.0__b77a5c561934e089 of System.Data. 在这里您可以看到System.Data的版本2.0.0.0__b77a5c561934e089。

A DLL is identified by 5 parts: DLL由5个部分标识:

 Name Version Architecture Culture Public Key 

... and that's the part I'm unclear on. ...这就是我不清楚的部分。 Once I've gotten to the leaves of the tree how do I extract those 5 parts of the DLL's identification, and is there any relation to the name of the assembly? 到达树上的叶子后,如何提取DLL标识的那5个部分,并且与程序集名称有任何关系?

In the example I'm working with the assemblies are directories with names like: 在该示例中,我正在使用程序集的是具有以下名称的目录:

v4.0_2.0.6178.1045__d45c8e156fba2841 v4.0_2.0.6178.1045__d45c8e156fba2841

... and inside that directory there's a DLL with a name like ...在该目录中有一个DLL,其名称类似于

Ab3d.DXEngine.dll Ab3d.DXEngine.dll

... so how do I extract the five parts of its identification? ...那么我该如何提取其识别的五个部分?

EDIT: 编辑:

Lifu Huang, below suggested that there was a way to access ILDASM from visual studio. 下面的Lifu Huang建议,有一种方法可以从Visual Studio中访问ILDASM。 There wasn't a built-in way from mine (VS 2013) but there was a way to ADD it, described here: http://dailydotnettips.com/2016/01/05/did-you-know-you-can-launch-ildasm-tool-from-inside-visual-studio-itself-how/ ...so I did that and when I tried to run ILDASM on a DLL in the GAC I got an error from ILDASM saying " Protected module - cannot disassemble " 我没有内置的方法(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收到一条错误消息,说“ 受保护的模块-不能拆卸

how do I extract the five parts of its identification? 如何提取其标识的五个部分?

You can find them in the CLR header and the metadata of an assembly. 您可以在CLR标头和程序集的元数据中找到它们。

Actually every managed module (dll or exe) consists of four parts: 实际上,每个托管模块(dll或exe)都包含四个部分:

  • PE32 or PE32+ header (Information used by Windows) PE32或PE32 +标头 (Windows使用的信息)
  • CLR header (Information used by CLR) CLR标头 (CLR使用的信息)
  • Metadata (Here is a blog post introducing this topic). 元数据 (此处是介绍该主题的博客文章 )。 There are mainly three types of metadata tables: 元数据表主要有三种类型:

    • Assembly Manifest (global information about the assembly) 装配清单 (有关装配的全局信息)
    • Definition Tables (information about things defined in this module, eg ModuleDef, TypeDef, MethodDef, PropertyDef) 定义表 (有关此模块中定义的内容的信息,例如ModuleDef,TypeDef,MethodDef,PropertyDef)
    • Reference Tables (information about thing referred by this module, eg AssemblyRef, ModuleRef, TypeRef, MemberRef) 参考表 (有关此模块引用的内容的信息,例如AssemblyRef,ModuleRef,TypeRef,MemberRef)
  • IL Code (IL code generated from the source code) IL代码 (从源代码生成的IL代码)

You can read the metadata programmatically if you know the format. 如果知道格式,则可以通过编程方式读取元数据。 Here is some code that does it. 这是一些执行此操作的代码。 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);
    }

Much of the information you need is readily available from System.Reflection AssemblyName object. 您需要的许多信息都可以从System.Reflection AssemblyName对象中轻松获得。

This code will get the strong name, processor architecture, version, and public key token for System.Web.dll : 该代码将获得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())));

Output: 输出:

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

If you don't want to write a program just for this, you could also use a PowerShell script to do the same thing: 如果您不想为此编写程序,则还可以使用PowerShell脚本执行相同的操作:

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

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

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