Bifurcation of variables

An approach at protecting program functions

 

by

Lord Soth

 

 

All rights reserved to the Immortal Descendants

Visit us on the web at : http://www.ImmortalDescendants.com/

 

Published by Tsehp 12/8/1999

 

 

Greetings everyone. In this paper I will show you a new idea I had about protecting functions inside applications. The main principle driving me to look for such a protection was that most protections

nowadays are next to easily reversible. In fact, every cracker knows that everything can be cracked, simply because there is a "good key" if you will. This metaphore is derived from locks and keys and it means that if a lock can be opened by anyone, it can also be forced open by someone or something that does not possess they key. In any case, the important thing is to try to come up with a protection that would be as hard to crack as possible.

Yes we have seen many failed attempts and some successful. These have taught us one thing :

There ARE protections in the world that CANNOT be cracked without the original key. I will give some examples to these :

 

1.  Several dongle protections out there exist that would be nearly impossible to crack without the original dongle plug. Of course, the degree of the protection is directly related to how much effort the programmer has devoted in configuring it, but some protections exist that are impossible to crack without the original dongle to copy the "good" information from.

 

2.  Any encrypted protection that requires a password or set of binary values in order to decrypt a program executable or a part of it, or some data files that the application uses will be totally uncrackable without the password/binaries unless of course it can be brute forced easily.

We already have such good encryption keys that render brute forcing an impossible solution.

 

3.  Any type of demo of a shareware program, missing a portion of its code it uncrackable because that portion of code is just missing! Nothing will help you if one of the features of  a program just isn't there!

 

And the list can go on I presume, but all these are good examples, and they all share one thing in common : They CANNOT be cracked without the source key , file, or whatever it is the program needs.

 

Inventing yet another protection

 

So, we are set out to create a protection that is uncrackable without the source file. I will now try to explain as best I can why I came up with this weird seeming way of protection.

But first, the origin of the word Bifurcation, and the origin of the idea. In Bifurcation I mean the act

the Daktaklakpak did to the CHMMR in StarControl 3 some time during the game. For all those who don't know the game or never played it, I sympathize with you :)

When I saw that it gave me an idea. Bifurcation means something like : Dividing, Seperating, Destroying.

I decided to protect a program function by eliminating a critical aspect of the funtion in such a way that a cracker would not be able to recover it. Yes I am aware there might be many ways to accomplish this but I think this one is practically unnoticed!!

Lets now suppose that we have a program we want to protect, we also have its source naturally, lets assume for this purpose the source is in C.

We would like to take one of the functions inside the program and disable it. You will agree there are a few ways to disable functions in a program. The most simple is to either disable a menu item that is used to invoke the function, or by disabling a button, control.. etc..

Now, all these are crackable, so we will not rely on them to protect. What we'll do is actually ruin the function so that it would not run. How can we do this and be able to register a program and at the same time make it look like everything is ok ?

Well, the secret lies IMO in the variables the function is using. As you may or may not know, local variables in most language conventions are just allocated on the stack when the function is called.

This is done in the following manner in C language :

 

void OurFunction( variable list if needed.....)

{

                // decleration of local variables other than those the function receives

                int i, j, k;                 //declare some integers

                char str[20]="";    //declare a string of 20 characters

                .

                .

                // and so on and forth

 

                // now comes program code, we use the variables to do whatever we wish to do

}

 

How would this piece of code look like after compilation, that is, in Asm ?

Well here it is with all its glory :

 

Note : Function begins at address XXXXXXXX

 

XXXXXXXX        push ebp               ;save contents of EBP (base pointer register)

                                mov ebp,esp         ; save ESP register in EBP to reference variables

                                sub esp, 1A           ; allocate 26 bytes of memory on the stack

                                .

                                .

; now comes some sample program code

                                movsx eax, word ptr [ebp]   ; move value of i into EAX

                                add eax, word ptr [ebp+2]   ; add valure of j to eax (value of i), signed add

; and so on and forth

 

In this case as you can see, each integer is 2 bytes long in memory and we have 3 of them, plus a buffer of 20 bytes for the string, to a total of 26 bytes on the stack, or 1Ah.

The ESP is substracted this value because the standard use of the stack is in reverse, that is the lower ESP is, the more data is on the stack, and everything is referenced in positive offsets from the ESP register's value (that is now contained in EBP).

So the integer 'i' we declared earlier is at offset 0 from EBP (for example), and 'j' is at offset 2 , 'k' is at offset 4 , and the string is at offset 6 and is 20 bytes long.

Many times we will not see EBP used to access variables, but ESP directly, it all depends on the compiler's needs at the moment of compilation, and is of no concern to us. Whatever is used ESP or EBP is our tool of protection.

 

Ok, the next step is to explain Bifurcation. What this is as a matter of fact is to eliminate the correct variables. Since each variable is just an offset from the stack pointer, we can destroy program functionality by changing the offsets used AFTER the program is already finished!

If for example, we would have liked to Bifurcate the J variable from the example, we would change all instances of it in the function to something invalid, in the above example :

 

add eax, word ptr [ebp+??]

 

This line added J's value to I's. If we were to change the offset to anything else , we would have a problem in executing the function. If the offset is a byte value, we will of course need to use a byte value, if its a double word value, we will need a different double word value. The bigger the value, the harder its going to be for a anyone reversing the routine to know the correct offset from the stack pointer.

What good does that do you ask ?

Well the routine does now work correctly, or at all, and it doesn't take much change to make the function cause a GPF at execution time, and actually stop the program, although we don't want this, and will find a way around it a bit later.

Now, just one variable with a byte offset is not too much trouble, there are 256 possibilities. Substract from that the real amount of information allocated on the stack, and you get fewer possibilities, perfectly crackable. But what if the function is allocating 512 bytes on the stack (in our days they usually do much more) ?

Then we're faced with (to all those who know some probability) : 511! possiblites, where 511! is in fact 1*2*3*4*......*511, which is an INCREDIBLY HUGE number of possiblities!

If the offset is a word of a dword value this just makes it worse for you to guess the correct offset.

Now we will not just do that for one instance of the variable, we will do this to ALL the variable's instances in the routine, and thus make it completely un-executable.

Now the real magic is what would happen if all the instanced would be "Bifurcated". In such a case, there would be no chance of figuring out the real offset of the variable without checking all the options, and there are so many of them it would take too long.

And of course we don't have to settle for one variable, we can have 2 or 3 of them Bifurcated :)

If the offset we put in the place of the good offset is in fact something invalid (like FFFFh) we will indeed GPF the program when that code portion is executed. However, FFFFh for example is too obvious and therefore I think we could settle for something a bit smaller and more discrete :)

 

How to actually Bifurcate a variable

 

Well, now that we know what we should do, lets figure out how its done. Compile your program, and afterwards, before applying any weird protections (???), disassemble the program in your favourite disassembler or put a BPX with SI at that line of code (this is in fact the best way).

In SI, you can do symbolic debugging, and you can see pretty much how the asm looks like after compilation, although in debug compilation it is very basic in form and completely unoptimized.

Afterwards, you go to the disassembly and locate the instances of the variable. You know this because you can see in SI the offset from the stack pointer with the locals window, and thus you can easily locate the variable.

Then comes the part where you assemble the new instruction, for example :

 

add eax, word ptr [ebp+0002]

 

would change into :   add eax, word ptr [ebp+D12B]

 

or some other stupid offset like that. Of course each instance can have a different stupid offset, and its up to your imagination really :)

 

After assembling the instructions, your disassembler will show you the new opcodes, and the offset from the beginning of the file. Then all is left to do is to open the file in your favourite hex editor and change the bytes to the newly "Bifurcated" opcodes.

After this is done, you will have a protected EXE, but when the function runs it GPF's or does some other shit you don't really want it to do.

A good way in this situation is to disable the function's menu item (usually the easiest solution).

Right, you must be asking, how does the program knows it is unregistered and needs to disable the menu item ?

Answer : check the bytes you bifurcated !!

 

If for example the bifurcated bytes are at offset YYYYh from the beginning of the file and their value is 2BD1 (the reverse from D12B), you will check those and a few other bytes in a CRC like checksum.

If the CRC passes, and the bytes are indeed 2BD1 (the bad bytes), you will go ahead and disable the menu. If its anything else, enable it :)

This is a very important point. Under no circumstances do you compare the target bytes with the original GOOD bytes and enable the menu if they are equal !!!

If you do that, people will have the good bytes readily available for them to use in a patch to eliminate the protection!

So if we check for the bad bytes and in fact we have something else (say 0200h , which are the good bytes), the program will enable the menu item for us to use. Since no one patches a program except crackers, this solution is safe and you know that the menu item will be disabled untill you supply them with a patch to the program.

 

I remind you, the more instances of a variable you bifurcate, the harder it is to restore functionality to your function.

A good example of a weakened bifurcation is the ID Crackme 7, coded by your truly :)

I bifurcated 2 instances of a variable needed in the little graphics demo, and not all of them, hence the weakness. Soon I will publish the solution to the crackme.

 

Registering the program for the user (after he/she pays hehe)

 

Well, now that we know how to protect, we will need to know how to deprotect. This can be done easily with a simple patch generator. We have the original good EXE, and the bifurcated one, all we need is to make a patch, and we're done!

Of course there is an inherent problem here, or several in fact. Spreading of the patch could easily render the protection useless. Also, examing a good exe file and making a patch would have the same result. The pros and cons are yours to consider, but consider you can add some protection by making the patch only work on a specific machine, or making it self-terminate, or something.

There are many possiblities, I bet some are good to complete this protection.

If anyone has any good idea, be sure to send them my way :)

 

 

Thats it for today, I hope you enjoyed this paper and learned something.

 

For any comments, suggestions, bug reports (??? hehe), please Email me at :

 

lordsoth8@hotmail.com

LordSoth@ImmortalDescendants.com

 

or via ICQ : # 5178515

 

Greetins extend to all the ID members, all the +HCU members, the +Sandman (a +HCU member, but I feel he deserves a special thank you), The Snake, The Hobgoblin, Zitterbe, Princess, Goatass, Jeff and many many more I don't remember (as of the time of this writing, I am not at home).

I apologize if I didn't list you :(