stringtranslate.com

inyección de DLL

En programación de computadoras , la inyección de DLL es una técnica utilizada para ejecutar código dentro del espacio de direcciones de otro proceso obligándolo a cargar una biblioteca de enlaces dinámicos . [1] Los programas externos suelen utilizar la inyección de DLL para influir en el comportamiento de otro programa de una manera que sus autores no anticiparon ni pretendieron. [1] [2] [3] Por ejemplo, el código inyectado podría conectar llamadas a funciones del sistema, [4] [5] o leer el contenido de los cuadros de texto de contraseñas , lo que no se puede hacer de la forma habitual. [6] Un programa utilizado para inyectar código arbitrario en procesos arbitrarios se llama inyector DLL .

Enfoques en Microsoft Windows

Hay varias formas en Microsoft Windows de forzar que un proceso cargue y ejecute código en una DLL que los autores no pretendían:

Enfoques en sistemas tipo Unix

En sistemas operativos tipo Unix con el enlazador dinámico basado en ld.so (en BSD ) y ld-linux.so (en Linux ), se pueden vincular bibliotecas arbitrarias a un nuevo proceso ingresando el nombre de ruta de la biblioteca en la variable de entorno LD_PRELOAD . que se pueden configurar globalmente o individualmente para un solo proceso. [37]

Por ejemplo, en un sistema Linux, este comando inicia el comando "prog" con la biblioteca compartida del archivo "test.so" vinculada en el momento del lanzamiento:

LD_PRELOAD = programa "./test.so" 

Una biblioteca de este tipo se puede crear de la misma manera que otros objetos compartidos . Con GCC , esto implica compilar el archivo fuente que contiene los nuevos globales a vincular, con la opción -fpic o -fPIC , [38] y vincularlo con la opción -shared . [39] La biblioteca tiene acceso a los símbolos externos declarados en el programa como cualquier otra biblioteca.

En macOS , el siguiente comando inicia el comando "prog" con la biblioteca compartida del archivo "test.dylib" vinculada en el momento del lanzamiento: [40]

DYLD_INSERT_LIBRARIES = "./test.dylib" DYLD_FORCE_FLAT_NAMESPACE = 1 programa  

También es posible utilizar técnicas basadas en depuradores en sistemas tipo Unix. [41]

Código de muestra

Copiar una DLL cargada con LoadLibrary a un proceso remoto

Como no hay ninguna LoadLibrary()llamada para cargar una DLL en un proceso externo, debe copiar una DLL cargada localmente en la memoria asignada de forma remota. El siguiente código comentado muestra cómo hacerlo.

#include <Windows.h> #include <TlHelp32.h> #include <iostream> #include <memoria> #include <system_error> #include <charconv> #include <vector> #include <cassert>        #si está definido (_MSC_VER) #advertencia pragma (deshabilitar: 6387) #endifusando el espacio de nombres estándar ;  usando XHANDLE = Unique_ptr < void , decltype ([]( void * h ) { h && h != INVALID_HANDLE_VALUE && CloseHandle ( ( HANDLE ) h ); }) > ; usando XHMODULE = Unique_ptr < remove_reference_t < decltype ( * HMODULE ()) > , decltype ([]( HMODULE hm ) { hm && FreeLibrary ( hm ); }) > ;                               MODULEENTRY32W getModuleDescription ( HMODULE hmModule ); size_t maxReadableRange ( vacío * pRegión ); cadena getAbsolutePathA ( char const * fileName , char const * err ); DWORD dumpParseDWORD ( wchar_t const * str ); wstring getAbsolutePath ( wchar_t const * makeAbsolute , char const * errStr ); [[ noreturn ]] void throwSysErr ( char const * str );                                  constexpr wchar_t const * LOADER_DLL_NAME = L "loaderDll.dll" ; constexpr char const * LOADER_THREAD_PROC = "loadLibraryThread" ;          int wmain ( int argc , wchar_t ** argv ) { intenta { si ( argc < 3 ) devuelve EXIT_FAILURE ; wchar_t const * ProcessId = argv [ 1 ], * remotoLoadedDll = argv [ 2 ], * initData = argc >= 4 ? argv [ 3 ] : L "" ; DWORD dwProcessId = tontoParseDWORD ( id de proceso ); XHANDLE xhProcess ( OpenProcess ( PROCESS_ALL_ACCESS , FALSE , dwProcessId ) ); if ( ! xhProcess . get () ) throwSysErr ( "no se puede abrir el proceso remoto con acceso ilimitado" ); XHMODULE xhmLocalLoader ; ENTRADA DE MÓDULO32W meLocalLoader ; para ( ; ; ) { xhmLocalLoader . restablecer ( LoadLibraryW ( LOADER_DLL_NAME ) ); if ( ! xhmLocalLoader . get () ) throwSysErr ( "no se puede cargar la DLL del cargador localmente" ); // obtener la dirección inicial y el tamaño del módulo meLocalLoader = getModuleDescription ( ( HMODULE ) xhmLocalLoader . get () ); // intenta asignar un rango de memoria en el proceso externo con el mismo tamaño que ocupa la DLL en nuestro proceso if ( VirtualAllocEx ( xhProcess . get (), meLocalLoader . modBaseAddr , meLocalLoader . modBaseSize , MEM_RESERVE | MEM_COMMIT , PAGE_EXECUTE_READWRITE ) ) break ; // la asignación falló, biblioteca gratuita xhmLocalLoader .                                                                   restablecer ( nulptr ); // intenta reservar el rango de direcciones que la biblioteca ocupaba antes para evitar // el reciclaje de ese rango de direcciones con la siguiente llamada a LoadLibrary(). if ( ! VirtualAlloc ( meLocalLoader . modBaseAddr , meLocalLoader . modBaseSize , MEM_RESERVE , PAGE_NOACCESS ) ) throwSysErr ( "no se puede reservar el rango de direcciones de la DLL previamente asignada" ); } LPTHREAD_START_ROUTINE loaderThreadProc = ( LPTHREAD_START_ROUTINE ) GetProcAddress ( ( HMODULE ) xhmLocalLoader . get (), :: LOADER_THREAD_PROC ); if ( ! loaderThreadProc ) throwSysErr ( "no se puede obtener el punto de entrada del procedimiento" ); // copiar todo el contenido DLL legible al proceso de destino if ( Size_T copiado ; ! WriteProcessMemory ( xhProcess . get (), meLocalLoader . modBaseAddr , meLocalLoader . modBaseAddr , meLocalLoader . modBaseSize , & copiado ) && GetLastError () != ERROR_PARTIAL_COPY ) throwSysErr ( "no se puede copiar la DLL del cargador al proceso remoto" ); // crea dos cadenas C concatenadas que contienen la DLL a cargar así como el parámetro // dado a la DLL cargada de forma remota wstring data ( getAbsolutePath ( remoteLoadedDll , "no se puede obtener la ruta absoluta a la DLL para cargarla de forma remota" ) ); datos += L '\0' ; datos += datosinit ; datos += L '\0' ; tamaño_t tamaño de datos = datos . tamaño () * tamaño de ( wchar_t ); auto initStrErr = []() { tirarSysErr (                                                            "no se pudieron copiar los datos de inicialización a la DLL del cargador" ); }; void * datos remotos ; // asigna de forma remota memoria lo suficientemente grande como para contener al menos nuestras dos cadenas if ( ! ( remoteData = VirtualAllocEx ( xhProcess . get (), nullptr , dataSize , MEM_RESERVE | MEM_COMMIT , PAGE_READWRITE )) ) initStrErr (); // escribe ambas cadenas en la memoria remota if ( TAMAÑO_T copiado ;! WriteProcessMemory ( xhProcess . get (), datos remotos , datos . datos (), tamaño de datos , & copiado ) || copiado ! = tamaño de datos ) initStrErr (); // crear un hilo de carga de DLL remoto; el punto de entrada dado tiene la misma dirección en nuestro proceso así como la dirección remota // le damos a este hilo la dirección de nuestras dos cadenas copiadas remotamente XHANDLE xhRemoteInitThread ( CreateRemoteThread ( xhProcess . get (), nullptr , 0 , loaderThreadProc , remoteData , 0 , nullptr ) ); if ( ! xhRemoteInitThread . get () ) throwSysErr ( "no se pudo crear el hilo de inicialización remota" ); // esperar a que termine el hilo de nuestro cargador remoto // debería hacerlo muy pronto, ya que su única tarea es copiar las cadenas de la DLL cargada de forma remota y cargar esta DLL por sí misma if ( WaitForSingleObject ( xhRemoteInitThread . get (), INFINITE ) == WAIT_FAILED ) throwSysErr ( "no puedo esperar al hilo de inicialización remota" ); DWORD dwInitThreadExitCode ; if ( ! GetExitCodeThread ( xhRemoteInitThread . get (), & dwInitThreadExitCode ) ) throwSysErr                                                         ( "no se puede obtener el código de éxito del hilo de inicialización" ); // comprueba el código de salida del cargador remoto, debería ser NO_ERROR (0) if ( dwInitThreadExitCode != NO_ERROR ) throw system_error ( ( int ) dwInitThreadExitCode , system_category (), "Error LoadLibrary() en dll del cargador remoto" ); } catch ( excepción constante y se ) { cout << se . qué () << endl ; } }                   MODULEENTRY32W getModuleDescription ( HMODULE hmModule ) { // devuelve la ruta absoluta para un identificador de módulo determinado auto getModulePath = []( HMODULE hm , char const * err ) -> wstring { wchar_t modulePath [ MAX_PATH ]; if ( DWORD dwRet = GetModuleFileNameW ( hm , modulePath , MAX_PATH ); ! dwRet || dwRet >= MAX_PATH ) throwSysErr ( err ); devolver ruta del módulo ; }; // ruta del módulo de la DLL local wstring moduleAbsolute ( getModulePath ( hmModule , "no se puede obtener la ruta absoluta para la DLL del cargador local" ) ); XHANDLE xhToolHelp ( CreateToolhelp32Snapshot ( TH32CS_SNAPMODULE , GetCurrentProcessId () ) ); auto toolHelpErr = []() { throwSysErr ( "no se pueden enumerar los módulos en el proceso de inyección" ); }; if ( xhToolHelp . get () == INVALID_HANDLE_VALUE ) toolHelpErr (); MODULEENTRY32W yo ; a mí . dwSize = tamaño de ; if ( ! Module32FirstW ( xhToolHelp . get (), & yo ) ) toolHelpErr (); for ( ; ; ) { // tiene la imagen actual en la instantánea la misma ruta que la DLL proporcionada por el identificador del módulo // no es necesario comparar sin distinguir entre mayúsculas y minúsculas porque obtuvimos ambas rutas del kernel para que coincidan exactamente if ( getModulePath ( yo . hModule , "no puedo obtener la ruta absoluta para el nombre de DLL enumerado en la ayuda de herramientas " ) == moduleAbsolute ) devuélveme                                                                              ; a mí . dwSize = tamaño de ; if ( ! Module32NextW ( xhToolHelp . get (), & me ) ) toolHelpErr (); } }        [[ noreturn ]] void throwSysErr ( char const * str ) { throw system_error ( ( int ) GetLastError (), system_category (), str ); }          DWORD dumpParseDWORD ( wchar_t const * str ) { // from_chars del idiota porque no hay from_chars para caracteres Unicode DWORD dwRet = 0 ; mientras ( * str ) dwRet = dwRet * 10 + ( carácter sin firmar )( * str ++ - L '0' ); devolver dwRet ; }                    wstring getAbsolutePath ( wchar_t const * makeAbsolute , char const * errStr ) { // obtiene la ruta absoluta de una ruta relativa determinada wstring path ( MAX_PATH , L '\0' ); DWORD dwLongitud ; if ( ! ( dwLength = GetFullPathNameW ( makeAbsolute , MAX_PATH , ruta . data (), nullptr )) ) throwSysErr ( erStr ); // si deRet == MAX_PATH podríamos omitir un carácter de terminación cero, trátelo como un error; de lo contrario, if ( dwLength >= MAX_PATH ) throw invalid_argument ( errStr ); camino . cambiar el tamaño ( dwLength ); vía de retorno ; }                                   

El principal problema resuelto aquí es que una DLL cargada localmente y copiada a un proceso remoto debe ocupar las mismas direcciones que en el proceso de inyección. El código anterior hace esto asignando memoria para el mismo rango de direcciones que el ocupado anteriormente en el proceso de inyección. Si esto falla, la DLL se libera localmente, el rango de direcciones anterior se marca como reservado y LoadLibrary()se vuelve a intentar la llamada. Al reservar el rango de direcciones anterior, el código evita que el siguiente LoadLibrary()intento asigne el mismo rango de direcciones utilizado anteriormente.

El principal inconveniente de ese enfoque es que la DLL copiada en el proceso externo es que no hay otras dependencias de la biblioteca DLL de esa DLL cargada en el espacio de direcciones externas o punteros, como llamadas a funciones, a las DLL cargadas por el proceso externo. ajustado de acuerdo con las dependencias de la DLL copiada. Afortunadamente, las DLL generalmente tienen direcciones de carga preferidas que son respetadas por el cargador del kernel . Algunas DLL como kernel32.dllse cargan de manera confiable al principio, cuando el espacio de direcciones del proceso está ocupado por la imagen ejecutable y las DLL dependientes. Normalmente tienen direcciones fiables y no conflictivas. Por lo tanto, la DLL copiada puede utilizar cualquier kernel32.dllllamada, por ejemplo, para cargar otra DLL con todas las ventajas de una DLL cargada localmente, es decir, que tenga todas las dependencias relativas de biblioteca. La ruta a esa DLL se copia en el espacio de direcciones externas y se proporciona como un parámetro nulo para la función de subproceso. La implementación anterior también permite tener parámetros adicionales, que se pasan a la DLL copiada de forma remota después de que la cadena con la DLL que se cargará de forma remota se pase a esa DLL.

El siguiente código es la fuente de la DLL del cargador copiada de forma remota que solo realiza kernel32.dllllamadas:

#incluye <Windows.h> #incluye <atómico>  usando el espacio de nombres estándar ;  BOOL APIENTRY DllMain ( HMODULE hModule , DWORD ul_reason_for_call , LPVOID lpReserved ) { return TRUE ; }          DWORD WINAPI loadLibraryThread ( LPVOID lpvThreadParam );     // MSVC / clang-cl manipulación #if definido(_M_IX86) #pragma comentario(enlazador, "/export:loadLibraryThread=?loadLibraryThread@@YGKPAX@Z") #elif definido(_M_X64) #pragma comentario(enlazador, "/exportar :loadLibraryThread=?loadLibraryThread@@YAKPEAX@Z") #else #error plataforma no compatible #endifDWORD WINAPI loadLibraryThread ( LPVOID lpvThreadParam ) { // uso atomics para evitar que el "optimizador" reemplace mi código con // las llamadas de biblioteca wsclen o memcpy a direcciones externas en realidad no son válidas // con esta DLL copiada // ignora cualquier barrera de carga atómica desde esto no tiene que ser rápido atomic_wchar_t const // ruta a la biblioteca para cargar desde dentro * libPath = ( atomic_wchar_t * ) lpvThreadParam , // puntero a los parámetros dados a esta biblioteca * data = libPath ; // avanza los datos a los parámetros reales while ( * data ++ ); MANEJAR hEventoSaliente ; // crear un evento con nombre para notificar a la DLL remota que los datos ya se han copiado // necesario porque la ejecución remota de la DLL comienza directamente después de LoadLibrary()S if ( ! ( hOutboundEvent = CreateEventA ( nullptr , FALSE , FALSE , "nasty hackers" )) ) devolver GetLastError (); // tamaño de los parámetros dados a la DLL size_t dataSize = 0 ; mientras ( datos [ tamaño de datos ++ ] ); si ( tamaño de datos >= MAX_PATH ) devuelve ERROR_INVALID_PARAMETER ; // limpia LoadLibrary() con todas las dependencias de DLL HMODULE hm = LoadLibraryW ( ( wchar_t * ) libPath ); si ( ! hm ) devuelve GetLastError (); // obtener la dirección de exportación de parámetros de la DLL cargada wchar_t volatile ( & initData )[ MAX_PATH ] = * ( wchar_t ( ) [ MAX_PATH ]) GetProcAddress ( hm , "initData" ); // ¿La DLL cargada no proporciona dicha exportación, es decir, no depende de parámetros? si ( !                                                    initData ) devuelve NO_ERROR ; // copia los parámetros a la DLL para ( size_t i = 0 ; i ! = dataSize ; initData [ i ] = data [ i ], ++ i ); // notifica que los parámetros están disponibles si ( ! SetEvent ( hOutboundEvent ) ) return GetLastError (); devolver NO_ERROR ; }                    

El último código muestra un ejemplo de una DLL cargada por la DLL del cargador que imprime los parámetros en un archivo.

#incluye <Windows.h> #incluye <fstream> #incluye <atómico>   usando el espacio de nombres estándar ;  #if definido(_MSC_VER) #pragma advertencia(disable: 6387) // el identificador devuelto podría ser nulo #endif#si está definido (_M_IX86) #comentario de pragma (enlazador, "/export:DllMain=_DllMain@12") #elif definido (_M_X64) #comentario de pragma (enlazador, "/export:DllMain=_DllMain@12") #else #error plataforma no compatible #endifusando el espacio de nombres estándar ;  DWORD WINAPI myThread ( LPVOID lpvThreadParam );     BOOL APIENTRY DllMain ( HMODULE hModule , DWORD dwReason , LPVOID lpReserved ) { switch ( dwReason ) { case DLL_PROCESS_ATTACH : // crear hilo ya que no se llama a ninguna exportación desde la DLL del cargador CreateThread ( nullptr , 0 , myThread , nullptr , 0 , nullptr ) ; predeterminado : romper ; } devuelve VERDADERO ; }                    externo " C" __declspec ( dllexport ) wchar_t initData [ MAX_PATH ] = {0} ;      DWORD WINAPI myThread ( LPVOID lpvThreadParam ) { // espera a que initData sea completado por la DLL del cargador // salta eso si no confías en ningún initData // ya que el evento denominado "hackers desagradables" ha sido creado por nuestra propia DLL / / LoadLibrary() solo nos estamos conectando a un evento con nombre, pero no creando uno if ( WaitForSingleObject ( CreateEventA ( nullptr , FALSE , FALSE , "hackers desagradables" ) , INFINITE ) != WAIT_OBJECT_0 ) return 0 ; // escribe parámetros en un archivo para probar la función // el siguiente código no funciona cuando la DLL no está vinculada estáticamente por razones desconocidas wofstream wofs ; ¡guau ! open ( "c: \\ Usuarios \\ xxx \\ test.txt " , ofstream :: out | ofstream :: trunc ); wofs << initData << endl ; devolver 0 ; }                             

Un hecho importante es que no se realizan exportaciones desde la DLL del cargador, sino que toda la inicialización se realiza desde DllMain. La única exportación es la de initData, que recibe los parámetros dados por el proceso de inyección a través de la DLL del cargador. Y hay que tener en cuenta que el subproceso creado a partir de una función DllMain no está programado hasta que su DLL_THREAD_ATTACHfunción haya tenido éxito. Por lo tanto, es posible que no haya ninguna sincronización desde adentro DllMaincon el hilo creado.

Referencias

  1. ^ ab James Shewmaker (2006). "Análisis de la inyección de DLL" (PDF) . Presentación GSM . Muesca azul. Archivado desde el original (PDF) el 3 de diciembre de 2008 . Consultado el 31 de agosto de 2008 .
  2. ^ ab Iczelion (agosto de 2002). "Tutorial 24: Ganchos de Windows". Página de inicio del ensamblaje Win32 de Iczelion . Archivado desde el original el 1 de agosto de 2008 . Consultado el 31 de agosto de 2008 .
  3. ^ Rocky Pulley (19 de mayo de 2005). "Ampliación del Administrador de tareas con inyección de DLL". Proyecto de código . Archivado desde el original el 6 de febrero de 2009 . Consultado el 1 de septiembre de 2008 .
  4. ^ ab Nasser R. Rowhani (23 de octubre de 2003). "Tutorial de inyección de DLL e interceptación de funciones". Proyecto de código . Archivado desde el original el 15 de abril de 2018 . Consultado el 31 de agosto de 2008 .
  5. ^ abc Ivo Ivanov (2 de diciembre de 2002). "Se revela el enlace de API". Proyecto de código . Consultado el 31 de agosto de 2008 .
  6. ^ abcd Robert Kuster (20 de agosto de 2003). "Tres formas de inyectar su código en otro proceso". Proyecto de código . Consultado el 31 de agosto de 2008 .
  7. ^ "Trabajar con el valor de registro AppInit_DLLs". Ayuda y soporte técnico de Microsoft . Microsoft. 21 de noviembre de 2006 . Consultado el 31 de agosto de 2008 .
  8. ^ Raymond Chen (13 de diciembre de 2007). "AppInit_DLLs debe cambiarse de nombre a Deadlock_Or_Crash_Randomly_DLLs". Lo viejo y nuevo . Microsoft . Consultado el 31 de agosto de 2008 .
  9. ^ "dllmain.c". ReaccionOS . Fundación ReactOS. 8 de julio de 2008 . Consultado el 31 de agosto de 2008 .[ enlace muerto permanente ]
  10. ^ AppInit_DLL en Windows 7 y Windows Server 2008 R2
  11. ^ "AppInit DLL y arranque seguro". MSDN . Consultado el 29 de marzo de 2016 .
  12. ^ " Microsoft Windows ' AtomBombing' mediante inyección de código" . Lectura oscura . Consultado el 20 de abril de 2017 .
  13. ^ abcd Trent Waddington. "InyectarDLL". Archivado desde el original el 30 de diciembre de 2019 . Consultado el 31 de agosto de 2008 .
  14. ^ "Inyección de Dll". DreamInCode.net . Grupo de medios1. 4 de mayo de 2006. Archivado desde el original el 2 de septiembre de 2008 . Consultado el 31 de agosto de 2008 .
  15. ^ Greg Jenkins (noviembre de 2007). "Marco de inyección de DLL". Circo Ring3 . WordPress. Archivado desde el original el 28 de junio de 2020 . Consultado el 31 de agosto de 2008 .
  16. ^ Drew Benton (17 de agosto de 2007). "Una solución de inyección de DLL más completa con CreateRemoteThread". Proyecto de código . Consultado el 1 de septiembre de 2008 .
  17. ^ "Crear proceso". SDK de plataforma para Windows XP SP2 . Microsoft . Consultado el 31 de agosto de 2008 .
  18. ^ "PROCESO_INFORMACIÓN". SDK de plataforma para Windows XP SP2 . Microsoft . Consultado el 31 de agosto de 2008 .
  19. ^ "Función GetWindowThreadProcessId". SDK de plataforma para Windows XP SP2 . Microsoft . Consultado el 31 de agosto de 2008 .
  20. ^ "Procesos de enumeración". SDK de plataforma para Windows XP SP2 . Microsoft . Consultado el 31 de agosto de 2008 .
  21. ^ "GetModuleBaseName". SDK de plataforma para Windows XP SP2 . Microsoft . Consultado el 31 de agosto de 2008 .
  22. ^ "VirtualAllocEx". SDK de plataforma para Windows XP SP2 . Microsoft . Consultado el 31 de agosto de 2008 .
  23. ^ "Memoria de proceso de escritura". SDK de plataforma para Windows XP SP2 . Microsoft . Consultado el 31 de agosto de 2008 .
  24. ^ "Puesto avanzado que evita la autoprotección mediante inyección avanzada de DLL con vulnerabilidad de robo de identificador". Matousec . 1 de diciembre de 2006. Archivado desde el original el 6 de febrero de 2009 . Consultado el 31 de agosto de 2008 .
  25. ^ "Crear hilo remoto". SDK de plataforma para Windows XP SP2 . Microsoft . Consultado el 31 de agosto de 2008 .
  26. ^ "Cargar biblioteca". SDK de plataforma para Windows XP SP2 . Microsoft . Consultado el 31 de agosto de 2008 .
  27. ^ ab "DllPrincipal". SDK de plataforma para Windows XP SP2 . Microsoft . Consultado el 31 de agosto de 2008 .
  28. ^ "Función SetWindowsHookEx". SDK de plataforma para Windows XP SP2 . Microsoft . Consultado el 31 de agosto de 2008 .
  29. ^ "Valor de registro de AppInit_DLLs y Windows 95". Ayuda y soporte técnico de Microsoft . Microsoft. 1 de marzo de 2005 . Consultado el 31 de agosto de 2008 .
  30. ^ "Inyección de Dll mediante el método SetWindowsHookEx()". Inversión del juego . 3 de abril de 2008 . Consultado el 1 de septiembre de 2008 .
  31. ^ "Inyección de DLL SetThreadContext". 16 de enero de 2007. Archivado desde el original el 23 de agosto de 2011 . Consultado el 1 de septiembre de 2008 .
  32. ^ Ben Botto (6 de septiembre de 2008). "Inyector DLL". Archivado desde el original el 7 de febrero de 2009 . Consultado el 1 de septiembre de 2008 .
  33. ^ "La carga insegura de la biblioteca podría permitir la ejecución remota de código". Microsoft . 10 de junio de 2011 . Consultado el 20 de abril de 2016 .
  34. ^ "Carga segura de bibliotecas para evitar ataques de precarga de DLL". Microsoft . 10 de junio de 2011 . Consultado el 8 de agosto de 2012 .
  35. ^ "Aviso de seguridad de Microsoft: la carga insegura de la biblioteca podría permitir la ejecución remota de código". Microsoft . 10 de junio de 2011 . Consultado el 20 de abril de 2016 .
  36. ^ Nicolas Falliere (26 de septiembre de 2010). "Infección por Stuxnet de los proyectos del paso 7". Symantec.
  37. ^ Linus Torvalds ; David Engel; Eric Youngdale; Peter MacDonald; Hongjiu Lu; Lars Wirzenius; Mitch D'Souza (14 de marzo de 1998). "ld.so/ld-linux.so - enlazador/cargador dinámico". Páginas de manual de UNIX . Archivado desde el original el 6 de febrero de 2009 . Consultado el 31 de agosto de 2008 .
  38. ^ "Opciones de generación de código". Usando la colección de compiladores GNU (GCC) . Fundación de Software Libre . Consultado el 31 de agosto de 2008 . Genere código independiente de la posición (PIC) adecuado para su uso en una biblioteca compartida, si es compatible con la máquina de destino. cuadrados.-fpic
  39. ^ "Opciones de enlace". Usando la colección de compiladores GNU (GCC) . Fundación de Software Libre . Consultado el 31 de agosto de 2008 . Produzca un objeto compartido que luego pueda vincularse con otros objetos para formar un ejecutable. cuadrados-shared
  40. ^ "El truco LD_PRELOAD". Peter Goldsborough . Consultado el 17 de mayo de 2017 .
  41. ^ Gregory Shpitalnik (12 de febrero de 2009). "Inyección de código en una aplicación Linux en ejecución". Proyecto de código . Consultado el 18 de noviembre de 2010 .