|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Index
IntroductionThe standards of the .NET format are public, you can find them on Microsoft and in your .NET SDK (look after "Partition II Metadata.doc"), but they are intended to be more like a reference, not really a guide. So, the truth is that a description of the format can be useful. I mean, there's a huge difference between having the WinNT.h and having the full explanation of its structures and stuff. The documentation given by Microsoft has some explanations, but a lot of passages aren't very clear at all. Of course, it's required that you know quite well the PE File Format. If that's not the case, you should start with that first, otherwise you won't be able to make heads or tails of this article. A little warning: I'm not going to explain how to use the libraries given by Microsoft to access the .NET format, I'm going to explain the format itself. This article is based on the Framework 2.0. Getting StartedThe only existing tool (at the moment) for viewing and editing the .NET format is my CFF Explorer. I'm sorry for the spam, but you need this tool to dig into the internal structures of the .NET format. I programmed it for this reason in the first place. The reference you could eventually need is the one I mentioned above, and you can find the includes in your Framework SDK "Include" directory (i.e., "C:\...\Microsoft.NET\SDK\v2.0\include"). .NET PE FilesBefore we start with MetaData and other stuff, some small observations about .NET PEs are necessary. They all have, for default, three sections: .text, .reloc, .rsrc. The .text section contains the Import Table, the Import Address Table, and the .NET Section. The .reloc is just there to relocate the address which the EntryPoint instruction jumps to (it's the only address contained in the IAT). The IT counts just one imported module (mscoree.dll) and one imported function ( The .NET DirectoryThe obsolete COM Directory in PEs is now the .NET Directory (I call it this way). This sections starts with the COR20 structure, also known as the CLI header: // COM+ 2.0 header structure.
typedef struct IMAGE_COR20_HEADER
{
// Header versioning
DWORD cb;
WORD MajorRuntimeVersion;
WORD MinorRuntimeVersion;
// Symbol table and startup information
IMAGE_DATA_DIRECTORY MetaData;
DWORD Flags;
// DDBLD - Added next section to replace following lin
// DDBLD - Still verifying, since not in NT SDK
// DWORD EntryPointToken;
// If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is not set,
// EntryPointToken represents a managed entrypoint.
// If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is set,
// EntryPointRVA represents an RVA to a native entrypoint.
union {
DWORD EntryPointToken;
DWORD EntryPointRVA;
};
// DDBLD - End of Added Area
// Binding information
IMAGE_DATA_DIRECTORY Resources;
IMAGE_DATA_DIRECTORY StrongNameSignature;
// Regular fixup and binding information
IMAGE_DATA_DIRECTORY CodeManagerTable;
IMAGE_DATA_DIRECTORY VTableFixups;
IMAGE_DATA_DIRECTORY ExportAddressTableJumps;
// Precompiled image info (internal use only - set to zero)
MAGE_DATA_DIRECTORY ManagedNativeHeader;
}IMAGE_COR20_HEADER, *PIMAGE_COR20_HEADER;
A brief description of the members:
Okay, now let's begin with the main subject. The MetaData SectionThis section begins with a header that I called the
But what is a stream? A stream is a "section" in the Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00074690 6C 00 00 00 l...
000746A0 FA 37 01 00 23 53 74 72 69 6E 67 73 00 00 00 00 ú7..#Strings....
000746B0 68 38 01 00 15 6F 00 00 23 55 53 00 80 A7 01 00 h8...o..#US.€§..
000746C0 94 B3 00 00 23 42 6C 6F 62 00 00 00 14 5B 02 00 ”³..#Blob....[..
000746D0 10 00 00 00 23 47 55 49 44 00 00 00 24 5B 02 00 ....#GUID...$[..
000746E0 EC 59 02 00 23 7E 00 00 ìY..#~..
I marked every last byte of every Stream Header. As you can see, the string (plus its terminator) is always rounded up to 4. I think seeing it in a hex editor makes it easier to understand the disposition. The offset in a Stream Header is not a File Offset, but an offset you have to add to the Default streams are:
The MetaData TablesThey are also known as
"The
Following this, there's an array of Following the array, we will find the actual MetaData Tables. The defined tables are: 00 - Module 01 - TypeRef 02 - TypeDef
04 - Field 06 - MethodDef 08 - Param
09 - InterfaceImpl 10 - MemberRef 11 - Constant
12 - CustomAttribute 13 - FieldMarshal 14 - DeclSecurity
15 - ClassLayout 16 - FieldLayout 17 - StandAloneSig
18 - EventMap 20 - Event 21 - PropertyMap
23 - Property 24 - MethodSemantics 25 - MethodImpl
26 - ModuleRef 27 - TypeSpec 28 - ImplMap
29 - FieldRVA 32 - Assembly 33 - AssemblyProcessor
34 - AssemblyOS 35 - AssemblyRef 36 - AssemblyRefProcessor
37 - AssemblyRefOS 38 - File 39 - ExportedType
40 - ManifestResource 41 - NestedClass 42 - GenericParam
44 - GenericParamConstraint
As you can see, some numbers are missing, that's because some tables, as I said before, are not defined yet. It's important you understand how the tables are stored. A table is made of an array of rows; a row is a structure (let's call it this way for the moment, to make things easier). After the rows of a given table end, the rows of the next table follow. The problem with a row (remember, think of it like a structure) is that some of its fields aren't always of the same size and they change from assembly to assembly, so you have to calculate them dynamically. For example, I talked about the For example, the first element of a Let's consider the
OK, I hope what I wrote above is clear. If not, you should try reading it again... and again. Now, I will list each table, give a brief description of it (and whatever I have to say in addition) and list (copy them from the SDK) its columns. Ah, before I forget, a token is a 00 - Module TableIt's a one row table representing the current assembly. Columns:
01 - TypeRef TableEach row represents an imported class, its namespace, and the assembly which contains it. Columns:
02 - TypeDef TableEach row represents a class in the current assembly. Columns:
The available flags are: typedef enum CorTypeAttr
{
// Use this mask to retrieve the type visibility information.
tdVisibilityMask = 0x00000007,
tdNotPublic = 0x00000000,
// Class is not public scope.
tdPublic = 0x00000001,
// Class is public scope.
tdNestedPublic = 0x00000002,
// Class is nested with public visibility.
tdNestedPrivate = 0x00000003,
// Class is nested with private visibility.
tdNestedFamily = 0x00000004,
// Class is nested with family visibility.
tdNestedAssembly = 0x00000005,
// Class is nested with assembly visibility.
tdNestedFamANDAssem = 0x00000006,
// Class is nested with family and assembly visibility.
tdNestedFamORAssem = 0x00000007,
// Class is nested with family or assembly visibility.
// Use this mask to retrieve class layout information
tdLayoutMask = 0x00000018,
tdAutoLayout = 0x00000000,
// Class fields are auto-laid out
tdSequentialLayout = 0x00000008,
// Class fields are laid out sequentially
tdExplicitLayout = 0x00000010,
// Layout is supplied explicitly
// end layout mask
// Use this mask to retrieve class semantics information.
tdClassSemanticsMask = 0x00000060,
tdClass = 0x00000000,
// Type is a class.
tdInterface = 0x00000020,
// Type is an interface.
// end semantics mask
// Special semantics in addition to class semantics.
tdAbstract = 0x00000080,
// Class is abstract
tdSealed = 0x00000100,
// Class is concrete and may not be extended
tdSpecialName = 0x00000400,
// Class name is special. Name describes how.
// Implementation attributes.
tdImport = 0x00001000,
// Class / interface is imported
tdSerializable = 0x00002000,
// The class is Serializable.
// Use tdStringFormatMask to retrieve string information for native interop
tdStringFormatMask = 0x00030000,
tdAnsiClass = 0x00000000,
// LPTSTR is interpreted as ANSI in this class
tdUnicodeClass = 0x00010000,
// LPTSTR is interpreted as UNICODE
tdAutoClass = 0x00020000,
// LPTSTR is interpreted automatically
tdCustomFormatClass = 0x00030000,
// A non-standard encoding specified by CustomFormatMask
tdCustomFormatMask = 0x00C00000,
// Use this mask to retrieve non-standard encoding
// information for native interop.
// The meaning of the values of these 2 bits is unspecified.
// end string format mask
tdBeforeFieldInit = 0x00100000,
// Initialize the class any time before first static field access.
tdForwarder = 0x00200000,
// This ExportedType is a type forwarder.
// Flags reserved for runtime use.
tdReservedMask = 0x00040800,
tdRTSpecialName = 0x00000800,
// Runtime should check name encoding.
tdHasSecurity = 0x00040000,
// Class has security associate with it.
} CorTypeAttr;
04 - Field TableEach row represents a field in a Columns:
Available flags are: typedef enum CorFieldAttr
{
// member access mask - Use this mask to retrieve
// accessibility information.
fdFieldAccessMask = 0x0007,
fdPrivateScope = 0x0000,
// Member not referenceable.
fdPrivate = 0x0001,
// Accessible only by the parent type.
fdFamANDAssem = 0x0002,
// Accessible by sub-types only in this Assembly.
fdAssembly = 0x0003,
// Accessibly by anyone in the Assembly.
fdFamily = 0x0004,
// Accessible only by type and sub-types.
fdFamORAssem = 0x0005,
// Accessibly by sub-types anywhere, plus anyone in assembly.
fdPublic = 0x0006,
// Accessibly by anyone who has visibility to this scope.
// end member access mask
// field contract attributes.
fdStatic = 0x0010,
// Defined on type, else per instance.
fdInitOnly = 0x0020,
// Field may only be initialized, not written to after init.
fdLiteral = 0x0040,
// Value is compile time constant.
fdNotSerialized = 0x0080,
// Field does not have to be serialized when type is remoted.
fdSpecialName = 0x0200,
// field is special. Name describes how.
// interop attributes
fdPinvokeImpl = 0x2000,
// Implementation is forwarded through pinvoke.
// Reserved flags for runtime use only.
fdReservedMask = 0x9500,
fdRTSpecialName = 0x0400,
// Runtime(metadata internal APIs) should check name encoding.
fdHasFieldMarshal = 0x1000,
// Field has marshalling information.
fdHasDefault = 0x8000,
// Field has default.
fdHasFieldRVA = 0x0100,
// Field has RVA.
} CorFieldAttr;
06 - MethodDef TableEach row represents a method in a specific class. The method's sequence follows the same logic as the field's one. Columns:
Available flags are: typedef enum CorMethodAttr
{
// member access mask - Use this mask to retrieve
// accessibility information.
mdMemberAccessMask = 0x0007,
mdPrivateScope = 0x0000,
// Member not referenceable.
mdPrivate = 0x0001,
// Accessible only by the parent type.
mdFamANDAssem = 0x0002,
// Accessible by sub-types only in this Assembly.
mdAssem = 0x0003,
// Accessibly by anyone in the Assembly.
mdFamily = 0x0004,
// Accessible only by type and sub-types.
mdFamORAssem = 0x0005,
// Accessibly by sub-types anywhere, plus anyone in assembly.
mdPublic = 0x0006,
// Accessibly by anyone who has visibility to this scope.
// end member access mask
// method contract attributes.
mdStatic = 0x0010,
// Defined on type, else per instance.
mdFinal = 0x0020,
// Method may not be overridden.
mdVirtual = 0x0040,
// Method virtual.
mdHideBySig = 0x0080,
// Method hides by name+sig, else just by name.
// vtable layout mask - Use this mask to retrieve vtable attributes.
mdVtableLayoutMask = 0x0100,
mdReuseSlot = 0x0000, // The default.
mdNewSlot = 0x0100,
// Method always gets a new slot in the vtable.
// end vtable layout mask
// method implementation attributes.
mdCheckAccessOnOverride = 0x0200,
// Overridability is the same as the visibility.
mdAbstract = 0x0400,
// Method does not provide an implementation.
mdSpecialName = 0x0800,
// Method is special. Name describes how.
// interop attributes
mdPinvokeImpl = 0x2000,
// Implementation is forwarded through pinvoke.
mdUnmanagedExport = 0x0008,
// Managed method exported via thunk to unmanaged code.
// Reserved flags for runtime use only.
mdReservedMask = 0xd000,
mdRTSpecialName = 0x1000,
// Runtime should check name encoding.
mdHasSecurity = 0x4000,
// Method has security associate with it.
mdRequireSecObject = 0x8000,
// Method calls another method containing security code.
} CorMethodAttr;
typedef enum CorMethodImpl
{
// code impl mask
miCodeTypeMask = 0x0003, // Flags about code type.
miIL = 0x0000, // Method impl is IL.
miNative = 0x0001, // Method impl is native.
miOPTIL = 0x0002, // Method impl is OPTIL
miRuntime = 0x0003, // Method impl is provided by the runtime.
// end code impl mask
// managed mask
miManagedMask = 0x0004, // Flags specifying whether the code is managed
// or unmanaged.
miUnmanaged = 0x0004, // Method impl is unmanaged, otherwise managed.
miManaged = 0x0000, // Method impl is managed.
// end managed mask
// implementation info and interop
miForwardRef = 0x0010, // Indicates method is defined; used primarily
// in merge scenarios.
miPreserveSig = 0x0080, // Indicates method sig is not to be mangled to
// do HRESULT conversion.
miInternalCall = 0x1000, // Reserved for internal use.
miSynchronized = 0x0020, // Method is single threaded through the body.
miNoInlining = 0x0008, // Method may not be inlined.
miMaxMethodImplVal = 0xffff, // Range check value
} CorMethodImpl;
The 08 - Param TableEach row represents a method's parameter. Columns:
Available flags are: typedef enum CorParamAttr
{
pdIn = 0x0001, // Param is [In]
pdOut = 0x0002, // Param is [out]
pdOptional = 0x0010, // Param is optional
// Reserved flags for Runtime use only.
pdReservedMask = 0xf000,
pdHasDefault = 0x1000, // Param has default value.
pdHasFieldMarshal = 0x2000, // Param has FieldMarshal.
pdUnused = 0xcfe0,
} CorParamAttr;
09 - InterfaceImpl TableEach row tells the framework a class that implements a specific interface. Columns:
10 - MemberRef TableAlso known as the MethodRef table. Each row represents an imported method. Columns:
11 - Constant TableEach row represents a constant value for a Param, Field, or Property. Columns:
12 - CustomAttribute TableI think the best description is given by the SDK: "The CustomAttribute table stores data that can be used to instantiate a Custom Attribute (more precisely, an object of the specified Custom Attribute class) at runtime. The column called Columns:
13 - FieldMarshal TableEach row tells the way a Param or Field should be treated when called from/to unmanaged code. Columns:
14 - DeclSecurity TableSecurity attributes attached to a class, method or assembly. Columns:
15 - ClassLayout TableRemember " Columns:
16 - FieldLayout TableRelated with the ClassLayout. Columns:
17 - StandAloneSig TableEach row represents a signature that isn't referenced by any other table. Columns:
18 - EventMap TableList of events for a specific class. Columns:
20 - Event TableEach row represents an event. Columns:
Available flags are: typedef enum CorEventAttr
{
evSpecialName = 0x0200,
// event is special. Name describes how.
// Reserved flags for Runtime use only.
evReservedMask = 0x0400,
evRTSpecialName = 0x0400,
// Runtime(metadata internal APIs) should check name encoding.
} CorEventAttr;
21 - PropertyMap TableList of Properties owned by a specific class. Columns:
23 - Property TableEach row represents a property. Columns:
Available flags are: typedef enum CorPropertyAttr
{
prSpecialName = 0x0200,
// property is special. Name describes how.
// Reserved flags for Runtime use only.
prReservedMask = 0xf400,
prRTSpecialName = 0x0400,
// Runtime(metadata internal APIs) should check name encoding.
prHasDefault = 0x1000, // Property has default
prUnused = 0xe9ff,
} CorPropertyAttr;
24 - MethodSemantics TableLinks Events and Properties to specific methods. For example, an Event can be associated to more methods. A property uses this table to associate get/set methods. Columns:
Available flags are: typedef enum CorMethodSemanticsAttr
{
msSetter = 0x0001, // Setter for property
msGetter = 0x0002, // Getter for property
msOther = 0x0004, // other method for property or event
msAddOn = 0x0008, // AddOn method for event
msRemoveOn = 0x0010, // RemoveOn method for event
msFire = 0x0020, // Fire method for event
} CorMethodSemanticsAttr;
25 - MethodImpl TableI quote: "MethodImpls lets a compiler override the default inheritance rules provided by the CLI. Their original use was to allow a class " Columns:
26 - ModuleRef TableEach row represents a reference to an external module. Columns:
27 - TypeSpec TableEach row represents a specification for a TypeDef or TypeRef. The only column indexes a token in the #Blob stream. Columns:
28 - ImplMap TableI quote: "The ImplMap table holds information about unmanaged methods that can be reached from managed code, using PInvoke dispatch. Each row of the ImplMap table associates a row in the MethodDef table ( Columns:
Available flags are: typedef enum CorPinvokeMap
{
pmNoMangle = 0x0001,
// Pinvoke is to use the member name as specified.
// Use this mask to retrieve the CharSet information.
pmCharSetMask = 0x0006,
pmCharSetNotSpec = 0x0000,
pmCharSetAnsi = 0x0002,
pmCharSetUnicode = 0x0004,
pmCharSetAuto = 0x0006,
pmBestFitUseAssem = 0x0000,
pmBestFitEnabled = 0x0010,
pmBestFitDisabled = 0x0020,
pmBestFitMask = 0x0030,
pmThrowOnUnmappableCharUseAssem = 0x0000,
pmThrowOnUnmappableCharEnabled = 0x1000,
pmThrowOnUnmappableCharDisabled = 0x2000,
pmThrowOnUnmappableCharMask = 0x3000,
pmSupportsLastError = 0x0040,
// Information about target function. Not relevant for fields.
// None of the calling convention flags is relevant for fields.
pmCallConvMask = 0x0700,
pmCallConvWinapi = 0x0100,
// Pinvoke will use native callconv appropriate to target windows platform.
pmCallConvCdecl = 0x0200,
pmCallConvStdcall = 0x0300,
pmCallConvThiscall = 0x0400,
// In M9, pinvoke will raise exception.
pmCallConvFastcall = 0x0500,
pmMaxValue = 0xFFFF,
} CorPinvokeMap;
29 - FieldRVA TableEach row is an extension for a Field table. The RVA in this table gives the location of the initial value for a Field. Columns:
32 - Assembly TableIt's a one-row table. It stores information about the current assembly. Columns:
Available flags are: typedef enum CorAssemblyFlags
{
afPublicKey = 0x0001,
// The assembly ref holds the full (unhashed) public key.
afPA_None = 0x0000,
// Processor Architecture unspecified
afPA_MSIL = 0x0010,
// Processor Architecture: neutral (PE32)
afPA_x86 = 0x0020,
// Processor Architecture: x86 (PE32)
afPA_IA64 = 0x0030,
// Processor Architecture: Itanium (PE32+)
afPA_AMD64 = 0x0040,
// Processor Architecture: AMD X64 (PE32+)
afPA_Specified = 0x0080,
// Propagate PA flags to AssemblyRef record
afPA_Mask = 0x0070,
// Bits describing the processor architecture
afPA_FullMask = 0x00F0,
// Bits describing the PA incl. Specified
afPA_Shift = 0x0004,
// NOT A FLAG, shift count in PA flags <--> index conversion
afEnableJITcompileTracking = 0x8000, // From "DebuggableAttribute".
afDisableJITcompileOptimizer= 0x4000, // From "DebuggableAttribute".
afRetargetable = 0x0100,
// The assembly can be retargeted (at runtime) to an
// assembly from a different publisher.
} CorAssemblyFlags;
The 33 - AssemblyProcessor TableThis table is ignored by the CLI and shouldn't be present in an assembly. Columns:
34 - AssemblyOS TableThis table is ignored by the CLI and shouldn't be present in an assembly. Columns:
35 - AssemblyRef TableEach row references an external assembly. Columns:
The flags are the same ones of the Assembly table. 36 - AssemblyRefProcessor TableThis table is ignored by the CLI and shouldn't be present in an assembly. Columns:
37 - AssemblyRefOS TableThis table is ignored by the CLI and shouldn't be present in an assembly. Columns:
38 - File TableEach row references an external file. Columns:
Available flags are: typedef enum CorFileFlags
{
ffContainsMetaData = 0x0000,
// This is not a resource file
ffContainsNoMetaData = 0x0001,
// This is a resource file or other non-metadata-containing file
} CorFileFlags;
39 - ExportedType TableI quote: "The ExportedType table holds a row for each type, defined within other modules of this Assembly, that is exported out of this Assembly. In essence, it stores TypeDef row numbers of all types that are marked public in other modules that this Assembly comprises". Be careful, this doesn't mean that when an assembly uses a class contained in my assembly, I export that type. In fact, I haven't yet seen this table in an assembly. Columns:
The flags are the same ones of the TypeDef. 40 - ManifestResource TableEach row references an internal or external resource. Columns:
Available flags are: typedef enum CorManifestResourceFlags
{
mrVisibilityMask = 0x0007,
mrPublic = 0x0001,
// The Resource is exported from the Assembly.
mrPrivate = 0x0002,
// The Resource is private to the Assembly.
} CorManifestResourceFlags;
If the Implementation index is 0, then the referenced resource is internal. We obtain the File Offset of the resource by adding the converted Resources RVA (the one in the CLI Header) to the offset present in this table. I wrote an article, you can either find on NTCore or CodeProject, about Manifest Resources, anyway I quote some parts from the article to give at least a brief explanation, since this section is absolutely undocumented. There are different kinds of resources referenced by this table, and not all of them can be treated in the same way. Reading a bitmap, for example, is very simple: every Manifest Resource begins with a A very brief description of the ".resources" files format: "The first OK, now we get to the interesting part. The next To gather the additional information we need, we have to skip the resource types. For each type, there's a 7 bit encoded integer which gives the size of the string that follows. To decode these kind of integers, you have to read every byte until you find one which hasn't the highest bit set and make some additional operations to obtain the final value... For the moment, let's just stick to the format. After having skipped the types, we have to align our position to an 8 byte base. Then we have a If you're interested in this subject, check out the other article I wrote, since there you can find code that may help you understand this better. 41 - NestedClass TableEach row represents a nested class. You know what a nested class is, right? There are only two columns, of course. Columns:
42 - GenericParam TableI quote: "The GenericParam table stores the generic parameters used in generic type definitions and generic methoddefinitions. These generic parameters can be constrained (i.e., generic arguments shall extend some class and/or implement certain interfaces) or unconstrained.". Columns:
Available flags are: typedef enum CorGenericParamAttr
{
// Variance of type parameters, only applicable to generic parameters
// for generic interfaces and delegates
gpVarianceMask = 0x0003,
gpNonVariant = 0x0000,
gpCovariant = 0x0001,
gpContravariant = 0x0002,
// Special constraints, applicable to any type parameters
gpSpecialConstraintMask = 0x001C,
gpNoSpecialConstraint = 0x0000,
gpReferenceTypeConstraint = 0x0004, // type argument must be a reference type
gpNotNullableValueTypeConstraint = 0x0008, // type argument must be a value
// type but not Nullable
gpDefaultConstructorConstraint = 0x0010, // type argument must have a public
// default constructor
} CorGenericParamAttr;
44 - GenericParamConstraint TableI quote: "The GenericParamConstraint table records the constraints for each generic parameter. Each generic parameter can be constrained to derive from zero or one class. Each generic parameter can be constrained to implement zero or more interfaces. Conceptually, each row in the GenericParamConstraint table is ‘owned’ by a row in the GenericParam table. All rows in the GenericParamConstraint table for a given Owner shall refer to distinct constraints.". The columns needed are, of course, only two Columns:
OK, that's all about MetaData tables. The last thing I have to explain, as I promised, is the Method format. MethodsEvery method contained in an assembly is referenced in the MethodDef table, the RVA tells us where the method is. The method body is made of three or at least two parts:
The first byte of the method tells us the type of header used. If the method uses a tiny header, the
The available flags are:
This means that when the Extra sections can have a Fat (1 byte flags, 3 bytes size) or a Small header (1 byte flags, 1 byte size); the size includes the header size. The type of the header and the type of the section is specified in the first byte, of course:
No other types than the exception handling sections are declared (this doesn't mean you shouldn't check the
Otherwise:
The number of the clauses is given by the
And the fat one:
Available flags are:
OK, that's all. The #Blob StreamThis stream contains different things as you might have already noticed going through the MetaData tables, but the only thing in this stream which is a bit difficult to understand are signatures. Every signature referenced by the MetaData tables is contained in this stream. What does a signature stand for? For instance, it could tell us the declaration of a method (be it a defined method or a referenced one), this meaning the parameters and the return type of that method. The various kinds of signatures are: When I first wrote this article (11/12/2005) the .NET reference content about signatures was a little bit poor, but now, after the April 2006 release, it has a very rich and full explanation about this subject. So there's no point in explaining the schema of every kind of signatures, you can find those in the reference. I'll explain one type of signature and I think it should be enough to understand the logic behind all of them. Let's take for instance the private void f()
{
int A = 3;
bool B = false;
if (A == 3 && B == false)
{
// I had to put the "if" clause,
// because without it the local variables
// would have been discarded for being unreferenced
}
}
The signature for the local variables in this method would be: 04 07 02 08 02. Keep in mind that every integer in the Blob is encoded but that in this case we won't notice it because the signature is made of values which are all less than 0x80. The first byte stands for the number of bytes of the signature, which in this case are 4 (keep in mind that this length is encoded).. So, the actual signature begins form the second byte and its first member is 0x07, which is the | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||