Jeremy Tchao
Jeremy Tchao

Reputation: 33

How does this 1984 International Obfuscated C Code Contest winning entry work?

I am new to C and I eagerly want to know by what magic this segment of code works?

int i;main(){for(;i["]<i;++i){--i;}"];read('-'-'-',i+++"hell\
o, world!\n",'/'/'/'));}read(j,i,p){write(j/p+p,i---j,i/i);}

The source can be found here:http://www.ioccc.org/1984/anonymous.c

And the following is a hint that comes with the code:

Dishonorable mention: Anonymous

The author was too embarrassed that he/she could write such trash, so I promised to protect their identity. I will say that the author of this program has a well known connection with the C programming language. This program is a unique variation on the age old "Hello, world" program. What reads like a read may be written like a write! Copyright (c) 1984, Landon Curt Noll. All Rights Reserved. Permission for personal, educational or non-profit use is granted provided this this copyright and notice are included in its entirety and remains unaltered. All other uses must receive prior permission in writing from both Landon Curt Noll and Larry Bassel.

Upvotes: 3

Views: 1767

Answers (2)

R Sahu
R Sahu

Reputation: 206697

When you have an obfuscated code, you'll need to cleanup physical layout, add some white space, add the necessary indentation, and then compile the code. The warnings from the compiler will tell you a lot about some of the things the program hides.

First Cut Simplification - Add Whitespace

int i;
main()
{
   for( ; i["]<i;++i){--i;}"];
          read('-'-'-', i+++"hell\o, world!\n", '/'/'/'));
}

read(j,i,p)
{
   write(j/p+p,i---j,i/i);
}

When the program is compiled using gcc -Wall, I get the following warnings:

soc.c:2:1: warning: return type defaults to ‘int’ [enabled by default]
 main()
 ^
soc.c: In function ‘main’:
soc.c:4:4: warning: implicit declaration of function ‘read’ [-Wimplicit-function-declaration]
    for( ; i["]<i;++i){--i;}"]; read('-'-'-', i+++"hell\o, world!\n", '/'/'/'));
    ^
soc.c:4:50: warning: unknown escape sequence: '\o' [enabled by default]
    for( ; i["]<i;++i){--i;}"]; read('-'-'-', i+++"hell\o, world!\n", '/'/'/'));
                                                  ^
soc.c: At top level:
soc.c:7:1: warning: return type defaults to ‘int’ [enabled by default]
 read(j,i,p)
 ^
soc.c: In function ‘read’:
soc.c:7:1: warning: type of ‘j’ defaults to ‘int’ [enabled by default]
soc.c:7:1: warning: type of ‘i’ defaults to ‘int’ [enabled by default]
soc.c:7:1: warning: type of ‘p’ defaults to ‘int’ [enabled by default]
soc.c:9:4: warning: implicit declaration of function ‘write’ [-Wimplicit-function-declaration]
    write(j/p+p,i---j,i/i);
    ^
soc.c:9:17: warning: operation on ‘i’ may be undefined [-Wsequence-point]
    write(j/p+p,i---j,i/i);
                 ^
soc.c:9:17: warning: operation on ‘i’ may be undefined [-Wsequence-point]
soc.c:10:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

Second Cut Simplification - Un-obfuscation

Based on the above warnings, the program can be un-obfuscated to:

int i;

void read(int j, char* i, int p);
void write(int j, char* i, int p);

int main()
{
   for( ; i["]<i;++i){--i;}"];
          read('-'-'-', i+++"hell\o, world!\n", '/'/'/'));
   return 0;
}

void read(int j, char* i, int p)
{
   write(j/p+p, (i--) - j, 1);
}

The above version has no compiler warnings and produces the same output.

Third Cut Simplification - Un-obfuscate more

The expression i["]<i;++i){--i;}"] is used to run the loop 14 times. Simple as that. It can be simplified to i < 14.

'-'-'-' is the same as '-' - '-' which equals to 0.

'/'/'/' is the same as '/' / '/' which equals to 1.

i+++"hello, world!\n" is same as i++ + "hello, world!\n" which is same as s + i++ where s can be char const* s = "hello, world!\n";

The for loop can be simplified to:

   char const* s = "hello, world!\n";
   for( ; i < 14; read(0, s+i++, 1));

Since the value of j in read is always zero, the implementation of read can be simplified to:

void read(int j, char* i, int p)
{
   write(0, (i--), 1);
}

The expression (i--) can be simplified to just i since decrementing as a side effect does not change the workings of the function. In other words, the above function is:

void read(int j, char* i, int p)
{
   write(0, i, 1);
}

When we realize that the value of argument j is always 0 and the value of argument p is always 1, we can change the for loop in the main function to:

   for( ; i < 14; i++)
   {
      write(0, s+i, 1);
   }

Hence, the entire program can be simplified to:

void write(int j, char const* i, int p);

int main()
{
   int i = 0;
   char const* s = "hello, world!\n";
   for( ; i < 14; i++ )
   {
      write(0, s+i, 1);
   }
   return 0;
}

Fourth Cut Simplification - Make It Trivial

The above version has a hard coded number 14. That is the number of characters in s. Hence, the program can be made trivial by changing it to:

void write(int j, char const* i, int p);

int main()
{
   write(0, "hello, world!\n", 14);
   return 0;
}

Upvotes: 15

Jo&#235;l Hecht
Jo&#235;l Hecht

Reputation: 1842

Let's rewrite a bit the code, replace some expressions and add comments

int i; // i = 0 by default

main()
{
    for( ;
        "]<i;++i){--i;}" [i];  // magic: it is the same as i["]<i;++i){--i;}"];
                               // the important part is that there's 14 chars in the
                               // string, same length that "hello, world!\n"
                               // the content of the string has no importance here,
                               // in the end 'i' will go from 0 to 14

        read(0, // since '-' - '-' is equal to 0,
             "hello, world!\n" + (i++),  // same as i+++"hello, world!\n"
                                      // it is pointers arythmetic
                                      // the second arg to the read
                                      // function defined further points
                                      // to the letter to print
             1)) // '/' / '/' division result is 1
      ;
}

// the read function is then always called with
// j == 0
// i is a pointer to the char to print
// p == 1
// And for the obfuscation fun, the read function will write something :)
read(j,i,p)
{
    write(0,  // j/p+p is equal to 0, which is the stdout 
          i,  // i-- - j is equal to i, decrement of i comes later
          1);  // i / i is equal to 1, this means one char to print
}

Upvotes: 4

Related Questions