IOCCC image by Matt Zucker

The International Obfuscated C Code Contest

obfuscation.html for 2020/ferguson2

Obfuscation

            int *z=(int[13]) { 0 } , *e, *g;

Then in main:

            e = z + 10;
            g = e + 1;

            for (j=-3; j < 0; ++j)
                e<:j:> = j+3;

Which I think is more confusing: when one is iterating an array you don’t expect to start out with index < 0 but to then compare that that index < 0 and increment until 0 along with setting the value of the array to j + 3 is more confusing still. There are at least two other ways that are much easier to read that could accomplish the same thing. It continues on:

            /* ... */
            e<:i-3:> = (j < 1 ? 1 : (j > 5 ? 5 : j))-1;
            void w(char *s, int k, int v)
            {
                    for(e<:2:> = 0; s<:*P:>; ++e<:2:>)
                    {
                            v = s<:e<:2:>:>;
                            if(v > 64 && v < 91)
                                s<:e<:2:>:> = (((v - 65 + k) % 26) + 65);
                    }
            }
            void Q(void)
            {
                    for(*g = 0; *g < 3; ++*g)
                    {
                            *Y<:16+e<:1:>:>=S<:e<:e<:1:>-3:>:>;
                            R<:e<:1:>:>=Y<:e<:-3+e<:1:>:>:>;
                            w(R[*g],*(e+e<:1:>-6)=q(Y<:8:>,*Y<:7:>),*g);
                    }
            }

First of all: why do I set e[2] to 0 and increment it for each pass in the loop, but then the condition for the loop is s[*P]?

Second notice the many references to e[1] (as e[1] and g). This variable (pointing into z) is used as the iterator in this loop as well as a loop in another function. Now why do I pass g to the function w()? To mislead. Originally it was more misleading in that I didn’t touch the parameter ‘v’ in the function and did a *g = v; at the end of the function. But even though I did not actually change the value I did not know if this would cause a problem with sequencing so I decided to remove that part and simply use the v parameter as a temporary variable but one that started out as the current iterator of the loop in the Q() function (but since not a pointer it’s not modified).

Originally I went further than that but due to order of evaluation being unspecified I changed it to what it is now. Anyway:

You can also see that I use the value of e[1]-3 as the index of S[e] (so S[e[e[1]-3]]) (I think I said that right; I honestly don’t know now because there is such major array and offset abuse. The entire prog.c is riddled with offset abuses.).

            for (*g = 0 ; *g < 10; ++*g)
            {
                r<:-2:> = Y<:14:><:*(e+1):>; r<:-3:> = Y<:15:><:1<:e:>:>;
                if (r<:-3:> && r<:-2:> == r<:-1:>)
                    return r<:-3:>;
                if (r<:-2:> && r<:-3:> == r<:-1:>)
                    return r<:-2:>;
            }

This e[1] of course is the same as *g as above and as you can see has multiple dimensions (that is the reference to Y does) too (and this is also strewn about the code). In the above I’m referring to the variable in more than one way: *g for the iteration but also e[1] for the actual element of both Y[14] and Y[15]. I also happen to use S (via r which points to S + 10) which I use as the two chars to compare (this is the plugboard function).

                k = Z(r<:-1:>=k);

The char is just used as a way to be able to call the function and assign to the proper variable at the same time: in the function Z I don’t care about x because it’s the same value as r[-1] (which I do care about). Why is it attached to S? Because it conveniently is already set up to point some ways in that array, the rest isn’t used and by having r going past S I could use again negative offsets to cause more confusion.

                r<:-2:> = Y<:14:><:*(e+1):>; r<:-3:> = Y<:15:><:1<:e:>:>;

I refer to e[1] as both: *(e+1) and 1[e].

            (Y<:e<:-10:>+5:><:k-'A':>) && (k = Y<:e<:-10:>+5:><:k-'A':>);

(Of course this also removes an if statement by joining with a &&).

            %:define J(x)                 do(*x)=getchar(); while((*x)=='\n')

Is used quite a number of times and although it could be a function that takes a pointer to an int it was more convenient this way (I believe it used more bytes but I no longer know that). There are many others and they all save bytes (or at least most of them do if not all). There is one in particular I want to bring up though because I think it’s a curious one and it ties in to another point above:

            %:define A(y)                                 *(&Y<:7:><:1:>+(y))

What is special about this one: Above I noted how I sort of refer directly to the notch settings (I think it was the notch settings anyway). Now I could have done say

            char a = Y[7][1], b = Y[7][3], c = Y[7][5];

But I felt that doing instead the pointer arithmetic was worth doing. However it used significantly more bytes even as a macro: 17 if I recall right. That’s with the macro. If I were to include it three times by itself it’d be many more. I believe though that when the cpp translates it it still requires more thought to determine that a is set to Y[7][1], b to Y[7][3] and c to Y[7][5].

Obfuscation wrt recode.c

                                /\
                    /           This is     *not* what you think:
                            void D(char*x){ /* ... */ }

Is that valid and if so how does it function? Yes it’s valid but I’ll leave the other part of the question up to the reader to answer. Hint: you already know how it works (yes, really you do)! Another hint: This is and is not a misleading comment (conversely this makes this hint both misleading - and also not).


Jump to: top