github.com/saferwall/pe@v1.5.2/dotnet.go (about)

     1  // Copyright 2018 Saferwall. All rights reserved.
     2  // Use of this source code is governed by Apache v2 license
     3  // license that can be found in the LICENSE file.
     4  
     5  package pe
     6  
     7  import (
     8  	"encoding/binary"
     9  )
    10  
    11  // References
    12  // https://www.ntcore.com/files/dotnetformat.htm
    13  
    14  // COMImageFlagsType represents a COM+ header entry point flag type.
    15  type COMImageFlagsType uint32
    16  
    17  // COM+ Header entry point flags.
    18  const (
    19  	// The image file contains IL code only, with no embedded native unmanaged
    20  	// code except the start-up stub (which simply executes an indirect jump to
    21  	// the CLR entry point).
    22  	COMImageFlagsILOnly = 0x00000001
    23  
    24  	// The image file can be loaded only into a 32-bit process.
    25  	COMImageFlags32BitRequired = 0x00000002
    26  
    27  	// This flag is obsolete and should not be set. Setting it—as the IL
    28  	// assembler allows, using the .corflags directive—will render your module
    29  	// un-loadable.
    30  	COMImageFlagILLibrary = 0x00000004
    31  
    32  	// The image file is protected with a strong name signature.
    33  	COMImageFlagsStrongNameSigned = 0x00000008
    34  
    35  	// The executable’s entry point is an unmanaged method. The EntryPointToken/
    36  	// EntryPointRVA field of the CLR header contains the RVA of this native
    37  	// method. This flag was introduced in version 2.0 of the CLR.
    38  	COMImageFlagsNativeEntrypoint = 0x00000010
    39  
    40  	// The CLR loader and the JIT compiler are required to track debug
    41  	// information about the methods. This flag is not used.
    42  	COMImageFlagsTrackDebugData = 0x00010000
    43  
    44  	// The image file can be loaded into any process, but preferably into a
    45  	// 32-bit process. This flag can be only set together with flag
    46  	// COMIMAGE_FLAGS_32BITREQUIRED. When set, these two flags mean the image
    47  	// is platformneutral, but prefers to be loaded as 32-bit when possible.
    48  	// This flag was introduced in CLR v4.0
    49  	COMImageFlags32BitPreferred = 0x00020000
    50  )
    51  
    52  // V-table constants.
    53  const (
    54  	// V-table slots are 32-bits in size.
    55  	CORVTable32Bit = 0x01
    56  
    57  	// V-table slots are 64-bits in size.
    58  	CORVTable64Bit = 0x02
    59  
    60  	//  The thunk created by the common language runtime must provide data
    61  	// marshaling between managed and unmanaged code.
    62  	CORVTableFromUnmanaged = 0x04
    63  
    64  	// The thunk created by the common language runtime must provide data
    65  	// marshaling between managed and unmanaged code. Current appdomain should
    66  	// be selected to dispatch the call.
    67  	CORVTableFromUnmanagedRetainAppDomain = 0x08
    68  
    69  	// Call most derived method described by
    70  	CORVTableCallMostDerived = 0x10
    71  )
    72  
    73  // Metadata Tables constants.
    74  const (
    75  	// The current module descriptor.
    76  	Module = 0
    77  	// Class reference descriptors.
    78  	TypeRef = 1
    79  	// Class or interface definition descriptors.
    80  	TypeDef = 2
    81  	// A class-to-fields lookup table, which does not exist in optimized
    82  	// metadata (#~ stream).
    83  	FieldPtr = 3
    84  	// Field definition descriptors.
    85  	Field = 4
    86  	// A class-to-methods lookup table, which does not exist in
    87  	// optimized metadata (#~ stream).
    88  	MethodPtr = 5
    89  	// Method definition descriptors.
    90  	MethodDef = 6
    91  	// A method-to-parameters lookup table, which does not exist in optimized
    92  	// metadata (#~ stream).
    93  	ParamPtr = 7
    94  	// Parameter definition descriptors.
    95  	Param = 8
    96  	// Interface implementation descriptors.
    97  	InterfaceImpl = 9
    98  	// Member (field or method) reference descriptors.
    99  	MemberRef = 10
   100  	// Constant value descriptors that map the default values stored in the
   101  	// #Blob stream to respective fields, parameters, and properties.
   102  	Constant = 11
   103  	// Custom attribute descriptors.
   104  	CustomAttribute = 12
   105  	// Field or parameter marshaling descriptors for managed/unmanaged
   106  	// inter-operations.
   107  	FieldMarshal = 13
   108  	// Security descriptors.
   109  	DeclSecurity = 14
   110  	// Class layout descriptors that hold information about how the loader
   111  	// should lay out respective classes.
   112  	ClassLayout = 15
   113  	// Field layout descriptors that specify the offset or ordinal of
   114  	// individual fields.
   115  	FieldLayout = 16
   116  	// Stand-alone signature descriptors. Signatures per se are used in two
   117  	// capacities: as composite signatures of local variables of methods and as
   118  	// parameters of the call indirect (calli) IL instruction.
   119  	StandAloneSig = 17
   120  	// A class-to-events mapping table. This is not an intermediate lookup
   121  	// table, and it does exist in optimized metadata.
   122  	EventMap = 18
   123  	// An event map–to–events lookup table, which does not exist in optimized
   124  	// metadata (#~ stream).
   125  	EventPtr = 19
   126  	// Event descriptors.
   127  	Event = 20
   128  	// A class-to-properties mapping table. This is not an intermediate lookup
   129  	// table, and it does exist in optimized metadata.
   130  	PropertyMap = 21
   131  	// A property map–to–properties lookup table, which does not exist in
   132  	// optimized metadata (#~ stream).
   133  	PropertyPtr = 22
   134  	// Property descriptors.
   135  	Property = 23
   136  	// Method semantics descriptors that hold information about which method is
   137  	// associated with a specific property or event and in what capacity.
   138  	MethodSemantics = 24
   139  	// Method implementation descriptors.
   140  	MethodImpl = 25
   141  	// Module reference descriptors.
   142  	ModuleRef = 26
   143  	// Type specification descriptors.
   144  	TypeSpec = 27
   145  	// Implementation map descriptors used for the platform invocation
   146  	// (P/Invoke) type of managed/unmanaged code inter-operation.
   147  	ImplMap = 28
   148  	// Field-to-data mapping descriptors.
   149  	FieldRVA = 29
   150  	// Edit-and-continue log descriptors that hold information about what
   151  	// changes have been made to specific metadata items during in-memory
   152  	// editing. This table does not exist in optimized metadata (#~ stream)
   153  	ENCLog = 30
   154  	// Edit-and-continue mapping descriptors. This table does not exist in
   155  	// optimized metadata (#~ stream).
   156  	ENCMap = 31
   157  	// The current assembly descriptor, which should appear only in the prime
   158  	// module metadata.
   159  	Assembly = 32
   160  	// This table is unused.
   161  	AssemblyProcessor = 33
   162  	// This table is unused.
   163  	AssemblyOS = 34
   164  	// Assembly reference descriptors.
   165  	AssemblyRef = 35
   166  	// This table is unused.
   167  	AssemblyRefProcessor = 36
   168  	// This table is unused.
   169  	AssemblyRefOS = 37
   170  	// File descriptors that contain information about other files in the
   171  	// current assembly.
   172  	FileMD = 38
   173  	// Exported type descriptors that contain information about public classes
   174  	// exported by the current assembly, which are declared in other modules of
   175  	// the assembly. Only the prime module of the assembly should carry this
   176  	// table.
   177  	ExportedType = 39
   178  	// Managed resource descriptors.
   179  	ManifestResource = 40
   180  	// Nested class descriptors that provide mapping of nested classes to their
   181  	// respective enclosing classes.
   182  	NestedClass = 41
   183  	//  Type parameter descriptors for generic (parameterized) classes and
   184  	// methods.
   185  	GenericParam = 42
   186  	// Generic method instantiation descriptors.
   187  	MethodSpec = 43
   188  	// Descriptors of constraints specified for type parameters of generic
   189  	// classes and methods
   190  	GenericParamConstraint = 44
   191  )
   192  
   193  // Heaps Streams Bit Positions.
   194  const (
   195  	StringStream = 0
   196  	GUIDStream   = 1
   197  	BlobStream   = 2
   198  )
   199  
   200  // MetadataTableIndexToString returns the string representation of the metadata
   201  // table index.
   202  func MetadataTableIndexToString(k int) string {
   203  	metadataTablesMap := map[int]string{
   204  		Module:                 "Module",
   205  		TypeRef:                "TypeRef",
   206  		TypeDef:                "TypeDef",
   207  		FieldPtr:               "FieldPtr",
   208  		Field:                  "Field",
   209  		MethodPtr:              "MethodPtr",
   210  		MethodDef:              "MethodDef",
   211  		ParamPtr:               "ParamPtr",
   212  		Param:                  "Param",
   213  		InterfaceImpl:          "InterfaceImpl",
   214  		MemberRef:              "MemberRef",
   215  		Constant:               "Constant",
   216  		CustomAttribute:        "CustomAttribute",
   217  		FieldMarshal:           "FieldMarshal",
   218  		DeclSecurity:           "DeclSecurity",
   219  		ClassLayout:            "ClassLayout",
   220  		FieldLayout:            "FieldLayout",
   221  		StandAloneSig:          "StandAloneSig",
   222  		EventMap:               "EventMap",
   223  		EventPtr:               "EventPtr",
   224  		Event:                  "Event",
   225  		PropertyMap:            "PropertyMap",
   226  		PropertyPtr:            "PropertyPtr",
   227  		Property:               "Property",
   228  		MethodSemantics:        "MethodSemantics",
   229  		MethodImpl:             "MethodImpl",
   230  		ModuleRef:              "ModuleRef",
   231  		TypeSpec:               "TypeSpec",
   232  		ImplMap:                "ImplMap",
   233  		FieldRVA:               "FieldRVA",
   234  		ENCLog:                 "ENCLog",
   235  		ENCMap:                 "ENCMap",
   236  		Assembly:               "Assembly",
   237  		AssemblyProcessor:      "AssemblyProcessor",
   238  		AssemblyOS:             "AssemblyOS",
   239  		AssemblyRef:            "AssemblyRef",
   240  		AssemblyRefProcessor:   "AssemblyRefProcessor",
   241  		AssemblyRefOS:          "AssemblyRefOS",
   242  		FileMD:                 "File",
   243  		ExportedType:           "ExportedType",
   244  		ManifestResource:       "ManifestResource",
   245  		NestedClass:            "NestedClass",
   246  		GenericParam:           "GenericParam",
   247  		MethodSpec:             "MethodSpec",
   248  		GenericParamConstraint: "GenericParamConstraint",
   249  	}
   250  
   251  	if value, ok := metadataTablesMap[k]; ok {
   252  		return value
   253  	}
   254  	return ""
   255  }
   256  
   257  // GetMetadataStreamIndexSize returns the size of indexes to read into a
   258  // particular heap.
   259  func (pe *File) GetMetadataStreamIndexSize(BitPosition int) int {
   260  	// The `Heaps` field is a bit vector that encodes how wide indexes into the
   261  	// various heaps are:
   262  	// - If bit 0 is set, indexes into the "#String" heap are 4 bytes wide;
   263  	// - if bit 1 is set, indexes into the "#GUID" heap are 4 bytes wide;
   264  	// - if bit 2 is set, indexes into the "#Blob" heap are 4 bytes wide.
   265  	heaps := pe.CLR.MetadataTablesStreamHeader.Heaps
   266  	if IsBitSet(uint64(heaps), BitPosition) {
   267  		return 4
   268  	}
   269  	// Conversely, if the HeapSizes bit for a particular heap is not set,
   270  	// indexes into that heap are 2 bytes wide.
   271  	return 2
   272  }
   273  
   274  // ImageDataDirectory represents the  directory format.
   275  type ImageDataDirectory struct {
   276  
   277  	// The relative virtual address of the table.
   278  	VirtualAddress uint32 `json:"virtual_address"`
   279  
   280  	// The size of the table, in bytes.
   281  	Size uint32 `json:"size"`
   282  }
   283  
   284  // ImageCOR20Header represents the CLR 2.0 header structure.
   285  type ImageCOR20Header struct {
   286  
   287  	// Size of the header in bytes.
   288  	Cb uint32 `json:"cb"`
   289  
   290  	// Major number of the minimum version of the runtime required to run the
   291  	// program.
   292  	MajorRuntimeVersion uint16 `json:"major_runtime_version"`
   293  
   294  	// Minor number of the version of the runtime required to run the program.
   295  	MinorRuntimeVersion uint16 `json:"minor_runtime_version"`
   296  
   297  	// RVA and size of the metadata.
   298  	MetaData ImageDataDirectory `json:"meta_data"`
   299  
   300  	// Bitwise flags indicating attributes of this executable.
   301  	Flags COMImageFlagsType `json:"flags"`
   302  
   303  	// Metadata identifier (token) of the entry point for the image file; can
   304  	// be 0 for DLL images. This field identifies a method belonging to this
   305  	// module or a module containing the entry point method.
   306  	// In images of version 2.0 and newer, this field may contain RVA of the
   307  	// embedded native entry point method.
   308  	// union {
   309  	//
   310  	// If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is not set,
   311  	// EntryPointToken represents a managed entrypoint.
   312  	//	DWORD               EntryPointToken;
   313  	//
   314  	// If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is set,
   315  	// EntryPointRVA represents an RVA to a native entrypoint
   316  	//	DWORD               EntryPointRVA;
   317  	//};
   318  	EntryPointRVAorToken uint32 `json:"entry_point_rva_or_token"`
   319  
   320  	// This is the blob of managed resources. Fetched using
   321  	// code:AssemblyNative.GetResource and code:PEFile.GetResource and accessible
   322  	// from managed code from System.Assembly.GetManifestResourceStream. The
   323  	// metadata has a table that maps names to offsets into this blob, so
   324  	// logically the blob is a set of resources.
   325  	Resources ImageDataDirectory `json:"resources"`
   326  
   327  	// RVA and size of the hash data for this PE file, used by the loader for
   328  	// binding and versioning. IL assemblies can be signed with a public-private
   329  	// key to validate who created it. The signature goes here if this feature
   330  	// is used.
   331  	StrongNameSignature ImageDataDirectory `json:"strong_name_signature"`
   332  
   333  	// RVA and size of the Code Manager table. In the existing releases of the
   334  	// runtime, this field is reserved and must be set to 0.
   335  	CodeManagerTable ImageDataDirectory `json:"code_manager_table"`
   336  
   337  	// RVA and size in bytes of an array of virtual table (v-table) fixups.
   338  	// Among current managed compilers, only the VC++ linker and the IL
   339  	// assembler can produce this array.
   340  	VTableFixups ImageDataDirectory `json:"vtable_fixups"`
   341  
   342  	// RVA and size of an array of addresses of jump thunks. Among managed
   343  	// compilers, only the VC++ of versions pre-8.0 could produce this table,
   344  	// which allows the export of unmanaged native methods embedded in the
   345  	// managed PE file. In v2.0+ of CLR this entry is obsolete and must be set
   346  	// to 0.
   347  	ExportAddressTableJumps ImageDataDirectory `json:"export_address_table_jumps"`
   348  
   349  	// Reserved for precompiled images; set to 0
   350  	// NGEN images it points at a code:CORCOMPILE_HEADER structure
   351  	ManagedNativeHeader ImageDataDirectory `json:"managed_native_header"`
   352  }
   353  
   354  // ImageCORVTableFixup defines the v-table fixups that contains the
   355  // initializing information necessary for the runtime to create the thunks.
   356  // Non VOS v-table entries.  Define an array of these pointed to by
   357  // IMAGE_COR20_HEADER.VTableFixups.  Each entry describes a contiguous array of
   358  // v-table slots.  The slots start out initialized to the meta data token value
   359  // for the method they need to call.  At image load time, the CLR Loader will
   360  // turn each entry into a pointer to machine code for the CPU and can be
   361  // called directly.
   362  type ImageCORVTableFixup struct {
   363  	RVA   uint32 `json:"rva"`   // Offset of v-table array in image.
   364  	Count uint16 `json:"count"` // How many entries at location.
   365  	Type  uint16 `json:"type"`  // COR_VTABLE_xxx type of entries.
   366  }
   367  
   368  // MetadataHeader consists of a storage signature and a storage header.
   369  type MetadataHeader struct {
   370  
   371  	// The storage signature, which must be 4-byte aligned:
   372  	// ”Magic” signature for physical metadata, currently 0x424A5342, or, read
   373  	// as characters, BSJB—the initials of four “founding fathers” Brian Harry,
   374  	// Susa Radke-Sproull, Jason Zander, and Bill Evans, who started the
   375  	// runtime development in 1998.
   376  	Signature uint32 `json:"signature"`
   377  
   378  	// Major version.
   379  	MajorVersion uint16 `json:"major_version"`
   380  
   381  	// Minor version.
   382  	MinorVersion uint16 `json:"minor_version"`
   383  
   384  	// Reserved; set to 0.
   385  	ExtraData uint32 `json:"extra_data"`
   386  
   387  	// Length of the version string.
   388  	VersionString uint32 `json:"version_string"`
   389  
   390  	// Version string.
   391  	Version string `json:"version"`
   392  
   393  	// The storage header follows the storage signature, aligned on a 4-byte
   394  	// boundary.
   395  	//
   396  
   397  	// Reserved; set to 0.
   398  	Flags uint8 `json:"flags"`
   399  
   400  	// Another byte used for [padding]
   401  
   402  	// Number of streams.
   403  	Streams uint16 `json:"streams"`
   404  }
   405  
   406  // MetadataStreamHeader represents a Metadata Stream Header Structure.
   407  type MetadataStreamHeader struct {
   408  	// Offset in the file for this stream.
   409  	Offset uint32 `json:"offset"`
   410  
   411  	// Size of the stream in bytes.
   412  	Size uint32 `json:"size"`
   413  
   414  	// Name of the stream; a zero-terminated ASCII string no longer than 31
   415  	// characters (plus zero terminator). The name might be shorter, in which
   416  	// case the size of the stream header is correspondingly reduced, padded to
   417  	// the 4-byte boundary.
   418  	Name string `json:"name"`
   419  }
   420  
   421  // MetadataTableStreamHeader represents the Metadata Table Stream Header Structure.
   422  type MetadataTableStreamHeader struct {
   423  	// Reserved; set to 0.
   424  	Reserved uint32 `json:"reserved"`
   425  
   426  	// Major version of the table schema (1 for v1.0 and v1.1; 2 for v2.0 or later).
   427  	MajorVersion uint8 `json:"major_version"`
   428  
   429  	// Minor version of the table schema (0 for all versions).
   430  	MinorVersion uint8 `json:"minor_version"`
   431  
   432  	// Binary flags indicate the offset sizes to be used within the heaps.
   433  	// 4-byte unsigned integer offset is indicated by:
   434  	// - 0x01 for a string heap, 0x02 for a GUID heap, and 0x04 for a blob heap.
   435  	// If a flag is not set, the respective heap offset is a 2-byte unsigned integer.
   436  	// A #- stream can also have special flags set:
   437  	// - flag 0x20, indicating that the stream contains only changes made
   438  	// during an edit-and-continue session, and;
   439  	// - flag 0x80, indicating that the  metadata might contain items marked as
   440  	// deleted.
   441  	Heaps uint8 `json:"heaps"`
   442  
   443  	// Bit width of the maximal record index to all tables of the metadata;
   444  	// calculated at run time (during the metadata stream initialization).
   445  	RID uint8 `json:"rid"`
   446  
   447  	// Bit vector of present tables, each bit representing one table (1 if
   448  	// present).
   449  	MaskValid uint64 `json:"mask_valid"`
   450  
   451  	// Bit vector of sorted tables, each bit representing a respective table (1
   452  	// if sorted)
   453  	Sorted uint64 `json:"sorted"`
   454  }
   455  
   456  // MetadataTable represents the content of a particular table in the metadata.
   457  // The metadata schema defines 45 tables.
   458  type MetadataTable struct {
   459  	// The name of the table.
   460  	Name string `json:"name"`
   461  
   462  	// Number of columns in the table.
   463  	CountCols uint32 `json:"count_cols"`
   464  
   465  	// Every table has a different layout, defined in the ECMA-335 spec.
   466  	// Content abstract the type each table is pointing to.
   467  	Content interface{} `json:"content"`
   468  }
   469  
   470  // CLRData embeds the Common Language Runtime Header structure as well as the
   471  // Metadata header structure.
   472  type CLRData struct {
   473  	CLRHeader                  ImageCOR20Header          `json:"clr_header"`
   474  	MetadataHeader             MetadataHeader            `json:"metadata_header"`
   475  	MetadataStreamHeaders      []MetadataStreamHeader    `json:"metadata_stream_headers"`
   476  	MetadataStreams            map[string][]byte         `json:"-"`
   477  	MetadataTablesStreamHeader MetadataTableStreamHeader `json:"metadata_tables_stream_header"`
   478  	MetadataTables             map[int]*MetadataTable    `json:"metadata_tables"`
   479  	StringStreamIndexSize      int                       `json:"-"`
   480  	GUIDStreamIndexSize        int                       `json:"-"`
   481  	BlobStreamIndexSize        int                       `json:"-"`
   482  }
   483  
   484  func (pe *File) parseMetadataStream(off, size uint32) (MetadataTableStreamHeader, error) {
   485  
   486  	mdTableStreamHdr := MetadataTableStreamHeader{}
   487  	if size == 0 {
   488  		return mdTableStreamHdr, nil
   489  	}
   490  
   491  	mdTableStreamHdrSize := uint32(binary.Size(mdTableStreamHdr))
   492  	err := pe.structUnpack(&mdTableStreamHdr, off, mdTableStreamHdrSize)
   493  	if err != nil {
   494  		return mdTableStreamHdr, err
   495  	}
   496  
   497  	return mdTableStreamHdr, nil
   498  }
   499  
   500  func (pe *File) parseMetadataHeader(offset, size uint32) (MetadataHeader, error) {
   501  	var err error
   502  	mh := MetadataHeader{}
   503  
   504  	if mh.Signature, err = pe.ReadUint32(offset); err != nil {
   505  		return mh, err
   506  	}
   507  	if mh.MajorVersion, err = pe.ReadUint16(offset + 4); err != nil {
   508  		return mh, err
   509  	}
   510  	if mh.MinorVersion, err = pe.ReadUint16(offset + 6); err != nil {
   511  		return mh, err
   512  	}
   513  	if mh.ExtraData, err = pe.ReadUint32(offset + 8); err != nil {
   514  		return mh, err
   515  	}
   516  	if mh.VersionString, err = pe.ReadUint32(offset + 12); err != nil {
   517  		return mh, err
   518  	}
   519  	mh.Version, err = pe.getStringAtOffset(offset+16, mh.VersionString)
   520  	if err != nil {
   521  		return mh, err
   522  	}
   523  
   524  	offset += 16 + mh.VersionString
   525  	if mh.Flags, err = pe.ReadUint8(offset); err != nil {
   526  		return mh, err
   527  	}
   528  
   529  	if mh.Streams, err = pe.ReadUint16(offset + 2); err != nil {
   530  		return mh, err
   531  	}
   532  
   533  	return mh, err
   534  }
   535  
   536  // The 15th directory entry of the PE header contains the RVA and size of the
   537  // runtime header in the image file. The runtime header, which contains all of
   538  // the runtime-specific data entries and other information, should reside in a
   539  // read-only section of the image file. The IL assembler puts the common
   540  // language runtime header in the .text section.
   541  func (pe *File) parseCLRHeaderDirectory(rva, size uint32) error {
   542  
   543  	clrHeader := ImageCOR20Header{}
   544  	offset := pe.GetOffsetFromRva(rva)
   545  	err := pe.structUnpack(&clrHeader, offset, size)
   546  	if err != nil {
   547  		return err
   548  	}
   549  
   550  	pe.CLR.CLRHeader = clrHeader
   551  	if clrHeader.MetaData.VirtualAddress == 0 || clrHeader.MetaData.Size == 0 {
   552  		return nil
   553  	}
   554  
   555  	// If we get a CLR header, we assume that this is enough
   556  	// to say we have a CLR data to show even if parsing
   557  	// other structures fails later.
   558  	pe.HasCLR = true
   559  
   560  	offset = pe.GetOffsetFromRva(clrHeader.MetaData.VirtualAddress)
   561  	mh, err := pe.parseMetadataHeader(offset, clrHeader.MetaData.Size)
   562  	if err != nil {
   563  		return err
   564  	}
   565  	pe.CLR.MetadataHeader = mh
   566  	pe.CLR.MetadataStreams = make(map[string][]byte)
   567  	offset += 16 + mh.VersionString + 4
   568  
   569  	// Immediately following the MetadataHeader is a series of Stream Headers.
   570  	// A “stream” is to the metadata what a “section” is to the assembly. The
   571  	// NumberOfStreams property indicates how many StreamHeaders to read.
   572  	mdStreamHdrOff := uint32(0)
   573  	mdStreamHdrSize := uint32(0)
   574  	for i := uint16(0); i < mh.Streams; i++ {
   575  		sh := MetadataStreamHeader{}
   576  		if sh.Offset, err = pe.ReadUint32(offset); err != nil {
   577  			return err
   578  		}
   579  		if sh.Size, err = pe.ReadUint32(offset + 4); err != nil {
   580  			return err
   581  		}
   582  
   583  		// Name requires a special treatment.
   584  		offset += 8
   585  		for j := uint32(0); j <= 32; j++ {
   586  			var c uint8
   587  			if c, err = pe.ReadUint8(offset); err != nil {
   588  				return err
   589  			}
   590  
   591  			offset++
   592  			if c == 0 && (j+1)%4 == 0 {
   593  				break
   594  			}
   595  			if c != 0 {
   596  				sh.Name += string(c)
   597  			}
   598  		}
   599  
   600  		// The streams #~ and #- are mutually exclusive; that is, the metadata
   601  		// structure of the module is either optimized or un-optimized; it
   602  		// cannot be both at the same time or be something in between.
   603  		if sh.Name == "#~" || sh.Name == "#-" {
   604  			mdStreamHdrOff = sh.Offset
   605  			mdStreamHdrSize = sh.Size
   606  		}
   607  
   608  		// Save the stream into a map <string> []byte.
   609  		rva = clrHeader.MetaData.VirtualAddress + sh.Offset
   610  		start := pe.GetOffsetFromRva(rva)
   611  		pe.CLR.MetadataStreams[sh.Name] = pe.data[start : start+sh.Size]
   612  		pe.CLR.MetadataStreamHeaders = append(pe.CLR.MetadataStreamHeaders, sh)
   613  	}
   614  
   615  	// Get the Metadata Table Stream.
   616  	if mdStreamHdrSize == 0 {
   617  		return nil
   618  	}
   619  	// The .Offset indicated by the stream header is an RVA relative to the
   620  	// metadataDirectoryAddress in the CLRHeader.
   621  	rva = clrHeader.MetaData.VirtualAddress + mdStreamHdrOff
   622  	offset = pe.GetOffsetFromRva(rva)
   623  	mdTableStreamHdr, err := pe.parseMetadataStream(offset, mdStreamHdrSize)
   624  	if err != nil {
   625  		return nil
   626  	}
   627  	pe.CLR.MetadataTablesStreamHeader = mdTableStreamHdr
   628  
   629  	// Get the size of indexes of #String", "#GUID" and "#Blob" streams.
   630  	pe.CLR.StringStreamIndexSize = pe.GetMetadataStreamIndexSize(StringStream)
   631  	pe.CLR.GUIDStreamIndexSize = pe.GetMetadataStreamIndexSize(GUIDStream)
   632  	pe.CLR.BlobStreamIndexSize = pe.GetMetadataStreamIndexSize(BlobStream)
   633  
   634  	// This header is followed by a sequence of 4-byte unsigned integers
   635  	// indicating the number of records in each table marked 1 in the MaskValid
   636  	// bit vector.
   637  	offset += uint32(binary.Size(mdTableStreamHdr))
   638  	pe.CLR.MetadataTables = make(map[int]*MetadataTable)
   639  	for i := 0; i <= GenericParamConstraint; i++ {
   640  		if IsBitSet(mdTableStreamHdr.MaskValid, i) {
   641  			mdTable := MetadataTable{}
   642  			mdTable.Name = MetadataTableIndexToString(i)
   643  			mdTable.CountCols, err = pe.ReadUint32(offset)
   644  			if err != nil {
   645  				break
   646  			}
   647  			offset += 4
   648  			pe.CLR.MetadataTables[i] = &mdTable
   649  		}
   650  	}
   651  
   652  	// Parse the metadata tables.
   653  	for tableIndex := 0; tableIndex <= GenericParamConstraint; tableIndex++ {
   654  		table, ok := pe.CLR.MetadataTables[tableIndex]
   655  		if !ok {
   656  			continue
   657  		}
   658  
   659  		n := uint32(0)
   660  		switch tableIndex {
   661  		case Module: // 0x00
   662  			table.Content, n, err = pe.parseMetadataModuleTable(offset)
   663  		case TypeRef: // 0x01
   664  			table.Content, n, err = pe.parseMetadataTypeRefTable(offset)
   665  		case TypeDef: // 0x02
   666  			table.Content, n, err = pe.parseMetadataTypeDefTable(offset)
   667  		case Field: // 0x04
   668  			table.Content, n, err = pe.parseMetadataFieldTable(offset)
   669  		case MethodDef: // 0x06
   670  			table.Content, n, err = pe.parseMetadataMethodDefTable(offset)
   671  		case Param: // 0x08
   672  			table.Content, n, err = pe.parseMetadataParamTable(offset)
   673  		case InterfaceImpl: // 0x09
   674  			table.Content, n, err = pe.parseMetadataInterfaceImplTable(offset)
   675  		case MemberRef: // 0x0a
   676  			table.Content, n, err = pe.parseMetadataMemberRefTable(offset)
   677  		case Constant: // 0x0b
   678  			table.Content, n, err = pe.parseMetadataConstantTable(offset)
   679  		case CustomAttribute: // 0x0c
   680  			table.Content, n, err = pe.parseMetadataCustomAttributeTable(offset)
   681  		case FieldMarshal: // 0x0d
   682  			table.Content, n, err = pe.parseMetadataFieldMarshalTable(offset)
   683  		case DeclSecurity: // 0x0e
   684  			table.Content, n, err = pe.parseMetadataDeclSecurityTable(offset)
   685  		case ClassLayout: // 0x0f
   686  			table.Content, n, err = pe.parseMetadataClassLayoutTable(offset)
   687  		case FieldLayout: // 0x10
   688  			table.Content, n, err = pe.parseMetadataFieldLayoutTable(offset)
   689  		case StandAloneSig: // 0x11
   690  			table.Content, n, err = pe.parseMetadataStandAloneSignTable(offset)
   691  		case EventMap: // 0x12
   692  			table.Content, n, err = pe.parseMetadataEventMapTable(offset)
   693  		case Event: // 0x14
   694  			table.Content, n, err = pe.parseMetadataEventTable(offset)
   695  		case PropertyMap: // 0x15
   696  			table.Content, n, err = pe.parseMetadataPropertyMapTable(offset)
   697  		case Property: // 0x17
   698  			table.Content, n, err = pe.parseMetadataPropertyTable(offset)
   699  		case MethodSemantics: // 0x18
   700  			table.Content, n, err = pe.parseMetadataMethodSemanticsTable(offset)
   701  		case MethodImpl: // 0x19
   702  			table.Content, n, err = pe.parseMetadataMethodImplTable(offset)
   703  		case ModuleRef: // 0x1a
   704  			table.Content, n, err = pe.parseMetadataModuleRefTable(offset)
   705  		case TypeSpec: // 0x1b
   706  			table.Content, n, err = pe.parseMetadataTypeSpecTable(offset)
   707  		case ImplMap: // 0x1c
   708  			table.Content, n, err = pe.parseMetadataImplMapTable(offset)
   709  		case FieldRVA: // 0x1d
   710  			table.Content, n, err = pe.parseMetadataFieldRVATable(offset)
   711  		case Assembly: // 0x20
   712  			table.Content, n, err = pe.parseMetadataAssemblyTable(offset)
   713  		case AssemblyRef: // 0x23
   714  			table.Content, n, err = pe.parseMetadataAssemblyRefTable(offset)
   715  		case ExportedType: // 0x27
   716  			table.Content, n, err = pe.parseMetadataExportedTypeTable(offset)
   717  		case ManifestResource: // 0x28
   718  			table.Content, n, err = pe.parseMetadataManifestResourceTable(offset)
   719  		case NestedClass: // 0x29
   720  			table.Content, n, err = pe.parseMetadataNestedClassTable(offset)
   721  		case GenericParam: // 0x2a
   722  			table.Content, n, err = pe.parseMetadataGenericParamTable(offset)
   723  		case MethodSpec: // 0x2b
   724  			table.Content, n, err = pe.parseMetadataMethodSpecTable(offset)
   725  		case GenericParamConstraint: // 0x2c
   726  			table.Content, n, err = pe.parseMetadataGenericParamConstraintTable(offset)
   727  
   728  		default:
   729  			pe.logger.Warnf("unhandled metadata table %d %s offset 0x%x cols %d",
   730  				tableIndex, MetadataTableIndexToString(tableIndex), offset, table.CountCols)
   731  		}
   732  		offset += n
   733  
   734  	}
   735  
   736  	return nil
   737  }
   738  
   739  // String returns a string interpretation of a COMImageFlags type.
   740  func (flags COMImageFlagsType) String() []string {
   741  	COMImageFlags := map[COMImageFlagsType]string{
   742  		COMImageFlagsILOnly:           "IL Only",
   743  		COMImageFlags32BitRequired:    "32-Bit Required",
   744  		COMImageFlagILLibrary:         "IL Library",
   745  		COMImageFlagsStrongNameSigned: "Strong Name Signed",
   746  		COMImageFlagsNativeEntrypoint: "Native Entrypoint",
   747  		COMImageFlagsTrackDebugData:   "Track Debug Data",
   748  		COMImageFlags32BitPreferred:   "32-Bit Preferred",
   749  	}
   750  
   751  	var values []string
   752  	for k, v := range COMImageFlags {
   753  		if (k & flags) == k {
   754  			values = append(values, v)
   755  		}
   756  	}
   757  
   758  	return values
   759  }