Thunder_cls's NCrackme v0.1 Tutorial

December 13, 2015 - Reading time: 6 minutes

Target: Thunder_cls's NCrackme v0.1

URLhttp://crackmes.de/users/thunder_cls/ncrackme_v0.1/

Protection: Serial

Description: Crackme with a serial protection

Tools: .Net decompiler

First lets decompile the crackme and find the btnActivate_Click-method.

    private void btnActivate_Click(object sender, EventArgs e)
    {
      string text = this.txtCode.Text;
      if ((text.Length + 1) / 10 != 2 || !text.Substring(4, 1).Equals(text.Substring(9, 1)) || (!text.Substring(9, 1).Equals(text.Substring(14, 1)) || !text.Substring(14, 1).Equals("-")))
        return;
      string[] subcodeStrings;
      frmMain.SplitActCode(text, out subcodeStrings);
      if (!subcodeStrings[0].Equals(frmMain.Decode("VEMyTg==")) || !subcodeStrings[3].Equals(frmMain.Decode("UlRDUg==")) || !subcodeStrings[1].Substring(0, 2).Equals(DateTime.Now.Year.ToString().Substring(2, 2)) || !subcodeStrings[2].Substring(0, 2).Equals(DateTime.Now.Day.ToString("00")))
        return;
      int result1;
      int.TryParse(subcodeStrings[1].Substring(2, 2), out result1);
      int result2;
      int.TryParse(subcodeStrings[2].Substring(2, 2), out result2);
      double num1 = Math.Pow((double) result1, 2.0) * 54.0 - (double) (702 * result1) + 2160.0;
      double num2 = Math.Pow((double) result2, 2.0) * 54.0 - (double) (702 * result2) + 2160.0;
      if (result1 != result2 && num1.Equals(num2) && num2.Equals(0.0))
      {
        this.txtCode.Enabled = false;
        this.txtCode.Text = frmMain.Decode("UkVHSVNURVJFRA==");
        this.btnActivate.Enabled = false;
        this.btnBuy.Enabled = false;
        int num3 = (int) MessageBox.Show(frmMain.Decode("UHJvZHVjdCBjb3JyZWN0bHkgcmVnaXN0ZXJlZCE="), frmMain.Decode("UmVnaXN0ZXJlZA=="), MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
      }
      else
      {
        int num4 = (int) MessageBox.Show("SWYgeW91ciBtYXRoIHNraWxscyByIHJ1c3R5IHUgY2FuIGdldCBzb21lIGhlbHAgYnkgZ29pbmcgdG86ZDNkM0xuUnBaMlZ5TFdGc1oyVmljbUV1WTI5dEwyUnlhV3hzTHc9PQ==", "Hey U!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
      }
    }

Lets take a look at the first if-statement.

if ((text.Length + 1) / 10 != 2 || !text.Substring(4, 1).Equals(text.Substring(9, 1)) || (!text.Substring(9, 1).Equals(text.Substring(14, 1)) || !text.Substring(14, 1).Equals("-")))
        return;

So we can see that the length of the entered serial should be 20 by the (text.Length +1) / 10 != 2 statement. We also find out that the characters on positions 5, 10 and 15 should be '-'.
So we end up with is 'xxxx-xxxx-xxxx-xxxx' as our serial.

Next we se a call to SplitActCode, lets take a look at that method.

    public static void SplitActCode(string code, out string[] subcodeStrings)
    {
      subcodeStrings = code.Split('-');
    }

Ok, so now we have an array of strings split by the '-'-character. The next if-statement tells us more about what the correct serial is.

if (!subcodeStrings[0].Equals(frmMain.Decode("VEMyTg==")) || !subcodeStrings[3].Equals(frmMain.Decode("UlRDUg==")) || !subcodeStrings[1].Substring(0, 2).Equals(DateTime.Now.Year.ToString().Substring(2, 2)) || !subcodeStrings[2].Substring(0, 2).Equals(DateTime.Now.Day.ToString("00")))
        return;

Here we can see that the first block in our serial should equal the result of the Decode-method, lets take a look at that.

    public static string Decode(string str)
    {
      return Encoding.UTF8.GetString(Convert.FromBase64String(str));
    }

When we convert "VEMyTg==" and "UlRDUg==" from Base64 to UTF8 we get the strings "TC2N" and "RTCR", now lets go back to the if-statement.
Our first block should equal TC2N and our fourth block should equal RTCR. Now our serial is TC2N-xxxx-xxxx-RTCR.

!subcodeStrings[1].Substring(0, 2).Equals(DateTime.Now.Year.ToString().Substring(2, 2))

Tells us that the first two characters of the second block should equal the last two digits of the current year. So add that to our serial and we get TC2N-15xx-xxxx-RTCR

Finally we have the last statement,

!subcodeStrings[2].Substring(0, 2).Equals(DateTime.Now.Day.ToString("00"))

which tells us that the first two characters of our third block should equal the current day in numbers.

So our serial so far is TC2N-15xx-10xx-RTCR

To get the last characters for our serial we have to take a look at the next few lines of code.

int result1;
int.TryParse(subcodeStrings[1].Substring(2, 2), out result1);
int result2;
int.TryParse(subcodeStrings[2].Substring(2, 2), out result2);
double num1 = Math.Pow((double) result1, 2.0) * 54.0 - (double) (702 * result1) + 2160.0;
double num2 = Math.Pow((double) result2, 2.0) * 54.0 - (double) (702 * result2) + 2160.0;
if (result1 != result2 && num1.Equals(num2) && num2.Equals(0.0))

From this we now know that the last two characters of the second and third block of the serial should be an integer, we also find out that the calculations should be 0 for both of the integers and that they can't be the same number.

Lets rewrite the code as an equation, x^2*54-702*x+2160 = 0, or 54x^2-702x+2160=0.

And if we simplify the equation we get 54(x^2 - 702x/54 + 2160/54) = 54(x^2 - 13x + 40).

Now we can solve x^2-13x+40 using the quadratic formula.
x = (13 +- sqr(13^2 - 4*1*40))/2
  = (13 +- sqr(169 - 160))/2
  = (13 +- srq(9))/2
  = (13 +- 3)/2.

Finally our two possible values for x are 10/2 = 5 and 16/2 = 8.

Now we've got a valid serial TC2N-1505-1008-RTCR.

Following is a keygen written in C#.

namespace NCrackme_Keygen
{
    class Program
    {
        static void Main()
        {
            var stringBuilder = new StringBuilder();
            stringBuilder.Append("TC2N-");
            stringBuilder.Append(DateTime.Now.Year.ToString().Substring(2, 2));
            stringBuilder.Append("05-");
            stringBuilder.Append(DateTime.Now.Day.ToString("00"));
            stringBuilder.Append("08-RTCR");
            Console.WriteLine("Todays serial is: {0}", stringBuilder);
            Console.ReadKey();
        }
    }
}