Hola mundo ofuscados
« Ingeniería del software en Microsoft | Las cualidades del Clipo de Office »
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++)=0×48;*(z++)=y[x++]+0×1D; *(z++)=y[x++]+0×07;*(z++)=y[x++]+0×00;*(z++)=y[x++]+0×03; *(z++)=y[x++]-0×43;*(z++)=y[x++]-0×0C;*(z++)=y[x++]+0×57; *(z++)=y[x++]-0×08;*(z++)=y[x++]+0×03;*(z++)=y[x++]-0×06; *(z++)=y[x++]-0×08;*(z++)=y[x++]-0×43;*(z++)=y[x]-0×21; x=*(--z);while(y[x]!=NULL)putchar(y[x++]); }
#include<stdio.h> main() { int x = 0, y[14], *z = &y; *(z++) = 0×48; *(z++) = y[x++] + 0×1D; *(z++) = y[x++] + 0×07; *(z++) = y[x++] + 0×00; *(z++) = y[x++] + 0×03; *(z++) = y[x++] - 0×43; *(z++) = y[x++] - 0×0C; *(z++) = y[x++] + 0×57; *(z++) = y[x++] - 0×08; *(z++) = y[x++] + 0×03; *(z++) = y[x++] - 0×06; *(z++) = y[x++] - 0×08; *(z++) = y[x++] - 0×43; *(z++) = y[x] - 0×21; 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 0×48 (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 0×48 + 0×1D da como resultado 0×65, 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[]={0×48, 0×65,0×6C,0×6C, 0×6F,0×2C,0×20, 0×77,0×6F,0×72, 0×6C,0×64,0×21, 0×0A,0×00},*m=n; main(n){putchar (*m)!='\0′?main (m++):exit(n++);}
int n[] = {0×48, 0×65, 0×6C, 0×6C, 0×6F, 0×2C, 0×20, 0×77, 0×6F, 0×72, 0×6C, 0×64, 0×21, 0×0A, 0×00}, *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;}
Inicio
Archivos
Suscribirse
Acerca de
Contacto
Traducciones
Wiki
Entrada aleatoria
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
[...] Enlace: | Manuales de C Vía: | MundoGeek [...]
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.
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
[...] Mundo Geek, colección de "Hola Mundo" escritos en C ofuscado, esto sí que es código legible, [...]
[...] Hola Mundos en C ofuscados [...]
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!!!