cdeobfuscation

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.


Solution

  • 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;
    }