A Competição Internacional de Código Ofuscado em C (International Obfuscated C Code Contest, ou IOCCC) é uma comptetição anual que ocorre desde 1984. O vencedor é aquele que produzir o código em C mais criativo, bizarro e difícil de ler, mas que rode. Os programas vencedores geralmente são engraçados, magníficas obras de arte, na maioria das vezes, ótimos exemplos de como não programar em C.
Um exemplo famoso e que já venceu é este, que imprime todos os números primos menores que 100. Vamos conferir os resultados de simples transformações no código do programa:
void primes(int cap) {
int i, j, composite;
for(i = 2; i < cap; i++) {
composite = 0;
for(j = 2; j < i; j++)
composite += !(i % j);
if(!composite)
printf("%d\t", i);
}
}
int main() {
primes(100);
}
A primeira fase de transformações reduz a função primes: (1) O for é retirado e reescrito como um simples while contendo uma sequência de if-else; (2) O while é então escrito como recursão; (3) Os if-else em cascata são reescritos como um condicional apenas. Estas transformações já tornam o código consideravelmente obfuscated. O restante das transformações tem o objetivo de omitir detalhes da função: (4) remoção de variáveis intermediárias; (5) renomeação de variáveis para _, ___, etc; e, finalmente, (6) remoção de quaisquer espaços em branco e parênteses desnecessários.
Após esta primeira transformação:
void primes(int cap) {
int i, j, composite, t = 0;
while(t < cap * cap) {
i = t / cap;
j = t++ % cap;
if(i <= 1);
else if(j == 0)
composite = 0;
else if(j == i && !composite)
printf("%d\t",i);
else if(j > 1 && j < i)
composite += !(i % j);
}
}
int main() {
primes(100);
}
O programa agora é transformado pela substituição do while por uma recursão. Isto requer a adição de dois parâmetros ao cabeçalho da função prime. Veja também que um bloco if-else adicional deve ser adicionado para que haja incremento na recursão quando nenhuma condição for obedecida:
void primes(int cap, int t, int composite) {
int i,j;
i = t / cap;
j = t % cap;
if(i <= 1)
primes(cap,t+1,composite);
else if(j == 0)
primes(cap,t+1,0);
else if(j == i && !composite)
(printf("%d\t",i), primes(cap,t+1,0));
else if(j > 1 && j < i)
primes(cap,t+1, composite + !(i % j));
else if(t < cap * cap)
primes(cap,t+1,composite);
}
int main() {
primes(100,0,0);
}
Agora os nomes das variáveis são mudados para apenas letras e substituição de if-else pelo operador condicional ternário (ex: if(A) B else if(C) D else E -> A ? B : C ? D : E):
void primes(int m, int t, int c) {
int i,j;
i = t / m;
j = t % m;
(i <= 1) ? primes(m,t+1,c) : (j == 0) ? primes(m,t+1,0) : (j == i && !c) ?
(printf("%d\t",i), primes(m,t+1,0)) : (j > 1 && j < i) ?
primes(m,t+1,c + !(i % j)) : (t < m * m) ? primes(m,t+1,c) : 0;
}
int main() {
primes(100,0,0);
}
Agora o programa é transformado substituindo as variáveis i e j por (t / m) e (t % m), respectivamente:
void primes(int m, int t, int c) {
((t / m) <= 1) ? primes(m,t+1,c) : !(t % m) ? primes(m,t+1,0) :
((t % m)==(t / m) && !c) ? (printf("%d\t",(t / m)), primes(m,t+1,0)) :
((t % m)> 1 && (t % m) < (t / m)) ? primes(m,t+1,c + !((t / m) % (t % m))) :
(t < m * m) ? primes(m,t+1,c) : 0;
}
int main() {
primes(100,0,0);
}
Agora as variáveis m, t, e c são transformadas para _, __, ___, e ____, respectivamente:
void _(int __, int ___, int ____) {
((___ / __) <= 1) ? _(__,___+1,____) : !(___ % __) ? _(__,___+1,0) :
((___ % __)==(___ / __) && !____) ? (printf("%d\t",(___ / __)),
_(__,___+1,0)) : ((___ % __) > 1 && (___ % __) < (___ / __)) ?
_(__,___+1,____ + !((___ / __) % (___ % __))) : (___ < __ * __) ?
_(__,___+1,____) : 0;
}
int main() {
_(100,0,0);
}
Finalmente, espaços em branco, declaração de tipos, e parênteses não-ambíguos são removidos para se chegar à fully obfuscated version:
_(__,___,____){___/__<=1?_(__,___+1,____):!(___%__)?_(__,___+1,0):___%__==___/
__&&!____?(printf("%d\t",___/__),_(__,___+1,0)):___%__>1&&___%__<___/__?_(__,1+
___,____+!(___/__%(___%__))):___<__*__?_(__,___+1,____):0;}main(){_(100,0,0);}
Informações (em inglês) sobre o IOCCC podem ser vistas em http://www.ioccc.org/
Exemplo de Obfuscated Hello Word:
#include "stdio.h"
#define e 3
#define g (e/e)
#define h ((g+e)/2)
#define f (e-g-h)
#define j (e*e-g)
#define k (j-h)
#define l(x) tab2[x]/h
#define m(n,a) ((n&(a))==(a))
long tab1[]={ 989L,5L,26L,0L,88319L,123L,0L,9367L };
int tab2[]={ 4,6,10,14,22,26,34,38,46,58,62,74,82,86 };
main(m1,s) char *s; {
int a,b,c,d,o[k],n=(int)s;
if(m1==1){ char b[2*j+f-g]; main(l(h+e)+h+e,b); printf(b); }
else switch(m1-=h){
case f:
a=(b=(c=(d=g)<<g)<<g)<<g;
return(m(n,a|c)|m(n,b)|m(n,a|d)|m(n,c|d));
case h:
for(a=f;a<j;++a)if(tab1[a]&&!(tab1[a]%((long)l(n))))return(a);
case g:
if(n<h)return(g);
if(n<j){n-=g;c='D';o[f]=h;o[g]=f;}
else{c='\r'-'\b';n-=j-g;o[f]=o[g]=g;}
if((b=n)>=e)for(b=g<<g;b<n;++b)o[b]=o[b-h]+o[b-g]+c;
return(o[b-g]%n+k-h);
default:
if(m1-=e) main(m1-g+e+h,s+g); else *(s+g)=f;
for(*s=a=f;a<e;) *s=(*s<<e)|main(h+a++,(char *)m1);
}
}
Mais exemplos em: http://www.cise.ufl.edu/~manuel/obfuscate/obfuscate.html
return 0