Tag Archives: .NET

Drawing the Mandelbrot Fractal in C#

I suppose you could say I had a deprived coding childhood; I already wrote about how I never calculated pi and now I am about to tell you that until this afternoon, I had never drawn the Mandelbrot set. I don’t know why I never took the time to do so, but as with the pi calculator, when I decided to plot the Mandelbrot set, I found a very interesting coding challenge waiting for me.

The first step in the process was to fix the notoriously slow Bitmap.SetPixel() method. I haven’t decompiled System.Drawing to look at .NET’s implementation but I assume it involves some sort of Marshal.Copy()ing of unmanaged bitmap data to a managed byte array, modifications to pixels in the managed byte array, and recopying the array to unmanaged memory. That’s well and good for setting three pixels. We’re going to render Mandelbrot sets of an arbitrary size; 2800×1600 is about 4.5 million pixels. Bitmap.SetPixel() would make this process way, way longer than necessary.

I created a class with a readable, writable bitmap as well as a method to set any of its pixels using unsafe code.

public class FastBitmap
    public FastBitmap(int width, int height)
        this.Bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);
    public unsafe void SetPixel(int x, int y, Color color)
        BitmapData data = this.Bitmap.LockBits(new Rectangle(0, 0, this.Bitmap.Width, this.Bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
        IntPtr scan0 = data.Scan0;
        byte* imagePointer = (byte*)scan0.ToPointer(); // Pointer to first pixel of image
        int offset = (y * data.Stride) + (3 * x); // 3x because we have 24bits/px = 3bytes/px
        byte* px = (imagePointer + offset); // pointer to the pixel we want
        px[0] = color.B; // Red component
        px[1] = color.G; // Green component
        px[2] = color.R; // Blue component
        this.Bitmap.UnlockBits(data); // Set the data again
    public Bitmap Bitmap

This class isn’t very useful outside of this program; it would need some modifications to use pixel formats other than 24bpp RGB. However, it gets the job done! The SetPixel method is what makes this class useful. It locks the provided Bitmap’s pixels, then gets a pointer to where the first color byte of the first pixel is in memory (Scan0.ToPointer()). It then figures out what the offset is to the pixel we want to modify. Finally, it creates a pointer to the pixel we want. It sets the blue, green and red to the specified color’s blue, green and red, then finally unlocks the bitmap data. When the data gets unlocked, it is saved in memory.

The SetPixel method presented here does not provide tremendous performance. It does, however, let you work with a bitmap fast enough that you won’t get bored. Most Mandelbrot rendering time is in calculations, anyway.

Now that we have an image class, we can get down to the math. The Mandelbrot fractal is based on the following formula:

Where C is the starting point on the complex plane and the starting value is zero.

Where C is the starting point on the complex plane and the starting value is zero.

The formula is given a starting value, C, that lies somewhere in the complex plane. If the formula (using C) does not tend to infinity, then C is part of the Mandelbrot set. If C tends to infinity, it is part of the Mandelbrot set. As a quick programmatic note, if the absolute value of Z sub N (the value of the formula after N iterations) ever becomes greater than two, the formula will tend to infinity.

Knowing that, we can start coming up with some pseudo-code:

for x on the screen:
  for y on the screen:
    scale (x, y) to the complex plane to figure out where we are
    c = where we are on the screen
    z = 0 + 0i
    b = a bitmap
    for i = 0 to however many iterations:
      z = z^2 + c
      if |z| > 2:
        plot (x, y) on b as some color that indicates how much "infinite tendency" there is at C

If you read the Wikipedia article about rendering the Mandelbrot set, you will notice that it uses two real numbers to accomplish the same thing as one complex one. C# has a complex number class, which we will use in our code. However, before we talk about the actual rendering, we need a color palette. The members of the Mandelbrot set will be rendered black (or actually, based on the flow of the pseudo-code, not rendered at all), while the rest of the set will be rendered some color based on how many iterations it takes for the absolute value of Z to eclipse two. The more iterations it takes, the whiter the pixel. The fewer iterations, the bluer the pixel. It all comes together in the following (very simple) method:

public static List<Color> GenerateColorPalette()
    List<Color> retVal = new List<Color>();
    for (int i = 0; i <= 255; i++)
        retVal.Add(Color.FromArgb(255, i, i, 255));
    return retVal;

Okay, we can finally translate the pseudo-code into a real Mandelbrot-rendering method:

public static Bitmap DrawMandelbrot(int width, int height, double rMin, double rMax, double iMin, double iMax)
    List<Color> Palette = GenerateColorPalette();
    FastBitmap img = new FastBitmap(width, height); // Bitmap to contain the set
    double rScale = (Math.Abs(rMin) + Math.Abs(rMax)) / width; // Amount to move each pixel in the real numbers
    double iScale = (Math.Abs(iMin) + Math.Abs(iMax)) / height; // Amount to move each pixel in the imaginary numbers
    for (int x = 0; x < width; x++)
        for (int y = 0; y < height; y++)
            Complex c = new Complex(x * rScale + rMin, y * iScale + iMin); // Scaled complex number
            Complex z = c;
            for (int i = 0; i < Palette.Count; i++) // 255 iterations with the method we already wrote
                if (z.Magnitude >= 2.0)
                    img.SetPixel(x, y, Palette[i]); // Set the pixel if the magnitude is greater than two
                    break; // We're done with this loop
                    z = c + Complex.Pow(z, 2); // Z = Zlast^2 + C
    return img.Bitmap;

Some notable points about this method:

  1. The rScale and iScale variables represent the change in real or imaginary value in the complex plane of each pixel on the screen.
  2. Some good parameters to pass to this method are rMin = -2.5, rMax = 1.0, iMin = -1.0 and iMax (no copyright infringement intended!) = 1.0.
  3. This method could be significantly improved on multi-core machines by dividing up the x-values to render and running a thread on each core. However, any rendering would have to be done after all the threads finished to avoid any cross-thread bit-locking issues. Luckily, the part that takes a while is the iterating, not the rendering.

That’s all it takes to draw a pretty good-looking Mandelbrot fractal. Here’s a fairly large one that you can give to your math teacher. I promise it will make him or her proud. I’m totally giving one to my math team coach as a New Year’s present.

Very blue...

Very blue…

It serves!

Writing a Working Web Server in Under 100 Lines of Code

UPDATE 12/30/12: You must run the compiled executable as an administrator on systems with UAC. Otherwise, the program will crash and exit.

I was reading some coding blogs last night and I happened across a guy who had written a minuscule web server in C# over his lunch break. I knew right away that I had to have one, too. A server like this one serves little practical purpose; it does not support any sort of server-side scripting (though adding a BASIC interpreter to it would be extremely cool). It does, however, serve a wide variety of documents (and will detect their MIME type prior to serving them.

The first thing I did was write a Log method to make console output look fancy:

static void Log(string message)
    Console.WriteLine("[{0}]: {1}", DateTime.Now, message);

That was quick. Next was to create an actual server method, which would continuously loop and be started asynchronously by the Main() method.

static void RunServer(int port)
    HttpListener listener = new HttpListener();
    listener.Prefixes.Add(string.Format("http://+:{0}/", port)); // Where to listen
    listener.Start(); // Fire up the server
    while (true)
        HttpListenerContext context = listener.GetContext(); // Get a connection
        Log("Requested: " + context.Request.Url);
        if (context.Request.RawUrl.EndsWith("/")) // Just asking for index; redirect
            context.Response.StatusCode = 301;
            context.Response.StatusDescription = "301 Moved Permanently";
            context.Response.RedirectLocation = context.Request.RawUrl + "index.html"; // Just send browser to index.html
            Log("Redirected client to /index.html.");
            byte[] retVal;
                retVal = File.ReadAllBytes("www" + context.Request.RawUrl); // Give the client the requested page
                context.Response.StatusCode = 404; // File not found; tell the client.
                context.Response.StatusDescription = "404 Not Found";
                Log("404: " + context.Request.RawUrl);
            string mime = GetMimeType(context.Request.RawUrl);
            context.Response.Headers.Add(HttpResponseHeader.ContentType, mime); // Give response a MIME type
            Stream respStream = context.Response.OutputStream; // Response stream we'll write to
            respStream.Write(retVal, 0, retVal.Length);
            context.Response.StatusCode = 200;
            context.Response.StatusDescription = "200 OK"; // Let client know stuff is okay
            Log("Served: " + context.Request.RawUrl + " as " + mime + ".");

There’s quite a bit going on here; I’ll try to explain it all. The beginning of this method configures an HttpListener to wait for connections and starts it. It then starts an infinite loop (the user can stop the server by closing the console window) of continuously waiting for and serving requests (listener.GetContext() blocks until something makes a request). A client can ask for three things in this simple server (since we’re not running server-side scripts):

  1. A page that exists (e.g. /index.html)
  2. A page that doesn’t exist (e.g. __++++_____-sdasfash1234.abcdf)
  3. A directory root that may or may not exist (e.g. /mysite/)

The first thing we check for is the directory root case. We check the URL to see if it ends in a slash. If it does, we redirect the client to whatever the path is, plus “index.html.” We could simply serve the “index.html” off the bat, but we’re (poorly) code golfing right now! That would take more code and accomplish essentially the same thing!

If the RawUrl does not end in a slash, we’re serving a page! Anyway, the server stores all its files in a “www” folder that lives in the same directory as the executable. Fetching “www” plus the raw path with File.ReadAllBytes gets the data of the file we are looking for. The try statement is used in the event we can’t find the file. If an exception does get raised, the server returns a “404 File Not Found” error to the client. If this server were fancy, it would also serve a 404 error page.

If the server can find the file, it determines the MIME type through a simplistic process I will detail in a moment, sets the MIME type in the header, writes the data to the client stream, gives the client a “200 OK” (I am not sure if the order matters for all this, or if all the data simply gets flushed when the HttpResponse gets closed, but this code worked fine in Chrome and IE 9), and closes the connection.

The last thing is to determine the MIME type of the file. Rather than using WIN32 interop calls, I decided to write a simplistic method of my own based on the file extension being served.

static string GetMimeType(string fileName)
    // Fast way of determining if the lowercase file name ends with something
    Func<string, bool> fendw = new Func<string, bool>(inp => fileName.ToLower().EndsWith(inp));
    // Use our function to figure out the mime type
    if (fendw(".htm") || fendw(".html")) return "text/html";
    else if (fendw(".ico")) return "image/vnd.microsoft.icon";
    else if (fendw(".png")) return "image/png";
    else if (fendw(".jpg") || fendw(".jpeg")) return "image/jpeg";
    else if (fendw(".gif")) return "image/gif";
    else if (fendw(".js")) return "text/javascript";
    else if (fendw(".css")) return "text/css";
    else return "application/octet-stream";

This method wouldn’t be very interesting were it not for the Lambda Expression (remember those things I love?). The Lambda Expression takes as a string as an argument and returns a Boolean of whether the lowercase version of the provided file name ends with the specified text. In other words, it checks to see if the file has whatever extension you pass to it and ignores case. The “fendw” name, although cryptic, is short for “file ends with;” it prevented me from having to type fileName.ToLower().EndsWith(…) over and over again!

That’s it. The web server works — we just need to add a Main() method:

static void Main(string[] args)
    Console.WriteLine("On what port should the server run?:");
    int port = int.Parse(Console.ReadLine());
    Task server = new Task(() => RunServer(port)); // Start the server async
    Log("Server started on port " + port.ToString() + ". Close this window to stop it.");
    while (!server.IsCompleted) ; // Wait infinitely

The first part of this method gets the port the user wants to run the server on. I used 2013, since it’s almost New Year’s! Next, it creates an asynchronous task (using a Lambda Expression again!) to run the server on, then fires it up and blocks indefinitely. The use of the Lambda expression is unnecessary here (since the thread Main() runs on will just loop forever), but if you wanted to listen on more ports, you could create more tasks to run new instances of the server on. It makes the code more extensible, right?

It serves!

It serves!

Serving a real web page from a website I built for a charity organization last year!

Serving a real web page from a website I built for a charity organization last year!

If you desired, you could actually open a port in your router and let your friends connect to your cool new server. I should probably warn you that doing so would be a terribly risky idea, even if you only have the port open for a short while. You wouldn’t run through wolf-infested woods with a steak or swim at the Great Barrier Reef with a gaping leg wound for ten minutes, so why would you do the same on the Internet? In other words: this code is provided “AS-IS” with no express or implied warranty, especially since I do not really know how secure this server is. My guess is that it isn’t. Still, it’s hard to go wrong with a 100-line server!

I LOVE Lambda Expressions

Lambda Expressions essentially add anonymous methods (methods that are attached to a piece of code, have no name and cannot really be explicitly called) to C#. I have not used them very much in my time as a developer, partly because they are newish and partly because I have never really had a need to use them. Yesterday, I decided to do some research into them and I really liked what I saw. Using Lambda Expressions in C# code adds a real JavaScript feel. It’s like the inline, more organized beauty of JavaScript without all sorts of annoying asynchronousness (though asynchronous delegates are possible in C#).

C# and the .NET Framework have always had very slick event handling. I have heard horror stories about listeners and hundreds of lines of code in Java, but since I am not a Java developer, I cannot relay a firsthand account of just how scary it gets. I can tell you that C# event handling started out great and became even better.

For the purposes of this blog post, I made a Windows application with three buttons (aptly named button1, button2 and button3).

Lambda Expressions at Work

Hey look, a sneak preview! Yippee!

In early versions of the language, if you wanted to do something when one of the buttons got clicked, you had to attach an event handler method like this:

button1.Click += new EventHandler(button1_Click);
void button1_Click(object sender, EventArgs e)
    MessageBox.Show("You clicked button1!");

Granted, this is awesome, but for quick snippets to run in event handlers, it’s not a very efficient use of space. Additionally, it’s hard to keep track of your code flow because you have to scroll down from where the method is attached to see what the event handler does. I am not advocating for cluttering your methods with tons of anonymous method code. I am saying that sometimes, you just want to see what is happening in your program without looking all over the place.

That’s where a delegate method comes in:

button2.Click += delegate(object sender, EventArgs e)
    MessageBox.Show("You clicked button2!")

Whoa! That’s way better! But wait, there’s more! Enter the Lambda Expression! To use Lambda Expressions, you need to use the Lambda operator. Since λ and Λ aren’t standard keyboard characters, C# uses => (not to be confused with >=) as the lambda operator. On the left side of your expression are the parameters. They do not need to be strongly-typed (scary, I know); you only have to provide a name for each and the type is inferred. On the right side of the expression is what you want to do with the code. Ready, set…

button3.Click += (sender, e) => MessageBox.Show("You clicked button3!");

WOW! That saved a lot of code! Unfortunately, it was kind of a silly example. Let’s try a slightly more complicated, relevant one. Let’s say you wanted to return the first name in a list that started with “B”. Ordinarily, you’d use a foreach loop:

List names = new List();
names.AddRange(new string[] { "John", "Bob", "Steve", "Mike", "Bill", "Emily", "Jenny", "Morgan" });
foreach (string name in names)
    if (name.StartsWith("B"))

That’s seven lines of code for the loop. With a Lambda Expression, you can cut that done to one:

List names = new List();
names.AddRange(new string[] { "John", "Bob", "Steve", "Mike", "Bill", "Emily", "Jenny", "Morgan" });
MessageBox.Show(names.First(name => name.StartsWith("B")));

Uhhh… okay. What the heck. Maybe that example is worth dissecting a little bit!

Just as before, we create a list of strings and add a bunch of names to it. Then, instead of manually looping through the list, we use a LINQ extension method. The LINQ extension will return a string (because names is a list of strings) and takes a Lambda Expression as an argument. The Lambda expression takes an argument of its own, which will be a string. It will return true if name.StartsWith(“B”) is true (note that you do not use the “return” keyword with it), and names.First will return whatever string causes the Lambda Expression to return true. Basically you end up with the first name that starts with a capital letter B, which in this case is “Bob.” Try it!

Bob Message Box


Of course, Lambda expressions have an associated type: System.Func. System.Func is a generic type; the List<string>.First method we’ve been using actually takes a parameter of the type System.Func<string, bool> where string is the parameter and bool is the return value of the Lambda Expression with which it is associated. Thus, you can actually declare Lambda expressions as variables!

Func fd = st => st.StartsWith("B"); // Declare Lambda Expression
MessageBox.Show(names.First(fd)); // Pass the Lambda Expression variable as an argument.
MessageBox.Show(fd("Steve").ToString()); // Use the Lambda Expression just like any other method (displays "False" here).

I have barely scratched the surface of Lambda Expressions in this post. You can use them asynchronously and do countless, really cool things with them with the help of LINQ. As I am hoping to get a Macbook for Christmas so I can learn Objective-C, I won’t get to use Lambda Expressions very much but I already know I am going to miss them.

If you want to learn more about Lambda Expressions, go to the MSDN page about them here or this really good StackOverflow post.

Happy expressing!

Quotebook, a Grotesquely Over-complicated Version of a Program I Wrote for a Quiz

Last week in my video game development class (which is an introductory-level course on Python 3 with some focus on games), we had a quiz. We had to talk about some things we’d learned, describe the intricate differences between Python’s if, elif and else statements, then write a program. The program intrigued me: the goal was to “simulate a fortune cookie” and display one of five different, pre-determined strings at random.

My first reaction was relief that I was going to be able to write the program with little issue. My second reaction was how incredibly far I could take that idea. An entire social network materialized in my head; a place where people could go to share and discuss quotes or fortunes. Then I realized that I was crazy, but I did decide to make some changes to the program we’d written in my spare time:

  1. Create an online component that would allow anyone to submit quotes to the “fortune cookie”. The “cookie” has become a system that I call Quotebook, for lack of a better name.
  2. Create a Python client for some kind of bare-bones Quotebook API that would accomplish the same task as the quiz program, except after retrieving the quote from Quotebook.

I knew the Python part would be the easy part, so I fired up Visual Studio and got cracking. I used most of the default template but changed the top text and removed the menu. I kept the HeadLoginView and all the other assorted login-related items so I could use the Membership class to attribute submitted quotes to a user. I also added a database to the project and created a table called quotes. Quotes has four columns:

  1. id (int)
  2. byUser (nvarchar)
  3. timestamp (timestamp)
  4. quoteText (nvarchar)

On the homepage, I added a big TextBox and a submit button. Then, I wired it up to write to the database:

protected void btnSubmitQuote_Click(object sender, EventArgs e)
    if (HttpContext.Current.User.Identity.IsAuthenticated) // Make sure user is authed before writing bad things to DB
        // Connect to the DB
        SqlConnection sconn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["messageDB"].ConnectionString);
        // Create the command to insert the values into the database
        // PARAMETERS are used to STERILIZE all inputs.
        SqlCommand scomm = new SqlCommand("INSERT INTO quotes (byUser, quoteText) VALUES (@byuser, @quotetext)", sconn);
        scomm.Parameters.Add(new SqlParameter("@byuser", System.Data.SqlDbType.NVarChar));
        scomm.Parameters.Add(new SqlParameter("@quotetext", System.Data.SqlDbType.NVarChar));
        scomm.Parameters["@byuser"].Value = Membership.GetUser().UserName;
        scomm.Parameters["@quotetext"].Value = tbQuote.Text;
        // Commit to DB
        // Close and refresh page.
        lblError.Text = "
You must login or register before adding a quote!"; // Alert user

There are a lot of points to cover here. First, the user state gets checked so quotes don’t get attributed to some kind of phantom (and so no exceptions get thrown!). I added a red, textless label to the area next to the submit button so that if the user isn’t logged in, he will get an error message. If he is logged in, the quote gets written to the database. I had to provide my own connection string in the web.config file. The connection string gets used to connect to the database, and a command gets created on that connection.

The command has two parameters: the text of the quote and the user’s name. Those are set through SQL parameters. Although I have no plans to SQL injection attack my own database, it is good practice to use parameters whenever user input is to be committed to a database. After the parameters get set, the data gets written and the connection gets closed.

With the input side of the Quotebook I/O taken care of, I set out to write the output. I wanted two different kinds of output: a mess of all the quotes in reverse chronological order on the homepage and the “bare-bones API” I mentioned earlier. Before I wrote either, I created an easy way to get data out of the database that I call the QuoteEnumerator class. I created a struct called Quote, which contains the quote text and the name of the quote submitter. QuoteEnumerator has a static method that returns a list of all the Quotes stored in the database. I implemented the two like this:

/// <summary>
/// Reads the DB and creates lists of quotes.
/// </summary>
public class QuoteEnumerator
    /// <summary>
    /// Obtains a list of quotes from the ASP.NET database.
    /// </summary>
    /// <returns></returns>
    public static List<Quote> GetQuotes()
        List<Quote> retval = new List<Quote>();
        // Connect to DB and set up the query
        SqlConnection sconn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["messageDB"].ConnectionString);
        SqlCommand scomm = new SqlCommand("SELECT * FROM quotes", sconn);
        // Read the database
        SqlDataReader sdr = scomm.ExecuteReader();
        if (sdr.HasRows)
            while (sdr.Read())
                // Iterate through the results
                Quote q = new Quote();
                q.QuoteSubmitter = sdr["byUser"].ToString();
                q.QuoteText = sdr["quoteText"].ToString();
        return retval;
/// <summary>
/// Contains a quote once it is extracted from the DB.
/// </summary>
public struct Quote
    public string QuoteText { get; set; }
    public string QuoteSubmitter { get; set; }

The QuoteEnumerator.GetQuotes() method is a relatively simplistic database reading method. It utilizes a SqlDataReader to iterate through all the rows. For each row, it retrieves the quote text and quote submitter, then adds them to a list containing all the other quotes. It returns that list. Using GetQuotes made implementing the homepage side of the output easy.

// Default.aspx.cs
protected void Page_Load(object sender, EventArgs e)
    foreach (Quote q in QuoteEnumerator.GetQuotes())
        // Append the quote to the page in a pretty-looking (?) way
        lblError.Text += string.Format("<div style='display:block; padding:2px; margin:0 auto; border:1px solid black; width:80%; text-align:center;'>{0}<br/><br/><span style='font-size:smaller'>Submitted by {1}</span></div><br>", q.QuoteText.Replace("\n", "<br/>"), q.QuoteSubmitter);

The result is, uh, kinda stunning…

Quotebook Image

That comment was sure telling the truth!

I only had two obstacles left: implementing the API and implementing the Python script that would utilize it. The API came first. I created a page called getmessage.aspx and deleted all of the code from the ASPX page except the top line indicating that it was, indeed, ASPX. In the code behind, I came up with this little gem to write a random quote as a string to the page (and to give credit to the submitter):

protected void Page_Load(object sender, EventArgs e)
    // Grab a random quote
    List<Quote> allQuotes = QuoteEnumerator.GetQuotes();
    Quote chosen = allQuotes[new Random().Next(0, allQuotes.Count)];
    // Write the quote as the response text
    Response.Write(chosen.QuoteText + "\n\nSubmitted by " + chosen.QuoteSubmitter);

Lastly, I created a Python script to read from the API. It uses urllib, and given my limited Python knowledge, it is more than good enough! (Keep in mind that this is Python 3; my last Python post was written in Python 2)

# randomMessage.py
# Random message downloader python script
print("Fortune Cookie")
DLURL = "http://localhost:6642/getmessage.aspx" # Replace with yours
import urllib.request
while input("Enter Q to quit or press ENTER to continue: ").lower() != "q":
    # Open the API page
    response = urllib.request.urlopen(DLURL)
    data = response.read().decode("utf-8") # Download and decode to a string
    print("\n" + data, end="\n\n")

With that, I entered some quotes and fired my creation up!

Quotebook Python Script Running

The awesome thing about Python is how incredibly easy it is to build relatively useful programs like this one.

Sure, it’s seven or eight times more code than the school version, but it’s extensible.

Do you have any improvements for this? Additional features? Let me know!

.NET Applications: Open Source by Default

If you have been developing .NET applications for much time, I hope you have come to realize that your Windows applications are not very secure. What do I mean by that? Let’s take a very simple application as an example:

using System;
namespace InsecureApp
    class Program
        static void Main(string[] args)
            for (; ; )
                Console.WriteLine("Enter your password:");
                if (Console.ReadLine() == "secret")
                    Console.WriteLine("Logged in. My social security number is 123-45-6789.");
                    Console.WriteLine("Your session has expired. Logged out.");
                    Console.WriteLine("Incorrect password.");

I realize this example is trivial, but I am trying to illustrate a point. I’ll do it in two ways: first, using ildasm.exe and second by using Telerik JustDecompile. No, this isn’t a product endorsement. I just needed to find a free decompiler.

You can run IL DASM with the Visual Studio Command Prompt. Here’s the output from my test program:

IL DASM Example Image

Please don’t sign me up for too many credit cards!

Not that scary, right? Potential crackers can only see the login password and your social security number. In an actual application, an email address, password, or authentication token could be visible in plain text. Remember, I did this with a free tool. I didn’t even have to download anything! What if I did, you ask?

Decompiled Code

Oh, bother.

Not only is the code reasonably close to what it actually was (to the point where it is easy-to-understand), I could look at the code in VB.NET if I wanted to and there is syntax highlighting! This is another free tool that you can use without even understanding CIL. But, say you did. Back in the day (and I do mean “in the day”, perhaps four or five years ago), I became interested in what was going on behind-the-scenes in .NET and learned some CIL. I also learned that you can use /OUT=”location” with IL DASM to actually output CIL to a file. Oh, I forgot to mention – there is a corresponding IL ASM to put the program back together.

Let’s say I’m a lazy cracker, so I am going to just jump to being logged in and then never log out. I changed the CIL for Main to look like this:

  .method private hidebysig static void  Main(string[] args) cil managed
    // Code size       81 (0x51)
    .maxstack  2
    .locals init ([0] bool CS$4$0000)
	ldstr "Cracked by 1337 H4x0r or something"
	call void [mscorlib]System.Console::set_Title(string)
    IL_0026:  ldstr      "Logged in. My social security number is 123-45-6789."
    IL_002b:  call       void [mscorlib]System.Console::WriteLine(string)
	call string [mscorlib]System.Console::ReadLine()
  } // end of method Program::Main

I then reassembled my program and ran it. There was no need to log in, and the program conveniently waited for me to hit enter before closing!

Simple Program Cracked

It took a surprising number of tries to assemble this application properly.

So, what can you do? Can you strong name your assembly? Sure, but it won’t do much to anyone that knows his or her stuff. Can you obfuscate it? Sure, but it’s only a roadblock. I did some reading about protecting .NET Windows applications from piracy, and the consensus seems to be that much protection isn’t worth it. Would you rather spend your time keeping people that will not pay for your software from using it or adding features to make more people willing to pay for it?

The important thing to take away from this post is to realize that anyone can see and modify what you write. You should not handle tasks that should be secure (such as anything that requires password or key storage) on the client side. Server-sided code is much better suited to secure tasks (since you cannot download ASP.NET binaries from a server unless something is seriously wrong), so anything that has to remain a secret should remain remote. Remember, transmitted data can be intercepted, so I am not telling you to send your passwords from the server to the client. I am telling you to have the client ask the server to do its dirty work.

The bigger message I wish to convey, though, is that you should minimize the amount of data that needs to be protected.