para ofuscar ofuscacion herramientas codigo c c-preprocessor obfuscation

ofuscacion - ofuscar codigo c#



Este código C ofuscado dice que se ejecuta sin main(), pero ¿qué hace realmente? (6)

Alguien está tratando de actuar como mago. Él cree que puede engañarnos. Pero todos sabemos, la ejecución del programa c comienza con main() .

int begin() será reemplazado con decode(a,n,i,m,a,t,e) por un paso de la etapa de preprocesador. Por otra parte, la decode(a,n,i,m,a,t,e) se reemplazará con m ## a ## i ## n. Como por asociación posicional de llamada macro, s tendrá un valor de carácter a . Del mismo modo, u será reemplazado por ''i'' t será reemplazado por ''n''. Y así es como, m##s##u##t se convertirá en main

En cuanto al símbolo ## en la expansión de macro, es el operador de preprocesamiento y realiza el pegado de tokens. Cuando se expande una macro, los dos tokens a cada lado de cada operador ''##'' se combinan en un solo token, que luego reemplaza el ''##'' y los dos tokens originales en la expansión de la macro.

Si no me cree, puede compilar su código con la -E . Se detendrá el proceso de compilación después del preprocesamiento y puede ver el resultado del pegado de tokens.

gcc -E FILENAME.c

#include <stdio.h> #define decode(s,t,u,m,p,e,d) m##s##u##t #define begin decode(a,n,i,m,a,t,e) int begin() { printf("Ha HA see how it is?? "); }

¿Esto indirectamente llama main ? ¿cómo?


El lenguaje C define el entorno de ejecución en dos categorías: independiente y alojado . En ambos entornos de ejecución, el entorno llama a una función para el inicio del programa.
En un programa de entorno independiente , la función de inicio puede definirse como implementación, mientras que en el entorno hospedado debe ser main . Ningún programa en C puede ejecutarse sin la función de inicio del programa en los entornos definidos.

En su caso, main está oculto por las definiciones de preprocesador. begin() se expandirá para decode(a,n,i,m,a,t,e) que luego se expandirá a main .

int begin() -> int decode(a,n,i,m,a,t,e)() -> int m##a##i##n() -> int main()

decode(s,t,u,m,p,e,d) es una macro parametrizada con 7 parámetros. La lista de reemplazo para esta macro es m##s##u##t . m, s, u y t son los parámetros , 1º, y utilizados en la lista de reemplazo.

s, t, u, m, p, e, d 1 2 3 4 5 6 7

El descanso no sirve de nada ( solo para ofuscar ). El argumento pasado para decode es " a , n , i , m , a, t, e", por lo que los identificadores m, s, u y t se reemplazan con los argumentos m, a, i y n , respectivamente.

m --> m s --> a u --> i t --> n


El programa en cuestión llama a main() debido a la expansión de macro, pero su suposición es errónea: ¡ no tiene que llamar a main() en absoluto!

Estrictamente hablando, puede tener un programa en C y poder compilarlo sin tener un símbolo main . main es algo a lo que la c library espera acceder, después de que haya terminado su propia inicialización. Por lo general, saltas a main desde el símbolo de libc conocido como _start . Siempre es posible tener un programa muy válido, que simplemente ejecute el ensamblaje, sin tener un main. Mira esto:

/* This must be compiled with the flag -nostdlib because otherwise the * linker will complain about multiple definitions of the symbol _start * (one here and one in glibc) and a missing reference to symbol main * (that the libc expects to be linked against). */ void _start () { /* calling the write system call, with the arguments in this order: * 1. the stdout file descriptor * 2. the buffer we want to print (Here it''s just a string literal). * 3. the amount of bytes we want to write. */ asm ("int $0x80"::"a"(4), "b"(1), "c"("Hello world!/n"), "d"(13)); asm ("int $0x80"::"a"(1), "b"(0)); /* calling exit syscall, with the argument to be 0 */ }

Compile lo anterior con gcc -nostdlib without_main.c , y vea cómo imprime Hello World! en la pantalla simplemente emitiendo llamadas al sistema (interrupciones) en el ensamblaje en línea.

Para obtener más información sobre este problema en particular, consulte el blog ksplice

Otra cuestión interesante es que también puede tener un programa que se compila sin que el símbolo main corresponda a una función C. Por ejemplo, puede tener lo siguiente como un programa C muy válido, que solo hace que el compilador se queje cuando sube el nivel de Advertencias.

/* These values are extracted from the decimal representation of the instructions * of a hello world program written in asm, that gdb provides. */ const int main[] = { -443987883, 440, 113408, -1922629632, 4149, 899584, 84869120, 15544, 266023168, 1818576901, 1461743468, 1684828783, -1017312735 };

Los valores en la matriz son bytes que corresponden a las instrucciones necesarias para imprimir Hello World en la pantalla. Para obtener una descripción más detallada de cómo funciona este programa específico, eche un vistazo a esta publicación de blog , que es donde también lo leí primero.

Quiero hacer un aviso final sobre estos programas. No sé si se registran como programas C válidos de acuerdo con la especificación del lenguaje C, pero compilarlos y ejecutarlos es ciertamente muy posible, incluso si violan la especificación misma.


En su ejemplo, la función main() está realmente presente, porque begin es una macro que el compilador reemplaza con macro de decode que a su vez reemplaza por la expresión m ## s ## u ## t. Usando la expansión de macro ## , llegará a la palabra main desde decode . Este es un rastro:

begin --> decode(a,n,i,m,a,t,e) --> m##parameter1##parameter3##parameter2 ---> main

Es solo un truco tener main() , pero usar el nombre main() para la función de entrada del programa no es necesario en el lenguaje de programación C. Depende de sus sistemas operativos y del enlazador como una de sus herramientas.

En Windows, no siempre usa main() , sino WinMain o wWinMain , aunque puede usar main() , incluso con la cadena de herramientas de Microsoft . En Linux, uno puede usar _start .

Depende del enlazador como herramienta del sistema operativo establecer el punto de entrada, y no el idioma en sí. ¡Incluso puede establecer nuestro propio punto de entrada, y puede crear una biblioteca que también sea ejecutable !


Intente usar gcc -E source.c , la salida termina con:

int main() { printf("Ha HA see how it is?? "); }

Entonces, una función main() es realmente generada por el preprocesador.


decode(a,b,c,d,[...]) baraja los primeros cuatro argumentos y los une para obtener un nuevo identificador, en el orden dacb . (Los tres argumentos restantes se ignoran). Por ejemplo, la decode(a,n,i,m,[...]) proporciona el identificador main . Tenga en cuenta que así es como se define la macro de begin .

Por lo tanto, la macro de begin se define simplemente como main .