1
C# CRASH COURSE

image

Unlike other languages, such as Ruby, Python, and Perl, C# programs can be run by default on all modern Windows machines. In addition, running programs written in C# on a Linux system such as Ubuntu, Fedora, or another flavor couldn’t be easier, especially since Mono can quickly be installed by most Linux package managers like apt or yum. This puts C# in a better position to meet cross-platform needs than most languages, with the benefit of an easy and powerful standard library at your fingertips. All in all, C# and the Mono/.NET libraries make a compelling framework for anyone wanting to write cross-platform tools quickly and easily.

Choosing an IDE

Most who want to learn C# will use an integrated development environment (IDE) like Visual Studio for writing and compiling their code. Visual Studio by Microsoft is the de facto standard for C# development around the globe. Free versions such as Visual Studio Community Edition are available for personal use and can be downloaded from Microsoft’s website at https://www.visualstudio.com/downloads/.

During the development of this book, I used MonoDevelop and Xamarin Studio depending on whether I was on Ubuntu or OS X, respectively. On Ubuntu, you can easily install MonoDevelop using the apt package manager. MonoDevelop is maintained by Xamarin, the company that also maintains Mono. To install it, use the following command:

$ sudo apt-get install monodevelop

Xamarin Studio is the OS X brand of the MonoDevelop IDE. Xamarin Studio and MonoDevelop have the same functionality, but with slightly different user interfaces. You can download the installer for the Xamarin Studio IDE from the Xamarin website at https://www.xamarin.com/download-it/.

Any of these three IDEs will fulfill our needs in this book. In fact, if you just want to use vim, you don’t even need an IDE! We’ll also soon cover how to compile a simple example using the command line C# compiler shipped with Mono instead of an IDE.

A Simple Example

To anyone who’s used C or Java, the C# syntax will seem very familiar. C# is a strongly typed language, like C and Java, which means that a variable you declare in your code can be only one type (an integer, string, or Dog class, for example) and will always be that type, no matter what. Let’s start by taking a quick look at the Hello World example in Listing 1-1, which shows some basic C# types and syntax.

using System;

namespace ch1_hello_world
{
  class MainClass
  {
    public static void Main(string[] args)
    {
    string hello = "Hello World!";
    DateTime now = DateTime.Now;
    Console.Write(hello);
    Console.WriteLine(" The date is " + now.ToLongDateString());
    }
  }
}

Listing 1-1: A basic Hello World application

Right off the bat, we need to import the namespaces we’ll use, and we do this with a using statement that imports the System namespace . This enables access to libraries in a program, similar to #include in C, import in Java and Python, and require in Ruby and Perl. After declaring the library we want to use, we declare the namespace our classes will live in.

Unlike C (and older versions of Perl), C# is an object-oriented language, similar to Ruby, Python, and Java. This means that we can build complex classes to represent data structures, along with the methods for those data structures, while writing code. Namespaces allow us to organize our classes and code as well as to prevent potential name collisions, such as when two programmers create two classes with the same name. If two classes with the same name are in different namespaces, there won’t be a problem. Every class is required to have a namespace.

With the namespace out of the way, we can declare a class that will hold our Main() method . As we stated previously, classes allow us to create complex data types as well as data structures that better fit real-world objects. In this example, the name of the class doesn’t actually matter; it’s just a container for our Main() method, which is what really matters because the Main() method is what will execute when we run our sample application. Every C# application requires a Main() method, just like in C and Java. If your C# application accepts arguments on the command line, you can use the args variable to access the arguments passed to the application.

Simple data structures, such as strings , exist in C#, and more complex ones, such as a class representing the date and time , can also be created. The DateTime class is a core C# class for dealing with dates. In our example, we use it to store the current date and time (DateTime.Now) in the variable now. Finally, with our variables declared, we can print a friendly message using the Console class’s Write() and WriteLine() methods (the latter of which includes a newline character at the end).

If you’re using an IDE, you can compile and run the code by clicking the Run button, which is in the top-left corner of the IDE and looks like a Play button, or by pressing the F5 key. However, if you would like to compile the source code from the command line with the Mono compiler, you can easily do that as well. From the directory with your C# class code, use the mcs tool shipped with Mono to compile your classes into an executable, like so:

$ mcs Main.cs -out:ch1_hello_world.exe

Running the code from Listing 1-1 should print both the string "Hello World!" and the current date on the same line, as in Listing 1-2. On some Unix systems, you may need to run mono ch1_hello_world.exe.

$ ./ch1_hello_world.exe
Hello World! The date is Wednesday, June 28, 2017

Listing 1-2: Running the Hello World application

Congratulations on your first C# application!

Introducing Classes and Interfaces

Classes and interfaces are used to create complex data structures that would be difficult to represent with just built-in structures. Classes and interfaces can have properties, which are variables that get or set values for a class or interface, and methods, which are like functions that execute on the class (or subclasses) or interface and are unique to it. Properties and methods are used to represent data about an object. For instance, a Firefighter class might need an int property to represent the firefighter’s pension or a method that tells the firefighter to drive to a place where there’s a fire.

Classes can be used as blueprints to create other classes in a technique called subclassing. When a class subclasses another class, it inherits the properties and methods from that class (known as the parent class). Interfaces are used as a blueprint for new classes as well, but unlike classes, they don’t have inheritance. Thus a base class that implements an interface won’t pass down the interface’s properties and methods if it’s subclassed.

Creating a Class

We’ll create the simple class shown in Listing 1-3 as an example that represents a public servant data structure for someone who works every day to make our lives easier and better.

public abstract class PublicServant
{
  public int PensionAmount { get; set; }
  public abstract void DriveToPlaceOfInterest();
}

Listing 1-3: The PublicServant abstract class

The PublicServant class is a special kind of class. It is an abstract class . Generally, you can just create a class like you do any other type of variable, and it is called an instance or an object. Abstract classes, though, cannot be instantiated like other classes; they can only be inherited through subclassing. There are many types of public servants—firefighters and police officers are two that come to mind immediately. It would therefore make sense to have a base class that these two types of public servants inherit from. In this case, if these two classes were subclasses of PublicServant, they would inherit a PensionAmount property and a DriveToPlaceOfInterest delegate that must be implemented by subclasses of PublicServant. There is no general “public servant” job that someone can apply for, so there isn’t a reason to create just a PublicServant instance.

Creating an Interface

A complement to classes in C# are interfaces. Interfaces allow a programmer to force a class to implement certain properties or methods that aren’t inherited. Let’s create a simple interface to start with, as shown in Listing 1-4. This interface is called IPerson and will declare a couple of properties that people usually have.

public interface IPerson
{
  string Name { get; set; }
  int Age { get; set; }
}

Listing 1-4: The IPerson interface

NOTE

Interfaces in C# are usually prefaced with an I to distinguish them from classes that may implement them. This I isn’t required, but it is a very common pattern used in mainstream C# development.

If a class were to implement the IPerson interface , that class would need to implement both a Name and an Age property on its own. Otherwise, it wouldn’t compile. I’ll show exactly what this means when we implement the Firefighter class next, which implements the IPerson interface. For now, just know that interfaces are an important and useful feature of C#. Programmers familiar with interfaces in Java will feel right at home with them. C programmers can think of them as header files with function declarations that expect a .c file to implement the function. Those familiar with Perl, Ruby, or Python may find interfaces strange at first because there isn’t a comparable feature in those languages.

Subclassing from an Abstract Class and Implementing an Interface

Let’s put our PublicServant class and IPerson interface to some use and solidify a bit of what we have talked about. We can create a class to represent our firefighters that inherits from the PublicServant class and implements the IPerson interface, as shown in Listing 1-5.

public class Firefighter : PublicServant, IPerson
{
  public Firefighter(string name, int age)
  {
    this.Name = name;
    this.Age = age;
  }

  //implement the IPerson interface
  public string Name { get; set; }
  public int Age { get; set; }

  public override void DriveToPlaceOfInterest()
  {
    GetInFiretruck();
    TurnOnSiren();
    FollowDirections();
  }

  private void GetInFiretruck() {}
  private void TurnOnSiren() {}
  private void FollowDirections() {}
}

Listing 1-5: The Firefighter class

The Firefighter class is a bit more complex than anything we’ve implemented yet. First, note that the Firefighter class inherits from the PublicServant class and implements the IPerson interface . This is done by listing the class and interface, separated by commas, after the Firefighter class name and a colon. We then create a new constructor that is used to set the properties of a class when a new class instance is created. The new constructor will accept the name and age of the firefighter as arguments, which will set the Name and Age properties required by the IPerson interface with the values passed. We then override the DriveToPlaceOfInterest() method inherited from the PublicServant class with one of our own, calling a few empty methods that we declare. We’re required to implement the DriveToPlaceOfInterest() method because it’s marked as abstract in the PublicServant class and abstract methods have to be overridden by subclasses.

NOTE

Classes come with a default constructor that has no parameters to create instances. Creating a new constructor actually overrides the default constructor.

The PublicServant class and IPerson interface can be very flexible and can be used to create classes with completely different uses. We will implement one more class, a PoliceOfficer class, as shown in Listing 1-6, using PublicServant and IPerson.

public class PoliceOfficer : PublicServant, IPerson
{
  private bool _hasEmergency;

  public PoliceOfficer(string name, int age)
  {
    this.Name = name;
    this.Age = age;
    _hasEmergency = false;
  }

  //implement the IPerson interface
  public string Name { get; set; }
  public int Age { get; set; }

  public bool HasEmergency
  {
    get { return _hasEmergency; }
    set { _hasEmergency = value; }
  }

  public override void DriveToPlaceOfInterest()
  {
    GetInPoliceCar();
    if (this.HasEmergency)
      TurnOnSiren();

    FollowDirections();
  }

  private void GetInPoliceCar() {}
  private void TurnOnSiren() {}
  private void FollowDirections() {}
}

Listing 1-6: The PoliceOfficer class

The PoliceOfficer class is similar to the Firefighter class, but there are a few differences. Most notably, a new property called HasEmergency is set in the constructor . We also override the DriveToPlaceOfInterest() method as in the previous Firefighter class, but this time, we use the HasEmergency property to determine whether the officer should drive the car with the siren on. We can use the same combination of parent class and interface to create classes that function completely differently.

Tying Everything Together with the Main() Method

We can use our new classes to test a few more features of C#. Let’s write a new Main() method to show off these new classes, as shown in Listing 1-7.

using System;

namespace ch1_the_basics
{
  public class MainClass
  {
    public static void Main(string[] args)
    {
      Firefighter firefighter = new Firefighter("Joe Carrington", 35);
      firefighter.PensionAmount = 5000;

      PrintNameAndAge(firefighter);
      PrintPensionAmount(firefighter);

      firefighter.DriveToPlaceOfInterest();

      PoliceOfficer officer = new PoliceOfficer("Jane Hope", 32);
      officer.PensionAmount = 5500;
      officer.HasEmergency = true;

     PrintNameAndAge(officer);
      PrintPensionAmount(officer);

      officer.DriveToPlaceOfInterest();
    }

    static void PrintNameAndAge(IPerson person)
    {
      Console.WriteLine("Name: " + person.Name);
      Console.WriteLine("Age: " + person.Age);
    }

    static void PrintPensionAmount(PublicServant servant)
    {
      if (servant is Firefighter)
        Console.WriteLine("Pension of firefighter: " + servant.PensionAmount);
      else if (servant is PoliceOfficer)
        Console.WriteLine("Pension of officer: " + servant.PensionAmount);
    }
  }
}

Listing 1-7: Tying together the PoliceOfficer and Firefighter classes with a Main() method

To use the PoliceOfficer and Firefighter classes, we must instantiate them using the constructors we defined in the respective classes. We do this first with the Firefighter class , passing a name of Joe Carrington and an age of 35 to the class constructor and assigning the new class to the firefighter variable. We also set the firefighter PensionAmount property to 5000. After the firefighter has been set up, we pass the object to the PrintNameAndAge() and PrintPension() methods.

Note that the PrintNameAndAge() method takes the IPerson interface as an argument, not a Firefighter, PoliceOfficer, or PublicServant class. When a class implements an interface, you can create methods that accept that interface (in our case, IPerson) as an argument. If you pass IPerson to a method, the method only has access to the properties or methods that the interface requires instead of to the whole class. In our example, only the Name and Age properties are available, which is all we need for the method.

Similarly, the PrintPensionAmount() method accepts PublicServant as its argument, so it only has access to the PublicServant properties and methods. We can use the C# is keyword to check whether an object is a certain type of class, so we do this to check whether our public servant is a Firefighter or a PoliceOfficer , and we print a message depending on which it is.

We do the same for the PoliceOfficer class as we did for Firefighter, creating a new class with a name of Jane Hope and an age of 32; then we set her pension to 5500 and her HasEmergency property to true. After printing the name, age, and pension , we call the officer’s DriveToPlaceOfInterest() method .

Running the Main() Method

Running the application should demonstrate how classes and methods interact with each other, as shown in Listing 1-8.

$ ./ch1_the_basics.exe
Name: Joe Carrington
Age: 35
Pension of firefighter: 5000
Name: Jane Hope
Age: 32
Pension of officer: 5500

Listing 1-8: Running the basics program’s Main() method

As you can see, the public servants’ names, ages, and pensions are printed to the screen, exactly as expected!

Anonymous Methods

The methods we have used so far have been class methods, but we can also use anonymous methods. This powerful feature of C# allows us to dynamically pass and assign methods using delegates. With a delegate, a delegate object is created that holds a reference to the method that will be called. We create this delegate in a parent class and then assign the delegate’s reference to anonymous methods in subclasses of the parent class. This way, we can dynamically assign a block of code in a subclass to the delegate instead of overriding the parent class’s method. To demonstrate how to use delegates and anonymous methods, we can build on the classes we have already created.

Assigning a Delegate to a Method

Let’s update the PublicServant class to use a delegate for the method DriveToPlaceOfInterest(), as shown in Listing 1-9.

public abstract class PublicServant
{
  public int PensionAmount { get; set; }
  public delegate void DriveToPlaceOfInterestDelegate();
  public DriveToPlaceOfInterestDelegate DriveToPlaceOfInterest { get; set; }
}

Listing 1-9: The PublicServant class with a delegate

In the previous PublicServant class, we needed to override the DriveToPlaceOfInterest() method if we wanted to change it. In the new PublicServant class, DriveToPlaceOfInterest() is replaced with a delegate and a property that allow us to call and assign DriveToPlaceOfInterest(). Now, any classes inheriting from the PublicServant class will have a delegate they can use to set their own anonymous method for DriveToPlaceOfInterest() instead of having to override the method within each class. Because they inherit from PublicServant, we’ll need to update our Firefighter and PoliceOfficer class constructors accordingly.

Updating the Firefighter Class

We’ll update the Firefighter class first with the new delegate property. The constructor, shown in Listing 1-10, is the only change we make.

   public Firefighter(string name, int age)
   {
     this.Name = name;
     this.Age = age;

     this.DriveToPlaceOfInterest += delegate
     {
       Console.WriteLine("Driving the firetruck");
       GetInFiretruck();
       TurnOnSiren();
       FollowDirections();
     };
   }

Listing 1-10: The Firefighter class using the delegate for the DriveToPlaceOfInterest() method

In the new Firefighter class constructor , we assign the Name and Age like we did before. Next, we create the anonymous method and assign it to the DriveToPlaceOfInterest delegate property using the += operator so that calling DriveToPlaceOfInterest() will call the anonymous method. This anonymous method prints "Driving the firetruck" and then runs the empty methods from the original class. This way, we can add the customized code we want to each method within a class without having to override it.

Creating Optional Arguments

The PoliceOfficer class requires a similar change; we update the constructor as shown in Listing 1-11. Because we’re already updating this class, we can also change it to use an optional argument, which is a parameter in a constructor that does not have to be included when a new instance is created. We’ll create two anonymous methods and use an optional argument to determine which method to assign to the delegate.

   public PoliceOfficer(string name, int age, bool hasEmergency = false)
   {
     this.Name = name;
     this.Age = age;
     this.HasEmergency = hasEmergency;

     if (this.HasEmergency)
     {
       this.DriveToPlaceOfInterest += delegate
       {
         Console.WriteLine("Driving the police car with siren");
         GetInPoliceCar();
         TurnOnSiren();
         FollowDirections();
       };
     } else
     {
       this.DriveToPlaceOfInterest += delegate
     {
       Console.WriteLine("Driving the police car");
       GetInPoliceCar();
       FollowDirections();
     };
    }
   }

Listing 1-11: The new PoliceOfficer constructor

In the new PoliceOfficer constructor , we set the Name and Age properties as we did originally. This time, however, we also use an optional third argument to assign the HasEmergency property . The third argument is optional because it does not need to be specified; it has a default value (false) when the constructor is provided with only the first two arguments. We then set the DriveToPlaceOfInterest delegate property with a new anonymous method, depending on whether HasEmergency is true .

Updating the Main() Method

With the new constructors, we can run an updated Main() method that is almost identical to the first. It’s detailed in Listing 1-12.

   public static void Main(string[] args)
   {
     Firefighter firefighter = new Firefighter("Joe Carrington", 35);
     firefighter.PensionAmount = 5000;

     PrintNameAndAge(firefighter);
     PrintPensionAmount(firefighter);

     firefighter.DriveToPlaceOfInterest();

     PoliceOfficer officer = new PoliceOfficer("Jane Hope", 32);
     officer.PensionAmount = 5500;

     PrintNameAndAge(officer);
     PrintPensionAmount(officer);

     officer.DriveToPlaceOfInterest();

     officer = new PoliceOfficer("John Valor", 32, true);
     PrintNameAndAge(officer);
     officer.DriveToPlaceOfInterest();
   }

Listing 1-12: The updated Main() method using our classes with delegates for driving to places of interest

The only differences are in the last three lines, which demonstrate creating a new PoliceOfficer who has an emergency (the third argument to the constructor is true), as opposed to Jane Hope , who has none. We then call DriveToPlaceOfInterest() on the John Valor officer .

Running the Updated Main() Method

Running the new method shows how creating two PoliceOfficer classes—one with an emergency and one without—will print two different things, as demonstrated in Listing 1-13.

  $ ./ch1_the_basics_advanced.exe
  Name: Joe Carrington
  Age: 35
  Pension of firefighter: 5000
  Driving the firetruck
  Name: Jane Hope
  Age: 32
  Pension of officer: 5500
Driving the police car
  Name: John Valor
  Age: 32
Driving the police car with siren

Listing 1-13: Running the new Main() method with classes using delegates

As you can see, creating a PoliceOfficer class with an emergency causes the officer to drive with the siren on . Jane Hope, on the other hand, can drive without her siren on because she has no emergency.

Integrating with Native Libraries

Finally, sometimes you need to use libraries that are available only in standard operating system libraries, such as libc on Linux and user32.dll on Windows. If you plan to use code in a library that was written in C, C++, or another language that gets compiled down to native assembly, C# makes working with these native libraries very easy, and we will use this technique in Chapter 4 when making cross-platform Metasploit payloads. This feature is called Platform Invoke, or P/Invoke for short. Programmers often need to use native libraries because they are faster than a virtual machine such as used by .NET or Java. Programmers such as financial or scientific professionals who use code to do heavy math might write the code that they need to be fast in C (for example, code for interfacing directly with hardware) but use C# to handle code that requires less speed.

Listing 1-14 shows a simple application that uses P/Invoke to call the standard C function printf() in Linux or to pop up a message box using user32.dll on Windows.

class MainClass
{
  [DllImport("user32", CharSet=CharSet.Auto)]
  static extern int MessageBox(IntPtr hWnd, String text, String caption, int options);

  [DllImport("libc")]
  static extern void printf(string message);
  static void Main(string[] args)
  {
    OperatingSystem os = Environment.OSVersion;

    if (os.Platform == PlatformID.Win32Windows||os.Platform == PlatformID.Win32NT)
    {
    MessageBox(IntPtr.Zero, "Hello world!", "Hello world!", 0);
    } else
    {
    printf("Hello world!");
    }
  }
}

Listing 1-14: Demonstrating P/Invoke with a simple example

This example looks more complex than it is. We first declare two functions that will be looked up externally in different libraries. We do this using the DllImport attribute . Attributes allow you to add extra information to methods (or classes, class properties, and so on) that is used at runtime by the .NET or Mono virtual machine. In our case, the DllImport attribute tells the runtime to look up the method we are declaring in another DLL, instead of expecting us to write it.

We also declare the exact function names and the parameters the functions expect. For Windows, we can use the MessageBox() function, which expects a few parameters such as the title of the pop-up and the text to be displayed. For Linux, the printf() function expects a string to print. Both of these functions are looked up at runtime, which means we can compile this on any system because the function in the external library isn’t looked for until the program is running and the function is called. This lets us compile the application on any operating system, regardless of whether that system has either or both libraries.

With our native functions declared, we can write a quick Main() method that checks the current operating system with an if statement using os.Platform . The Platform property we use maps to the PlatformID enumeration , which stores the available operating systems that the program could be running on. Using the PlatformID enumeration, we can test whether we are on Windows and then call the respective method: either MessageBox() on Windows or printf() on Unix. This application, when compiled, can be run on either a Windows machine or a Linux machine, no matter what operating system compiled it.

Conclusion

The C# language has many modern features that make it a great language for complex data and applications. We have only scratched the surface of some of the more powerful features like anonymous methods and P/Invoke. You’ll become intimate with the concepts of classes and interfaces, as well as many other advanced features, in the chapters to come. In addition, you’ll learn about many more of the core classes available to you, such as HTTP and TCP clients and much more.

As we develop our own custom security tools throughout this book, you will also learn about general programming patterns, which are useful conventions for creating classes that make building on them easy and fast. Good examples of programming patterns are used in Chapters 5 and 11 where we interface with APIs and RPCs of third-party tools such as Nessus and Metasploit.

By the end of this book, we will have covered how C# can be used for every security practitioner’s job—from the security analyst to the engineer, and even the hobbyist researcher at home. C# is a beautiful and powerful language, and with cross-platform support from Mono bringing C# to phones and embedded devices, it is just as capable and usable as Java and other alternatives.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset