En fitzrovian.com podemos encontrar varios Hola Mundo escritos en C ofuscado. Se llama código ofuscado a aquel en el que se utilizan todos los artificios posibles para dificultar al máximo la lectura del programa, a modo de chiste, broma, y pasatiempo.
A continuación he copiado cada uno de ellos, junto con una explicación de cómo imprime «Hello world» cada programa, explicación a la que podéis acceder pulsando sobre el botón del mismo nombre.
¿Cuántos podéis descifrar por vosotros mismos?
hello1.c
#define _________ } #define ________ putchar #define _______ main #define _(a) ________(a); #define ______ _______(){ #define __ ______ _(0x48)_(0x65)_(0x6C)_(0x6C) #define ___ _(0x6F)_(0x2C)_(0x20)_(0x77)_(0x6F) #define ____ _(0x72)_(0x6C)_(0x64)_(0x21) #define _____ __ ___ ____ _________ #include<stdio.h> _____
#define x y
haría que se sustituyera el texto x por y en el archivo antes de ejecutarlo. Por lo tanto tras hacer las sustituciones y obviando los define que ya no necesitamos nos quedaría algo como
#include<stdio.h> main(){ putchar(0x48); putchar(0x65); putchar(0x6C); putchar(0x6C); putchar(0x6F); putchar(0x2C); putchar(0x20); putchar(0x77); putchar(0x6F); putchar(0x72); putchar(0x6C); putchar(0x64); putchar(0x21); }
El método putchar no hace más que imprimir el carácter que se le pasa. Sin embargo el carácter en este caso está expresado con su código ASCII en hexadecimal.
hello2.c
#include<stdio.h> main(){ int x=0,y[14],*z=&y;*(z++)=0x48;*(z++)=y[x++]+0x1D; *(z++)=y[x++]+0x07;*(z++)=y[x++]+0x00;*(z++)=y[x++]+0x03; *(z++)=y[x++]-0x43;*(z++)=y[x++]-0x0C;*(z++)=y[x++]+0x57; *(z++)=y[x++]-0x08;*(z++)=y[x++]+0x03;*(z++)=y[x++]-0x06; *(z++)=y[x++]-0x08;*(z++)=y[x++]-0x43;*(z++)=y[x]-0x21; x=*(--z);while(y[x]!=NULL)putchar(y[x++]); }
#include<stdio.h> main() { int x = 0, y[14], *z = &y; *(z++) = 0x48; *(z++) = y[x++] + 0x1D; *(z++) = y[x++] + 0x07; *(z++) = y[x++] + 0x00; *(z++) = y[x++] + 0x03; *(z++) = y[x++] - 0x43; *(z++) = y[x++] - 0x0C; *(z++) = y[x++] + 0x57; *(z++) = y[x++] - 0x08; *(z++) = y[x++] + 0x03; *(z++) = y[x++] - 0x06; *(z++) = y[x++] - 0x08; *(z++) = y[x++] - 0x43; *(z++) = y[x] - 0x21; x = *(--z); while(y[x] != NULL) putchar(y[x++]); }
Como vemos tenemos una matriz 'y' en la que almacenaremos los caracteres de "hello world" y una variable 'x' que sirve como índice para recorrer la matriz e imprimir cada uno de los caracteres en un while. De nuevo se utiliza la representación en ASCII de cada caracter, sin embargo esta vez hay que lidiar con punteros (direcciones de memoria).
El operador & sirve para obtener la dirección de memoria de una variable, mientras que el operador * sirve para referirse al contenido que se almacena en una dirección de memoria.
La variable z se trata de una variable de tipo puntero que almacena la dirección en la que se guarda la matriz y. Al sumar 1 a z con el operador ++ lo que estamos haciendo es aumentar la dirección de memoria en el tamaño que tiene un entero en la plataforma en la que se ejecuta el programa. Por lo tanto con *(z++) = 0x48
lo que estamos haciendo es asignarle el caracter 0x48 (H) a la posición 1 de la matriz.
Para terminar de rizar el rizo los siguientes caracteres a introducir en las posiciones de la matriz se obtienen sumando y restando del valor de la posición anterior de la matriz. Por ejemplo 0x48 + 0x1D da como resultado 0x65, que es el caracter e.
hello3.c
#include<stdio.h> #define __(a) goto a; #define ___(a) putchar(a); #define _(a,b) ___(a) __(b); main() { _:__(t)a:_('r',g)b:_('$',p) c:_('l',f)d:_(' ',s)e:_('a',s) f:_('o',q)g:_('l',h)h:_('d',n) i:_('e',w)j:_('e',x)k:_('\n',z) l:_('H',l)m:_('X',i)n:_('!',k) o:_('z',q)p:_('q',b)q:_(',',d) r:_('i',l)s:_('w',v)t:_('H',j) u:_('a',a)v:_('o',a)w:_(')',k) x:_('l',c)y:_('\t',g)z:___(0x0)}
#include<stdio.h> main() { _: goto t; a: putchar('r'); goto g; b: putchar('$'); goto p; c: putchar('l'); goto f; d: putchar(' '); goto s; e: putchar('a'); goto s; f: putchar('o'); goto q; g: putchar('l'); goto h; h: putchar('d'); goto n; i: putchar('e'); goto w; j: putchar('e'); goto x; k: putchar('\n'); goto z; l: putchar('H'); goto l; m: putchar('X'); goto i; n: putchar('!'); goto k; o: putchar('z'); goto q; p: putchar('q'); goto b; q: putchar(','); goto d; r: putchar('i'); goto l; s: putchar('w'); goto v; t: putchar('H'); goto j; u: putchar('a'); goto a; v: putchar('o'); goto a; w: putchar(')'); goto k; x: putchar('l'); goto c; y: putchar('\t'); goto g; z: putchar(0x0); }
Este "puzzle" se basa en las etiquetas y los goto. Las etiquetas se parecen a los procedimientos en tanto que permiten asociar un nombre a un fragmento de código, que podemos ejecutar mediante goto.
Lo primero con lo que nos encontraríamos es un goto t
por lo que saltaríamos a ejecutar el código definido en esa etiqueta: la impresión del caracter H y un salto a j, donde a su vez se imprime el caracter e y se salta a x. Y asi sucesivamente.
hello4.c
int n[]={0x48, 0x65,0x6C,0x6C, 0x6F,0x2C,0x20, 0x77,0x6F,0x72, 0x6C,0x64,0x21, 0x0A,0x00},*m=n; main(n){putchar (*m)!='\0'?main (m++):exit(n++);}
int n[] = {0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x2C, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00}, *m = n; main(n) { putchar(*m) != '\0' ? main(m++) : exit(n++); }
Como vemos n es una matriz con los caracteres de "Hello, world!" y m un puntero a n. Cada vez que se ejecuta main se imprime el caracter al que apunta m. Además se comprueba si el caracter es '\0', es decir, el final de la cadena. Si se cumple la condición hemos terminado, en caso contrario, se llama a main aumentando en 1 el puntero, es decir, apuntando al próximo caracter de la matriz.
hello5.c
main(){int i,n[]={(((1<<1)<<(1<<1)<<(1<< 1)<<(1<<(1>>1)))+((1<<1)<<(1<<1))), (((1 <<1)<<(1<<1)<<(1<<1)<<(1<<1))-((1<<1)<<( 1<<1)<<(1<<1))+((1<<1)<<(1<<(1>>1)))+ (1 <<(1>>1))),(((1<<1)<<(1<<1)<<(1<<1)<< (1 <<1))-((1<<1)<<(1<<1)<<(1<<(1>>1)))- ((1 <<1)<<(1<<(1>>1)))),(((1<<1)<<(1<<1)<<(1 <<1)<<(1<<1))-((1<<1)<<(1<<1)<<(1<<(1>>1 )))-((1<<1)<<(1<<(1>>1)))),(((1<<1)<< (1 <<1)<<(1<<1)<<(1<<1))-((1<<1)<<(1<<1)<<( 1<<(1>>1)))-(1<<(1>>1))),(((1<<1)<<(1<<1 )<<(1<<1))+((1<<1)<<(1<<1)<<(1<<(1>>1))) -((1<<1)<<(1<<(1>>1)))),((1<<1)<< (1<<1) <<(1<<1)),(((1<<1)<<(1<<1)<<(1<<1)<<(1<< 1))-((1<<1)<<(1<<1))-(1<<(1>>1))),(((1<< 1)<<(1<<1)<<(1<<1)<<(1<<1))-((1<<1)<< (1 <<1)<<(1<<(1>>1)))-(1<<(1>>1))), (((1<<1 )<<(1<<1)<<(1<<1)<<(1<<1))- ((1<<1)<< (1 <<1)<<(1<<(1>>1)))+(1<<1)), (((1<<1)<< ( 1<<1)<<(1<<1)<< (1<<1))-((1<<1)<< (1<<1) <<(1<<(1>>1)))-((1<<1) <<(1<< (1>>1)))), (((1<<1)<< (1<<1)<<(1<<1)<< (1<<1))- ((1 <<1)<<(1<<1)<<(1<<1))+((1<<1)<< (1<<(1>> 1)))), (((1<<1)<<(1<<1) <<(1<<1))+(1<<(1 >>1))),(((1<<1)<<(1<<1))+((1<<1)<< (1<<( 1>>1))) + (1<< (1>>1)))}; for(i=(1>>1);i <(((1<<1) <<(1<<1))+((1 <<1)<< (1<<(1>>1 ))) + (1<<1)); i++) printf("%c",n[i]); }
hello6.c
#include <stdio.h> #define _(_) putchar(_); int main(void){int i = 0;_( ++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++ ++++i)_(++++++++++++++++++++ ++++++++++++++++++++++++++++ ++++++++++i)_(++++++++++++++ i)_(--++i)_(++++++i)_(------ ---------------------------- ---------------------------- ---------------------------- ---------------------------- ----------------i)_(-------- ----------------i)_(++++++++ ++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++ ++++++++++++++++++++++++++i) _(----------------i)_(++++++ i)_(------------i)_(-------- --------i)_(---------------- ---------------------------- ---------------------------- ---------------------------- ---------------------------- ------i)_(------------------ ---------------------------- i)return i;}
Cabe acotar que existe gente que ofusca código no a modo de chiste, broma, o pasatiempo sino con el fin de causar problemas de organización, de competencia o para volverse ‘imprescindibles’ para el stakeholder. Saludos.
Me he quedado ofuscado!!! jajaja
jajaja están muy buenos los códigos.
El que lo hizo tiene tiempo de sobra.
Ahh, la belleza del C, me he perdido en varias 😀
Para entender «al ojo» algo así hay que ser como el tipo de Matrix que al mirar el código veía mujeres rubias, morenas, etc.
En la Semana ESIDE o ESIDE WORDS llevan años organizando concursos de programación ofuscada, nunca he participado pero no dudo de que lleguen buenos trabajos 😉
En la Facultad somos asi 😛
Pingback: » “Hola Mundo” ofuscado en C | Informática Práctica |
Así es como se debe hacer, hombre. Cualquier cosa que sea más avanzada es herejía.
Excepto quizás el C++. El C++ es bueno si no usas strings ni herencias.
MORTAL! Insultas a c++
Se me olvidaba, por si a alguien le interesa:
http://semana.eside.deusto.es/index.php/Concursos
Es ahi dónde aparece el concurso 😉
El abuso nunca es bueno, pero también es necesario. 😛
Muchas gracias newton, muy interesante 🙂
Pingback: Resumen semanal 4 | Sin Conexión
Pingback: Los Links de Tolito » Blog Archive » Links del 3 de Marzo del 2008
Coincido con koki respecto a lo de matrix xD
Ofuscado? nunca lo habia oido… pero en fin, probe algunos codigos y funcan… hay que tener tiempo pa’ hacer algo asi… XD
No hay que tener tiempo pa’ hacer algo así sino un cerebro e mucha imaginación!!!
Saben me ha parecido fantastico todo estos codigos, auque solo se q esto es solo una probadita por decirlo asi.
Conosco una ing bueno ya master q dice ser programadora en C pero la verdad no le creo nada pues nunca lo ha demostrado.
Yo soy nuevo el el ramo pero cada vez me interesa saber mas y mas.
creo q esto me sirve d e aliento para saber q sepuede hacer mas y mas.
Si se me dificulta:
echo «Hello World»
Se imaginan con eso??? gente loca…
que pendejadas son esas??
keep up the wonderful work , I read few blog posts on this site and I think that your web site is rattling interesting and holds sets of wonderful info .
Pingback: Recursos - Grup de Valencià EDA ETSINF
En estos momentos hay un desafío llamado *Primer Concurso de Ofuscación de Código* y es organizado por HardForo (.com)