eSn-mIn’s Jandepora
oohh, an opensource crackme. this one was rather interesting. i spent the major part of the time commenting the source codes and trying out values just to trace program behavior.An open source crackme for Linux
the program’s protection algorithm can be divided into three steps. after a vector hash is created out of the user’s name:
a) the serial input is being checked for illegal characters, that is, any character that is not ‘a’, ‘b’ or ‘c’ (small letters).
b) the number of a,b and c characters are being tested against values corresponding to how many characters the serial must have.
c) check for the right order of a,b and c characters.
before moving further, please open a separate window for my commented jandepora crackme now.
the first two steps were easy to follow on the source code. the last step consisted of opening eight (8) child processes and some pipes to implement the order of characters. a correct serial/wrong serial condition is triggered by issuing SIGUSR1 and SIGUSR2 respectively. and only the last fork (fork 7) issued a wrong serial condition SIGUSR2. this line in particular:
launch(serial, &count, 8, 8, 8, SIGUSR2);
i compiled and ran the program under strace to keep track of pipes it uses for communication and then modified the launch() function so that it’ll print the fork id of the process who called it. i figured, as long as fork 7 won’t be called when t == _NUM_CHARS_, things will be ok. see commented jandepora crackme to understand the flow of the forks.
fork 0 - ‘c’
fork 1 - ‘a’
fork 2 - ‘b’
fork 3 - ‘c’
fork 5 - repeat characters.
this would translate to “every two letter c’s, there is at least one a and one b.”
now, the whole of step three will be an endless loop if it werent for _NUM_CHARS_ afterall. that arrangement provided a way for me to recycle characters again and create a circular loop between the forks too, at least until _NUM_CHARS_. i really didn’t care on which fork it will stop because afterall, they all issue SIGUSR1! perhaps there are other steps, but this one was the most obvious solution to take. in my example, i used the single letter ‘a’ as my name. and after the second check, i already constructed a serial that still has to be checked for correctness of order.
name: a
serial: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbcccccc
there were 43 ‘a’, 3 ‘b’ and 6 ‘c’
and constructing the second part of the serial, i had ‘cabccabccabc’ subtraced the number of ‘a’ characters used from the total number of ‘a’ (34-3 = 31) and the number of ‘b’ characters used from the total number of ‘b’ (3-3 = 0), i constructed the first part of the serial, i arrived at the string ‘aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacabccabccabc’
i tried it out and here’s what happened:
steph@heaven ~/git/reverse/jandepora $ ./crackme4 eSn-mIn's crackme #4 -------------------- [*] Input your user name: a [*] Input serial number: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacabccabccabc [*] Verifying serial number.. [!] Registered x)
success! it worked.. somehow. now i had to construct the keygen. (just had to put the logic i just discovered into working order)
/* jandepora opensource crackme
* keygenerator by niel
*
* i tested this on as many words as i could
* but it doesn't generate the correct keygen for all names.
* a name can also have more than one arrangement of a,b and c
* this is possible since the only thing that matters is that SIGUSR2 won't be
* raised when count = _NUM_CHARS_ (see fork 7 of jandepora crackme)
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define _NUM_CHARS_ 43
static void createvector(char *s, int *v)
{
int len;
unsigned int n;
n = 0;
len = strlen(s);
while (len > 0)
{
n = (n + s[len-1]) * 37;
len--;
}
v[1] = n % 17 + 1;
v[2] = n % 16 + 1;
v[0] = _NUM_CHARS_ - v[1] - v[2];
}
int main(int t, char **c)
{
char serial[58] = "";
int vector[3];
if (t != 2) {
printf("usage: %s name\n", *c);
goto quit;
}
createvector(c[1], vector);
#if 0
printf(">>> a: %d ", vector[0]);
printf("b: %d ", vector[1]);
printf("c: %d\n", vector[2]);
#endif
int a, b, i;
a = b = vector[2]/2;
vector[0] -= a;
vector[1] -= b;
for (i=0; i<vector [0]; i++)
strncat(serial, "a", 1);
for (i=0; i<vector[1]; i++)
strncat(serial, "b", 1);
for (i=0; i<vector[2]; i+=2)
strncat(serial, "cabc", 4);
serial[_NUM_CHARS_] = '\0';
printf("if serial doesn't work, try another name.\n");
printf("name : %s\n", c[1]);
printf("serial : %s\n", serial);
quit:
return 0;
}
i tried it out again with a random string and it still works!
steph@heaven ~/git/reverse/jandepora $ ./keygen gentoolinux if serial doesn't work, try another name. name : gentoolinux serial : aaaaaaaabbbbbbbbbbcabccabccabccabccabccabcc steph@heaven ~/git/reverse/jandepora $ ./crackme4 eSn-mIn's crackme #4 -------------------- [*] Input your user name: gentoolinux [*] Input serial number: aaaaaaaabbbbbbbbbbcabccabccabccabccabccabcc [*] Verifying serial number.. [!] Registered x)
it fails on some strings though, example.. i tried out ‘google’. at this point, i decided to look into other people’s solution and see which parts i got wrong. turns out, there are some words that don’t have any valid serial.
there are still two more crackmes left for the very easy level, but they’re not in english. i suppose it’s about time i tried my hands on the cracmes at next difficulty level. i hope i’ve learned enough to progress thru the challenges.
till next,
- niel
