Impossible is not french
Applying a scoring method to guess the key
javascri
Javascript
16 june 99
by Laurent
Courtesy of Fravia's page of reverse engineering
fra_00xx
990616
Laurent
1100
NA
PC
Amazing work by Laurent, a Javascript Lizard that has turned into a javascript wizard :-)
Read, meditate, think. Humans can reach the stars, and reverse javascript.
Enjoy!
There is a crack, a crack in everything That's how the light gets in
Rating
( )Beginner ( )Intermediate ( )Advanced ( )Expert


Impossible is not french
Applying a scoring method to guess the key
Written by Laurent


Introduction

In this essay I'll try to explain how I did to guess a working key for the

impossible entrance. Note that I said a working key, not the correct one. This is

because, even if that key works fine, it leads to a 404 page. So maybe it's not

the correct one.


Although I really think it's the correct one :)

Tools required
A C compiler

Target's URL/FTP
im_poss1.htm

Program History
Your_target's_history (if any)

Essay
First of all, i have to admit that at first sight I really thought it was really an impossible entrance.
It's only when I saw a post of sNw and DonQuijote saying that they were working hard on it that I thought "Well, Impossible is not french, so why not try it too".

The reason why I thought it was impossible is that from the cipher text you have, you can obtain *whatever* plaintext you want. Of course, the key may be quite long, but every plaintext is possible. Here is an example : Use the following key and you'll get a nice plain text :
--->x i8#:mje^FV5 b-CgX@S.e7Sdxix<---

Of course this lead to very long and weird key, but there was no 'obvious' way to guess key lenght or meaning, so i thought that it would be impossible to guess the correct one.

So, when I read sNw and DonQuijote talking about trying to search for a key which could give meaningfull words like 'location', 'window', 'navigate' and so on, I wrote a little program which allowed me to extract a key given a know plaintext and a cipher.
I run this program so it would give me every key for plaintext word to find at every possible place in the cipher. As you see it's quite easy but unfortunately it doesn't helped at all.
Actually, I wasn't expecting much result from this approach cause it would not have been an impossible entrance at all. Imagine that the word 'location' would have been in the plain text, that would have give us 8 letters of the key at once ...Too easy.
Before going anyfurther I'd like to say that I did not tried the word 'navigate' cause I think it's not working with Netscape products, so it would have restricted access to micro$oft users only, what would have been a real shame :)

Anyway, I then wondered how they could have hidden those 'necessary' words ? Was there any other way they could take you to another page without using something like 'location' ?
Then I thought that maybe 'location' was actually made up of a concatenation of little string like : "loc"+"ati"+"on" .... But then how could they pass that to eval ? eval would only return the concatenated string, but not executing it.... Then it poped in my mind ... Of course .. they use another eval in their cypher.
it's something like eval(fin) ... where fin is a string = "'eval('+'loc'+'ation'+'='+xxx.htm'+')'". So the first eval (the cyphered one) will return a full string which will be processed by the second eval(fin). That sound quite smart :)

So I run my program to extract keys for 'eval'. I used a max key length of 12 (thanks DonQuijote:). Well, as eval is not very long (4 char) I got lot of meaningless garbage :( But I was quite sure I was on the good way .... Unfortunately,I had to browse through 1071 (119*9) possible 'plaintext' to find the good one :(
Well, I sit down once again and thought that the good plain text should be full of character like ",+,lo,loc,at,io,ht, ml and so on ...
So I modified my program to 'score' each plaintext depending on the number of occurence of those character or mini-strings.

Bingo .... I got a plaintext with a score of 11 for a key length of 4 and 6 and a score of 8 for a key length of 12 :)
MoreOver the 12 char length key looks something like : _____rCrA___ ... Upper and lower case toggling, CrA like 'Crack' :)
Here is the plain text I obtained and below is the original cipher text followed by the key I applied :


     ;< /        eval        '+"o        "ti"         + "        +'ef        "'nE        AcK.        'ml'        < );

6gy.=gvlq:z91=uowwYsM+w86gyrQnzpPfI!7jFrBpWAy'H86jTJAlzly I!8lMNCoywG=H7~myrBpyF5aH~dSWYWSF2rkG!#HCoBnPDw@I~#fBtCkwep'E86g

_____rCrA________rCrA________rCrA________rCrA________rCrA________rCrA________rCrA________rCrA________rCrA________rCrA_____

I replaced the 'carriage return' character with the 'less than' (<) to improve readability.

Note that I wrote my program so that the _ char is used as 'unknow' key char. So it does not decipher for this character.

We are on the good way ... We have 'o' and 'ti' from 'location 'ef'from maybe 'href' and 'ml' from 'html'.

Now it's quite easy. Just try to guess some cipher-plain text pair and fill the gaps in the key.
I used the following :
1. the cipher 'f' should give a plain 'c' (after '+"o).

     ;< /*       eval        '+"oc       "ti"<        + ".       +'ef'       "'nE"       AcK.h       'ml'+       < );<    

_____rCrAc_______rCrAc_______rCrAc_______rCrAc_______rCrAc_______rCrAc_______rCrAc_______rCrAc_______rCrAc_______rCrAc___

2. the cipher 'B' should give a plain '+' (before "ti").

    0;< /*       eval       l'+"oc      +"ti"<      ' + ".      "+'ef'      +"'nE"      rAcK.h      +'ml'+      "< );<    

____ErCrAc______ErCrAc______ErCrAc______ErCrAc______ErCrAc______ErCrAc______ErCrAc______ErCrAc______ErCrAc______ErCrAc___

3. the cipher 'I' should give a 'a' or a '"' (after l'+"oc). It gives either H or K ... K is great ... it gives CrAcK

Well, you guess now how it work, so i won't bother typing all that.

Finally you get the right key ... %nEvErCrAcK%

Well, here below you'll find the program i used .. I tried to comment it as much as possible, but I'm quite lazy for that, sorry :(

#include <math.h>

#include <stdio.h>

#include <conio.h>

#include <stdlib.h>

#include <string.h>



//this is the original ciphertext

char* b="6gy.=gvlq:z91=uowwYsM+w86gyrQnzpPfI!7jFrBpWAy'H86jTJAlzly "+

        "I!8lMNCoywG=H7~myrBpyF5aH~dSWYWSF2rkG!#HCoBnPDw@I~#fBtCkwep'E86g";

//this is the original 'alphabet

char* a="@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234"+

        "56789~!#$%^&*():;/.\t\r -'+\"=";





//this function return the indexOf the char 'c' in the 'alphabet'

int cton(char c)

{

 int i;

 for (i=0; i<strlen(a); i++) {if (a[i] == c) return i;}

 printf("error\n");

 return 0;

}



//This function simply decipher the OrigString with the 'key' .

//The result is returned in OrigString

void decode(char* OrigString, char* key)

{

 int i;

 int pos = 0;

 char first, second;



  for (i=0;i < strlen(OrigString);i++)

  {

   first = OrigString[i];

   seconfiltered= key[pos];

   if (seconfiltered== '_') OrigString[i] = ' ';

    else OrigString[i]=a[(cton(first)-cton(second)+strlen(a))%strlen(a)];

   pos = (pos+1)%strlen(key);

  }

}



//This function return a valid key from a pair of cipher and plaintext.

//both cipher and plain text must have the same length

void getkey(char* cipher, char* plain, char* key)

{

 int i;



 for (i=0; i<trlen(cipher); i++)

 {key[i] = a[(cton(cipher[i])-cton(plain[i])+strlen(a))%strlen(a)];}

 key[i] = 0;

}



//This function was added when I wanted to 'score' each obtained plaintext.

//It return the number of time the plaintext 'st' contain the string in the tips array.

int check(char* st)

{

 int i,j;

 int score = 0;



 char* tips[11] = {"rep","lac","re","loc","ati","ht","lo","ca","oc","\"","+",};



 for (i=0; i<strlen(st); i++)

 {

  for (j=0; j<1; j++)

  {

   if (strncmp(&st[i],tips[j], strlen(tips[j])) == 0) score++;

  }

 }

 return score;

}



void main(void)

{

 char temp[128];

 char key[128];

 char tempkey[128];



 int i;



 //This is the plain text we want to obtain

 char* plaintofind = "eval";      



 FILE *outkey,*outplain,*outfull;

 // outkey will contain the key,

 // outplain the plain text

 // and full both the keys and the plain text



 outkey = fopen("key.txt", "wt");

 outplain = fopen("plain.txt", "wt");

 outfull = fopen("full.txt", "wt");



/*   // This was added when I already found the start of the key.

     //It allow me to get a key char from a cipher and a plain char

//	getkey("~~","''",key);

//	printf("***%s***\n",key);

				//And then to get the result of the new key.

	 strcpy(temp, b);

	 decode(temp, "____ErCrAc__");

	 printf("%s\n%s\n",temp,b);

	 fprintf(outfull,"%s\n%s\n",temp,b);

*/





//Here start the original program...



 // It loops from the first to the last char or the cipher

 for (i=0; i<strlen(b); i++)  

 {

  //Get a cipher of the same length of the plaintext and starting at the position i.

  strncpy(temp, &b[i], strlen(plaintofind)); 

  temp[strlen(plaintofind)] = 0;



  //Check if we didn't reach out of the cipher

  if (strlen(temp) == strlen(plaintofind)) 

  {

   getkey(temp, plaintofind, key);    //Get a valid key

   printf("%s : \n",key);

   fprintf(outkey, "%s : \n", key);

   fprintf(outfull, "%s : \n", key);   //print it to files

   int keylen;



   //Then decipher the while cipher with that key padded to differents lengths

   for (keylen=strlen(plaintofind); keylen< 13; keylen++)

   {

    while (strlen(key)<keylen) strcat(key, "_");  //pad with _

    strcpy(tempkey, key);

    strcat(tempkey, key);

    strcat(tempkey, key);



    //realign the key so that it start well

    strcpy(temp, &tempkey[keylen-(i%keylen)]);        

    temp[keylen]=0;

    strcpy(tempkey, temp);       //tempkey will be applied to the whole cipher



    printf("len : %d, %s : \n", keylen, tempkey);

    fprintf(outkey,"len : %d, %s : \n", keylen, tempkey);

    fprintf(outfull,"len : %d, %s : \n", keylen, tempkey);



    strcpy(temp, b);

    decode(temp, tempkey);                         //decipher



    //This was added for the scoring : write score

    printf("%02d  ", check(temp));                    

    fprintf(outplain,"%02d  ", check(temp));          

    fprintf(outfull,"%02d  ", check(temp));           



    printf("%s\n", temp);              //write the plaintext we obtained

    fprintf(outplain,"%s\n", temp);

    fprintf(outfull,"%s\n", temp);

   }

   fprintf(outfull, "---\n");          //end mark

  }

 }

 fclose(outkey);

 fclose(outplain);

 fclose(outfull);



 int ch = getch();

}



Final Notes

To conclude, once you got the trick they used it's not so impossible finally :)


Just a last thing ... I'm not french ... Just french speaking !


Ob Duh
I wont even bother explaining you that you should BUY this target program if you intend to use it for a longer period than the allowed one. Should you want to STEAL this software instead, you don't need to crack its protection scheme at all: you'll find it on most Warez sites, complete and already regged, farewell, don't come back.

You are deep inside fravia's page of reverse engineering, choose your way out:




redhomepage redlinks redsearch engines red+ORC redstudents' essays redacademy database
redtools redcocktails redbots wars redanonimity academy redantismut CGI-scripts
redcounter measures redmail_fravia+
redIs reverse engineering legal?