CrackMe Challenge [Part 5] - License Key (C#)


(The C# Dude) #1

Hey Mates,
as I said in my last post we’re coming to license key cracking. Note: I also said to make a challenge about nag removing but I think I cancel this because it’s just too easy (Think of a program with a message box at start; just remove the MessageBox() in code…). When we come to C++ this topic becomes interesting so you’ll see it then.

Description of the RE Challenge

Today we’ve got our first License algorithm (Yeah, everyone loves maths :grin:). It’s not a very complex one, so I think it’s a good start for keyGens. KeyGens? Yep, this time you don’t have to find the password (Or a valid license in this case), but you should write a simple tool for finding valid ones.

Difficulty: 3.5/10

Requirements

-C# Reversing (Think I’ll remove this point in the next posts…)
-Maybe a bit better knowledge of programming with C#; if you worked with other languages you can of course also take python, etc (Would be interesting to see it in other languages too), but I think it can’t hurt to learn the language you are reversing :wink:

Download

As always I highly recomment to take the obfuscated version but it’s Ok to have a look at the unobfuscated one too :slight_smile:.
Obfuscated: https://mega.nz/#!694nFRrB!bQKcK7Agu1MwuqBtyk_wRd-7KKCawruxZiTi-GBJejI
Unobfuscated: https://mega.nz/#!W9ZmhISC!ngaxfHNOnleFnKBs_VH9jCL4dMZBLKLZqmnI_Rks6Ng

Hints

I thought of adding a new section for helping without divulge everything because the board got spoilers! At this point a BIG thanks for the admins here on 0x00sec! They added the feature at the same day I asked for it!
Hint 1: [Spoiler]Just Copy the license algorithm out of the decompiled program[/Spoiler]
Hint 2: [Spoiler]Brute-Force the license key[/Spoiler]
Hint 3: [Spoiler]Start with “11111111” and loop through it with incrementing it everytime[/Spoiler]

Example Solution

This time it’s just the source code for an example KeyGen. Try it out if you want: http://pastebin.com/jhLtAnsh

Conclusion

This time you can build your own KeyGen which is a great step :slight_smile:. As last thing I ask you whether you are interested in harder challenges. Currently I’m working on a BIG project (More than just password cracking: Different cracking protections, requires much more time and thinking, different exercises; Should be 7.5/10 Difficulty) and I don’t know if I should use my time to post more basic articles first or if you have the fun and time for a bigger challenge. So you can chose between more basic articles in the next days and one bigger challenge.

|-TheDoctor-|


#2

My solution:

  1. Deobfuscate the C# executable.
  2. Find the class which contains the main method.
  3. Recognize that the string is parsed as individual elements (element int_0 of the key of length 1) with the following method:
    private static int smethod_1(string string_0, int int_0)
    {
    return int.Parse(string_0.Substring(int_0, 1));
    }
  4. The following line of code

result = (num % Class1.smethod_1(string_0, 0) == 0 && Class1.smethod_1(string_0, 2) + Class1.smethod_1(string_0, 5) == Class1.smethod_1(string_0, 1) && Class1.smethod_1(string_0, 3) * Class1.smethod_1(string_0, 7) % 2 == 0 && Class1.smethod_1(string_0, 6) - Class1.smethod_1(string_0, 5) == Class1.smethod_1(Environment.Version.ToString(), 0));

should then be interpreted as follows:
(i) Key[0] = (Key as integer) % Key[0] == 0; note that Key[0] cannot be 0 else a divide by zero exception will occur
(ii) Key[1] = Key[2] + Key[5]

(iii) (Key[3] * Key[7]) % 2 == 0
(iv) Key[6] - Key[5] == (.NET_Framework_version as integer)[0] (for me, it was 4)
(v) Key[1] and Key[5] can be defined a custom value as required which will derive Key[2] and Key[6]

(vi) Key[3] and Key[7] can be defined a custom value accordingly such that part (i) is true, i.e. Key[7] should be even
(vii) Key[4] can be any value

Example key: 25228372


(The C# Dude) #3

Wow, great work! Could be a new article ;). Are you ready for a bigger challenge?


#4

Sure m8te. ``


(The C# Dude) #5

How long did you need for this one?


#6

Probably like 30 minutes max. Actually can’t say. I was watching some friends playing games so my judgement may be off.


(Jakub) #7

Hi TheDoctor! For first thank you for you challenge I really like it :wink:

I’m not strong with math, but today I was able to solve this task. I spent about 1 hour to solve this on paper + write dirty version in Python.

My solution is just class with one public method generate which returns new key. This code not commented, so below I’ll write some generated keys.

using System;
using System.Text;

namespace REKeygen {
public class Part5Keygen {

    private Random _rand;
    private int _versionMajor;

    public Part5Keygen () {
        this._rand = new Random ();
        this._versionMajor = Environment.Version.Major;
    }

    public String generate () {
        int n0 = 1;
        int n1 = this.getRandInt ();
        int n2 = n1;
        int n3 = 2 * this.getRandInt (0, 4);
        int n4 = this.getRandInt ();
        int n5 = 0;
        int n6 = this._versionMajor;
        int n7 = this.getRandInt ();

        StringBuilder b = new StringBuilder (8);
        b.Append (n0);
        b.Append (n1);
        b.Append (n2);
        b.Append (n3);
        b.Append (n4);
        b.Append (n5);
        b.Append (n6);
        b.Append (n7);

        return b.ToString ();
    }

    private int getRandInt(int min = 0, int max = 9) {
        return this._rand.Next(min,max);
    }
}

}

Some codes:

13325043
10043042
15501044
11122046
14468045


(The C# Dude) #8

Another excellent work! Seems like you’re ready for bigger challenges… See my next part for a short introduction to Client/Server cracking :slight_smile:.


(Mostly whitehat) #9

Thanks for the challenge. Had a lot of fun writing a keygen for it.
keygen:

// 
// keygenerator.cpp 
//

#include <string>
#include <iostream>
#include <random>

using namespace std;

// Random number generation function
int random(int min, int max, std::mt19937 gen)
{
	std::uniform_int_distribution<> num_random(min, max);
	return num_random(gen);
}

void generate_key(int version, int number_array[])
{
	// Setup the random number generator
	std::random_device rd_source; // obtain a random number from hardware
	std::mt19937 gen(rd_source()); // seed the generator

	// Set the first digit to one, so that the whole number can always be divided by it
	number_array[0] = 1; 
	number_array[3] = random(0, 4, gen) * 2; // Single digit multiple of 2
	number_array[4] = random(0,9,gen); // completly random
	number_array[5] = random(0,9 - version,gen); // stop 6 from being larger then 9
	number_array[6] = number_array[5] + version; // digit 6 - digit 5 has to equal common runtime version
	number_array[7] = random(0, 4, gen) * 2; // Single digit multiple of 2
	number_array[2] = random(0, 9 - number_array[5], gen); // make sure digit 1 isn't larger then 9
	number_array[1] = number_array[5] + number_array[2];
}

int main(int argc, char *argv[])
{
	int runtime_version = 4;
	int key_number = 10;

	cout << "Generating " << key_number << " keys:" << endl;
	for (int i = 1; i <= key_number; i++) {
		int key_array[8];
		generate_key(runtime_version, key_array);
		for (int e = 0; e < 8; ++e)
			cout << key_array[e];
		cout << endl;
	}
	cout << "Key generation finshed!" << endl;
	getchar();
}

(The C# Dude) #10

Very cool solution in C++ :smile:. Hope you’ll have fun with the following challenges :wink:.


#11

I used C to write the keygen and JustDecompile with De4dot to deobfuscate and see the algo:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(int argc, char *argv[]) {
    srand(time(NULL) * clock());

    int key[8];
    key[0] = (rand() % 2) +1; // 1 or 2
    
    key[2] = (rand() % 4) +1; // 1 -> 4
    key[3] = 2;
    key[4] = rand() % 10; // 0 -> 9
    key[5] = 1;
    key[6] = 5;
    key[7] = key[0]; // same as 1
    
    key[1] = key[2] + key[5];

    for (int n = 0; n <= 7; n++) {
        printf("%d", key[n]);
    }
    printf("\n");

    return 0;
}

I ran it 10 times with the output:

>1 .. 10 | % { .\465.exe }
23223152
23220152
23220152
25426152
23220152
13224151
12125151
23220152
23220152
13224151                        

Not the best solution, simple and works from what I can tell. Sick as a dog today, let me know if I screwed up somewhere. Took 1hr 20(ish)mins (with interruptions; at work)


(The C# Dude) #12

Hold that speed! And a big thanks for the detailed solutions; I’m sure other people can benefit from it :wink:.


(Casa Sensei) #13

Here’s my solution for the challenge :

[spoiler]using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var alphabet = “1234567890”;
var q = alphabet.Select(x => x.ToString());
int size = 8;
for (int i = 0; i < size-1; i++)
q = q.SelectMany(x => alphabet, (x, y) => x + y);

            foreach (var item in q)
            {
                //Console.WriteLine(item);
                {
                    int num = int.Parse(item);
                    bool flag = num % Program.smethod_1(item, 0) == 0 && (Program.smethod_1(item, 2) + Program.smethod_1(item, 5) == Program.smethod_1(item, 1) && (Program.smethod_1(item, 3) * Program.smethod_1(item, 7) % 2 == 0 && Program.smethod_1(item, 6) - Program.smethod_1(item, 5) == Program.smethod_1(Environment.Version.ToString(), 0)));
                    if (flag)
                    {
                        Console.WriteLine(num);
                        Console.Read();
                    }
                }
            }
            
        Console.Read();
    }
   
    private static int smethod_1(string item, int int_0)
    {
        return int.Parse(item.Substring(int_0, 1));
    }
}

}[/spoiler]


#14

Here is my first try on one of these nice challenges :slight_smile: Written in C#.
Somewhat late but i dont mind that, somewhere i had to get started :’)

From what i can tell the generated keys are correct.
Sample Key: 13223154

[spoiler]
using System;
using System.Text;

namespace Part5KeyGen
{
class Program
{
private static int[] key = new int[8];
private static int repeat = 0;

    static void Main(string[] args)
    {
        if (args.Length > 0) { repeat = int.Parse(args[0]); }
        do
        {
            var rnd = new Random();
            key[7] = int.Parse(Environment.Version.ToString(1));
            key[0] = rnd.Next(1, 2);
            key[2] = rnd.Next(1, 4);
            key[3] = 2;
            key[4] = rnd.Next(0, 9);
            key[5] = 1;
            key[6] = 5;
            key[1] = key[2] + key[5];
            Console.WriteLine("Your Key: " + KeyArray2String());
            repeat--;
        } while (repeat >= 0);
        Console.WriteLine("Press Any Key to continue...");
        Console.ReadKey();
    }


    private static string KeyArray2String()
    {
        StringBuilder build = new StringBuilder();
        foreach(int letter in key)
            build.Append(letter);
        return build.ToString();
    }
}

}[/spoiler]

Greetz


(The C# Dude) #15

Both are cool solutions! Interesting to see how from time to time another guy solves one of the challenges.

At this point: Thanks to everyone who participates! I always enjoy seeing that these challenges are really used…


(Casa Sensei) #16

Thank you for posting these challenges !
I do love them and I learn quite a lot !


(rok) #17

Hello all,
How you deobfuscate the executable ?
thank you all


(The C# Dude) #18

Have a look at the third part of my series which handles deobfuscation.

Good luck! But I recommend you to start with the second part if you’re new to reversing.