Introduction

The goal of this article is to explain the CIL syntax and semantics for defining object-oriented language elements such as namespace, interface, field, class, etc. CIL programming is typically done using non-specialized editors that do not provide Intellisense and other rich-environment features available in the Visual Studio IDE. Yet IL developers can still implement all the same constructs they would typically implement using higher level languages, such as C#. And having an understanding of the inner workings of CIL and .NET is beneficial, especially while doing code optimization, debugging, or reverse engineering (such as malicious code detection or subverting security mechanisms).

Field Metadata

Fields allocate storage for .NET data types, which can include numeric, character, and decimal types. You can declare fields using the .field directive. It has three parameters: name, signature, and access modifiers (flags). Fields in the .NET framework can be categorized as value types or reference types.

.field <flags> <type> <name>

The field flags determine the accessibility scope of the field inside and outside the assembly (public, private), contract (static, initonly, literal), and reserved (marshal, rtspecialname). The type indicates the type of data (strings, character, numeric types, etc.) to be stored at this location.

The fields can be either global (inside class type) or local (inside function scope). The code in Syntax 1 shows data fields defined in the class-level scope.

Properties Metadata

Properties enable strict control over access to the internal state of an object. They behave like a public field, and the notation to access a property is the same as a public field on the instance. A property is a shorthand notation used to read and write fields. The .property directive is employed to define a property using the related .get and .set as shown in Syntax 2 and Listing 2.

Namespace

A namespace is a collection of related .NET types, such as classes, interfaces, etc., contained within an assembly. A single assembly can have more than one namespace definition. The Namespace in IL coding is declared using .namespace directive, as shown in Syntax 3.

It's important to remember that namespaces are neither considered metadata, nor referenced by IL tokens. The metadata in Figure 1 shows that none of the metadata or token relate to a namespace.

Figure 1: Metadata

Class Metadata

The Class type in IL code is defined using the .class directive. It implicitly obtains the entry of .NET System.Object base class entry as well as class should be specified by its full name, even if it is resided in the same assembly.

As we know, C# code controls the visibility of fields, methods, classes, and properties through various keywords such as public, private, abstract, sealed, etc. Table 1 describes the IL keywords for controlling the availability of types inside or outside an assembly.

Table 1: Visibility Attributes IL Code

Keyword (Attribute)

Description

extends

Allows the child class to inherits the base class

implements

Enables a class to implement the Interface functionality

sealed

Define a sealed class during inheritance

abstract

Define an abstract class

public, private, nested public, nested private

Controls the visibility of the fields, methods, and properties inside or outside the assembly

auto, sequential, explicit

These flags assist in mapping a field's data to memory (auto is the default)

Constructor Metadata

Constructors are used to initialize classes, and defined through the .ctor and .cctor directives in IL code. .ctor represents an instance-level constructor while .cctor represents a static-level constructor. Note that constructors do not return a value and so are implicitly treated as void. Syntax 4 demonstrates a default class constructor.

In the code above, it is mandatory to include the specialname and rtspecialname attributes, which uniquely identify a constructor definition in the IL code. Syntax 5 demonstrates declaring a constructor that accepts an integer argument.

Interface Metadata

An interface creates a description of properties and methods of a class type. Unlike a class, however; it is not possible to create an instance of an interface. In fact, an interface can only implement another interface. Also, an interface cannot be derived from another type like classes can. The interface shouldn't be sealed, and methods defined in an interface must be marked as virtual. Interface types are defined through .class directive in IL code as shows in Syntax 6.

Structure Metadata

Structures are user-defined types. They can contain any number of data fields, and members that operate on those fields. The structure type must be defined as sealed. Syntax 8 demonstrates using the .class directive to define a structure.

Enumerator typically contains constant fields that must be defined with a value within range for the underlying type. Listing 6 illustrates this by defining three constant values: Red, Green, and Blue.

Generics Metadata

Generics allow us to build unique types that are converted into closed types at run time. We can build generic classes that contain any integer, string, or objects types. Generics collections are far superior to their counterpart collection classes, such as Arrays, because they offer the ultimate in type safety.

Generics are defined using single tick ( ` ) in IL code, followed by a numeric value which represent the number of generic type parameters.

The IL code above would map to the following C# code, where we are defining a generic type that accepts an integer at run time.

List<int> gObj= new List<int>();

Similarly, the code in Listing 7 implements a generic class that accepts an integer type parameter at runtime and yields the addition of each added number without even bothering about type conversions at runtime.

Inheritance Metadata

Inheritance of types is a way in which the derived type guarantees support for all of the type contracts of the base class type. In addition, the derived type usually provides additional functionality or specialized behavior. In IL code, derived classes inherit the base class contracts through extends keyword as shown in Syntax 11.

The code in Listing 8 demonstrates implementing inheritance. The Father class serves as a base class to Child class. Therefore, the child class can use all of the Father class functionality, as well as add new features.

Polymorphism Metadata

The .NET framework implements polymorphism, which it overrides the base class' virtual methods. A virtual method definition can be marked by the newslot attribute in the base class only, which creates a new virtual method for the defining class and any classes derived from it. The important point to remember is that the newslot attribute would be specified in the derived class as shown in Syntax 12.

The sample in Listing 9 manipulates the numeric parameters to the various Calculation() methods, using polymorphism. In the base class, an addition operation is performed, whereas in the derived class, the base class functionality is hidden and a multiplication operation is performed.

Conclusion

This article provides a comprehensive overview of IL coding and syntax. As with higher level languages like C#, we have reached thorough understanding about how to code various inherent types of the CLR through IL opcodes, and analysis of the corresponding, generated metadata. We have got deeper into the coding mechanisms of typical CLR programming constructs like constructors, structures, generics and, moreover, the object-oriented programming features such as inheritance, interfaces, encapsulation, and polymorphism using CIL.

End-User License

Author Information

Ajay Yadav is an author, Cyber Security Specialist, Subject-Matter-Expert, Software Engineer, and System Programmer with more than eight years of work experience on diverse technology domains. He earned a Master and Bachelor Degree in Computer Science, along with numerous premier professional certifications from Microsoft, EC-council, and Red-hat. For several years, he has been researching on Reverse Engineering, Secure Source Coding, Advance Software Debugging, Vulnerability Assessment, System Programming and Exploit Development. He is a regular contributor to various international programming journals as well as assists developer community with writing blogs, research articles, tutorials, training material and books on sophisticated technology. His spare time activity includes tourism, movies and meditation. He can be reached at om.ajay007@gmail.com;