Justin Angel‘s Windows Phone Marketplace Statistics post makes very interesting reading. Justin has done a stellar job downloading all of the Marketplace applications and performing a lot of statistical analysis.
I was particularly interested in one of the statistics: 97% of Marketplace apps aren’t obfuscated. On the off chance that you haven’t come across obfuscation yet, here’s something from wikipedia to get you started:
Obfuscation is the concealment of intended meaning in communication, making communication confusing, intentionally ambiguous, and more difficult to interpret.
http://en.wikipedia.org/wiki/Obfuscation
Obviously this means that a mere 3% of the apps in the Marketplace have some form of obfuscation. Justin was looking for PreEmptive Solutions Dotfuscator signatures, which is currently the only Windows Phone obfuscater available. Regardless of the obfuscation monopoly, 3% for what is currently the de facto tool is surprisingly low and worrying. I think back to my days in academia and how source code was something to be protected. Getting your hands on somebody else’s code was (for some students) a real boon – if you were struggling, picking up a top student’s discarded source code could provide you with something from which gave you a start. I witnessed this a few times, it happened “back in the day”, and I’m sure it still happens today.
Traditionally, we’ve used reflection to provide us with some insight as to the contents of .net assemblies. We used, almost exclusively, .NET Reflector, although recently we’ve seen similar offerings from JetBrains (dotPeek) and Telerik (JustDecompile) to name but two other reverse engineering or decompilation tools. Typically, these tools looks for .dll or .exe files. Windows Phone apps are deployed via a .xap file, we need to crack open the .xap and extract the .dlls that we are interested in looking at. Given that .xap files are actually no more than .zip files, we can simply rename the .xap to .zip and pull out the .dlls from there.
An Example
About 20 years ago (ahem!), my Pascal tutor set us a programming exercise. The full details are documented in this post. In a nutshell, we had to create a [Pascal] program that accepted a letter A thru Z and plotted a text-based triangle, where the chosen letter was the “middle” of the triangle. Once you see the screenshot (and the code), all will become clear.
Needless to say, the problem wasn’t as simple as it sounded. As soon as students demonstrated a solution, others were keen to look at the algorithms and tricks used to arrive at the solution. The code below presents a re-hashed version of my original submission, updated slightly such that it runs as a Windows Phone app.
private void button1_Click(object sender, RoutedEventArgs e)
{
char widest_char;
int next_char, finish_char, wide, range, direction, position, spacelength, loop;
widest_char = 'F';
wide = (int)widest_char;
direction = 1;
spacelength = 1;
position = 1;
next_char = 66;
finish_char = 65;
range = 2 * (wide - finish_char);
// Calculate initial left indent
int mid = wide - 65 + 1;
String firstLetter = Char.ToString((char)finish_char);
firstLetter = firstLetter.PadLeft(mid + 1);
textBlock1.Text = firstLetter + "\n";
for (loop = 1; loop < range; loop++)
{
textBlock1.Text += (" ".PadLeft(mid - position));
textBlock1.Text += ((char)next_char);
textBlock1.Text += (" ".PadLeft(spacelength));
textBlock1.Text += ((char)next_char);
textBlock1.Text += "\n";
next_char = next_char + (1 * direction);
position = position + (1 * direction);
spacelength = spacelength + (2 * direction);
// Flip direction when the middle of the diamond is reached
if (next_char == wide) direction = -1;
}
textBlock1.Text += firstLetter;
textBlock1.Text += "\n";
}
Here's a screenshot of the output:
Visual Studio 2010 created a .xap file that was deployed to the emulator or physical device. In order to extract the .dll that makes up the diamond application, we rename the .xap file as a .zip file, from there it's just copy and paste.
It's a different story for dotPeek now. It can still inspect the .dll with ease, however the meaningful variable names have been largely lost. The crux of this particular code example revolves around the algorithm that is used to create the diamond shape - some students were very keen to get a glimpse of an algorithm! The algorithm is still very obvious from the code fragment below:
private void button1_Click(object sender, RoutedEventArgs e)
{
char ch = 'F';
int num1 = (int) ch;
int num2 = 1;
int totalWidth = 1;
int num3 = 1;
int num4 = 66;
int num5 = 65;
int num6 = 2 * (num1 - num5);
int num7 = num1 - 65 + 1;
string str1 = char.ToString((char) num5).PadLeft(num7 + 1);
this.textBlock1.Text = str1 + "\n";
for (int index = 1; index < num6; ++index)
{
TextBlock textBlock1 = this.textBlock1;
string str2 = textBlock1.Text + " ".PadLeft(num7 - num3);
textBlock1.Text = str2;
TextBlock textBlock2 = this.textBlock1;
string str3 = textBlock2.Text + (object) (char) num4;
textBlock2.Text = str3;
TextBlock textBlock3 = this.textBlock1;
string str4 = textBlock3.Text + " ".PadLeft(totalWidth);
textBlock3.Text = str4;
TextBlock textBlock4 = this.textBlock1;
string str5 = textBlock4.Text + (object) (char) num4;
textBlock4.Text = str5;
TextBlock textBlock5 = this.textBlock1;
string str6 = textBlock5.Text + "\n";
textBlock5.Text = str6;
num4 += num2;
num3 += num2;
totalWidth += 2 * num2;
if (num4 == num1)
num2 = -1;
}
TextBlock textBlock6 = this.textBlock1;
string str7 = textBlock6.Text + str1;
textBlock6.Text = str7;
TextBlock textBlock7 = this.textBlock1;
string str8 = textBlock7.Text + "\n";
textBlock7.Text = str8;
}
Obfuscating the .xap using PreEmptive Solutions' Dotfuscator, changes the playing field quite significantly. Whilst Dotfuscator can obfuscate a Windows Phone .xap file, we still have to rename it to a .zip before we can inspect the assemblies found inside it. Extracting the assembly that draws the diamond, then firing it through dotPeek results in the following, rather lengthy, code fragement:
private void ᜀ(object A_0, RoutedEventArgs A_1)
{
int A_1_1 = 6;
switch (0)
{
default:
label_2:
char ch = 'F';
int num1 = (int) ch;
int num2 = 1;
int totalWidth = 1;
int num3 = 1;
int num4 = 66;
int num5 = 65;
int num6 = 2 * (num1 - num5);
int num7 = num1 - 65 + 1;
string str1 = char.ToString((char) num5).PadLeft(num7 + 1);
this.textBlock1.Text = str1 + MainPage.b("ሗ", A_1_1);
int num8 = 1;
int num9 = 1;
while (true)
{
switch (num9)
{
case 0:
label_8:
num2 = -1;
num9 = 5;
continue;
case 1:
case 4:
num9 = 3;
continue;
case 2:
if (num4 == num1)
{
num9 = 0;
continue;
}
else
goto case 5;
case 3:
if (num8 < num6)
{
TextBlock textBlock1 = this.textBlock1;
string str2 = textBlock1.Text + MainPage.b("㠗", A_1_1).PadLeft(num7 - num3);
textBlock1.Text = str2;
TextBlock textBlock2 = this.textBlock1;
string str3 = textBlock2.Text + (object) (char) num4;
textBlock2.Text = str3;
TextBlock textBlock3 = this.textBlock1;
string str4 = textBlock3.Text + MainPage.b("㠗", A_1_1).PadLeft(totalWidth);
textBlock3.Text = str4;
TextBlock textBlock4 = this.textBlock1;
string str5 = textBlock4.Text + (object) (char) num4;
textBlock4.Text = str5;
TextBlock textBlock5 = this.textBlock1;
string str6 = textBlock5.Text + MainPage.b("ሗ", A_1_1);
textBlock5.Text = str6;
num4 += num2;
num3 += num2;
totalWidth += 2 * num2;
num9 = 2;
continue;
}
else
{
num9 = 6;
continue;
}
case 5:
if (1 == 0)
;
switch (1 == 1 ? 1 : 0)
{
case 0:
case 2:
goto label_8;
case 1:
if (0 == 0)
;
++num8;
num9 = 4;
continue;
default:
goto case 1;
}
case 6:
goto label_15;
default:
goto label_2;
}
}
label_15:
TextBlock textBlock6 = this.textBlock1;
string str7 = textBlock6.Text + str1;
textBlock6.Text = str7;
TextBlock textBlock7 = this.textBlock1;
string str8 = textBlock7.Text + MainPage.b("ሗ", A_1_1);
textBlock7.Text = str8;
break;
}
}
Clearly the Dotfuscator version is much harder to understand. This is about as far as most obfuscation methods can go, they won't make it impossible to reverse engineer your application, but they will make it very time-consuming for those trying to read and understand the code.
If you are planning to obfuscate your Windows Phone apps, be sure to test them after they have been obfuscated. Like any tool that alters code post-compile, there is a chance that something may cause your app to fail. As part of the Windows Phone SDK, the Application Deployment tool is your friend. It will let you deploy .xap files to the emulator or a physical device outside of Visual Studio 2010. In other words, once you've built and tested your app, after you've obfuscated the .xap, use the Application Deployment tool to re-test the deployment.
Of course, if you are targeting Windows Phone Mango, all of this becomes rather academic. As Justin points out, from Mango onwards, .xap files will be DRM protected. Whilst your .xap will be downloadable from the Marketplace, the file itself can't be cracked open in the same way I mentioned earlier in this post. However, if you are planning to target Windows Phone 7.0 "NoDo" 7392/7390 builds, obfuscation might be something for you to consider.