Worst abuse of the C preprocessor (IOCCC winner, 1986)
The International Obfuscated C Code Contest (IOCCC)
The International Obfuscated C Code Contest (abbreviated IOCCC) is a computer programming contest for the most creatively obfuscated C code. Held annually in the years 1984–1996, 1998, 2000, 2001, 2004–2006, 2011–2015 and then in 2018, it is described as “celebrating syntactical opaqueness”. The winning code for the 25th contest, held in 2018, was released in May 2018.
Entries are evaluated anonymously by a panel of judges. The judging process is documented in the competition guidelines and consists of elimination rounds. By tradition, no information is given about the total number of entries for each competition. Winning entries are awarded with a category, such as “Worst Abuse of the C preprocessor” or “Most Erratic Behavior”, and then announced on the official IOCCC website. The contest states that being announced on the IOCCC website is the reward for winning.
The IOCCC rules
- To write the most Obscure/Obfuscated C program within the rules.
- To show the importance of programming style, in an ironic way.
- To stress C compilers with unusual code.
- To illustrate some of the subtleties of the C language.
- To provide a safe forum for poor C code.
In 1986 the winner of this contest was Jim Hague for Kent at Canterbury university UK with an amazing code. You can find the code here
Comment of the judge: Compile this program and feed ascii text into standard input. This program is known to pass lint on some systems and abort lint on others.
This program was selected for the 1987 t-shirt collection.
Think morse code when you ponder this program. Note how use of similar variables can be obfuscating! The author notes that this program implements the international morse standard. Now for extra credit, what morse message does the program spell out?
What is Obfuscation code?
Is a well-known term in software engineering. It is the concealment of written code purposefully by the programmer. It is mainly done for the purposes of security by making it obscure to avoid tampering, hide implicit values or conceal the logic used. One can obfuscate code with the help of language-specific deobfuscators that convert into meaningful code.
Example of obfuscated c code
int i;main(){for(i=0;i[“]<i;++i){ — i;}”];
read(‘-’-’-’,i+++”hell\
o,world!\n”,’/’/’/’));}read(j,i,p){
write(j/p+p,i — -j,i/i);}
Here is the deobfuscated version which a person can understand.
int i;void write_char(char ch)
{
printf(“%c”, ch);
}int main()
{
for (i = 0; i < 15; i++) {
write_char(“hello, world!\n”[i]);
}
return 0;
}
In 1986 Jim Hague won the IOCCC with this code.
#define DIT (
#define DAH )
#define __DAH ++
#define DITDAH *
#define DAHDIT for
#define DIT_DAH malloc
#define DAH_DIT gets
#define _DAHDIT char
_DAHDIT _DAH_[]="ETIANMSURWDKGOHVFaLaPJBXCYZQb54a3d2f16g7c8a90l?e'b.s;i,d:"
;main DIT DAH{_DAHDIT
DITDAH _DIT,DITDAH DAH_,DITDAH DIT_,
DITDAH _DIT_,DITDAH DIT_DAH DIT
DAH,DITDAH DAH_DIT DIT DAH;DAHDIT
DIT _DIT=DIT_DAH DIT 81 DAH,DIT_=_DIT
__DAH;_DIT==DAH_DIT DIT _DIT DAH;__DIT
DIT'\n'DAH DAH DAHDIT DIT DAH_=_DIT;DITDAH
DAH_;__DIT DIT DITDAH
_DIT_?_DAH DIT DITDAH DIT_ DAH:'?'DAH,__DIT
DIT' 'DAH,DAH_ __DAH DAH DAHDIT DIT
DITDAH DIT_=2,_DIT_=_DAH_; DITDAH _DIT_&&DIT
DITDAH _DIT_!=DIT DITDAH DAH_>='a'? DITDAH
DAH_&223:DITDAH DAH_ DAH DAH; DIT
DITDAH DIT_ DAH __DAH,_DIT_ __DAH DAH
DITDAH DIT_+= DIT DITDAH _DIT_>='a'? DITDAH _DIT_-'a':0
DAH;}_DAH DIT DIT_ DAH{ __DIT DIT
DIT_>3?_DAH DIT DIT_>>1 DAH:'\0'DAH;return
DIT_&1?'-':'.';}__DIT DIT DIT_ DAH _DAHDIT
DIT_;{DIT void DAH write DIT 1,&DIT_,1 DAH;}
This code works as a translator for morse code. To compile this program we should use the command gcc hague.c -o h. And we will see something like this
After we execute the program we will have a space to write what ever you want in this case we will use the phrase “Hello, Holberton” and we will see the phrase in morse code.
As we can see in the code made by Jim Hague hi starting defining macros like this.
#define DIT (
#define DAH )
#define __DAH ++
#define DITDAH *
#define DAHDIT for
#define DIT_DAH malloc
#define DAH_DIT gets
#define _DAHDIT char
Jim used the parenthesis symbols “( )” to create to start the program and assign loop structures with , “++” to control l; he defined “malloc” to dynamically assign memory and “char” for some variables.
With this command we can stop the compilation at the preprocessing part so we can make the code more understandable to humans. gcc -E hague.c -o ha. And we will get this code
# 1 "hague.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "hague.c"
# 9 "hague.c"
char _DAH_[]=
"ETIANMSURWDKGOHVFaLaPJBXCYZQb54a3d2f16g7c8a90l?e'b.s;i,d:";
main ( ){char
* _DIT,* DAH_,* DIT_,
* _DIT_,* malloc (
),* gets ( );for
( _DIT=malloc ( 81 ),DIT_=_DIT
++;_DIT==gets ( _DIT );__DIT
('\n') ) for ( DAH_=_DIT;*
DAH_;__DIT ( *
_DIT_?_DAH ( * DIT_ ):'?'),__DIT
(' '),DAH_ ++ ) for (
* DIT_=2,_DIT_=_DAH_; * _DIT_&&(
* _DIT_!=( * DAH_>='a'? *
DAH_&223:* DAH_ ) ); (
* DIT_ ) ++,_DIT_ ++ )
* DIT_+= ( * _DIT_>='a'? * _DIT_-'a':0
);}_DAH ( DIT_ ){ __DIT (
DIT_>3?_DAH ( DIT_>>1 ):'\0');return
DIT_&1?'-':'.';}__DIT ( DIT_ ) char
DIT_;{( void ) write ( 1,&DIT_,1 );}
If we separate the functions this would be clearer for the human.
char _DAH_[] = "ETIANMSURWDKGOHVFaLaPJBXCYZQb54a3d2f16g7c8a90l?e'b.s;i,d:";/* function main */main ()
{
char *_DIT, *DAH_, *DIT_, *_DIT_, *malloc (), *gets ();/* The loop starts at the input line and prints a new line after finishing. */for (_DIT = malloc (81), DIT_ = _DIT++; _DIT == gets (_DIT); __DIT ('\n'))
for (DAH_ = _DIT;
*DAH_; __DIT (*_DIT_ ? _DAH (*DIT_) : '?'), __DIT (' '), DAH_++) for (*DIT_ = 2, _DIT_ = _DAH_;
*_DIT_ && (*_DIT_ != (*DAH_ >= 'a' ? *DAH_ & 223 : *DAH_));
(*DIT_)++, _DIT_++)
*DIT_ += (*_DIT_ >= 'a' ? *_DIT_ - 'a' : 0);
}/* in nested for loop, check if current character is in _DAH_, if so call conversion; otherwise, print '?' *// * End of main function *//* _DAH - convert to morse code */_DAH (DIT_)
{
__DIT (DIT_ > 3 ? _DAH (DIT_ >> 1) : '\0');
return DIT_ & 1 ? '-' : '.';
}
/* End function convert _DAH *//* __DIT - print to standard output*/__DIT (DIT_)
char DIT_;
{
(void) write (1, &DIT_, 1);
}
/* End function __DIT */
After that we can deobfuscated the code and will be understandable for us.
char ascii_array[] = "ETIANMSURWDKGOHVFaLaPJBXCYZQb54a3d2f16g7c8a90l?e'b.s;i,d:";/* Main function */main (){
char *_dot, *_dash, *_2_dot, *_3_dot, *malloc(), *gets();/* The loop starts at the input line and prints a new line after finishing. */for(_dot = malloc(81), _2_dot = _dot++; _dot == gets(_dot); print('\n'))for (_dash = _dot; *_dash; print(*_3_dot ? convert(*_2_dot) : '?'), print(' '), _dash ++)for (* _2_dot = 2, _3_dot = ascii_array; *_3_dot && (*_3_dot != (*_dash >= 'a' ? *_dash & 223 : *_dash));
(*_dot)++, _3_dot++)
*_2_dot += (* _3_dot >= 'a' ? *_3_dot - 'a' : 0);}
/* in nested for loop, check if current character is in _DAH_, if so call conversion; otherwise, print '?' *// * End of main function *//* _DAH - convert to morse code */convert(_2_dot){
print(_2_dot > 3 ? convert(_2_dot >> 1) : '\0');
return _2_dot &1 ? '-' : '.';
}/* End function convert _DAH *//* __DIT - print to standard output*/print( _2_dot ) char _2_dot;
{
(void) write(1, &_2_dot, 1);
}/* End function __DIT */
Is really nice the way that we can obfuscated a C code, i hope you find this blog interesting. If you want to know more about morse code here you can find it.