Introducción a la Inyección de DLL
La inyección de DLL es una técnica que permite cargar una biblioteca de vínculos dinámicos (DLL) externa en el espacio de memoria de otro proceso en ejecución. Esto se logrra mapeando el contenido de la DLL dentro de la dirección virtual del proceso objetivo, permitiendo así la ejecución de su código dentro de ese contexto. Esta técnica tiene múltiples aplicaciones, tanto legítimas (depuración, extensión de funcionalidades de software) como maliciosas (espionaje, persistencia de malware).
Creación de una DLL Simple
Para este ejemplo, se crea una DLL que muestra un cuadro de diálogo cuando se carga en un proceso. A continuación se presenta el código modificado.
Archivo de encabezado (dll.h):
#ifndef DLL_HEADER_GUARD
#define DLL_HEADER_GUARD
#ifdef BUILDING_DLL_EXPORT
#define API_EXPORT __declspec(dllexport)
#else
#define API_EXPORT __declspec(dllimport)
#endif
class API_EXPORT DemoClass {};
#endif
Archivo de implementación (dllmain.cpp):
#include "dll.h"
#include <windows.h>
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD reason, LPVOID reserved)
{
if (reason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hModule);
MessageBoxA(NULL, "¡Carga exitosa de la DLL!", "Demo de Inyección", MB_OK | MB_ICONINFORMATION);
}
else if (reason == DLL_PROCESS_DETACH)
{
// Limpieza si es necesaria
}
return TRUE;
}
Se compila este proyecto para obtener demo.dll.
Implementación del Inyector
El proceso de inyección clásico se divide en cuatro fases principales, que se implementan mediante funciones específicas de la API de Windows.
- Apertura del proceso objetivo: Se obtiene un identificador con permisos adecuados usando
OpenProcess. - Asignación de memoria en el proceso remoto: Se reserva un espacio contiguo con
VirtualAllocEx. - Escritura de la ruta de la DLL en la memoria remota: Se transfiere la cadena de caracteres mediante
WriteProcessMemory. - Creación de un hilo remoto: Se ejecuta
LoadLibraryAcomo punto de entrada del nuevo hilo, pasando la dirección donde se escribió la ruta de la DLL.
Esquema del código del inyector:
#include <windows.h>
#include <tlhelp32.h>
#include <cstdio>
// Función auxiliar para buscar un proceso por nombre
DWORD FindProcessId(const char* processName)
{
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry))
{
do
{
if (!_stricmp(entry.szExeFile, processName))
{
CloseHandle(snapshot);
return entry.th32ProcessID;
}
} while (Process32Next(snapshot, &entry));
}
CloseHandle(snapshot);
return 0;
}
int main(int argc, char* argv[])
{
const char* dllPath = "C:\\Ruta\\demo.dll"; // Ruta completa a la DLL
DWORD pathLen = strlen(dllPath) + 1;
// 1. Obtener el PID del objetivo (ej. "notepad.exe")
DWORD targetPid = FindProcessId("notepad.exe");
if (!targetPid)
{
printf("Proceso objetivo no encontrado.\n");
return 1;
}
// 2. Abrir el proceso
HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, targetPid);
if (!hProcess)
{
printf("Error al abrir el proceso (Código: %lu).\n", GetLastError());
return 1;
}
// 3. Asignar memoria en el proceso remoto
LPVOID remoteBuffer = VirtualAllocEx(hProcess, NULL, pathLen, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!remoteBuffer)
{
printf("Error al asignar memoria remota.\n");
CloseHandle(hProcess);
return 1;
}
// 4. Escribir la ruta de la DLL en la memoria asignada
WriteProcessMemory(hProcess, remoteBuffer, dllPath, pathLen, NULL);
// 5. Obtener la dirección de LoadLibraryA
HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
LPTHREAD_START_ROUTINE loadLibAddr = (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryA");
// 6. Crear el hilo remoto que ejecutará LoadLibraryA
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, loadLibAddr, remoteBuffer, 0, NULL);
if (hThread)
{
WaitForSingleObject(hThread, INFINITE);
printf("Inyección completada.\n");
CloseHandle(hThread);
}
else
{
printf("Error al crear el hilo remoto.\n");
}
// 7. Liberar recursos
VirtualFreeEx(hProcess, remoteBuffer, 0, MEM_RELEASE);
CloseHandle(hProcess);
return 0;
}
Verificación de la Inyección
Tras ejecutar el inyector, se puede usar una herramienta como Process Explorer o listDLLs para inspeccionar los módulos cargados en el proceso notepad.exe. La presencia de demo.dll en la lista confirma que la técnica ha funcionado correctamente.