Para usar una DLL primero tiene que ser importada en el proceso y ya se puede usar sus funciones
Crear DLL
Visual Studio: nuevo proyecto de tipo Dynamic-Link Library (DLL)
El dllmain.cpp que genera la plantilla
Podemos renombrar dllmain.cpp a dllmain.c
Quitar Header Precompilados
Puede existir framework.hpch.hpch.cpp al crear el proyecto pero no son necesarios y se pueden borrar
Los archivos de la plantilla que se pueden borrar
Después de borrar ajustamos las propiedades
Menú Project, opción Properties del proyecto
Propiedades del proyecto: Precompiled Header en Use (/Yu)
Se cambia a Not Using Precompiled Headers
Exportar función
c
#include <Windows.h>// Exported functionextern"C"__declspec(dllexport) VOID WINAPI HelloWorld(VOID)
{
MessageBoxA(NULL, "Hello, World!", "DLL Message", MB_ICONINFORMATION);
}
// Entry point for the DLL
BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Ver funciones exportadas
terminal
dumpbin /exports sampleDLL.dll
Load-Time Linking vs Run-Time Linking
Load-time: Windows carga la DLL al arrancar el programa, antes de main. Tú llamas a la función directamente (MessageBoxA(...)) y el compilador lo apunta en la IAT del .exe. Si la DLL falta, el programa ni arranca.
Run-time: tú cargas la DLL cuando quieras con LoadLibraryA, buscas la función con GetProcAddress y la llamas mediante un puntero a función (typedef + cast). Si la DLL falta, LoadLibraryA devuelve NULL y tú decides qué hacer. Al terminar, FreeLibrary.
Método usado Run-Time
La DLL generada junto al ejecutable que la carga
c
#include <stdio.h>#include <Windows.h>// Casteamos la funcion de la DLL ya que se exporto como VOID WINAPI HelloWorld(VOID);typedefVOID(WINAPI* fnHelloWorld)(VOID);
intmain() {
// Cargamos la DLL
HMODULE hModule = GetModuleHandleA("DllGenerador.dll");
BOOL cargadoManualmente = FALSE;
if (hModule == NULL) {
hModule = LoadLibraryA("DllGenerador.dll");
if (hModule == NULL) {
printf("[!] LoadLibraryA Failed With Error: %lu\n", GetLastError());
return -1;
}
cargadoManualmente = TRUE;
}
printf("[+] Se ha cargado correctamente la dll Handle: 0x%p\n", hModule);
// Obtenemos puntero hacia la dir de Memoria de HelloWorld de la DLL y lo almacenamos en pHelloWorld
PVOID pHelloWorld = GetProcAddress(hModule, "HelloWorld");
if (pHelloWorld == NULL) {
printf("[!] GetProcAddress Failed With Error: %lu\n", GetLastError());
if (cargadoManualmente) FreeLibrary(hModule);
return -1;
}
// Type-Casteamos la direccion de memoria para hacer que matchee con el casteo de arriba
fnHelloWorld HelloWorld = (fnHelloWorld)pHelloWorld;
// Ejecutamos la funciónHelloWorld();
if (cargadoManualmente)
FreeLibrary(hModule);
return0;
}
RunDLL32
terminal
rundll32.exe <dllname>, <function exported to run>