C++: Insertar un ejecutable dentro de otro… y luego ejecutarlo

Vamos a explicar cómo tomar un ejecutable (o cualquier otro fichero binario), insertarlo dentro de un ejecutable y posteriormente cómo recuperar ese ejecutable embebido, soltarlo a disco y ejecutarlo. El escenario típico es borrar el propio ejecutable que actúa como hospedante, pero seguro que a las mentes calenturientas de mis lectores se les ocurren más aplicaciones.

El problema no existía en Windows 95 y siguientes: un programa podía borrar su propio ejecutable y terminar sin ningún problema (o casi). Pero en los núcleos NT hacer eso es harina de otro costal. Teóricamente se puede hacer mientras que el ejecutable a borrar no abra ningún handle… pero evidentemente cualquier ejecutable suele abrir no uno, sino infinidad de ellos.

La solución consiste entonces en disponer de dos ejecutables en disco. El primero hará su tarea y llamará al segundo antes de terminar, que tras unos instantes procederá a borrar el primero, quedando éste último en disco. Pero entonces tenemos que distribuir dos ficheros y colocarlos en el mismo sitio, por lo que la mejor solución es que el primero contenga al segundo en sus entrañas y lo use a voluntad. Incidentalmente el segundo podría decir a Windows que lo borre en el siguiente reinicio, pero no vamos a entrar en detalles sobre esto.

Primer paso: Insertar el ejecutable

Suponiendo que tengamos ya construido nuestro ejecutable (que vamos a llamar “borra.exe”), insertar un recurso del tipo RCDATA en un fichero ejecutable es una tarea trivial. Basta con abrir el fichero de recursos del ejecutable (el .rc) como texto e insertar la línea:

ELEXE RCDATA «..\final\Win32\Release\borra.exe»

Recompilamos y ya tenemos el ejecutable como recurso binario embebido en nuestro propio ejecutable. Evidentemente no estamos limitados a ningún tipo de archivo en concreto. Podríamos hacerlo incluso con recursos normales (mapas de bits, iconos, cadenas, etc.). La única diferencia es la forma de recuperar un recurso binario de uno almacenado como estándar.

Segundo paso: Sacar el ejecutable y ponerlo en disco

Cuando queramos volcar nuestro ejecutable a disco, debemos ejecutar algo parecido a lo siguiente:

HRSRC res=FindResource(NULL,_T(«ELEXE»),RT_RCDATA);
if(res==NULL)
     return GetLastError();

int size=SizeofResource(NULL,res);
HGLOBAL hRes=LoadResource(NULL,res);
unsigned char *pRes=(unsigned char *)LockResource(hRes);

HANDLE hFile=CreateFile(szT2Path,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL);
if(hFile==INVALID_HANDLE_VALUE)
     return GetLastError();

WriteFile(hFile,pRes,size,&bytesWritten,NULL);
CloseHandle(hFile);

ShellExecute(HWND_DESKTOP,NULL,szT2Path,NULL,NULL,SW_SHOWNORMAL);


El primer paso consiste en llamar a FindResource con el nombre y el tipo de recurso. Si nuestro fichero hubiera estado almacenado en otro lugar que no fuera nuestro propio ejecutable, el primer parámetro a pasar es la instancia del fichero externo.

Tras tener un handle válido, tenemos que mirar el tamaño que ocupa el recurso almacenado, lo que hacemos con SizeofResource.

Ahora viene cargar el recurso en memoria y obtener un handle de memoria (LoadResource). Pero todavía no podemos acceder a los bytes de nuestro fichero, debemos bloquear el acceso a los mismos mediante LockResource, lo que nos devolverá un área de memoria accesible.

Aquí el autor lo ha asignado a un buffer de caracteres sin signo, pero realmente cualquier tipo de dato es perfectamente válido, aunque tenemos que tener en cuenta de no guardar ningún byte de más en el fichero final. Haciéndolo con un buffer de caracteres nos aseguramos de guardar el tamaño correcto.

Ya solo nos queda guardar el buffer a disco y hacer la llamada para ejecutar el fichero extraído.

Quizás nos preguntemos por qué no hemos liberado la memoria apuntada por pRes: está expresamente descrito en la documentación de la MSDN: no debemos hacerlo nosotros, ya lo hará el sistema cuando corresponda.

Consideraciones finales

Evidentemente una solución más sencilla sería marcar el propio ejecutable para ser borrado en el siguiente reinicio en lugar de hacer toda esta parafernalia, pero a veces puede no interesarnos que dicho fichero esté en disco hasta ese momento.

De todos modos aplicaciones para esto las hay a montones. Soltar un ejecutable que haga algo, termine y luego sea borrado por el programa principal, forzar un reinicio del programa principal, distribuir un solo exe que luego suelte todos los ficheros que necesite…

5 comentarios sobre “C++: Insertar un ejecutable dentro de otro… y luego ejecutarlo”

  1. Hay otra aplicación interesante para esta técnica, además de la que tu comentas. Y es proporcionar en un solo ejecutable nativo la versión compilada para 32 bits y para 64 de una aplicación.

    La idea es porporcionar solo un ejecutable de 32 bits, que contiene el de 64 bits en su interior como recurso. Cuando ejecutamos en una maquina de 64 bits, el ejecutable de 32, en realidad lo que ocurre es que se extrae el de 64 y se ejecuta.

    Las herramientas de System Internals usan esta técnica para que no te tengas que preocupar de usar la versión adecuada…

    Interesante artículo.

    Un saludo!

  2. esta tecnica – aunque no con el mismo codigo – la conoci por alla del 2002, llamada como » blindear» , muy usada por troyanos, o bueno … para esconder troyanos…., pero ya muchos antivirus los reconocen como virus, has probado en el tuyo para ver si es reconocido como virus?

    Salu2

    Ddaz

  3. Rodrigo, la motivación más evidente y ni se me ocurre, y eso que estoy cansado de lanzar el Process Explorer, que hace justamente eso. En fin.

    Ddaz: No lo he probado porque no tengo antivirus instalado, pero ni el fichero contenedor ni el contenido -en mi caso- hacen cosa mala alguna (tampoco puedo decir qué hacen). Además, el destino final es ir embebidos en máquinas industriales, por lo que tampoco me preocupa el tema de los antivirus. De todos modos, cualquier antivirus medianamente decente debería reconocer que no hay nada malo en ello… si los ejecutables no hacen nada malo.

  4. y como hariamos para insertar un recurso a un programa compilado?
    he visto que lo hace una aplicacion llamada ResHacker, en la cual se pueden agregar recursos a otras aplicaciones, por ejemplo agregar iconos, imagenes, exes…
    como se podria hacer eso? alguna ayuda? algunos links?

    GRACIAS, ha sido util este papper

  5. Lo primero de todo sería entender el formato de los exe y cómo se almacenan los segmentos y demás, luego ver cómo se almacenan los recursos y las tablas de recursos.

    Nunca lo he hecho (para eso ya existen otros programas que lo hacen), pero un punto de partida bueno sería la Wikipedia: http://en.wikipedia.org/wiki/EXE

    Por otro lado, no tiene mucho sentido insertar un recurso en un exe si luego el exe en tiempo de ejecución no va a saber qué hacer con él.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *