Jump to content
Tuts 4 You

Recommended Posts

Teddy Rogers
Posted

Introduction

In the next part of our serial we will focus on one of the most important parts of protection of every shareware program - secure generation and verifying registration numbers. On the proposal of this algorithm stands or fails a possibility of creation of crackers registration numbers generator to a program.

Example algorithms in this article are written in Pascal. We think that almost every programmer should be familiar with this language or at least to some extent.

A lot of programmers are not very careful when programming algorithm verifying and use algorithms like:

function CheckKey(UserName, UserKey: string): boolean;
var i: integer;
Key: integer;
begin,
Key:=42;
for i:=1 to Length(UserName) do
Key:=Key + Ord(UserName[i]);
Result:=IntToStr(Key) = UserKey;
end;

Why is such an algorithm incorrect? At the first sight it is obvious that it is too simple and considerably eligible even after translation, at the level of Assembler. The second biggest mistake is that in the semifinal line, the counted key is directly being compared to the inserted key. Therefore at the time of comparison, there is fully functional registration number somewhere in the memory, so the only thing left to do is to find it.

Another big mistake is that the key is not divided into more parts and it is possible to verify it only by this one feature. A cracker needs to find this feature only in order to understand how a correct registration number should look like and what kind of algorithm is responsible for its creation. In such case, even a programming of keygen is for an experienced cracker a question of ten minutes, not mentioning that a crack (that makes sure that this function will keep returning True value) can be done within minutes. This short time period is almost alarming and enables cracker to develop cracks “as he goes”.

Designing a better registration number

To harden up crackers work is not as a difficult as it might seem. Most of all, it is necessary to give up simple numbers and master strings of multiple stand-alone units that are being verified separately by different algorithms.

A suitable scheme would then look like this (no boundaries to ones imagination, though):

ABCDEF123-ABC123-AB123456-F2

A key set up in this way can be verified by four functions. Explanation to separate parts is then as follows:

The first part is generated from the name of user by using a more difficult algorithm. In the second part the name together with the first part is used for generation. The third part is CRC-32, ElfHash, or a different control sum of the first and the second part of the key. The last two numbers could be some kind of controlling sum up of the user’s name.

What are the advantages of this kind of a registration number? During the registration (inserting the registration number) it is not necessary to check the entire number. It is enough to verify the validity of the last and semi las part of the code. By doing this, we also prevent from user’s mistake while copying the number into the program.

If both this parts are correct, the program can pretend that it is registered. The thing is that the cracker will have no idea about how the first or the second part looks like and what should it contain in order to be fully functional.

Accidental check ups are ideal

These two parts are then kept unrevealed and we can check them some other more convenient time, such as while starting a program or when using a certain feature that is available only in the registered version of the program. The best way to do this is to base the number verification on coincidence. We can for example create a random number anywhere from 1 to 6 and if we get 3, a certain part of the number is verified. This uncertainty will not please the cracker, for he will have to study and test the program much longer, until he uncovers all parts of the program.

In case that the last and the semi last part of the code is correct, but a different part is incorrect, there is no need to discuss this with the user, because the user at that time is most probably a cracker. So it is wise to purposely create some kind of an error in the program that will sooner or later (not immediately, though, so it doesn’t say where the verifying takes place) create a breakdown of the program. This error can be for example calling an object destructor that we plan on cooperating with in the nearest future. Or we can rewrite parts of the program in its memory with nonsense.

Do not punish the cracker by detuning the system

Here, it is suitable to warn you with one (according to us a very unfair) thing that is sometimes implemented into ones protection. When the program realizes that it is being cracked it causes a major damage in the program (such as deleting a half of register, rewriting random sectors on the disc with zero or other mischief.)

This behavior is incorrect and not ethic, because the protection should be defensive and not offensive. The only goal achieved is that the cracker will take it personally and will do his utmost to crack every succeeding program of his main personal enemy.

Also take into consideration the fact that the program is often being cracked by individuals who do not go public with their knowledge afterwards, but rather keep it for themselves in order to learn more tricks in terms of protection of ones software against piracy attacks. If he is angered by a collapse or damage to his system, he will publish the crack even though that was not his original intention. One should also consider an option that the detection system might for some reason fail and cause damages to innocent people.

Spice called RSA

If we really want to balance out a cracker, it is wise to consider implementation of asymmetrical cryptography, particularly above the implementation of digital signature. A more observant reader sees were we are aiming with this advice. If the digital signature was a part of the registration number, then it would be simply impossible to create a keygen or a serial.

Based on our private key that is located inside of our computer only, generator of registration numbers creates a digital signature of user’s name. This signature then becomes a part of registration number. In order to verify the signature, our program then uses public key that is identified in the program. Without the knowledge of the private key, there is basically no way to generate the correct digital signature and so the registration number.

To those, who are not so familiar with the term of asymmetrical cryptography, I should remind that there is no mathematical method that would enable the tracking of a private key from a public key. It has a lot to do with a factorization problem, but that is above the subject of this article.

Using RSA or other asymmetrical cipher is therefore a very strong method that, if applied right, gives very good results. Its only disadvantage lies in the fact that it unnecessarily prolongs the registration number and its rewriting into the registration dialogue by hand (considering a reasonable length of key – at least 512 bites) is practically impossible. In such situation, keyfiles – files containing information about user’s registration that he gets via e-mail from the author of the program upon registering, become handy.

Problems with security when using RSA

Implementation of RSA if using suitable libraries, is a question of couple of minutes. In the simplest cases, it can look like this :

...
Valid:=RSAVerify(UsrName, TheKey, e, n);
if not Valid then
...
else
...

However, it is necessary to point out two problems that happened here : RSAVerify function, regardless of how difficult it is, only returns or False value. Once the cracker succeeds in modifying this function so that it only returns True value, he won. Similarly, if substitutes “If not Valid” statement to “if Valid” (what equals the change of JNZ to JZ), he changes the whole logics of the program and so he wins again.

The second problem can be a substitution of a public key inside a program for another, his own key, to which the cracker has a relevant private key. However, this solution is very unusual, because in order break the protection, it would need a combination of crack + keygen, or crack + serial. Still, in some cases, crackers are willing to accept these unconventional solutions.

In both solutions for program protection by using RSA mentioned above, the cracker needs to access the program – whether it is the modification of EXE files, or memory modification via so-called loader (a program that executes inquired change in memory upon running an application). The cracker simply does not have another choice. Such access is relatively easy to reveal and there are even methods on how to prevent it. But that is another story…

Article from:

http://www.defendion.com/article-crack_part_2.htm

Ted.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...