Feed on
Posts
Comments

If you have programmed in .NET for more than a couple of weeks you’ve probably read something about how easy it is to disassemble your .NET assembly.  You may have also noticed the Dotfuscator Community Edition tool in the Visual Studio.NET 2003 tools folder and thought - ‘OK, I can use this to protect my code’. 

Just how easy is it for some to read your code after disassembly?  I thought I would do a simple test this week to find out.  See for yourself.

Finding a simple algorithm

The first step was to find a simple, short algorithm to compile into an assembly.   I needed some C# samples for the test because I knew that the Salamander on-line disassembler generated C# code. A quick search on Google turned up a quick-sort algorithm on Code Project.   Before continuing, let me give full credit to the author of the code I’m using for the test - Mark Clifton.  Check out his CodeProject article on Quick Sort to learn more about his code.

Tools of the trade

Assembler and disassemblers — compilers and decompilers, these are the yin/yang of the programming world. For those who may have forgotten the difference between a disassembler and a decompiler here is a short refresher.  Both of these tools take an existing executable file and turn it into a more readable format.

Disassembler:  Converts a compiled application into an assembler language.  This is very easy to do in  .NET because the code in the EXE is stored in IL (Intermediate Language).  Assembler instructions are closer to the CPU instruction set than they are to higher level languages like Java or Visual Basic.

Decompiler:  Converts a compiled application into a specific higher level language.  In other words it changes it to the language with which you normally write your code (C#, VB.NET, Java).

Finding a decompiler

There are a number of disassembler available for .NET code including ILDASM which ships with .NET.  There are also several decompilers.  I heard about the Remotesoft Salamander   decompiler while speaking at a software conference this year and thought I would use it for this test.  Written by Dr. Huihong Luo it will frighten you with the ease that it cracks your code.  I suppose that is its main purpose as Remotesoft also sells obfuscater tools.

Code Comparison

Here is Marks’ original code on the left and the decompiled version on the right.  I’ve tried to format the code so that the functions line up for easier comparison.

Note that all the comments in the original code do not make it into the ‘cracked’ version. 

Note: the original code was not obfuscated before compiling.

 

 

using System;
using System.Collections;
using System.IO;

// heavily modified from: http://www.msdnaa.net/Resources/Display.aspx?ResID=952

namespace AAL.Lib

{

// my own interface, allowing control over the swap process

public interface ISwap

{

void Swap(ArrayList array, int left, int right);

}

// implements a default swapper and comparer

public class Sort : ISwap, IComparer

{

public static IComparer comparer;

public static ISwap swapper;

///

/// The basic constructor does a quicksort using the built in comparer and swapper

///

/// The array to sort.

public static void QuickSort(ArrayList array)

{

Sort s=new Sort();

Sort.comparer=s;

Sort.swapper=s;

QuickSort(array, 0, array.Count-1);

}

///

/// Specifies my own swapper, but the default comparer

///

/// The array to sort.

/// The custom swapper.

public static void QuickSort(ArrayList array, ISwap swapper)

{

Sort.comparer=new Sort();

Sort.swapper=swapper;

QuickSort(array, 0, array.Count-1);

}

///

/// Specifies my own comparer, but the default swapper

///

/// The array to sort.

/// The customer comparer.

public static void QuickSort(ArrayList array, IComparer comparer)

{

Sort.comparer=comparer;

Sort.swapper=new Sort();

QuickSort(array, 0, array.Count-1);

}

///

/// Specifies both my comparer and my swapper

///

/// The array to sort.

/// The custom comparer.

/// The custom swapper.

public static void QuickSort(ArrayList array, IComparer comparer, ISwap swapper)

{

Sort.comparer=comparer;

Sort.swapper=swapper;

QuickSort(array, 0, array.Count-1);

}

private static void QuickSort(ArrayList array, int lower, int upper)

{

// Check for non-base case

if (lower < upper)

{

// Split and sort partitions

int split=Pivot(array, lower, upper);

QuickSort(array, lower, split-1);

QuickSort(array, split+1, upper);

}

}

private static int Pivot(ArrayList array, int lower, int upper)

{

// Pivot with first element

int left=lower+1;

object pivot=array[lower];

int right=upper;

// Partition array elements

while (left <= right)

{

// Find item out of place

while ( (left <= right) && (comparer.Compare(array[left], pivot) <= 0) )

{

++left;

}

while ( (left <= right) && (comparer.Compare(array[right], pivot) > 0) )

{

–right;

}

// Swap values if necessary

if (left < right)

{

swapper.Swap(array, left, right);

++left;

–right;

}

}

// Move pivot element

swapper.Swap(array, lower, right);

return right;

}

public void Swap(ArrayList array, int left, int right)

{

object swap=array[left];

array[left]=array[right];

array[right]=swap;

}

public int Compare(object a, object b)

{

return a.ToString().CompareTo(b.ToString());

}

}

}

// Decompiled by Salamander version 1.1 Beta
// Copyright 2002 Remotesoft Inc. All rights reserved.
// http://www.remotesoft.com/salamander

using System;
using System.Collections;

namespace AAL.Lib

{

public class Sort: ISwap, IComparer

{

public static IComparer comparer;

public static ISwap swapper;

public static void QuickSort(ArrayList array)

{

Sort sort = new Sort();

comparer = sort;

swapper = sort;

QuickSort(array, 0, array.Count - 1);

}

public static void QuickSort(ArrayList array, ISwap swapper)

{

comparer = new Sort();

Sort.swapper = swapper;

QuickSort(array, 0, array.Count - 1);

}

public static void QuickSort(ArrayList array, IComparer comparer)

{

Sort.comparer = comparer;

swapper = new Sort();

QuickSort(array, 0, array.Count - 1);

}

public static void QuickSort(ArrayList array, IComparer comparer, ISwap swapper)

{

Sort.comparer = comparer;

Sort.swapper = swapper;

QuickSort(array, 0, array.Count - 1);

}

private static void QuickSort(ArrayList array, int lower, int upper)

{

if (lower < upper)

{

int i = Pivot(array, lower, upper);

QuickSort(array, lower, i - 1);

QuickSort(array, i + 1, upper);

}

}

private static int Pivot(ArrayList array, int lower, int upper)

{

int i = lower + 1;

object local = array[lower];

int j = upper;

while (i <= j)

{

for (i++; i <= j && comparer.Compare(array[i], local) <= 0; i++)

{

}

for (; i <= j && comparer.Compare(array[j], local) > 0; j–)

{

}

if (i < j)

{

swapper.Swap(array, i, j);

i++;

j–;

}

}

swapper.Swap(array, lower, j);

return j;

}

public virtual void Swap(ArrayList array, int left, int right)

{

object local = array[left];

array[left] = array[right];

array[right] = local;

}

public virtual int Compare(object a, object b)

{

return a.ToString().CompareTo(b.ToString());

}

}

}


Leave a Reply