/* * although not strictly deobfuscated it is commented to try and explain it more * * Please note that I have tried to keep this consistent with the 'final * product' but I had to make fixes and so some of this might be out of date. * Still I am trying to redo it all; but some comments might not be strictly * correct. In which case I hope you can then fully appreciate just how twisted * this code is (and you probably will anyway)! * * Also it is true that some of the variables in the code (which are in the * submission itself, I believe but perhaps not) are not used. This was a * mistake but it's not worth the effort to try and find them all, especially as * it can also cause confusion to people. Trying to parse the code once let * alone several times (which I did) was not something I wanted to repeat again. * * And on that note: there indeed might be things wrongly stated. I tried but * failed to completely understand what I wrote years back. I have no idea how I * managed some of this and I don't know what I did in every case so any * incorrect statements are simply a sign of the obfuscation - a good thing! */ #include #include #include #include #ifndef DICT #define DICT "dict" #endif /* * English -> Navajo. * * I am sorry but I can't even begin to fathom TRYING to do this again for the * alt code (X=1), especially as a lot of it is the same but with some subtle * differences. */ #define X 0 /* * the struct a is the holder of state but the state is, as will be seen soon, * mostly anonymous. Even the function pointers array has a different order per * function call! The only time (I think) that there is some form of consistency * is the *k and *c of the struct a which is the linked list of words for either * deciphering (alt version with -DX=1) or enciphering (with -DX=0) */ struct a { /* * some of these are consistent if they're only used in a single function. I * believe this applies in particular to: * * a - for Z(), which parses main() args and acts on them - it is that * part of main()'s body instead of in main(), this so I could make it * harder to follow with anonymous and inconsistent ordering and * variables. * N - first field in dictionary file. * S - second field in dictionary file. * A - temporary buffer when reading in dictionary file (which S and N use). * * Like I said the order of v changes depending on the function. * * However as for S and N it's not so simple because these char *'s are not * directly strdup()d! Instead the function that does this, called by F() * but not by those names (I will explain this later) set the 's' (below) in * an anonymous structure to either S or N in the call. The function being * called in all cases (even though it does not look like it) is the same in * every case even though it doesn't look like it; that function is w(). */ char *w, *c, *s, *x, *t, *u, **h, *S, *N, *A,*(*v[9])(struct a *), *y; struct a *e, *a, *z, *k, *j; int l; } *f, *c; /* ^ the linked list pointers - f is the list and c each node as the list is * created. The ->e is the next node which is why this is consistent, at least * in f. */ /* * this is the alphabet of the language and it's translated for exact matches in * the alt version especially (it might be used in the encipher - regular - * version but I'm no longer sure of this). * * As can be seen the first element, element 0, is the letter, and the second * element, element 1, is the translation. The word for C for instance is MOASI * and it translates to 'cat'. When prog.alt encounters this it will report * 'cat'. If however prog encounters it it will translate the letters as it's * not in the dictionary. As well if prog.alt encounters something not in the * dictionary, say IOCCC, it will spell out the letters. * * If one does something like: * * ./prog.alt $(./prog ioccc) * * then it should print out 'ioccc' (w/o quotes of course). */ char *B[][2] = { { "A", "WOL-LA-CHEE" } , { "B", "SHUSH" } , { "C", "MOASI" } , { "D", "CHINDI" } , { "E", "DZEH" } , { "F", "CHUO" } , { "G", "JEHA" } , { "H", "TSE-GAH" } , { "I", "YEH-HES" } , { "J", "AH-YA-TSINNE" } , { "K", "BA-AH-NE-DI-TININ" } , { "L", "NASH-DOIE-TSO" } , { "M", "BE-TAS-TNI" } , { "N", "TSAH" } , { "O", "A-KHA" } , { "P", "CLA-GI-AIH" } , { "Q", "CA-YEILTH" } , { "R", "DAH-NES-TSA" } , { "S", "KLESH" } , { "T", "D-AH" } , { "U", "NO-DA-IH" } , { "V", "A-KEH-DI-GLINI" } , { "W", "GLOE-IH" } , { "X", "AL-NA-AS-DZOH" } , { "Y", "TSAH-AS-ZIH" } , { "Z", "BESH-DO-TLIZ" } , } , *Y(struct a *) ; int z, J, C, k, H, D, s, L; size_t n, o; FILE *g; /* * these variables would not fit in the structs as they are needed in multiple * functions. Besides the next node of the linked list we can use the other * members of the struct anonymously and differently depending on the function * (to make it extremely hard to keep track of what is what). * * Now it would be possible to have these in as different variables but that * would go well beyond the size limit of rule 2! * * I will tell what these are as we encounter them. */ char *I(struct a *a) { /* * okay this is truly dreadful. * * What z is set to is actually 0. That's it. * * Remember that a->z is actually a->j which is f. Well okay you can't know * that yet but you will. */ for (a->a = a->z, z = 0**"1"; a->a; a->a = a->a->e) { /* * the function called (a->v[2] (and remember a is anonymous in this * function, created by the calling function at time of calling it) is * Y(). Y() also takes a struct a * but we create it as we call the * function itself, just like what happened when we were called. We set * .w to a->a->w (a->a is the current node in the linked list) and .c to * a->x. But what are these? * * Well a->w is assigned (will talk about this later) the first field OR * second field of the dictionary depending on if we are deciphering or * enciphering. Of course this file is enciphering but that only adds to * confusion! As I see it right now, if deciphering (X==1) (which again * does not happen here) then it is the second field (S in that struct); * else it is the first field (N in that struct). * * And what was 'x'? I am sorry but I can't figure that out but I can * say that Y() checks if two strings are equal but ignoring !isalpha(). * What this implies is it is either the first or second string as Y() * acts on exact matches of letters as noted earlier. * * Okay doing an fprintf() suggests that it is the input. For instance * if I were to do ./prog.alt shush the a->x is shush itself. */ if (a->v[2](&(struct a){ .w=a->a->w, .c=a->x} )) { /* * just to make sure we print out the stuff before in case there is * a non-alpha character (or characters) */ while (!isalpha(*a->x) && *(a->x)) { L=putchar(*a->x); ++a->x; } /* * okay this is also really nasty. Remember that z starts out at 0 * and a->c is (I think!) the first field if X==1 (which is false) * and the second field if X==0 (enciphering mode, true). Well okay * so this part is not the nasty part; it's the body of the loop. */ while ((z++)[a->a->c]) /* * this is truly awful. First of all remember that z starts out * at 0 here and we want to set 's' to something terrible. But * what in the world is '-*"1"-*"1"- -97? It is -1. But why do I * want s to be -1? Well I don't. Remember that I'm adding it to * s which starts out at 0. Thus the first pass this will be * indeed -1, second pass 0 etc. But why start out at -1 when it * seems like we're indexing into a->c (a char *)? This is * extremely nasty too. * * Let us break this down a bit more. If s is -1 the !s (will * end up being?) false. That means the !isupper(a->x[0**"z"]) * will not be called the first time (or perhaps it will, I * don't know now). Okay but we have to back up a bit. What is * 0**"z"? That is 0, as you'd expect. So what is a->x[1]? This * is also very ugly. I believe (but I am no longer sure!) that * the calling code is: * * (((*a->h[--a->l]=='e'-':')&&(*a->v)(&(struct a){ .v[0]=I, * .s=((a->l)[a->h])+1} ) &&++a->l)||(a->v[1](&(struct a){ * .v[2]=Y,.x=((a->l)[a->h])} ),++a->l)); if (g) puts(""); } * * Okay actually I'm sorry. I have absolutely no idea what this * is. But the numbers at least can be explained. Also we can * break the code down more though, just not determine all the * values. If !s and isupper(a->x[1]) we will index a->a->c[s]. * But when it's not we will call tolower(a->a->c[s]). Now you * might ask how in the world a->a->c[s] is legal on the first * pass. I'm sorry but once again I have no clue I just know it * does not evaluate to invalid indexing. Even more baffling is * if the index starts out at 0 (i.e. - -98 instead of - - 97), * the code does not work! Of course it might not be baffling at * all but seems that way after trying to parse this nasty nasty * code. */ s=z+-*"1"-*"1"- -97,L=putchar(!s&&isupper(a->x[0**"z"])?a->a->c[s]:tolower(a->a->c[s])); goto n; } } /* * if we get here it means that the word is not in the dictionary. And of * course this is also extremely nasty, the expressions. The 2/ *"z" * evaluates to 0 and the 1+0**"1" evaluates to 1. * * Okay and the number[pointer] indexing is used. As noted above I believe * K->x is the actual input. I'll try and parse the loop but no guarantees I * get everything! Much of this was written years ago. */ for (z = 2/ *"z", s=1+0**"1"; z[a->x]; ++z) { /* * okay the first part is simple enough. For each !isalpha() char in * a->x we simply print the char via putchar(). Again I'm unclear what * a->x is however. */ if (!isalpha(z[a->x])) L=putchar(z[a->x]); else { /* * so C is if the current char of the current input is lower case. I * am not sure if we actually need to save this or not but it's * quite possible we do. It might just be to save bytes (or it might * not save bytes). */ C = islower(z[a->x]); /* * This is even nastier than before I guess. * * The first one is easy: J is set to 0 and while J < 26 and ... * hold on, what are we checking against now? * * Well remember that B is the letter <-> Navajo word for that * letter array. So B[J][0] would be the letter itself and B[J][1] * will be the word itself. But now we have the other horrible * expressions! Remember that if X (it's always 0 in this file) is * non-zero it's deciphering and if it's 0 (always 0 here) it's * enciphering. But what is: * * 1/ *"1"+s/ * *"1"+1/ *"1"+s/ *"1"+1+(s-s)**"1"+(s*(s-s))**"1" * * ? Well first of all let's clarify that this is actually: * * 1/ *"1"+s/ *"1"+1/ *"1"+s/ *"1"+1+(s-s)**"1"+(s*(s-s))**"1" * * Observe too how a space removed in several places will turn it * into a comment! * * I can try and parse some of this but I'm not really sure of all * of it. For instance, how is (s*(s-s)) parsed? It would appear that * it's s * 0 and it might very well be. Assuming that s is 0 (for * example) it is 1; assuming it is 1 it is ... 1? So it seems. And * assuming it is 2 is .... 1 again? So it seems! So how in the * world does this work? Well remember what we're trying to get: * either the first element or the second, and in this place we * always need 1. Let's evaluate the other part (I'm sure you can * figure it out though after this first one): 0! Okay but there's * something really sneaky here (and above): ask yourself if 's' is * actually incremented. Got your answer? Okay good! In fact if you * were to update it you will get bad answers! For instance what * happens if it's 2? I got 5764801. And then what if it's 0? * -5764801. */ for (J = *"1"-*"1"; J < 26 && B[J][X?1/ *"1"+s/ *"1"+1/ *"1"+s/ *"1"+1+(s-s)**"1"+(s*(s-s))**"1":((((s-1)**"1")**"1")**"1")**"1"]; ++J) { /* * oh dear did I do it again? Yup. I did. But in this case you * can probably figure it out. Even so I'll evaluate these for * you. Yes: 0+*"1"-*"1" is 0. */ if (*B[J][0+*"1"-*"1"] == toupper(z[a->x])) { /* * Not again! Okay to help out let's remember s is 1. So s * * 2 is 2. It's the other stuff that's a nightmare. * * (s*2)**"9"-171+*"9" == 0 * * And you probably want to kill me but what is: * * *"1"-49 ? * * It is 0. And since you killed me you probably now want to * chop me up into tiny bits but before you do that I guess * you want to know what s/ *"1"+s/ *"1"+1/ *"1"+(s*s*s) is? * That evaluates to 1. */ for (k = (s*2)**"9"-171+*"9"; H=B[J][X?*"1"-49:s/ *"1"+s/ *"1"+1/ *"1"+(s*s*s)][k]; ++k) putchar(C?tolower(H):toupper(H)); /* * this is putchar(' ') */ L=putchar(('\0'+'!'-1)); break; } } } } /* * we jumped here if a word was in the dictionary and translated, as * explained earlier but we also get here if we don't (obviously) */ n: /* * if the last char we pushed on the stream is a space, don't add a space */ if (!isspace(L)) putchar(' '); return a->s; } /* * Z() used to be the parsing of args in main() and it's also truly dreadful, I * know. Unfortunately I am not sure if I can explain it all but I will try. */ char *Z(struct a *a) { /* * it would appear that a->l was argc of main() (c) and a->h is the argv * (a) so the condition of the loop is going through all the args. However * before we can continue we need to see how this function was called: * * Z(&(struct a){ .v = { t, I } ,.k=0, .l=c, .h=a, .j=f} ); * * This means that a->v[0] == t() and a->v[1] == I and a (our struct)'s l is * c (argc in main()) and our a->l is argv in main(). Additionally a->j is * the linked list of words. */ while (a->h[a->l++]) /* * I() :-) no longer can parse this completely (as in I don't know all * of what it does) but I'll still try breaking it down a bit. I make no * promises however. I will break the line up to help out, though it * might not do that much good. */ /* * first notice how where the loop condition (postfix) increments argc * (a->l) the body of the loop immediately decrements (prefix decrement) * and compares the first char of the current arg to - what? The * expression 'e'-':' evaluates to '+'. This is checking for file as * input. */ (((*a->h[--a->l]=='e'-':')&& /* * Okay remember what I said above about x->v[0] being t() ? That means * that this is calling t(). */ (*a->v) /* * ...and here we create the anonymous struct * for t(). As you can see * the first function pointer in the v[] array is I(). Observe how in * _this_ function v[0] is a different function! In this function v->[0] * is t() but in this next function (t() itself!) it will be I()! But how * do we construct it? Well... * * The &(struct a) is important because we can't do: * * (struct a *) * * because it is an error: * * prog.c:67:41: error: initialization of non-aggregate type 'struct a *' * with a designated initializer list. * * (Okay the line numbers are different but you get the idea.) * But since we need a pointer we can use & to get the address of the * anonymous struct. */ (&(struct a) /* * Now the fun part! The object we create is in the {}s (of course). Each * field, even pointers use '.' (which as shown above is required as we * can't do { ->s=... } as it's also illegal and this is why we make it a * struct that's not a pointer and take its address to get past that * problem). * * Here we are saying that in the anonymous struct we're passing to t() * the v[0] is I() and the s (a char *) is - what? Well this is awful. Do * you remember that a->l is argc and a->h is argv from main()? So * * ((a->l)[a->h]) * * is argv[argc]. Now the usual C programmer would point out that that is * NULL. But something *extremely* nasty was done before we called this * function. I will explain it (or rather try to) in main() but it looks * like this: * * F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } )); * * Remember that c in main() (or our a->l) is argc. So this horrible call * resets c to some value, in particular 1 though that line does a lot * more. * * So what this part does is, again, set OUR v[0] to I() which we are now * calling, remember, and set OUR s (a char *) that is a->s to beyond * (argv[argc])+1 (starting out with argc == 1). This also sets .j to * a->k which is actually - what? This is sneaky. In main() when calling * Z() a->j is set to f (the linked list) but here we're setting a->j (in * the function call) to a->k. But in main() in calling Z() a->k is set * to NULL! Further down though we will do .z=a->j so this might (or * might not) be called a red herring. * * But of course we're not done! */ { .v[0]=I, .j=a->k, .s=((a->l)[a->h])+1} ) /* * I'm sure that some people are screaming by now, if they even got this * far, but here we are doing something sneaky (imagine that) too. * * Remember how the loop condition incremented argc but the loop body * immediately decremented it (since we needed to check the first char * of the first arg, not the next)? Well the problem is now that we have * checked that we nee to get x-> (argc) incremented again, but prefix. */ &&++a->l)|| /* * But of course if these (what are these? Please go back up and check, I * too am getting tired of trying to parse all this and I have a lot more * to do!) did not succeed we still have more nastiness. * * a->v[1] is I() so now main() is (or rather we, Z(), are on behalf of * main()) calling t with - yup, ANOTHER anonymous struct a *! */ (a->v[1](&(struct a) /* * The good news at least is you know how the struct is constructed but * what are we doing here and why? * * Well here we are saying that in the call to I() that v[2] is Y() (not * again) and x (a char *, not like x here which is a struct a *) is set * to the current argv[argc]. * */ { .v[2]=Y,.x=((a->l)[a->h]),.z=a->j} /* * this is the end of the function call but we're not actually done just * yet. * * Observe how we are prefix incrementing a->l again (argc in main())! */ ),++a->l)); /* * Okay but you might ask yourself: how come we're using the comma * operator here? Well because at this point although we do need to * call I() we also need to increment argc (a->l) yet again! * * But...why? After all the body of the loop does this! Not quite. It * does do this but that was on the left hand side (lhs) of the body * of the loop and the beginning of the body of the loop decremented * it! So in order to get argc back to the next one we have to * increment it as a side effect! */ /* * we only do this because we need to return a char *; a simple return * 0 would also work and so would a return NULL. */ return ""; } /* * this function is simpler though there still are some potentially confusing * things going on here. Yes this looks kind of like a rot13 implementation but * the dictionary file actually has Z -> A, Y -> B, X -> C etc. But what was r * formed of? Actually this is extremely sneaky. */ char *w(struct a *a) { /* * Okay but you might notice I did something nasty again. Okay I did * multiple nasty things! You probably can figure these out at least though. * Anyway, 1/ *"s" is 0 and 'k'-'*' evaluates, as you might have guessed, to * 'A'. * * That means start out at 0, go through a->s - well you get the idea. But * what is a->s? Well that is the dictionary file of course but that'll be * discussed in the respective function. */ for (D = 1/ *"s"; a && a->s && D[a->s] && (a->s[D]) && (a->s[D] = isupper(a->s[D])?("ZYXWVUTSRQPONMLKJIHGFEDCBA" )[(a->s[D] - ('k'-'*'))]:D[a->s]); ++D) ; /* * at one point it was possible for a to be NULL so we checked here. It * shouldn't be needed now though. */ return a?a->s:""; } /* * this is kind of like strcasecmp() except that it ignores !isalpha(). There is * only one thing that might not be immediately obvious so I'll only comment on * that. Well okay as you'll see a->w is the first string and a->c is the * second. But besides that it's pretty easy. */ char *Y(struct a *a) { if (*a->w && *a->c && a->w[1] && a->c[1]) while (*a->w && *a->c) { while (!isalpha(*a->w) && *a->w++); while (!isalpha(*a->c) && *a->c++); if (!*a->c || !*a->w || tolower(*a->w) != tolower(*a->c)) break; ++a->w; ++a->c; } /* * remember that we need to return a char * so what this does is it * evaluates to either a 'true' value (non NULL string) or a NULL pointer. * This can be checked as if an int but matching the requirement that it * returns a char * (for the function pointer array). */ return !*a->w&&!*a->c?"":0; } /* * This function reads in the dictionary file as the first line might suggest. */ char *F(struct a *a) { g = fopen(DICT, "r"); if (g) { /* * We use getline(3) even though there is the bug I mentioned in the * remarks file because we can have it dynamically allocate memory. It * stores the newline but so does fgets() and we don't really care about * it. In fact we do not want to remove the newline! */ while (getline(&a->A, &n, g) != -1) /* * So we were called like this: * * F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } )); * * I am not going to explain the first part until main() but the * second part, which can only happen by the comma operator (like in * other places) and which we use as we need the other thing to be * done first, it sets up our struct a *a's .l to 0, v[0] to &w and * v[1] to &w. Why both? To mislead of course! */ /* * this part is easy but note how we use a->A and a->S as the first * and second column. They are not really needed except to have them * also in the struct (and even if they were not NULL we assign them * first). */ if ((a->N = strtok(a->A, "\t")) && (a->S = strtok(0, "\t"))) { /* * Oh no! Not another bonkers calculation! Well fortunately you can * probably put together what it is but if not it evaluates to 1. * Basically we're allocating a struct a *. */ c = calloc(1**"0"-47, sizeof *c); /* * more fun with anonymous structs here as we populate the struct a * * we just created. As I might have said elsewhere if X is non-zero * (never true here) it means decipher and otherwise it means encipher. * means. But observe how c->w can be one or the other just like * c->c. That's because the X check is done in other places too. * * Now about these structs being created. For c->w it is a strdup()d * copy of the result of calling w() on either a->S or a->N. * Similarly we are doing the same thing (but opposite order) for * c->c. But hold on a moment you might think. Why then are we * assigning multiple values? Well actually we're not. This is just * the copy but both are always assigned to the w()'s struct a *'s s * (a char *). * * As for the function calls: * * a->l is 0 and a->e is NULL but even if it wasn't it would * evaluate to 1 and so a->v[a->l], a->v[a->e==0] (as 1 or 0) * and a->v[1] all point to w()! */ c->w = strdup(X?a->v[a->l](&(struct a){ .s=a->S} ):a->v[a->e==0](&(struct a){ .s=a->N} )); c->c = strdup(X?a->v[1](&(struct a){ .s=a->N} ):a->v[a->l](&(struct a){ .s=a->S} )); c->e = f; f = c; } free(a->A); a->A = 0; fclose(g); g = 0; } else puts("couldn't open dict"); return ""; } /* * fortunately t() is a bit easier - although you might remember the call to it * is not. */ char *t(struct a *a) { /* * this assigns o with 0 */ o = *""; g = fopen(a->s, "r"); a->A = 0; while (g && getline(&a->A, &o, g) != -1) { /* * the usual suspect: we're using a->S as a temporary value for strtok() * to extract the first field (space or tab delimited) */ a->S = strtok(a->A, " \t"); while (a->S) /* * strdup() is useful here */ if ((a->y=strdup(a->S))) { /* * if a token was found then we will call a->v[0] which is I don't * even know; I'm really tired doing this and I have more to parse * for you - sorry! Anyway in that function v[2] will be Y() and w * will be S (the token we extracted). */ (*a->v)(&(struct a){ .v[2]=Y, .x=a->y} ); /* * get next token for this line */ a->S = strtok(0, " \t"); free(a->y); a->y=0; /* * if the last char we pushed on the stream is a space * don't add a space */ if (L!='\n')putchar(' '); } } if(g) { clearerr(g); fclose(g); g = 0; free(a->A); a->A= 0; } return ""; } /* * Good news: we've reached the last function! * * Bad news: it's also dreadful, really dreadful! */ int main(int c, char **a) { /* * Do I have to try and parse this? Okay well I did explain in one function * (F() itself) the second half but I did not explain the first half so I'll * try here. * * Remember how I said (I think I said anyway) that argc is set to 1? Well * that is because: * * ((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u) * * evaluates to 113 and 113 & 9 is 1. The other parts are just a * distraction. * * Notice the double {} there (that's not the only place this occurs though * I think). */ F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } )); /* * This was the one that processes the args. It is not a hard call to deal * with (the function Z() itself is of course): call Z() with an anonymous * struct a * with v[0] == t(), v[1] == I(), l == c (argc), a == a * (argv) and k == 0 (NULL) and j == f (linked list of words) */ Z(&(struct a){ .v = { t, I } ,.k=0, .l=c, .h=a, .j=f} ); puts(""); /* * Now go have some good chocolate or some great pie! You deserve it! */ }