简体   繁体   中英

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?

The writer walks us through the tree structure for C:\\Windows\\assembly\\GAC_64\\System.Data and concludes with . . .

Here you can see version 2.0.0.0__b77a5c561934e089 of System.Data.

A DLL is identified by 5 parts:

 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?

In the example I'm working with the assemblies are directories with names like:

v4.0_2.0.6178.1045__d45c8e156fba2841

... and inside that directory there's a DLL with a name like

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. 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 "

how do I extract the five parts of its identification?

You can find them in the CLR header and the metadata of an assembly.

Actually every managed module (dll or exe) consists of four parts:

  • PE32 or PE32+ header (Information used by Windows)
  • CLR header (Information used by 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)
    • Reference Tables (information about thing referred by this module, eg AssemblyRef, ModuleRef, TypeRef, MemberRef)
  • IL Code (IL code generated from the source code)

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.

This code will get the strong name, processor architecture, version, and public key token for 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:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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