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 }