*********************************************************************

******************  ENABLING THE BACKDOOR .... **********************

*********************************************************************

 

Author : j!m

Date   : 10-24-2001

Target : All the software you can download at www.gregorybraun.com !!

Tools  : Softice, borland C,

 

INTRODUCTION

************

Gregory Braun is a shareware author, you can find and download on his site all the progs he has done.

Maybe you can find some interesting things may be not, i have downloaded crypto3.6 (file crypto) and FxEdit (hex editor).

My first goal was to devise a keygen for these pieces of software.

I achieved this task easily and i will not give you here all the details of the operation since

the interest is somewhere else (sorry, no ASM this time!).

In this essay, we are going to reverse the key generation scheme used in the products in order to create

some valid keys but also to enable a strange feature included in all Braun's softwa

re: a magic password that automatically

registers the programs!!

Ok, here we go now,

 

THE KEYGEN SCHEME

*****************

Very simple:

The valid key is the decimal representation of the number computed by:

 

H(name) + H(organization) + Product_key

 

Where H is an Hash function implemented in the same way in all the products, only the product_key differs and is

included in the exe file.

 

the C implementation of the Hash function is given here (i let you play with softice...;-)

<------------------ Listing 1: the H function ------------------------>

int hashval(char *s) {

      unsigned char table1[54] = {

      0x23,0x73,0x65,0x72,0x42,0x26,0x6E,0x7A,0x7C,0x6D,

      0x66,0x4D,0x31,0x2F,0x35,0x28,0x21,0x73,0x64,0x24,

      0x4D,0x71,0x2E,0x7B,0x73,0x5D,0x2B,0x73,0x46,0x6A,

      0x74,0x4B,0x70,0x7A,0x53,0x64,0x74,0x7A,0x6F,0x58,

      0x71,0x6D,0x62,0x5E,0x41,0x6C,0x40,0x64,0x76,0x3A,

      0x73,0x3F,0x78,0x2F};

 

      unsigned char table2[54] = {

      0x7C,0x62,0x21,0x70,0x7A,0x2A,0x6C,0x73,0x3B,0x72,

      0x6E,0x7C,0x6C,0x66,0x24

,0x76,0x69,0x5E,0x41,0x78,

      0x70,0x65,0x29,0x72,0x78,0x35,0x61,0x69,0x63,0x26,

      0x39,0x2F,0x32,0x6D,0x35,0x6C,0x73,0x69,0x34,0x40,

      0x30,0x64,0x6D,0x5A,0x77,0x39,0x34,0x63,0x6D,0x71,

      0x70,0x66,0x68,0x77};

 

      unsigned int i,l,c,a,b;

      l = strlen(s);

      c = 0;

     

      for (i=0; i<l; i++) {

            a = table2[i];

            b = table1[i+l];

            a *= b;

            a *= (i+1);

            b = s[i];

            a *= b;

            c += a;

        }

 

      return(c);

}

<----------------------------------------------------------------->

 

As an example, i give you the product_key of the tools i've downloaded:

crypto3.6: 0xC69AA96C | 0x378 (| is a logic OR ;-))

FxEdit   : 0xFEDAADEF | 0x378

 

So you can now make a keygen for these tools if you want!!

 

During my investigations i have found two curious tests, just before the serial validation.

i found something like this:

 

if H(name) = 0x119A792 

     register the program to Gregory Braun/Software Design!!!

else

     if H(name) = 0x0D5FCE3C

          ... do something !

     else

         compute val

id_key = H(name) + H(organization) + product_key

         if serial entered = valid_key

             register to name/organization

          else

             bad serial

         end if

      end if

end if

 

it looks like there is a 'magic' password that automatically register the program!, no need of a serial!!

I decided to find this 'magic' value!!

 

HOW TO DO THAT?

***************

It would be fine to find a function H' such that H'(H(name)) = name !!

So all we'll have to to is to compute H'(0x119A792) to get the right name to enter!

 

If the H function is well designed, such H' doesn't exist but maybe H is not well designed...

 

So, i looked deep into the H function in order to find a non-ierative form of the function

First thing to notice: the calculated Hash depends on the length of the string.

 

if i compute H for a one character string the function returns:

H = table2[0]*table1[1]*1*P[0]

 

if i compute H for a two characters string the function returns:

H = table2[0]*table1[2]*1*

P[0] + table2[1]*table1[3]*2*P[1]

 

if i compute H for a three characters string the function returns:

H = table2[0]*table1[3]*1*P[0] + table2[1]*table1[4]*2*P[1] + table2[2]*table1[5]*3*P[2]

 

Let's call each hash function Hi(P) (i = length of string to hash, P is the password string, P[j] are the characters)

 

if I compute H for a 'i' characters string the function returns:

Hi = table2[0]*table1[i]*1*P[0] + table2[1]*table1[i+1]*2*P[1] + ... + table2[i-1]*table1[2i-1]*i*P[i-1]

 

woow!!

 

As you can see (but maybe not!) the values in front of P[j] are constants for a given Hi.

So i have precomputed them, and here comes the coefficients for the 21 first Hi:

 

H1 : 14260

H2 : 12524,22344

H3 : 14136,12936,3762

H4 : 38184,7448,10890,54656

H5 : 4712,21560,12078,55552,66490

H6 : 13640,23912,12276,48832,62220,19404

H7 : 15128,24304,10791,45696,46970,12348,35532

H8 : 15376,21364,10098,34496,29890,11844,40068,36800

H9 : 13516,19992,7623,21952,28670,13356,30240,30360,61065

H10: 12648,15092,4851,21056

,32330,10080,24948,105800,53100,41040

H11: 9548,9604,4653,23744,24400,8316,86940,92000,19116,87780,136730

H12: 6076,9212,5247,17920,20130,28980,75600,33120,40887,128820,55660,183024

H13: 5828,10388,3960,14784,70150,25200,27216,70840,60003,52440,148830,171120,130572

H14: 6572,7840,3267,51520,61000,9072,58212,103960,24426,140220,139150,138384,60372,164220

H15: 4960,6468,11385,44800,21960,19404,85428,42320,65313,131100,112530,63984,161460,99960,57240

H16: 4092,22540,9900,16128,46970,28476,34776,113160,61065,106020,52030,171120,98280,151368,62640,141600

H17: 14260,19600,3564,34496,68930,11592,92988,105800,49383,49020,139150,104160,148824,165648,40500,211456,217770

H18: 12400,7056,7623,50624,28060,30996,86940,85560,22833,131100,84700,157728,162864,107100,60480,230336,148155,169200

H19: 4464,15092,11187,20608,75030,28980,70308,39560,61065,79800,128260,172608,105300,159936,65880,156704,178500,196272,150670

H20:

9548,22148,4554,55104,70150,23436,32508,105800,37170,120840,140360,111600,157248,174216,44820,

188800,207060,206424,137085,211200

H21:

14012,9016,12177,51520,56730,10836,86940,64400,56286,132240,90750,166656,171288,118524,54000,219008,217770,187812,108680,271200,256368

 

for example, if you want to compute the Hash of a five letter word, you have to use H5:

H5=4712*P[0] + 21560*P[1] + 12078*P[3] + 55552*P[4] + 66490*P[5] where P[0..5] are the five password letters.

 

AND NOW?

********

We have to find the password such that Hi(P) = 0x119A792 and it seems that Hi' will be very, very hard to find.

The tasks seems awfull since the password could be any length so we don't know which Hi has been used to compute this magic value...

We have to solve H1 = 0x119A792, H2 = 0x119A792, H3 = 0x119A792, ...

This kind of equations are called 'Diophantine linear equations', and are very well known from mathematicians and

cryptographers.

Solving these kind of equations is possible but will ask you advanced mathematics and you will have to read (and understand!) some papers like 'An algorithm for solving a

 diophantine equation with lower and upper bounds on the variables' by Karen Aardal, Arjen K. Lenstra, Cor Hurkens!!! or/and mastering Maple!

 

very, very difficult problem...what can i do since i can't find H' easily?

Two things:

Either a dictionnary or a brute force attack upon the hash function, the dictionnary attack is very easy to implement and should work...if the password is a word you can find in a dictionnary!

To do a brute force i have to test all the combinations of characters of arbitrary length since i don't know the password length and its composition, this is an incredible amount of words!!

It's totally impossible to do.

 

Hummm let's have a sit, it's time to go to the brain start menu!

 

have you said 'any length' for the password?

 

maybe it is not...

 

This exercise has a lot of constraints and now i will use my favorite method to solve difficult problems:

The relaxation!

This means that i will 'relax' some constaints to simplify the problem!

One of the constraints is the lengt

h of the password, another one is about the characters composing the password, they may be anything among 'a'...'z', 'A'...'Z', digits, special chars, i don't know what but i will do one hypothesis to simplify this last constraint:

 

I will assume that the password is composed of letters 'a'....'z', may be it's not true may be it is..;-)

 

Ascii values for a and z are: a=97, z=122, ok?

 

so the idea now is to minimize/maximize the Hi functions.

 

max value of Hi(P) is reached when all the password letters = 'z', P[0] = P[1] =...= P[i] = 122

min value of Hi(P) is reached when all the password letters = 'a', P[0] = P[1] =...= P[i] = 97

 

let's take the example:

H5=4712*P[0] + 21560*P[1] + 12078*P[3] + 55552*P[4] + 66490*P[5]

 

if P[0] = P[1] = ... = P[5] = 'z' = 122 then

H5 = 122 * ( 4712 + 21560 + 12078 + 55552 + 66490 ) = 122 * SUM(coefficients) = max H5

 

same thing when P[0] = P[1] = ... = P[5] = 'a' = 97, H5 = 97 * SUM(coefficients) = min H5

 

I have computed the sum of the coefficients for al

l Hi, in order to compute min and max values like this:

 

       sum     min val    max val

H1  :  14260,    1383220,   1739720

H2  :  34868,    3382196,   4253896

H3  :  30834,    2990898,   3761748

H4  :  81178,    7874266,   9903716

H5  :  160392,  15558024,  19567824

H6  :  180284,  17487548,  21994648

H7  :  190769,  18504593,  23273818

H8  :  199936,  19393792,  24392192

H9  :  226774,  21997078,  27666428

H10 :  320945,  31131665,  39155290

H11 :  502831,  48774607,  61345382

H12 :  604676,  58653572,  73770472

H13 :  791331,  76759107,  96542382

H14 :  968215,  93916855, 118122230

H15 :  928312,  90046264, 113254064

H16 : 1120165, 108656005, 136660130

H17 : 1477141, 143282677, 180211202

H18 : 1583755, 153624235, 193218110

H19 : 1720224, 166861728, 209867328

H20 : 2060071, 199826887, 251328662

H21 : 2356213, 228552661, 287457986

H22 : 2492521, 241774537, 304087562

H23 : 2546487, 247009239, 310671414

 

The hash to find is TARGET1=0x119A792 = 18458514

take a look above and see w

here you can find TARGET1!!,

 

TARGET1 may be between min H5 and max H5 or between min H6 and max H6 and that's all.

 

WHAT DOES THIS MEAN?

********************

it means that (with our hypothesis) TARGET1 is a 5 or 6 letters word !!

 

you can do the same thing for TARGET2 = 0x0D5FCE3C = 224382524, you will see that it's a very long pass phrase!!

 

and now all you have to do is solving the following equations:

 

H5 = 4712*p[0] + 21560*p[1] + 12078*p[3] + 55552*p[4] + 66490*p[5] = 18458514

 

and

 

H6 = 13640*p[0] + 23912*p[1] + 12276*p[2] + 48832*p[3] + 62220*p[4] * 19404*p[5] = 18458514

 

in order to find the solution!

 

Implement the algorithm described in the paper mentionned above and obtain the right values for p[j]!!

This is an elegant method...i'm waiting for your source code ;-)

 

For the guys (like me) who stopped maths to do computer programming when they were 8 we are going on with our brutal idea!!

we can know write a brute forcer that will try all the words from 'aaaaa' to 'zzzzzz',

if the length of the word we are trying is 5 we compute H5 else if it is 6 we compute H6.

 

LET'S DO IT NOW!

****************

<------------------------------- Listing 2: C implementation of the crap above! ------------------->

 

//brute force attack upon gregory braun's hash function

//trying to find a collision!

//hard job ;-) done by J!M

 

#include <stdio.h>

#include <conio.h>

#include <string.h>

#include <stdlib.h>

#include <math.h>

 

unsigned char table1[54] = {

      0x23,0x73,0x65,0x72,0x42,0x26,0x6E,0x7A,0x7C,0x6D,

      0x66,0x4D,0x31,0x2F,0x35,0x28,0x21,0x73,0x64,0x24,

      0x4D,0x71,0x2E,0x7B,0x73,0x5D,0x2B,0x73,0x46,0x6A,

      0x74,0x4B,0x70,0x7A,0x53,0x64,0x74,0x7A,0x6F,0x58,

      0x71,0x6D,0x62,0x5E,0x41,0x6C,0x40,0x64,0x76,0x3A,

      0x73,0x3F,0x78,0x2F};

 

unsigned char table2[54] = {

      0x7C,0x62,0x21,0x70,0x7A,0x2A,0x6C,0x73,0x3B,0x72,

      0x6E,0x7C,0x6C,0x66,0x24,0x76,0x69,0x5E,0x41,0x78,

      0x70,0x65,0x29,0x72,0x78,0x35,0x61,0x69,0x63,0x26,

      0x39,0x2F,0x32,0x6D,0x35,0x6C,0x73,0x69,0x34,0x40,

      0x30,0

x64,0x6D,0x5A,0x77,0x39,0x34,0x63,0x6D,0x71,

      0x70,0x66,0x68,0x77};

 

int main() {

     

      unsigned int i,j,k,r,l,line_count,target,accu,coeff[25][25];

      double nb_passwords;

      char password[6];

 

      //compute equations' coefficients for H5 and H6

      for (i=5; i<7; i++) {

            for (j=0; j<i; j++) {

                  coeff[i-1][j] = table2[j]*table1[i+j]*(j+1);

            }

      }

 

      //define the target

      target = 0x0119A792;

      line_count = 0;

     

      //BRUTE FORCE ATTACK, test all combinations of words of 5 or 6 chars, about 320 000 000 words!!

      for (i=5; i<7; i++) {

            nb_passwords = pow(26,i);

            l = 0;

            for (j=0; j<i; j++) password[j] = 'a';

            while ( l < nb_passwords ) {

                  k = l;

                  j = 0;

                  do {

                        r = k % 26;

                        k = floor(k/26);

                        j++;

                        password[i-j] = 0x61 + r;    

                  } while ( k > 0 );

                  l++;

 

                  line_count++;

                  if (!(line_count % 10000)) {

                        printf("%u passwords processed\r",line_count);

                  }

     

                  accu = 0;

                  for (j=0; j<i; j++) accu += coeff[i-1][j] * password[j];

                  if ( accu == target ) {

                        pr

intf("\nTarget FOUND! with password: %s\n",password);

                  }

            }

      }

      printf("\nHalt on fire!! press any key to quit\n");

      getch();

      return 0;

}

<--------------------------------------------------------------------------------------------------->

 

After a few minutes of intensive work the little program gave me 4 answers:

 

'dowtt', 'vrgpx', 'zippy', 'zulqu'

 

I think the magic value is 'zippy' but the three other words work well !!

Because H5('zippy') = H5('dowtt') = ... = 0x119A792 !!! we found what cryptographers call 'COLLISION':

two or more things that gave the same hash value.

One quality of a well designed hash function is to be collisions resistant.

There are two kinds of resistance: strong collision avoidance and weak collision avoidance...i will not explain here

the differences between these properties..may be in another tutorial?

 

and now all is done!!

Enter one of these four words into the registration name and press enter: YOU ARE REGISTERED! no need of a serial.

Yes, you can

 say Thanks!!!

 

 

THAT'S ALL FOLKS!

*****************

Question? comments? you have found another way? the second password? mail to me:

 

zejim@netcourrier.com

 

See ya

 

 

ONE LAST WORD...

****************

if you have to use a hash function in your programs keep the following things in mind:

-don't use your own algorithm!! use SHA, MD4, MD5, TIGER... it exists a lot of well designed hash functions.

-if you hash something, hash something complicated and/or very long to avoid dictionnary and brute force attacks.

---------------------------------------------------------------------------------------------------------------

PS: The dictionnary attack gave me 'zippy' in a few seconds ...

 

PS PS: If you plan to use crypto 3.6 to protect your valuable datas, i suggest you to read casimir's papers about

gregrory braun's cryptographic implementations it should freeze you!...